@commonpub/layer 0.43.1 → 0.43.2

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.
@@ -266,20 +266,50 @@ const userUsername = computed(() => user.value?.username ?? '');
266
266
 
267
267
  .cpub-layout { min-height: 100vh; display: flex; flex-direction: column; }
268
268
 
269
- /* ═══ TOPBAR ═══ */
269
+ /* ═══ TOPBAR ═══
270
+ Structure is token-driven (--cpub-topbar-*) so a theme can change the bar's SHAPE
271
+ — height, radius, shadow, position, padding — not just its colors, without forking
272
+ this layout. Every default reproduces the current flat 48px bar exactly.
273
+ (Centering the bar's CONTENT at a max width while keeping a full-bleed background
274
+ needs an inner wrapper element, which the base markup doesn't have — that one
275
+ aspect stays a structural choice, not a token.) */
270
276
  .cpub-topbar {
271
- position: fixed; top: 0; left: 0; right: 0; height: 48px;
272
- background: var(--surface); border-bottom: var(--border-width-default) solid var(--border);
273
- display: flex; align-items: center; padding: 0 20px; gap: 0; z-index: 100;
277
+ position: var(--cpub-topbar-position, fixed); top: 0; left: 0; right: 0;
278
+ height: var(--cpub-topbar-height, 48px);
279
+ background: var(--cpub-topbar-bg, var(--surface));
280
+ border-bottom: var(--cpub-topbar-border, var(--border-width-default) solid var(--border));
281
+ border-bottom-left-radius: var(--cpub-topbar-radius, 0);
282
+ border-bottom-right-radius: var(--cpub-topbar-radius, 0);
283
+ box-shadow: var(--cpub-topbar-shadow, none);
284
+ backdrop-filter: var(--cpub-topbar-blur, none);
285
+ display: flex; align-items: center;
286
+ padding: 0 var(--cpub-topbar-padding-x, 20px); gap: 0; z-index: 100;
274
287
  }
275
288
  .cpub-topbar-logo { display: flex; align-items: center; flex-shrink: 0; text-decoration: none; color: var(--text); }
276
289
 
277
290
  /* Nav styles use :deep() to reach into NavRenderer/NavDropdown/NavLink child components */
278
291
  :deep(.cpub-topbar-nav) { display: flex; align-items: center; gap: 2px; margin-left: 24px; }
279
- :deep(.cpub-nav-link) { font-size: 12px; color: var(--text-dim); padding: 5px 12px; border: var(--border-width-default) solid transparent; background: none; text-decoration: none; transition: color 0.15s, background 0.15s; display: flex; align-items: center; gap: 6px; }
292
+ /* Nav-link shape + active state are token-driven (--cpub-nav-link-*) so a theme can
293
+ make pill-shaped/larger/accent-colored nav links (deveco) without forking. Defaults
294
+ = the current 12px square neutral link. */
295
+ :deep(.cpub-nav-link) {
296
+ font-size: var(--cpub-nav-link-size, 12px);
297
+ font-weight: var(--cpub-nav-link-weight, 400);
298
+ color: var(--cpub-nav-link-color, var(--text-dim));
299
+ padding: var(--cpub-nav-link-padding, 5px 12px);
300
+ border: var(--border-width-default) solid transparent;
301
+ border-radius: var(--cpub-nav-link-radius, var(--radius));
302
+ background: none; text-decoration: none;
303
+ transition: color 0.15s, background 0.15s; display: flex; align-items: center; gap: 6px;
304
+ }
280
305
  :deep(.cpub-nav-link i) { font-size: 10px; }
281
306
  :deep(.cpub-nav-link:hover) { color: var(--text); background: var(--surface2); }
282
- :deep(.cpub-nav-link.router-link-active) { color: var(--text); background: var(--surface2); border-color: var(--border); }
307
+ :deep(.cpub-nav-link.router-link-active) {
308
+ color: var(--cpub-nav-link-active-color, var(--text));
309
+ background: var(--cpub-nav-link-active-bg, var(--surface2));
310
+ border-color: var(--cpub-nav-link-active-border, var(--border));
311
+ font-weight: var(--cpub-nav-link-active-weight, 400);
312
+ }
283
313
  :deep(.cpub-nav-link--disabled) { opacity: 0.35; cursor: not-allowed; pointer-events: none; }
284
314
 
285
315
  /* Nav dropdowns */
@@ -343,7 +373,7 @@ const userUsername = computed(() => user.value?.username ?? '');
343
373
  .cpub-dropdown-item--mobile { display: none; }
344
374
 
345
375
  .cpub-mobile-toggle { display: none; width: 32px; height: 32px; background: none; border: var(--border-width-default) solid transparent; color: var(--text-dim); font-size: 16px; cursor: pointer; align-items: center; justify-content: center; }
346
- .cpub-mobile-menu { display: none; position: fixed; inset: 0; top: 48px; z-index: 99; background: var(--color-surface-overlay-light); }
376
+ .cpub-mobile-menu { display: none; position: fixed; inset: 0; top: var(--cpub-topbar-height, 48px); z-index: 99; background: var(--color-surface-overlay-light); }
347
377
  :deep(.cpub-mobile-nav) { background: var(--surface); border-bottom: var(--border-width-default) solid var(--border); padding: 8px 0; display: flex; flex-direction: column; box-shadow: var(--shadow-md); }
348
378
  :deep(.cpub-mobile-link) { display: flex; align-items: center; gap: 10px; padding: 10px 20px; font-size: 13px; color: var(--text-dim); text-decoration: none; transition: background 0.1s; }
349
379
  :deep(.cpub-mobile-link:hover) { background: var(--surface2); color: var(--text); }
@@ -351,22 +381,27 @@ const userUsername = computed(() => user.value?.username ?? '');
351
381
  .cpub-mobile-divider { height: 2px; background: var(--border2); margin: 4px 16px; }
352
382
  .cpub-mobile-nav-extra { border-top: var(--border-width-default) solid var(--border2); }
353
383
 
354
- #main-content { margin-top: 48px; flex: 1; }
384
+ /* Offsets the fixed top bar MUST track --cpub-topbar-height (only when the bar is
385
+ actually fixed; a sticky bar reserves its own space, so a theme that switches to
386
+ sticky should zero this via --cpub-content-top-offset). */
387
+ #main-content { margin-top: var(--cpub-content-top-offset, var(--cpub-topbar-height, 48px)); flex: 1; }
355
388
 
356
389
  /* ═══ FOOTER ═══ */
357
- .cpub-footer { background: var(--surface); border-top: var(--border-width-default) solid var(--border); margin-top: auto; }
390
+ /* Footer bg + text are token-driven (--cpub-footer-*) so a theme can ship a dark/branded
391
+ footer (deveco green) without forking. Defaults = the current neutral surface footer. */
392
+ .cpub-footer { background: var(--cpub-footer-bg, var(--surface)); border-top: var(--border-width-default) solid var(--cpub-footer-border, var(--border)); margin-top: auto; }
358
393
  .cpub-footer-inner { max-width: 1200px; margin: 0 auto; padding: 40px 32px 32px; display: grid; grid-template-columns: 1.5fr repeat(3, 1fr); gap: 32px; }
359
394
  .cpub-footer-brand { display: flex; flex-direction: column; gap: 8px; }
360
- .cpub-footer-logo { font-family: var(--font-mono); font-size: 14px; font-weight: 700; color: var(--text); }
361
- .cpub-footer-tagline { font-size: 12px; color: var(--text-dim); }
395
+ .cpub-footer-logo { font-family: var(--font-mono); font-size: 14px; font-weight: 700; color: var(--cpub-footer-heading, var(--text)); }
396
+ .cpub-footer-tagline { font-size: 12px; color: var(--cpub-footer-text, var(--text-dim)); }
362
397
  .cpub-footer-social { display: flex; gap: 8px; margin-top: 8px; }
363
- .cpub-footer-social-link { width: 28px; height: 28px; background: var(--surface2); border: var(--border-width-default) solid var(--border); display: flex; align-items: center; justify-content: center; color: var(--text-dim); font-size: 12px; text-decoration: none; transition: all 0.12s; }
398
+ .cpub-footer-social-link { width: 28px; height: 28px; background: var(--surface2); border: var(--border-width-default) solid var(--border); display: flex; align-items: center; justify-content: center; color: var(--cpub-footer-text, var(--text-dim)); font-size: 12px; text-decoration: none; transition: all 0.12s; }
364
399
  .cpub-footer-social-link:hover { background: var(--accent); color: var(--color-text-inverse); border-color: var(--accent); }
365
400
  .cpub-footer-col { display: flex; flex-direction: column; gap: 6px; }
366
- .cpub-footer-col-title { font-family: var(--font-mono); font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-faint); margin-bottom: 4px; }
367
- .cpub-footer-link { font-size: 12px; color: var(--text-dim); text-decoration: none; transition: color 0.12s; }
368
- .cpub-footer-link:hover { color: var(--text); }
369
- .cpub-footer-bottom { max-width: 1200px; margin: 0 auto; padding: 16px 32px; border-top: var(--border-width-default) solid var(--border); font-size: 10px; font-family: var(--font-mono); color: var(--text-faint); }
401
+ .cpub-footer-col-title { font-family: var(--font-mono); font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--cpub-footer-muted, var(--text-faint)); margin-bottom: 4px; }
402
+ .cpub-footer-link { font-size: 12px; color: var(--cpub-footer-text, var(--text-dim)); text-decoration: none; transition: color 0.12s; }
403
+ .cpub-footer-link:hover { color: var(--cpub-footer-link-hover, var(--text)); }
404
+ .cpub-footer-bottom { max-width: 1200px; margin: 0 auto; padding: 16px 32px; border-top: var(--border-width-default) solid var(--cpub-footer-border, var(--border)); font-size: 10px; font-family: var(--font-mono); color: var(--cpub-footer-muted, var(--text-faint)); }
370
405
 
371
406
  @media (max-width: 768px) {
372
407
  :deep(.cpub-topbar-nav) { display: none; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commonpub/layer",
3
- "version": "0.43.1",
3
+ "version": "0.43.2",
4
4
  "type": "module",
5
5
  "main": "./nuxt.config.ts",
6
6
  "files": [
@@ -56,13 +56,13 @@
56
56
  "@commonpub/auth": "0.7.0",
57
57
  "@commonpub/config": "0.16.0",
58
58
  "@commonpub/docs": "0.6.3",
59
+ "@commonpub/learning": "0.5.2",
59
60
  "@commonpub/editor": "0.7.11",
60
- "@commonpub/explainer": "0.7.15",
61
61
  "@commonpub/schema": "0.25.0",
62
- "@commonpub/server": "2.71.0",
63
- "@commonpub/ui": "0.9.1",
62
+ "@commonpub/explainer": "0.7.15",
63
+ "@commonpub/ui": "0.9.2",
64
64
  "@commonpub/protocol": "0.12.0",
65
- "@commonpub/learning": "0.5.2"
65
+ "@commonpub/server": "2.71.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@testing-library/jest-dom": "^6.9.1",
package/theme/base.css CHANGED
@@ -231,6 +231,46 @@
231
231
  --cpub-card-min: 260px; /* min column width before wrapping (auto-fill) */
232
232
  --cpub-card-gap: 20px; /* gutter between cards */
233
233
 
234
+ /* === CHROME (topbar / nav / footer / banner) ===
235
+ The global layout chrome is fully token-driven so an instance theme can change
236
+ its SHAPE — not just colors — without forking the layout (the deveco use case).
237
+ Every default below EXACTLY reproduces the current base look, so existing
238
+ instances + built-in themes are unaffected unless they opt in by overriding a
239
+ token. A theme that wants e.g. deveco's elevated rounded bar sets these in its
240
+ own [data-theme="…"] / :root block. See layers/base/layouts/default.vue. */
241
+
242
+ /* Top bar */
243
+ --cpub-topbar-height: 48px; /* MUST match the content top-offset + mobile-menu top */
244
+ --cpub-topbar-bg: var(--surface);
245
+ --cpub-topbar-border: var(--border-width-default) solid var(--border); /* shorthand: full bottom border */
246
+ --cpub-topbar-radius: 0; /* deveco: 12px rounded bottom */
247
+ --cpub-topbar-shadow: none; /* deveco: 0 2px 8px rgba(0,0,0,.08) */
248
+ --cpub-topbar-position: fixed; /* deveco: sticky */
249
+ --cpub-topbar-padding-x: 20px;
250
+ --cpub-topbar-blur: none; /* deveco: blur(8px) backdrop */
251
+ /* Top offset reserved for the fixed bar. A theme that makes the bar `sticky`
252
+ (which reserves its own space) should set this to 0. Default = the bar height. */
253
+ --cpub-content-top-offset: var(--cpub-topbar-height, 48px);
254
+
255
+ /* Nav links (rendered by NavRenderer → .cpub-nav-link) */
256
+ --cpub-nav-link-size: 12px; /* deveco: 14px */
257
+ --cpub-nav-link-weight: 400; /* deveco: 500 */
258
+ --cpub-nav-link-padding: 5px 12px; /* deveco: 8px 14px */
259
+ --cpub-nav-link-radius: var(--radius); /* deveco: 6px (pill) */
260
+ --cpub-nav-link-color: var(--text-dim);
261
+ --cpub-nav-link-active-color: var(--text); /* deveco: var(--deveco-dark-green) */
262
+ --cpub-nav-link-active-bg: var(--surface2); /* deveco: var(--accent-bg) */
263
+ --cpub-nav-link-active-weight: 400; /* deveco: 600 */
264
+ --cpub-nav-link-active-border: var(--border); /* color of the active link border */
265
+
266
+ /* Footer */
267
+ --cpub-footer-bg: var(--surface); /* deveco: var(--deveco-dark-green) */
268
+ --cpub-footer-text: var(--text-dim); /* body/link text; deveco: rgba(255,255,255,.7) */
269
+ --cpub-footer-muted: var(--text-faint); /* col titles / bottom bar; deveco: rgba(255,255,255,.4) */
270
+ --cpub-footer-border: var(--border); /* deveco: rgba(255,255,255,.1) */
271
+ --cpub-footer-link-hover: var(--text); /* link hover color; deveco: var(--accent) */
272
+ --cpub-footer-heading: var(--text); /* brand logo text; deveco uses its dark-bg logo */
273
+
234
274
  /* === FOCUS === */
235
275
  --focus-ring: var(--shadow-accent);
236
276
  }