kmcom-nuxt-layers 1.7.3 → 1.7.5

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.
@@ -12,7 +12,7 @@ const asBlog = (item: unknown) => item as BlogCollectionItem
12
12
  <NuxtContentDetail collection="blog" :slug not-found-message="Blog post not found">
13
13
  <template #headline="{ item }">
14
14
  <div class="flex items-center gap-3 text-sm text-muted">
15
- <time v-if="asBlog(item).date">{{ new Date(asBlog(item).date).toLocaleDateString() }}</time>
15
+ <time v-if="asBlog(item).date">{{ new Date(asBlog(item).date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }) }}</time>
16
16
  <UBadge v-if="asBlog(item).badge" color="primary" variant="subtle">
17
17
  {{ asBlog(item).badge }}
18
18
  </UBadge>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ const { contentLayer } = useAppConfig()
3
+ if (contentLayer?.sections?.gallery === false) {
4
+ throw createError({ statusCode: 404, statusMessage: 'Not Found' })
5
+ }
6
+
7
+ const { slug, index } = defineProps<{
8
+ slug: string
9
+ index: number
10
+ }>()
11
+ </script>
12
+
13
+ <template>
14
+ <LayoutSection>
15
+ <LayoutGridItem>
16
+ <GalleryImageDetail :slug :index />
17
+ </LayoutGridItem>
18
+ </LayoutSection>
19
+ </template>
@@ -1,13 +1,13 @@
1
1
  <script setup lang="ts">
2
- const { contentLayer } = useAppConfig()
3
- if (contentLayer?.sections?.gallery === false) {
4
- throw createError({ statusCode: 404, statusMessage: 'Not Found' })
5
- }
2
+ const { contentLayer } = useAppConfig()
3
+ if (contentLayer?.sections?.gallery === false) {
4
+ throw createError({ statusCode: 404, statusMessage: 'Not Found' })
5
+ }
6
6
 
7
- useSeoMeta({
8
- title: 'Gallery',
9
- description: 'Photo collections and visual work',
10
- })
7
+ useSeoMeta({
8
+ title: 'Gallery',
9
+ description: 'Photo collections and visual work',
10
+ })
11
11
  </script>
12
12
 
13
13
  <template>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ const { contentLayer } = useAppConfig()
3
+ if (contentLayer?.sections?.gallery === false) {
4
+ throw createError({ statusCode: 404, statusMessage: 'Not Found' })
5
+ }
6
+
7
+ const { slug } = defineProps<{
8
+ slug: string
9
+ }>()
10
+ </script>
11
+
12
+ <template>
13
+ <LayoutSection>
14
+ <LayoutGridItem>
15
+ <GalleryDetail :slug />
16
+ </LayoutGridItem>
17
+ </LayoutSection>
18
+ </template>
@@ -27,14 +27,13 @@ useSeoMeta({
27
27
  <template>
28
28
  <div class="min-h-screen p-8">
29
29
  <UContainer>
30
+ <ClientOnly>
30
31
  <div class="space-y-8">
31
- <!-- Header -->
32
32
  <div class="text-center">
33
33
  <h1 class="text-4xl font-bold mb-2">Core Layer Diagnostics</h1>
34
34
  <p class="text-gray-500 dark:text-gray-400">Feature detection and system information</p>
35
35
  </div>
36
36
 
37
- <!-- CSS Features -->
38
37
  <UCard>
39
38
  <template #header>
40
39
  <h2 class="text-xl font-semibold">CSS Features</h2>
@@ -73,7 +72,6 @@ useSeoMeta({
73
72
  </div>
74
73
  </UCard>
75
74
 
76
- <!-- Image Formats -->
77
75
  <UCard>
78
76
  <template #header>
79
77
  <h2 class="text-xl font-semibold">Image Formats</h2>
@@ -92,7 +90,6 @@ useSeoMeta({
92
90
  </div>
93
91
  </UCard>
94
92
 
95
- <!-- JavaScript APIs -->
96
93
  <UCard>
97
94
  <template #header>
98
95
  <h2 class="text-xl font-semibold">JavaScript APIs</h2>
@@ -121,7 +118,6 @@ useSeoMeta({
121
118
  </div>
122
119
  </UCard>
123
120
 
124
- <!-- Device Info -->
125
121
  <UCard>
126
122
  <template #header>
127
123
  <h2 class="text-xl font-semibold">Device Information</h2>
@@ -136,7 +132,6 @@ useSeoMeta({
136
132
  </div>
137
133
  </UCard>
138
134
 
139
- <!-- Network Info -->
140
135
  <UCard>
141
136
  <template #header>
142
137
  <h2 class="text-xl font-semibold">Network Information</h2>
@@ -177,7 +172,6 @@ useSeoMeta({
177
172
  </div>
178
173
  </UCard>
179
174
 
180
- <!-- Rendering Info -->
181
175
  <UCard>
182
176
  <template #header>
183
177
  <h2 class="text-xl font-semibold">Rendering Information</h2>
@@ -200,7 +194,6 @@ useSeoMeta({
200
194
  </div>
201
195
  </UCard>
202
196
 
203
- <!-- PWA Info -->
204
197
  <UCard>
205
198
  <template #header>
206
199
  <h2 class="text-xl font-semibold">PWA Information</h2>
@@ -223,6 +216,11 @@ useSeoMeta({
223
216
  </div>
224
217
  </UCard>
225
218
  </div>
219
+
220
+ <template #fallback>
221
+ <div class="text-center text-muted py-16">Loading diagnostics…</div>
222
+ </template>
223
+ </ClientOnly>
226
224
  </UContainer>
227
225
  </div>
228
226
  </template>
@@ -1,4 +1,6 @@
1
1
  <script setup lang="ts">
2
+ defineOptions({ inheritAttrs: false })
3
+
2
4
  const props = withDefaults(
3
5
  defineProps<{
4
6
  /**
@@ -48,7 +50,7 @@ const percentage = computed(() => Math.round(progress.value * 100))
48
50
 
49
51
  <template>
50
52
  <!-- Linear Progress -->
51
- <div v-if="type === 'linear'" class="motion-scroll-progress-linear">
53
+ <div v-if="type === 'linear'" class="motion-scroll-progress-linear" v-bind="$attrs">
52
54
  <div
53
55
  class="w-full rounded-full overflow-hidden"
54
56
  :style="{ height: `${height}px`, backgroundColor: bgColor }"
@@ -69,6 +71,7 @@ const percentage = computed(() => Math.round(progress.value * 100))
69
71
  <!-- Circular Progress -->
70
72
  <ProgressCircular
71
73
  v-else
74
+ v-bind="$attrs"
72
75
  :progress="progress"
73
76
  :size
74
77
  :stroke-width="strokeWidth"
@@ -2,7 +2,7 @@
2
2
  // @ts-nocheck - TSL types are complex
3
3
  import { DoubleSide } from 'three'
4
4
  import { MeshBasicNodeMaterial } from 'three/webgpu'
5
- import { float, positionLocal, uv, vec3, vec4 } from 'three/tsl'
5
+ import { float, Fn, positionLocal, uv, vec3, vec4 } from 'three/tsl'
6
6
 
7
7
  const { transparent = false } = defineProps<{
8
8
  transparent?: boolean
@@ -28,18 +28,16 @@ watch(
28
28
  const vertex = pipeline.stagesFor('vertex')
29
29
  const ray = pipeline.stagesFor('ray')
30
30
 
31
- // UV chain generators read pipeline.uvNode.value in their stage fn closures
32
- pipeline.uvNode.value = uvStages.reduce((node, { fn }) => fn(node), uv())
33
-
34
- // Ray chain sky/tunnel generators read pipeline.rayNode.value in their closures
35
- pipeline.rayNode.value = ray.reduce((node, { fn }) => fn(node), screenRayNode)
36
-
37
- // Fragment chain
38
- material.colorNode = fragment.reduce((node, { fn }) => fn(node), vec4(0, 0, 0, 1))
31
+ // Wrap each chain in Fn() so TSL .toVar()/.assign() ops (used by noise functions
32
+ // like simplexNoise3d) have a valid stack context. Without this, TSL throws
33
+ // "No stack defined for assign operation".
34
+ pipeline.uvNode.value = Fn(() => uvStages.reduce((node, { fn }) => fn(node), uv()))()
35
+ pipeline.rayNode.value = Fn(() => ray.reduce((node, { fn }) => fn(node), screenRayNode))()
36
+ material.colorNode = Fn(() => fragment.reduce((node, { fn }) => fn(node), vec4(0, 0, 0, 1)))()
39
37
  material.needsUpdate = true
40
38
 
41
39
  if (vertex.length > 0) {
42
- material.positionNode = vertex.reduce((node, { fn }) => fn(node), positionLocal)
40
+ material.positionNode = Fn(() => vertex.reduce((node, { fn }) => fn(node), positionLocal))()
43
41
  material.needsUpdate = true
44
42
  }
45
43
  },
@@ -1,17 +1,23 @@
1
- import { createSharedComposable, useLocalStorage } from '@vueuse/core'
1
+ import { createSharedComposable } from '@vueuse/core'
2
2
  import type { AccentColor } from '#layers/theme/app/types/theme'
3
3
 
4
4
  export const useAccentColor = createSharedComposable(() => {
5
5
  const appConfig = useAppConfig()
6
-
7
6
  const defaultAccent = (appConfig.themeLayer?.defaultAccent ?? 'blue') as AccentColor
8
- const accent = useLocalStorage<AccentColor>('theme-colour', defaultAccent)
7
+
8
+ // useState ensures server value is serialized into the Nuxt payload and reused
9
+ // during hydration, avoiding a mismatch with localStorage (client-only).
10
+ // theme.client.ts reads localStorage after hydration and calls setAccent.
11
+ const accent = useState<AccentColor>('theme-accent', () => defaultAccent)
9
12
 
10
13
  const pageAccent = ref<AccentColor | null>(null)
11
14
  const activeAccent = computed<AccentColor>(() => pageAccent.value ?? accent.value)
12
15
 
13
16
  function setAccent(color: AccentColor) {
14
17
  accent.value = color
18
+ if (import.meta.client) {
19
+ localStorage.setItem('theme-colour', color)
20
+ }
15
21
  }
16
22
 
17
23
  function setPageAccent(color: AccentColor | null) {
@@ -1,8 +1,8 @@
1
- import { createSharedComposable, useLocalStorage, usePreferredContrast } from '@vueuse/core'
1
+ import { createSharedComposable, usePreferredContrast } from '@vueuse/core'
2
2
  import type { PreferenceOverride } from '#layers/theme/app/types/theme'
3
3
 
4
4
  export const useThemeContrast = createSharedComposable(() => {
5
- const contrastOverride = useLocalStorage<PreferenceOverride>('theme-contrast', 'system')
5
+ const contrastOverride = useState<PreferenceOverride>('theme-contrast', () => 'system')
6
6
  const systemContrast = usePreferredContrast()
7
7
 
8
8
  const effectiveHighContrast = computed(() => {
@@ -13,6 +13,9 @@ export const useThemeContrast = createSharedComposable(() => {
13
13
 
14
14
  function setContrastOverride(value: PreferenceOverride) {
15
15
  contrastOverride.value = value
16
+ if (import.meta.client) {
17
+ localStorage.setItem('theme-contrast', value)
18
+ }
16
19
  }
17
20
 
18
21
  return {
@@ -1,8 +1,8 @@
1
- import { createSharedComposable, useLocalStorage, usePreferredReducedMotion } from '@vueuse/core'
1
+ import { createSharedComposable, usePreferredReducedMotion } from '@vueuse/core'
2
2
  import type { PreferenceOverride } from '#layers/theme/app/types/theme'
3
3
 
4
4
  export const useThemeMotion = createSharedComposable(() => {
5
- const motionOverride = useLocalStorage<PreferenceOverride>('theme-motion', 'system')
5
+ const motionOverride = useState<PreferenceOverride>('theme-motion', () => 'system')
6
6
  const systemMotion = usePreferredReducedMotion()
7
7
 
8
8
  const effectiveReducedMotion = computed(() => {
@@ -13,6 +13,9 @@ export const useThemeMotion = createSharedComposable(() => {
13
13
 
14
14
  function setMotionOverride(value: PreferenceOverride) {
15
15
  motionOverride.value = value
16
+ if (import.meta.client) {
17
+ localStorage.setItem('theme-motion', value)
18
+ }
16
19
  }
17
20
 
18
21
  return {
@@ -1,12 +1,11 @@
1
1
  import {
2
2
  createSharedComposable,
3
- useLocalStorage,
4
3
  usePreferredReducedTransparency,
5
4
  } from '@vueuse/core'
6
5
  import type { PreferenceOverride } from '#layers/theme/app/types/theme'
7
6
 
8
7
  export const useThemeTransparency = createSharedComposable(() => {
9
- const transparencyOverride = useLocalStorage<PreferenceOverride>('theme-transparency', 'system')
8
+ const transparencyOverride = useState<PreferenceOverride>('theme-transparency', () => 'system')
10
9
  const systemTransparency = usePreferredReducedTransparency()
11
10
 
12
11
  const effectiveReducedTransparency = computed(() => {
@@ -17,6 +16,9 @@ export const useThemeTransparency = createSharedComposable(() => {
17
16
 
18
17
  function setTransparencyOverride(value: PreferenceOverride) {
19
18
  transparencyOverride.value = value
19
+ if (import.meta.client) {
20
+ localStorage.setItem('theme-transparency', value)
21
+ }
20
22
  }
21
23
 
22
24
  return {
@@ -1,8 +1,25 @@
1
+ import type { AccentColor, PreferenceOverride } from '#layers/theme/app/types/theme'
2
+
1
3
  export default defineNuxtPlugin(() => {
2
- const { activeAccent } = useAccentColor()
3
- const { effectiveHighContrast } = useThemeContrast()
4
- const { effectiveReducedMotion } = useThemeMotion()
5
- const { effectiveReducedTransparency } = useThemeTransparency()
4
+ const { setAccent, activeAccent } = useAccentColor()
5
+ const { setContrastOverride, effectiveHighContrast } = useThemeContrast()
6
+ const { setMotionOverride, effectiveReducedMotion } = useThemeMotion()
7
+ const { setTransparencyOverride, effectiveReducedTransparency } = useThemeTransparency()
8
+
9
+ // Restore persisted preferences. useState defaults were serialized from the
10
+ // server, so hydration matches. We update to the stored values here, after
11
+ // hydration completes, to avoid any mismatch.
12
+ const storedAccent = localStorage.getItem('theme-colour')
13
+ if (storedAccent) setAccent(storedAccent as AccentColor)
14
+
15
+ const storedContrast = localStorage.getItem('theme-contrast')
16
+ if (storedContrast) setContrastOverride(storedContrast as PreferenceOverride)
17
+
18
+ const storedMotion = localStorage.getItem('theme-motion')
19
+ if (storedMotion) setMotionOverride(storedMotion as PreferenceOverride)
20
+
21
+ const storedTransparency = localStorage.getItem('theme-transparency')
22
+ if (storedTransparency) setTransparencyOverride(storedTransparency as PreferenceOverride)
6
23
 
7
24
  watch(activeAccent, (color) => {
8
25
  document.documentElement.setAttribute('data-theme-colour', color)
@@ -1,9 +1,13 @@
1
+ <script setup lang="ts">
2
+ const year = useState('footer-year', () => new Date().getFullYear())
3
+ </script>
4
+
1
5
  <template>
2
6
  <UFooter>
3
7
  <template #bottom>
4
8
  <div class="pt-10">
5
9
  <p class="text-center text-sm text-neutral-300">
6
- Copyright © {{ new Date().getFullYear() }}
10
+ Copyright © {{ year }}
7
11
  </p>
8
12
  </div>
9
13
  </template>
@@ -20,7 +20,7 @@ const radius = computed(() => (size - strokeWidth) / 2)
20
20
  const circumference = computed(() => 2 * Math.PI * radius.value)
21
21
  const strokeDasharray = computed(() => `${progress * circumference.value} ${circumference.value}`)
22
22
 
23
- const gradientId = `progress-circular-gradient-${Math.random().toString(36).slice(2, 9)}`
23
+ const gradientId = `progress-circular-gradient-${useId()}`
24
24
  </script>
25
25
 
26
26
  <template>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kmcom-nuxt-layers",
3
3
  "private": false,
4
- "version": "1.7.3",
4
+ "version": "1.7.5",
5
5
  "description": "Composable Nuxt 4 layers for building scalable Vue applications",
6
6
  "exports": {
7
7
  "./layers/core": "./layers/core/nuxt.config.ts",
@@ -140,7 +140,7 @@
140
140
  "eslint-plugin-prettier": "^5.5.6",
141
141
  "eslint-plugin-unicorn": "^64.0.0",
142
142
  "eslint-plugin-unused-imports": "^4.4.1",
143
- "eslint-plugin-vue": "^10.9.1",
143
+ "eslint-plugin-vue": "^10.9.2",
144
144
  "netlify-cli": "^26.1.0",
145
145
  "npm-check-updates": "^22.2.1",
146
146
  "nuxt": "^4.4.7",
@@ -1,18 +0,0 @@
1
- <script setup lang="ts">
2
- const { contentLayer } = useAppConfig()
3
- if (contentLayer?.sections?.gallery === false) {
4
- throw createError({ statusCode: 404, statusMessage: 'Not Found' })
5
- }
6
-
7
- const route = useRoute()
8
- const slug = route.params.slug as string
9
- const index = Number(route.params.imageId)
10
- </script>
11
-
12
- <template>
13
- <LayoutSection>
14
- <LayoutGridItem>
15
- <GalleryImageDetail :slug="slug" :index="index" />
16
- </LayoutGridItem>
17
- </LayoutSection>
18
- </template>
@@ -1,17 +0,0 @@
1
- <script setup lang="ts">
2
- const { contentLayer } = useAppConfig()
3
- if (contentLayer?.sections?.gallery === false) {
4
- throw createError({ statusCode: 404, statusMessage: 'Not Found' })
5
- }
6
-
7
- const route = useRoute()
8
- const slug = route.params.slug as string
9
- </script>
10
-
11
- <template>
12
- <LayoutSection>
13
- <LayoutGridItem>
14
- <GalleryDetail :slug="slug" />
15
- </LayoutGridItem>
16
- </LayoutSection>
17
- </template>
@@ -1,236 +0,0 @@
1
- <script setup lang="ts">
2
- const umainRef = ref()
3
- </script>
4
-
5
- <template>
6
- <MastMain :umain="umainRef">
7
- <UContainer class="py-12 space-y-12">
8
- <!-- Header Section -->
9
- <div class="space-y-4">
10
- <SiteTitle site-title="UI Layer" tag="h1" title-variant="default" />
11
- <Typography
12
- tag="p"
13
- weight="font-normal"
14
- leading="leading-relaxed"
15
- color="muted"
16
- class="text-lg"
17
- >
18
- A unified, typed design system for Nuxt applications. This layer provides typography,
19
- colors, media handling, and reusable UI primitives.
20
- </Typography>
21
- </div>
22
-
23
- <!-- Typography Section -->
24
- <section class="space-y-6">
25
- <TypographyHeadline :level="2" color="highlighted">
26
- Typography Components
27
- </TypographyHeadline>
28
-
29
- <div class="space-y-4">
30
- <div class="space-y-2">
31
- <TypographyHeadline :level="1"> Headline Level 1 </TypographyHeadline>
32
- <TypographyHeadline :level="2"> Headline Level 2 </TypographyHeadline>
33
- <TypographyHeadline :level="3"> Headline Level 3 </TypographyHeadline>
34
- <TypographyHeadline :level="4"> Headline Level 4 </TypographyHeadline>
35
- </div>
36
-
37
- <Typography tag="p" leading="leading-relaxed">
38
- The Typography component provides full control over font weight, width, slant, leading,
39
- tracking, alignment, and text transformation through typed props.
40
- </Typography>
41
-
42
- <TypographyCodeBlock language="typescript" color="muted">
43
- &lt;Typography weight="font-bold" leading="leading-tight" tracking="tracking-tight" &gt;
44
- Fully typed typography &lt;/Typography&gt;</TypographyCodeBlock
45
- >
46
- </div>
47
- </section>
48
-
49
- <!-- Color System Section -->
50
- <section class="space-y-6">
51
- <TypographyHeadline :level="2" color="highlighted"> Color System </TypographyHeadline>
52
-
53
- <div class="space-y-4">
54
- <div>
55
- <Typography tag="h3" weight="font-semibold" class="mb-2"> Semantic Colors </Typography>
56
- <div class="flex flex-wrap gap-2">
57
- <Typography
58
- color="dimmed"
59
- class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded"
60
- >
61
- Dimmed
62
- </Typography>
63
- <Typography
64
- color="muted"
65
- class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded"
66
- >
67
- Muted
68
- </Typography>
69
- <Typography
70
- color="toned"
71
- class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded"
72
- >
73
- Toned
74
- </Typography>
75
- <Typography
76
- color="highlighted"
77
- class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded"
78
- >
79
- Highlighted
80
- </Typography>
81
- </div>
82
- </div>
83
-
84
- <div>
85
- <Typography tag="h3" weight="font-semibold" class="mb-2"> Status Colors </Typography>
86
- <div class="flex flex-wrap gap-2">
87
- <Typography color="info" class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded">
88
- Info
89
- </Typography>
90
- <Typography
91
- color="success"
92
- class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded"
93
- >
94
- Success
95
- </Typography>
96
- <Typography
97
- color="warning"
98
- class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded"
99
- >
100
- Warning
101
- </Typography>
102
- <Typography
103
- color="error"
104
- class="px-3 py-2 bg-neutral-100 dark:bg-neutral-800 rounded"
105
- >
106
- Error
107
- </Typography>
108
- </div>
109
- </div>
110
- </div>
111
- </section>
112
-
113
- <!-- Components Section -->
114
- <section class="space-y-6">
115
- <TypographyHeadline :level="2" color="highlighted">
116
- Available Components
117
- </TypographyHeadline>
118
-
119
- <div class="grid md:grid-cols-2 gap-6">
120
- <UCard>
121
- <template #header>
122
- <TypographyHeadline :level="3"> Typography </TypographyHeadline>
123
- </template>
124
- <div class="space-y-2">
125
- <Typography tag="p" color="muted" leading="leading-relaxed">
126
- Base component with full control over font properties
127
- </Typography>
128
- <ul class="list-disc list-inside space-y-1 text-sm text-muted">
129
- <li>Typography (base)</li>
130
- <li>Headline (h1-h6)</li>
131
- <li>CodeBlock</li>
132
- <li>QuoteBlock</li>
133
- </ul>
134
- </div>
135
- </UCard>
136
-
137
- <UCard>
138
- <template #header>
139
- <TypographyHeadline :level="3"> Links </TypographyHeadline>
140
- </template>
141
- <div class="space-y-2">
142
- <Typography tag="p" color="muted" leading="leading-relaxed">
143
- Type-safe navigation with named routes
144
- </Typography>
145
- <ul class="list-disc list-inside space-y-1 text-sm text-muted">
146
- <li>Named route enforcement</li>
147
- <li>Color support</li>
148
- <li>ULink wrapper</li>
149
- </ul>
150
- </div>
151
- </UCard>
152
-
153
- <UCard>
154
- <template #header>
155
- <TypographyHeadline :level="3"> Media </TypographyHeadline>
156
- </template>
157
- <div class="space-y-2">
158
- <Typography tag="p" color="muted" leading="leading-relaxed">
159
- Responsive image handling with optimization
160
- </Typography>
161
- <ul class="list-disc list-inside space-y-1 text-sm text-muted">
162
- <li>Picture component</li>
163
- <li>Multiple formats (avif, webp)</li>
164
- <li>Responsive sizing</li>
165
- <li>Lazy loading</li>
166
- </ul>
167
- </div>
168
- </UCard>
169
-
170
- <UCard>
171
- <template #header>
172
- <TypographyHeadline :level="3"> Branding </TypographyHeadline>
173
- </template>
174
- <div class="space-y-2">
175
- <Typography tag="p" color="muted" leading="leading-relaxed">
176
- Site branding and structure components
177
- </Typography>
178
- <ul class="list-disc list-inside space-y-1 text-sm text-muted">
179
- <li>Masthead/Main wrapper</li>
180
- <li>Site Title with variants</li>
181
- <li>Semantic HTML structure</li>
182
- </ul>
183
- </div>
184
- </UCard>
185
- </div>
186
- </section>
187
-
188
- <!-- Quote Example -->
189
- <section class="space-y-6">
190
- <TypographyHeadline :level="2" color="highlighted"> Quote Block </TypographyHeadline>
191
-
192
- <TypographyQuoteBlock color="muted" class="border-l-4 border-primary pl-4 italic">
193
- A unified, typed design system that provides consistency across projects while maintaining
194
- flexibility for customization.
195
- </TypographyQuoteBlock>
196
- </section>
197
-
198
- <!-- Features List -->
199
- <section class="space-y-6">
200
- <TypographyHeadline :level="2" color="highlighted"> Key Features </TypographyHeadline>
201
-
202
- <div class="grid md:grid-cols-3 gap-4">
203
- <div class="space-y-2">
204
- <Typography weight="font-semibold" color="primary"> Fully Typed </Typography>
205
- <Typography tag="p" color="muted" leading="leading-relaxed" class="text-sm">
206
- Complete TypeScript coverage with semantic types for typography, colors, and
207
- breakpoints
208
- </Typography>
209
- </div>
210
-
211
- <div class="space-y-2">
212
- <Typography weight="font-semibold" color="primary"> Composable First </Typography>
213
- <Typography tag="p" color="muted" leading="leading-relaxed" class="text-sm">
214
- Built on Vue composables (useTypography, useColor, usePicture) for maximum reusability
215
- </Typography>
216
- </div>
217
-
218
- <div class="space-y-2">
219
- <Typography weight="font-semibold" color="primary"> Responsive Ready </Typography>
220
- <Typography tag="p" color="muted" leading="leading-relaxed" class="text-sm">
221
- Comprehensive breakpoint system supporting Tailwind, device, phone, and tablet
222
- breakpoints
223
- </Typography>
224
- </div>
225
- </div>
226
- </section>
227
-
228
- <!-- Footer -->
229
- <footer class="pt-8 border-t border-neutral-200 dark:border-neutral-800">
230
- <Typography tag="p" color="dimmed" align="center" class="text-sm">
231
- UI Layer - A reusable design system for Nuxt
232
- </Typography>
233
- </footer>
234
- </UContainer>
235
- </MastMain>
236
- </template>