This repository has been archived on 2026-08-11. You can view files and clone it, but cannot push or open issues or pull requests.
Gishen-B2B/docs/features/portal-layout.md
kirukib 3778801ef5 Ship Gishen B2B institutional portal with polished layout and mock-backed flows.
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>
2026-08-06 21:18:23 +03:00

4.3 KiB
Raw Blame History

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

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:

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.

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.*.