diff --git a/.cursor/rules/dyolink-overview.mdc b/.cursor/rules/dyolink-overview.mdc index 581523d..08edc17 100644 --- a/.cursor/rules/dyolink-overview.mdc +++ b/.cursor/rules/dyolink-overview.mdc @@ -24,6 +24,8 @@ Monorepo: `backend/` (NestJS + Prisma), `frontend/` (Next.js + next-intl), `infr All user-visible strings: `frontend/messages/en.json`, `fa.json`, `nl.json` — add keys to **all three**. +Dates/times/numbers: `frontend/src/lib/i18n/format.ts` + `useLocale()`. **Form date fields:** `AppDateInput` only (no native ``); wire format `YYYY-MM-DD`. **Filter selects:** `FORM_SELECT_CLASS` from `components/shared/formSelectStyles.ts` (chevron via `globals.css`). **Tables:** `components/ui/shared/Table.tsx` — use `text-start`/`text-end`/`text-center`, never physical `text-left`/`text-right`. Appointments: `ScheduleDayPicker`. Skill: `.cursor/skills/i18n-formatting/SKILL.md`. + ## Treatment / appointment colors Treatment-type colors and labels: `components/shared/treatmentTypeDisplay.ts` + `catalog-type-colors.ts`. UI badges: `components/ui/treatment/TreatmentTypeBadge.tsx`. diff --git a/.cursor/rules/frontend-components.mdc b/.cursor/rules/frontend-components.mdc index 2714891..f338867 100644 --- a/.cursor/rules/frontend-components.mdc +++ b/.cursor/rules/frontend-components.mdc @@ -51,3 +51,14 @@ Reference: `app/.../treatment/page.tsx` + `components/ui/treatment/TreatmentWork 1. Check `components/ui/shared/` for an existing primitive. 2. Check the feature's `ui/{feature}/` folder for an existing pattern. 3. Add i18n keys to en, fa, and nl. + +## Shared form & table primitives + +| Need | Use | +|------|-----| +| Date filter / due date field | `AppDateInput` (`ui/shared/`) — not `` | +| Filter or inline `` filters/fields — `ps-3 pe-10`, chevron from `globals.css` | +| **`FORM_SELECT_COMPACT_CLASS`** | Tiny selects (e.g. sort direction `↓`/`↑`) — symmetric `px-2`, no chevron gutter | +| **`Dropdown`** | Labeled form select — only where already used; prefer `FORM_SELECT_CLASS` for new filters | +| **`CompactSelect`** | Year/month/day sub-selects inside calendar panels | + +**`AppDateInput` behavior** + +- `fa`: Jalali display `YYYY/MM/DD` (Persian digits), parse/mask in `persianCalendar.ts` +- `en` / `nl`: Gregorian display `YYYY-MM-DD`, parse/mask in `dateInputFormat.ts` +- Calendar icon at **`end-3`** (matches select chevron inset); text uses **`text-start`** (logical — right in RTL, left in LTR) +- Popup: **`CalendarDayPartsPanel`** (shared with schedule picker) +- **Do not** add native `` — one component for all locales + +**Select chevron** + +- Defined once in `frontend/src/styles/globals.css` on `.form-select:not(.form-select-no-chevron)` +- RTL: `background-position: left 0.75rem center`; LTR: `right 0.75rem center` +- `text-align: start` on selects + +## Calendar / appointment pickers + +| Component | Use for | +|-----------|---------| +| `ScheduleDayPicker` | Appointments strip — nav arrows + today toggle + expandable panel | +| `CalendarDaySelect` | Navigator wrapper (arrows + panel) | +| `CalendarDayPartsPanel` | Year / month / day row — used by schedule picker and `AppDateInput` | + +Persian (`fa`): Jalali calendar + `arabext` digits via Intl (`usesPersianCalendar`). Internal model stays **`Date` at local midnight** (Gregorian) — APIs unchanged. + +- Conversion: `frontend/src/lib/i18n/persianCalendar.ts` +- Gregorian typing: `frontend/src/lib/i18n/dateInputFormat.ts` +- Gregorian month labels: `schedule.monthJanuary` … message keys + +## RTL + +- `dir` / `lang` on `` from `app/[locale]/layout.tsx` +- `isRtlLocale` in `frontend/src/i18n/routing.ts` +- Use **logical** CSS: `text-start`, `text-end`, `ps-*`, `pe-*`, `ms-*`, `me-*` +- **`Table`**: default `[&_th]:text-start [&_td]:text-start`; override with `text-center` or `text-end` on cells — **never** `text-left` / `text-right` on headers (causes header/body column drift in RTL) +- Minimal overrides in `globals.css` — avoid double-mirroring (no extra `row-reverse` on shells that already inherit `direction: rtl`) + +## i18n strings + +- User-facing copy: `frontend/messages/{en,fa,nl}.json` — all three locales. + +## Verify + +```bash +cd frontend && npx tsc --noEmit +``` + +Manual: switch to Persian — Cases date filters, Tasks filter row (single line + sort visible), Staff/Orgs table columns aligned; switch to English — date fields match adjacent dropdown alignment. diff --git a/AGENTS.md b/AGENTS.md index 7154132..dfe31c4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,6 +38,8 @@ frontend/src/ **Example thin page:** `app/.../treatment/page.tsx` → imports `TreatmentWorkspace` from `components/ui/treatment/`. +**i18n formatting:** Display dates/times/numbers via `lib/i18n/format.ts` + `useLocale()`. Form dates: **`AppDateInput`** (all locales — same component, masked typing + calendar popup). Appointments strip: **`ScheduleDayPicker`**. Filter `