kmcom-nuxt-layers 2.6.2 → 2.7.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.
Files changed (114) hide show
  1. package/docs/ARCHITECTURE.md +21 -17
  2. package/docs/FEEDS.md +42 -34
  3. package/docs/IMPROVE-AUDIT-README.md +9 -10
  4. package/docs/IMPROVE-AUDIT-RESULTS.md +16 -17
  5. package/docs/IMPROVE-DEEP-AUDIT-RESULTS.md +29 -29
  6. package/docs/LAYERS-FIXES.md +1 -0
  7. package/docs/LAYOUT.md +91 -86
  8. package/docs/MIGRATION.md +93 -60
  9. package/docs/UPAGE-GRID-INTEGRATION.md +12 -10
  10. package/docs/USAGE.md +29 -38
  11. package/layers/animations/app/utils/pointerMotion.ts +1 -4
  12. package/layers/baseline/app/components/BaselineStatus.vue +13 -13
  13. package/layers/baseline/app/plugins/baseline-status.client.ts +4 -1
  14. package/layers/canvas/app/composables/useRendererCapabilities.ts +2 -2
  15. package/layers/content/app/components/Blog/Card.vue +1 -0
  16. package/layers/content/app/components/Gallery/Card.vue +1 -1
  17. package/layers/content/app/components/Gallery/Detail.vue +8 -1
  18. package/layers/content/app/components/Portfolio/Card.vue +1 -0
  19. package/layers/content/app/components/Portfolio/ColorPalette.vue +8 -1
  20. package/layers/content/app/components/Portfolio/Typography.vue +12 -2
  21. package/layers/content/app/composables/useGalleryItems.ts +3 -2
  22. package/layers/content/app/composables/usePortfolioItems.ts +3 -2
  23. package/layers/core/app/components/DiagnosticsPage.vue +15 -3
  24. package/layers/core/app/utils/featureClasses.test.ts +1 -3
  25. package/layers/core/app/utils/featureClasses.ts +1 -3
  26. package/layers/core/app/utils/helpers.test.ts +6 -2
  27. package/layers/core/nuxt.config.ts +2 -0
  28. package/layers/feeds/app/assets/css/feeds.css +3 -2
  29. package/layers/feeds/app/components/Feeds/Index.vue +36 -6
  30. package/layers/feeds/app/components/Feeds/RouteCard.vue +1 -3
  31. package/layers/feeds/app/plugins/feed-head.ts +2 -2
  32. package/layers/feeds/package.json +1 -1
  33. package/layers/feeds/public/feed/style.css +9 -9
  34. package/layers/feeds/server/utils/content-adapter.test.ts +3 -4
  35. package/layers/feeds/server/utils/content-adapter.ts +1 -1
  36. package/layers/feeds/server/utils/feed-author.test.ts +3 -3
  37. package/layers/feeds/server/utils/feed-config.test.ts +28 -6
  38. package/layers/feeds/server/utils/feed-config.ts +1 -4
  39. package/layers/feeds/server/utils/feed-service.ts +1 -1
  40. package/layers/feeds/server/utils/formats/rss.ts +1 -1
  41. package/layers/feeds/server/utils/formats.test.ts +1 -1
  42. package/layers/forms/app/utils/fieldProps.ts +1 -2
  43. package/layers/forms/server/api/contact.post.ts +4 -1
  44. package/layers/layout/app/assets/css/layout/grids.css +12 -3
  45. package/layers/layout/app/assets/css/layout/modes/fluid.css +9 -0
  46. package/layers/layout/app/components/Layout/Section/Sidebar.vue +11 -4
  47. package/layers/layout/app/utils/gridPlacementStyle.test.ts +3 -9
  48. package/layers/layout/app/utils/gridPlacementStyle.ts +10 -7
  49. package/layers/mailer/server/utils/email.ts +4 -3
  50. package/layers/mailer/server/utils/hooks.ts +1 -1
  51. package/layers/metadata/app/composables/useMetadataItem.ts +6 -2
  52. package/layers/metadata/app/composables/useMetadataSearch.ts +6 -2
  53. package/layers/metadata/providers/comicvine/server/utils/metadata-comicvine/client.ts +5 -5
  54. package/layers/metadata/providers/comicvine/server/utils/metadata-comicvine/provider.ts +11 -3
  55. package/layers/metadata/providers/google-books/server/utils/metadata-google-books/client.ts +9 -6
  56. package/layers/metadata/providers/google-books/server/utils/metadata-google-books/provider.ts +6 -3
  57. package/layers/metadata/providers/openlibrary/server/utils/metadata-openlibrary/normalise.test.ts +3 -1
  58. package/layers/metadata/providers/openlibrary/server/utils/metadata-openlibrary/provider.ts +4 -2
  59. package/layers/metadata/providers/themoviedb/server/utils/metadata-tmdb/client.test.ts +1 -3
  60. package/layers/metadata/providers/themoviedb/server/utils/metadata-tmdb/provider.ts +3 -1
  61. package/layers/metadata/server/api/metadata/status.get.ts +13 -18
  62. package/layers/metadata/server/utils/metadata/provider-registry.test.ts +1 -1
  63. package/layers/metadata/server/utils/metadata/search.test.ts +18 -18
  64. package/layers/metadata/server/utils/metadata/search.ts +16 -8
  65. package/layers/navigation/app/utils/site.test.ts +1 -3
  66. package/layers/scroll/app/components/Motion/PinnedSection.vue +11 -1
  67. package/layers/scroll/app/composables/useSectionProgress.ts +1 -1
  68. package/layers/scroll/app/plugins/locomotive-scroll.client.ts +6 -0
  69. package/layers/scroll/app/utils/scroll.ts +5 -1
  70. package/layers/seo/app/utils/seoConfig.test.ts +1 -1
  71. package/layers/shader/app/assets/css/shader.css +1 -1
  72. package/layers/shader/app/components/Material/AmbientAurora.client.vue +16 -4
  73. package/layers/shader/app/components/Material/AmbientFlow.client.vue +21 -5
  74. package/layers/shader/app/components/Material/AmbientGradientMesh.client.vue +21 -5
  75. package/layers/shader/app/components/Material/AmbientNebula.client.vue +21 -5
  76. package/layers/shader/app/components/Material/AmbientOcean.client.vue +16 -4
  77. package/layers/shader/app/components/Material/Gradient.client.vue +1 -1
  78. package/layers/shader/app/components/Material/Image.client.vue +1 -1
  79. package/layers/shader/app/components/Material/Noise.client.vue +11 -3
  80. package/layers/shader/app/composables/useAmbientMaterials.ts +0 -1
  81. package/layers/shader/app/shaders/common/blend.ts +5 -1
  82. package/layers/shader/app/shaders/common/grain.ts +5 -1
  83. package/layers/shader/app/shaders/common/lighting.ts +1 -6
  84. package/layers/shader/app/shaders/common/noise.ts +3 -1
  85. package/layers/shader/app/shaders/common/patterns.ts +1 -1
  86. package/layers/shader/app/shaders/common/shapes.ts +5 -1
  87. package/layers/shader/app/shaders/common/uv.ts +19 -2
  88. package/layers/shader/app/shaders/createMaterial.ts +11 -6
  89. package/layers/shader/app/shaders/layers/shaderGradient.ts +2 -12
  90. package/layers/shader/app/shaders/types.ts +1 -1
  91. package/layers/shader/app/types/uniforms.ts +1 -0
  92. package/layers/shader/app/utils/tsl/animation.ts +34 -36
  93. package/layers/starter/app/components/StarterDesignSystem.vue +120 -120
  94. package/layers/starter/app/components/StarterHome.vue +233 -208
  95. package/layers/theme/app/assets/css/theme.css +1 -1
  96. package/layers/theme/server/utils/accent-css.test.ts +17 -2
  97. package/layers/theme/server/utils/fouc-config.test.ts +7 -3
  98. package/layers/theme/server/utils/fouc-config.ts +24 -12
  99. package/layers/transitions/app/assets/css/transitions.css +6 -0
  100. package/layers/typography/app/assets/css/typography.css +313 -0
  101. package/layers/typography/app/components/Typography/Headline.vue +23 -14
  102. package/layers/typography/app/components/Typography/HeadlineScreen.vue +5 -12
  103. package/layers/typography/app/components/Typography/index.vue +4 -0
  104. package/layers/typography/app/composables/typography.ts +45 -5
  105. package/layers/typography/app/types/typography.ts +36 -7
  106. package/layers/typography/nuxt.config.ts +2 -0
  107. package/layers/visual/app/app.config.ts +1 -1
  108. package/layers/visual/app/assets/css/visual.css +1 -1
  109. package/layers/visual/app/composables/accent.ts +1 -2
  110. package/layers/visual/app/composables/tint.ts +1 -2
  111. package/layers/visual/app/types/media.ts +2 -2
  112. package/layers/visual/app/utils/gradientStyle.test.ts +1 -2
  113. package/layers/visual/app/utils/responsiveSizes.ts +0 -1
  114. package/package.json +36 -16
@@ -1,221 +1,247 @@
1
1
  <script setup lang="ts">
2
- useSeoMeta({
3
- title: 'kmcom-nuxt-layers Starter',
4
- description:
5
- 'A production-ready Nuxt starter powered by kmcom-nuxt-layers. Composable, modular, and ready to ship.',
6
- })
2
+ useSeoMeta({
3
+ title: 'kmcom-nuxt-layers Starter',
4
+ description:
5
+ 'A production-ready Nuxt starter powered by kmcom-nuxt-layers. Composable, modular, and ready to ship.',
6
+ })
7
7
 
8
- const { gsap, ScrollTrigger } = useGsap()
9
- gsap.registerPlugin(ScrollTrigger)
8
+ const { gsap, ScrollTrigger } = useGsap()
9
+ gsap.registerPlugin(ScrollTrigger)
10
10
 
11
- const heroRef = ref<HTMLElement | null>(null)
12
- const sectionsRef = ref<HTMLElement | null>(null)
11
+ const heroRef = useTemplateRef<HTMLElement>('heroRef')
12
+ const sectionsRef = useTemplateRef<HTMLElement>('sectionsRef')
13
13
 
14
- let ctx: ReturnType<typeof gsap.context> | null = null
14
+ let ctx: ReturnType<typeof gsap.context> | null = null
15
15
 
16
- onMounted(() => {
17
- ctx = gsap.context(() => {
18
- if (heroRef.value) {
19
- gsap.from(Array.from(heroRef.value.children), {
20
- y: 24,
21
- opacity: 0,
22
- duration: 0.7,
23
- stagger: 0.1,
24
- ease: 'power3.out',
25
- })
26
- }
16
+ onMounted(() => {
17
+ ctx = gsap.context(() => {
18
+ if (heroRef.value) {
19
+ gsap.from(Array.from(heroRef.value.children), {
20
+ y: 24,
21
+ opacity: 0,
22
+ duration: 0.7,
23
+ stagger: 0.1,
24
+ ease: 'power3.out',
25
+ })
26
+ }
27
27
 
28
- if (sectionsRef.value) {
29
- gsap.from(sectionsRef.value.querySelectorAll('.layer-card'), {
30
- scrollTrigger: {
31
- trigger: sectionsRef.value,
32
- start: 'top 85%',
33
- toggleActions: 'play none none none',
34
- },
35
- y: 32,
36
- opacity: 0,
37
- scale: 0.97,
38
- duration: 0.5,
39
- stagger: { amount: 0.5 },
40
- ease: 'power3.out',
41
- })
42
- }
28
+ if (sectionsRef.value) {
29
+ gsap.from(sectionsRef.value.querySelectorAll('.layer-card'), {
30
+ scrollTrigger: {
31
+ trigger: sectionsRef.value,
32
+ start: 'top 85%',
33
+ toggleActions: 'play none none none',
34
+ },
35
+ y: 32,
36
+ opacity: 0,
37
+ scale: 0.97,
38
+ duration: 0.5,
39
+ stagger: { amount: 0.5 },
40
+ ease: 'power3.out',
41
+ })
42
+ }
43
+ })
43
44
  })
44
- })
45
45
 
46
- onUnmounted(() => {
47
- ctx?.revert()
48
- ctx = null
49
- })
46
+ onUnmounted(() => {
47
+ ctx?.revert()
48
+ ctx = null
49
+ })
50
50
 
51
- const appConfig = useAppConfig()
52
- const activeLayers = appConfig.layers ?? {}
51
+ const appConfig = useAppConfig()
52
+ const activeLayers = appConfig.layers ?? {}
53
53
 
54
- type LayerDef = {
55
- name: string
56
- key: string
57
- description: string
58
- icon: string
59
- features: string[]
60
- borderColor: string
61
- bgColor: string
62
- iconBg: string
63
- iconColor: string
64
- }
54
+ type LayerDef = {
55
+ name: string
56
+ key: string
57
+ description: string
58
+ icon: string
59
+ features: string[]
60
+ borderColor: string
61
+ bgColor: string
62
+ iconBg: string
63
+ iconColor: string
64
+ }
65
65
 
66
- const coreLayers: LayerDef[] = [
67
- {
68
- name: 'Core',
69
- key: 'core',
70
- description: 'Foundation utilities, error handling, device detection, PWA support',
71
- icon: 'i-lucide-box',
72
- features: ['Browser Detection', 'Screen Info', 'Network Status', 'Loading States', 'PWA'],
73
- borderColor: 'border-blue-500/30',
74
- bgColor: 'bg-blue-500/5',
75
- iconBg: 'bg-blue-500/10',
76
- iconColor: 'text-blue-500',
77
- },
78
- {
79
- name: 'UI',
80
- key: 'ui',
81
- description: 'Typography, navigation, visual primitives and the design system',
82
- icon: 'i-lucide-palette',
83
- features: ['Typography', 'Color Tokens', 'Navigation', 'Visual Primitives', 'Toast', 'Modal'],
84
- borderColor: 'border-pink-500/30',
85
- bgColor: 'bg-pink-500/5',
86
- iconBg: 'bg-pink-500/10',
87
- iconColor: 'text-pink-500',
88
- },
89
- {
90
- name: 'Layout',
91
- key: 'layout',
92
- description: 'Swiss Grid system, sections, and page containers',
93
- icon: 'i-lucide-layout',
94
- features: ['18-Col Grid', 'Hero Section', 'Split Section', 'Gallery Section', 'Grid Debug'],
95
- borderColor: 'border-amber-500/30',
96
- bgColor: 'bg-amber-500/5',
97
- iconBg: 'bg-amber-500/10',
98
- iconColor: 'text-amber-500',
99
- },
100
- {
101
- name: 'Motion',
102
- key: 'motion',
103
- description: 'GSAP, Lenis smooth scroll, page transitions and animation effects',
104
- icon: 'i-lucide-sparkles',
105
- features: ['GSAP', 'ScrollTrigger', 'Lenis', 'Marquee', 'Magnetic', 'Tilt', 'Cursor'],
106
- borderColor: 'border-emerald-500/30',
107
- bgColor: 'bg-emerald-500/5',
108
- iconBg: 'bg-emerald-500/10',
109
- iconColor: 'text-emerald-500',
110
- },
111
- {
112
- name: 'Forms',
113
- key: 'forms',
114
- description: 'Config-driven form fields with Zod validation and type inference',
115
- icon: 'i-lucide-file-input',
116
- features: ['Dynamic Fields', 'Zod Validation', 'Type Inference', 'Auto Icons', 'Contact Form'],
117
- borderColor: 'border-cyan-500/30',
118
- bgColor: 'bg-cyan-500/5',
119
- iconBg: 'bg-cyan-500/10',
120
- iconColor: 'text-cyan-500',
121
- },
122
- {
123
- name: 'Theme',
124
- key: 'theme',
125
- description: 'Dark mode, accent color palettes and design token system',
126
- icon: 'i-lucide-swatch-book',
127
- features: ['Dark Mode', 'Accent Colors', 'Color Tokens', 'Color Mode'],
128
- borderColor: 'border-neutral-400/30',
129
- bgColor: 'bg-neutral-400/5',
130
- iconBg: 'bg-neutral-400/10',
131
- iconColor: 'text-neutral-400',
132
- },
133
- {
134
- name: 'Content',
135
- key: 'content',
136
- description: 'Markdown CMS with typed collections via @nuxt/content',
137
- icon: 'i-lucide-file-text',
138
- features: ['Markdown', 'Collections', 'Frontmatter', 'Content API', 'Zod Schemas'],
139
- borderColor: 'border-rose-500/30',
140
- bgColor: 'bg-rose-500/5',
141
- iconBg: 'bg-rose-500/10',
142
- iconColor: 'text-rose-500',
143
- },
144
- {
145
- name: 'Scripts',
146
- key: 'scripts',
147
- description: 'Third-party script management with performance-safe loading',
148
- icon: 'i-lucide-code',
149
- features: ['Lazy Loading', 'Analytics', 'Consent-Aware', 'Performance-Safe'],
150
- borderColor: 'border-indigo-500/30',
151
- bgColor: 'bg-indigo-500/5',
152
- iconBg: 'bg-indigo-500/10',
153
- iconColor: 'text-indigo-500',
154
- },
155
- {
156
- name: 'Routing',
157
- key: 'routing',
158
- description: 'Advanced routing utilities, typed middleware and navigation helpers',
159
- icon: 'i-lucide-route',
160
- features: ['Typed Routes', 'Middleware', 'Route Guards', 'Navigation Utils'],
161
- borderColor: 'border-teal-500/30',
162
- bgColor: 'bg-teal-500/5',
163
- iconBg: 'bg-teal-500/10',
164
- iconColor: 'text-teal-500',
165
- },
166
- {
167
- name: 'SEO',
168
- key: 'seo',
169
- description: 'Meta tags, Open Graph, JSON-LD, sitemap and robots.txt via @nuxtjs/seo',
170
- icon: 'i-lucide-search',
171
- features: ['Meta Tags', 'Open Graph', 'JSON-LD', 'Sitemap', 'Robots.txt', 'Schema.org'],
172
- borderColor: 'border-sky-500/30',
173
- bgColor: 'bg-sky-500/5',
174
- iconBg: 'bg-sky-500/10',
175
- iconColor: 'text-sky-500',
176
- },
177
- {
178
- name: 'Feeds',
179
- key: 'feeds',
180
- description: 'RSS and feed aggregation with display components',
181
- icon: 'i-lucide-rss',
182
- features: ['RSS Feeds', 'Feed Display', 'Feed Parser'],
183
- borderColor: 'border-orange-500/30',
184
- bgColor: 'bg-orange-500/5',
185
- iconBg: 'bg-orange-500/10',
186
- iconColor: 'text-orange-500',
187
- },
188
- ]
66
+ const coreLayers: LayerDef[] = [
67
+ {
68
+ name: 'Core',
69
+ key: 'core',
70
+ description: 'Foundation utilities, error handling, device detection, PWA support',
71
+ icon: 'i-lucide-box',
72
+ features: ['Browser Detection', 'Screen Info', 'Network Status', 'Loading States', 'PWA'],
73
+ borderColor: 'border-blue-500/30',
74
+ bgColor: 'bg-blue-500/5',
75
+ iconBg: 'bg-blue-500/10',
76
+ iconColor: 'text-blue-500',
77
+ },
78
+ {
79
+ name: 'UI',
80
+ key: 'ui',
81
+ description: 'Typography, navigation, visual primitives and the design system',
82
+ icon: 'i-lucide-palette',
83
+ features: ['Typography', 'Color Tokens', 'Navigation', 'Visual Primitives', 'Toast', 'Modal'],
84
+ borderColor: 'border-pink-500/30',
85
+ bgColor: 'bg-pink-500/5',
86
+ iconBg: 'bg-pink-500/10',
87
+ iconColor: 'text-pink-500',
88
+ },
89
+ {
90
+ name: 'Layout',
91
+ key: 'layout',
92
+ description: 'Swiss Grid system, sections, and page containers',
93
+ icon: 'i-lucide-layout',
94
+ features: ['18-Col Grid', 'Hero Section', 'Split Section', 'Gallery Section', 'Grid Debug'],
95
+ borderColor: 'border-amber-500/30',
96
+ bgColor: 'bg-amber-500/5',
97
+ iconBg: 'bg-amber-500/10',
98
+ iconColor: 'text-amber-500',
99
+ },
100
+ {
101
+ name: 'Motion',
102
+ key: 'motion',
103
+ description: 'GSAP, Lenis smooth scroll, page transitions and animation effects',
104
+ icon: 'i-lucide-sparkles',
105
+ features: ['GSAP', 'ScrollTrigger', 'Lenis', 'Marquee', 'Magnetic', 'Tilt', 'Cursor'],
106
+ borderColor: 'border-emerald-500/30',
107
+ bgColor: 'bg-emerald-500/5',
108
+ iconBg: 'bg-emerald-500/10',
109
+ iconColor: 'text-emerald-500',
110
+ },
111
+ {
112
+ name: 'Forms',
113
+ key: 'forms',
114
+ description: 'Config-driven form fields with Zod validation and type inference',
115
+ icon: 'i-lucide-file-input',
116
+ features: [
117
+ 'Dynamic Fields',
118
+ 'Zod Validation',
119
+ 'Type Inference',
120
+ 'Auto Icons',
121
+ 'Contact Form',
122
+ ],
123
+ borderColor: 'border-cyan-500/30',
124
+ bgColor: 'bg-cyan-500/5',
125
+ iconBg: 'bg-cyan-500/10',
126
+ iconColor: 'text-cyan-500',
127
+ },
128
+ {
129
+ name: 'Theme',
130
+ key: 'theme',
131
+ description: 'Dark mode, accent color palettes and design token system',
132
+ icon: 'i-lucide-swatch-book',
133
+ features: ['Dark Mode', 'Accent Colors', 'Color Tokens', 'Color Mode'],
134
+ borderColor: 'border-neutral-400/30',
135
+ bgColor: 'bg-neutral-400/5',
136
+ iconBg: 'bg-neutral-400/10',
137
+ iconColor: 'text-neutral-400',
138
+ },
139
+ {
140
+ name: 'Content',
141
+ key: 'content',
142
+ description: 'Markdown CMS with typed collections via @nuxt/content',
143
+ icon: 'i-lucide-file-text',
144
+ features: ['Markdown', 'Collections', 'Frontmatter', 'Content API', 'Zod Schemas'],
145
+ borderColor: 'border-rose-500/30',
146
+ bgColor: 'bg-rose-500/5',
147
+ iconBg: 'bg-rose-500/10',
148
+ iconColor: 'text-rose-500',
149
+ },
150
+ {
151
+ name: 'Scripts',
152
+ key: 'scripts',
153
+ description: 'Third-party script management with performance-safe loading',
154
+ icon: 'i-lucide-code',
155
+ features: ['Lazy Loading', 'Analytics', 'Consent-Aware', 'Performance-Safe'],
156
+ borderColor: 'border-indigo-500/30',
157
+ bgColor: 'bg-indigo-500/5',
158
+ iconBg: 'bg-indigo-500/10',
159
+ iconColor: 'text-indigo-500',
160
+ },
161
+ {
162
+ name: 'Routing',
163
+ key: 'routing',
164
+ description: 'Advanced routing utilities, typed middleware and navigation helpers',
165
+ icon: 'i-lucide-route',
166
+ features: ['Typed Routes', 'Middleware', 'Route Guards', 'Navigation Utils'],
167
+ borderColor: 'border-teal-500/30',
168
+ bgColor: 'bg-teal-500/5',
169
+ iconBg: 'bg-teal-500/10',
170
+ iconColor: 'text-teal-500',
171
+ },
172
+ {
173
+ name: 'SEO',
174
+ key: 'seo',
175
+ description: 'Meta tags, Open Graph, JSON-LD, sitemap and robots.txt via @nuxtjs/seo',
176
+ icon: 'i-lucide-search',
177
+ features: ['Meta Tags', 'Open Graph', 'JSON-LD', 'Sitemap', 'Robots.txt', 'Schema.org'],
178
+ borderColor: 'border-sky-500/30',
179
+ bgColor: 'bg-sky-500/5',
180
+ iconBg: 'bg-sky-500/10',
181
+ iconColor: 'text-sky-500',
182
+ },
183
+ {
184
+ name: 'Feeds',
185
+ key: 'feeds',
186
+ description: 'RSS and feed aggregation with display components',
187
+ icon: 'i-lucide-rss',
188
+ features: ['RSS Feeds', 'Feed Display', 'Feed Parser'],
189
+ borderColor: 'border-orange-500/30',
190
+ bgColor: 'bg-orange-500/5',
191
+ iconBg: 'bg-orange-500/10',
192
+ iconColor: 'text-orange-500',
193
+ },
194
+ ]
189
195
 
190
- const addonLayers: LayerDef[] = [
191
- {
192
- name: 'Canvas',
193
- key: 'canvas',
194
- description: 'WebGL/WebGPU canvas foundation required by the shader layer',
195
- icon: 'i-lucide-monitor',
196
- features: ['WebGL', 'WebGPU', 'Canvas Composables', '3D Foundation'],
197
- borderColor: 'border-purple-500/30',
198
- bgColor: 'bg-purple-500/5',
199
- iconBg: 'bg-purple-500/10',
200
- iconColor: 'text-purple-500',
201
- },
202
- {
203
- name: 'Shader',
204
- key: 'shader',
205
- description: 'Three.js + TresJS shader system with TSL, noise and post-processing',
206
- icon: 'i-lucide-shapes',
207
- features: ['TSL Shaders', 'Noise', 'Gradients', 'Fresnel', 'Post-Processing', 'WebGPU'],
208
- borderColor: 'border-violet-500/30',
209
- bgColor: 'bg-violet-500/5',
210
- iconBg: 'bg-violet-500/10',
211
- iconColor: 'text-violet-500',
212
- },
213
- ]
196
+ const addonLayers: LayerDef[] = [
197
+ {
198
+ name: 'Canvas',
199
+ key: 'canvas',
200
+ description: 'WebGL/WebGPU canvas foundation required by the shader layer',
201
+ icon: 'i-lucide-monitor',
202
+ features: ['WebGL', 'WebGPU', 'Canvas Composables', '3D Foundation'],
203
+ borderColor: 'border-purple-500/30',
204
+ bgColor: 'bg-purple-500/5',
205
+ iconBg: 'bg-purple-500/10',
206
+ iconColor: 'text-purple-500',
207
+ },
208
+ {
209
+ name: 'Shader',
210
+ key: 'shader',
211
+ description: 'Three.js + TresJS shader system with TSL, noise and post-processing',
212
+ icon: 'i-lucide-shapes',
213
+ features: ['TSL Shaders', 'Noise', 'Gradients', 'Fresnel', 'Post-Processing', 'WebGPU'],
214
+ borderColor: 'border-violet-500/30',
215
+ bgColor: 'bg-violet-500/5',
216
+ iconBg: 'bg-violet-500/10',
217
+ iconColor: 'text-violet-500',
218
+ },
219
+ ]
214
220
 
215
- const marqueeItems = [
216
- 'Core', '◆', 'UI', '◆', 'Layout', '◆', 'Motion', '◆', 'Forms', '◆',
217
- 'Theme', '◆', 'Content', '◆', 'SEO', '◆', 'Scripts', '◆', 'Routing', '◆', 'Feeds', '◆',
218
- ]
221
+ const marqueeItems = [
222
+ 'Core',
223
+ '◆',
224
+ 'UI',
225
+ '◆',
226
+ 'Layout',
227
+ '◆',
228
+ 'Motion',
229
+ '◆',
230
+ 'Forms',
231
+ '◆',
232
+ 'Theme',
233
+ '◆',
234
+ 'Content',
235
+ '◆',
236
+ 'SEO',
237
+ '◆',
238
+ 'Scripts',
239
+ '◆',
240
+ 'Routing',
241
+ '◆',
242
+ 'Feeds',
243
+ '◆',
244
+ ]
219
245
  </script>
220
246
 
221
247
  <template>
@@ -269,14 +295,14 @@ const marqueeItems = [
269
295
  v-for="item in marqueeItems"
270
296
  :key="item"
271
297
  class="text-muted whitespace-nowrap text-xs font-semibold uppercase tracking-widest"
272
- >{{ item }}</span>
298
+ >{{ item }}</span
299
+ >
273
300
  </MotionMarquee>
274
301
  </div>
275
302
 
276
303
  <div ref="sectionsRef">
277
304
  <UContainer class="px-8 pb-8 pt-10">
278
305
  <div class="space-y-12">
279
-
280
306
  <!-- Core Layers -->
281
307
  <section>
282
308
  <div class="mb-6">
@@ -408,7 +434,6 @@ const marqueeItems = [
408
434
  View Source
409
435
  </UButton>
410
436
  </div>
411
-
412
437
  </div>
413
438
  </UContainer>
414
439
  </div>
@@ -36,7 +36,7 @@
36
36
 
37
37
  [data-theme-transparency='reduced'] :where([class*='backdrop-blur']) {
38
38
  backdrop-filter: none !important;
39
- -webkit-backdrop-filter: none !important;
39
+ backdrop-filter: none !important;
40
40
  }
41
41
 
42
42
  [data-theme-transparency='reduced'] :where([class*='bg-default/'], [class*='bg-elevated/']) {
@@ -4,8 +4,23 @@ import { describe, expect, it } from 'vitest'
4
4
  import { buildAccentCSS } from './accent-css'
5
5
 
6
6
  const ACCENTS = [
7
- 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal',
8
- 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose',
7
+ 'red',
8
+ 'orange',
9
+ 'amber',
10
+ 'yellow',
11
+ 'lime',
12
+ 'green',
13
+ 'emerald',
14
+ 'teal',
15
+ 'cyan',
16
+ 'sky',
17
+ 'blue',
18
+ 'indigo',
19
+ 'violet',
20
+ 'purple',
21
+ 'fuchsia',
22
+ 'pink',
23
+ 'rose',
9
24
  ] as const
10
25
 
11
26
  const SHADES = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const
@@ -30,7 +30,9 @@ describe('buildThemeInitScript', () => {
30
30
  expect(script).toContain("var ct=localStorage.getItem('theme-contrast');")
31
31
  expect(script).toContain("var ctv=ct?JSON.parse(ct):'system';")
32
32
  expect(script).toContain("if(ctv==='on'){h.setAttribute('data-theme-contrast','high')}")
33
- expect(script).toContain("else if(ctv==='off'){h.setAttribute('data-theme-contrast','standard')}")
33
+ expect(script).toContain(
34
+ "else if(ctv==='off'){h.setAttribute('data-theme-contrast','standard')}"
35
+ )
34
36
  expect(script).toContain(
35
37
  "else{h.setAttribute('data-theme-contrast',(window.matchMedia&&window.matchMedia('(prefers-contrast:more)').matches)?'high':'standard')}"
36
38
  )
@@ -48,7 +50,9 @@ describe('buildThemeInitScript', () => {
48
50
  it('emits a JSON-parsed tri-state block for theme-transparency', () => {
49
51
  expect(script).toContain("var t=localStorage.getItem('theme-transparency');")
50
52
  expect(script).toContain("if(tv==='on'){h.setAttribute('data-theme-transparency','reduced')}")
51
- expect(script).toContain("else if(tv==='off'){h.setAttribute('data-theme-transparency','full')}")
53
+ expect(script).toContain(
54
+ "else if(tv==='off'){h.setAttribute('data-theme-transparency','full')}"
55
+ )
52
56
  expect(script).toContain(
53
57
  "window.matchMedia('(prefers-reduced-transparency:reduce)').matches)?'reduced':'full'"
54
58
  )
@@ -65,7 +69,7 @@ describe('buildThemeInitScript', () => {
65
69
  })
66
70
 
67
71
  it('does not JSON.parse the theme-mode value (jsonParsed: false)', () => {
68
- expect(script).not.toContain("JSON.parse(dm)")
72
+ expect(script).not.toContain('JSON.parse(dm)')
69
73
  })
70
74
 
71
75
  it('produces valid, evaluable JavaScript', () => {
@@ -20,40 +20,52 @@ const THEME_PREFERENCES: TriStatePreference[] = [
20
20
  storageKey: 'theme-contrast',
21
21
  attribute: 'data-theme-contrast',
22
22
  jsonParsed: true,
23
- conditionA: 'on', valueA: 'high',
24
- conditionB: 'off', valueB: 'standard',
23
+ conditionA: 'on',
24
+ valueA: 'high',
25
+ conditionB: 'off',
26
+ valueB: 'standard',
25
27
  mediaQuery: '(prefers-contrast:more)',
26
- mediaTrue: 'high', mediaFalse: 'standard',
28
+ mediaTrue: 'high',
29
+ mediaFalse: 'standard',
27
30
  },
28
31
  {
29
32
  varName: 'm',
30
33
  storageKey: 'theme-motion',
31
34
  attribute: 'data-theme-motion',
32
35
  jsonParsed: true,
33
- conditionA: 'on', valueA: 'reduced',
34
- conditionB: 'off', valueB: 'full',
36
+ conditionA: 'on',
37
+ valueA: 'reduced',
38
+ conditionB: 'off',
39
+ valueB: 'full',
35
40
  mediaQuery: '(prefers-reduced-motion:reduce)',
36
- mediaTrue: 'reduced', mediaFalse: 'full',
41
+ mediaTrue: 'reduced',
42
+ mediaFalse: 'full',
37
43
  },
38
44
  {
39
45
  varName: 't',
40
46
  storageKey: 'theme-transparency',
41
47
  attribute: 'data-theme-transparency',
42
48
  jsonParsed: true,
43
- conditionA: 'on', valueA: 'reduced',
44
- conditionB: 'off', valueB: 'full',
49
+ conditionA: 'on',
50
+ valueA: 'reduced',
51
+ conditionB: 'off',
52
+ valueB: 'full',
45
53
  mediaQuery: '(prefers-reduced-transparency:reduce)',
46
- mediaTrue: 'reduced', mediaFalse: 'full',
54
+ mediaTrue: 'reduced',
55
+ mediaFalse: 'full',
47
56
  },
48
57
  {
49
58
  varName: 'dm',
50
59
  storageKey: 'theme-mode',
51
60
  attribute: 'data-theme-mode',
52
61
  jsonParsed: false,
53
- conditionA: 'dark', valueA: 'dark',
54
- conditionB: 'light', valueB: 'light',
62
+ conditionA: 'dark',
63
+ valueA: 'dark',
64
+ conditionB: 'light',
65
+ valueB: 'light',
55
66
  mediaQuery: '(prefers-color-scheme:dark)',
56
- mediaTrue: 'dark', mediaFalse: 'light',
67
+ mediaTrue: 'dark',
68
+ mediaFalse: 'light',
57
69
  },
58
70
  ]
59
71
 
@@ -49,6 +49,7 @@
49
49
  from {
50
50
  opacity: 0;
51
51
  }
52
+
52
53
  to {
53
54
  opacity: 1;
54
55
  }
@@ -58,6 +59,7 @@
58
59
  from {
59
60
  opacity: 1;
60
61
  }
62
+
61
63
  to {
62
64
  opacity: 0;
63
65
  }
@@ -68,6 +70,7 @@
68
70
  transform: translateY(20px);
69
71
  opacity: 0;
70
72
  }
73
+
71
74
  to {
72
75
  transform: translateY(0);
73
76
  opacity: 1;
@@ -79,6 +82,7 @@
79
82
  transform: translateY(-20px);
80
83
  opacity: 0;
81
84
  }
85
+
82
86
  to {
83
87
  transform: translateY(0);
84
88
  opacity: 1;
@@ -90,6 +94,7 @@
90
94
  transform: translateX(-20px);
91
95
  opacity: 0;
92
96
  }
97
+
93
98
  to {
94
99
  transform: translateX(0);
95
100
  opacity: 1;
@@ -101,6 +106,7 @@
101
106
  transform: translateX(20px);
102
107
  opacity: 0;
103
108
  }
109
+
104
110
  to {
105
111
  transform: translateX(0);
106
112
  opacity: 1;