@commonpub/layer 0.3.38 → 0.4.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.
@@ -0,0 +1,456 @@
1
+ @layer commonpub {
2
+ /* ===========================================
3
+ CommonPub Agora Theme — Light
4
+ "Where makers gather, build, and share."
5
+
6
+ Warm institutional aesthetic: parchment
7
+ backgrounds, commons green accent, Fraunces
8
+ serif display, Work Sans body, soft rgba
9
+ borders, paper texture, snappy easing.
10
+
11
+ This is a COMPLETE design system, not just
12
+ a color swap. It overrides tokens AND
13
+ component styles.
14
+ =========================================== */
15
+
16
+ [data-theme="agora"] {
17
+ /* === SURFACES (warm, paper-like) === */
18
+ --bg: #f7f4ed;
19
+ --surface: #faf8f3;
20
+ --surface2: #ece8de;
21
+ --surface3: #e2ddd2;
22
+
23
+ --color-surface: var(--surface);
24
+ --color-surface-alt: var(--surface2);
25
+ --color-surface-raised: var(--surface);
26
+ --color-surface-overlay: rgba(26, 26, 26, 0.5);
27
+ --color-surface-overlay-light: rgba(26, 26, 26, 0.4);
28
+ --color-surface-scrim: rgba(247, 244, 237, 0.75);
29
+ --color-surface-hover: var(--surface2);
30
+ --color-bg-subtle: var(--bg);
31
+
32
+ /* === TEXT (ink gradations) === */
33
+ --text: #1a1a1a;
34
+ --text-dim: #4a4a44;
35
+ --text-faint: #7a7a72;
36
+
37
+ --color-text: var(--text);
38
+ --color-text-secondary: var(--text-dim);
39
+ --color-text-muted: var(--text-faint);
40
+ --color-text-inverse: #f7f4ed;
41
+
42
+ /* === BORDERS (soft, warm) === */
43
+ --border: rgba(26, 26, 26, 0.25);
44
+ --border2: rgba(26, 26, 26, 0.12);
45
+
46
+ --color-border: var(--border2);
47
+ --color-border-strong: var(--border);
48
+ --color-border-focus: var(--accent);
49
+
50
+ /* === ACCENT (commons green) === */
51
+ --accent: #3d8b5e;
52
+ --accent-bg: rgba(61, 139, 94, 0.08);
53
+ --accent-bg-strong: rgba(61, 139, 94, 0.2);
54
+ --accent-bg-heavy: rgba(61, 139, 94, 0.4);
55
+ --accent-bg-solid: rgba(61, 139, 94, 0.6);
56
+ --accent-border: rgba(61, 139, 94, 0.25);
57
+ --accent-focus-ring: 0 0 0 3px rgba(61, 139, 94, 0.12);
58
+
59
+ --color-primary: var(--accent);
60
+ --color-primary-hover: #348050;
61
+ --color-primary-text: #ffffff;
62
+ --color-on-primary: #ffffff;
63
+ --color-accent: var(--accent);
64
+ --color-accent-hover: #348050;
65
+ --color-accent-text: #ffffff;
66
+ --color-on-accent: #ffffff;
67
+ --color-accent-bg: var(--accent-bg);
68
+ --color-accent-border: var(--accent-border);
69
+
70
+ /* === SEMANTIC COLORS (warm palette) === */
71
+ --green: #3d8b5e;
72
+ --green-bg: rgba(61, 139, 94, 0.08);
73
+ --green-border: rgba(61, 139, 94, 0.25);
74
+
75
+ --yellow: #c4882a;
76
+ --yellow-bg: rgba(196, 136, 42, 0.08);
77
+ --yellow-border: rgba(196, 136, 42, 0.25);
78
+
79
+ --red: #c4443a;
80
+ --red-bg: rgba(196, 68, 58, 0.08);
81
+ --red-border: rgba(196, 68, 58, 0.25);
82
+
83
+ --purple: #7b5ea7;
84
+ --purple-bg: rgba(123, 94, 167, 0.08);
85
+ --purple-border: rgba(123, 94, 167, 0.25);
86
+
87
+ --teal: #2a9d8f;
88
+ --teal-bg: rgba(42, 157, 143, 0.08);
89
+ --teal-border: rgba(42, 157, 143, 0.25);
90
+
91
+ --pink: #b85a7a;
92
+ --pink-bg: rgba(184, 90, 122, 0.08);
93
+ --pink-border: rgba(184, 90, 122, 0.25);
94
+
95
+ --color-success: var(--green);
96
+ --color-warning: var(--yellow);
97
+ --color-error: var(--red);
98
+ --color-info: #4a7fb8;
99
+ --color-success-bg: var(--green-bg);
100
+ --color-warning-bg: var(--yellow-bg);
101
+ --color-error-bg: var(--red-bg);
102
+ --color-info-bg: rgba(74, 127, 184, 0.08);
103
+
104
+ /* === OVERLAYS === */
105
+ --color-badge-overlay: rgba(26, 26, 26, 0.75);
106
+
107
+ /* === INTERACTIVE === */
108
+ --color-link: #2a6342;
109
+ --color-link-hover: #1e4f32;
110
+
111
+ /* === TYPOGRAPHY (warm, distinctive) === */
112
+ --font-sans: 'Work Sans', system-ui, -apple-system, sans-serif;
113
+ --font-mono: 'JetBrains Mono', ui-monospace, monospace;
114
+ --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
115
+
116
+ --font-heading: var(--font-display);
117
+ --font-body: var(--font-sans);
118
+
119
+ /* Font Sizes (Agora scale) */
120
+ --text-xs: 0.6875rem; /* 11px */
121
+ --text-sm: 0.8125rem; /* 13px */
122
+ --text-base: 0.9375rem; /* 15px */
123
+ --text-md: 1.0625rem; /* 17px */
124
+ --text-lg: 1.25rem; /* 20px */
125
+ --text-xl: 1.5rem; /* 24px */
126
+ --text-2xl: 1.875rem; /* 30px */
127
+ --text-3xl: 2.375rem; /* 38px */
128
+ --text-4xl: 3rem; /* 48px */
129
+ --text-5xl: 4rem; /* 64px */
130
+ --text-label: 0.625rem; /* 10px — monospace UI labels */
131
+
132
+ /* Line Heights */
133
+ --leading-tight: 1.15;
134
+ --leading-snug: 1.35;
135
+ --leading-normal: 1.7;
136
+ --leading-relaxed: 1.9;
137
+
138
+ /* Letter Spacing (wider for Agora's institutional feel) */
139
+ --tracking-tight: -0.02em;
140
+ --tracking-normal: 0;
141
+ --tracking-wide: 0.06em;
142
+ --tracking-wider: 0.1em;
143
+ --tracking-widest: 0.16em;
144
+
145
+ /* === SHADOWS (offset, warm ink) === */
146
+ --shadow-sm: 2px 2px 0 rgba(26, 26, 26, 0.25);
147
+ --shadow-md: 4px 4px 0 rgba(26, 26, 26, 0.25);
148
+ --shadow-lg: 6px 6px 0 rgba(26, 26, 26, 0.25);
149
+ --shadow-xl: 8px 8px 0 rgba(26, 26, 26, 0.25);
150
+ --shadow-accent: 4px 4px 0 var(--accent);
151
+
152
+ /* === TRANSITIONS (snappy) === */
153
+ --transition-fast: 120ms cubic-bezier(0.22, 1, 0.36, 1);
154
+ --transition-default: 250ms cubic-bezier(0.22, 1, 0.36, 1);
155
+ --transition-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);
156
+
157
+ /* === FOCUS (glow instead of outline) === */
158
+ --focus-ring: 0 0 0 3px rgba(61, 139, 94, 0.2);
159
+ }
160
+
161
+
162
+ /* ═══════════════════════════════════════════
163
+ PAPER TEXTURE OVERLAY
164
+ Subtle noise that gives everything a
165
+ tactile, printed-on-paper feel.
166
+ ═══════════════════════════════════════════ */
167
+
168
+ [data-theme="agora"] body::after {
169
+ content: '';
170
+ position: fixed;
171
+ inset: 0;
172
+ pointer-events: none;
173
+ z-index: 9999;
174
+ opacity: 0.02;
175
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
176
+ }
177
+
178
+
179
+ /* ═══════════════════════════════════════════
180
+ TYPOGRAPHY OVERRIDES
181
+ Fraunces for display/headings, Work Sans
182
+ for body, wider tracking on labels.
183
+ ═══════════════════════════════════════════ */
184
+
185
+ [data-theme="agora"] h1,
186
+ [data-theme="agora"] h2,
187
+ [data-theme="agora"] h3 {
188
+ font-family: var(--font-display);
189
+ }
190
+
191
+ /* Focus: glow instead of outline */
192
+ [data-theme="agora"] :focus-visible {
193
+ outline: none;
194
+ box-shadow: var(--focus-ring);
195
+ }
196
+
197
+
198
+ /* ═══════════════════════════════════════════
199
+ COMPONENT: TOPBAR / NAVIGATION
200
+ ═══════════════════════════════════════════ */
201
+
202
+ [data-theme="agora"] .cpub-topbar {
203
+ background: var(--surface);
204
+ border-bottom-color: var(--border);
205
+ }
206
+
207
+ /* Agora wordmark in topbar */
208
+ [data-theme="agora"] .cpub-site-logo .cpub-logo-name {
209
+ font-family: var(--font-display);
210
+ font-weight: 700;
211
+ letter-spacing: -0.02em;
212
+ }
213
+
214
+ [data-theme="agora"] .cpub-site-logo .cpub-logo-bracket {
215
+ color: var(--accent);
216
+ }
217
+
218
+ [data-theme="agora"] .cpub-topbar-link.router-link-active {
219
+ color: var(--accent);
220
+ }
221
+
222
+
223
+ /* ═══════════════════════════════════════════
224
+ COMPONENT: BUTTONS
225
+ Snappy easing, green primary, softer borders.
226
+ ═══════════════════════════════════════════ */
227
+
228
+ [data-theme="agora"] .cpub-btn {
229
+ border-color: var(--border);
230
+ transition: transform var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
231
+ }
232
+
233
+ [data-theme="agora"] .cpub-btn:hover {
234
+ transform: translateY(-1px);
235
+ box-shadow: var(--shadow-sm);
236
+ }
237
+
238
+ [data-theme="agora"] .cpub-btn:active {
239
+ transform: translateY(0);
240
+ box-shadow: none;
241
+ }
242
+
243
+ [data-theme="agora"] .cpub-btn-primary {
244
+ background: var(--accent);
245
+ border-color: #2a6342;
246
+ box-shadow: var(--shadow-md);
247
+ }
248
+
249
+ [data-theme="agora"] .cpub-btn-primary:hover {
250
+ background: #348050;
251
+ box-shadow: var(--shadow-accent);
252
+ transform: translateY(-1px);
253
+ }
254
+
255
+ [data-theme="agora"] .cpub-btn-ghost {
256
+ color: var(--accent);
257
+ border-color: transparent;
258
+ }
259
+
260
+ [data-theme="agora"] .cpub-btn-ghost:hover {
261
+ color: #2a6342;
262
+ background: var(--accent-bg);
263
+ }
264
+
265
+
266
+ /* ═══════════════════════════════════════════
267
+ COMPONENT: CARDS
268
+ Linen backgrounds, soft borders, accent
269
+ left-border treatment on hover.
270
+ ═══════════════════════════════════════════ */
271
+
272
+ [data-theme="agora"] .cpub-sb-card,
273
+ [data-theme="agora"] .cpub-stat-card {
274
+ background: var(--bg);
275
+ border-color: var(--border);
276
+ box-shadow: var(--shadow-sm);
277
+ }
278
+
279
+ [data-theme="agora"] .cpub-sb-card:hover,
280
+ [data-theme="agora"] .cpub-stat-card:hover {
281
+ box-shadow: var(--shadow-md);
282
+ }
283
+
284
+ /* Content cards get accent left border on hover */
285
+ [data-theme="agora"] .cpub-content-card {
286
+ border-color: var(--border);
287
+ background: var(--surface);
288
+ transition: transform var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast);
289
+ }
290
+
291
+ [data-theme="agora"] .cpub-content-card:hover {
292
+ border-left-color: var(--accent);
293
+ border-left-width: 4px;
294
+ transform: translateY(-2px);
295
+ box-shadow: var(--shadow-md);
296
+ }
297
+
298
+ /* Card headers use display font */
299
+ [data-theme="agora"] .cpub-content-card h3,
300
+ [data-theme="agora"] .cpub-content-card .cpub-card-title {
301
+ font-family: var(--font-display);
302
+ font-weight: 700;
303
+ }
304
+
305
+
306
+ /* ═══════════════════════════════════════════
307
+ COMPONENT: INPUTS & FORMS
308
+ Soft borders, glow focus ring.
309
+ ═══════════════════════════════════════════ */
310
+
311
+ [data-theme="agora"] .cpub-input,
312
+ [data-theme="agora"] .cpub-textarea,
313
+ [data-theme="agora"] .cpub-select {
314
+ border-color: var(--border);
315
+ background: var(--bg);
316
+ transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
317
+ }
318
+
319
+ [data-theme="agora"] .cpub-input:focus,
320
+ [data-theme="agora"] .cpub-textarea:focus,
321
+ [data-theme="agora"] .cpub-select:focus {
322
+ border-color: var(--accent);
323
+ box-shadow: var(--focus-ring);
324
+ outline: none;
325
+ }
326
+
327
+ /* Form labels get wider tracking */
328
+ [data-theme="agora"] .cpub-form-label {
329
+ letter-spacing: var(--tracking-wider);
330
+ }
331
+
332
+
333
+ /* ═══════════════════════════════════════════
334
+ COMPONENT: BADGES & TAGS
335
+ Thinner borders (1px), warmer palette.
336
+ ═══════════════════════════════════════════ */
337
+
338
+ [data-theme="agora"] .cpub-tag {
339
+ border-width: 1px;
340
+ }
341
+
342
+ [data-theme="agora"] .cpub-badge-filled {
343
+ background: var(--accent);
344
+ border-color: var(--accent);
345
+ color: #fff;
346
+ }
347
+
348
+
349
+ /* ═══════════════════════════════════════════
350
+ COMPONENT: SECTION TITLES & HEADINGS
351
+ Fraunces display, green accent numbers.
352
+ ═══════════════════════════════════════════ */
353
+
354
+ [data-theme="agora"] .cpub-section-title-lg {
355
+ font-family: var(--font-display);
356
+ font-weight: 700;
357
+ }
358
+
359
+ [data-theme="agora"] .cpub-section-title-sm {
360
+ font-family: var(--font-display);
361
+ font-weight: 600;
362
+ }
363
+
364
+ [data-theme="agora"] .admin-page-title {
365
+ font-family: var(--font-display);
366
+ }
367
+
368
+
369
+ /* ═══════════════════════════════════════════
370
+ COMPONENT: LINKS
371
+ Green links with underline offset.
372
+ ═══════════════════════════════════════════ */
373
+
374
+ [data-theme="agora"] a:not(.cpub-btn):not(.cpub-topbar-link):not(.cpub-footer-link):not(.admin-nav-link) {
375
+ text-decoration-color: rgba(61, 139, 94, 0.3);
376
+ text-underline-offset: 2px;
377
+ }
378
+
379
+
380
+ /* ═══════════════════════════════════════════
381
+ COMPONENT: FOOTER
382
+ Warm treatment, serif brand name.
383
+ ═══════════════════════════════════════════ */
384
+
385
+ [data-theme="agora"] .cpub-footer {
386
+ border-top-color: var(--border);
387
+ }
388
+
389
+ [data-theme="agora"] .cpub-footer-logo .cpub-logo-name {
390
+ font-family: var(--font-display);
391
+ font-weight: 700;
392
+ }
393
+
394
+ [data-theme="agora"] .cpub-footer-col-title {
395
+ letter-spacing: var(--tracking-widest);
396
+ }
397
+
398
+
399
+ /* ═══════════════════════════════════════════
400
+ PROSE / CONTENT AREA
401
+ Serif headings, warmer body feel.
402
+ ═══════════════════════════════════════════ */
403
+
404
+ [data-theme="agora"] .cpub-prose h1,
405
+ [data-theme="agora"] .cpub-prose h2,
406
+ [data-theme="agora"] .cpub-prose h3,
407
+ [data-theme="agora"] .cpub-prose h4 {
408
+ font-family: var(--font-display);
409
+ }
410
+
411
+ [data-theme="agora"] .cpub-prose blockquote {
412
+ border-left-color: var(--accent);
413
+ background: var(--accent-bg);
414
+ }
415
+
416
+ [data-theme="agora"] .cpub-prose a {
417
+ color: var(--accent);
418
+ text-decoration-color: rgba(61, 139, 94, 0.3);
419
+ }
420
+
421
+ [data-theme="agora"] .cpub-prose code {
422
+ background: var(--surface2);
423
+ border-color: var(--border2);
424
+ }
425
+
426
+
427
+ /* ═══════════════════════════════════════════
428
+ ADMIN LAYOUT
429
+ Warm sidebar, serif titles.
430
+ ═══════════════════════════════════════════ */
431
+
432
+ [data-theme="agora"] .admin-brand {
433
+ font-family: var(--font-display);
434
+ }
435
+
436
+ [data-theme="agora"] .admin-nav-link.router-link-exact-active {
437
+ color: var(--accent);
438
+ background: var(--accent-bg);
439
+ }
440
+
441
+ [data-theme="agora"] .admin-badge {
442
+ background: var(--accent);
443
+ }
444
+
445
+
446
+ /* ═══════════════════════════════════════════
447
+ CONTENT TYPE BADGE COLORS (Agora palette)
448
+ ═══════════════════════════════════════════ */
449
+
450
+ [data-theme="agora"] [data-content-type="article"] { --badge-color: #4a7fb8; --badge-bg: rgba(74, 127, 184, 0.08); }
451
+ [data-theme="agora"] [data-content-type="blog"] { --badge-color: #3d8b5e; --badge-bg: rgba(61, 139, 94, 0.08); }
452
+ [data-theme="agora"] [data-content-type="project"] { --badge-color: #7b5ea7; --badge-bg: rgba(123, 94, 167, 0.08); }
453
+ [data-theme="agora"] [data-content-type="explainer"] { --badge-color: #2a9d8f; --badge-bg: rgba(42, 157, 143, 0.08); }
454
+ [data-theme="agora"] [data-content-type="video"] { --badge-color: #c4443a; --badge-bg: rgba(196, 68, 58, 0.08); }
455
+ [data-theme="agora"] [data-content-type="tutorial"] { --badge-color: #c4882a; --badge-bg: rgba(196, 136, 42, 0.08); }
456
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared theme family configuration.
3
+ * Used by both server (instanceTheme.ts) and client (useTheme.ts).
4
+ *
5
+ * To add a new theme:
6
+ * 1. Create the CSS file(s) in packages/ui/theme/
7
+ * 2. Register in packages/ui/src/theme.ts BUILT_IN_THEMES
8
+ * 3. Add the family mapping here
9
+ * 4. Add theme ID to VALID_IDS in server/utils/instanceTheme.ts
10
+ * 5. Add CSS import in layers/base/nuxt.config.ts
11
+ */
12
+
13
+ /** Map every theme ID to its family name */
14
+ export const THEME_TO_FAMILY: Record<string, string> = {
15
+ base: 'classic',
16
+ dark: 'classic',
17
+ generics: 'generics',
18
+ agora: 'agora',
19
+ 'agora-dark': 'agora',
20
+ };
21
+
22
+ /** Light/dark variants for each family */
23
+ export const FAMILY_VARIANTS: Record<string, { light: string; dark: string }> = {
24
+ classic: { light: 'base', dark: 'dark' },
25
+ agora: { light: 'agora', dark: 'agora-dark' },
26
+ generics: { light: 'generics', dark: 'generics' },
27
+ };
28
+
29
+ /** Whether a theme ID is a dark theme */
30
+ export const IS_DARK: Record<string, boolean> = {
31
+ base: false,
32
+ dark: true,
33
+ generics: true,
34
+ agora: false,
35
+ 'agora-dark': true,
36
+ };
37
+
38
+ /** All valid theme IDs */
39
+ export const VALID_THEME_IDS = new Set(Object.keys(THEME_TO_FAMILY));