9686b54b41
Seven radii were in circulation (4/5/6/8/12/16px + pill) with no rule for which went where; one toolbar row on /transactions mixed four shape languages. This locks a 4-tier ladder (design.md convention 16): - pill: interactive toolbar controls (buttons, chips, pickers, segmented controls, toolbar search, count nubs) - rounded-xl (12px): overlay tier: page panel, dialogs, slide-overs - rounded-lg (8px): cards, form fields, popover/menu content, boxes - rounded-sm (4px): nested leaves (menu items, checkboxes, kbd/code nubs) Changes: - New SegmentedControl primitive (pill-in-pill tablist, h-8) replaces the hand-rolled bg-muted/70 tablist copied across 11 files - New ToolbarSearch primitive (pill, h-8) adopted on 9 page toolbars; dialog/picker searches keep the rounded-lg Input - dialog.tsx 8px -> 12px, matching SettingsModal/slide-over/CommandPalette - ContextPicker chips at the shared h-8 toolbar height - ~300 rounded-md / bare rounded call sites remapped by role; auth icon tiles and the mobile nav sheet come down from 16px to 12px - rounded-md, bare rounded, rounded-2xl and rounded-[Npx] are dead vocabulary, enforced by a new off-ladder-radius check in check:guards Verified: lint 0 errors, 14422 unit tests pass, check:guards green, tsc clean on all changed files, sandbox screenshots of transactions/ bookkeeping/granskning toolbars and the Ny verifikation dialog. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
93 lines
3.7 KiB
TypeScript
93 lines
3.7 KiB
TypeScript
'use client'
|
|
|
|
import { usePathname } from 'next/navigation'
|
|
import { Skeleton } from '@/components/ui/skeleton'
|
|
|
|
/**
|
|
* Shared loading fallback for the dashboard segment. It is the Suspense
|
|
* fallback for Hem (app/(dashboard)/page.tsx) and for every child route that
|
|
* has no loading.tsx of its own, so it deliberately mirrors Hem's silhouette:
|
|
* a greeting hero (H1 + date line) followed by a single "Att göra"-style pane
|
|
* of list rows (see DashboardContent / AttGoraSection).
|
|
*
|
|
* A greeting + hairline-separated rows reads honestly on Hem and stays neutral
|
|
* on the plain list pages that fall back here (a page title + rows), which is
|
|
* why it is not shaped like any one page's specific grid.
|
|
*
|
|
* /chat is the exception: MainContainer renders it full-bleed (no max-width,
|
|
* no padding), so the column silhouette would stretch edge-to-edge and read
|
|
* broken. The chat branch mirrors the two-pane chat shell instead:
|
|
* conversation sidebar + empty conversation pane (see ChatLayout/ChatSidebar).
|
|
*/
|
|
export default function DashboardLoading() {
|
|
const pathname = usePathname()
|
|
|
|
if (pathname.startsWith('/chat')) {
|
|
return (
|
|
<div className="flex h-full">
|
|
{/* Desktop mounts ChatSidebar COLLAPSED (a 48px rail), so the skeleton
|
|
must be a rail too: a 320px skeleton that snapped to 48px on hydrate
|
|
was a visible layout jump on every /chat load. Mobile mounts the
|
|
full-width list, so that shape stays there. */}
|
|
<aside className="hidden md:flex md:w-12 shrink-0 flex-col items-center border-r border-border bg-card/40 py-3 gap-2">
|
|
<Skeleton className="h-8 w-8 rounded-full" />
|
|
<Skeleton className="h-8 w-8" />
|
|
</aside>
|
|
<aside className="flex w-full flex-col border-r border-border bg-card/40 md:hidden shrink-0">
|
|
<div className="space-y-3 border-b border-border px-5 py-4">
|
|
<div className="flex items-center gap-2">
|
|
<Skeleton className="h-8 w-8 shrink-0 rounded-full" />
|
|
<div className="flex-1 space-y-1.5">
|
|
<Skeleton className="h-4 w-28" />
|
|
<Skeleton className="h-2.5 w-20" />
|
|
</div>
|
|
</div>
|
|
<Skeleton className="h-8 w-full" />
|
|
</div>
|
|
<div className="space-y-1 p-3">
|
|
{['w-40', 'w-48', 'w-36', 'w-44'].map((w, i) => (
|
|
<div key={i} className="space-y-1.5 px-2 py-2.5">
|
|
<Skeleton className={`h-3.5 ${w}`} />
|
|
<Skeleton className="h-2.5 w-24" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
</aside>
|
|
<div className="hidden min-w-0 flex-1 bg-background md:block" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-8">
|
|
{/* Greeting hero (title + date line) */}
|
|
<section>
|
|
<Skeleton className="h-7 w-52" />
|
|
<Skeleton className="mt-2 h-3.5 w-64" />
|
|
</section>
|
|
|
|
{/* Single pane: header over a hairline, then list rows */}
|
|
<section>
|
|
<div className="flex items-baseline justify-between border-b border-border px-1 pb-2.5">
|
|
<Skeleton className="h-4 w-24" />
|
|
<Skeleton className="h-3 w-16" />
|
|
</div>
|
|
|
|
<Skeleton className="ml-1 mt-5 mb-1 h-2.5 w-20" />
|
|
<div>
|
|
{['w-44', 'w-52', 'w-40', 'w-48', 'w-44'].map((w, i) => (
|
|
<div
|
|
key={i}
|
|
className="flex items-start gap-3 border-b border-border px-1 py-3.5"
|
|
>
|
|
<Skeleton className="mt-px h-[15px] w-[15px] shrink-0" />
|
|
<Skeleton className={`h-3.5 ${w}`} />
|
|
<Skeleton className="ml-auto h-5 w-7 shrink-0 rounded-full" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
)
|
|
}
|