@atlashub/smartstack-cli 4.75.0 → 4.79.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/dist/index.js +87 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/project/claude-md/root.CLAUDE.md.template +1 -1
- package/templates/skills/ai-prompt/SKILL.md +64 -0
- package/templates/skills/ai-prompt/references/ai-agent-modes.md +89 -0
- package/templates/skills/ai-prompt/references/eval-framework.md +129 -0
- package/templates/skills/apex/SKILL.md +2 -2
- package/templates/skills/apex/references/checks/frontend-checks.sh +123 -11
- package/templates/skills/apex/references/checks/seed-checks.sh +81 -7
- package/templates/skills/apex/references/core-seed-data.md +27 -22
- package/templates/skills/apex/references/domain-events-pattern.md +45 -0
- package/templates/skills/apex/references/entity-hooks-pattern.md +68 -0
- package/templates/skills/apex/references/licensing-enforcement.md +52 -0
- package/templates/skills/apex/references/post-checks.md +18 -1
- package/templates/skills/apex/references/smartstack-api.md +116 -5
- package/templates/skills/apex/references/smartstack-frontend.md +1 -1
- package/templates/skills/apex/references/smartstack-layers.md +6 -6
- package/templates/skills/apex/steps/step-00-init.md +1 -1
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +26 -0
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +124 -2
- package/templates/skills/apex/steps/step-04-examine.md +163 -0
- package/templates/skills/apex-verify/SKILL.md +110 -0
- package/templates/skills/apex-verify/references/audit-rules.md +50 -0
- package/templates/skills/apex-verify/steps/step-00-init.md +119 -0
- package/templates/skills/apex-verify/steps/step-01-nav-audit.md +96 -0
- package/templates/skills/apex-verify/steps/step-02-crud-audit.md +127 -0
- package/templates/skills/apex-verify/steps/step-03-perm-audit.md +119 -0
- package/templates/skills/apex-verify/steps/step-04-route-audit.md +98 -0
- package/templates/skills/apex-verify/steps/step-05-report.md +110 -0
- package/templates/skills/application/references/contexts-cheatsheet.md +86 -0
- package/templates/skills/application/references/extensions-system.md +158 -0
- package/templates/skills/application/references/frontend-route-naming.md +7 -5
- package/templates/skills/application/references/frontend-verification.md +7 -5
- package/templates/skills/application/references/provider-template.md +4 -2
- package/templates/skills/application/references/smartstack-provider.md +118 -0
- package/templates/skills/application/references/themes-db-driven.md +484 -0
- package/templates/skills/application/templates-frontend.md +2 -2
- package/templates/skills/application/templates-seed.md +4 -2
- package/templates/skills/audit-route/references/routing-pattern.md +3 -1
- package/templates/skills/business-analyse/SKILL.md +3 -3
- package/templates/skills/business-analyse/_shared.md +37 -0
- package/templates/skills/business-analyse/react/components.md +30 -28
- package/templates/skills/business-analyse/references/03-json-schemas.md +11 -3
- package/templates/skills/business-analyse/references/03-post-check-validation.md +64 -0
- package/templates/skills/business-analyse/references/canonical-json-formats.md +7 -3
- package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
- package/templates/skills/business-analyse/references/validation-checklist.md +5 -5
- package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +15 -4
- package/templates/skills/business-analyse/steps/step-03-specify.md +162 -4
- package/templates/skills/business-analyse/steps/step-04-consolidate.md +211 -1
- package/templates/skills/business-analyse/templates-react.md +15 -15
- package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +3 -0
- package/templates/skills/business-analyse-html/html/ba-interactive.html +198 -16
- package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +64 -0
- package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +80 -11
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-consolidation.js +2 -2
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +6 -3
- package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +46 -0
- package/templates/skills/business-analyse-html/references/02-feature-data-building.md +4 -2
- package/templates/skills/business-analyse-html/references/data-build.md +2 -0
- package/templates/skills/business-analyse-html/references/data-mapping.md +88 -21
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +6 -0
- package/templates/skills/business-analyse-html/steps/step-04-verify.md +92 -3
- package/templates/skills/business-analyse-quick/SKILL.md +807 -0
- package/templates/skills/{sketch → business-analyse-quick}/references/domain-heuristics.md +59 -3
- package/templates/skills/business-analyse-quick/references/prd-schema.md +268 -0
- package/templates/skills/business-analyse-review/references/review-data-mapping.md +6 -0
- package/templates/skills/cli-app-sync/SKILL.md +105 -4
- package/templates/skills/cli-app-sync/references/comparison-map.md +13 -0
- package/templates/skills/cli-app-sync/references/diff-entities.md +162 -0
- package/templates/skills/dev-start/SKILL.md +7 -7
- package/templates/skills/documentation/templates.md +16 -16
- package/templates/skills/migrate/SKILL.md +312 -0
- package/templates/skills/migrate/references/v3.34-to-v3.46.md +289 -0
- package/templates/skills/sketch/SKILL.md +15 -153
- package/templates/skills/smoke-generation/SKILL.md +313 -0
- package/templates/skills/ui-components/SKILL.md +11 -1
- package/templates/skills/ui-components/patterns/data-table.md +1 -1
- package/templates/skills/ui-components/references/component-catalog.md +82 -0
- package/templates/skills/workflow/SKILL.md +70 -1
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# Themes & Branding (DB-driven, Tailwind v4) — Canonical Reference
|
|
2
|
+
|
|
3
|
+
> **Reference for `application`, `ui-components`, `apex` skills** — the COMPLETE token map any generated UI must respect. SmartStack v3.46+ is theme-driven: every color, radius, shadow, and font in a generated component MUST come from one of the CSS variables below. Hardcoded Tailwind colors break dark mode and per-tenant branding.
|
|
4
|
+
|
|
5
|
+
## When This Reference Applies
|
|
6
|
+
|
|
7
|
+
- The client wants several themes (light/dark + custom)
|
|
8
|
+
- The client wants per-tenant branding (logo, favicon, colors)
|
|
9
|
+
- You generate UI code that needs to consume theme tokens
|
|
10
|
+
- The user asks "how do I add a custom theme", "how do I change the logo per tenant", "what about Tailwind colors"
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## TL;DR — 5 canonical rules
|
|
15
|
+
|
|
16
|
+
1. **Always use CSS variables for color/border/radius/shadow.** `bg-[var(--bg-card)]` — not `bg-white`.
|
|
17
|
+
2. **Never use `dark:` prefix.** SmartStack toggles a `.dark` class on `<html>`; CSS vars adapt automatically.
|
|
18
|
+
3. **Status badges use the 4 status token sets** (`--success-*`, `--warning-*`, `--error-*`, `--info-*`).
|
|
19
|
+
4. **Action buttons use the accent tokens** (`--color-accent-50..950` or `--accent-*`).
|
|
20
|
+
5. **Reusable component classes go in `@layer components`** (one definition, not duplicated in every component).
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Section 1 — CSS Variables (canonical token map)
|
|
25
|
+
|
|
26
|
+
All variables are defined on `:root` (light defaults) and overridden by `.dark` for dark mode. They are exported by `@atlashub/smartstack/theme.css` (auto-imported when you import the SDK).
|
|
27
|
+
|
|
28
|
+
### 1.1 Backgrounds
|
|
29
|
+
|
|
30
|
+
| Variable | Light | Dark | Use case |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `--bg-app` | `#fafafa` | `#161618` | App root background, `<body>` |
|
|
33
|
+
| `--bg-primary` | `#ffffff` | `#1c1c1f` | Main containers, cards, page bodies |
|
|
34
|
+
| `--bg-secondary` | `#f4f4f5` | `#232326` | Secondary zones, hover surfaces |
|
|
35
|
+
| `--bg-tertiary` | `#e4e4e7` | `#2a2a2e` | Tertiary layers, distinct from secondary |
|
|
36
|
+
| `--bg-card` | `#ffffff` | `#1c1c1f` | Explicit card wrappers |
|
|
37
|
+
| `--bg-hover` | `#f4f4f5` | `#27272a` | Hover state on surfaces |
|
|
38
|
+
| `--bg-active` | `#e4e4e7` | `#3f3f46` | Active / selected state |
|
|
39
|
+
|
|
40
|
+
### 1.2 Text
|
|
41
|
+
|
|
42
|
+
| Variable | Light | Dark | Use case |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `--text-primary` | `#18181b` | `#e4e4e7` | Body text, headings |
|
|
45
|
+
| `--text-secondary` | `#52525b` | `#a1a1aa` | Subtitles, helper text |
|
|
46
|
+
| `--text-tertiary` | `#71717a` | `#71717a` | Hints, metadata |
|
|
47
|
+
| `--text-muted` | `#a1a1aa` | `#52525b` | Very muted text |
|
|
48
|
+
| `--text-inverse` | `#fafafa` | `#e4e4e7` | Text on dark surface (fallback) |
|
|
49
|
+
|
|
50
|
+
### 1.3 Borders
|
|
51
|
+
|
|
52
|
+
| Variable | Light | Dark | Use case |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `--border-color` | `#e4e4e7` | `#3f3f46` | Standard border |
|
|
55
|
+
| `--border-subtle` | `#f4f4f5` | `#27272a` | Very light divider |
|
|
56
|
+
| `--border-strong` | `#d4d4d8` | `#52525b` | Strong divider |
|
|
57
|
+
| `--border-width` | `1px` | `1px` | Border thickness (overridable per theme) |
|
|
58
|
+
|
|
59
|
+
### 1.4 Status (4 sets — canonical for badges/banners/toasts)
|
|
60
|
+
|
|
61
|
+
| Variable | Light | Dark | Use case |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `--success-bg` | `#f0fdfa` | `rgba(20,184,166,0.15)` | Success badge / banner background |
|
|
64
|
+
| `--success-text` | `#0f766e` | `#5eead4` | Success label text |
|
|
65
|
+
| `--success-border` | `#99f6e4` | `rgba(20,184,166,0.3)` | Success border |
|
|
66
|
+
| `--success-dot` | `#14b8a6` | `#14b8a6` | Status dot (always vivid) |
|
|
67
|
+
| `--warning-bg` | `#fffbeb` | `rgba(245,158,11,0.15)` | Warning bg |
|
|
68
|
+
| `--warning-text` | `#b45309` | `#fbbf24` | Warning text |
|
|
69
|
+
| `--warning-border` | `#fde68a` | `rgba(245,158,11,0.3)` | Warning border |
|
|
70
|
+
| `--warning-dot` | `#f59e0b` | `#f59e0b` | Warning dot |
|
|
71
|
+
| `--error-bg` | `#fff1f2` | `rgba(244,63,94,0.15)` | Error bg |
|
|
72
|
+
| `--error-text` | `#be123c` | `#fb7185` | Error text |
|
|
73
|
+
| `--error-border` | `#fecdd3` | `rgba(244,63,94,0.3)` | Error border |
|
|
74
|
+
| `--error-dot` | `#f43f5e` | `#f43f5e` | Error dot |
|
|
75
|
+
| `--info-bg` | `#f0f9ff` | `rgba(14,165,233,0.15)` | Info bg |
|
|
76
|
+
| `--info-text` | `#0369a1` | `#7dd3fc` | Info text |
|
|
77
|
+
| `--info-border` | `#bae6fd` | `rgba(14,165,233,0.3)` | Info border |
|
|
78
|
+
| `--info-dot` | `#0ea5e9` | `#0ea5e9` | Info dot |
|
|
79
|
+
|
|
80
|
+
### 1.5 Accent (dynamic — set by ThemeContext from `selectedPreset.accentColorKey`)
|
|
81
|
+
|
|
82
|
+
| Variable | Default light (indigo) | Default dark (indigo) | Use case |
|
|
83
|
+
|---|---|---|---|
|
|
84
|
+
| `--color-accent-50` | `#eef2ff` | `#1e1b4b` | Lightest accent (badge bg) |
|
|
85
|
+
| `--color-accent-100` | `#e0e7ff` | `#312e81` | |
|
|
86
|
+
| `--color-accent-200` | `#c7d2fe` | `#3730a3` | |
|
|
87
|
+
| `--color-accent-300` | `#a5b4fc` | `#4338ca` | |
|
|
88
|
+
| `--color-accent-400` | `#818cf8` | `#4f46e5` | |
|
|
89
|
+
| `--color-accent-500` | `#6366f1` | `#6366f1` | Primary accent (icons, links) |
|
|
90
|
+
| `--color-accent-600` | `#4f46e5` | `#818cf8` | Action button bg |
|
|
91
|
+
| `--color-accent-700` | `#4338ca` | `#a5b4fc` | Hover for action button |
|
|
92
|
+
| `--color-accent-800` | `#3730a3` | `#c7d2fe` | |
|
|
93
|
+
| `--color-accent-900` | `#312e81` | `#e0e7ff` | |
|
|
94
|
+
| `--color-accent-950` | `#1e1b4b` | `#eef2ff` | Darkest accent |
|
|
95
|
+
| `--accent-bg` | `#eef2ff` | `rgba(99,102,241,0.15)` | Accent badge / hover background (semantic alias) |
|
|
96
|
+
| `--accent-text` | `#4338ca` | `#a5b4fc` | Accent label text |
|
|
97
|
+
| `--accent-border` | `#c7d2fe` | `rgba(99,102,241,0.3)` | Accent border |
|
|
98
|
+
|
|
99
|
+
### 1.6 Border-radius (overridable per theme)
|
|
100
|
+
|
|
101
|
+
| Variable | Default | Use case |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `--radius-card` | `12px` | Card corners |
|
|
104
|
+
| `--radius-button` | `8px` | Button corners |
|
|
105
|
+
| `--radius-badge` | `8px` | Badge / chip corners |
|
|
106
|
+
| `--radius-input` | `8px` | Input field corners |
|
|
107
|
+
| `--radius-modal` | `16px` | Modal corners |
|
|
108
|
+
| `--radius-menu-item` | `8px` | Sidebar / menu item corners |
|
|
109
|
+
|
|
110
|
+
### 1.7 Item palette (depends on `selectedPreset.itemPaletteKey`)
|
|
111
|
+
|
|
112
|
+
| Variable | neutral light | neutral dark | Use case |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `--item-color-light` | `#ffffff` | `#1c1c1f` | Item lightest tint |
|
|
115
|
+
| `--item-color-medium` | `#f4f4f5` | `#27272a` | Item medium tint |
|
|
116
|
+
| `--item-color-dark` | `#e4e4e7` | `#3f3f46` | Item darkest tint |
|
|
117
|
+
| `--item-color-border` | `#d4d4d8` | `#52525b` | Item border |
|
|
118
|
+
|
|
119
|
+
### 1.8 Typography & shadows
|
|
120
|
+
|
|
121
|
+
| Variable | Default | Use case |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `--font-sans` | `'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif` | Default font stack |
|
|
124
|
+
| `--shadow-sm` | `0 1px 2px 0 rgba(0,0,0,0.05)` | Subtle elevation |
|
|
125
|
+
| `--shadow-md` | `0 4px 6px -1px rgba(0,0,0,0.1)` | Medium elevation |
|
|
126
|
+
| `--shadow-lg` | `0 10px 15px -3px rgba(0,0,0,0.1)` | Large elevation |
|
|
127
|
+
| `--shadow-xl` | `0 20px 25px -5px rgba(0,0,0,0.1)` | Extra-large elevation |
|
|
128
|
+
|
|
129
|
+
### 1.9 Tooltip variants
|
|
130
|
+
|
|
131
|
+
| Variable | Light | Dark | Use case |
|
|
132
|
+
|---|---|---|---|
|
|
133
|
+
| `--tooltip-info-bg` | `#eff6ff` | `#1a2c3b` | Info tooltip bg |
|
|
134
|
+
| `--tooltip-success-bg` | `#f0fdf4` | `#1a3329` | Success tooltip bg |
|
|
135
|
+
| `--tooltip-warning-bg` | `#fefce8` | `#3b2f1a` | Warning tooltip bg |
|
|
136
|
+
| `--tooltip-error-bg` | `#fef2f2` | `#3b1c1e` | Error tooltip bg |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Section 2 — TypeScript tokens
|
|
141
|
+
|
|
142
|
+
### 2.1 `ACCENT_COLORS` (13 palettes)
|
|
143
|
+
|
|
144
|
+
Defined in `web/smartstack-web/src/config/themePresets.ts`. Each palette exposes 11 shades (50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950).
|
|
145
|
+
|
|
146
|
+
**Neutrals:** `slate`, `gray`, `zinc`, `stone`
|
|
147
|
+
**Vibrants:** `indigo` (default primary), `violet`, `blue`, `cyan`, `teal`, `emerald`, `amber`, `orange`, `rose`, `pink`
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
ACCENT_COLORS: Record<string, { name: string; shades: ColorShades }>
|
|
151
|
+
ColorShades = { 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950 }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The user-selected key is stored in `UiPreset.accentColorKey` and applied at runtime by `ThemeContext.applyAccent()`, which writes the 11 shades to `--color-accent-50..950`.
|
|
155
|
+
|
|
156
|
+
### 2.2 `ITEM_PALETTES` (6 palettes)
|
|
157
|
+
|
|
158
|
+
| Key | Label FR | Use case |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| `neutral` | Neutre | Default — CRUD tables, cards |
|
|
161
|
+
| `ocean` | Océan | Soft blues |
|
|
162
|
+
| `forest` | Forêt | Natural greens |
|
|
163
|
+
| `sunset` | Coucher de soleil | Warm oranges/amber |
|
|
164
|
+
| `lavender` | Lavande | Elegant purples |
|
|
165
|
+
| `rose` | Rose | Soft pinks |
|
|
166
|
+
|
|
167
|
+
Each palette ships `light` and `dark` color sets `{ light, medium, dark, border }`.
|
|
168
|
+
|
|
169
|
+
### 2.3 `BORDER_RADIUS_VALUES` (6 presets)
|
|
170
|
+
|
|
171
|
+
| Key | px | Label FR |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| `none` | `0px` | Carré |
|
|
174
|
+
| `small` | `4px` | Léger |
|
|
175
|
+
| `medium` | `8px` | Moyen (default for buttons/badges) |
|
|
176
|
+
| `large` | `12px` | Arrondi (default for cards) |
|
|
177
|
+
| `xlarge` | `16px` | Très arrondi (default for modals) |
|
|
178
|
+
| `xxlarge` | `24px` | Pill |
|
|
179
|
+
|
|
180
|
+
### 2.4 `UiTheme` JSON shape (backend → frontend contract)
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
interface UiTheme {
|
|
184
|
+
backgroundsJson: string; // { app, primary, secondary, tertiary, card, hover, active }
|
|
185
|
+
textColorsJson: string; // { primary, secondary, tertiary, muted, inverse }
|
|
186
|
+
borderColorsJson: string; // { default, subtle, strong, width: number }
|
|
187
|
+
statusColorsJson: string; // { success/warning/error/info: { bg, text, border, dot } }
|
|
188
|
+
defaultBorderRadiusJson: string; // { card, button, badge, input, modal, menuItem }
|
|
189
|
+
defaultAccentColorKey: string; // e.g. "indigo" | hex like "#ff00aa"
|
|
190
|
+
defaultItemPaletteKey: string; // "neutral" | "ocean" | ...
|
|
191
|
+
}
|
|
192
|
+
interface UiPreset {
|
|
193
|
+
accentColorKey: string; // overrides theme.defaultAccentColorKey
|
|
194
|
+
itemPaletteKey: string | null; // overrides theme.defaultItemPaletteKey
|
|
195
|
+
borderRadiusJson: string | null; // overrides theme.defaultBorderRadiusJson
|
|
196
|
+
backgroundOverrideJson: string | null;
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Section 3 — Tailwind v4 setup (mandatory in client projects)
|
|
203
|
+
|
|
204
|
+
### 3.1 `package.json`
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"dependencies": {
|
|
209
|
+
"tailwindcss": "^4.1.18",
|
|
210
|
+
"@tailwindcss/vite": "^4.1.18"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 3.2 `vite.config.ts`
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
219
|
+
import react from '@vitejs/plugin-react';
|
|
220
|
+
import { defineConfig } from 'vite';
|
|
221
|
+
|
|
222
|
+
export default defineConfig({
|
|
223
|
+
plugins: [react(), tailwindcss()],
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 3.3 `index.css` (minimum)
|
|
228
|
+
|
|
229
|
+
```css
|
|
230
|
+
@import "tailwindcss";
|
|
231
|
+
@source "../node_modules/@atlashub/smartstack";
|
|
232
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
233
|
+
|
|
234
|
+
@theme {
|
|
235
|
+
--color-primary-50: #eef2ff;
|
|
236
|
+
--color-primary-100: #e0e7ff;
|
|
237
|
+
/* ... 9 shades total ... */
|
|
238
|
+
--color-primary-950: #1e1b4b;
|
|
239
|
+
|
|
240
|
+
--color-accent-50: #f5f3ff;
|
|
241
|
+
/* ... 9 shades ... */
|
|
242
|
+
--color-accent-950: #2e1065;
|
|
243
|
+
|
|
244
|
+
--font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Then optionally @layer components { .card { ... } } for shared classes */
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
> Tailwind v4 has **no `tailwind.config.ts`** — tokens go in `@theme {}` blocks inside CSS.
|
|
251
|
+
|
|
252
|
+
### 3.4 Dark mode
|
|
253
|
+
|
|
254
|
+
```css
|
|
255
|
+
:root { /* light defaults already declared */ }
|
|
256
|
+
|
|
257
|
+
.dark {
|
|
258
|
+
color-scheme: dark;
|
|
259
|
+
--bg-app: #161618;
|
|
260
|
+
--text-primary: #e4e4e7;
|
|
261
|
+
/* ... overrides for all variables ... */
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Toggle from JS:
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
document.documentElement.classList.toggle('dark', wantDark);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`ThemeContext` does this automatically based on the luminance of `--bg-app` — never write the toggle yourself in components.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Section 4 — className conventions (constated patterns)
|
|
276
|
+
|
|
277
|
+
### Pattern A — Tailwind utility + CSS var (most common)
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
<p className="text-[var(--text-secondary)]">{subtitle}</p>
|
|
281
|
+
<div className="bg-[var(--bg-primary)]/80 backdrop-blur-lg border-b border-[var(--border-color)]" />
|
|
282
|
+
<button className="bg-[var(--color-accent-600)] hover:bg-[var(--color-accent-700)] text-white px-4 py-2 rounded-[var(--radius-button)]">Save</button>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Pattern B — Custom @layer components class
|
|
286
|
+
|
|
287
|
+
```css
|
|
288
|
+
@layer components {
|
|
289
|
+
.card {
|
|
290
|
+
background: var(--bg-card);
|
|
291
|
+
border: 1px solid var(--border-color);
|
|
292
|
+
border-radius: var(--radius-card);
|
|
293
|
+
box-shadow: var(--shadow-sm);
|
|
294
|
+
}
|
|
295
|
+
.badge-success {
|
|
296
|
+
background: var(--success-bg);
|
|
297
|
+
color: var(--success-text);
|
|
298
|
+
border: 1px solid var(--success-border);
|
|
299
|
+
border-radius: var(--radius-badge);
|
|
300
|
+
padding: 0.125rem 0.5rem;
|
|
301
|
+
font-size: 0.75rem;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
<div className="card">...</div>
|
|
308
|
+
<span className="badge-success">OK</span>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Pattern C — Inline style for dynamic gradients
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
const accentGradient: React.CSSProperties = {
|
|
315
|
+
background: 'linear-gradient(to bottom right, var(--color-accent-500), var(--color-accent-600))',
|
|
316
|
+
};
|
|
317
|
+
<div style={accentGradient}>{initials}</div>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Pattern D — Variant mapping (modal/banner color)
|
|
321
|
+
|
|
322
|
+
```tsx
|
|
323
|
+
const VARIANT_CONFIG = {
|
|
324
|
+
danger: { iconColor: 'text-[var(--error-text)]', buttonColor: 'bg-[var(--error-text)] hover:opacity-90', iconBg: 'bg-[var(--error-bg)]' },
|
|
325
|
+
warning: { iconColor: 'text-[var(--warning-text)]', buttonColor: 'bg-[var(--warning-text)] hover:opacity-90', iconBg: 'bg-[var(--warning-bg)]' },
|
|
326
|
+
info: { iconColor: 'text-[var(--info-text)]', buttonColor: 'bg-[var(--color-accent-600)] hover:bg-[var(--color-accent-700)]', iconBg: 'bg-[var(--info-bg)]' },
|
|
327
|
+
};
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Section 5 — Migration map (Tailwind hardcoded → CSS var)
|
|
333
|
+
|
|
334
|
+
Use this table when fixing a generated file that violates the theme.
|
|
335
|
+
|
|
336
|
+
| Hardcoded Tailwind | SmartStack CSS var |
|
|
337
|
+
|---|---|
|
|
338
|
+
| `bg-white` | `bg-[var(--bg-card)]` |
|
|
339
|
+
| `bg-gray-50` | `bg-[var(--bg-primary)]` |
|
|
340
|
+
| `bg-gray-100` | `bg-[var(--bg-secondary)]` |
|
|
341
|
+
| `bg-gray-200` | `bg-[var(--bg-tertiary)]` |
|
|
342
|
+
| `text-gray-900` | `text-[var(--text-primary)]` |
|
|
343
|
+
| `text-gray-700` | `text-[var(--text-secondary)]` |
|
|
344
|
+
| `text-gray-500` | `text-[var(--text-tertiary)]` |
|
|
345
|
+
| `text-gray-400` | `text-[var(--text-muted)]` |
|
|
346
|
+
| `border-gray-200` | `border-[var(--border-color)]` |
|
|
347
|
+
| `border-gray-100` | `border-[var(--border-subtle)]` |
|
|
348
|
+
| `bg-blue-500/10` (info badge) | `bg-[var(--info-bg)]` |
|
|
349
|
+
| `text-blue-600` (info text) | `text-[var(--info-text)]` |
|
|
350
|
+
| `bg-blue-600` (action button) | `bg-[var(--color-accent-600)]` |
|
|
351
|
+
| `text-blue-600` (link) | `text-[var(--color-accent-600)]` |
|
|
352
|
+
| `bg-red-500/10` | `bg-[var(--error-bg)]` |
|
|
353
|
+
| `text-red-500` / `text-red-600` | `text-[var(--error-text)]` |
|
|
354
|
+
| `border-red-500/30` | `border-[var(--error-border)]` |
|
|
355
|
+
| `bg-yellow-500/10` / `bg-amber-500/10` | `bg-[var(--warning-bg)]` |
|
|
356
|
+
| `text-yellow-600` / `text-amber-600` | `text-[var(--warning-text)]` |
|
|
357
|
+
| `bg-green-500/10` | `bg-[var(--success-bg)]` |
|
|
358
|
+
| `text-green-600` | `text-[var(--success-text)]` |
|
|
359
|
+
| `bg-purple-500/10` | `bg-[var(--accent-bg)]` |
|
|
360
|
+
| `text-purple-600` | `text-[var(--accent-text)]` |
|
|
361
|
+
| `dark:bg-gray-900` | (remove — `.dark` class on root drives `--bg-app`) |
|
|
362
|
+
| `dark:text-white` | (remove — CSS vars adapt automatically) |
|
|
363
|
+
|
|
364
|
+
### Status badge recipe (canonical, theme-aware)
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
// success / warning / error / info / accent / neutral — pick one set
|
|
368
|
+
<span className="px-2 py-0.5 rounded text-xs font-medium border bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]">
|
|
369
|
+
Approved
|
|
370
|
+
</span>
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### HTTP method badge recipe (REST conventions)
|
|
374
|
+
|
|
375
|
+
| Method | Token set |
|
|
376
|
+
|---|---|
|
|
377
|
+
| `GET` | `--info-*` |
|
|
378
|
+
| `POST` | `--success-*` |
|
|
379
|
+
| `PUT` | `--warning-*` |
|
|
380
|
+
| `PATCH` | `--accent-*` |
|
|
381
|
+
| `DELETE` | `--error-*` |
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Section 6 — Branding assets (DB-driven)
|
|
386
|
+
|
|
387
|
+
### Architecture (since v3.45)
|
|
388
|
+
|
|
389
|
+
`BrandingAsset` entity stores uploads (logo, favicon) per scope:
|
|
390
|
+
|
|
391
|
+
```csharp
|
|
392
|
+
class BrandingAsset : BaseEntity, IAuditableEntity, IOptionalTenantEntity
|
|
393
|
+
{
|
|
394
|
+
public BrandingAssetType AssetType { get; } // Logo=0, LogoDark=1, Favicon=2
|
|
395
|
+
public BrandingAssetScope Scope { get; } // Platform=0, Tenant=1
|
|
396
|
+
public Guid? TenantId { get; }
|
|
397
|
+
public string StorageFileName { get; } // resolved via IFileStorageService
|
|
398
|
+
public string ContentType { get; }
|
|
399
|
+
public long FileSizeBytes { get; }
|
|
400
|
+
public string OriginalFileName { get; }
|
|
401
|
+
public int? Width { get; }
|
|
402
|
+
public int? Height { get; }
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
`UiTheme` may reference assets via `LogoAssetId`, `LogoDarkAssetId`, `FaviconAssetId` (theme-level overrides).
|
|
407
|
+
|
|
408
|
+
### Built-in seeds (immutable)
|
|
409
|
+
|
|
410
|
+
- `UiThemeSeedData.DarkThemeId` = `f1e8a3d2-4b7c-4e5f-9a2c-6d1b8e4f3c7a`
|
|
411
|
+
- `UiThemeSeedData.LightThemeId` = `c2d9b4e5-3a8f-4c6d-b1e7-5f2c9a8b3d4e`
|
|
412
|
+
|
|
413
|
+
These IDs MUST be referenced by const, never re-generated.
|
|
414
|
+
|
|
415
|
+
### API endpoints
|
|
416
|
+
|
|
417
|
+
| Endpoint | Purpose |
|
|
418
|
+
|---|---|
|
|
419
|
+
| `GET /api/ui/themes` | List effective themes for current user |
|
|
420
|
+
| `GET /api/ui/themes/{id}` | Get one theme |
|
|
421
|
+
| `POST /api/ui/themes` | Create custom theme (admin) |
|
|
422
|
+
| `GET /api/ui/branding/{type}` | Resolve asset for current tenant + assetType |
|
|
423
|
+
| `POST /api/ui/branding` | Upload asset (admin) |
|
|
424
|
+
|
|
425
|
+
The frontend `ThemeContext` calls these at startup and after a tenant switch.
|
|
426
|
+
|
|
427
|
+
### Frontend consumption
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
import { useTheme } from '@atlashub/smartstack';
|
|
431
|
+
|
|
432
|
+
function MyComponent() {
|
|
433
|
+
const { mode, selectedTheme, toggleMode, setTheme } = useTheme();
|
|
434
|
+
// selectedTheme.BackgroundsJson is parsed and applied to :root by ThemeSync.
|
|
435
|
+
// Components only consume var(--xxx) and never read the JSON directly.
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Section 7 — DO / DON'T
|
|
442
|
+
|
|
443
|
+
| ✅ DO | ❌ DON'T |
|
|
444
|
+
|---|---|
|
|
445
|
+
| Read theme via `useTheme()` | Read `localStorage` for theme directly |
|
|
446
|
+
| Use CSS vars (`var(--bg-card)`, `var(--text-primary)`, …) | Hardcode `bg-blue-500`, `text-gray-900`, `bg-white` |
|
|
447
|
+
| Toggle dark mode via `useTheme().toggleMode()` | Use `dark:` Tailwind prefix |
|
|
448
|
+
| Reference `DarkThemeId`/`LightThemeId` as constants | Re-generate the built-in theme GUIDs |
|
|
449
|
+
| Upload branding via `/api/ui/branding` | Replace logo file directly on disk |
|
|
450
|
+
| Use `BrandingAssetScope.Tenant` for per-tenant logos | Hardcode logo path in `App.tsx` |
|
|
451
|
+
| Put reusable component classes in `@layer components` | Duplicate the same className across 10 components |
|
|
452
|
+
| Use status tokens (`--success-*`, …) for badges | Pick a random Tailwind shade per badge |
|
|
453
|
+
| Rely on `IFileStorageService` for asset URLs | Hardcode `/uploads/logo.png` paths |
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## Section 8 — Validation hooks
|
|
458
|
+
|
|
459
|
+
Generated UI MUST pass `apex/references/checks/frontend-checks.sh` (POST-CHECK C9 / C9b / C9c) which now BLOCK on:
|
|
460
|
+
|
|
461
|
+
- `bg|text|border-(red|blue|green|gray|white|black|slate|zinc|neutral|stone|amber|yellow|orange|purple|indigo|violet|cyan|pink|emerald|rose|sky|teal|lime|fuchsia)-\d+` in `.tsx`
|
|
462
|
+
- `dark:` prefix on any utility class
|
|
463
|
+
- Hex colors `#xxxxxx` inside `className=[…]`
|
|
464
|
+
|
|
465
|
+
Before declaring a generation complete, run:
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
bash templates/skills/apex/references/checks/frontend-checks.sh
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Expected: `0 BLOCKING`. If C9 / C9b / C9c trigger, use the migration table in Section 5 to fix.
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Reference source files (read-only — do NOT copy verbatim)
|
|
476
|
+
|
|
477
|
+
- `D:\01 - projets\SmartStack.app\features\IA-Workflow\web\smartstack-web\src\index.css` (CSS vars)
|
|
478
|
+
- `D:\01 - projets\SmartStack.app\features\IA-Workflow\web\smartstack-web\src\base.css` (custom @layer classes)
|
|
479
|
+
- `D:\01 - projets\SmartStack.app\features\IA-Workflow\web\smartstack-web\src\config\themePresets.ts` (ACCENT_COLORS, ITEM_PALETTES, BORDER_RADIUS)
|
|
480
|
+
- `D:\01 - projets\SmartStack.app\features\IA-Workflow\web\smartstack-web\src\contexts\ThemeContext.tsx` (apply* functions)
|
|
481
|
+
- `D:\01 - projets\SmartStack.app\features\IA-Workflow\src\SmartStack.Domain\Platform\Administration\UiConfiguration\UiTheme.cs`
|
|
482
|
+
- `D:\01 - projets\SmartStack.app\features\IA-Workflow\src\SmartStack.Domain\Platform\Administration\UiConfiguration\BrandingAsset.cs`
|
|
483
|
+
|
|
484
|
+
See also [smartstack-provider.md](smartstack-provider.md) for `ThemeProvider` wrapping order, [contexts-cheatsheet.md](contexts-cheatsheet.md) for `useTheme()` API.
|
|
@@ -114,7 +114,7 @@ export function $MODULE_PASCALDetailPage() {
|
|
|
114
114
|
} finally {
|
|
115
115
|
setLoading(false);
|
|
116
116
|
}
|
|
117
|
-
}, [$entityId
|
|
117
|
+
}, [$entityId]);
|
|
118
118
|
|
|
119
119
|
useEffect(() => {
|
|
120
120
|
loadData();
|
|
@@ -239,7 +239,7 @@ export function $MODULE_PASCALEditPage() {
|
|
|
239
239
|
} finally {
|
|
240
240
|
setLoading(false);
|
|
241
241
|
}
|
|
242
|
-
}, [$entityId
|
|
242
|
+
}, [$entityId]);
|
|
243
243
|
|
|
244
244
|
useEffect(() => {
|
|
245
245
|
loadData();
|
|
@@ -804,10 +804,12 @@ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
|
804
804
|
}
|
|
805
805
|
else
|
|
806
806
|
{
|
|
807
|
+
// v3.46+ signature : Zone removed. New flags isOpen + isPersonal at the END (optional, default false).
|
|
807
808
|
app = NavigationApplication.Create(
|
|
808
|
-
|
|
809
|
+
"{app_code}", "{app_label_en}",
|
|
809
810
|
"{app_desc_en}", "{app_icon}", IconType.Lucide,
|
|
810
|
-
"/{app_code}", {display_order}
|
|
811
|
+
"/{app_code}", {display_order},
|
|
812
|
+
isOpen: false, isPersonal: false);
|
|
811
813
|
context.NavigationApplications.Add(app);
|
|
812
814
|
await ((DbContext)context).SaveChangesAsync(ct);
|
|
813
815
|
|
|
@@ -56,7 +56,9 @@ Navigation and permissions are **entirely driven by the database**. The React fr
|
|
|
56
56
|
- Sole routing engine — App.tsx reduced to providers + DynamicRouter
|
|
57
57
|
- Handles: dynamic app routes, feature gating, auto-redirects, outlet tab routes, doc routes
|
|
58
58
|
- `OUTLET_SECTIONS` config for tab-based pages
|
|
59
|
-
- `
|
|
59
|
+
- `IMPLICIT_SUFFIXES` (24 suffixes : `.detail`, `.edit`, `.create`, `.new`, `.duplicate`, `.settings`, `.configure`, `.permissions`, `.members`, `.history`, `.logs`, `.analytics`, `.preview`, `.versions`, `.comments`, `.attachments`, `.audit`, `.export`, `.notifications`, `.schedule`, `.workflow`, `.summary`, `.test`, `.runs`, `.import`) auto-generate child routes (e.g. `/users/:id` for `.detail`) without seeding them in the menu
|
|
60
|
+
- **`mergeRoutes()` and `getStaticAppRoutes()` REMOVED in v3.7+** — clients must register pages via `PageRegistry.register()` only. Legacy migration helpers no longer exist.
|
|
61
|
+
- API-driven `isOpen` flag on each application bypasses permission checks (replaces hardcoded OPEN_APPS list). DTO field on `ApplicationMenuDto`.
|
|
60
62
|
|
|
61
63
|
### 4. useRouteConfig
|
|
62
64
|
|
|
@@ -38,7 +38,7 @@ Path A — FAST (small module, < 5 min) Path B — FULL (multi-module,
|
|
|
38
38
|
│ │
|
|
39
39
|
▼ ▼
|
|
40
40
|
┌──────────────┐ ┌──────────────────┐
|
|
41
|
-
│ /
|
|
41
|
+
│ /business-analyse-quick│ 0-2 questions │ /business-analyse│ ~40 questions
|
|
42
42
|
│ (2 min) │ Pure inference │ (steps 00-04) │ JSON output
|
|
43
43
|
└──────┬───────┘ └────────┬─────────┘
|
|
44
44
|
│ Natural language prompt │ entities/rules/usecases.json
|
|
@@ -84,7 +84,7 @@ Path A — FAST (small module, < 5 min) Path B — FULL (multi-module,
|
|
|
84
84
|
|
|
85
85
|
| From | To | Data | Format |
|
|
86
86
|
|------|----|------|--------|
|
|
87
|
-
| `/
|
|
87
|
+
| `/business-analyse-quick` | `/apex` | Inferred design (entities, FK, labels, code patterns) | Natural language prompt |
|
|
88
88
|
| `/business-analyse` | `/business-analyse-design` | Entities, use cases, permissions | JSON (`entities.json`, `usecases.json`, `permissions.json`) |
|
|
89
89
|
| `/business-analyse-design` | `/business-analyse-html` | Screen specs, wireframes, navigation | JSON (`screens.json`, `navigation.json`) |
|
|
90
90
|
| `/business-analyse-html` | Client | Interactive review document | HTML (`ba-interactive.html`) |
|
|
@@ -104,7 +104,7 @@ Path A — FAST (small module, < 5 min) Path B — FULL (multi-module,
|
|
|
104
104
|
| Cadrage/scope only | `/business-analyse-html` | Just regenerate HTML |
|
|
105
105
|
| No corrections (approved) | `/business-analyse-handoff` | Proceed to code generation |
|
|
106
106
|
|
|
107
|
-
> **Rule:** Path A (`/
|
|
107
|
+
> **Rule:** Path A (`/business-analyse-quick` → `/apex`) is for quick, single-module additions. Path B (full cycle) is for multi-module projects or when the client needs a formal review process.
|
|
108
108
|
> **PRD generation:** Handoff data and PRD files are generated by the `/business-analyse-handoff` skill.
|
|
109
109
|
|
|
110
110
|
## JSON Architecture — Granular files + Index
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
(date validation, required fields) are the MINIMUM baseline. Domain rules
|
|
14
14
|
(half-day absences, team capacity, carry-over limits, credit note linking,
|
|
15
15
|
sequential invoice numbering) are what make an analysis valuable.
|
|
16
|
+
**Target: >= 2 domain-specific rules per business module (`domainSpecific: true`).**
|
|
17
|
+
Post-check C19 enforces this as a WARNING.
|
|
16
18
|
|
|
17
19
|
4. **ALWAYS propose contextual views.** A workflow module without filtered
|
|
18
20
|
views (open-requests, rejected, history, my-{entity}) is incomplete.
|
|
@@ -25,6 +27,41 @@
|
|
|
25
27
|
"standard billing also includes credit notes, payment tracking, and
|
|
26
28
|
dunning. Would you like to add these?" The user came to you for expertise.
|
|
27
29
|
|
|
30
|
+
7. **NEVER compress or batch module processing in step-03.** Each module MUST be
|
|
31
|
+
processed sequentially in the main context. Sub-agents do NOT have access to the
|
|
32
|
+
JSON schema and WILL produce inconsistent formats. If there are 15+ modules, the
|
|
33
|
+
correct approach is to maintain sequential processing, NOT to "accelerate" by
|
|
34
|
+
batching. The ba-012 audit proved that batching reduced schema conformity from
|
|
35
|
+
95% to 35% — the rework cost exceeded any time saved.
|
|
36
|
+
|
|
37
|
+
8. **ALL generated JSON content values MUST be in `{language}`** (from metadata or config).
|
|
38
|
+
This applies to ALL text values written to JSON files:
|
|
39
|
+
- Entity `description`, attribute `description`, relationship `description`
|
|
40
|
+
- Business rule `name`, `statement`, `examples[].input`, `examples[].expected`
|
|
41
|
+
- Use case `name`, `mainScenario[]` steps, `alternativeScenarios[].steps[]`, `errorScenarios[].steps[]`, `preconditions[]`, `postconditions[]`
|
|
42
|
+
- Permission `description`, role `description`
|
|
43
|
+
- Lifecycle state `displayName`
|
|
44
|
+
- Section and resource labels
|
|
45
|
+
|
|
46
|
+
**Mixed-language content across modules is a BLOCKING quality defect.**
|
|
47
|
+
If `language == "fr"` : write "Créer une absence", NOT "Create an absence".
|
|
48
|
+
If `language == "en"` : write "Create an absence", NOT "Créer une absence".
|
|
49
|
+
Technical identifiers (entity names, field names, enum values, IDs) remain in English/PascalCase.
|
|
50
|
+
|
|
51
|
+
9. **BR `examples[]` are TEST DATA, not documentation.** Each example must be a
|
|
52
|
+
concrete test case with the `{scenario, given, when, then}` format:
|
|
53
|
+
- `given`: object with `Entity.field: concreteValue` pairs (initial state)
|
|
54
|
+
- `when`: string action (`"create"`, `"submit"`, `"calculate_remaining"`)
|
|
55
|
+
- `then`: object with expected outcome (`{result: "success"|"error", Entity.field: value}`)
|
|
56
|
+
|
|
57
|
+
These examples directly feed:
|
|
58
|
+
- Gherkin `Examples:` tables (step-03, F-ter)
|
|
59
|
+
- `brToCodeMapping` in handoff
|
|
60
|
+
- Automated unit/integration tests in `/business-analyse-develop`
|
|
61
|
+
|
|
62
|
+
A rule without test-ready examples = a test gap in development.
|
|
63
|
+
Prose examples like `"code déjà existant"` are INSUFFICIENT — use concrete values.
|
|
64
|
+
|
|
28
65
|
---
|
|
29
66
|
|
|
30
67
|
## JSON-First Architecture
|