feat: mobile-optimize admin section

- Layout: sidebar hidden on mobile, replaced with horizontal top nav strip
- Tables: overflow-x-auto + hide secondary columns (email/category/dates/
  plays/likes) on small screens; show email inline under name on mobile
- Forms: grid-cols-2 → grid-cols-1 sm:grid-cols-2 on all admin forms
- Markdown editor: Write/Preview tab toggle on mobile, side-by-side on sm+
- Padding: p-3 sm:p-6 on all admin pages for tighter mobile layout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 14:36:52 +01:00
parent a7fafaf7c5
commit 648123fab5
9 changed files with 105 additions and 46 deletions

View File

@@ -38,7 +38,7 @@
}
</script>
<div class="p-6">
<div class="p-3 sm:p-6">
<div class="flex items-center justify-between mb-6">
<h1 class="text-2xl font-bold">Articles</h1>
<Button href="/admin/articles/new">
@@ -46,13 +46,13 @@
</Button>
</div>
<div class="rounded-lg border border-border/40 overflow-hidden">
<div class="rounded-lg border border-border/40 overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-muted/30">
<tr>
<th class="px-4 py-3 text-left font-medium text-muted-foreground">Article</th>
<th class="px-4 py-3 text-left font-medium text-muted-foreground">Category</th>
<th class="px-4 py-3 text-left font-medium text-muted-foreground">Published</th>
<th class="px-4 py-3 text-left font-medium text-muted-foreground hidden sm:table-cell">Category</th>
<th class="px-4 py-3 text-left font-medium text-muted-foreground hidden sm:table-cell">Published</th>
<th class="px-4 py-3 text-right font-medium text-muted-foreground">Actions</th>
</tr>
</thead>
@@ -85,8 +85,8 @@
</div>
</div>
</td>
<td class="px-4 py-3 text-muted-foreground capitalize">{article.category ?? "—"}</td>
<td class="px-4 py-3 text-muted-foreground">
<td class="px-4 py-3 text-muted-foreground capitalize hidden sm:table-cell">{article.category ?? "—"}</td>
<td class="px-4 py-3 text-muted-foreground hidden sm:table-cell">
{timeAgo.format(new Date(article.publish_date))}
</td>
<td class="px-4 py-3 text-right">

View File

@@ -25,6 +25,7 @@
);
let imageId = $state<string | null>(data.article.image ?? null);
let saving = $state(false);
let editorTab = $state<"write" | "preview">("write");
let preview = $derived(content ? (marked.parse(content) as string) : "");
@@ -67,7 +68,7 @@
}
</script>
<div class="p-6">
<div class="p-3 sm:p-6">
<div class="flex items-center gap-4 mb-6">
<Button variant="ghost" href="/admin/articles" size="sm">
<span class="icon-[ri--arrow-left-line] h-4 w-4 mr-1"></span>Back
@@ -76,7 +77,7 @@
</div>
<div class="space-y-5 max-w-4xl">
<div class="grid grid-cols-2 gap-4">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="space-y-1.5">
<Label for="title">Title *</Label>
<Input id="title" bind:value={title} />
@@ -94,11 +95,28 @@
<!-- Markdown editor with live preview -->
<div class="space-y-1.5">
<Label>Content (Markdown)</Label>
<div class="grid grid-cols-2 gap-4 min-h-96">
<Textarea bind:value={content} class="h-full min-h-96 font-mono text-sm resize-none" />
<div class="flex items-center justify-between">
<Label>Content (Markdown)</Label>
<div class="flex rounded-lg border border-border/40 overflow-hidden text-xs sm:hidden">
<button
type="button"
class={`px-3 py-1 transition-colors ${editorTab === "write" ? "bg-primary/10 text-primary" : "text-muted-foreground"}`}
onclick={() => (editorTab = "write")}
>Write</button>
<button
type="button"
class={`px-3 py-1 transition-colors ${editorTab === "preview" ? "bg-primary/10 text-primary" : "text-muted-foreground"}`}
onclick={() => (editorTab = "preview")}
>Preview</button>
</div>
</div>
<div class="sm:grid sm:grid-cols-2 sm:gap-4 min-h-96">
<Textarea
bind:value={content}
class={`h-full min-h-96 font-mono text-sm resize-none ${editorTab === "preview" ? "hidden sm:flex" : ""}`}
/>
<div
class="rounded-lg border border-border/40 bg-muted/20 p-4 overflow-auto prose prose-sm max-w-none prose-headings:text-foreground prose-p:text-muted-foreground"
class={`rounded-lg border border-border/40 bg-muted/20 p-4 overflow-auto prose prose-sm max-w-none prose-headings:text-foreground prose-p:text-muted-foreground min-h-96 ${editorTab === "write" ? "hidden sm:block" : ""}`}
>
{#if preview}
{@html preview}
@@ -121,7 +139,7 @@
<FileDropZone accept="image/*" maxFileSize={10 * MEGABYTE} onUpload={handleImageUpload} />
</div>
<div class="grid grid-cols-2 gap-4">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="space-y-1.5">
<Label for="category">Category</Label>
<Input id="category" bind:value={category} />

View File

@@ -20,6 +20,7 @@
let publishDate = $state("");
let imageId = $state<string | null>(null);
let saving = $state(false);
let editorTab = $state<"write" | "preview">("write");
let preview = $derived(content ? (marked.parse(content) as string) : "");
@@ -72,7 +73,7 @@
}
</script>
<div class="p-6">
<div class="p-3 sm:p-6">
<div class="flex items-center gap-4 mb-6">
<Button variant="ghost" href="/admin/articles" size="sm">
<span class="icon-[ri--arrow-left-line] h-4 w-4 mr-1"></span>Back
@@ -81,7 +82,7 @@
</div>
<div class="space-y-5 max-w-4xl">
<div class="grid grid-cols-2 gap-4">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="space-y-1.5">
<Label for="title">Title *</Label>
<Input
@@ -106,15 +107,30 @@
<!-- Markdown editor with live preview -->
<div class="space-y-1.5">
<Label>Content (Markdown)</Label>
<div class="grid grid-cols-2 gap-4 min-h-96">
<div class="flex items-center justify-between">
<Label>Content (Markdown)</Label>
<div class="flex rounded-lg border border-border/40 overflow-hidden text-xs sm:hidden">
<button
type="button"
class={`px-3 py-1 transition-colors ${editorTab === "write" ? "bg-primary/10 text-primary" : "text-muted-foreground"}`}
onclick={() => (editorTab = "write")}
>Write</button>
<button
type="button"
class={`px-3 py-1 transition-colors ${editorTab === "preview" ? "bg-primary/10 text-primary" : "text-muted-foreground"}`}
onclick={() => (editorTab = "preview")}
>Preview</button>
</div>
</div>
<!-- Mobile: single pane toggled; Desktop: side by side -->
<div class="sm:grid sm:grid-cols-2 sm:gap-4 min-h-96">
<Textarea
bind:value={content}
placeholder="Write in Markdown…"
class="h-full min-h-96 font-mono text-sm resize-none"
class={`h-full min-h-96 font-mono text-sm resize-none ${editorTab === "preview" ? "hidden sm:flex" : ""}`}
/>
<div
class="rounded-lg border border-border/40 bg-muted/20 p-4 overflow-auto prose prose-sm max-w-none prose-headings:text-foreground prose-p:text-muted-foreground"
class={`rounded-lg border border-border/40 bg-muted/20 p-4 overflow-auto prose prose-sm max-w-none prose-headings:text-foreground prose-p:text-muted-foreground min-h-96 ${editorTab === "write" ? "hidden sm:block" : ""}`}
>
{#if preview}
{@html preview}
@@ -131,7 +147,7 @@
{#if imageId}<p class="text-xs text-green-600 mt-1">Image uploaded ✓</p>{/if}
</div>
<div class="grid grid-cols-2 gap-4">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="space-y-1.5">
<Label for="category">Category</Label>
<Input id="category" bind:value={category} placeholder="e.g. news, tutorial…" />