@commonpub/layer 0.71.2 → 0.72.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/components/ContentCard.vue +4 -0
- package/components/VideoCard.vue +3 -0
- package/components/admin/theme/studio/AdminThemeStudio.vue +31 -1
- package/components/hub/HubHero.vue +3 -0
- package/layouts/default.vue +1 -0
- package/package.json +7 -7
- package/theme/base.css +10 -0
- package/theme/components.css +4 -0
- package/utils/themeDiscovery.ts +21 -1
|
@@ -164,6 +164,10 @@ function formatCount(n: number | undefined): string {
|
|
|
164
164
|
align-items: center;
|
|
165
165
|
justify-content: center;
|
|
166
166
|
overflow: hidden;
|
|
167
|
+
/* Edge-spanning section inside the card's overflow:hidden — the container
|
|
168
|
+
clips the outer corners; rounding HERE creates wedge gaps on rounded
|
|
169
|
+
themes (universal radius leak). */
|
|
170
|
+
border-radius: 0;
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
.cpub-cc-cover {
|
package/components/VideoCard.vue
CHANGED
|
@@ -55,6 +55,9 @@ function formatDuration(seconds: number | null | undefined): string {
|
|
|
55
55
|
background: var(--surface2);
|
|
56
56
|
border-bottom: var(--border-width-default) solid var(--border);
|
|
57
57
|
overflow: hidden;
|
|
58
|
+
/* Edge-spanning section inside the card's overflow:hidden — rounding here
|
|
59
|
+
creates wedge gaps on rounded themes; the container clips the corners. */
|
|
60
|
+
border-radius: 0;
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
.cpub-video-thumb img {
|
|
@@ -83,8 +83,30 @@ const SCHEMES: { val: HarmonyScheme; label: string }[] = [
|
|
|
83
83
|
// --- Design-ethos archetype (Phase 3) ----------------------------------
|
|
84
84
|
// Applies a whole structural preset (shape/shadow/border/type/density/texture)
|
|
85
85
|
// while preserving the user's chosen color + mode, then tags the recipe.
|
|
86
|
+
// `treatment` is REPLACED, not merged: switching Glass → Brutalist must clear
|
|
87
|
+
// the translucency, otherwise the ethos switch is incoherent.
|
|
86
88
|
function applyArchetype(a: DesignArchetype): void {
|
|
87
|
-
|
|
89
|
+
const { treatment, ...rest } = a.patch;
|
|
90
|
+
recipe.value = { ...recipe.value, ...rest, treatment, archetype: a.k };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// --- Surface treatment (glass + page gradient) --------------------------
|
|
94
|
+
// Normalized so "all off" stores `undefined` (keeps legacy recipes and the
|
|
95
|
+
// no-treatment projection byte-identical).
|
|
96
|
+
const glassPct = computed(() => Math.round((recipe.value.treatment?.glass ?? 0) * 100));
|
|
97
|
+
function setTreatment(patch: { glass?: number; bgGradient?: boolean }): void {
|
|
98
|
+
const next = {
|
|
99
|
+
glass: recipe.value.treatment?.glass ?? 0,
|
|
100
|
+
bgGradient: recipe.value.treatment?.bgGradient ?? false,
|
|
101
|
+
...patch,
|
|
102
|
+
};
|
|
103
|
+
recipe.value.treatment =
|
|
104
|
+
next.glass > 0 || next.bgGradient
|
|
105
|
+
? {
|
|
106
|
+
...(next.glass > 0 ? { glass: next.glass } : {}),
|
|
107
|
+
...(next.bgGradient ? { bgGradient: true } : {}),
|
|
108
|
+
}
|
|
109
|
+
: undefined;
|
|
88
110
|
}
|
|
89
111
|
|
|
90
112
|
// --- Neutral temperature (Phase 2) -------------------------------------
|
|
@@ -529,6 +551,14 @@ function finishWith(apply: boolean): void {
|
|
|
529
551
|
<span class="cpub-studio-lbl">Grain <span class="cpub-studio-val">{{ Math.round(recipe.texture * 100) }}%</span></span>
|
|
530
552
|
<input type="range" min="0" max="12" :value="Math.round(recipe.texture * 100)" class="cpub-studio-range" @input="recipe.texture = Number(($event.target as HTMLInputElement).value) / 100" />
|
|
531
553
|
</label>
|
|
554
|
+
<label class="cpub-studio-field">
|
|
555
|
+
<span class="cpub-studio-lbl">Glass <span class="cpub-studio-val">{{ glassPct }}%</span></span>
|
|
556
|
+
<input type="range" min="0" max="30" :value="glassPct" class="cpub-studio-range" aria-label="Glass strength" @input="setTreatment({ glass: Number(($event.target as HTMLInputElement).value) / 100 })" />
|
|
557
|
+
</label>
|
|
558
|
+
<div class="cpub-studio-toggle-line">
|
|
559
|
+
<span class="cpub-studio-lbl">Background gradient <span class="cpub-studio-hint">tints toward accent</span></span>
|
|
560
|
+
<button type="button" class="cpub-studio-switch" :class="{ on: recipe.treatment?.bgGradient }" :aria-pressed="Boolean(recipe.treatment?.bgGradient)" aria-label="Toggle background gradient" @click="setTreatment({ bgGradient: !recipe.treatment?.bgGradient })" />
|
|
561
|
+
</div>
|
|
532
562
|
<label class="cpub-studio-field">
|
|
533
563
|
<span class="cpub-studio-lbl">Motion</span>
|
|
534
564
|
<span class="cpub-studio-seg">
|
|
@@ -67,6 +67,9 @@ const isCompanyHub = computed(() => hubType.value === 'company');
|
|
|
67
67
|
position: relative;
|
|
68
68
|
overflow: hidden;
|
|
69
69
|
border-bottom: var(--border-width-default) solid var(--border);
|
|
70
|
+
/* Edge-spanning band inside the hero's overflow:hidden — rounding here
|
|
71
|
+
creates wedge gaps on rounded themes; the container clips the corners. */
|
|
72
|
+
border-radius: 0;
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
.cpub-hub-banner-pattern {
|
package/layouts/default.vue
CHANGED
|
@@ -281,6 +281,7 @@ const userUsername = computed(() => user.value?.username ?? '');
|
|
|
281
281
|
border-bottom-left-radius: var(--cpub-topbar-radius, 0);
|
|
282
282
|
border-bottom-right-radius: var(--cpub-topbar-radius, 0);
|
|
283
283
|
box-shadow: var(--cpub-topbar-shadow, none);
|
|
284
|
+
-webkit-backdrop-filter: var(--cpub-topbar-blur, none);
|
|
284
285
|
backdrop-filter: var(--cpub-topbar-blur, none);
|
|
285
286
|
display: flex; align-items: center;
|
|
286
287
|
padding: 0 var(--cpub-topbar-padding-x, 20px); gap: 0; z-index: 100;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commonpub/layer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"files": [
|
|
@@ -55,15 +55,15 @@
|
|
|
55
55
|
"zod": "^4.3.6",
|
|
56
56
|
"@commonpub/auth": "0.8.0",
|
|
57
57
|
"@commonpub/config": "0.21.0",
|
|
58
|
+
"@commonpub/server": "2.84.1",
|
|
59
|
+
"@commonpub/ui": "0.13.0",
|
|
60
|
+
"@commonpub/learning": "0.5.2",
|
|
61
|
+
"@commonpub/theme-studio": "0.6.0",
|
|
58
62
|
"@commonpub/docs": "0.6.3",
|
|
63
|
+
"@commonpub/schema": "0.40.0",
|
|
59
64
|
"@commonpub/editor": "0.7.11",
|
|
60
|
-
"@commonpub/explainer": "0.7.15",
|
|
61
|
-
"@commonpub/learning": "0.5.2",
|
|
62
65
|
"@commonpub/protocol": "0.13.0",
|
|
63
|
-
"@commonpub/
|
|
64
|
-
"@commonpub/server": "2.84.1",
|
|
65
|
-
"@commonpub/theme-studio": "0.5.1",
|
|
66
|
-
"@commonpub/ui": "0.12.2"
|
|
66
|
+
"@commonpub/explainer": "0.7.15"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@testing-library/jest-dom": "^6.9.1",
|
package/theme/base.css
CHANGED
|
@@ -216,6 +216,15 @@
|
|
|
216
216
|
--shadow-block: 4px 4px 0 var(--border);
|
|
217
217
|
--shadow-block-sm: 2px 2px 0 var(--border);
|
|
218
218
|
|
|
219
|
+
/* === TREATMENTS ===
|
|
220
|
+
Surface effects. Defaults are TRUE no-ops: `none`, never `blur(0)` — any
|
|
221
|
+
non-none backdrop-filter creates a stacking context and becomes the
|
|
222
|
+
containing block for fixed/absolute descendants, which would move
|
|
223
|
+
dropdowns/modals on every existing theme. Built-in themes don't set
|
|
224
|
+
these; Theme Studio emits them for glass recipes. */
|
|
225
|
+
--surface-backdrop: none; /* backdrop-filter for cards/panels (glass) */
|
|
226
|
+
--bg-image: none; /* page background gradient (gradients only) */
|
|
227
|
+
|
|
219
228
|
/* === TRANSITIONS === */
|
|
220
229
|
--transition-fast: 0.1s ease;
|
|
221
230
|
--transition-default: 0.15s ease;
|
|
@@ -298,6 +307,7 @@ body {
|
|
|
298
307
|
line-height: var(--leading-normal);
|
|
299
308
|
color: var(--text);
|
|
300
309
|
background-color: var(--bg);
|
|
310
|
+
background-image: var(--bg-image, none);
|
|
301
311
|
-webkit-font-smoothing: antialiased;
|
|
302
312
|
-moz-osx-font-smoothing: grayscale;
|
|
303
313
|
}
|
package/theme/components.css
CHANGED
|
@@ -90,6 +90,10 @@
|
|
|
90
90
|
padding: 16px;
|
|
91
91
|
margin-bottom: 12px;
|
|
92
92
|
box-shadow: var(--shadow-block);
|
|
93
|
+
/* Glass treatment hook — `none` by default (a true no-op; non-none values
|
|
94
|
+
create a stacking context, so only opted-in themes pay that cost). */
|
|
95
|
+
-webkit-backdrop-filter: var(--surface-backdrop, none);
|
|
96
|
+
backdrop-filter: var(--surface-backdrop, none);
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
.cpub-sb-title {
|
package/utils/themeDiscovery.ts
CHANGED
|
@@ -15,6 +15,25 @@ export interface DiscoveredTheme {
|
|
|
15
15
|
isDark: boolean;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Substitute `var(--x)` / `var(--x, fallback)` references in a default
|
|
20
|
+
* value using a property getter (computed style). getComputedStyle returns
|
|
21
|
+
* custom properties with their var() references ALREADY substituted, so a
|
|
22
|
+
* spec default like `var(--surface)` must be resolved the same way before
|
|
23
|
+
* diffing — otherwise every var()-defaulted token (font-heading, the chrome
|
|
24
|
+
* family) reads as "overridden" on a stock site.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveVarRefs(get: (name: string) => string, value: string): string {
|
|
27
|
+
let out = value;
|
|
28
|
+
for (let i = 0; i < 4 && out.includes('var('); i++) {
|
|
29
|
+
out = out.replace(/var\((--[a-zA-Z0-9_-]+)(?:,\s*([^()]*))?\)/g, (_, name: string, fb?: string) => {
|
|
30
|
+
const v = get(name).trim();
|
|
31
|
+
return v || fb || '';
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
|
|
18
37
|
/**
|
|
19
38
|
* Read `getComputedStyle(:root)` for every canonical token and return
|
|
20
39
|
* the subset that differs from `TOKEN_SPECS[i].default`.
|
|
@@ -23,11 +42,12 @@ export function detectAppliedOverrides(): DiscoveredTheme {
|
|
|
23
42
|
if (typeof window === 'undefined') return { count: 0, tokens: {}, isDark: false };
|
|
24
43
|
const root = document.documentElement;
|
|
25
44
|
const cs = getComputedStyle(root);
|
|
45
|
+
const get = (name: string): string => cs.getPropertyValue(name);
|
|
26
46
|
const overrides: Record<string, string> = {};
|
|
27
47
|
for (const spec of TOKEN_SPECS) {
|
|
28
48
|
const actual = cs.getPropertyValue(`--${spec.key}`).trim();
|
|
29
49
|
if (!actual) continue;
|
|
30
|
-
if (normalize(actual) !== normalize(spec.default)) {
|
|
50
|
+
if (normalize(actual) !== normalize(resolveVarRefs(get, spec.default))) {
|
|
31
51
|
overrides[spec.key] = actual;
|
|
32
52
|
}
|
|
33
53
|
}
|