create-freakpunch 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -3
- package/bin/create-freakpunch.mjs +227 -0
- package/files/README.md +19 -0
- package/files/app.config.ts +50 -0
- package/files/locales.ts +10 -0
- package/files/registry.ts +17 -0
- package/package.json +23 -6
- package/template/.dockerignore +17 -0
- package/template/.oxlintrc.json +9 -0
- package/template/AGENTS.md +6 -0
- package/template/BACKEND.md +108 -0
- package/template/CLAUDE.md +297 -0
- package/template/Dockerfile +19 -0
- package/template/_gitignore +26 -0
- package/template/components.json +27 -0
- package/template/design/COMPONENTS.md +145 -0
- package/template/design/DESIGN.md +212 -0
- package/template/design/PATTERNS.md +110 -0
- package/template/index.html +25 -0
- package/template/nginx.conf +32 -0
- package/template/package-lock.json +6484 -0
- package/template/package.json +51 -0
- package/template/public/favicon.svg +1 -0
- package/template/public/robots.txt +2 -0
- package/template/src/app.config.ts +50 -0
- package/template/src/app.roles.ts +24 -0
- package/template/src/components/ui/alert-dialog.tsx +181 -0
- package/template/src/components/ui/avatar.tsx +116 -0
- package/template/src/components/ui/badge.tsx +57 -0
- package/template/src/components/ui/breadcrumb.tsx +130 -0
- package/template/src/components/ui/button.tsx +58 -0
- package/template/src/components/ui/calendar.tsx +277 -0
- package/template/src/components/ui/card.tsx +99 -0
- package/template/src/components/ui/chart.tsx +370 -0
- package/template/src/components/ui/checkbox.tsx +28 -0
- package/template/src/components/ui/combobox.tsx +329 -0
- package/template/src/components/ui/command.tsx +191 -0
- package/template/src/components/ui/dialog.tsx +162 -0
- package/template/src/components/ui/dropdown-menu.tsx +271 -0
- package/template/src/components/ui/empty.tsx +103 -0
- package/template/src/components/ui/field.tsx +236 -0
- package/template/src/components/ui/input-group.tsx +263 -0
- package/template/src/components/ui/input.tsx +45 -0
- package/template/src/components/ui/kbd.tsx +31 -0
- package/template/src/components/ui/label.tsx +17 -0
- package/template/src/components/ui/pagination.tsx +134 -0
- package/template/src/components/ui/popover.tsx +87 -0
- package/template/src/components/ui/radio-group.tsx +35 -0
- package/template/src/components/ui/select.tsx +204 -0
- package/template/src/components/ui/separator.tsx +25 -0
- package/template/src/components/ui/sheet.tsx +139 -0
- package/template/src/components/ui/sidebar.tsx +741 -0
- package/template/src/components/ui/skeleton.tsx +13 -0
- package/template/src/components/ui/sonner.tsx +78 -0
- package/template/src/components/ui/spinner.tsx +42 -0
- package/template/src/components/ui/switch.tsx +29 -0
- package/template/src/components/ui/table.tsx +121 -0
- package/template/src/components/ui/tabs.tsx +191 -0
- package/template/src/components/ui/textarea.tsx +17 -0
- package/template/src/components/ui/toggle-group.tsx +94 -0
- package/template/src/components/ui/toggle.tsx +48 -0
- package/template/src/components/ui/tooltip.tsx +91 -0
- package/template/src/core/api/demo.ts +8 -0
- package/template/src/core/api/http.ts +76 -0
- package/template/src/core/api/mock.ts +88 -0
- package/template/src/core/api/rest.ts +67 -0
- package/template/src/core/api/types.ts +21 -0
- package/template/src/core/audit/audit.service.ts +94 -0
- package/template/src/core/audit/hooks.ts +19 -0
- package/template/src/core/auth/auth-store.ts +52 -0
- package/template/src/core/auth/auth.service.ts +86 -0
- package/template/src/core/auth/can.tsx +39 -0
- package/template/src/core/auth/dev-role-switcher.tsx +64 -0
- package/template/src/core/auth/local-credentials.ts +46 -0
- package/template/src/core/auth/permissions.ts +115 -0
- package/template/src/core/auth/require-auth.tsx +16 -0
- package/template/src/core/auth/require-permission.tsx +24 -0
- package/template/src/core/auth/roles.ts +9 -0
- package/template/src/core/auth/types.ts +20 -0
- package/template/src/core/auth/use-auth.ts +19 -0
- package/template/src/core/company/company.service.ts +94 -0
- package/template/src/core/company/hooks.ts +40 -0
- package/template/src/core/company/password-policy.ts +40 -0
- package/template/src/core/company/types.ts +46 -0
- package/template/src/core/company/use-app-name.ts +7 -0
- package/template/src/core/components/button-link.tsx +14 -0
- package/template/src/core/components/confirm-dialog.tsx +116 -0
- package/template/src/core/components/data-table/data-table.tsx +297 -0
- package/template/src/core/components/data-table/features.ts +24 -0
- package/template/src/core/components/data-table/table-header-cell.tsx +13 -0
- package/template/src/core/components/data-table/toolbar.tsx +100 -0
- package/template/src/core/components/data-table/use-list-url-state.ts +108 -0
- package/template/src/core/components/date-picker.tsx +71 -0
- package/template/src/core/components/file-attachments.tsx +84 -0
- package/template/src/core/components/form-error.tsx +9 -0
- package/template/src/core/components/form-page.tsx +93 -0
- package/template/src/core/components/image-upload.tsx +86 -0
- package/template/src/core/components/page.tsx +75 -0
- package/template/src/core/components/phone-input.tsx +58 -0
- package/template/src/core/components/search-select.tsx +57 -0
- package/template/src/core/components/segmented.tsx +41 -0
- package/template/src/core/components/states.tsx +97 -0
- package/template/src/core/components/status-badge.tsx +26 -0
- package/template/src/core/components/user-avatar.tsx +23 -0
- package/template/src/core/config/runtime.ts +16 -0
- package/template/src/core/config/types.ts +37 -0
- package/template/src/core/i18n/i18n.ts +69 -0
- package/template/src/core/i18n/i18next.d.ts +12 -0
- package/template/src/core/i18n/keys.ts +37 -0
- package/template/src/core/i18n/language-switcher.tsx +45 -0
- package/template/src/core/i18n/types.ts +17 -0
- package/template/src/core/i18n/use-format.ts +31 -0
- package/template/src/core/layout/app-shell.tsx +50 -0
- package/template/src/core/layout/app-sidebar.tsx +285 -0
- package/template/src/core/layout/command-menu.tsx +117 -0
- package/template/src/core/layout/top-bar.tsx +100 -0
- package/template/src/core/lib/csv.ts +27 -0
- package/template/src/core/lib/format.ts +87 -0
- package/template/src/core/lib/phone.ts +50 -0
- package/template/src/core/lib/storage.ts +27 -0
- package/template/src/core/modules/lazy-page.ts +9 -0
- package/template/src/core/modules/navigation.ts +39 -0
- package/template/src/core/modules/types.ts +55 -0
- package/template/src/core/notifications/hooks.ts +84 -0
- package/template/src/core/notifications/notification-center.tsx +251 -0
- package/template/src/core/notifications/notifications.service.ts +132 -0
- package/template/src/core/notifications/types.ts +70 -0
- package/template/src/core/preferences/preferences-store.ts +70 -0
- package/template/src/core/setup/setup-gate.tsx +20 -0
- package/template/src/core/setup/setup.service.ts +101 -0
- package/template/src/core/theme/brand-context.tsx +53 -0
- package/template/src/core/theme/brand.ts +29 -0
- package/template/src/core/theme/theme-context.tsx +62 -0
- package/template/src/core/theme/theme-options.ts +8 -0
- package/template/src/core/theme/theme-toggle.tsx +45 -0
- package/template/src/core/users/hooks.ts +51 -0
- package/template/src/core/users/types.ts +37 -0
- package/template/src/core/users/users.service.ts +167 -0
- package/template/src/hooks/use-mobile.ts +19 -0
- package/template/src/index.css +321 -0
- package/template/src/lib/utils.ts +1 -0
- package/template/src/locales/en/account.ts +180 -0
- package/template/src/locales/en/auth.ts +18 -0
- package/template/src/locales/en/common.ts +151 -0
- package/template/src/locales/en/company.ts +380 -0
- package/template/src/locales/en/dashboard.ts +46 -0
- package/template/src/locales/en/errors.ts +18 -0
- package/template/src/locales/en/notifications.ts +43 -0
- package/template/src/locales/en/settings.ts +25 -0
- package/template/src/locales/en/setup.ts +45 -0
- package/template/src/locales/index.ts +58 -0
- package/template/src/locales/tr/account.ts +184 -0
- package/template/src/locales/tr/auth.ts +22 -0
- package/template/src/locales/tr/common.ts +154 -0
- package/template/src/locales/tr/company.ts +384 -0
- package/template/src/locales/tr/dashboard.ts +50 -0
- package/template/src/locales/tr/errors.ts +22 -0
- package/template/src/locales/tr/notifications.ts +47 -0
- package/template/src/locales/tr/settings.ts +29 -0
- package/template/src/locales/tr/setup.ts +49 -0
- package/template/src/main.tsx +16 -0
- package/template/src/modules/locales.ts +10 -0
- package/template/src/modules/registry.ts +17 -0
- package/template/src/pages/dashboard/dashboard-page.tsx +55 -0
- package/template/src/pages/dashboard/quick-actions.tsx +37 -0
- package/template/src/pages/login-page.tsx +152 -0
- package/template/src/pages/no-access-page.tsx +11 -0
- package/template/src/pages/not-found-page.tsx +61 -0
- package/template/src/pages/settings/account/account.service.ts +128 -0
- package/template/src/pages/settings/account/components/mock-qr.tsx +50 -0
- package/template/src/pages/settings/account/components/password-strength.tsx +38 -0
- package/template/src/pages/settings/account/components/two-factor-dialog.tsx +140 -0
- package/template/src/pages/settings/account/hooks.ts +73 -0
- package/template/src/pages/settings/account/notifications-page.tsx +103 -0
- package/template/src/pages/settings/account/preferences-page.tsx +157 -0
- package/template/src/pages/settings/account/profile-page.tsx +242 -0
- package/template/src/pages/settings/account/security-page.tsx +364 -0
- package/template/src/pages/settings/account/types.ts +37 -0
- package/template/src/pages/settings/company/audit-log-page.tsx +126 -0
- package/template/src/pages/settings/company/branding-page.tsx +278 -0
- package/template/src/pages/settings/company/components/invite-dialog.tsx +106 -0
- package/template/src/pages/settings/company/components/read-only-notice.tsx +13 -0
- package/template/src/pages/settings/company/danger-zone-page.tsx +127 -0
- package/template/src/pages/settings/company/general-page.tsx +234 -0
- package/template/src/pages/settings/company/integrations/api-keys-panel.tsx +170 -0
- package/template/src/pages/settings/company/integrations/hooks.ts +37 -0
- package/template/src/pages/settings/company/integrations/integrations-page.tsx +57 -0
- package/template/src/pages/settings/company/integrations/integrations.service.ts +153 -0
- package/template/src/pages/settings/company/integrations/settings-forms.tsx +299 -0
- package/template/src/pages/settings/company/integrations/webhooks-panel.tsx +179 -0
- package/template/src/pages/settings/company/modules-page.tsx +65 -0
- package/template/src/pages/settings/company/roles-page.tsx +116 -0
- package/template/src/pages/settings/company/security-policies-page.tsx +164 -0
- package/template/src/pages/settings/company/users-page.tsx +262 -0
- package/template/src/pages/settings/settings-layout.tsx +57 -0
- package/template/src/pages/settings/settings-nav.ts +69 -0
- package/template/src/pages/settings/settings-routes.tsx +49 -0
- package/template/src/pages/setup-page.tsx +387 -0
- package/template/src/providers.tsx +68 -0
- package/template/src/router.tsx +59 -0
- package/template/tools/check-design.mjs +73 -0
- package/template/tools/new-module.mjs +90 -0
- package/template/tools/templates/module/api/__id__.mock.ts.tpl +17 -0
- package/template/tools/templates/module/api/__id__.service.ts.tpl +51 -0
- package/template/tools/templates/module/hooks.ts.tpl +57 -0
- package/template/tools/templates/module/index.ts.tpl +44 -0
- package/template/tools/templates/module/locales/en.ts.tpl +51 -0
- package/template/tools/templates/module/locales/tr.ts.tpl +55 -0
- package/template/tools/templates/module/pages/__id__-detail-page.tsx.tpl +103 -0
- package/template/tools/templates/module/pages/__id__-form-page.tsx.tpl +121 -0
- package/template/tools/templates/module/pages/__id__-list-page.tsx.tpl +234 -0
- package/template/tools/templates/module/types.ts.tpl +32 -0
- package/template/tsconfig.app.json +32 -0
- package/template/tsconfig.json +12 -0
- package/template/tsconfig.node.json +23 -0
- package/template/vite.config.ts +47 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Design system
|
|
2
|
+
|
|
3
|
+
The official design language of this admin panel. Every screen in every project built
|
|
4
|
+
from this template follows it. Components and patterns live in [COMPONENTS.md](COMPONENTS.md) and
|
|
5
|
+
[PATTERNS.md](PATTERNS.md). The single source of truth for values is `src/index.css`.
|
|
6
|
+
|
|
7
|
+
## Principles
|
|
8
|
+
|
|
9
|
+
1. **Minimal, Apple/Revolut-like.** Calm surfaces, generous whitespace, few lines. Remove before adding.
|
|
10
|
+
2. **Black, white, warm grays + one accent.** The brand color is the only hue that decorates. Every
|
|
11
|
+
other color must carry meaning (status, delta, danger).
|
|
12
|
+
3. **No glassmorphism.** No blur, no translucent cards, no gradients on surfaces. Overlays dim the page
|
|
13
|
+
with a flat tint; they never blur it.
|
|
14
|
+
4. **Tokens only.** Colors, radii, shadows, fonts and layout spacing come from CSS variables. A
|
|
15
|
+
component never contains a hex/oklch value, an arbitrary shadow, or a new font.
|
|
16
|
+
5. **Quiet hierarchy.** Hierarchy comes from size, weight and muted text, not from color or borders.
|
|
17
|
+
6. **Same in both themes and both languages.** Every screen works in light and dark, in English and
|
|
18
|
+
Turkish, and from 360px wide up.
|
|
19
|
+
|
|
20
|
+
## Layout: canvas + floating panel
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
┌ canvas (--canvas, warm off-white) ───────────────────────────────┐
|
|
24
|
+
│ sidebar ┌ panel (--background, radius-panel, shadow-panel)┐
|
|
25
|
+
│ (on the canvas) │ top bar: sidebar toggle · breadcrumbs · tools │
|
|
26
|
+
│ │────────────────────────────────────────────────│
|
|
27
|
+
│ ▢ Dashboard │ Page title [actions] │
|
|
28
|
+
│ ▣ Orders ←pill│ description │
|
|
29
|
+
│ │ ┌ card ┐ ┌ card ┐ │
|
|
30
|
+
│ │ └──────┘ └──────┘ │
|
|
31
|
+
│ [user card] └────────────────────────────────────────────────┘
|
|
32
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- The sidebar sits **directly on the canvas** (no background of its own). The page content lives in a
|
|
36
|
+
white **floating panel** inset by `--panel-inset` (8px) with `--radius-panel` (16px),
|
|
37
|
+
`--shadow-panel` and a 1px `ring-border`. The panel scrolls internally.
|
|
38
|
+
- Inside the panel: top bar `--topbar-height` (52px), then content padded with `--page-gutter` (24px,
|
|
39
|
+
16px on mobile via `--page-gutter-mobile`) and capped at `--page-max-width` (80rem), centered.
|
|
40
|
+
- Below `md` the sidebar becomes a sheet and the panel fills the screen without inset or radius.
|
|
41
|
+
- Full-screen pages outside the app (landing, login, 404) sit on the canvas; a single centered card
|
|
42
|
+
(login) uses `--radius-panel` and `--shadow-panel`.
|
|
43
|
+
|
|
44
|
+
## Typography
|
|
45
|
+
|
|
46
|
+
| Use | Font | Classes |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| Everything | Inter Variable (`font-sans`) | default |
|
|
49
|
+
| Page title (h1) | Inter, 24px semibold, tight | `text-2xl font-semibold tracking-tight` |
|
|
50
|
+
| Section title (h2 inside a form/settings section) | Inter 14px medium | `text-sm font-medium` |
|
|
51
|
+
| Body | Inter 14px | `text-sm` |
|
|
52
|
+
| Secondary text, descriptions | Inter 13px, muted | `text-xs text-muted-foreground` / `text-sm text-muted-foreground` |
|
|
53
|
+
| Card/sidebar eyebrows, table headers | Inter 11px medium, uppercase, tracked, muted | `label-caps` |
|
|
54
|
+
| Numbers, IDs, SKUs, timestamps | Inter with tabular figures | `tabular-nums` |
|
|
55
|
+
| KPI values | Inter 24px semibold, tabular | `text-2xl font-semibold tracking-tight tabular-nums` |
|
|
56
|
+
|
|
57
|
+
- **Inter is the only font.** There is no monospace face: `font-mono` is disabled in `@theme`, and
|
|
58
|
+
`code`/`kbd`/`pre` inherit Inter. Do not add fonts.
|
|
59
|
+
- The type scale (`text-2xs` 12px, `text-xs` 13px, `text-sm` 14px … `text-7xl`) and letter spacing are
|
|
60
|
+
tuned in `@theme inline`; use the scale, not arbitrary sizes. Exceptions already in the codebase
|
|
61
|
+
(`text-[13px]` nav items, `text-[10.5px]`/`text-[11px]` small meta) are the only allowed ones.
|
|
62
|
+
- Uppercase `label-caps` is for **short labels only** (one to three words), never for sentences.
|
|
63
|
+
Numbers that line up (tables, KPIs, counters, times) use `tabular-nums`.
|
|
64
|
+
- Headings use sentence case ("New order", not "New Order"), in both languages.
|
|
65
|
+
|
|
66
|
+
## Spacing
|
|
67
|
+
|
|
68
|
+
- Tailwind's 4px scale. Common rhythm: `gap-2` (8) inside controls, `gap-4` (16) between cards and
|
|
69
|
+
fields, `gap-6` (24) between page blocks, `p-4`/`p-5`/`p-6` inside cards.
|
|
70
|
+
- Page frame: `Page` stacks header and body with `gap-6`.
|
|
71
|
+
- Form sections: `p-5 md:p-6`, two columns (`16rem` label column + fields) from `md` up.
|
|
72
|
+
- Layout spacing that defines the shell is tokenized: `--panel-inset`, `--page-gutter`,
|
|
73
|
+
`--page-gutter-mobile`, `--page-max-width`, `--topbar-height`.
|
|
74
|
+
|
|
75
|
+
## Radius
|
|
76
|
+
|
|
77
|
+
| Token / class | Value | Use |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| `rounded-md` | 8px | small buttons (`sm`, `icon-sm`), segmented items, menu items |
|
|
80
|
+
| `rounded-lg` | 10px | default buttons, inputs, icon tiles, nav pills |
|
|
81
|
+
| `rounded-xl` = `--radius` | 12px | cards, panels, tables, form cards, controls groups |
|
|
82
|
+
| `rounded-(--radius-panel)` = `rounded-2xl` | 16px | the floating content panel, login card, dialogs |
|
|
83
|
+
| `rounded-full` | — | badges, status dots, avatars, landing pills |
|
|
84
|
+
|
|
85
|
+
Nothing is rounder than 16px except pills and circles.
|
|
86
|
+
|
|
87
|
+
## Shadows (very soft)
|
|
88
|
+
|
|
89
|
+
| Token | Use |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| `shadow-(--shadow-card)` | every card / panel / table on the page |
|
|
92
|
+
| `shadow-(--shadow-raised)` | raised pills: active nav item, segmented selection, workspace/user cards, icon tiles |
|
|
93
|
+
| `shadow-(--shadow-panel)` | the floating content panel, login card |
|
|
94
|
+
| `shadow-(--shadow-popover)` (`shadow-lg`) | menus, popovers, toasts |
|
|
95
|
+
| `shadow-(--shadow-dialog)` (`shadow-xl`) | dialogs and sheets |
|
|
96
|
+
|
|
97
|
+
Shadows are always paired with a 1px hairline (`border` or `ring-1 ring-border`). Never use
|
|
98
|
+
Tailwind's default shadow values directly or invent a new one.
|
|
99
|
+
|
|
100
|
+
## Borders
|
|
101
|
+
|
|
102
|
+
1px hairlines everywhere: `border` (color `--border`), `divide-y` between rows, `ring-1 ring-border`
|
|
103
|
+
for raised elements. Inputs use `--input` / `--field-border`. No 2px borders except focus rings.
|
|
104
|
+
|
|
105
|
+
## Color tokens
|
|
106
|
+
|
|
107
|
+
All colors are defined in `src/index.css` (`:root` for light, `.dark` for dark) and exposed as
|
|
108
|
+
Tailwind utilities through `@theme inline`.
|
|
109
|
+
|
|
110
|
+
### Surfaces
|
|
111
|
+
|
|
112
|
+
| Token | Light | Dark | Use |
|
|
113
|
+
| --- | --- | --- | --- |
|
|
114
|
+
| `bg-canvas` | warm off-white `oklch(0.974 0.004 84.6)` | `oklch(0.155 …)` | app background, sidebar, full-screen pages |
|
|
115
|
+
| `bg-background` | white | `oklch(0.195 …)` | floating content panel |
|
|
116
|
+
| `bg-card` | white | `oklch(0.215 …)` | cards, tables, form cards |
|
|
117
|
+
| `bg-popover` | white | `oklch(0.235 …)` | menus, popovers, toasts |
|
|
118
|
+
| `bg-raised` | white | `oklch(0.26 …)` | raised pills on the canvas or inside fills |
|
|
119
|
+
| `bg-fill-1` … `bg-fill-4` | gray at 5/8/12/16% | white at 4/7/11/15% | subtle fills: table header, icon tiles, segmented track, hover |
|
|
120
|
+
| `bg-muted`, `bg-secondary` | very light warm gray | | rarely; prefer fills |
|
|
121
|
+
|
|
122
|
+
### Text
|
|
123
|
+
|
|
124
|
+
| Token | Use |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `text-foreground` | primary text |
|
|
127
|
+
| `text-muted-foreground` | descriptions, meta, inactive nav, table secondary columns |
|
|
128
|
+
| `text-primary` | brand links and active icons only |
|
|
129
|
+
|
|
130
|
+
### Lines and controls
|
|
131
|
+
|
|
132
|
+
`border` (`--border`), `--input`, `--field`, `--field-border`, `bg-control`, `bg-control-hover`,
|
|
133
|
+
`--control-border` are used by the SortUI controls. You rarely reference them directly.
|
|
134
|
+
|
|
135
|
+
### Brand (the one accent)
|
|
136
|
+
|
|
137
|
+
`--brand` / `--brand-foreground` (default indigo). Derived: `--primary`, `--primary-foreground`,
|
|
138
|
+
`--ring`, `--selection`, `--sidebar-primary`, `--chart-1`. The brand comes from `appConfig.brand`
|
|
139
|
+
and can be overridden in Settings → Company → Branding (stored in `localStorage` `fp:brand`).
|
|
140
|
+
|
|
141
|
+
### Semantic
|
|
142
|
+
|
|
143
|
+
| Token | Light / dark | Meaning |
|
|
144
|
+
| --- | --- | --- |
|
|
145
|
+
| `success` | green | active, healthy, positive delta, successful login |
|
|
146
|
+
| `warning` | amber | needs attention, low stock, invited/pending |
|
|
147
|
+
| `danger` / `destructive` | red | errors, negative delta, destructive actions, failed login |
|
|
148
|
+
| `info` | blue | neutral informational events |
|
|
149
|
+
|
|
150
|
+
### Charts
|
|
151
|
+
|
|
152
|
+
`--chart-1` follows the brand; `--chart-2`…`--chart-10` are muted companions. Single-series charts use
|
|
153
|
+
`--chart-1` only; sparklines use `--muted-foreground`.
|
|
154
|
+
|
|
155
|
+
### Theme scoping
|
|
156
|
+
|
|
157
|
+
Tokens are declared on `:root, .light` and `.dark`, so adding `light` or `dark` to an element forces
|
|
158
|
+
that subtree into a theme regardless of the app theme. Use only for previews that must show a specific
|
|
159
|
+
background (e.g. the logo tiles in Settings → Company → Branding).
|
|
160
|
+
|
|
161
|
+
## When to use the accent
|
|
162
|
+
|
|
163
|
+
Use the brand color for:
|
|
164
|
+
- the primary action on a screen (one default `Button` per view, the rest `outline`/`ghost`),
|
|
165
|
+
- focus rings (`--ring`), text selection,
|
|
166
|
+
- the active nav icon, checked switches/checkboxes/radios, selected states,
|
|
167
|
+
- unread indicators: the notification count badge and unread dots,
|
|
168
|
+
- links inside prose (`text-primary`), chart series 1.
|
|
169
|
+
|
|
170
|
+
Do **not** use it for: backgrounds of cards or sections, headings, large areas, borders around
|
|
171
|
+
content, or as a status color.
|
|
172
|
+
|
|
173
|
+
## When to use semantic colors
|
|
174
|
+
|
|
175
|
+
Only when the color **means something** and always paired with text (never color alone):
|
|
176
|
+
- status dot + label (`StatusBadge`, `StatusDot`),
|
|
177
|
+
- deltas (`text-success` / `text-danger` with an arrow icon),
|
|
178
|
+
- inline warnings like low stock (`text-warning`),
|
|
179
|
+
- destructive buttons and menu items (`variant="destructive"`),
|
|
180
|
+
- the error icon in `ErrorState`, password strength bars.
|
|
181
|
+
|
|
182
|
+
Never tint whole cards or table rows with a semantic color. A danger-zone card uses a neutral card
|
|
183
|
+
with destructive buttons, not a red background.
|
|
184
|
+
|
|
185
|
+
## Utilities
|
|
186
|
+
|
|
187
|
+
- `label-caps`: small uppercase Inter label (eyebrows, table headers, sidebar groups).
|
|
188
|
+
- Table headers: use `TableHeaderCell` (`core/components/data-table/table-header-cell.tsx`), the one
|
|
189
|
+
shared header style (`label-caps`, `h-10`, `bg-fill-1`, outer cells aligned to the card padding).
|
|
190
|
+
- `scrollbar-none`: horizontal scrollers (mobile settings sub-nav, tab lists) stay scrollable
|
|
191
|
+
without a visible bar.
|
|
192
|
+
|
|
193
|
+
## Motion
|
|
194
|
+
|
|
195
|
+
Subtle and fast: SortUI defaults (fade/scale ~150ms), `transition-opacity` for refetching tables, a
|
|
196
|
+
short fade/slide-in when the settings save bar appears.
|
|
197
|
+
Theme switches disable transitions for one frame. No decorative animation.
|
|
198
|
+
|
|
199
|
+
## Icons
|
|
200
|
+
|
|
201
|
+
lucide-react, 16px (`size-4`) in controls and lists, 20px (`size-5`) in empty states and feature
|
|
202
|
+
tiles, `strokeWidth` default (1.75 for large decorative icons). Icon-only buttons always have an
|
|
203
|
+
`aria-label` (translated).
|
|
204
|
+
|
|
205
|
+
## Accessibility
|
|
206
|
+
|
|
207
|
+
- Real links for navigation (`Link`, `ButtonLink`), buttons for actions.
|
|
208
|
+
- Visible focus rings in the brand color; never remove outlines without a replacement.
|
|
209
|
+
- Every control has a label (visible `FieldLabel` or translated `aria-label`).
|
|
210
|
+
- Keyboard: ⌘K / Ctrl K command menu, ⌘B / Ctrl B sidebar toggle, menus and dialogs from SortUI.
|
|
211
|
+
- Color is never the only signal (status dots have labels, deltas have arrows).
|
|
212
|
+
- `<html lang>` follows the active language.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Page patterns
|
|
2
|
+
|
|
3
|
+
Copy the closest existing page instead of starting from scratch. Reference implementations are named
|
|
4
|
+
for each pattern.
|
|
5
|
+
|
|
6
|
+
## List page
|
|
7
|
+
|
|
8
|
+
Reference: the list page `npm run new-module` generates, and `src/pages/settings/company/users-page.tsx`.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
Page title="Orders" description="…" actions={<primary create button>}
|
|
12
|
+
└ DataTable
|
|
13
|
+
├ toolbar: TableSearch · FilterSelect × n · ClearFiltersButton (only when filters are active)
|
|
14
|
+
├ columns: identity column first (icon/avatar + name link + muted sub-line),
|
|
15
|
+
│ status as StatusBadge, numbers right-aligned + tabular, dates muted,
|
|
16
|
+
│ secondary columns hideOnMobile, row actions last (… dropdown)
|
|
17
|
+
├ empty: "no matches" (clear filters) vs "nothing yet" (create action)
|
|
18
|
+
└ footer: counter · rows per page · pager
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- State lives in the URL (`useListUrlState`); pagination/sorting are server-side.
|
|
22
|
+
- The name cell is a real `Link` to the detail page; the row itself is not clickable.
|
|
23
|
+
- Deletion from a row: `useConfirm` → `toast.promise`.
|
|
24
|
+
|
|
25
|
+
## Form page (create / edit)
|
|
26
|
+
|
|
27
|
+
Reference: the form page `npm run new-module` generates.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Page title="New order" description="…"
|
|
31
|
+
└ FormLayout submitLabel onCancel (saveBar="always")
|
|
32
|
+
├ FormSection "Details" — most important fields first, autofocus on create
|
|
33
|
+
├ FormSection "Organization"
|
|
34
|
+
└ FormSection "Pricing & inventory"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- One schema (Zod) shared with the service; messages are translation keys.
|
|
38
|
+
- Default `onSubmit` validation. Submit button disabled while submitting and (in edit) while clean.
|
|
39
|
+
- On success: toast + navigate to the detail page. On error: `toast.error` with the message.
|
|
40
|
+
- Two fields side by side with `grid gap-4 sm:grid-cols-2` only when they are related and short.
|
|
41
|
+
|
|
42
|
+
## Detail page
|
|
43
|
+
|
|
44
|
+
Reference: the detail page `npm run new-module` generates.
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
Page title={name} description={muted id} leading={icon tile} actions={Delete (destructive) · Edit (primary)}
|
|
48
|
+
└ grid lg:grid-cols-3
|
|
49
|
+
├ Panel "Overview" (lg:col-span-2) — prose / main content
|
|
50
|
+
└ Panel "Summary" — dl rows: muted label left, value right
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Loading: `LoadingState`. Errors: `ErrorState` with a "Back to list" `notFoundAction`.
|
|
54
|
+
|
|
55
|
+
## Settings page
|
|
56
|
+
|
|
57
|
+
Reference: `src/pages/settings/` (`settings-layout.tsx`, `account/profile-page.tsx`).
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Settings layout: left sub-navigation (groups "My account", "Company") │ Outlet
|
|
61
|
+
└ Page title="Profile" description="…"
|
|
62
|
+
└ FormLayout saveBar="dirty"
|
|
63
|
+
├ FormSection …
|
|
64
|
+
└ FormSection …
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- Each settings page is its own sub-route (`/app/settings/<page>` or `/app/settings/company/<page>`)
|
|
68
|
+
with a `crumb` and, for company pages, a `permission` in its route handle.
|
|
69
|
+
- The save bar appears only when the form is dirty; Cancel resets to the saved values.
|
|
70
|
+
- Settings that take effect immediately (theme, language) don't use a save bar.
|
|
71
|
+
- Read-only states (e.g. a role without edit permission) disable fields and hide the save bar.
|
|
72
|
+
- Saving company settings records an audit log entry (in the service layer).
|
|
73
|
+
- Toggle lists (notifications): a card with one row per item, label + description on the left,
|
|
74
|
+
switches on the right, column headers in `label-caps`.
|
|
75
|
+
- Danger zone: neutral cards, one per action, each with a title, a description of the consequence and a
|
|
76
|
+
`destructive` button that opens a typed confirmation.
|
|
77
|
+
|
|
78
|
+
## Dashboard
|
|
79
|
+
|
|
80
|
+
Reference: `src/pages/dashboard/dashboard-page.tsx`. KPI grid (4 cards, skeletons while loading) →
|
|
81
|
+
main chart `Panel` + quick actions `Panel` → activity `Panel`. Period switch is a `Segmented` in the
|
|
82
|
+
page actions.
|
|
83
|
+
|
|
84
|
+
## No access / not found
|
|
85
|
+
|
|
86
|
+
`src/pages/no-access-page.tsx`, `src/pages/not-found-page.tsx`: centered `label-caps` code, title,
|
|
87
|
+
one sentence, one outline button back.
|
|
88
|
+
|
|
89
|
+
## Do
|
|
90
|
+
|
|
91
|
+
- Start every screen with `<Page>` and translated `title`/`description`.
|
|
92
|
+
- Use `Panel` / `FormLayout` / `DataTable` for every boxed surface, so radius, border and shadow match.
|
|
93
|
+
- Keep one primary (brand) button per view; put it last in the actions row.
|
|
94
|
+
- Write copy in sentence case, short and specific ("Save changes", "Invite user").
|
|
95
|
+
- Ship every string in EN **and** TR in the same change.
|
|
96
|
+
- Check the screen in light + dark, EN + TR, and at 360px width.
|
|
97
|
+
- Gate actions with permissions (`Can`, route `handle.permission`), and remember UI checks are
|
|
98
|
+
convenience only — the backend enforces security.
|
|
99
|
+
|
|
100
|
+
## Don't
|
|
101
|
+
|
|
102
|
+
- Don't hard-code colors, shadows, radii, fonts or text sizes outside the scale.
|
|
103
|
+
- Don't use blur, glass, gradients on surfaces, or colored card backgrounds.
|
|
104
|
+
- Don't use the brand color for decoration or status; don't use semantic colors without meaning.
|
|
105
|
+
- Don't call `fetch` or mock data from a screen; go through module hooks → service.
|
|
106
|
+
- Don't put navigation in tabs, or actions in links.
|
|
107
|
+
- Don't write user-facing text in components (including `aria-label`, `placeholder`, toasts and
|
|
108
|
+
validation messages); add keys to the locale files.
|
|
109
|
+
- Don't format numbers/dates by hand; use `useFormat()` (locale, timezone and date format aware).
|
|
110
|
+
- Don't add another component library or edit vendored SortUI files.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
8
|
+
<meta name="description" content="Admin panel" />
|
|
9
|
+
<meta name="color-scheme" content="light dark" />
|
|
10
|
+
<title>freakpunch</title>
|
|
11
|
+
<script>
|
|
12
|
+
// Apply the saved theme before first paint (see src/core/theme/theme-context.tsx).
|
|
13
|
+
try {
|
|
14
|
+
var t = JSON.parse(localStorage.getItem('fp:theme') || '"system"')
|
|
15
|
+
var dark = t === 'dark' || (t === 'system' && matchMedia('(prefers-color-scheme: dark)').matches)
|
|
16
|
+
document.documentElement.classList.toggle('dark', dark)
|
|
17
|
+
document.documentElement.style.colorScheme = dark ? 'dark' : 'light'
|
|
18
|
+
} catch (e) {}
|
|
19
|
+
</script>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="root"></div>
|
|
23
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
server {
|
|
2
|
+
listen 80;
|
|
3
|
+
server_name _;
|
|
4
|
+
root /usr/share/nginx/html;
|
|
5
|
+
index index.html;
|
|
6
|
+
|
|
7
|
+
gzip on;
|
|
8
|
+
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
|
|
9
|
+
|
|
10
|
+
# Block search engine indexing on every response
|
|
11
|
+
add_header X-Robots-Tag "noindex, nofollow" always;
|
|
12
|
+
|
|
13
|
+
# Hashed build assets: cache forever
|
|
14
|
+
location /assets/ {
|
|
15
|
+
expires 1y;
|
|
16
|
+
add_header Cache-Control "public, immutable";
|
|
17
|
+
# add_header in a location drops the server-level ones, so repeat it here
|
|
18
|
+
add_header X-Robots-Tag "noindex, nofollow" always;
|
|
19
|
+
try_files $uri =404;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# The app shell must always be revalidated so new deploys show up
|
|
23
|
+
location = /index.html {
|
|
24
|
+
add_header Cache-Control "no-cache";
|
|
25
|
+
add_header X-Robots-Tag "noindex, nofollow" always;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# SPA fallback: deep links like /app/settings load index.html on refresh
|
|
29
|
+
location / {
|
|
30
|
+
try_files $uri $uri/ /index.html;
|
|
31
|
+
}
|
|
32
|
+
}
|