@koehler8/cms 1.0.0-beta.28 → 1.0.0-beta.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koehler8/cms",
3
- "version": "1.0.0-beta.28",
3
+ "version": "1.0.0-beta.30",
4
4
  "description": "Vertex CMS — lightweight, config-driven Vue 3 framework with theming, extensions, and SSG support",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -80,8 +80,8 @@
80
80
  "vue-router": "^5.0.0"
81
81
  },
82
82
  "dependencies": {
83
- "@unhead/vue": "^2.0.19",
84
- "ajv": "^8.17.1",
83
+ "@unhead/vue": "^2.1.15",
84
+ "ajv": "^8.20.0",
85
85
  "ajv-formats": "^3.0.1",
86
86
  "canvas": "^3.2.0",
87
87
  "dotenv": "^17.2.3",
@@ -90,9 +90,11 @@
90
90
  "sharp": "^0.33.5"
91
91
  },
92
92
  "devDependencies": {
93
- "@vue/test-utils": "^2.4.6",
94
- "happy-dom": "^20.8.9",
95
- "vitest": "^4.1.4"
93
+ "@vue/test-utils": "^2.4.10",
94
+ "happy-dom": "^20.9.0",
95
+ "vitest": "^4.1.6",
96
+ "vue": "^3.5.34",
97
+ "vue-router": "^5.0.7"
96
98
  },
97
99
  "engines": {
98
100
  "node": ">=20.19.0",
@@ -273,10 +273,19 @@ function getHeaderOffset() {
273
273
  .promo-surface {
274
274
  position: relative;
275
275
  min-height: var(--promo-surface-min-height, calc(100vh + 75px));
276
- background: var(
276
+ background-color: var(
277
277
  --promo-surface-bg,
278
278
  var(--hero-surface-bg, var(--theme-body-background, #060212))
279
279
  );
280
+ /* Two background-image declarations form a CSS-cascade fallback chain.
281
+ The first sets a basic url(); the second, if the browser parses
282
+ image-set() (and the type() argument), overrides with format
283
+ negotiation. Browsers that can't parse image-set fall back to the
284
+ url() above. Custom properties are populated by usePromoBackgroundStyles
285
+ via Vue's :style object binding — see that composable for why this
286
+ pattern is needed instead of a single background-image string. */
287
+ background-image: var(--promo-bg-fallback);
288
+ background-image: var(--promo-bg-set, var(--promo-bg-fallback));
280
289
  background-repeat: no-repeat;
281
290
  background-size: cover;
282
291
  background-position: center;
@@ -23,14 +23,34 @@ function selectLargestEntry(srcset = '') {
23
23
  }
24
24
 
25
25
  /**
26
- * Build a CSS background-image declaration that respects the neon backdrop toggle
27
- * and reuses the responsive image metadata returned by `useResponsiveImage`.
26
+ * Build a hero-background style binding that pairs a `url()` fallback with an
27
+ * `image-set()` upgrade. Returns an OBJECT with two CSS custom properties.
28
+ *
29
+ * Why an object with custom properties instead of a single `background-image`
30
+ * string: Vue 3's `:style` parses a string into a normalized object keyed by
31
+ * property name. A string with two `background-image` declarations
32
+ * (`background-image: url(...); background-image: image-set(...)`) collapses
33
+ * to a single entry — only the last value survives. This loses the
34
+ * progressive-enhancement chain that's the whole point of pairing a `url()`
35
+ * fallback with an `image-set()` upgrade. By emitting two custom properties,
36
+ * Vue keeps both, and the consuming CSS rule chains them as two real
37
+ * declarations of `background-image` so browsers walk the cascade naturally.
38
+ *
39
+ * Consumed by Hero.vue's `.promo-surface` rule, which declares:
40
+ *
41
+ * background-image: var(--promo-bg-fallback);
42
+ * background-image: var(--promo-bg-set, var(--promo-bg-fallback));
43
+ *
44
+ * Browsers that can parse `image-set()` (and its `type()` argument) use the
45
+ * second declaration; browsers that can't fall through to the first.
46
+ *
28
47
  * @param {object} options
29
48
  * @param {{
30
49
  * sources: import('vue').MaybeRefOrGetter<Array<{ type: string, srcset: string }>>,
31
50
  * fallbackSrc: import('vue').MaybeRefOrGetter<string>,
32
51
  * fallbackFormat: import('vue').MaybeRefOrGetter<string>
33
52
  * }} options.imageSet
53
+ * @returns {import('vue').ComputedRef<Record<string, string> | null>}
34
54
  */
35
55
  export function usePromoBackgroundStyles({ imageSet }) {
36
56
  return computed(() => {
@@ -38,30 +58,26 @@ export function usePromoBackgroundStyles({ imageSet }) {
38
58
  const fallbackFormat = (unref(imageSet?.fallbackFormat) || 'jpg').toLowerCase();
39
59
  const sources = unref(imageSet?.sources) || [];
40
60
 
41
- const formatEntries = [];
61
+ if (!fallbackSrc) return null;
42
62
 
63
+ const formatEntries = [];
43
64
  sources.forEach((source) => {
44
65
  const largest = selectLargestEntry(source?.srcset);
45
66
  if (largest) {
46
67
  formatEntries.push(`url("${largest}") type("${source?.type}") 1x`);
47
68
  }
48
69
  });
49
-
50
70
  if (fallbackSrc) {
51
71
  const fallbackMime = fallbackFormat === 'jpg' ? 'jpeg' : fallbackFormat;
52
72
  formatEntries.push(`url("${fallbackSrc}") type("image/${fallbackMime}") 1x`);
53
73
  }
54
74
 
55
- const cssImageSet = formatEntries.length ? `image-set(${formatEntries.join(', ')})` : '';
56
- let style = '';
57
-
58
- if (fallbackSrc) {
59
- style += `background-image: url("${fallbackSrc}");`;
60
- }
61
- if (cssImageSet) {
62
- style += `background-image: ${cssImageSet};`;
75
+ const result = {
76
+ '--promo-bg-fallback': `url("${fallbackSrc}")`,
77
+ };
78
+ if (formatEntries.length) {
79
+ result['--promo-bg-set'] = `image-set(${formatEntries.join(', ')})`;
63
80
  }
64
-
65
- return style;
81
+ return result;
66
82
  });
67
83
  }