Deliver role-aware shell (sidebar, breadcrumbs, quick search, tables, detail/create layouts), locale-ready pages, shared backend/feature docs, and Vercel project config so HR, finance, and members can demo against typed mocks. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
4.3 KiB
Markdown
106 lines
4.3 KiB
Markdown
# Portal layout conventions (Yimaru / Fortune)
|
||
|
||
Shared shell patterns for list, detail, and create pages.
|
||
|
||
**Workspace:** `/Users/kirukib/Desktop/Yaltopia Project/Gishen-B2B`
|
||
|
||
## Components
|
||
|
||
| Piece | Path | Role |
|
||
|-------|------|------|
|
||
| `PageShell` | `src/components/layout/page-shell.tsx` | Full-width page header + content; optional `breadcrumb` |
|
||
| `DetailPageLayout` | `src/components/layout/detail-layout.tsx` | Detail wrapper; **breadcrumbs on by default** |
|
||
| `Breadcrumbs` / `Bc` | `src/components/layout/breadcrumbs.tsx` | Fortune-style trail; locale links via `@/i18n/routing` |
|
||
| `StatCard` / `StatCardGrid` | `src/components/layout/stat-card.tsx` | Flat MakerSys metrics (thin border, brand mint icon well) |
|
||
| `TablePanel` | `src/components/table/table-panel.tsx` | Flat white panel (`rounded-xl`, thin border, no shadow) wrapping toolbar + table |
|
||
| `TableToolbar` | `src/components/table/table-toolbar.tsx` | In-panel search / filter strip (hairline bottom) |
|
||
| `DataTable` | `src/components/table/data-table.tsx` | Column-driven table inside `TablePanel` |
|
||
| Table primitives | `src/components/ui/table.tsx` | Yimaru / Fortune density: muted uppercase headers, `px-4` cells, mint hover |
|
||
|
||
## Breadcrumbs API
|
||
|
||
```tsx
|
||
import { Breadcrumbs, Bc } from "@/components/layout/breadcrumbs";
|
||
import { PageShell } from "@/components/layout/page-shell";
|
||
import { DetailPageLayout } from "@/components/layout/detail-layout";
|
||
|
||
// Detail — breadcrumbs default true
|
||
<DetailPageLayout title="…">…</DetailPageLayout>
|
||
|
||
// Create / nested — opt in
|
||
<PageShell title="…" breadcrumb>…</PageShell>
|
||
|
||
// Custom trail (tests / one-offs)
|
||
<Breadcrumbs items={[{ href: "/", label: "Dashboard" }, { label: "Custom" }]} />
|
||
```
|
||
|
||
### Labels
|
||
|
||
- Static paths and dynamic parents map to `bc.*` keys in `src/messages/en.json` + `am.json`.
|
||
- Path map lives in `PATH_LABEL_KEYS` / `DYNAMIC_PARENT_KEYS` inside `breadcrumbs.tsx`.
|
||
- To extend: add a path key → `bc` message key, then Amharic/English strings.
|
||
|
||
## When to use what
|
||
|
||
| Surface | Stats | Tabs | Breadcrumbs | Width |
|
||
|---------|:-----:|:----:|:-----------:|-------|
|
||
| List dashboards | ✓ metric strip | — | off | full |
|
||
| Detail | metrics + sections | shadcn `Tabs` (line) | on | full |
|
||
| Create / import / nested settings | — | optional | on | full-width form card (no `max-w-*` unless interaction needs it) |
|
||
|
||
## List tables
|
||
|
||
Use the shared panel pattern so every list matches MakerSys / Yimaru:
|
||
|
||
```tsx
|
||
import { TablePanel } from "@/components/table/table-panel";
|
||
import { TableToolbar } from "@/components/table/table-toolbar";
|
||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||
|
||
<TablePanel
|
||
loading={isLoading}
|
||
loadingLabel={t("common.loading")}
|
||
toolbar={
|
||
<TableToolbar
|
||
search={search}
|
||
onSearchChange={setSearch}
|
||
resultCount={filtered.length}
|
||
resultLabel={t("common.results")}
|
||
/>
|
||
}
|
||
>
|
||
<Table>…</Table>
|
||
</TablePanel>
|
||
```
|
||
|
||
Conventions:
|
||
|
||
- **Panel:** `rounded-xl`, `border-border`, white `bg-card`, **no shadow** — do not wrap tables in padded `Card` / `CardContent`.
|
||
- **Header row:** muted background, compact uppercase labels (`text-[11px]`, tracking), `px-4`.
|
||
- **Body:** comfortable `py-4` rows, mint-tinted hover, last row border removed.
|
||
- **Empty / loading:** centered `h-28` empty cell or `TablePanel` `loading` state.
|
||
- **Mobile:** horizontal scroll via the table container (`overflow-x-auto`).
|
||
- **Detail embeds:** prefer `DetailTableSection` (same panel chrome) with flush table primitives.
|
||
|
||
## Tabs
|
||
|
||
Use `@/components/ui/tabs`. Default `TabsList` variant is **line** (Yimaru/Fortune underline). Keep 2–4 sections max.
|
||
|
||
```tsx
|
||
const tTabs = useTranslations("tabs");
|
||
|
||
<Tabs defaultValue="profile" className="w-full">
|
||
<TabsList>
|
||
<TabsTrigger value="profile">{tTabs("profile")}</TabsTrigger>
|
||
</TabsList>
|
||
<TabsContent value="profile" className="space-y-4 pt-1">…</TabsContent>
|
||
</Tabs>
|
||
```
|
||
|
||
Labels live under root `tabs.*` in `en.json` / `am.json` (`profile`, `entitlement`, `dependants`, `clinical`, `rules`, `perks`, `summary`, `errors`, `breakdown`, `contract`, `people`, `spend`, `info`, `basics`). Prefer `useTranslations("tabs")` so missing keys never render as nested `tabs.tabs.*`.
|
||
|
||
## Related docs
|
||
|
||
- [i18n.md](i18n.md) — message files
|
||
- [INDEX.md](INDEX.md) — feature → route map
|