another step just a little remaining
This commit is contained in:
@@ -37,7 +37,20 @@
|
||||
"Bash(node -e \"const n = require\\('c:/Users/Lenovo/Desktop/balinyaar/client/node_modules/notistack'\\); console.log\\(Object.keys\\(n\\)\\)\")",
|
||||
"Bash(Get-ChildItem -Path \"c:\\\\Users\\\\Lenovo\\\\Desktop\\\\balinyaar\\\\client\" -Force)",
|
||||
"Bash(Select-Object Name, PSIsContainer)",
|
||||
"Bash(npm audit *)"
|
||||
"Bash(npm audit *)",
|
||||
"Bash(*)",
|
||||
"Read(*)",
|
||||
"Edit(*)",
|
||||
"Write(*)",
|
||||
"Glob(*)",
|
||||
"Grep(*)",
|
||||
"WebFetch(*)",
|
||||
"WebSearch(*)",
|
||||
"Agent(*)",
|
||||
"NotebookEdit(*)",
|
||||
"Skill(*)",
|
||||
"mcp__claude_ai_Mermaid_Chart__validate_and_render_mermaid_diagram",
|
||||
"Edit(/.claude/skills/frontend-designer/**)"
|
||||
],
|
||||
"defaultMode": "bypassPermissions"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
---
|
||||
name: frontend-designer
|
||||
description: >-
|
||||
Design and build UI for the Balinyaar client (Next.js 16 + MUI v9). Use when
|
||||
creating or restyling any screen, page, component, layout, or visual in
|
||||
client/ — turning a feature, mockup, or Figma design into branded, RTL-aware,
|
||||
dark-mode-ready, i18n-complete React/MUI code. Covers the brand palette,
|
||||
design tokens, typography, the App* component library, layout shells, icons,
|
||||
and the hard rules every Balinyaar UI must follow.
|
||||
---
|
||||
|
||||
# Balinyaar Frontend Designer
|
||||
|
||||
Build UI that looks like Balinyaar and behaves correctly in both locales and both
|
||||
color schemes on the first try. This skill is the design contract; the engineering
|
||||
contract (providers, fetch, cookies, routing) lives in [client/CLAUDE.md](../../../client/CLAUDE.md) — read it
|
||||
before touching layout/provider/data code, **don't restate it**, and never violate it.
|
||||
|
||||
**Stack:** Next.js 16 (App Router, Turbopack) · React 19 · MUI v9 (`@mui/material`) ·
|
||||
Emotion (RTL via `stylis-plugin-rtl`) · next-intl v4 · notistack. Everything below
|
||||
lives under `client/src/`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Brand identity
|
||||
|
||||
Balinyaar is a **trust-first home-nursing marketplace in Iran**. The visual tone is
|
||||
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.
|
||||
|
||||
| Role | Light | Dark |
|
||||
|------|-------|------|
|
||||
| Primary — deep teal | `#1d4a40` | `#6fc0ac` (lifted, readable on dark) |
|
||||
| Secondary — terracotta | `#d98c6a` | `#e6a98a` |
|
||||
| Page surface | `#faf9f5` cream | `#0f1c19` deep teal |
|
||||
| Paper / card | `#ffffff` | `#16302a` teal surface |
|
||||
| Text primary | `#1b2521` ink | `#f3efe9` cream |
|
||||
|
||||
---
|
||||
|
||||
## 2. Design tokens — the two-layer system (read this before styling anything)
|
||||
|
||||
Colors exist in **two mirrored places** that must stay in sync. Pick the right one:
|
||||
|
||||
1. **MUI palette** — `src/theme/colors.ts` (`BRAND`, `LIGHT_PALETTE`, `DARK_PALETTE`).
|
||||
Drives `--mui-palette-*` and all MUI component coloring. Reach it through MUI APIs:
|
||||
`color="primary"`, `sx={{ color: 'text.secondary', bgcolor: 'background.paper' }}`.
|
||||
**This is the default for component styling.** It auto-switches with the color scheme.
|
||||
|
||||
2. **`--bal-*` CSS variables** — `src/theme/tokens.css`, defined under
|
||||
`[data-mui-color-scheme='light'|'dark']`. The source of truth for **custom CSS
|
||||
outside MUI's palette** and for **semantic feedback colors MUI doesn't define**:
|
||||
`--bal-success`, `--bal-error`, `--bal-warning`, `--bal-info` (each `+ -contrast`).
|
||||
Reference as `var(--bal-primary)`, `var(--bal-success-contrast)`, etc.
|
||||
|
||||
**Rules:**
|
||||
- Styling a MUI component → use palette keys (`color="primary"`, `sx` palette refs).
|
||||
- Need success/error/warning/info → use `--bal-*` tokens, **not** MUI defaults — the
|
||||
MUI palette has no semantic colors, and these tokens are brand-harmonized.
|
||||
- Need a custom color in raw CSS → add a `--bal-*` token (in **both** scheme blocks),
|
||||
then `var(--…)`. **Never hard-code a hex** in `sx`, `styled`, or a component.
|
||||
- Adding/changing a color means editing `tokens.css` **and** `colors.ts` together (the
|
||||
file headers call out the sync requirement).
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
re-uppercase button text.
|
||||
- Headings (`h1`–`h6`) use the display font; `h6` is weight 600, the rest 700.
|
||||
- **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.**
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
## 4. The component library — reach for these before raw MUI
|
||||
|
||||
Shared primitives live in `src/components/` (barrel: `@/components`). Prefer the `App*`
|
||||
wrapper over the bare MUI component — the wrappers carry the house defaults.
|
||||
|
||||
| Component | Use for | Notes |
|
||||
|-----------|---------|-------|
|
||||
| `AppButton` | all buttons & button-links | default `variant="contained"`; pass `to`/`href` to render as a link automatically; `startIcon`/`endIcon` accept an **icon name string** (e.g. `startIcon="search"`) or a node; non-MUI `color` strings become text color |
|
||||
| `AppIconButton` | icon-only actions | takes an icon `name`, `title`, `to`/`onClick` |
|
||||
| `AppIcon` | any icon | `icon="home"` by registered name (§6); `size`, `color` props |
|
||||
| `AppLink` | internal/external links | locale-aware Next navigation; default underline `hover` |
|
||||
| `AppAlert` | inline alerts | default `severity="error"`, `variant="filled"` |
|
||||
| `AppImage` | images | wrapper around next/image conventions |
|
||||
| `AppLoading` | loading state | default circular, `primary`, `3rem` |
|
||||
| `ErrorBoundary` | wrapping fault-prone subtrees | already wraps page content in the shell |
|
||||
| `UserInfo` | user avatar/identity block | feature component |
|
||||
|
||||
Defaults for these live in `src/components/config.ts` (`APP_BUTTON_VARIANT`,
|
||||
`APP_ICON_SIZE = 24`, `CONTENT_MAX_WIDTH = 800`, `CONTENT_MIN_WIDTH = 320`, alert/link/
|
||||
loading defaults). Change a default there, not per-call-site.
|
||||
|
||||
For layout/spacing use MUI primitives directly: `Box`, `Stack`, `Container`, `Grid`,
|
||||
`Paper`, `Card`. Use the `spacing`/`sx` system (theme spacing unit = 8px) — never inline
|
||||
pixel margins for rhythm.
|
||||
|
||||
**New shared component?** Put it in `src/components/<Name>/<Name>.tsx` with an
|
||||
`index.tsx` barrel, follow the `App*` prop-spreading + JSDoc style of `AppButton.tsx`,
|
||||
and add a co-located `.test.tsx` (mandatory for anything imported in >1 place — see
|
||||
CLAUDE.md "Unit Testing"; wrap with `<ThemeProvider>`, never mock MUI).
|
||||
|
||||
---
|
||||
|
||||
## 5. Layout & page shells
|
||||
|
||||
- **Private (authenticated) screens** render inside `PrivateLayout` →
|
||||
`TopBarAndSideBarLayout` (`src/layout/`): a `TopBar` + a `SideBar` (variant
|
||||
`sidebarPersistentOnDesktop`: persistent ≥desktop, temporary drawer on mobile) +
|
||||
a dark-mode toggle. Sidebar nav items are `{ title, path, icon }` arrays built with
|
||||
`useTranslations('nav')`. Page content is auto-wrapped in `ErrorBoundary`.
|
||||
- **Public screens** use `PublicLayout`.
|
||||
- Shell dimensions are constants in `src/layout/config.ts` (`SIDE_BAR_WIDTH = 240px`,
|
||||
top-bar `56px` mobile / `64px` desktop, anchors). Respect them; don't hard-code.
|
||||
- A page is `src/app/[locale]/(private|public-routes)/…/page.tsx`. Keep page bodies to
|
||||
composition + content; push reusable visuals into `src/components/`.
|
||||
- Constrain reading width with `CONTENT_MAX_WIDTH` (800) for text-heavy views; full-bleed
|
||||
is fine for dashboards/tables.
|
||||
- Use `useIsMobile()` (`@/hooks`) for responsive branching, or MUI breakpoints in `sx`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Icons
|
||||
|
||||
Icons are a **name registry**, not free imports. `src/components/common/AppIcon/config.ts`
|
||||
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`.
|
||||
|
||||
**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.
|
||||
|
||||
---
|
||||
|
||||
## 7. Non-negotiable rules for every Balinyaar UI
|
||||
|
||||
Every screen/component you produce must satisfy **all** of these:
|
||||
|
||||
1. **i18n — no hard-coded user-facing strings.** Add the key to **both**
|
||||
`messages/en.json` and `messages/fa.json` (keep them in sync; top-level keys are
|
||||
namespaces). Client: `useTranslations(ns)`. Server: `getTranslations(ns)`.
|
||||
2. **RTL-safe.** `fa` is the default locale and is **RTL**. Never use directional
|
||||
hard-coding (`marginLeft`, `left:`, `textAlign: 'left'`) for layout flow — use
|
||||
logical/MUI-flipped props (`ml`→ MUI flips; prefer `marginInlineStart`, `start`/`end`,
|
||||
`sx` shorthand that the RTL Emotion cache mirrors). Test the layout visually at `/fa`.
|
||||
Do **not** pass `flexWrap`/`useFlexGap` as `Stack` props — use `sx={{ flexWrap: 'wrap' }}`.
|
||||
3. **Dark-mode correct.** Pull every color from the palette or `--bal-*` tokens so it
|
||||
switches automatically. Verify on both schemes — never assume a light background.
|
||||
4. **Tokens, not hexes.** No raw color literals in `sx`/`styled`/components (§2).
|
||||
5. **Constants, not magic values.** Cookie names, routes, repeated dimensions, event
|
||||
names → named constants (CLAUDE.md "Constants").
|
||||
6. **Use the wrappers** (§4) and the **icon registry** (§6) before bare MUI.
|
||||
7. **Shared component ⇒ co-located test** (§4).
|
||||
8. **MUI v9 API only.** No v5/v6-era props (e.g. `Stack` `useFlexGap`, `storageWindow`).
|
||||
Avoid deprecated APIs that throw.
|
||||
|
||||
---
|
||||
|
||||
## 8. Workflow: turning a design or feature into a screen
|
||||
|
||||
1. **Locate & scope.** Decide private vs public route; confirm the layout shell. Identify
|
||||
which existing `App*` components and tokens already cover the design.
|
||||
2. **Tokens first.** If the design needs a color/spacing not in the system, add the
|
||||
`--bal-*` token (both schemes) + mirror in `colors.ts` if it's palette-level.
|
||||
3. **Compose with primitives.** Build with `Box`/`Stack`/`Grid`/`Paper` + `App*`
|
||||
wrappers. Keep raw MUI to layout/structural components.
|
||||
4. **Wire copy through i18n.** Every label/placeholder/aria string → both message files.
|
||||
5. **Verify the four axes:** `/fa` (RTL) and `/en` (LTR) × light and dark. The default
|
||||
route is `/fa` — start there.
|
||||
6. **Tests** for any new shared component; **never** add a layout above `[locale]`
|
||||
(breaks locale/dir — see CLAUDE.md).
|
||||
7. Data/fetch/auth/cookies/toasts → follow CLAUDE.md (`serverFetch`/`clientFetch`,
|
||||
`@/lib/cookies/*`, `dispatchToast`/`useSnackbar`). Don't reinvent these.
|
||||
|
||||
---
|
||||
|
||||
## 9. Anti-patterns (design-specific — CLAUDE.md has the full engineering list)
|
||||
|
||||
- Hard-coded hex/rgb in components → use palette keys or `--bal-*` tokens.
|
||||
- MUI default success/error colors for feedback → use `--bal-*` semantic tokens.
|
||||
- `marginLeft`/`left`/`textAlign:'left'` for flow → breaks RTL; use logical props.
|
||||
- Hard-coded English (or any) UI string → add to both message files.
|
||||
- Loading a font in a component/page → fonts live only in `src/app/[locale]/layout.tsx`.
|
||||
- `createTheme()` in a component → use `APP_THEME_LTR`/`APP_THEME_RTL`.
|
||||
- Raw MUI icon where a registry name is expected → register it in `AppIcon/config.ts`.
|
||||
- New shared component without a `.test.tsx`, or mocking MUI in tests.
|
||||
- Re-introducing `src/app/layout.tsx` / any layout above `[locale]`.
|
||||
|
||||
---
|
||||
|
||||
## 10. Design ↔ Figma (optional)
|
||||
|
||||
A Figma MCP is connected. When the user provides a figma.com URL or asks to implement a
|
||||
Figma frame, use the Figma tools (`get_design_context`, `get_screenshot`, `get_metadata`)
|
||||
to pull the design, then map it onto **this** system: translate Figma colors to the
|
||||
nearest `--bal-*`/palette token (don't introduce new hexes unless the design truly adds a
|
||||
brand color), Figma type to `<Typography>` variants, and Figma components to the `App*`
|
||||
library. Follow the Figma plugin skills (`/figma-use`, `/figma-generate-design`) when
|
||||
pushing code back into Figma.
|
||||
|
||||
---
|
||||
|
||||
## Key files
|
||||
|
||||
| Concern | File |
|
||||
|---------|------|
|
||||
| Brand color tokens (CSS) | `client/src/theme/tokens.css` |
|
||||
| MUI palette (mirror) | `client/src/theme/colors.ts` |
|
||||
| Typography & fonts | `client/src/theme/typography.ts` |
|
||||
| Theme factory (shape, schemes, dir) | `client/src/theme/theme.ts` |
|
||||
| Theme provider / RTL cache | `client/src/theme/ThemeProvider.tsx` |
|
||||
| Component library | `client/src/components/` (`@/components`) |
|
||||
| Component defaults | `client/src/components/config.ts` |
|
||||
| Icon registry | `client/src/components/common/AppIcon/config.ts` |
|
||||
| Layout shells | `client/src/layout/` |
|
||||
| Layout dimensions | `client/src/layout/config.ts` |
|
||||
| Messages (i18n) | `client/messages/{en,fa}.json` |
|
||||
| Engineering contract | `client/CLAUDE.md` |
|
||||
Reference in New Issue
Block a user