docs(design): define typography and dark theme
This commit is contained in:
51
DESIGN.md
51
DESIGN.md
@@ -1,7 +1,7 @@
|
||||
# Design System — ZarinPal Merchant Analytics
|
||||
|
||||
- Status: Draft baseline for approval
|
||||
- Version: 0.2.4
|
||||
- Status: Approved baseline — licensed font assets pending; implementation not yet authorized
|
||||
- Version: 0.3.0
|
||||
- Last updated: 2026-08-20
|
||||
- Direction: Persian-first RTL
|
||||
|
||||
@@ -34,10 +34,39 @@ The authenticated panel screenshots are the primary behavioral reference: fixed
|
||||
|
||||
All text/background pairs must meet WCAG 2.2 AA contrast. Chart palettes require patterns, labels, or shapes in addition to hue.
|
||||
|
||||
### Theme contract
|
||||
|
||||
Light and dark modes are first-class variants of the same semantic token system. Components consume role tokens rather than raw palette values; dark mode is not a color inversion or an after-launch skin.
|
||||
|
||||
| Semantic role | Light | Dark | Notes |
|
||||
|---|---:|---:|---|
|
||||
| `--color-canvas` | `#F1F1F3` | `#0F0F10` | Application workspace |
|
||||
| `--color-surface` | `#FFFFFF` | `#19191A` | Cards, drawers, dialogs |
|
||||
| `--color-surface-muted` | `#F7F7F8` | `#28282A` | Nested panels and table headers |
|
||||
| `--color-text-primary` | `#19191A` | `#FFFFFF` | Primary content |
|
||||
| `--color-text-secondary` | `#3D3D42` | `#D1D1D6` | Supporting content |
|
||||
| `--color-text-muted` | `#6B6B73` | `#A7A7AF` | Metadata; contrast must be verified at actual size |
|
||||
| `--color-border` | `#E3E3E7` | `#3A3A3D` | Dividers and neutral outlines |
|
||||
| `--color-brand-action` | `#0A33FF` | `#90AEF4` | Primary action and active state |
|
||||
| `--color-on-brand` | `#FFFFFF` | `#0A0A0A` | Content on brand action |
|
||||
| `--color-focus-ring` | `#0A33FF` | `#90AEF4` | Keyboard focus |
|
||||
| `--color-semantic-success` | `#248061` | `#6FD6AE` | Positive values with text/icon support |
|
||||
| `--color-semantic-warning` | `#8A5300` | `#F3BE5B` | Caution and incomplete verification |
|
||||
| `--color-semantic-danger` | `#C93637` | `#FF8A8B` | Error and destructive meaning |
|
||||
| `--color-semantic-info` | `#0A33FF` | `#90AEF4` | Informational emphasis |
|
||||
|
||||
- The initial theme follows `prefers-color-scheme` unless the user has explicitly selected light or dark. The explicit choice is persisted locally because it is presentation-only and non-sensitive.
|
||||
- Theme selection is applied before first paint to avoid a light/dark flash. The toggle remains keyboard and screen-reader operable and exposes its current state.
|
||||
- Semantic success, warning, danger, information, chart, hover, pressed, disabled, skeleton, scrim, and elevation tokens have separately tested light/dark values before delivery.
|
||||
- Every data series maintains at least 3:1 non-text contrast against its chart surface. Text maintains WCAG 2.2 AA, and status/trend meaning never depends on color alone.
|
||||
|
||||
### Typography
|
||||
|
||||
- Preferred Persian UI family: a legally distributable Yekan-family webfont if supplied/licensed for this project.
|
||||
- Safe open fallback: `Vazirmatn`, then `Tahoma`, system sans-serif.
|
||||
- Required Persian UI family: licensed **Iran Yekan X Professional** (`IRANYekanX`), matching the current ZarinPal panel's `IRANYekanXVFaNumVF` variable font.
|
||||
- Required asset: the Persian-number (`FaNum`) variable webfont in WOFF2, covering the `wght` axis from 100–1000. The product uses 400 for body/value text, 500 for labels and controls, 600 for emphasis, and 700 for section/page headings. No separate static weights are required when the variable file is supplied.
|
||||
- Purchase/issue the website or software license for this project and domain. Font files are proprietary assets: they must be delivered privately, self-hosted by the frontend, excluded from public-source distribution unless the license explicitly permits it, and never copied from ZarinPal's CDN.
|
||||
- Runtime fallback while the licensed asset is unavailable: `Tahoma`, system sans-serif. The fallback is for resilience, not the approved visual baseline.
|
||||
- Evidence: inspection of the current [ZarinPal panel](https://next.zarinpal.com/beta/panel) found `IRANYekanXVFaNumVF` declared for weights 100–1000. The licensed [Iran Yekan X product page](https://fontiran.com/fonts/iranyekan) identifies the professional package as the option containing all weights, the variable font, Persian-number assets, and WOFF/WOFF2 webfonts.
|
||||
- Use tabular numerals for tables/KPIs where supported.
|
||||
- Body: 14–16 px, line-height 1.7–1.9 for Persian.
|
||||
- Labels/meta: 12–14 px; never below 12 px.
|
||||
@@ -94,6 +123,7 @@ Navigation labels should describe merchant tasks, not internal database concepts
|
||||
## Core component contracts
|
||||
|
||||
- **App shell:** sidebar/drawer, utility header, page title, merchant identity, analytics progress/status. First access idempotently starts a run, then opens its authenticated SSE stream; the page reveals overview, payment performance, fees, and peer comparison independently as each becomes ready.
|
||||
- **Theme control:** accessible light/dark toggle in the utility area, initialized from the persisted choice or system preference and applied without a first-paint flash.
|
||||
- **Metric card:** label, formatted value/unit, comparison and period, semantic trend, definition link, independent queued/calculating/ready/failed states.
|
||||
- **Chart card:** title, period/filter controls, concise takeaway, plot, legend, accessible tabular alternative, provenance link, and section-local loading/error behavior.
|
||||
- **Insight card:** deterministic finding, numeric evidence, suggested merchant action, confidence/limitation; AI-generated copy is visibly labeled later.
|
||||
@@ -112,6 +142,7 @@ Navigation labels should describe merchant tasks, not internal database concepts
|
||||
- Tooltips are keyboard reachable and not the sole location of important values.
|
||||
- Charts have a textual summary and downloadable/visible data table when practical.
|
||||
- Zero, unavailable, suppressed, and not-yet-calculated are visually and linguistically distinct.
|
||||
- A deterministic insight card appears only with at least 100 relevant sessions and a qualifying change: at least 3 percentage points for rates or 20 percent for amounts/counts. Smaller comparisons remain visible in metrics without being promoted into an action claim.
|
||||
- A ready section appears immediately without layout-shifting or blocking on unfinished siblings. Overall progress remains understandable without relying on animation.
|
||||
- Source statuses `Paid` and `Verified` both count as successful bank payments because funds were deducted. Keep them visually distinguishable: `Paid` means merchant verification is incomplete and is an actionable gap; `Verified` is finalized.
|
||||
- Present `fee_amount_rial` as the merchant's real fee, summed once per session. Never multiply it by retry attempts or label it as obfuscated/relative-only in the product.
|
||||
@@ -131,7 +162,9 @@ Navigation labels should describe merchant tasks, not internal database concepts
|
||||
|
||||
- Root UI is `lang="fa" dir="rtl"`.
|
||||
- Technical identifiers, URLs, hashes, and mixed Latin values use isolated LTR spans (`dir="ltr"`) to prevent bidi corruption.
|
||||
- Use `Intl.NumberFormat`/`Intl.DateTimeFormat`. Display merchant-facing dates in the Jalali calendar and `Asia/Tehran`; API instants remain ISO-8601 UTC. Specifications must still choose Persian vs Latin digits and Rial/Toman terminology before implementation.
|
||||
- Merchant-facing numbers, percentages, chart axes, counts, dates, and monetary values use Persian digits through locale-aware formatting (`fa-IR`). Technical identifiers and machine-facing values retain their canonical Latin representation inside isolated LTR spans.
|
||||
- Display money in **Rial only**, with an explicit `ریال` unit. Do not silently convert to Toman or mix the two units.
|
||||
- Use `Intl.NumberFormat`/`Intl.DateTimeFormat`. Display merchant-facing dates in the Jalali calendar and `Asia/Tehran`; API instants remain ISO-8601 UTC.
|
||||
- Do not concatenate translated fragments. Write complete Persian strings with correct نیمفاصله.
|
||||
- Authentication errors must not reveal whether a username exists.
|
||||
|
||||
@@ -149,6 +182,7 @@ Navigation labels should describe merchant tasks, not internal database concepts
|
||||
|
||||
| Version | Date | Decision |
|
||||
|---|---|---|
|
||||
| 0.3.0 | 2026-08-20 | Approved Iran Yekan X Professional FaNum variable typography, Persian digits, Rial-only values, and first-class light/dark semantic themes. Added the deterministic insight eligibility threshold. |
|
||||
| 0.2.4 | 2026-08-20 | Fixed the static-demo default period, comparison fallback, overview KPI priority, and safe read-only drill-down scope; added accurate `NoAttempt`/`InBank` stage language from the CTO data guide. |
|
||||
| 0.2.3 | 2026-08-20 | Kept authentication UX intentionally demo-sized: generic and throttled username/password login now, with a clean replacement boundary for ZarinPal SSO after acceptance. |
|
||||
| 0.2.2 | 2026-08-20 | Defined backend-owned session UX: authentication tokens remain inaccessible to the frontend, and expiry/revocation returns the user to login with a generic, accessible message. |
|
||||
@@ -165,9 +199,6 @@ Navigation labels should describe merchant tasks, not internal database concepts
|
||||
|
||||
Any material token/component/interaction change increments this version and adds a row describing why it changed. A surprising or difficult-to-reverse change also receives an ADR.
|
||||
|
||||
## Open design decisions before approval
|
||||
## Open design decisions before implementation planning
|
||||
|
||||
1. Licensed Yekan-family assets vs open `Vazirmatn` fallback.
|
||||
2. Persian or Latin digits for dashboard values.
|
||||
3. Rial-only vs Toman display and conversion wording.
|
||||
4. Whether a dark theme is required; it is not assumed merely because the public site uses dark feature sections.
|
||||
None. Licensed font-file delivery remains an implementation input, not an unresolved design decision.
|
||||
|
||||
Reference in New Issue
Block a user