feat: refactor /me into admin-style layout with profile, security, recordings, analytics sub-pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
112
packages/frontend/src/routes/me/+layout.svelte
Normal file
112
packages/frontend/src/routes/me/+layout.svelte
Normal file
@@ -0,0 +1,112 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { Avatar, AvatarImage, AvatarFallback } from "$lib/components/ui/avatar";
|
||||
import { getUserInitials } from "$lib/utils";
|
||||
import { getAssetUrl } from "$lib/api";
|
||||
|
||||
const { children, data } = $props();
|
||||
|
||||
const navLinks = $derived([
|
||||
{ name: $_("me.nav.profile"), href: "/me/profile", icon: "icon-[ri--user-line]" },
|
||||
{ name: $_("me.nav.security"), href: "/me/security", icon: "icon-[ri--shield-keyhole-line]" },
|
||||
{
|
||||
name: $_("me.nav.recordings"),
|
||||
href: "/me/recordings",
|
||||
icon: "icon-[ri--play-list-2-line]",
|
||||
},
|
||||
...(data.isModel
|
||||
? [
|
||||
{
|
||||
name: $_("me.nav.analytics"),
|
||||
href: "/me/analytics",
|
||||
icon: "icon-[ri--line-chart-line]",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]);
|
||||
|
||||
function isActive(href: string) {
|
||||
return page.url.pathname.startsWith(href);
|
||||
}
|
||||
|
||||
const user = $derived(data.authStatus.user!);
|
||||
const avatarUrl = $derived(
|
||||
user.avatar ? (getAssetUrl(user.avatar, "thumbnail") ?? undefined) : undefined,
|
||||
);
|
||||
const displayName = $derived(user.artist_name ?? user.email);
|
||||
</script>
|
||||
|
||||
<div class="min-h-screen bg-gradient-to-br from-background via-primary/5 to-accent/5">
|
||||
<div class="container mx-auto px-4">
|
||||
<!-- Mobile top nav -->
|
||||
<div class="lg:hidden border-b border-border/40">
|
||||
<div class="flex items-center gap-1 overflow-x-auto py-2 scrollbar-none">
|
||||
<a
|
||||
href="/"
|
||||
class="shrink-0 text-xs text-muted-foreground hover:text-foreground transition-colors px-2"
|
||||
>
|
||||
{$_("me.nav.back_mobile")}
|
||||
</a>
|
||||
{#each navLinks as link (link.href)}
|
||||
<a
|
||||
href={link.href}
|
||||
class={`shrink-0 flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-sm font-medium transition-colors ${
|
||||
isActive(link.href)
|
||||
? "bg-primary/10 text-primary"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
||||
}`}
|
||||
>
|
||||
<span class={`${link.icon} h-4 w-4 shrink-0`}></span>
|
||||
<span class="hidden sm:inline">{link.name}</span>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Desktop layout -->
|
||||
<div class="flex min-h-screen">
|
||||
<!-- Sidebar (desktop only) -->
|
||||
<aside class="hidden lg:flex w-56 shrink-0 flex-col border-r border-border/40">
|
||||
<div class="px-4 py-5 border-b border-border/40">
|
||||
<a href="/" class="text-xs text-muted-foreground hover:text-foreground transition-colors">
|
||||
{$_("me.nav.back_to_site")}
|
||||
</a>
|
||||
<div class="mt-3 flex items-center gap-3">
|
||||
<Avatar class="h-9 w-9 shrink-0">
|
||||
<AvatarImage src={avatarUrl} alt={displayName} />
|
||||
<AvatarFallback class="text-xs">
|
||||
{getUserInitials(displayName)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-semibold text-foreground truncate">{displayName}</p>
|
||||
<p class="text-xs text-muted-foreground">{$_("me.title")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="flex-1 p-3 space-y-1">
|
||||
{#each navLinks as link (link.href)}
|
||||
<a
|
||||
href={link.href}
|
||||
class={`flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors ${
|
||||
isActive(link.href)
|
||||
? "bg-primary/10 text-primary"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
||||
}`}
|
||||
>
|
||||
<span class={`${link.icon} h-4 w-4`}></span>
|
||||
{link.name}
|
||||
</a>
|
||||
{/each}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="flex-1 min-w-0">
|
||||
{@render children()}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user