kmcom-nuxt-layers 4.0.1 → 5.0.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/docs/superpowers/plans/2026-09-03-layout-layer-fluid-rebuild.md +8 -8
- package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-7-design.md +1 -1
- package/docs/superpowers/specs/2026-08-31-swiss-grid-layer-design.md +3 -3
- package/docs/superpowers/specs/2026-09-03-layout-layer-fluid-rebuild-design.md +3 -3
- package/layers/content/app/components/Blog/Article.vue +1 -1
- package/layers/content/app/components/Gallery/Detail.vue +8 -8
- package/layers/content/app/components/Gallery/Grid.vue +8 -8
- package/layers/content/app/components/Gallery/ImageDetail.vue +6 -6
- package/layers/content/app/components/Gallery/Lightbox.vue +3 -3
- package/layers/content/app/components/NuxtContent/Detail.vue +1 -1
- package/layers/content/app/components/NuxtContent/List.vue +1 -1
- package/layers/content/app/components/Portfolio/ColorPalette.vue +5 -5
- package/layers/content/app/components/Portfolio/Detail.vue +1 -1
- package/layers/content/app/components/Portfolio/List.vue +1 -1
- package/layers/content/app/components/Portfolio/Typography.vue +5 -5
- package/layers/content/app/components/content/Figure.vue +1 -1
- package/layers/core/app/assets/css/core.css +9 -9
- package/layers/core/app/assets/css/layout.css +1 -1
- package/layers/core/app/components/DiagnosticsPage.vue +15 -15
- package/layers/core/app/components/Element.test.ts +1 -1
- package/layers/core/app/components/ElementTw.test.ts +1 -1
- package/layers/core/app/components/ErrorBoundary.vue +5 -5
- package/layers/core/app/composables/useElementGrid.test.ts +1 -1
- package/layers/core/app/composables/useElementInteraction.test.ts +1 -1
- package/layers/core/app/composables/useElementLayout.test.ts +1 -1
- package/layers/core/app/composables/useElementSizing.test.ts +1 -1
- package/layers/core/app/composables/useElementSurface.test.ts +1 -1
- package/layers/core/app/composables/useLayoutAttrs.test.ts +1 -1
- package/layers/core/app/error.vue +1 -1
- package/layers/core/app/pages/[...slug].vue +2 -2
- package/layers/core/app/utils/browserInfo.test.ts +1 -1
- package/layers/core/app/utils/featureClasses.test.ts +1 -1
- package/layers/core/app/utils/scrollGuardClamp.test.ts +1 -1
- package/layers/core/app/utils/styleToTailwindClasses.test.ts +1 -1
- package/layers/data/forms/app/utils/contact-schema.test.ts +1 -1
- package/layers/data/forms/app/utils/fieldProps.test.ts +1 -1
- package/layers/data/metadata/providers/comicvine/server/utils/metadata-comicvine/normalise.test.ts +1 -1
- package/layers/data/metadata/providers/google-books/server/utils/metadata-google-books/client.test.ts +1 -1
- package/layers/data/metadata/providers/google-books/server/utils/metadata-google-books/normalise.test.ts +1 -1
- package/layers/data/metadata/providers/openlibrary/server/utils/metadata-openlibrary/client.test.ts +1 -1
- package/layers/data/metadata/providers/openlibrary/server/utils/metadata-openlibrary/normalise.test.ts +1 -1
- package/layers/data/metadata/providers/themoviedb/server/utils/metadata-tmdb/client.test.ts +1 -1
- package/layers/data/metadata/providers/themoviedb/server/utils/metadata-tmdb/normalise.test.ts +1 -1
- package/layers/data/metadata/server/utils/metadata/cache.test.ts +1 -1
- package/layers/data/metadata/server/utils/metadata/provider-registry.test.ts +1 -1
- package/layers/data/metadata/server/utils/metadata/search.test.ts +1 -1
- package/layers/delivery/feeds/app/assets/css/feeds.css +23 -11
- package/layers/delivery/feeds/app/components/Feeds/Index.vue +10 -10
- package/layers/delivery/feeds/app/components/Feeds/RouteCard.vue +1 -1
- package/layers/delivery/feeds/public/feed/style.css +16 -16
- package/layers/delivery/feeds/server/utils/content-adapter.test.ts +1 -1
- package/layers/delivery/feeds/server/utils/feed-author.test.ts +1 -1
- package/layers/delivery/feeds/server/utils/feed-config.test.ts +1 -1
- package/layers/delivery/feeds/server/utils/formats.test.ts +1 -1
- package/layers/delivery/scripts/app/components/BaselineStatus.vue +3 -1
- package/layers/delivery/seo/app/utils/seoConfig.test.ts +1 -1
- package/layers/design-system/theming/app/assets/css/theme.css +0 -1
- package/layers/design-system/theming/app/components/ThemePicker/AccentButton.vue +2 -2
- package/layers/design-system/theming/app/components/ThemePicker/Menu.vue +3 -3
- package/layers/design-system/theming/app/composables/useAccentColor.ts +4 -1
- package/layers/design-system/theming/app/plugins/theme.client.ts +15 -13
- package/layers/design-system/theming/app/utils/themeAdapter.ts +1 -1
- package/layers/design-system/theming/nuxt.config.ts +1 -1
- package/layers/design-system/theming/server/utils/accent-css.test.ts +1 -1
- package/layers/design-system/theming/server/utils/fouc-config.test.ts +1 -1
- package/layers/design-system/typography/app/components/Typography/TextStroke.vue +1 -1
- package/layers/design-system/visual/app/assets/css/visual.css +0 -1
- package/layers/design-system/visual/app/components/Accent/Scene.vue +2 -2
- package/layers/design-system/visual/app/components/Tint/Overlay.vue +1 -1
- package/layers/design-system/visual/app/utils/colorTokens.test.ts +1 -1
- package/layers/design-system/visual/app/utils/gradientStyle.test.ts +1 -1
- package/layers/design-system/visual/app/utils/responsiveSizes.test.ts +1 -1
- package/layers/motion/animations/app/components/Motion/Marquee.vue +1 -1
- package/layers/motion/animations/app/components/Motion/MarqueeText.vue +3 -3
- package/layers/motion/scroll/app/components/Motion/HorizontalScroll.vue +1 -1
- package/layers/motion/scroll/app/components/Motion/PinnedSection.vue +2 -2
- package/layers/motion/scroll/app/components/Motion/ScrollProgress.vue +2 -2
- package/layers/motion/scroll/app/components/Motion/ScrollStats.vue +6 -6
- package/layers/motion/transitions/app/assets/css/transitions.css +12 -12
- package/layers/render/canvas/package.json +2 -1
- package/layers/render/shader/app/assets/css/shader.css +5 -5
- package/layers/render/shader/app/shaders/common/grain.ts +1 -1
- package/layers/render/shader/app/types/tsl.ts +1 -1
- package/layers/render/shader/app/utils/tsl/index.ts +2 -0
- package/layers/structure/grid/app/assets/css/grid.css +2 -0
- package/layers/structure/grid/app/composables/useGridTracks.test.ts +1 -1
- package/layers/structure/grid/app/types/tracks.test.ts +1 -1
- package/layers/structure/grid/app/utils/placement.test.ts +1 -1
- package/layers/structure/layout/app/components/Layout/Grid/Debug.vue +1 -1
- package/layers/structure/layout/app/components/Layout/Page/Header.vue +3 -3
- package/layers/structure/layout/app/components/Layout/Page/index.vue +16 -11
- package/layers/structure/layout/app/utils/gridPlacementStyle.test.ts +1 -1
- package/layers/structure/navigation/app/components/Mast/Nav.vue +1 -1
- package/layers/structure/navigation/app/components/Mast/NavModal.vue +2 -2
- package/layers/structure/navigation/app/utils/site.test.ts +1 -1
- package/layers/structure/routing/app/utils/resolveRoute.test.ts +1 -1
- package/package.json +20 -32
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
<template #description>
|
|
35
35
|
<div class="space-y-2">
|
|
36
36
|
<p class="text-muted">{{ message }}</p>
|
|
37
|
-
<code v-if="error?.statusMessage" class="block rounded
|
|
37
|
+
<code v-if="error?.statusMessage" class="bg-elevated block rounded px-2 py-1 text-sm">
|
|
38
38
|
{{ error.statusMessage }}
|
|
39
39
|
</code>
|
|
40
40
|
</div>
|
|
@@ -88,10 +88,10 @@
|
|
|
88
88
|
<UEmpty :icon :title :description size="xl">
|
|
89
89
|
<!-- Show attempted path -->
|
|
90
90
|
<template v-if="config.showPath !== false" #description>
|
|
91
|
-
<p class="mb-2
|
|
91
|
+
<p class="text-muted mb-2">
|
|
92
92
|
{{ description }}
|
|
93
93
|
</p>
|
|
94
|
-
<code class="
|
|
94
|
+
<code class="bg-elevated rounded px-2 py-1 text-sm">
|
|
95
95
|
{{ attemptedPath }}
|
|
96
96
|
</code>
|
|
97
97
|
</template>
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
MetadataSearchInput,
|
|
4
4
|
MetadataSearchResult,
|
|
5
5
|
} from '#layers/metadata/shared/types'
|
|
6
|
-
import { beforeEach, describe, expect, it, vi } from '
|
|
6
|
+
import { beforeEach, describe, expect, it, vi } from 'vite-plus/test'
|
|
7
7
|
|
|
8
8
|
import { hashQuery, makeCacheKey } from './cache'
|
|
9
9
|
|
|
@@ -17,42 +17,54 @@
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.feed-badge-rss {
|
|
20
|
-
background-color: color-mix(
|
|
21
|
-
|
|
20
|
+
background-color: color-mix(
|
|
21
|
+
in srgb,
|
|
22
|
+
var(--color-orange-500, oklch(70.49% 0.1867 47.6deg)) 12%,
|
|
23
|
+
transparent
|
|
24
|
+
);
|
|
25
|
+
color: var(--color-orange-600, oklch(64.61% 0.1943 41.12deg));
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
.feed-badge-atom {
|
|
25
|
-
background-color: color-mix(
|
|
26
|
-
|
|
29
|
+
background-color: color-mix(
|
|
30
|
+
in srgb,
|
|
31
|
+
var(--color-purple-500, oklch(62.68% 0.2325 303.9deg)) 12%,
|
|
32
|
+
transparent
|
|
33
|
+
);
|
|
34
|
+
color: var(--color-purple-600, oklch(55.75% 0.2525 302.32deg));
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
.feed-badge-json {
|
|
30
|
-
background-color: color-mix(
|
|
31
|
-
|
|
38
|
+
background-color: color-mix(
|
|
39
|
+
in srgb,
|
|
40
|
+
var(--color-yellow-500, oklch(79.52% 0.1617 86.05deg)) 12%,
|
|
41
|
+
transparent
|
|
42
|
+
);
|
|
43
|
+
color: var(--color-yellow-600, oklch(68.06% 0.1423 75.83deg));
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
@media (prefers-color-scheme: dark) {
|
|
35
47
|
.feed-badge-rss {
|
|
36
|
-
color: var(--color-orange-400,
|
|
48
|
+
color: var(--color-orange-400, oklch(75.76% 0.159 55.93deg));
|
|
37
49
|
}
|
|
38
50
|
|
|
39
51
|
.feed-badge-atom {
|
|
40
|
-
color: var(--color-purple-400,
|
|
52
|
+
color: var(--color-purple-400, oklch(72.17% 0.1767 305.5deg));
|
|
41
53
|
}
|
|
42
54
|
|
|
43
55
|
.feed-badge-json {
|
|
44
|
-
color: var(--color-yellow-400,
|
|
56
|
+
color: var(--color-yellow-400, oklch(86.06% 0.1731 91.94deg));
|
|
45
57
|
}
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
/* Feed preview code block — used in playground and consuming apps */
|
|
49
61
|
.feed-preview {
|
|
50
62
|
border-radius: var(--ui-radius, 0.375rem);
|
|
51
|
-
background-color: var(--color-gray-950,
|
|
63
|
+
background-color: var(--color-gray-950, oklch(12.96% 0.0274 261.69deg));
|
|
52
64
|
padding: 1rem;
|
|
53
65
|
max-height: 24rem;
|
|
54
66
|
overflow: auto;
|
|
55
|
-
color: var(--color-gray-100,
|
|
67
|
+
color: var(--color-gray-100, oklch(96.7% 0.0029 264.54deg));
|
|
56
68
|
font-size: 0.75rem;
|
|
57
69
|
line-height: 1.6;
|
|
58
70
|
font-family: var(--font-mono, ui-monospace, monospace);
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
>
|
|
26
26
|
<div class="pointer-events-none absolute inset-0">
|
|
27
27
|
<div
|
|
28
|
-
class="absolute -right-20
|
|
28
|
+
class="absolute top-0 -right-20 h-72 w-72 rounded-full bg-orange-400/20 blur-3xl dark:bg-orange-500/15"
|
|
29
29
|
/>
|
|
30
30
|
<div
|
|
31
|
-
class="absolute -left-20
|
|
31
|
+
class="absolute bottom-0 -left-20 h-80 w-80 rounded-full bg-sky-400/12 blur-3xl dark:bg-sky-500/10"
|
|
32
32
|
/>
|
|
33
33
|
<div
|
|
34
34
|
class="absolute inset-x-8 top-0 h-px bg-linear-to-r from-transparent via-orange-400/35 to-transparent"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
<div class="feeds-split grid gap-6">
|
|
40
40
|
<div class="space-y-6">
|
|
41
41
|
<div
|
|
42
|
-
class="inline-flex items-center gap-2 rounded-full border border-amber-200/80 bg-white/80 px-3 py-1 text-[0.68rem] font-semibold
|
|
42
|
+
class="inline-flex items-center gap-2 rounded-full border border-amber-200/80 bg-white/80 px-3 py-1 text-[0.68rem] font-semibold tracking-[0.35em] text-amber-700 uppercase shadow-sm backdrop-blur dark:border-slate-700 dark:bg-slate-900/60 dark:text-amber-200"
|
|
43
43
|
>
|
|
44
44
|
<UIcon name="i-lucide-rss" class="text-sm" />
|
|
45
45
|
Feeds layer
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
class="rounded-2xl border border-slate-200/80 bg-white/75 p-4 shadow-sm backdrop-blur dark:border-slate-800 dark:bg-slate-900/45"
|
|
64
64
|
>
|
|
65
65
|
<p
|
|
66
|
-
class="text-[0.68rem] font-semibold
|
|
66
|
+
class="text-[0.68rem] font-semibold tracking-[0.3em] text-slate-500 uppercase dark:text-slate-400"
|
|
67
67
|
>
|
|
68
68
|
Default
|
|
69
69
|
</p>
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
class="rounded-2xl border border-slate-200/80 bg-white/75 p-4 shadow-sm backdrop-blur dark:border-slate-800 dark:bg-slate-900/45"
|
|
80
80
|
>
|
|
81
81
|
<p
|
|
82
|
-
class="text-[0.68rem] font-semibold
|
|
82
|
+
class="text-[0.68rem] font-semibold tracking-[0.3em] text-slate-500 uppercase dark:text-slate-400"
|
|
83
83
|
>
|
|
84
84
|
Exposed
|
|
85
85
|
</p>
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
class="rounded-2xl border border-slate-200/80 bg-white/75 p-4 shadow-sm backdrop-blur dark:border-slate-800 dark:bg-slate-900/45"
|
|
96
96
|
>
|
|
97
97
|
<p
|
|
98
|
-
class="text-[0.68rem] font-semibold
|
|
98
|
+
class="text-[0.68rem] font-semibold tracking-[0.3em] text-slate-500 uppercase dark:text-slate-400"
|
|
99
99
|
>
|
|
100
100
|
Limit
|
|
101
101
|
</p>
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
class="flex flex-wrap items-center gap-3 rounded-2xl border border-slate-200/80 bg-white/70 px-4 py-3 text-sm shadow-sm backdrop-blur dark:border-slate-800 dark:bg-slate-900/45"
|
|
114
114
|
>
|
|
115
115
|
<span
|
|
116
|
-
class="text-xs font-semibold
|
|
116
|
+
class="text-xs font-semibold tracking-[0.3em] text-slate-500 uppercase dark:text-slate-400"
|
|
117
117
|
>
|
|
118
118
|
Site
|
|
119
119
|
</span>
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
>
|
|
135
135
|
<div class="flex items-center justify-between gap-3">
|
|
136
136
|
<p
|
|
137
|
-
class="text-[0.68rem] font-semibold
|
|
137
|
+
class="text-[0.68rem] font-semibold tracking-[0.35em] text-slate-500 uppercase dark:text-slate-400"
|
|
138
138
|
>
|
|
139
139
|
Global routes
|
|
140
140
|
</p>
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
<div class="flex flex-wrap items-end justify-between gap-4">
|
|
163
163
|
<div>
|
|
164
164
|
<p
|
|
165
|
-
class="text-[0.68rem] font-semibold
|
|
165
|
+
class="text-[0.68rem] font-semibold tracking-[0.35em] text-slate-500 uppercase dark:text-slate-400"
|
|
166
166
|
>
|
|
167
167
|
Collection routes
|
|
168
168
|
</p>
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
>
|
|
191
191
|
<div>
|
|
192
192
|
<p
|
|
193
|
-
class="text-[0.68rem] font-semibold
|
|
193
|
+
class="text-[0.68rem] font-semibold tracking-[0.35em] text-slate-500 uppercase dark:text-slate-400"
|
|
194
194
|
>
|
|
195
195
|
Collection
|
|
196
196
|
</p>
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
<UCard
|
|
51
51
|
:to="route.path"
|
|
52
52
|
:ui="{ body: 'p-0' }"
|
|
53
|
-
class="group relative overflow-hidden border-slate-200/80 bg-white/90 shadow-none transition duration-200 hover:-translate-y-0.5 hover:border-slate-300 hover:shadow-md dark:border-slate-800 dark:bg-slate-950/55 dark:hover:border-slate-700
|
|
53
|
+
class="group @container relative overflow-hidden border-slate-200/80 bg-white/90 shadow-none transition duration-200 hover:-translate-y-0.5 hover:border-slate-300 hover:shadow-md dark:border-slate-800 dark:bg-slate-950/55 dark:hover:border-slate-700"
|
|
54
54
|
>
|
|
55
55
|
<div class="absolute inset-y-0 left-0 w-1" :class="routeTone.strip" />
|
|
56
56
|
<div :class="compact ? 'flex items-center gap-3 p-3' : 'flex items-center gap-3 p-4'">
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
:root {
|
|
15
|
-
--feed-bg: var(--ui-bg,
|
|
16
|
-
--feed-bg-elevated: var(--ui-bg-elevated,
|
|
17
|
-
--feed-bg-accented: var(--ui-bg-accented,
|
|
18
|
-
--feed-border: var(--ui-border,
|
|
19
|
-
--feed-text: var(--ui-text,
|
|
20
|
-
--feed-text-muted: var(--ui-text-muted,
|
|
21
|
-
--feed-text-toned: var(--ui-text-toned,
|
|
15
|
+
--feed-bg: var(--ui-bg, oklch(100% 0 0deg));
|
|
16
|
+
--feed-bg-elevated: var(--ui-bg-elevated, oklch(98.42% 0.0034 247.86deg));
|
|
17
|
+
--feed-bg-accented: var(--ui-bg-accented, oklch(96.83% 0.0069 247.9deg));
|
|
18
|
+
--feed-border: var(--ui-border, oklch(92.88% 0.0126 255.51deg));
|
|
19
|
+
--feed-text: var(--ui-text, oklch(20.77% 0.0398 265.75deg));
|
|
20
|
+
--feed-text-muted: var(--ui-text-muted, oklch(55.44% 0.0407 257.42deg));
|
|
21
|
+
--feed-text-toned: var(--ui-text-toned, oklch(44.55% 0.0374 257.28deg));
|
|
22
22
|
--feed-primary: var(--ui-color-primary-500, oklch(62.3% 0.214 259.5deg));
|
|
23
23
|
--feed-primary-text: var(--ui-color-primary-600, oklch(54.6% 0.214 259.5deg));
|
|
24
24
|
--feed-primary-bg: var(--ui-color-primary-50, oklch(97% 0.03 259.5deg));
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
|
|
29
29
|
@media (prefers-color-scheme: dark) {
|
|
30
30
|
:root {
|
|
31
|
-
--feed-bg: var(--ui-bg,
|
|
32
|
-
--feed-bg-elevated: var(--ui-bg-elevated,
|
|
33
|
-
--feed-bg-accented: var(--ui-bg-accented,
|
|
34
|
-
--feed-border: var(--ui-border,
|
|
35
|
-
--feed-text: var(--ui-text,
|
|
36
|
-
--feed-text-muted: var(--ui-text-muted,
|
|
37
|
-
--feed-text-toned: var(--ui-text-toned,
|
|
31
|
+
--feed-bg: var(--ui-bg, oklch(12.88% 0.0406 264.7deg));
|
|
32
|
+
--feed-bg-elevated: var(--ui-bg-elevated, oklch(20.77% 0.0398 265.75deg));
|
|
33
|
+
--feed-bg-accented: var(--ui-bg-accented, oklch(27.95% 0.0368 260.03deg));
|
|
34
|
+
--feed-border: var(--ui-border, oklch(27.95% 0.0368 260.03deg));
|
|
35
|
+
--feed-text: var(--ui-text, oklch(98.42% 0.0034 247.86deg));
|
|
36
|
+
--feed-text-muted: var(--ui-text-muted, oklch(71.07% 0.0351 256.79deg));
|
|
37
|
+
--feed-text-toned: var(--ui-text-toned, oklch(86.9% 0.0198 252.89deg));
|
|
38
38
|
--feed-primary: var(--ui-color-primary-400, oklch(71% 0.18 259.5deg));
|
|
39
39
|
--feed-primary-text: var(--ui-color-primary-400, oklch(71% 0.18 259.5deg));
|
|
40
40
|
--feed-primary-bg: var(--ui-color-primary-950, oklch(22% 0.06 259.5deg));
|
|
@@ -160,7 +160,7 @@ a:hover {
|
|
|
160
160
|
border-radius: var(--feed-radius);
|
|
161
161
|
background-color: var(--feed-primary);
|
|
162
162
|
padding: 0.5rem 1.125rem;
|
|
163
|
-
color:
|
|
163
|
+
color: oklch(100% 0 0deg);
|
|
164
164
|
font-weight: 600;
|
|
165
165
|
font-size: 0.875rem;
|
|
166
166
|
line-height: 1;
|
|
@@ -169,7 +169,7 @@ a:hover {
|
|
|
169
169
|
|
|
170
170
|
.feed-subscribe:hover {
|
|
171
171
|
opacity: 0.85;
|
|
172
|
-
color:
|
|
172
|
+
color: oklch(100% 0 0deg);
|
|
173
173
|
text-decoration: none;
|
|
174
174
|
}
|
|
175
175
|
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
},
|
|
12
12
|
setup(props) {
|
|
13
|
-
|
|
13
|
+
// Render the custom element on server AND client. Returning null on the server
|
|
14
|
+
// produced a comment node there but an element on the client (hydration mismatch);
|
|
15
|
+
// an unregistered custom element is inert until the client script upgrades it.
|
|
14
16
|
return () => h('baseline-status', { featureId: props.featureId })
|
|
15
17
|
},
|
|
16
18
|
})
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
class="size-8 rounded-full ring-1 ring-offset-2 transition-shadow duration-200"
|
|
22
22
|
:class="[
|
|
23
23
|
active
|
|
24
|
-
? 'ring-
|
|
25
|
-
: '
|
|
24
|
+
? 'ring-primary ring-offset-bg shadow-lg ring-2'
|
|
25
|
+
: 'hover:ring-muted ring-offset-bg ring-transparent hover:shadow-md',
|
|
26
26
|
]"
|
|
27
27
|
:style="bgStyle"
|
|
28
28
|
:aria-label="`Set accent color to ${color}`"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
<li class="flex w-full flex-row items-center justify-between py-1">
|
|
35
35
|
<div>
|
|
36
36
|
<h2 class="text-lg font-semibold">High Contrast</h2>
|
|
37
|
-
<p v-if="contrastOverride === 'system'" class="text-
|
|
37
|
+
<p v-if="contrastOverride === 'system'" class="text-muted text-sm">
|
|
38
38
|
Following system
|
|
39
39
|
</p>
|
|
40
40
|
</div>
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
<li class="flex w-full flex-row items-center justify-between py-1">
|
|
50
50
|
<div>
|
|
51
51
|
<h2 class="text-lg font-semibold">Reduce Motion</h2>
|
|
52
|
-
<p v-if="motionOverride === 'system'" class="text-
|
|
52
|
+
<p v-if="motionOverride === 'system'" class="text-muted text-sm">
|
|
53
53
|
Following system
|
|
54
54
|
</p>
|
|
55
55
|
</div>
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
<li class="flex w-full flex-row items-center justify-between py-1">
|
|
65
65
|
<div>
|
|
66
66
|
<h2 class="text-lg font-semibold">Reduce Transparency</h2>
|
|
67
|
-
<p v-if="transparencyOverride === 'system'" class="text-
|
|
67
|
+
<p v-if="transparencyOverride === 'system'" class="text-muted text-sm">
|
|
68
68
|
Following system
|
|
69
69
|
</p>
|
|
70
70
|
</div>
|
|
@@ -13,7 +13,10 @@ export const useAccentColor = createSharedComposable(() => {
|
|
|
13
13
|
// theme.client.ts reads localStorage after hydration and calls setAccent.
|
|
14
14
|
const accent = useState<AccentColor>('theme-accent', () => defaultAccent)
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// Page-scoped override. Must be useState (not a module-level ref): pages call
|
|
17
|
+
// setPageAccent() during setup, and a plain ref is not carried in the SSR payload,
|
|
18
|
+
// so the server rendered the default accent while the client had the page's.
|
|
19
|
+
const pageAccent = useState<AccentColor | null>('theme-page-accent', () => null)
|
|
17
20
|
const activeAccent = computed<AccentColor>(() => pageAccent.value ?? accent.value)
|
|
18
21
|
|
|
19
22
|
function setAccent(color: AccentColor) {
|
|
@@ -10,19 +10,21 @@ export default defineNuxtPlugin({
|
|
|
10
10
|
const { setTransparencyOverride, effectiveReducedTransparency } = useThemeTransparency()
|
|
11
11
|
|
|
12
12
|
// Restore persisted preferences. useState defaults were serialized from the
|
|
13
|
-
// server, so hydration matches
|
|
14
|
-
// hydration
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
// server, so hydration matches only if client state is still at those defaults
|
|
14
|
+
// while hydrating. Plugin setup runs BEFORE hydration, so the stored values are
|
|
15
|
+
// applied on `app:mounted` (after hydration) instead of here.
|
|
16
|
+
useNuxtApp().hook('app:mounted', () => {
|
|
17
|
+
const restorers: Array<[key: string, apply: (value: string) => void]> = [
|
|
18
|
+
['theme-colour', (v) => setAccent(v as AccentColor)],
|
|
19
|
+
['theme-contrast', (v) => setContrastOverride(v as PreferenceOverride)],
|
|
20
|
+
['theme-motion', (v) => setMotionOverride(v as PreferenceOverride)],
|
|
21
|
+
['theme-transparency', (v) => setTransparencyOverride(v as PreferenceOverride)],
|
|
22
|
+
]
|
|
23
|
+
for (const [key, apply] of restorers) {
|
|
24
|
+
const stored = localStorage.getItem(key)
|
|
25
|
+
if (stored) apply(stored)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
26
28
|
|
|
27
29
|
watch(
|
|
28
30
|
activeAccent,
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
v-bind="$attrs"
|
|
32
32
|
>
|
|
33
33
|
<!-- Sizer: transparent text for natural sizing + selectable -->
|
|
34
|
-
<span class="text-stroke-sizer text-transparent
|
|
34
|
+
<span class="text-stroke-sizer whitespace-nowrap text-transparent" aria-hidden="true">{{
|
|
35
35
|
text
|
|
36
36
|
}}</span>
|
|
37
37
|
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
</script>
|
|
26
26
|
|
|
27
27
|
<template>
|
|
28
|
-
<component :is="tag" class="relative overflow-clip
|
|
29
|
-
<div class="absolute inset-0
|
|
28
|
+
<component :is="tag" class="relative isolate overflow-clip">
|
|
29
|
+
<div class="pointer-events-none absolute inset-0" aria-hidden="true">
|
|
30
30
|
<AccentBlob
|
|
31
31
|
v-for="(blob, i) in resolvedBlobs"
|
|
32
32
|
:key="i"
|
|
@@ -20,6 +20,6 @@
|
|
|
20
20
|
<template>
|
|
21
21
|
<component :is="tag" class="relative">
|
|
22
22
|
<slot />
|
|
23
|
-
<span class="absolute inset-0
|
|
23
|
+
<span class="pointer-events-none absolute inset-0" :style aria-hidden="true" />
|
|
24
24
|
</component>
|
|
25
25
|
</template>
|