@commonpub/layer 0.68.1 → 0.69.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.
@@ -29,6 +29,8 @@ import {
29
29
  SHADOW_PRESETS,
30
30
  RATIOS,
31
31
  FONTS,
32
+ DESIGN_ARCHETYPES,
33
+ type DesignArchetype,
32
34
  defaultRecipe,
33
35
  type HarmonyScheme,
34
36
  } from '@commonpub/theme-studio';
@@ -75,6 +77,44 @@ const SCHEMES: { val: HarmonyScheme; label: string }[] = [
75
77
  { val: 'monochrome', label: 'Mono' },
76
78
  ];
77
79
 
80
+ // --- Design-ethos archetype (Phase 3) ----------------------------------
81
+ // Applies a whole structural preset (shape/shadow/border/type/density/texture)
82
+ // while preserving the user's chosen color + mode, then tags the recipe.
83
+ function applyArchetype(a: DesignArchetype): void {
84
+ recipe.value = { ...recipe.value, ...a.patch, archetype: a.k };
85
+ }
86
+
87
+ // --- Neutral temperature (Phase 2) -------------------------------------
88
+ // Decouples surfaces/text from the accent hue. "Auto" = accent-tinted.
89
+ type NeutralMode = 'auto' | 'pure' | 'warm' | 'cool';
90
+ const NEUTRALS: { k: NeutralMode; label: string }[] = [
91
+ { k: 'auto', label: 'Auto' },
92
+ { k: 'pure', label: 'Pure' },
93
+ { k: 'warm', label: 'Warm' },
94
+ { k: 'cool', label: 'Cool' },
95
+ ];
96
+ const neutralMode = computed<NeutralMode>(() => {
97
+ if (recipe.value.neutralHue === undefined && recipe.value.neutralSat === undefined) return 'auto';
98
+ if ((recipe.value.neutralSat ?? 0) === 0) return 'pure';
99
+ const h = recipe.value.neutralHue ?? 0;
100
+ return h < 120 || h >= 300 ? 'warm' : 'cool';
101
+ });
102
+ function setNeutral(m: NeutralMode): void {
103
+ if (m === 'auto') {
104
+ recipe.value.neutralHue = undefined;
105
+ recipe.value.neutralSat = undefined;
106
+ } else if (m === 'pure') {
107
+ recipe.value.neutralHue = 0;
108
+ recipe.value.neutralSat = 0;
109
+ } else if (m === 'warm') {
110
+ recipe.value.neutralHue = 30;
111
+ recipe.value.neutralSat = 8;
112
+ } else {
113
+ recipe.value.neutralHue = 220;
114
+ recipe.value.neutralSat = 8;
115
+ }
116
+ }
117
+
78
118
  // --- Emit on every change ---------------------------------------------
79
119
 
80
120
  function emitGenerate(): void {
@@ -232,6 +272,24 @@ function finishWith(apply: boolean): void {
232
272
  <div class="cpub-studio-body">
233
273
  <!-- STEP 1: COLOR -->
234
274
  <div v-if="step === 0">
275
+ <div class="cpub-studio-arch">
276
+ <span class="cpub-studio-sublbl">Style <span class="cpub-studio-hint">sets shape, shadow, type &amp; feel</span></span>
277
+ <div class="cpub-studio-archgrid">
278
+ <button
279
+ v-for="a in DESIGN_ARCHETYPES"
280
+ :key="a.k"
281
+ type="button"
282
+ class="cpub-studio-archcard"
283
+ :class="{ on: recipe.archetype === a.k }"
284
+ :title="a.sub"
285
+ @click="applyArchetype(a)"
286
+ >
287
+ <span class="cpub-studio-archname">{{ a.label }}</span>
288
+ <span class="cpub-studio-archsub">{{ a.sub }}</span>
289
+ </button>
290
+ </div>
291
+ </div>
292
+
235
293
  <div class="cpub-studio-tabs">
236
294
  <button type="button" :class="{ on: colorTab === 'vibe' }" @click="colorTab = 'vibe'">By vibe</button>
237
295
  <button type="button" :class="{ on: colorTab === 'custom' }" @click="colorTab = 'custom'">My colors</button>
@@ -296,6 +354,12 @@ function finishWith(apply: boolean): void {
296
354
  <button v-for="sc in SCHEMES" :key="sc.val" type="button" :class="{ on: recipe.scheme === sc.val }" @click="recipe.scheme = sc.val">{{ sc.label }}</button>
297
355
  </span>
298
356
  </label>
357
+ <label class="cpub-studio-field">
358
+ <span class="cpub-studio-lbl">Neutral <span class="cpub-studio-hint">surface tint</span></span>
359
+ <span class="cpub-studio-seg">
360
+ <button v-for="n in NEUTRALS" :key="n.k" type="button" :class="{ on: neutralMode === n.k }" @click="setNeutral(n.k)">{{ n.label }}</button>
361
+ </span>
362
+ </label>
299
363
  <div class="cpub-studio-field">
300
364
  <span class="cpub-studio-lbl">Suggested family</span>
301
365
  <span class="cpub-studio-family">
@@ -502,6 +566,14 @@ function finishWith(apply: boolean): void {
502
566
  .cpub-studio-dots { display: flex; gap: 3px; }
503
567
  .cpub-studio-dots span { flex: 1; height: 14px; }
504
568
 
569
+ .cpub-studio-arch { margin-bottom: var(--space-3); }
570
+ .cpub-studio-archgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 6px; }
571
+ .cpub-studio-archcard { display: flex; flex-direction: column; gap: 2px; background: var(--surface2); border: var(--border-width-thin) solid var(--border2); padding: var(--space-2); cursor: pointer; text-align: left; }
572
+ .cpub-studio-archcard:hover { border-color: var(--text-faint); }
573
+ .cpub-studio-archcard.on { border-color: var(--accent); background: var(--accent-bg); }
574
+ .cpub-studio-archname { font-family: var(--font-mono); font-size: var(--text-label); font-weight: var(--font-weight-bold); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--text); }
575
+ .cpub-studio-archsub { font-size: var(--text-label); color: var(--text-faint); line-height: var(--leading-tight); }
576
+
505
577
  .cpub-studio-sublbl { font-family: var(--font-mono); font-size: var(--text-label); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--text-faint); margin: var(--space-4) 0 var(--space-2); }
506
578
  .cpub-studio-pallist, .cpub-studio-setlist { display: flex; flex-direction: column; gap: 6px; }
507
579
  .cpub-studio-palchip { display: flex; align-items: center; gap: var(--space-2); background: var(--surface2); border: var(--border-width-thin) solid var(--border2); padding: 6px 8px; cursor: pointer; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commonpub/layer",
3
- "version": "0.68.1",
3
+ "version": "0.69.0",
4
4
  "type": "module",
5
5
  "main": "./nuxt.config.ts",
6
6
  "files": [
@@ -56,14 +56,14 @@
56
56
  "@commonpub/auth": "0.8.0",
57
57
  "@commonpub/config": "0.20.0",
58
58
  "@commonpub/docs": "0.6.3",
59
- "@commonpub/learning": "0.5.2",
59
+ "@commonpub/protocol": "0.13.0",
60
60
  "@commonpub/explainer": "0.7.15",
61
- "@commonpub/editor": "0.7.11",
61
+ "@commonpub/learning": "0.5.2",
62
+ "@commonpub/schema": "0.38.0",
62
63
  "@commonpub/server": "2.83.0",
63
- "@commonpub/schema": "0.37.0",
64
- "@commonpub/theme-studio": "0.3.0",
65
- "@commonpub/ui": "0.12.0",
66
- "@commonpub/protocol": "0.13.0"
64
+ "@commonpub/ui": "0.12.1",
65
+ "@commonpub/editor": "0.7.11",
66
+ "@commonpub/theme-studio": "0.4.0"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@testing-library/jest-dom": "^6.9.1",
package/theme/base.css CHANGED
@@ -300,9 +300,35 @@ body {
300
300
  *::before,
301
301
  *::after {
302
302
  box-sizing: border-box;
303
+ }
304
+
305
+ /* Surface radius. Real UI surfaces (buttons, cards, inputs, tags, panels)
306
+ * inherit the theme's --radius. Structural, media, and decorative elements are
307
+ * reset to 0 below so a rounded theme (e.g. Stoa, --radius:12px) does NOT put
308
+ * radii on line breaks, dividers, rules, icons, images, table cells, or
309
+ * pseudo-element decorations — the "line breaks carry rounded corners" bug.
310
+ * (Elements that genuinely want rounding set it explicitly, e.g. avatars use
311
+ * --radius-full; an explicit class-level border-radius outranks these resets.) */
312
+ * {
303
313
  border-radius: var(--radius);
304
314
  }
305
315
 
316
+ hr,
317
+ svg,
318
+ img,
319
+ picture,
320
+ video,
321
+ canvas,
322
+ iframe,
323
+ table, thead, tbody, tfoot, tr, td, th, caption, col, colgroup,
324
+ ::before,
325
+ ::after,
326
+ ::marker,
327
+ ::placeholder,
328
+ .cpub-divider {
329
+ border-radius: 0;
330
+ }
331
+
306
332
  /* === ACCESSIBILITY === */
307
333
 
308
334
  /* Skip-to-content link */