- Created 11 reusable UI components: PageHeader, SectionCard, StatCard, StatusBadge, TabBar, MemberList, ActivityFeed, EventCard, ContentSkeleton, QuickLinkGrid, ModuleCard - Created route-specific +layout.svelte for documents, calendar, kanban, events, settings, account - Each layout renders PageHeader instantly from parent data, shows ContentSkeleton during navigation - Removed full-page PageSkeleton from parent layout - Refactored all pages to use new components instead of inline markup - Overview page: uses StatCard, SectionCard, EventCard, ActivityFeed, MemberList, QuickLinkGrid - Events list: uses EventCard, Button components - Event detail: uses ModuleCard, SectionCard - Settings/Account/Calendar/Kanban: headers in layouts, toolbars in pages - Added i18n keys for overview page (EN + ET) - 0 errors, 112 tests pass
38 lines
881 B
Svelte
38 lines
881 B
Svelte
<script lang="ts">
|
|
interface Tab {
|
|
value: string;
|
|
label: string;
|
|
icon?: string;
|
|
}
|
|
|
|
interface Props {
|
|
tabs: Tab[];
|
|
active: string;
|
|
onchange: (value: string) => void;
|
|
}
|
|
|
|
let { tabs, active, onchange }: Props = $props();
|
|
</script>
|
|
|
|
<div class="flex items-center gap-1 px-6 py-3 border-b border-light/5 shrink-0">
|
|
{#each tabs as tab}
|
|
<button
|
|
type="button"
|
|
class="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-body-sm font-body transition-colors {active ===
|
|
tab.value
|
|
? 'bg-primary text-background'
|
|
: 'text-light/50 hover:text-white hover:bg-dark/50'}"
|
|
onclick={() => onchange(tab.value)}
|
|
>
|
|
{#if tab.icon}
|
|
<span
|
|
class="material-symbols-rounded"
|
|
style="font-size: 16px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 16;"
|
|
>{tab.icon}</span
|
|
>
|
|
{/if}
|
|
{tab.label}
|
|
</button>
|
|
{/each}
|
|
</div>
|