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.
Files changed (216) hide show
  1. package/README.md +24 -3
  2. package/bin/create-freakpunch.mjs +227 -0
  3. package/files/README.md +19 -0
  4. package/files/app.config.ts +50 -0
  5. package/files/locales.ts +10 -0
  6. package/files/registry.ts +17 -0
  7. package/package.json +23 -6
  8. package/template/.dockerignore +17 -0
  9. package/template/.oxlintrc.json +9 -0
  10. package/template/AGENTS.md +6 -0
  11. package/template/BACKEND.md +108 -0
  12. package/template/CLAUDE.md +297 -0
  13. package/template/Dockerfile +19 -0
  14. package/template/_gitignore +26 -0
  15. package/template/components.json +27 -0
  16. package/template/design/COMPONENTS.md +145 -0
  17. package/template/design/DESIGN.md +212 -0
  18. package/template/design/PATTERNS.md +110 -0
  19. package/template/index.html +25 -0
  20. package/template/nginx.conf +32 -0
  21. package/template/package-lock.json +6484 -0
  22. package/template/package.json +51 -0
  23. package/template/public/favicon.svg +1 -0
  24. package/template/public/robots.txt +2 -0
  25. package/template/src/app.config.ts +50 -0
  26. package/template/src/app.roles.ts +24 -0
  27. package/template/src/components/ui/alert-dialog.tsx +181 -0
  28. package/template/src/components/ui/avatar.tsx +116 -0
  29. package/template/src/components/ui/badge.tsx +57 -0
  30. package/template/src/components/ui/breadcrumb.tsx +130 -0
  31. package/template/src/components/ui/button.tsx +58 -0
  32. package/template/src/components/ui/calendar.tsx +277 -0
  33. package/template/src/components/ui/card.tsx +99 -0
  34. package/template/src/components/ui/chart.tsx +370 -0
  35. package/template/src/components/ui/checkbox.tsx +28 -0
  36. package/template/src/components/ui/combobox.tsx +329 -0
  37. package/template/src/components/ui/command.tsx +191 -0
  38. package/template/src/components/ui/dialog.tsx +162 -0
  39. package/template/src/components/ui/dropdown-menu.tsx +271 -0
  40. package/template/src/components/ui/empty.tsx +103 -0
  41. package/template/src/components/ui/field.tsx +236 -0
  42. package/template/src/components/ui/input-group.tsx +263 -0
  43. package/template/src/components/ui/input.tsx +45 -0
  44. package/template/src/components/ui/kbd.tsx +31 -0
  45. package/template/src/components/ui/label.tsx +17 -0
  46. package/template/src/components/ui/pagination.tsx +134 -0
  47. package/template/src/components/ui/popover.tsx +87 -0
  48. package/template/src/components/ui/radio-group.tsx +35 -0
  49. package/template/src/components/ui/select.tsx +204 -0
  50. package/template/src/components/ui/separator.tsx +25 -0
  51. package/template/src/components/ui/sheet.tsx +139 -0
  52. package/template/src/components/ui/sidebar.tsx +741 -0
  53. package/template/src/components/ui/skeleton.tsx +13 -0
  54. package/template/src/components/ui/sonner.tsx +78 -0
  55. package/template/src/components/ui/spinner.tsx +42 -0
  56. package/template/src/components/ui/switch.tsx +29 -0
  57. package/template/src/components/ui/table.tsx +121 -0
  58. package/template/src/components/ui/tabs.tsx +191 -0
  59. package/template/src/components/ui/textarea.tsx +17 -0
  60. package/template/src/components/ui/toggle-group.tsx +94 -0
  61. package/template/src/components/ui/toggle.tsx +48 -0
  62. package/template/src/components/ui/tooltip.tsx +91 -0
  63. package/template/src/core/api/demo.ts +8 -0
  64. package/template/src/core/api/http.ts +76 -0
  65. package/template/src/core/api/mock.ts +88 -0
  66. package/template/src/core/api/rest.ts +67 -0
  67. package/template/src/core/api/types.ts +21 -0
  68. package/template/src/core/audit/audit.service.ts +94 -0
  69. package/template/src/core/audit/hooks.ts +19 -0
  70. package/template/src/core/auth/auth-store.ts +52 -0
  71. package/template/src/core/auth/auth.service.ts +86 -0
  72. package/template/src/core/auth/can.tsx +39 -0
  73. package/template/src/core/auth/dev-role-switcher.tsx +64 -0
  74. package/template/src/core/auth/local-credentials.ts +46 -0
  75. package/template/src/core/auth/permissions.ts +115 -0
  76. package/template/src/core/auth/require-auth.tsx +16 -0
  77. package/template/src/core/auth/require-permission.tsx +24 -0
  78. package/template/src/core/auth/roles.ts +9 -0
  79. package/template/src/core/auth/types.ts +20 -0
  80. package/template/src/core/auth/use-auth.ts +19 -0
  81. package/template/src/core/company/company.service.ts +94 -0
  82. package/template/src/core/company/hooks.ts +40 -0
  83. package/template/src/core/company/password-policy.ts +40 -0
  84. package/template/src/core/company/types.ts +46 -0
  85. package/template/src/core/company/use-app-name.ts +7 -0
  86. package/template/src/core/components/button-link.tsx +14 -0
  87. package/template/src/core/components/confirm-dialog.tsx +116 -0
  88. package/template/src/core/components/data-table/data-table.tsx +297 -0
  89. package/template/src/core/components/data-table/features.ts +24 -0
  90. package/template/src/core/components/data-table/table-header-cell.tsx +13 -0
  91. package/template/src/core/components/data-table/toolbar.tsx +100 -0
  92. package/template/src/core/components/data-table/use-list-url-state.ts +108 -0
  93. package/template/src/core/components/date-picker.tsx +71 -0
  94. package/template/src/core/components/file-attachments.tsx +84 -0
  95. package/template/src/core/components/form-error.tsx +9 -0
  96. package/template/src/core/components/form-page.tsx +93 -0
  97. package/template/src/core/components/image-upload.tsx +86 -0
  98. package/template/src/core/components/page.tsx +75 -0
  99. package/template/src/core/components/phone-input.tsx +58 -0
  100. package/template/src/core/components/search-select.tsx +57 -0
  101. package/template/src/core/components/segmented.tsx +41 -0
  102. package/template/src/core/components/states.tsx +97 -0
  103. package/template/src/core/components/status-badge.tsx +26 -0
  104. package/template/src/core/components/user-avatar.tsx +23 -0
  105. package/template/src/core/config/runtime.ts +16 -0
  106. package/template/src/core/config/types.ts +37 -0
  107. package/template/src/core/i18n/i18n.ts +69 -0
  108. package/template/src/core/i18n/i18next.d.ts +12 -0
  109. package/template/src/core/i18n/keys.ts +37 -0
  110. package/template/src/core/i18n/language-switcher.tsx +45 -0
  111. package/template/src/core/i18n/types.ts +17 -0
  112. package/template/src/core/i18n/use-format.ts +31 -0
  113. package/template/src/core/layout/app-shell.tsx +50 -0
  114. package/template/src/core/layout/app-sidebar.tsx +285 -0
  115. package/template/src/core/layout/command-menu.tsx +117 -0
  116. package/template/src/core/layout/top-bar.tsx +100 -0
  117. package/template/src/core/lib/csv.ts +27 -0
  118. package/template/src/core/lib/format.ts +87 -0
  119. package/template/src/core/lib/phone.ts +50 -0
  120. package/template/src/core/lib/storage.ts +27 -0
  121. package/template/src/core/modules/lazy-page.ts +9 -0
  122. package/template/src/core/modules/navigation.ts +39 -0
  123. package/template/src/core/modules/types.ts +55 -0
  124. package/template/src/core/notifications/hooks.ts +84 -0
  125. package/template/src/core/notifications/notification-center.tsx +251 -0
  126. package/template/src/core/notifications/notifications.service.ts +132 -0
  127. package/template/src/core/notifications/types.ts +70 -0
  128. package/template/src/core/preferences/preferences-store.ts +70 -0
  129. package/template/src/core/setup/setup-gate.tsx +20 -0
  130. package/template/src/core/setup/setup.service.ts +101 -0
  131. package/template/src/core/theme/brand-context.tsx +53 -0
  132. package/template/src/core/theme/brand.ts +29 -0
  133. package/template/src/core/theme/theme-context.tsx +62 -0
  134. package/template/src/core/theme/theme-options.ts +8 -0
  135. package/template/src/core/theme/theme-toggle.tsx +45 -0
  136. package/template/src/core/users/hooks.ts +51 -0
  137. package/template/src/core/users/types.ts +37 -0
  138. package/template/src/core/users/users.service.ts +167 -0
  139. package/template/src/hooks/use-mobile.ts +19 -0
  140. package/template/src/index.css +321 -0
  141. package/template/src/lib/utils.ts +1 -0
  142. package/template/src/locales/en/account.ts +180 -0
  143. package/template/src/locales/en/auth.ts +18 -0
  144. package/template/src/locales/en/common.ts +151 -0
  145. package/template/src/locales/en/company.ts +380 -0
  146. package/template/src/locales/en/dashboard.ts +46 -0
  147. package/template/src/locales/en/errors.ts +18 -0
  148. package/template/src/locales/en/notifications.ts +43 -0
  149. package/template/src/locales/en/settings.ts +25 -0
  150. package/template/src/locales/en/setup.ts +45 -0
  151. package/template/src/locales/index.ts +58 -0
  152. package/template/src/locales/tr/account.ts +184 -0
  153. package/template/src/locales/tr/auth.ts +22 -0
  154. package/template/src/locales/tr/common.ts +154 -0
  155. package/template/src/locales/tr/company.ts +384 -0
  156. package/template/src/locales/tr/dashboard.ts +50 -0
  157. package/template/src/locales/tr/errors.ts +22 -0
  158. package/template/src/locales/tr/notifications.ts +47 -0
  159. package/template/src/locales/tr/settings.ts +29 -0
  160. package/template/src/locales/tr/setup.ts +49 -0
  161. package/template/src/main.tsx +16 -0
  162. package/template/src/modules/locales.ts +10 -0
  163. package/template/src/modules/registry.ts +17 -0
  164. package/template/src/pages/dashboard/dashboard-page.tsx +55 -0
  165. package/template/src/pages/dashboard/quick-actions.tsx +37 -0
  166. package/template/src/pages/login-page.tsx +152 -0
  167. package/template/src/pages/no-access-page.tsx +11 -0
  168. package/template/src/pages/not-found-page.tsx +61 -0
  169. package/template/src/pages/settings/account/account.service.ts +128 -0
  170. package/template/src/pages/settings/account/components/mock-qr.tsx +50 -0
  171. package/template/src/pages/settings/account/components/password-strength.tsx +38 -0
  172. package/template/src/pages/settings/account/components/two-factor-dialog.tsx +140 -0
  173. package/template/src/pages/settings/account/hooks.ts +73 -0
  174. package/template/src/pages/settings/account/notifications-page.tsx +103 -0
  175. package/template/src/pages/settings/account/preferences-page.tsx +157 -0
  176. package/template/src/pages/settings/account/profile-page.tsx +242 -0
  177. package/template/src/pages/settings/account/security-page.tsx +364 -0
  178. package/template/src/pages/settings/account/types.ts +37 -0
  179. package/template/src/pages/settings/company/audit-log-page.tsx +126 -0
  180. package/template/src/pages/settings/company/branding-page.tsx +278 -0
  181. package/template/src/pages/settings/company/components/invite-dialog.tsx +106 -0
  182. package/template/src/pages/settings/company/components/read-only-notice.tsx +13 -0
  183. package/template/src/pages/settings/company/danger-zone-page.tsx +127 -0
  184. package/template/src/pages/settings/company/general-page.tsx +234 -0
  185. package/template/src/pages/settings/company/integrations/api-keys-panel.tsx +170 -0
  186. package/template/src/pages/settings/company/integrations/hooks.ts +37 -0
  187. package/template/src/pages/settings/company/integrations/integrations-page.tsx +57 -0
  188. package/template/src/pages/settings/company/integrations/integrations.service.ts +153 -0
  189. package/template/src/pages/settings/company/integrations/settings-forms.tsx +299 -0
  190. package/template/src/pages/settings/company/integrations/webhooks-panel.tsx +179 -0
  191. package/template/src/pages/settings/company/modules-page.tsx +65 -0
  192. package/template/src/pages/settings/company/roles-page.tsx +116 -0
  193. package/template/src/pages/settings/company/security-policies-page.tsx +164 -0
  194. package/template/src/pages/settings/company/users-page.tsx +262 -0
  195. package/template/src/pages/settings/settings-layout.tsx +57 -0
  196. package/template/src/pages/settings/settings-nav.ts +69 -0
  197. package/template/src/pages/settings/settings-routes.tsx +49 -0
  198. package/template/src/pages/setup-page.tsx +387 -0
  199. package/template/src/providers.tsx +68 -0
  200. package/template/src/router.tsx +59 -0
  201. package/template/tools/check-design.mjs +73 -0
  202. package/template/tools/new-module.mjs +90 -0
  203. package/template/tools/templates/module/api/__id__.mock.ts.tpl +17 -0
  204. package/template/tools/templates/module/api/__id__.service.ts.tpl +51 -0
  205. package/template/tools/templates/module/hooks.ts.tpl +57 -0
  206. package/template/tools/templates/module/index.ts.tpl +44 -0
  207. package/template/tools/templates/module/locales/en.ts.tpl +51 -0
  208. package/template/tools/templates/module/locales/tr.ts.tpl +55 -0
  209. package/template/tools/templates/module/pages/__id__-detail-page.tsx.tpl +103 -0
  210. package/template/tools/templates/module/pages/__id__-form-page.tsx.tpl +121 -0
  211. package/template/tools/templates/module/pages/__id__-list-page.tsx.tpl +234 -0
  212. package/template/tools/templates/module/types.ts.tpl +32 -0
  213. package/template/tsconfig.app.json +32 -0
  214. package/template/tsconfig.json +12 -0
  215. package/template/tsconfig.node.json +23 -0
  216. 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
+ }