refactor(admin): extract EntityNavSection to eliminate nav markup repetition (#197)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
90
frontend/src/routes/admin/EntityNavSection.svelte
Normal file
90
frontend/src/routes/admin/EntityNavSection.svelte
Normal file
@@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
href: string;
|
||||
label: string;
|
||||
isActive: boolean;
|
||||
count?: number;
|
||||
topBorder?: boolean;
|
||||
icon: Snippet;
|
||||
variant?: 'sidebar' | 'flyout';
|
||||
onTabletTrigger?: (event: MouseEvent) => void;
|
||||
onFlyoutClick?: () => void;
|
||||
}
|
||||
|
||||
let {
|
||||
href,
|
||||
label,
|
||||
isActive,
|
||||
count,
|
||||
topBorder = false,
|
||||
icon,
|
||||
variant = 'sidebar',
|
||||
onTabletTrigger,
|
||||
onFlyoutClick
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if variant === 'sidebar'}
|
||||
<!-- Tablet button (visible at md, hidden at lg) -->
|
||||
<button
|
||||
data-flyout-trigger
|
||||
type="button"
|
||||
aria-label={label}
|
||||
title={label}
|
||||
onclick={onTabletTrigger}
|
||||
class="flex min-h-[44px] w-full flex-col items-center justify-center gap-0.5 border-l-[3px] py-3 transition-colors lg:hidden
|
||||
{topBorder ? 'border-t border-white/10' : ''}
|
||||
{isActive ? 'border-brand-mint bg-white/10' : (topBorder ? 'border-l-transparent hover:bg-white/5' : 'border-transparent hover:bg-white/5')}"
|
||||
>
|
||||
{@render icon()}
|
||||
{#if count !== undefined}
|
||||
<span class="text-[9px] font-bold {isActive ? 'text-white/80' : 'text-white/35'}"
|
||||
>{count}</span
|
||||
>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<!-- Desktop link (hidden at md, visible at lg) -->
|
||||
<a
|
||||
href={href}
|
||||
class="hidden flex-col items-start justify-center gap-0.5 border-l-[3px] px-3.5 py-2.5 transition-colors lg:flex
|
||||
{topBorder ? 'border-t border-white/10' : ''}
|
||||
{isActive ? 'border-brand-mint bg-white/10' : (topBorder ? 'border-l-transparent hover:bg-white/5' : 'border-transparent hover:bg-white/5')}"
|
||||
aria-current={isActive ? 'page' : undefined}
|
||||
title={label}
|
||||
>
|
||||
{@render icon()}
|
||||
{#if count !== undefined}
|
||||
<span class="text-[13px] font-black {isActive ? 'text-white/65' : 'text-white/50'}"
|
||||
>{count}</span
|
||||
>
|
||||
{/if}
|
||||
<span
|
||||
class="text-[9px] font-extrabold tracking-[0.5px] uppercase {isActive ? 'text-white' : 'text-white/55'}"
|
||||
>{label}</span
|
||||
>
|
||||
</a>
|
||||
{:else}
|
||||
<!-- Flyout link -->
|
||||
<a
|
||||
href={href}
|
||||
onclick={onFlyoutClick}
|
||||
class="flex flex-col items-start justify-center gap-0.5 border-l-[3px] px-3.5 py-2.5 transition-colors
|
||||
{topBorder ? 'border-t border-white/10' : ''}
|
||||
{isActive ? 'border-brand-mint bg-white/10' : (topBorder ? 'border-l-transparent hover:bg-white/5' : 'border-transparent hover:bg-white/5')}"
|
||||
aria-current={isActive ? 'page' : undefined}
|
||||
>
|
||||
{@render icon()}
|
||||
{#if count !== undefined}
|
||||
<span class="text-[13px] font-black {isActive ? 'text-white/65' : 'text-white/50'}"
|
||||
>{count}</span
|
||||
>
|
||||
{/if}
|
||||
<span
|
||||
class="text-[9px] font-extrabold tracking-[0.5px] uppercase {isActive ? 'text-white' : 'text-white/55'}"
|
||||
>{label}</span
|
||||
>
|
||||
</a>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user