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.
- package/layers/content/app/components/Blog/Article.vue +1 -1
- package/layers/content/app/components/Gallery/ImagePage.vue +19 -0
- package/layers/content/app/{pages/gallery/index.vue → components/Gallery/Page.vue} +8 -8
- package/layers/content/app/components/Gallery/SlugPage.vue +18 -0
- package/layers/core/app/{pages/diagnostics.vue → components/DiagnosticsPage.vue} +6 -8
- package/layers/motion/app/components/Motion/ScrollProgress.vue +4 -1
- package/layers/shader/app/components/Shader/Pipeline.client.vue +8 -10
- package/layers/theme/app/composables/useAccentColor.ts +9 -3
- package/layers/theme/app/composables/useThemeContrast.ts +5 -2
- package/layers/theme/app/composables/useThemeMotion.ts +5 -2
- package/layers/theme/app/composables/useThemeTransparency.ts +4 -2
- package/layers/theme/app/plugins/theme.client.ts +21 -4
- package/layers/ui/app/components/Mast/Footer.vue +5 -1
- package/layers/ui/app/components/Progress/Circular.vue +1 -1
- package/package.json +2 -2
- package/layers/content/app/pages/gallery/[slug]/[imageId].vue +0 -18
- package/layers/content/app/pages/gallery/[slug]/index.vue +0 -17
- package/layers/ui/app/pages/index.vue +0 -236
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
const { contentLayer } = useAppConfig()
|
|
3
|
+
if (contentLayer?.sections?.gallery === false) {
|
|
4
|
+
throw createError({ statusCode: 404, statusMessage: 'Not Found' })
|
|
5
|
+
}
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 © {{
|
|
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-${
|
|
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.
|
|
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.
|
|
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
|
-
<Typography weight="font-bold" leading="leading-tight" tracking="tracking-tight" >
|
|
44
|
-
Fully typed typography </Typography></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>
|