@foliokit/cms-ui 0.4.2 → 1.0.1

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 (45) hide show
  1. package/README.md +155 -0
  2. package/eslint.config.mjs +48 -0
  3. package/ng-package.json +19 -0
  4. package/package.json +12 -19
  5. package/project.json +32 -0
  6. package/src/index.ts +7 -0
  7. package/src/lib/about-page/about-page.component.ts +219 -0
  8. package/src/lib/app-shell/app-shell.component.html +57 -0
  9. package/src/lib/app-shell/app-shell.component.scss +204 -0
  10. package/src/lib/app-shell/app-shell.component.ts +88 -0
  11. package/src/lib/app-shell/shell-nav-footer.directive.ts +4 -0
  12. package/src/lib/cms-ui/cms-ui.html +1 -0
  13. package/src/lib/cms-ui/cms-ui.scss +0 -0
  14. package/src/lib/cms-ui/cms-ui.spec.ts +93 -0
  15. package/src/lib/cms-ui/cms-ui.ts +9 -0
  16. package/src/lib/links-page/links-page.component.ts +256 -0
  17. package/src/lib/route-data.ts +27 -0
  18. package/src/lib/shell-config.token.ts +11 -0
  19. package/src/lib/theme.service.ts +44 -0
  20. package/src/styles/_focus.scss +17 -0
  21. package/src/styles/_reset.scss +65 -0
  22. package/src/styles/_theme.scss +76 -0
  23. package/src/styles/_tokens.scss +216 -0
  24. package/src/styles/_typography.scss +146 -0
  25. package/src/styles/index.scss +5 -0
  26. package/src/styles/tokens.css +135 -0
  27. package/tsconfig.json +31 -0
  28. package/tsconfig.lib.json +12 -0
  29. package/tsconfig.lib.prod.json +9 -0
  30. package/tsconfig.spec.json +8 -0
  31. package/esm2022/foliokit-cms-ui.js +0 -5
  32. package/esm2022/foliokit-cms-ui.js.map +0 -1
  33. package/esm2022/index.js +0 -4
  34. package/esm2022/index.js.map +0 -1
  35. package/esm2022/lib/app-shell/app-shell.component.js +0 -52
  36. package/esm2022/lib/app-shell/app-shell.component.js.map +0 -1
  37. package/esm2022/lib/shell-config.token.js +0 -3
  38. package/esm2022/lib/shell-config.token.js.map +0 -1
  39. package/esm2022/lib/theme.service.js +0 -45
  40. package/esm2022/lib/theme.service.js.map +0 -1
  41. package/foliokit-cms-ui.d.ts +0 -5
  42. package/index.d.ts +0 -3
  43. package/lib/app-shell/app-shell.component.d.ts +0 -17
  44. package/lib/shell-config.token.d.ts +0 -9
  45. package/lib/theme.service.d.ts +0 -11
@@ -0,0 +1,44 @@
1
+ import { computed, inject, Injectable, PLATFORM_ID, signal } from '@angular/core';
2
+ import { isPlatformBrowser } from '@angular/common';
3
+
4
+ export type ColorScheme = 'light' | 'dark';
5
+
6
+ const STORAGE_KEY = 'folio-theme';
7
+
8
+ @Injectable({ providedIn: 'root' })
9
+ export class ThemeService {
10
+ private readonly platformId = inject(PLATFORM_ID);
11
+
12
+ readonly scheme = signal<ColorScheme>(this.resolveInitialScheme());
13
+ readonly isDark = computed(() => this.scheme() === 'dark');
14
+
15
+ toggle(): void {
16
+ this.scheme.update((s) => (s === 'light' ? 'dark' : 'light'));
17
+ this.apply();
18
+ }
19
+
20
+ apply(): void {
21
+ if (!isPlatformBrowser(this.platformId)) return;
22
+ const current = this.scheme();
23
+ document.documentElement.setAttribute('data-theme', current);
24
+ try {
25
+ localStorage.setItem(STORAGE_KEY, current);
26
+ } catch {
27
+ // localStorage may be unavailable (private browsing, etc.)
28
+ }
29
+ }
30
+
31
+ private resolveInitialScheme(): ColorScheme {
32
+ if (!isPlatformBrowser(this.platformId)) return 'light';
33
+
34
+ try {
35
+ const stored = localStorage.getItem(STORAGE_KEY) as ColorScheme | null;
36
+ if (stored === 'light' || stored === 'dark') return stored;
37
+ } catch {
38
+ // ignore
39
+ }
40
+
41
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
42
+ return prefersDark ? 'dark' : 'light';
43
+ }
44
+ }
@@ -0,0 +1,17 @@
1
+ // FolioKit Global Focus Styles
2
+ // Replaces browser default outlines and Material's mat-focus-indicator
3
+ // with a single, brand-token-driven focus ring across all apps.
4
+
5
+ *:focus-visible {
6
+ outline: none;
7
+ box-shadow: 0 0 0 3px var(--focus-ring), 0 0 0 1px var(--focus-border);
8
+ }
9
+
10
+ // Disable Material's built-in focus indicator — it double-renders with ours.
11
+ .mat-focus-indicator::before {
12
+ display: none !important;
13
+ }
14
+
15
+ .mat-mdc-focus-indicator::before {
16
+ display: none !important;
17
+ }
@@ -0,0 +1,65 @@
1
+ // FolioKit Base Reset
2
+ // Single shared reset for all FolioKit apps.
3
+ // Depends on semantic tokens from _tokens.scss — no Tailwind, no Material.
4
+
5
+ *,
6
+ *::before,
7
+ *::after {
8
+ box-sizing: border-box;
9
+ margin: 0;
10
+ padding: 0;
11
+ }
12
+
13
+ html {
14
+ height: 100%;
15
+ scroll-behavior: smooth;
16
+ }
17
+
18
+ body {
19
+ height: 100%;
20
+ background: var(--bg);
21
+ color: var(--text-primary);
22
+ font-family: var(--font-body);
23
+ font-size: 16px;
24
+ line-height: 1.5;
25
+ -webkit-font-smoothing: antialiased;
26
+ transition: background 0.25s ease, color 0.25s ease;
27
+ min-height: 100vh;
28
+ }
29
+
30
+ img,
31
+ video {
32
+ max-width: 100%;
33
+ display: block;
34
+ }
35
+
36
+ a {
37
+ color: inherit;
38
+ }
39
+
40
+ ::-webkit-scrollbar {
41
+ width: 6px;
42
+ height: 6px;
43
+ }
44
+
45
+ ::-webkit-scrollbar-track {
46
+ background: transparent;
47
+ }
48
+
49
+ ::-webkit-scrollbar-thumb {
50
+ background: var(--border-strong);
51
+ border-radius: var(--r-sm);
52
+ }
53
+
54
+ // ── Reduced motion ────────────────────────────────────────────────────────────
55
+ // WCAG 2.1 — disable non-essential animation for users who prefer reduced motion.
56
+ @media (prefers-reduced-motion: reduce) {
57
+ *,
58
+ *::before,
59
+ *::after {
60
+ animation-duration: 0.01ms !important;
61
+ animation-iteration-count: 1 !important;
62
+ transition-duration: 0.01ms !important;
63
+ scroll-behavior: auto !important;
64
+ }
65
+ }
@@ -0,0 +1,76 @@
1
+ // FolioKit Angular Material M3 Theme
2
+ // Single shared theme config for all FolioKit apps.
3
+ // Standardized on mat.theme() — replaces per-app M3 configs.
4
+
5
+ @use '@angular/material' as mat;
6
+
7
+ // ─── Light Theme ─────────────────────────────────────────────────────────────
8
+
9
+ html,
10
+ html[data-theme='light'] {
11
+ @include mat.theme((
12
+ color: (
13
+ theme-type: light,
14
+ primary: mat.$cyan-palette,
15
+ tertiary: mat.$cyan-palette,
16
+ ),
17
+ typography: 'Plus Jakarta Sans',
18
+ density: 0,
19
+ ));
20
+
21
+ // FolioKit → M3 system token bridge
22
+ --mat-sys-primary: var(--teal-500);
23
+ --mat-sys-on-primary: #FFFFFF;
24
+ --mat-sys-surface: var(--surface-1);
25
+ --mat-sys-on-surface: var(--text-primary);
26
+ --mat-sys-surface-variant: var(--surface-2);
27
+ --mat-sys-outline: var(--border-strong);
28
+ --mat-sys-background: var(--bg);
29
+
30
+ // ── Brand motion timing (nudges Material animations) ─────────────────────
31
+ --mat-sys-motion-duration-short1: 120ms;
32
+ --mat-sys-motion-duration-medium1: 180ms;
33
+
34
+ // ── Form field overrides (OPTION A) ──────────────────────────────────────
35
+ --mat-form-field-container-shape: var(--r-md);
36
+ --mat-form-field-outlined-idle-outline-color: var(--border-strong);
37
+ --mat-form-field-outlined-hover-outline-color: var(--border-accent);
38
+ --mdc-outlined-text-field-focus-outline-color: var(--focus-border);
39
+ --mdc-outlined-text-field-label-text-size: 12px;
40
+ --mdc-outlined-text-field-label-text-weight: 500;
41
+ }
42
+
43
+ // ─── Dark Theme ──────────────────────────────────────────────────────────────
44
+
45
+ html[data-theme='dark'] {
46
+ @include mat.theme((
47
+ color: (
48
+ theme-type: dark,
49
+ primary: mat.$cyan-palette,
50
+ tertiary: mat.$cyan-palette,
51
+ ),
52
+ typography: 'Plus Jakarta Sans',
53
+ density: 0,
54
+ ));
55
+
56
+ // FolioKit → M3 system token bridge
57
+ --mat-sys-primary: var(--teal-400);
58
+ --mat-sys-on-primary: var(--slate-950);
59
+ --mat-sys-surface: var(--surface-1);
60
+ --mat-sys-on-surface: var(--text-primary);
61
+ --mat-sys-surface-variant: var(--surface-2);
62
+ --mat-sys-outline: var(--border-strong);
63
+ --mat-sys-background: var(--bg);
64
+
65
+ // ── Brand motion timing ───────────────────────────────────────────────────
66
+ --mat-sys-motion-duration-short1: 120ms;
67
+ --mat-sys-motion-duration-medium1: 180ms;
68
+
69
+ // ── Form field overrides (OPTION A) ──────────────────────────────────────
70
+ --mat-form-field-container-shape: var(--r-md);
71
+ --mat-form-field-outlined-idle-outline-color: var(--border-strong);
72
+ --mat-form-field-outlined-hover-outline-color: var(--border-accent);
73
+ --mdc-outlined-text-field-focus-outline-color: var(--focus-border);
74
+ --mdc-outlined-text-field-label-text-size: 12px;
75
+ --mdc-outlined-text-field-label-text-weight: 500;
76
+ }
@@ -0,0 +1,216 @@
1
+ :root {
2
+ /* Slate — primary neutral (cool blue-grey) */
3
+ --slate-950: #0C0F14;
4
+ --slate-900: #151A23;
5
+ --slate-800: #1E2533;
6
+ --slate-700: #2D3748;
7
+ --slate-600: #4A5568;
8
+ --slate-500: #718096;
9
+ --slate-400: #A0AEC0;
10
+ --slate-300: #CBD5E0;
11
+ --slate-200: #E2E8F0;
12
+ --slate-100: #EDF2F7;
13
+ --slate-50: #F7FAFC;
14
+ /* Cloud — page surfaces */
15
+ --cloud-0: #FFFFFF;
16
+ --cloud-100: #F8FAFD;
17
+ --cloud-200: #F0F4F9;
18
+ --cloud-300: #E4ECF4;
19
+ /* Teal — brand accent */
20
+ --teal-900: #0D2B2B;
21
+ --teal-800: #134040;
22
+ --teal-700: #1A5C5C;
23
+ --teal-600: #217A7A;
24
+ --teal-500: #2A9797;
25
+ --teal-400: #38B2AC;
26
+ --teal-300: #6DD5CE;
27
+ --teal-200: #B2E8E5;
28
+ --teal-100: #E0F5F4;
29
+ --teal-50: #F0FAFA;
30
+ /* Violet — Angular flare, used sparingly */
31
+ --violet-600: #553C9A;
32
+ --violet-500: #6B46C1;
33
+ --violet-400: #805AD5;
34
+ --violet-100: #EDE9FE;
35
+ --violet-50: #F5F3FF;
36
+ /* Functional */
37
+ --green-700: #1A5C38;
38
+ --green-600: #22794A;
39
+ --green-400: #4ADE80;
40
+ --green-100: #D4EDDA;
41
+ --blue-700: #1A3F7A;
42
+ --blue-600: #2252A4;
43
+ --blue-400: #60A5FA;
44
+ --blue-100: #D6E4F7;
45
+ --red-700: #7D1F1A;
46
+ --red-600: #A12B24;
47
+ --red-100: #F9DEDD;
48
+ --amber-600: #C27820;
49
+ --amber-500: #D4892A;
50
+ --amber-400: #E09A40;
51
+ --amber-100: #FBF0DC;
52
+ /* Typography */
53
+ --font-display: 'Fraunces', Georgia, serif;
54
+ --font-body: 'Plus Jakarta Sans', system-ui, sans-serif;
55
+ --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
56
+ /* Radii */
57
+ --r-xs: 2px;
58
+ --r-sm: 4px;
59
+ --r-md: 6px;
60
+ --r-lg: 10px;
61
+ --r-xl: 14px;
62
+ --r-2xl: 20px;
63
+ /* Code block (always dark regardless of theme) */
64
+ --code-block-bg: #141920;
65
+ --code-block-text: #CDD9E8;
66
+ }
67
+ [data-theme="light"] {
68
+ --bg: var(--cloud-100);
69
+ --bg-subtle: var(--cloud-200);
70
+ --surface-0: var(--cloud-0);
71
+ --surface-1: var(--cloud-100);
72
+ --surface-2: var(--cloud-200);
73
+ --surface-3: var(--cloud-300);
74
+ --border: var(--slate-200);
75
+ --border-strong: var(--slate-300);
76
+ --border-accent: var(--teal-300);
77
+ --text-primary: var(--slate-900);
78
+ --text-secondary: var(--slate-600);
79
+ --text-muted: var(--slate-400);
80
+ --text-disabled: var(--slate-300);
81
+ --text-accent: var(--teal-600);
82
+ --text-on-accent: #FFFFFF;
83
+ --text-on-dark: #E8EDF5;
84
+ --btn-primary-bg: var(--teal-500);
85
+ --btn-primary-text: #FFFFFF;
86
+ --btn-primary-hover: var(--teal-600);
87
+ --logo-bg: var(--slate-900);
88
+ --logo-text: var(--cloud-0);
89
+ --logo-dot: var(--teal-400);
90
+ --focus-ring: rgba(42, 151, 151, 0.22);
91
+ --focus-border: var(--teal-500);
92
+ --shadow-sm: 0 1px 3px rgba(12,15,20,0.07), 0 1px 2px rgba(12,15,20,0.04);
93
+ --shadow-md: 0 3px 10px rgba(12,15,20,0.08), 0 1px 4px rgba(12,15,20,0.05);
94
+ --shadow-lg: 0 8px 28px rgba(12,15,20,0.10), 0 2px 8px rgba(12,15,20,0.06);
95
+ --shadow-xl: 0 20px 56px rgba(12,15,20,0.12), 0 4px 16px rgba(12,15,20,0.07);
96
+ --nav-active-bg: var(--teal-50);
97
+ --nav-active-color: var(--teal-800);
98
+ --warning: var(--amber-600);
99
+ --warning-subtle: var(--amber-100);
100
+ color-scheme: light;
101
+ }
102
+ // ─── Badge classes ────────────────────────────────────────────────────────────
103
+
104
+ .badge {
105
+ display: inline-flex;
106
+ align-items: center;
107
+ gap: 5px;
108
+ font-family: var(--font-mono);
109
+ font-size: 9px;
110
+ font-weight: 500;
111
+ letter-spacing: 0.08em;
112
+ text-transform: uppercase;
113
+ padding: 2px 7px;
114
+ border-radius: var(--r-sm);
115
+ white-space: nowrap;
116
+ }
117
+
118
+ [data-theme="light"] {
119
+ .badge-pub {
120
+ background: var(--green-100);
121
+ color: var(--green-700);
122
+ }
123
+ .badge-draft {
124
+ background: var(--slate-100);
125
+ color: var(--slate-600);
126
+ }
127
+ .badge-sched {
128
+ background: var(--blue-100);
129
+ color: var(--blue-700);
130
+ }
131
+ }
132
+
133
+ [data-theme="dark"] .badge-pub {
134
+ background: color-mix(in srgb, var(--green-600) 20%, transparent);
135
+ color: var(--green-100);
136
+ }
137
+ [data-theme="dark"] .badge-draft {
138
+ background: color-mix(in srgb, var(--text-muted) 12%, transparent);
139
+ color: var(--text-muted);
140
+ }
141
+ [data-theme="dark"] .badge-sched {
142
+ background: color-mix(in srgb, var(--blue-600) 20%, transparent);
143
+ color: var(--blue-100);
144
+ }
145
+
146
+ // ─── Avatar classes ───────────────────────────────────────────────────────────
147
+
148
+ .avatar {
149
+ display: inline-flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ width: 26px;
153
+ height: 26px;
154
+ border-radius: 50%;
155
+ background: var(--logo-bg);
156
+ color: var(--logo-text);
157
+ font-family: var(--font-body);
158
+ font-weight: 600;
159
+ font-size: 10px;
160
+ flex-shrink: 0;
161
+ overflow: hidden;
162
+
163
+ img {
164
+ width: 100%;
165
+ height: 100%;
166
+ object-fit: cover;
167
+ }
168
+ }
169
+
170
+ .avatar--lg {
171
+ width: 64px;
172
+ height: 64px;
173
+ font-size: 22px;
174
+ }
175
+
176
+ .avatar--xl {
177
+ width: 96px;
178
+ height: 96px;
179
+ font-size: 32px;
180
+ }
181
+
182
+ [data-theme="dark"] {
183
+ --bg: #1A1F2E;
184
+ --bg-subtle: #1E2535;
185
+ --surface-0: #242B3D;
186
+ --surface-1: #2A3347;
187
+ --surface-2: #303B52;
188
+ --surface-3: #3A4660;
189
+ --border: rgba(255, 255, 255, 0.09);
190
+ --border-strong: rgba(255, 255, 255, 0.16);
191
+ --border-accent: rgba(56, 178, 172, 0.40);
192
+ --text-primary: #E8EDF5;
193
+ --text-secondary: #9AACBF;
194
+ --text-muted: #5F7490;
195
+ --text-disabled: #3D4F63;
196
+ --text-accent: var(--teal-300);
197
+ --text-on-accent: var(--slate-950);
198
+ --text-on-dark: #E8EDF5;
199
+ --btn-primary-bg: var(--teal-400);
200
+ --btn-primary-text: var(--slate-950);
201
+ --btn-primary-hover: var(--teal-300);
202
+ --logo-bg: var(--teal-500);
203
+ --logo-text: #FFFFFF;
204
+ --logo-dot: var(--teal-200);
205
+ --focus-ring: rgba(56, 178, 172, 0.28);
206
+ --focus-border: var(--teal-400);
207
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.30);
208
+ --shadow-md: 0 3px 10px rgba(0,0,0,0.35);
209
+ --shadow-lg: 0 8px 28px rgba(0,0,0,0.40);
210
+ --shadow-xl: 0 20px 56px rgba(0,0,0,0.50);
211
+ --nav-active-bg: rgba(56, 178, 172, 0.14);
212
+ --nav-active-color: var(--text-primary);
213
+ --warning: var(--amber-400);
214
+ --warning-subtle: rgba(122, 74, 0, 0.18);
215
+ color-scheme: dark;
216
+ }
@@ -0,0 +1,146 @@
1
+ // ── Web fonts ─────────────────────────────────────────────────────────────────
2
+ // Google Fonts CDN removed for privacy and CSP compliance.
3
+ // The font CSS custom properties (--font-display, --font-mono, --font-sans) in
4
+ // _tokens.scss include system font fallbacks that activate automatically when
5
+ // the named web fonts are not loaded.
6
+ //
7
+ // To re-enable Google Fonts, uncomment the line below:
8
+ // @import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,600;0,9..144,700;1,9..144,300;1,9..144,400;1,9..144,600&family=JetBrains+Mono:wght@300;400;500&family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&display=swap');
9
+ //
10
+ // Or use self-hosted font packages from Fontsource (no CDN, full control):
11
+ // npm install @fontsource-variable/fraunces @fontsource-variable/jetbrains-mono @fontsource-variable/plus-jakarta-sans
12
+ // Then import in your app's styles.scss:
13
+ // @import '@fontsource-variable/fraunces/index.css';
14
+ // @import '@fontsource-variable/jetbrains-mono/index.css';
15
+ // @import '@fontsource-variable/plus-jakarta-sans/index.css';
16
+ // ─────────────────────────────────────────────────────────────────────────────
17
+
18
+ // ── Article body content ──────────────────────────────────────────────────────
19
+
20
+ .folio-prose {
21
+
22
+ p {
23
+ font-size: 16px;
24
+ line-height: 1.85;
25
+ color: var(--text-primary);
26
+ margin-bottom: 1.3em;
27
+ }
28
+
29
+ h2 {
30
+ font-family: var(--font-display);
31
+ font-size: 20px;
32
+ font-weight: 600;
33
+ letter-spacing: -0.015em;
34
+ margin: 2em 0 0.6em;
35
+ color: var(--text-primary);
36
+ line-height: 1.2;
37
+ }
38
+
39
+ h3 {
40
+ font-family: var(--font-display);
41
+ font-size: 1.2rem;
42
+ font-weight: 600;
43
+ margin: 1.75em 0 0.5em;
44
+ color: var(--text-primary);
45
+ }
46
+
47
+ blockquote {
48
+ border-left: 2px solid var(--text-accent);
49
+ padding: 4px 20px;
50
+ margin: 1.8em 0;
51
+ font-family: var(--font-display);
52
+ font-style: italic;
53
+ font-size: 1.25rem;
54
+ color: var(--text-secondary);
55
+ line-height: 1.5;
56
+ }
57
+
58
+ a {
59
+ color: var(--text-accent);
60
+ text-underline-offset: 3px;
61
+
62
+ &:hover {
63
+ opacity: 0.8;
64
+ }
65
+ }
66
+
67
+ code {
68
+ font-family: var(--font-mono);
69
+ font-size: 0.87em;
70
+ background: var(--surface-2);
71
+ border: 1px solid var(--border);
72
+ border-radius: var(--r-xs);
73
+ padding: 1px 5px;
74
+ color: var(--text-accent);
75
+ }
76
+
77
+ pre {
78
+ background: var(--code-block-bg);
79
+ border-radius: var(--r-lg);
80
+ padding: 20px;
81
+ overflow-x: auto;
82
+ margin: 1.5em 0;
83
+
84
+ code {
85
+ background: none;
86
+ border: none;
87
+ padding: 0;
88
+ color: var(--code-block-text);
89
+ font-size: 13px;
90
+ line-height: 1.75;
91
+ }
92
+ }
93
+
94
+ ul,
95
+ ol {
96
+ padding-left: 1.5em;
97
+ margin-bottom: 1.25em;
98
+ }
99
+
100
+ li {
101
+ margin-bottom: 0.4em;
102
+ line-height: 1.7;
103
+ }
104
+
105
+ img {
106
+ border-radius: var(--r-md);
107
+ border: 1px solid var(--border);
108
+ margin: 2em 0;
109
+ }
110
+
111
+ hr {
112
+ border: none;
113
+ border-top: 1px solid var(--border);
114
+ margin: 2.5em 0;
115
+ }
116
+
117
+ strong {
118
+ font-weight: 600;
119
+ color: var(--text-primary);
120
+ }
121
+
122
+ table {
123
+ width: 100%;
124
+ border-collapse: collapse;
125
+ font-size: 0.9em;
126
+ margin: 1.5em 0;
127
+ }
128
+
129
+ th {
130
+ font-family: var(--font-mono);
131
+ font-size: 0.7em;
132
+ letter-spacing: 0.1em;
133
+ text-transform: uppercase;
134
+ font-weight: 400;
135
+ color: var(--text-muted);
136
+ padding: 8px 12px;
137
+ border-bottom: 1px solid var(--border);
138
+ text-align: left;
139
+ }
140
+
141
+ td {
142
+ padding: 10px 12px;
143
+ border-bottom: 1px solid var(--border);
144
+ color: var(--text-primary);
145
+ }
146
+ }
@@ -0,0 +1,5 @@
1
+ @forward 'tokens';
2
+ @forward 'reset';
3
+ @forward 'theme';
4
+ @forward 'typography';
5
+ @forward 'focus';
@@ -0,0 +1,135 @@
1
+ /*
2
+ * FolioKit Design Tokens
3
+ *
4
+ * CSS custom-property contract for the FolioKit design system.
5
+ * Import this file in your angular.json "styles" array:
6
+ *
7
+ * "styles": ["@foliokit/cms-ui/src/styles/tokens.css"]
8
+ *
9
+ * All semantic tokens (--bg, --surface-*, --text-*, --btn-*, --logo-*)
10
+ * resolve against the active [data-theme] attribute on a parent element.
11
+ */
12
+
13
+ :root {
14
+ /* Slate — primary neutral (cool blue-grey) */
15
+ --slate-950: #0C0F14;
16
+ --slate-900: #151A23;
17
+ --slate-800: #1E2533;
18
+ --slate-700: #2D3748;
19
+ --slate-600: #4A5568;
20
+ --slate-500: #718096;
21
+ --slate-400: #A0AEC0;
22
+ --slate-300: #CBD5E0;
23
+ --slate-200: #E2E8F0;
24
+ --slate-100: #EDF2F7;
25
+ --slate-50: #F7FAFC;
26
+ /* Cloud — page surfaces */
27
+ --cloud-0: #FFFFFF;
28
+ --cloud-100: #F8FAFD;
29
+ --cloud-200: #F0F4F9;
30
+ --cloud-300: #E4ECF4;
31
+ /* Teal — brand accent */
32
+ --teal-900: #0D2B2B;
33
+ --teal-800: #134040;
34
+ --teal-700: #1A5C5C;
35
+ --teal-600: #217A7A;
36
+ --teal-500: #2A9797;
37
+ --teal-400: #38B2AC;
38
+ --teal-300: #6DD5CE;
39
+ --teal-200: #B2E8E5;
40
+ --teal-100: #E0F5F4;
41
+ --teal-50: #F0FAFA;
42
+ /* Violet — Angular flare, used sparingly */
43
+ --violet-600: #553C9A;
44
+ --violet-500: #6B46C1;
45
+ --violet-400: #805AD5;
46
+ --violet-100: #EDE9FE;
47
+ --violet-50: #F5F3FF;
48
+ /* Functional */
49
+ --green-700: #1A5C38;
50
+ --green-600: #22794A;
51
+ --green-100: #D4EDDA;
52
+ --blue-700: #1A3F7A;
53
+ --blue-600: #2252A4;
54
+ --blue-100: #D6E4F7;
55
+ --red-700: #7D1F1A;
56
+ --red-600: #A12B24;
57
+ --red-100: #F9DEDD;
58
+ /* Typography */
59
+ --font-display: 'Fraunces', Georgia, serif;
60
+ --font-body: 'Plus Jakarta Sans', system-ui, sans-serif;
61
+ --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
62
+ /* Radii */
63
+ --r-xs: 2px;
64
+ --r-sm: 4px;
65
+ --r-md: 6px;
66
+ --r-lg: 10px;
67
+ --r-xl: 14px;
68
+ --r-2xl: 20px;
69
+ }
70
+ [data-theme="light"] {
71
+ --bg: var(--cloud-100);
72
+ --bg-subtle: var(--cloud-200);
73
+ --surface-0: var(--cloud-0);
74
+ --surface-1: var(--cloud-100);
75
+ --surface-2: var(--cloud-200);
76
+ --surface-3: var(--cloud-300);
77
+ --border: var(--slate-200);
78
+ --border-strong: var(--slate-300);
79
+ --border-accent: var(--teal-300);
80
+ --text-primary: var(--slate-900);
81
+ --text-secondary: var(--slate-600);
82
+ --text-muted: var(--slate-400);
83
+ --text-disabled: var(--slate-300);
84
+ --text-accent: var(--teal-600);
85
+ --text-on-accent: #FFFFFF;
86
+ --text-on-dark: #E8EDF5;
87
+ --btn-primary-bg: var(--teal-500);
88
+ --btn-primary-text: #FFFFFF;
89
+ --btn-primary-hover: var(--teal-600);
90
+ --logo-bg: var(--slate-900);
91
+ --logo-text: var(--cloud-0);
92
+ --logo-dot: var(--teal-400);
93
+ --focus-ring: rgba(42, 151, 151, 0.22);
94
+ --focus-border: var(--teal-500);
95
+ --shadow-sm: 0 1px 3px rgba(12,15,20,0.07), 0 1px 2px rgba(12,15,20,0.04);
96
+ --shadow-md: 0 3px 10px rgba(12,15,20,0.08), 0 1px 4px rgba(12,15,20,0.05);
97
+ --shadow-lg: 0 8px 28px rgba(12,15,20,0.10), 0 2px 8px rgba(12,15,20,0.06);
98
+ --shadow-xl: 0 20px 56px rgba(12,15,20,0.12), 0 4px 16px rgba(12,15,20,0.07);
99
+ --nav-active-bg: var(--teal-50);
100
+ --nav-active-color: var(--teal-800);
101
+ color-scheme: light;
102
+ }
103
+ [data-theme="dark"] {
104
+ --bg: #1A1F2E;
105
+ --bg-subtle: #1E2535;
106
+ --surface-0: #242B3D;
107
+ --surface-1: #2A3347;
108
+ --surface-2: #303B52;
109
+ --surface-3: #3A4660;
110
+ --border: rgba(255, 255, 255, 0.09);
111
+ --border-strong: rgba(255, 255, 255, 0.16);
112
+ --border-accent: rgba(56, 178, 172, 0.40);
113
+ --text-primary: #E8EDF5;
114
+ --text-secondary: #9AACBF;
115
+ --text-muted: #5F7490;
116
+ --text-disabled: #3D4F63;
117
+ --text-accent: var(--teal-300);
118
+ --text-on-accent: var(--slate-950);
119
+ --text-on-dark: #E8EDF5;
120
+ --btn-primary-bg: var(--teal-400);
121
+ --btn-primary-text: var(--slate-950);
122
+ --btn-primary-hover: var(--teal-300);
123
+ --logo-bg: var(--teal-500);
124
+ --logo-text: #FFFFFF;
125
+ --logo-dot: var(--teal-200);
126
+ --focus-ring: rgba(56, 178, 172, 0.28);
127
+ --focus-border: var(--teal-400);
128
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.30);
129
+ --shadow-md: 0 3px 10px rgba(0,0,0,0.35);
130
+ --shadow-lg: 0 8px 28px rgba(0,0,0,0.40);
131
+ --shadow-xl: 0 20px 56px rgba(0,0,0,0.50);
132
+ --nav-active-bg: rgba(56, 178, 172, 0.14);
133
+ --nav-active-color: var(--text-primary);
134
+ color-scheme: dark;
135
+ }