@djangocfg/layouts 2.1.257 → 2.1.259

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 (29) hide show
  1. package/README.md +101 -203
  2. package/package.json +18 -18
  3. package/src/index.ts +4 -1
  4. package/src/layouts/AppLayout/AppLayout.tsx +97 -8
  5. package/src/layouts/AppLayout/BaseApp.tsx +2 -0
  6. package/src/layouts/AppLayout/index.ts +6 -0
  7. package/src/layouts/PrivateLayout/PrivateLayout.tsx +3 -1
  8. package/src/layouts/PrivateLayout/components/PrivateContent.tsx +4 -1
  9. package/src/layouts/PublicLayout/PublicLayout.tsx +31 -8
  10. package/src/layouts/PublicLayout/components/PublicFooter/FooterProjectInfo.tsx +17 -24
  11. package/src/layouts/PublicLayout/components/PublicFooter/PublicFooter.tsx +79 -95
  12. package/src/layouts/PublicLayout/components/PublicFooter/index.ts +2 -0
  13. package/src/layouts/PublicLayout/components/PublicFooter/types.ts +41 -31
  14. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +69 -30
  15. package/src/layouts/PublicLayout/components/PublicNavbar.tsx +24 -34
  16. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +162 -94
  17. package/src/layouts/PublicLayout/components/ThemeBrandMark.tsx +83 -0
  18. package/src/layouts/PublicLayout/components/index.ts +2 -0
  19. package/src/layouts/PublicLayout/index.ts +5 -0
  20. package/src/layouts/PublicLayout/navbarTypes.ts +8 -0
  21. package/src/layouts/PublicLayout/publicShellShadow.ts +12 -0
  22. package/src/layouts/_components/UserMenu.tsx +2 -2
  23. package/src/layouts/types/index.ts +9 -1
  24. package/src/layouts/types/providers.types.ts +10 -0
  25. package/src/theme/ThemeStyleBridge.tsx +41 -0
  26. package/src/theme/buildThemeStyleSheet.ts +71 -0
  27. package/src/theme/index.ts +16 -0
  28. package/src/theme/themeStyle.types.ts +89 -0
  29. package/src/theme/themeStylePresets.ts +202 -0
@@ -0,0 +1,71 @@
1
+ import type { ThemeCssVarMap, ThemeStyleConfig, ThemeStylePresetId } from './themeStyle.types';
2
+ import { THEME_STYLE_PRESETS } from './themeStylePresets';
3
+
4
+ function mergeLayer(
5
+ base: ThemeCssVarMap | undefined,
6
+ over: ThemeCssVarMap | undefined
7
+ ): ThemeCssVarMap {
8
+ return { ...base, ...over };
9
+ }
10
+
11
+ /**
12
+ * Tailwind v4 `rounded-*` utilities are backed by `--radius-*` scale variables (xs/sm/md/…),
13
+ * not by our semantic `--radius`.
14
+ *
15
+ * When semantic `radius` is present, emit the derived scale too so the injected stylesheet
16
+ * controls both semantic and Tailwind scale rounding across the UI.
17
+ */
18
+ function withTailwindRadiusScale(vars: ThemeCssVarMap): Array<[string, string]> {
19
+ const entries = Object.entries(vars);
20
+ const radius = vars.radius;
21
+ if (!radius) return entries;
22
+
23
+ const r = String(radius).trim();
24
+ if (!r) return entries;
25
+
26
+ const scale: Array<[string, string]> = [
27
+ ['radius-xs', `calc(${r} - 6px)`],
28
+ ['radius-sm', `calc(${r} - 4px)`],
29
+ ['radius-md', `calc(${r} - 2px)`],
30
+ ['radius-lg', r],
31
+ ['radius-xl', `calc(${r} + 4px)`],
32
+ ['radius-2xl', `calc(${r} + 8px)`],
33
+ ['radius-3xl', `calc(${r} + 12px)`],
34
+ ['radius-4xl', `calc(${r} + 16px)`],
35
+ ];
36
+
37
+ // Put derived values after semantic `radius` so they always win in the injected block.
38
+ return [...entries, ...scale];
39
+ }
40
+
41
+ /**
42
+ * Build a small stylesheet fragment for injection after globals.
43
+ * Order: preset (if not default) → `vars.light` / `vars.dark`.
44
+ */
45
+ export function buildThemeStyleSheet(style?: ThemeStyleConfig): string {
46
+ if (!style) return '';
47
+
48
+ const presetId: ThemeStylePresetId = style.preset ?? 'default';
49
+ const preset = THEME_STYLE_PRESETS[presetId] ?? THEME_STYLE_PRESETS.default;
50
+
51
+ const light = mergeLayer(preset.light, style.vars?.light);
52
+ const dark = mergeLayer(preset.dark, style.vars?.dark);
53
+
54
+ const blocks: string[] = [];
55
+
56
+ if (Object.keys(light).length > 0) {
57
+ const body = withTailwindRadiusScale(light)
58
+ .map(([k, v]) => ` --${k}: ${v};`)
59
+ .join('\n');
60
+ blocks.push(`:root {\n${body}\n}`);
61
+ }
62
+
63
+ if (Object.keys(dark).length > 0) {
64
+ const body = withTailwindRadiusScale(dark)
65
+ .map(([k, v]) => ` --${k}: ${v};`)
66
+ .join('\n');
67
+ blocks.push(`.dark {\n${body}\n}`);
68
+ }
69
+
70
+ return blocks.join('\n\n');
71
+ }
@@ -0,0 +1,16 @@
1
+ export type {
2
+ ThemeCssVarChartKey,
3
+ ThemeCssVarChromeKey,
4
+ ThemeCssVarColorKey,
5
+ ThemeCssVarKey,
6
+ ThemeCssVarMap,
7
+ ThemeCssVarSidebarKey,
8
+ ThemeStyleConfig,
9
+ ThemeStylePresetId,
10
+ } from './themeStyle.types';
11
+
12
+ export { THEME_STYLE_PRESETS, THEME_STYLE_PRESET_ORDER } from './themeStylePresets';
13
+
14
+ export { buildThemeStyleSheet } from './buildThemeStyleSheet';
15
+
16
+ export { ThemeStyleBridge, type ThemeStyleBridgeProps } from './ThemeStyleBridge';
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Typed theme token overrides for BaseApp (`theme.style`).
3
+ *
4
+ * Values are raw HSL components as in ui-core CSS, e.g. `192 90% 35%` (no `hsl()` wrapper).
5
+ * **`radius`** accepts any valid CSS length (`0.75rem`, `1rem`, …).
6
+ *
7
+ * ### Parity with the Theme Configurator playground
8
+ *
9
+ * The playground (`apps/playground`) uses **`ThemeData`**: nested objects (`colors.primary`, `radius`, …).
10
+ * This package maps the **same semantics** onto **global CSS variables** (`--primary`, `--radius`, …) that
11
+ * `buildThemeStyleSheet` injects. Playground-only buckets (**`shadows`**, **`typography`**, **`spacing`**, …)
12
+ * are **not** represented here — export full CSS from the configurator when you need those.
13
+ *
14
+ * Rough mapping: `colors.*` → kebab key without `Foreground` → `*-foreground`; `radius` → `radius`;
15
+ * `sidebar.*` → `sidebar-*`.
16
+ */
17
+
18
+ /** Core semantic colors (HSL triplets) */
19
+ export type ThemeCssVarColorKey =
20
+ | 'background'
21
+ | 'foreground'
22
+ | 'card'
23
+ | 'card-foreground'
24
+ | 'popover'
25
+ | 'popover-foreground'
26
+ | 'primary'
27
+ | 'primary-foreground'
28
+ | 'secondary'
29
+ | 'secondary-foreground'
30
+ | 'muted'
31
+ | 'muted-foreground'
32
+ | 'accent'
33
+ | 'accent-foreground'
34
+ | 'destructive'
35
+ | 'destructive-foreground';
36
+
37
+ /** Layout / focus tokens — `radius` is usually a length, rest are HSL or shared with colors */
38
+ export type ThemeCssVarChromeKey = 'border' | 'input' | 'ring' | 'radius';
39
+
40
+ export type ThemeCssVarSidebarKey =
41
+ | 'sidebar-background'
42
+ | 'sidebar-foreground'
43
+ | 'sidebar-primary'
44
+ | 'sidebar-primary-foreground'
45
+ | 'sidebar-accent'
46
+ | 'sidebar-accent-foreground'
47
+ | 'sidebar-border'
48
+ | 'sidebar-ring';
49
+
50
+ export type ThemeCssVarChartKey = 'chart-1' | 'chart-2' | 'chart-3' | 'chart-4' | 'chart-5';
51
+
52
+ /**
53
+ * Keys that match `--${key}` in `ui-core` theme files (`light.css` / `dark.css`).
54
+ * Use `ThemeCssVarMap` for partial overrides on top of a preset.
55
+ */
56
+ export type ThemeCssVarKey =
57
+ | ThemeCssVarColorKey
58
+ | ThemeCssVarChromeKey
59
+ | ThemeCssVarSidebarKey
60
+ | ThemeCssVarChartKey;
61
+
62
+ /** Partial map of semantic variables for one color mode */
63
+ export type ThemeCssVarMap = Partial<Record<ThemeCssVarKey, string>>;
64
+
65
+ /** Built-in bundles in `THEME_STYLE_PRESETS` — see README preset table. */
66
+ export type ThemeStylePresetId =
67
+ | 'default'
68
+ | 'django-cfg'
69
+ | 'ios'
70
+ | 'soft'
71
+ | 'dense'
72
+ | 'high-contrast';
73
+
74
+ /**
75
+ * Optional style layer: named preset + per-mode overrides.
76
+ * Merged as: globals (CSS imports) → **preset** → **`vars.light` / `vars.dark`** (later wins).
77
+ */
78
+ export interface ThemeStyleConfig {
79
+ /**
80
+ * Built-in token bundle. Use `'default'` or omit to rely only on imported CSS + `vars`.
81
+ * @default 'default'
82
+ */
83
+ preset?: ThemeStylePresetId;
84
+ /** Fine-grained overrides on top of globals and preset */
85
+ vars?: {
86
+ light?: ThemeCssVarMap;
87
+ dark?: ThemeCssVarMap;
88
+ };
89
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Curated presets for `BaseApp` `theme.style` — small deltas over `ui-core` globals.
3
+ * For full token matrices (shadows, type scale, …) use the playground Theme Configurator → export CSS.
4
+ */
5
+
6
+ import type { ThemeCssVarMap, ThemeStylePresetId } from './themeStyle.types';
7
+
8
+ /** Stable order for UI lists / docs (every `ThemeStylePresetId` appears once). */
9
+ export const THEME_STYLE_PRESET_ORDER = [
10
+ 'default',
11
+ 'django-cfg',
12
+ 'ios',
13
+ 'soft',
14
+ 'dense',
15
+ 'high-contrast',
16
+ ] as const satisfies readonly ThemeStylePresetId[];
17
+
18
+ export const THEME_STYLE_PRESETS: Record<
19
+ ThemeStylePresetId,
20
+ { light: ThemeCssVarMap; dark: ThemeCssVarMap }
21
+ > = {
22
+ /** No extra rules — same as globals only (`vars` may still apply). */
23
+ default: {
24
+ light: {},
25
+ dark: {},
26
+ },
27
+
28
+ /**
29
+ * DjangoCFG brand: deeper cyan primary on light, bright cyan + dark label on dark
30
+ * (aligned with current `ui-core` theme files when globals are loaded).
31
+ */
32
+ 'django-cfg': {
33
+ light: {
34
+ primary: '192 90% 35%',
35
+ 'primary-foreground': '0 0% 100%',
36
+ ring: '192 90% 35%',
37
+ 'sidebar-primary': '192 90% 35%',
38
+ 'sidebar-ring': '192 90% 35%',
39
+ 'chart-1': '192 90% 35%',
40
+ },
41
+ dark: {
42
+ primary: '189 100% 50%',
43
+ 'primary-foreground': '0 0% 9%',
44
+ ring: '189 100% 50%',
45
+ 'sidebar-primary': '189 100% 50%',
46
+ 'sidebar-primary-foreground': '0 0% 9%',
47
+ 'sidebar-ring': '189 100% 50%',
48
+ 'chart-1': '189 100% 50%',
49
+ },
50
+ },
51
+
52
+ /**
53
+ * Apple-style system UI: #007AFF primary, very light chrome, ~12pt corners, hairline separators.
54
+ * (Inspired by `apps/playground` `macos` preset, mapped to semantic `--*` vars only.)
55
+ */
56
+ ios: {
57
+ light: {
58
+ background: '0 0% 98%',
59
+ foreground: '220 9% 12%',
60
+ card: '0 0% 100%',
61
+ 'card-foreground': '220 9% 12%',
62
+ popover: '0 0% 100%',
63
+ 'popover-foreground': '220 9% 12%',
64
+ primary: '211 100% 50%',
65
+ 'primary-foreground': '0 0% 100%',
66
+ secondary: '220 9% 92%',
67
+ 'secondary-foreground': '220 9% 12%',
68
+ muted: '220 9% 94%',
69
+ 'muted-foreground': '220 9% 40%',
70
+ accent: '220 9% 94%',
71
+ 'accent-foreground': '220 9% 12%',
72
+ destructive: '0 100% 58%',
73
+ 'destructive-foreground': '0 0% 100%',
74
+ border: '220 9% 88%',
75
+ input: '220 9% 88%',
76
+ ring: '211 100% 50%',
77
+ radius: '0.75rem',
78
+ 'sidebar-background': '0 0% 99%',
79
+ 'sidebar-foreground': '220 9% 12%',
80
+ 'sidebar-primary': '211 100% 50%',
81
+ 'sidebar-primary-foreground': '0 0% 100%',
82
+ 'sidebar-accent': '220 9% 94%',
83
+ 'sidebar-accent-foreground': '220 9% 12%',
84
+ 'sidebar-border': '220 9% 88%',
85
+ 'sidebar-ring': '211 100% 50%',
86
+ 'chart-1': '211 100% 50%',
87
+ 'chart-2': '145 63% 42%',
88
+ 'chart-3': '262 83% 58%',
89
+ 'chart-4': '35 100% 50%',
90
+ 'chart-5': '346 77% 50%',
91
+ },
92
+ dark: {
93
+ background: '240 6% 10%',
94
+ foreground: '0 0% 96%',
95
+ card: '240 6% 14%',
96
+ 'card-foreground': '0 0% 96%',
97
+ popover: '240 6% 16%',
98
+ 'popover-foreground': '0 0% 96%',
99
+ primary: '211 100% 55%',
100
+ 'primary-foreground': '0 0% 100%',
101
+ secondary: '240 5% 26%',
102
+ 'secondary-foreground': '0 0% 96%',
103
+ muted: '240 5% 16%',
104
+ 'muted-foreground': '240 5% 64%',
105
+ accent: '240 5% 18%',
106
+ 'accent-foreground': '0 0% 96%',
107
+ destructive: '0 100% 67%',
108
+ 'destructive-foreground': '0 0% 100%',
109
+ border: '240 5% 22%',
110
+ input: '240 5% 22%',
111
+ ring: '211 100% 55%',
112
+ radius: '0.75rem',
113
+ 'sidebar-background': '240 6% 8%',
114
+ 'sidebar-foreground': '0 0% 96%',
115
+ 'sidebar-primary': '211 100% 55%',
116
+ 'sidebar-primary-foreground': '0 0% 100%',
117
+ 'sidebar-accent': '240 5% 16%',
118
+ 'sidebar-accent-foreground': '0 0% 96%',
119
+ 'sidebar-border': '240 5% 22%',
120
+ 'sidebar-ring': '211 100% 55%',
121
+ 'chart-1': '211 100% 55%',
122
+ 'chart-2': '145 65% 52%',
123
+ 'chart-3': '262 83% 65%',
124
+ 'chart-4': '35 100% 58%',
125
+ 'chart-5': '346 77% 58%',
126
+ },
127
+ },
128
+
129
+ /** Soft, friendly surfaces: larger radius, low-contrast borders (product / marketing). */
130
+ soft: {
131
+ light: {
132
+ background: '0 0% 98%',
133
+ foreground: '240 6% 10%',
134
+ card: '0 0% 100%',
135
+ 'card-foreground': '240 6% 10%',
136
+ muted: '240 5% 96%',
137
+ 'muted-foreground': '240 4% 46%',
138
+ accent: '240 5% 94%',
139
+ 'accent-foreground': '240 6% 10%',
140
+ border: '240 5% 91%',
141
+ input: '240 5% 91%',
142
+ radius: '1rem',
143
+ 'sidebar-accent': '240 5% 94%',
144
+ 'sidebar-border': '240 5% 91%',
145
+ },
146
+ dark: {
147
+ background: '240 6% 8%',
148
+ foreground: '0 0% 96%',
149
+ card: '240 5% 12%',
150
+ 'card-foreground': '0 0% 96%',
151
+ muted: '240 4% 16%',
152
+ 'muted-foreground': '240 5% 64%',
153
+ accent: '240 5% 16%',
154
+ 'accent-foreground': '0 0% 96%',
155
+ border: '240 5% 20%',
156
+ input: '240 5% 20%',
157
+ radius: '1rem',
158
+ 'sidebar-background': '240 6% 6%',
159
+ 'sidebar-accent': '240 5% 14%',
160
+ 'sidebar-border': '240 5% 20%',
161
+ },
162
+ },
163
+
164
+ /** Compact controls: small radius, stronger borders (tables, admin, IDE-like). */
165
+ dense: {
166
+ light: {
167
+ radius: '0.25rem',
168
+ border: '0 0% 82%',
169
+ input: '0 0% 82%',
170
+ muted: '0 0% 94%',
171
+ card: '0 0% 100%',
172
+ accent: '0 0% 93%',
173
+ },
174
+ dark: {
175
+ radius: '0.25rem',
176
+ border: '0 0% 24%',
177
+ input: '0 0% 24%',
178
+ muted: '0 0% 12%',
179
+ card: '0 0% 10%',
180
+ accent: '0 0% 14%',
181
+ },
182
+ },
183
+
184
+ /** Stronger borders and text for glare / accessibility. */
185
+ 'high-contrast': {
186
+ light: {
187
+ border: '0 0% 72%',
188
+ input: '0 0% 72%',
189
+ 'muted-foreground': '0 0% 32%',
190
+ foreground: '0 0% 6%',
191
+ ring: '0 0% 20%',
192
+ },
193
+ dark: {
194
+ border: '0 0% 38%',
195
+ input: '0 0% 38%',
196
+ 'muted-foreground': '0 0% 78%',
197
+ foreground: '0 0% 100%',
198
+ background: '0 0% 6%',
199
+ ring: '0 0% 85%',
200
+ },
201
+ },
202
+ };