- Install @inlang/paraglide-js v2 with Vite plugin and paraglideMiddleware hook - Add messages/pl.json and messages/en.json with ~400 translation keys - Create project.inlang/settings.json (PL as base locale) - Add LanguageSwitcher component (cookie-based, no URL prefix needed) - Replace all hardcoded strings across 14 pages/components with m.*() calls - ProductForm uses derived label maps for all enum types (category, texture, etc.) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
85 lines
2.6 KiB
Svelte
85 lines
2.6 KiB
Svelte
<script lang="ts">
|
|
import type { PageData } from './$types';
|
|
import { m } from '$lib/paraglide/messages.js';
|
|
import { Badge } from '$lib/components/ui/badge';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '$lib/components/ui/card';
|
|
|
|
let { data }: { data: PageData } = $props();
|
|
|
|
const stateColors: Record<string, string> = {
|
|
excellent: 'bg-green-100 text-green-800',
|
|
good: 'bg-blue-100 text-blue-800',
|
|
fair: 'bg-yellow-100 text-yellow-800',
|
|
poor: 'bg-red-100 text-red-800'
|
|
};
|
|
</script>
|
|
|
|
<svelte:head><title>{m.dashboard_title()} — innercontext</title></svelte:head>
|
|
|
|
<div class="space-y-8">
|
|
<div>
|
|
<h2 class="text-2xl font-bold tracking-tight">{m.dashboard_title()}</h2>
|
|
<p class="text-muted-foreground">{m.dashboard_subtitle()}</p>
|
|
</div>
|
|
|
|
<div class="grid gap-6 md:grid-cols-2">
|
|
<!-- Latest skin snapshot -->
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>{m["dashboard_latestSnapshot"]()}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{#if data.latestSnapshot}
|
|
{@const s = data.latestSnapshot}
|
|
<div class="space-y-3">
|
|
<div class="flex items-center justify-between">
|
|
<span class="text-sm text-muted-foreground">{s.snapshot_date}</span>
|
|
{#if s.overall_state}
|
|
<span class="rounded-full px-2 py-0.5 text-xs font-medium {stateColors[s.overall_state] ?? ''}">
|
|
{s.overall_state}
|
|
</span>
|
|
{/if}
|
|
</div>
|
|
{#if s.active_concerns.length}
|
|
<div class="flex flex-wrap gap-1">
|
|
{#each s.active_concerns as concern (concern)}
|
|
<Badge variant="secondary">{concern.replace(/_/g, ' ')}</Badge>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
{#if s.notes}
|
|
<p class="text-sm text-muted-foreground">{s.notes}</p>
|
|
{/if}
|
|
</div>
|
|
{:else}
|
|
<p class="text-sm text-muted-foreground">{m["dashboard_noSnapshots"]()}</p>
|
|
{/if}
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<!-- Recent routines -->
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>{m["dashboard_recentRoutines"]()}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{#if data.recentRoutines.length}
|
|
<ul class="space-y-2">
|
|
{#each data.recentRoutines as routine (routine.id)}
|
|
<li class="flex items-center justify-between">
|
|
<a href="/routines/{routine.id}" class="text-sm hover:underline">
|
|
{routine.routine_date}
|
|
</a>
|
|
<Badge variant={routine.part_of_day === 'am' ? 'default' : 'secondary'}>
|
|
{routine.part_of_day.toUpperCase()}
|
|
</Badge>
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
{:else}
|
|
<p class="text-sm text-muted-foreground">{m["dashboard_noRoutines"]()}</p>
|
|
{/if}
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|