ui phase 0
This commit is contained in:
@@ -28,10 +28,24 @@ Balinyaar is a **trust-first home-nursing marketplace in Iran**. The visual tone
|
||||
calm, warm, clinical-but-human — not a cold medical dashboard. Default audience is
|
||||
Persian (RTL); English is secondary.
|
||||
|
||||
**Logo mark** (`product/balinyaar.html` seed deck): deep-teal square, lowercase
|
||||
display glyph in cream, a single terracotta dot. That trio — **teal ground, cream
|
||||
text, terracotta accent** — is the whole identity. Use terracotta sparingly as the
|
||||
single accent; teal carries everything else.
|
||||
**Logo mark** — this skill is the construction source of truth (the original
|
||||
`product/balinyaar.html` seed deck no longer exists in the repo): a deep-teal
|
||||
rounded-square ground (`var(--bal-primary)`), a cream lowercase "b" glyph built
|
||||
from a stem + a ring bowl (`var(--bal-primary-contrast)`), and a single
|
||||
terracotta dot accent (`var(--bal-secondary)`). That trio — **teal ground, cream
|
||||
glyph, terracotta accent** — is the whole identity. Use terracotta sparingly as
|
||||
the single accent; teal carries everything else. Implemented as two SVGs under
|
||||
`components/common/AppIcon/icons/`:
|
||||
- `LogoMark.tsx` — a monochrome `currentColor` version of just the glyph (no
|
||||
ground square), registered as `ICONS.logo`. Use via `<AppIcon icon="logo">`
|
||||
anywhere an inline, recolorable brand glyph is needed.
|
||||
- `LogoLockup.tsx` — the full-color mark (ground + glyph + dot, token-driven so
|
||||
it tracks the color scheme) for `BrandMark` (auth splash). The wordmark next
|
||||
to it stays real, translated `<Typography>` — never bake locale text into an SVG.
|
||||
- The favicon (`src/app/favicon.ico`) and `public/img/favicon/*.png` are
|
||||
rasterized from the same construction (fixed brand hex, not CSS vars — static
|
||||
binary assets are the one place a literal hex is correct). Regenerate with a
|
||||
`sharp`-based script if the mark ever changes; don't hand-edit the PNGs/ICO.
|
||||
|
||||
| Role | Light | Dark |
|
||||
|------|-------|------|
|
||||
@@ -67,21 +81,54 @@ Colors exist in **two mirrored places** that must stay in sync. Pick the right o
|
||||
- Adding/changing a color means editing `tokens.css` **and** `colors.ts` together (the
|
||||
file headers call out the sync requirement).
|
||||
|
||||
**Beyond color** — `tokens.css` also defines non-palette tokens (`colors.ts` never needs
|
||||
these; they're define-only in CSS):
|
||||
- **Radius** — `--bal-radius-sm` (4px, controls: buttons/inputs), `--bal-radius-md`
|
||||
(10px = `theme.shape.borderRadius`, the house default: cards/paper), `--bal-radius-lg`
|
||||
(16px: dialogs). Reference the token/constant, never invent a new radius.
|
||||
- **Elevation** — `--bal-shadow-1/2/3`, teal-tinted (black-teal in dark mode) shadow
|
||||
steps that back `theme.ts`'s `shadows` array — every MUI elevation (Paper, Dialog,
|
||||
Menu, Popover, AppBar) resolves through these, never MUI's default grey stack.
|
||||
- **Motion** — `--bal-motion-fast/base/slow` (120/200/300ms) + `--bal-easing-standard`.
|
||||
Consumed by the phase-12 app-wide motion pass; use them for any transition you add now.
|
||||
- **Focus** — `--bal-focus-ring`, the 2px ring `MuiCssBaseline`'s global `:focus-visible`
|
||||
override uses. Don't hand-roll a focus style; it's already uniform everywhere.
|
||||
- **Rating** — `--bal-rating` / `--bal-rating-empty` (filled/empty star colors) —
|
||||
`RatingInput` uses these, not `--bal-warning`.
|
||||
- **Trust** — `--bal-trust` / `--bal-trust-soft`, a distinct identity (not
|
||||
primary/success) for verified marks — `TrustBadge` and any future verification UI.
|
||||
- **Money emphasis** — `--bal-money-emphasis`, an AA-contrast-safe color for emphasized
|
||||
money text. `--bal-secondary` (terracotta) fails AA contrast at small sizes on light
|
||||
backgrounds — never use it for money text, use this token instead.
|
||||
|
||||
---
|
||||
|
||||
## 3. Typography & fonts
|
||||
|
||||
- `shape.borderRadius: 10` (set in `src/theme/theme.ts`) — the house corner radius.
|
||||
Don't override per-component unless deliberate; prefer multiples that read as related.
|
||||
- Buttons: `textTransform: 'none'`, weight 600 (set globally in `typography.ts`). Never
|
||||
- `shape.borderRadius: 10` (set in `src/theme/theme.ts`) — the house corner radius
|
||||
(= `--bal-radius-md`). Don't override per-component unless deliberate; the radius
|
||||
*scale* is `--bal-radius-sm` (4, controls) / `-md` (10, cards) / `-lg` (16, dialogs).
|
||||
- **Weight system — never write `fontWeight: 600`.** Mikhak and Space Grotesk both load
|
||||
only 400/500/700 (no 600 face), so a requested 600 silently renders full Bold. Use
|
||||
**700** for headings (`h1`–`h6`) and buttons/strong emphasis, **500** for lighter
|
||||
in-text emphasis (subtitles, row labels, chip text). This is enforced globally in
|
||||
`typography.ts`; match it in any new `sx` you write.
|
||||
- Buttons: `textTransform: 'none'`, weight 700 (set globally in `typography.ts`). Never
|
||||
re-uppercase button text.
|
||||
- Headings (`h1`–`h6`) use the display font; `h6` is weight 600, the rest 700.
|
||||
- Persian type scale (`TYPOGRAPHY_RTL`): `letterSpacing: 0` on every variant (Persian is
|
||||
a joined script — tracking breaks glyph connections), body line-height ≥1.7, heading
|
||||
line-height ~1.4–1.5 (room for ascenders/descenders), and `responsiveFontSizes()`
|
||||
wraps both themes (`theme.ts`) so heading sizes scale down on small viewports —
|
||||
don't hand-roll per-breakpoint `fontSize` overrides.
|
||||
- **Fonts are loaded per-locale in `src/app/[locale]/layout.tsx` only** — Mikhak
|
||||
(`--font-mikhak`) for `fa`, system stack for `en` (Space Grotesk `--font-space-grotesk`
|
||||
is declared but not yet wired). **Never load a font in a component or page.**
|
||||
(`--font-mikhak`) for `fa`, **Space Grotesk** (`--font-space-grotesk`, via
|
||||
`next/font/google`, self-hosted at build time) for `en`. Both `preload: false` with a
|
||||
conditional `.variable` className so neither ships to the other locale.
|
||||
**Never load a font in a component or page.**
|
||||
- Use `<Typography variant=…>` for text — it inherits the correct direction-aware family
|
||||
(`TYPOGRAPHY_RTL` = Mikhak everywhere for full Persian glyph coverage; `TYPOGRAPHY_LTR`).
|
||||
Import neither directly in components; let the theme apply them.
|
||||
(`TYPOGRAPHY_RTL` = Mikhak everywhere for full Persian glyph coverage; `TYPOGRAPHY_LTR`
|
||||
= Space Grotesk headings + system-stack body). Import neither directly in components;
|
||||
let the theme apply them.
|
||||
|
||||
---
|
||||
|
||||
@@ -141,13 +188,30 @@ Icons are a **name registry**, not free imports. `src/components/common/AppIcon/
|
||||
maps lowercase names → MUI/SVG components. Render with `<AppIcon icon="home" />` or pass
|
||||
the name to `AppButton`/`AppIconButton` (`icon="search"`).
|
||||
|
||||
Currently registered: `default, logo, close, menu, settings, visibilityon,
|
||||
visibilityoff, daynight, night, day, search, info, home, account, signup, login,
|
||||
logout, notifications, error`.
|
||||
**One visual family: MUI `*Rounded`.** Every registered icon is the `Rounded` variant of
|
||||
`@mui/icons-material` (warmer, softer strokes than the old filled/outlined mix — fits
|
||||
"clinical-but-human"). When adding an icon, import the `*Rounded` version; don't mix in a
|
||||
Filled/Outlined/Sharp/TwoTone icon next to it. ~90 names are registered today, spanning
|
||||
navigation, catalog, verification, booking, payments, admin, and messaging — read
|
||||
`AppIcon/config.ts` directly for the full list rather than duplicating it here (it drifts
|
||||
too fast for a skill doc to track reliably); the two structural rules below don't.
|
||||
|
||||
**Need a new icon:** import it into `config.ts`, add a **lowercase** key to `ICONS`, then
|
||||
reference by that name. Custom SVGs go in `AppIcon/icons/`. An unregistered name logs a
|
||||
warning and falls back to `default` — never pass a raw MUI icon where a name is expected.
|
||||
**`size` actually resizes now.** `AppIcon` drives size via `style.fontSize` (the basis for
|
||||
MUI SvgIcon's internal `1em` sizing) instead of `width`/`height` attributes, which MUI's
|
||||
own CSS used to beat. `<AppIcon icon="verified" size={48} />` renders 48px — no more
|
||||
silent 24px flattening.
|
||||
|
||||
**Directional icons mirror automatically.** Icons authored for LTR that must flip under
|
||||
RTL (`back`, `chevron_start`) are registered in `AppIcon/config.ts`'s `DIRECTIONAL_ICONS`
|
||||
set. `AppIcon` stamps `data-icon-directional` on those, and one CSS rule
|
||||
(`app/globals.css`) does `[dir='rtl'] [data-icon-directional] { transform: scaleX(-1); }`.
|
||||
Adding a new directional icon is a one-line registry addition — never hand-roll a
|
||||
per-component flip.
|
||||
|
||||
**Need a new icon:** import the `*Rounded` version into `config.ts`, add a **lowercase**
|
||||
key to `ICONS`, then reference by that name. Custom SVGs (the brand mark) go in
|
||||
`AppIcon/icons/`. An unregistered name logs a dev-only warning and falls back to
|
||||
`default` — never pass a raw MUI icon where a name is expected.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user