kmcom-nuxt-layers 1.6.17 → 1.6.20
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 +9 -5
- package/layers/content/app/components/Blog/Card.vue +11 -8
- package/layers/content/app/components/Blog/List.vue +12 -11
- package/layers/content/app/components/Gallery/Card.vue +6 -1
- package/layers/content/app/components/Gallery/Detail.vue +10 -6
- package/layers/content/app/components/Gallery/ImageDetail.vue +9 -3
- package/layers/content/app/components/NuxtContent/Detail.vue +7 -3
- package/layers/content/app/components/NuxtContent/Toc.vue +3 -1
- package/layers/content/app/components/Portfolio/Card.vue +5 -1
- package/layers/content/app/components/Portfolio/Detail.vue +32 -11
- package/layers/content/app/components/Portfolio/List.vue +4 -2
- package/layers/content/app/composables/useCollectionItem.ts +3 -1
- package/layers/content/app/composables/useCollectionSurround.ts +4 -6
- package/layers/content/app/types/content.ts +1 -1
- package/layers/content/package.json +1 -0
- package/layers/core/app/app.vue +1 -0
- package/layers/core/app/composables/useCache.ts +7 -8
- package/layers/core/app/composables/useScrollGuard.ts +0 -12
- package/layers/core/app/plugins/init.ts +4 -3
- package/layers/core/app/plugins/loading.client.ts +0 -2
- package/layers/core/app/plugins/scroll-guard.client.ts +0 -2
- package/layers/core/package.json +1 -0
- package/layers/core/tsconfig.json +2 -1
- package/layers/forms/app/components/Form/Contact.vue +1 -5
- package/layers/forms/app/components/Form/Field.vue +34 -22
- package/layers/forms/package.json +1 -0
- package/layers/layout/app/components/Layout/Page/Container.vue +7 -1
- package/layers/layout/app/components/Layout/Page/index.vue +4 -1
- package/layers/layout/package.json +1 -0
- package/layers/motion/app/components/Motion/Marquee.vue +12 -16
- package/layers/motion/app/components/Motion/Parallax.vue +1 -1
- package/layers/motion/app/components/Motion/Staggered.vue +1 -1
- package/layers/motion/app/components/Motion/Transition.vue +0 -13
- package/layers/motion/app/composables/useSmoothScroll.ts +1 -1
- package/layers/motion/package.json +1 -0
- package/layers/routing/app/middleware/02.governance.global.ts +2 -0
- package/layers/routing/app/plugins/feature-flags.client.ts +1 -0
- package/layers/routing/nuxt.config.ts +8 -4
- package/layers/routing/package.json +4 -1
- package/layers/shader/app/composables/useShader.ts +1 -1
- package/layers/shader/app/utils/tsl/noise.ts +0 -5
- package/layers/shader/nuxt.config.ts +1 -1
- package/layers/shader/package.json +3 -0
- package/layers/theme/app/plugins/theme.client.ts +0 -3
- package/layers/theme/package.json +1 -0
- package/layers/ui/app/app.config.ts +5 -0
- package/layers/ui/app/components/Accent/Scene.vue +14 -1
- package/layers/ui/app/components/Progress/Bar.vue +11 -1
- package/layers/ui/app/components/Typography/CodeBlock.vue +5 -4
- package/layers/ui/app/components/Typography/Headline.vue +11 -3
- package/layers/ui/app/components/Typography/QuoteBlock.vue +5 -1
- package/layers/ui/app/components/Typography/index.vue +1 -1
- package/layers/ui/app/composables/useSite.ts +6 -6
- package/layers/ui/app/types/accent.ts +1 -1
- package/layers/ui/app/types/app-config.d.ts +5 -0
- package/layers/ui/app/utils/createModal.ts +4 -3
- package/layers/ui/package.json +1 -0
- package/package.json +8 -8
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { BlogCollectionItem } from '@nuxt/content'
|
|
3
|
+
|
|
2
4
|
const { slug } = defineProps<{
|
|
3
5
|
slug: string
|
|
4
6
|
}>()
|
|
7
|
+
|
|
8
|
+
const asBlog = (item: unknown) => item as BlogCollectionItem
|
|
5
9
|
</script>
|
|
6
10
|
|
|
7
11
|
<template>
|
|
8
12
|
<NuxtContentDetail collection="blog" :slug not-found-message="Blog post not found">
|
|
9
13
|
<template #headline="{ item }">
|
|
10
14
|
<div class="flex items-center gap-3 text-sm text-muted">
|
|
11
|
-
<time v-if="item.date">{{ new Date(item.date).toLocaleDateString() }}</time>
|
|
12
|
-
<UBadge v-if="item.badge" color="primary" variant="subtle">
|
|
13
|
-
{{ item.badge }}
|
|
15
|
+
<time v-if="asBlog(item).date">{{ new Date(asBlog(item).date).toLocaleDateString() }}</time>
|
|
16
|
+
<UBadge v-if="asBlog(item).badge" color="primary" variant="subtle">
|
|
17
|
+
{{ asBlog(item).badge }}
|
|
14
18
|
</UBadge>
|
|
15
19
|
</div>
|
|
16
20
|
</template>
|
|
17
21
|
|
|
18
22
|
<template #after-content="{ item }">
|
|
19
|
-
<template v-if="item.tags?.length">
|
|
23
|
+
<template v-if="asBlog(item).tags?.length">
|
|
20
24
|
<USeparator class="my-8" />
|
|
21
25
|
<div class="flex flex-wrap gap-2">
|
|
22
|
-
<UBadge v-for="tag in item.tags" :key="tag" color="neutral" variant="subtle">
|
|
26
|
+
<UBadge v-for="tag in asBlog(item).tags" :key="tag" color="neutral" variant="subtle">
|
|
23
27
|
{{ tag }}
|
|
24
28
|
</UBadge>
|
|
25
29
|
</div>
|
|
@@ -17,24 +17,27 @@ const {
|
|
|
17
17
|
authors?: { name: string; avatar?: string; url?: string }[]
|
|
18
18
|
to?: string
|
|
19
19
|
}>()
|
|
20
|
+
|
|
21
|
+
const postProps = computed(() => ({
|
|
22
|
+
...(description !== undefined && { description }),
|
|
23
|
+
...(date !== undefined && { date }),
|
|
24
|
+
...(image !== undefined && { image }),
|
|
25
|
+
...(badge !== undefined && { badge }),
|
|
26
|
+
...(to !== undefined && { to }),
|
|
27
|
+
}))
|
|
20
28
|
</script>
|
|
21
29
|
|
|
22
30
|
<template>
|
|
23
31
|
<UBlogPost
|
|
24
32
|
:title
|
|
25
|
-
|
|
26
|
-
:date
|
|
27
|
-
:image
|
|
28
|
-
:badge
|
|
33
|
+
v-bind="postProps"
|
|
29
34
|
:authors="
|
|
30
35
|
authors.map((a) => ({
|
|
31
36
|
name: a.name,
|
|
32
|
-
|
|
33
|
-
to: a.url,
|
|
34
|
-
target: a.url ? '_blank' : undefined,
|
|
37
|
+
...(a.avatar && { avatar: { src: a.avatar } }),
|
|
38
|
+
...(a.url && { to: a.url, target: '_blank' as const }),
|
|
35
39
|
}))
|
|
36
40
|
"
|
|
37
|
-
:to
|
|
38
41
|
variant="outline"
|
|
39
42
|
/>
|
|
40
43
|
</template>
|
|
@@ -19,20 +19,21 @@ const { data: posts, status } = await useBlogPosts(options)
|
|
|
19
19
|
v-for="post in posts"
|
|
20
20
|
:key="post.id"
|
|
21
21
|
:title="post.title"
|
|
22
|
-
:description="post.description"
|
|
23
22
|
:date="post.date"
|
|
24
|
-
:image="post.image"
|
|
25
|
-
:badge="post.badge"
|
|
26
|
-
:authors="
|
|
27
|
-
post.authors?.map((a) => ({
|
|
28
|
-
name: a.name,
|
|
29
|
-
avatar: a.avatar ? { src: a.avatar } : undefined,
|
|
30
|
-
to: a.url,
|
|
31
|
-
target: a.url ? '_blank' : undefined,
|
|
32
|
-
}))
|
|
33
|
-
"
|
|
34
23
|
:to="post.path"
|
|
35
24
|
variant="outline"
|
|
25
|
+
v-bind="{
|
|
26
|
+
...(post.description !== undefined && { description: post.description }),
|
|
27
|
+
...(post.image !== undefined && { image: post.image }),
|
|
28
|
+
...(post.badge !== undefined && { badge: post.badge }),
|
|
29
|
+
...(post.authors && {
|
|
30
|
+
authors: post.authors.map((a) => ({
|
|
31
|
+
name: a.name,
|
|
32
|
+
...(a.avatar && { avatar: { src: a.avatar } }),
|
|
33
|
+
...(a.url && { to: a.url, target: '_blank' as const }),
|
|
34
|
+
})),
|
|
35
|
+
}),
|
|
36
|
+
}"
|
|
36
37
|
/>
|
|
37
38
|
</UBlogPosts>
|
|
38
39
|
</NuxtContentList>
|
|
@@ -15,10 +15,15 @@ const {
|
|
|
15
15
|
tags?: string[]
|
|
16
16
|
to?: string
|
|
17
17
|
}>()
|
|
18
|
+
|
|
19
|
+
const cardProps = computed(() => ({
|
|
20
|
+
...(description !== undefined && { description }),
|
|
21
|
+
...(to !== undefined && { to }),
|
|
22
|
+
}))
|
|
18
23
|
</script>
|
|
19
24
|
|
|
20
25
|
<template>
|
|
21
|
-
<UPageCard :title
|
|
26
|
+
<UPageCard :title v-bind="cardProps" variant="outline">
|
|
22
27
|
<img
|
|
23
28
|
v-if="coverImage"
|
|
24
29
|
:src="coverImage.src"
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { GalleryCollectionItem } from '@nuxt/content'
|
|
3
|
+
|
|
2
4
|
const { slug } = defineProps<{
|
|
3
5
|
slug: string
|
|
4
6
|
}>()
|
|
@@ -7,6 +9,8 @@ const lightboxOpen = ref(false)
|
|
|
7
9
|
const lightboxIndex = ref(0)
|
|
8
10
|
const lightboxImages = ref<{ src: string; alt: string; width?: number; height?: number }[]>([])
|
|
9
11
|
|
|
12
|
+
const asGallery = (item: unknown) => item as GalleryCollectionItem
|
|
13
|
+
|
|
10
14
|
function openLightbox(
|
|
11
15
|
images: { src: string; alt: string; width?: number; height?: number }[],
|
|
12
16
|
index: number
|
|
@@ -21,21 +25,21 @@ function openLightbox(
|
|
|
21
25
|
<NuxtContentDetail collection="gallery" :slug not-found-message="Gallery not found">
|
|
22
26
|
<template #headline="{ item }">
|
|
23
27
|
<div class="flex flex-wrap items-center gap-2">
|
|
24
|
-
<span v-if="item.images?.length" class="text-sm text-muted">
|
|
25
|
-
{{ item.images
|
|
28
|
+
<span v-if="asGallery(item).images?.length" class="text-sm text-muted">
|
|
29
|
+
{{ asGallery(item).images!.length }} image{{ asGallery(item).images!.length === 1 ? '' : 's' }}
|
|
26
30
|
</span>
|
|
27
|
-
<UBadge v-for="tag in item.tags" :key="tag" color="neutral" variant="subtle" size="xs">
|
|
31
|
+
<UBadge v-for="tag in asGallery(item).tags" :key="tag" color="neutral" variant="subtle" size="xs">
|
|
28
32
|
{{ tag }}
|
|
29
33
|
</UBadge>
|
|
30
34
|
</div>
|
|
31
35
|
</template>
|
|
32
36
|
|
|
33
37
|
<template #after-content="{ item }">
|
|
34
|
-
<template v-if="item.images?.length">
|
|
38
|
+
<template v-if="asGallery(item).images?.length">
|
|
35
39
|
<USeparator class="my-8" />
|
|
36
40
|
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
|
37
41
|
<div
|
|
38
|
-
v-for="(img, idx) in item.images"
|
|
42
|
+
v-for="(img, idx) in asGallery(item).images"
|
|
39
43
|
:key="img.src"
|
|
40
44
|
class="overflow-hidden rounded-lg group relative"
|
|
41
45
|
>
|
|
@@ -55,7 +59,7 @@ function openLightbox(
|
|
|
55
59
|
</NuxtLink>
|
|
56
60
|
<button
|
|
57
61
|
class="absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity duration-300 bg-black/50 hover:bg-black/70 text-white rounded-full p-1.5 cursor-pointer"
|
|
58
|
-
@click.stop="openLightbox(item.images
|
|
62
|
+
@click.stop="openLightbox(asGallery(item).images!, idx)"
|
|
59
63
|
>
|
|
60
64
|
<UIcon name="i-lucide-expand" class="size-4" />
|
|
61
65
|
</button>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { GalleryCollectionItem } from '@nuxt/content'
|
|
3
|
+
|
|
2
4
|
const { slug, index } = defineProps<{
|
|
3
5
|
slug: string
|
|
4
6
|
index: number
|
|
5
7
|
}>()
|
|
6
8
|
|
|
7
|
-
const { data:
|
|
9
|
+
const { data: rawItem } = await useCollectionItem('gallery', slug)
|
|
10
|
+
const item = computed(() => rawItem.value as GalleryCollectionItem | null)
|
|
8
11
|
|
|
9
12
|
const image = computed(() => item.value?.images?.[index])
|
|
10
13
|
const totalImages = computed(() => item.value?.images?.length ?? 0)
|
|
@@ -19,8 +22,11 @@ useSeoMeta({
|
|
|
19
22
|
</script>
|
|
20
23
|
|
|
21
24
|
<template>
|
|
22
|
-
<div v-if="item && image">
|
|
23
|
-
<UPageHeader
|
|
25
|
+
<div v-if="item && item.images && image">
|
|
26
|
+
<UPageHeader
|
|
27
|
+
:title="image.title || image.alt"
|
|
28
|
+
v-bind="image.caption ? { description: image.caption } : {}"
|
|
29
|
+
>
|
|
24
30
|
<template #headline>
|
|
25
31
|
<UBreadcrumb
|
|
26
32
|
:items="[
|
|
@@ -15,10 +15,14 @@ const {
|
|
|
15
15
|
const { data: item, status } = await useCollectionItem(collection, slug)
|
|
16
16
|
const { data: surround } = await useCollectionSurround(collection, slug)
|
|
17
17
|
|
|
18
|
+
const itemImage = computed(
|
|
19
|
+
() => (item.value as { image?: string } | null)?.image
|
|
20
|
+
)
|
|
21
|
+
|
|
18
22
|
useSeoMeta({
|
|
19
23
|
title: item.value?.title,
|
|
20
24
|
description: item.value?.description,
|
|
21
|
-
ogImage:
|
|
25
|
+
ogImage: itemImage,
|
|
22
26
|
})
|
|
23
27
|
</script>
|
|
24
28
|
|
|
@@ -26,7 +30,7 @@ useSeoMeta({
|
|
|
26
30
|
<div>
|
|
27
31
|
<USkeleton v-if="status === 'pending'" class="h-96 w-full" />
|
|
28
32
|
<UPage v-else-if="item">
|
|
29
|
-
<UPageHeader :title="item.title"
|
|
33
|
+
<UPageHeader :title="item.title" v-bind="item.description ? { description: item.description } : {}">
|
|
30
34
|
<template v-if="$slots.headline" #headline>
|
|
31
35
|
<slot name="headline" :item="item" />
|
|
32
36
|
</template>
|
|
@@ -45,7 +49,7 @@ useSeoMeta({
|
|
|
45
49
|
</UPageBody>
|
|
46
50
|
|
|
47
51
|
<template v-if="!hideToc" #right>
|
|
48
|
-
<NuxtContentToc
|
|
52
|
+
<NuxtContentToc v-bind="item.body?.toc?.links ? { links: item.body.toc.links } : {}" />
|
|
49
53
|
</template>
|
|
50
54
|
</UPage>
|
|
51
55
|
<div v-else class="text-muted text-center py-12">{{ notFoundMessage }}</div>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<!-- eslint-disable vue/require-default-prop -->
|
|
2
2
|
<script setup lang="ts">
|
|
3
|
+
import type { TocLink } from '@nuxt/content'
|
|
4
|
+
|
|
3
5
|
const { links, title = 'Table of Contents' } = defineProps<{
|
|
4
|
-
links?:
|
|
6
|
+
links?: TocLink[]
|
|
5
7
|
title?: string
|
|
6
8
|
}>()
|
|
7
9
|
</script>
|
|
@@ -20,7 +20,11 @@ const {
|
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
22
|
<template>
|
|
23
|
-
<UPageCard
|
|
23
|
+
<UPageCard
|
|
24
|
+
:title
|
|
25
|
+
variant="outline"
|
|
26
|
+
v-bind="{ ...(description !== undefined && { description }), ...(to !== undefined && { to }) }"
|
|
27
|
+
>
|
|
24
28
|
<img v-if="image" :src="image" :alt="title" class="w-full h-48 object-cover rounded" />
|
|
25
29
|
<template #footer>
|
|
26
30
|
<div class="flex flex-wrap gap-1.5">
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { PortfolioCollectionItem } from '@nuxt/content'
|
|
3
|
+
|
|
2
4
|
const { slug } = defineProps<{
|
|
3
5
|
slug: string
|
|
4
6
|
}>()
|
|
7
|
+
|
|
8
|
+
const asPortfolio = (item: unknown) => item as PortfolioCollectionItem
|
|
5
9
|
</script>
|
|
6
10
|
|
|
7
11
|
<template>
|
|
@@ -13,13 +17,19 @@ const { slug } = defineProps<{
|
|
|
13
17
|
>
|
|
14
18
|
<template #headline="{ item }">
|
|
15
19
|
<div class="flex flex-wrap items-center gap-2">
|
|
16
|
-
<UBadge v-if="item.client" color="primary" variant="subtle">
|
|
17
|
-
{{ item.client }}
|
|
20
|
+
<UBadge v-if="asPortfolio(item).client" color="primary" variant="subtle">
|
|
21
|
+
{{ asPortfolio(item).client }}
|
|
18
22
|
</UBadge>
|
|
19
|
-
<UBadge v-if="item.year" color="neutral" variant="subtle">
|
|
20
|
-
{{ item.year }}
|
|
23
|
+
<UBadge v-if="asPortfolio(item).year" color="neutral" variant="subtle">
|
|
24
|
+
{{ asPortfolio(item).year }}
|
|
21
25
|
</UBadge>
|
|
22
|
-
<UBadge
|
|
26
|
+
<UBadge
|
|
27
|
+
v-for="tag in asPortfolio(item).tags"
|
|
28
|
+
:key="tag"
|
|
29
|
+
color="neutral"
|
|
30
|
+
variant="subtle"
|
|
31
|
+
size="xs"
|
|
32
|
+
>
|
|
23
33
|
{{ tag }}
|
|
24
34
|
</UBadge>
|
|
25
35
|
</div>
|
|
@@ -27,8 +37,8 @@ const { slug } = defineProps<{
|
|
|
27
37
|
|
|
28
38
|
<template #links="{ item }">
|
|
29
39
|
<UButton
|
|
30
|
-
v-if="item.url"
|
|
31
|
-
:to="item.url"
|
|
40
|
+
v-if="asPortfolio(item).url"
|
|
41
|
+
:to="asPortfolio(item).url"
|
|
32
42
|
target="_blank"
|
|
33
43
|
icon="i-lucide-external-link"
|
|
34
44
|
variant="outline"
|
|
@@ -38,15 +48,26 @@ const { slug } = defineProps<{
|
|
|
38
48
|
</template>
|
|
39
49
|
|
|
40
50
|
<template #before-content="{ item }">
|
|
41
|
-
<img
|
|
51
|
+
<img
|
|
52
|
+
v-if="asPortfolio(item).image"
|
|
53
|
+
:src="asPortfolio(item).image"
|
|
54
|
+
:alt="item.title"
|
|
55
|
+
class="w-full rounded-lg mb-8"
|
|
56
|
+
/>
|
|
42
57
|
</template>
|
|
43
58
|
|
|
44
59
|
<template #after-content="{ item }">
|
|
45
|
-
<template v-if="item.colors?.length || item.typography?.length">
|
|
60
|
+
<template v-if="asPortfolio(item).colors?.length || asPortfolio(item).typography?.length">
|
|
46
61
|
<USeparator class="my-8" />
|
|
47
62
|
<div class="space-y-8">
|
|
48
|
-
<PortfolioColorPalette
|
|
49
|
-
|
|
63
|
+
<PortfolioColorPalette
|
|
64
|
+
v-if="asPortfolio(item).colors?.length"
|
|
65
|
+
:colors="asPortfolio(item).colors!"
|
|
66
|
+
/>
|
|
67
|
+
<PortfolioTypography
|
|
68
|
+
v-if="asPortfolio(item).typography?.length"
|
|
69
|
+
:typography="asPortfolio(item).typography!"
|
|
70
|
+
/>
|
|
50
71
|
</div>
|
|
51
72
|
</template>
|
|
52
73
|
</template>
|
|
@@ -19,9 +19,11 @@ const { data: items, status } = await usePortfolioItems(options)
|
|
|
19
19
|
v-for="item in items"
|
|
20
20
|
:key="item.id"
|
|
21
21
|
:title="item.title"
|
|
22
|
-
:description="item.description"
|
|
23
|
-
:to="item.path"
|
|
24
22
|
variant="outline"
|
|
23
|
+
v-bind="{
|
|
24
|
+
...(item.description !== undefined && { description: item.description }),
|
|
25
|
+
to: item.path,
|
|
26
|
+
}"
|
|
25
27
|
>
|
|
26
28
|
<img
|
|
27
29
|
v-if="item.image"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { Collections } from '@nuxt/content'
|
|
2
|
+
|
|
1
3
|
export function useCollectionItem(collection: string, slug: string) {
|
|
2
4
|
return useContentData(`${collection}-${slug}`, () =>
|
|
3
|
-
queryCollection(collection).path(`/${collection}/${slug}`).first()
|
|
5
|
+
queryCollection(collection as keyof Collections).path(`/${collection}/${slug}`).first()
|
|
4
6
|
)
|
|
5
7
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
fields: string[] = ['description']
|
|
5
|
-
) {
|
|
1
|
+
import type { PageCollections } from '@nuxt/content'
|
|
2
|
+
|
|
3
|
+
export function useCollectionSurround(collection: string, slug: string) {
|
|
6
4
|
return useContentData(`${collection}-${slug}-surround`, () =>
|
|
7
|
-
queryCollectionItemSurroundings(collection, `/${collection}/${slug}
|
|
5
|
+
queryCollectionItemSurroundings(collection as keyof PageCollections, `/${collection}/${slug}`)
|
|
8
6
|
)
|
|
9
7
|
}
|
package/layers/core/app/app.vue
CHANGED
|
@@ -78,15 +78,14 @@ export function useCache() {
|
|
|
78
78
|
|
|
79
79
|
try {
|
|
80
80
|
const cacheNames = await caches.keys()
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
: ''
|
|
81
|
+
await Promise.all(cacheNames.map((name) => caches.delete(name)))
|
|
82
|
+
if (process.env.NODE_ENV === 'development') {
|
|
83
|
+
console.log('[useCache] All caches cleared')
|
|
84
|
+
}
|
|
86
85
|
} catch (error) {
|
|
87
|
-
process.env.NODE_ENV === 'development'
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
if (process.env.NODE_ENV === 'development') {
|
|
87
|
+
console.error('[useCache] Failed to clear cache:', error)
|
|
88
|
+
}
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
|
|
@@ -77,18 +77,6 @@ function clampElement(el: HTMLElement) {
|
|
|
77
77
|
clampedCount.value++
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function restoreElement(el: HTMLElement) {
|
|
81
|
-
const saved = clampedElements.get(el)
|
|
82
|
-
if (!saved) return
|
|
83
|
-
|
|
84
|
-
el.style.transition = saved.transition
|
|
85
|
-
el.style.maxWidth = saved.maxWidth
|
|
86
|
-
el.style.boxSizing = saved.boxSizing
|
|
87
|
-
el.style.overflowX = saved.overflowX
|
|
88
|
-
|
|
89
|
-
clampedElements.delete(el)
|
|
90
|
-
clampedSet.delete(el)
|
|
91
|
-
}
|
|
92
80
|
|
|
93
81
|
function guard() {
|
|
94
82
|
if (!isEnabled.value || !opts) return
|
|
@@ -130,13 +130,14 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
// Test environment access (works on both server and client)
|
|
133
|
-
const env = useEnv()
|
|
133
|
+
const env = useEnv() as unknown as Record<string, unknown>
|
|
134
134
|
|
|
135
135
|
if (isDev) {
|
|
136
|
+
const publicConfig = env.public as Record<string, unknown> | undefined
|
|
136
137
|
// eslint-disable-next-line no-console
|
|
137
138
|
console.log('[Core Layer] Environment config loaded:', {
|
|
138
|
-
hasPublicConfig: !!
|
|
139
|
-
publicKeys: Object.keys(
|
|
139
|
+
hasPublicConfig: !!publicConfig,
|
|
140
|
+
publicKeys: Object.keys(publicConfig ?? {}),
|
|
140
141
|
})
|
|
141
142
|
}
|
|
142
143
|
} catch (error) {
|
|
@@ -29,8 +29,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
29
29
|
|
|
30
30
|
// console.log('[Loading Plugin] Config:', coreLayer?.loading)
|
|
31
31
|
|
|
32
|
-
if ((config.layers as Record<string, boolean> | undefined)?.core === false) return
|
|
33
|
-
|
|
34
32
|
// Check if loading is enabled
|
|
35
33
|
if (coreLayer?.loading?.enabled === false) {
|
|
36
34
|
// console.log('[Loading Plugin] Disabled')
|
|
@@ -24,8 +24,6 @@ export default defineNuxtPlugin(() => {
|
|
|
24
24
|
const config = useAppConfig()
|
|
25
25
|
const coreLayer = config.coreLayer as CoreLayerConfig | undefined
|
|
26
26
|
|
|
27
|
-
if ((config.layers as Record<string, boolean> | undefined)?.core === false) return
|
|
28
|
-
|
|
29
27
|
if (coreLayer?.scrollGuard?.enabled === false) {
|
|
30
28
|
if (import.meta.dev) {
|
|
31
29
|
// eslint-disable-next-line no-console
|
package/layers/core/package.json
CHANGED
|
@@ -17,11 +17,7 @@ const schema = z.object({
|
|
|
17
17
|
|
|
18
18
|
type FormState = z.infer<typeof schema>
|
|
19
19
|
|
|
20
|
-
const state = reactive
|
|
21
|
-
name: undefined,
|
|
22
|
-
email: undefined,
|
|
23
|
-
message: undefined,
|
|
24
|
-
})
|
|
20
|
+
const state = reactive({ name: '', email: '', message: '' })
|
|
25
21
|
|
|
26
22
|
const toast = useToast()
|
|
27
23
|
const isLoading = ref(false)
|
|
@@ -41,6 +41,36 @@ const resolvedIcon = computed(() => icon ?? config.value.icon)
|
|
|
41
41
|
const isTextarea = computed(() => config.value.component === 'UTextarea')
|
|
42
42
|
const isNumber = computed(() => config.value.component === 'UInputNumber')
|
|
43
43
|
|
|
44
|
+
const formFieldProps = computed(() => ({
|
|
45
|
+
name,
|
|
46
|
+
required,
|
|
47
|
+
size,
|
|
48
|
+
...(label !== undefined && { label }),
|
|
49
|
+
...(className !== undefined && { class: className }),
|
|
50
|
+
}))
|
|
51
|
+
|
|
52
|
+
const baseInputProps = computed(() => ({
|
|
53
|
+
size,
|
|
54
|
+
...(resolvedPlaceholder.value !== undefined && { placeholder: resolvedPlaceholder.value }),
|
|
55
|
+
...(resolvedIcon.value !== undefined && { leadingIcon: resolvedIcon.value }),
|
|
56
|
+
}))
|
|
57
|
+
|
|
58
|
+
const numberInputProps = computed(() => ({
|
|
59
|
+
size,
|
|
60
|
+
...(resolvedPlaceholder.value !== undefined && { placeholder: resolvedPlaceholder.value }),
|
|
61
|
+
...(resolvedIcon.value !== undefined && { leadingIcon: resolvedIcon.value }),
|
|
62
|
+
...(currencyOptions.value !== undefined && { formatOptions: currencyOptions.value }),
|
|
63
|
+
}))
|
|
64
|
+
|
|
65
|
+
const textInputProps = computed(() => ({
|
|
66
|
+
type: config.value.inputType,
|
|
67
|
+
size,
|
|
68
|
+
...(config.value.inputMode !== undefined && { inputmode: config.value.inputMode }),
|
|
69
|
+
...(config.value.autocomplete !== undefined && { autocomplete: config.value.autocomplete }),
|
|
70
|
+
...(resolvedPlaceholder.value !== undefined && { placeholder: resolvedPlaceholder.value }),
|
|
71
|
+
...(resolvedIcon.value !== undefined && { leadingIcon: resolvedIcon.value }),
|
|
72
|
+
}))
|
|
73
|
+
|
|
44
74
|
const currencyOptions = computed((): Intl.NumberFormatOptions | undefined => {
|
|
45
75
|
if (config.value.format === 'currency') {
|
|
46
76
|
return {
|
|
@@ -53,33 +83,15 @@ const currencyOptions = computed((): Intl.NumberFormatOptions | undefined => {
|
|
|
53
83
|
</script>
|
|
54
84
|
|
|
55
85
|
<template>
|
|
56
|
-
<UFormField
|
|
57
|
-
<UTextarea
|
|
58
|
-
v-if="isTextarea"
|
|
59
|
-
v-model="model as string"
|
|
60
|
-
:placeholder="resolvedPlaceholder"
|
|
61
|
-
:size
|
|
62
|
-
autoresize
|
|
63
|
-
/>
|
|
86
|
+
<UFormField v-bind="formFieldProps">
|
|
87
|
+
<UTextarea v-if="isTextarea" v-model="model as string" autoresize v-bind="baseInputProps" />
|
|
64
88
|
|
|
65
89
|
<UInputNumber
|
|
66
90
|
v-else-if="isNumber"
|
|
67
91
|
v-model="model as number"
|
|
68
|
-
|
|
69
|
-
:leading-icon="resolvedIcon"
|
|
70
|
-
:size
|
|
71
|
-
:format-options="currencyOptions"
|
|
92
|
+
v-bind="numberInputProps"
|
|
72
93
|
/>
|
|
73
94
|
|
|
74
|
-
<UInput
|
|
75
|
-
v-else
|
|
76
|
-
v-model="model as string"
|
|
77
|
-
:type="config.inputType"
|
|
78
|
-
:inputmode="config.inputMode"
|
|
79
|
-
:autocomplete="config.autocomplete"
|
|
80
|
-
:placeholder="resolvedPlaceholder"
|
|
81
|
-
:leading-icon="resolvedIcon"
|
|
82
|
-
:size
|
|
83
|
-
/>
|
|
95
|
+
<UInput v-else v-model="model as string" v-bind="textInputProps" />
|
|
84
96
|
</UFormField>
|
|
85
97
|
</template>
|
|
@@ -78,7 +78,13 @@ provide('pageTitle', title)
|
|
|
78
78
|
<!-- Optional visible header -->
|
|
79
79
|
<LayoutSection v-if="showHeader">
|
|
80
80
|
<LayoutGridItem :preset="headerPreset">
|
|
81
|
-
<LayoutPageHeader
|
|
81
|
+
<LayoutPageHeader
|
|
82
|
+
:title
|
|
83
|
+
v-bind="{
|
|
84
|
+
...(description !== undefined && { description }),
|
|
85
|
+
...(back !== undefined && { back }),
|
|
86
|
+
}"
|
|
87
|
+
/>
|
|
82
88
|
</LayoutGridItem>
|
|
83
89
|
</LayoutSection>
|
|
84
90
|
|
|
@@ -60,7 +60,10 @@ provide('pageTitle', title)
|
|
|
60
60
|
<!-- Optional visible page header — rendered as a grid section -->
|
|
61
61
|
<LayoutSection v-if="showHeader">
|
|
62
62
|
<LayoutGridItem preset="centered">
|
|
63
|
-
<LayoutPageHeader
|
|
63
|
+
<LayoutPageHeader
|
|
64
|
+
:title
|
|
65
|
+
v-bind="description !== undefined ? { description } : {}"
|
|
66
|
+
/>
|
|
64
67
|
</LayoutGridItem>
|
|
65
68
|
</LayoutSection>
|
|
66
69
|
|
|
@@ -142,12 +142,16 @@ function handleMouseLeave() {
|
|
|
142
142
|
<template>
|
|
143
143
|
<div
|
|
144
144
|
ref="containerRef"
|
|
145
|
-
class="motion-marquee"
|
|
145
|
+
class="motion-marquee width-full overflow-hidden"
|
|
146
146
|
:class="{ 'is-paused': isPaused }"
|
|
147
147
|
@mouseenter="handleMouseEnter"
|
|
148
148
|
@mouseleave="handleMouseLeave"
|
|
149
149
|
>
|
|
150
|
-
<div
|
|
150
|
+
<div
|
|
151
|
+
ref="contentRef"
|
|
152
|
+
class="motion-marquee__content flex will-change-transform w-max"
|
|
153
|
+
:style="{ gap }"
|
|
154
|
+
>
|
|
151
155
|
<slot />
|
|
152
156
|
<!-- Duplicate for seamless loop -->
|
|
153
157
|
<slot />
|
|
@@ -155,17 +159,9 @@ function handleMouseLeave() {
|
|
|
155
159
|
</div>
|
|
156
160
|
</template>
|
|
157
161
|
|
|
158
|
-
<style scoped>
|
|
159
|
-
.motion-marquee {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/* stylelint-disable-next-line selector-class-pattern */
|
|
165
|
-
.motion-marquee__content {
|
|
166
|
-
display: flex;
|
|
167
|
-
will-change: transform;
|
|
168
|
-
/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
|
|
169
|
-
width: max-content;
|
|
170
|
-
}
|
|
171
|
-
</style>
|
|
162
|
+
<!-- <style scoped>
|
|
163
|
+
/* .motion-marquee { width: 100%; overflow: hidden; } */ /* stylelint-disable-next-line
|
|
164
|
+
selector-class-pattern */ /* .motion-marquee__content { */ /* display: flex; */ /* will-change:
|
|
165
|
+
transform; */ /* stylelint-disable-next-line plugin/no-unsupported-browser-features */ /* width:
|
|
166
|
+
max-content; */ /* } */
|
|
167
|
+
</style> -->
|
|
@@ -50,7 +50,7 @@ onMounted(() => {
|
|
|
50
50
|
<template>
|
|
51
51
|
<div class="motion-staggered">
|
|
52
52
|
<slot
|
|
53
|
-
v-for="(
|
|
53
|
+
v-for="(_, index) in slots.default?.()"
|
|
54
54
|
:key="index"
|
|
55
55
|
:ref="(el: HTMLElement | null) => setItemRef(el, index)"
|
|
56
56
|
:class="{ animated: animatedItems[index] }"
|
|
@@ -43,20 +43,7 @@ onMounted(() => {
|
|
|
43
43
|
}, 50)
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
-
// Methods
|
|
47
|
-
const enter = (el: Element) => {
|
|
48
|
-
// Handle enter transition
|
|
49
|
-
;(el as HTMLElement).style.opacity = '0'
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
;(el as HTMLElement).style.opacity = '1'
|
|
52
|
-
}, 10)
|
|
53
|
-
}
|
|
54
46
|
|
|
55
|
-
const leave = (el: Element, done: () => void) => {
|
|
56
|
-
// Handle leave transition
|
|
57
|
-
;(el as HTMLElement).style.opacity = '0'
|
|
58
|
-
setTimeout(done, props.duration)
|
|
59
|
-
}
|
|
60
47
|
</script>
|
|
61
48
|
|
|
62
49
|
<template>
|
|
@@ -81,7 +81,7 @@ export function useSmoothScroll() {
|
|
|
81
81
|
duration: options?.duration ?? 1.2,
|
|
82
82
|
immediate: options?.immediate ?? false,
|
|
83
83
|
lock: options?.lock ?? false,
|
|
84
|
-
onComplete: options
|
|
84
|
+
...(options?.onComplete !== undefined && { onComplete: options.onComplete }),
|
|
85
85
|
})
|
|
86
86
|
} else {
|
|
87
87
|
// Native fallback
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
interface RoutePage {
|
|
2
|
+
file?: string
|
|
3
|
+
meta?: Record<string, unknown>
|
|
4
|
+
children?: RoutePage[]
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
export default defineNuxtConfig({
|
|
4
8
|
$meta: { name: 'routing' },
|
|
@@ -10,9 +14,9 @@ export default defineNuxtConfig({
|
|
|
10
14
|
compatibilityDate: '2026-01-30',
|
|
11
15
|
|
|
12
16
|
hooks: {
|
|
13
|
-
'pages:extend'(pages) {
|
|
17
|
+
'pages:extend'(pages: unknown[]) {
|
|
14
18
|
const cwd = process.cwd()
|
|
15
|
-
const tag = (list:
|
|
19
|
+
const tag = (list: RoutePage[]) => {
|
|
16
20
|
for (const page of list) {
|
|
17
21
|
if (page.file && !page.file.startsWith(cwd)) {
|
|
18
22
|
page.meta ??= {}
|
|
@@ -21,7 +25,7 @@ export default defineNuxtConfig({
|
|
|
21
25
|
if (page.children) tag(page.children)
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
|
-
tag(pages)
|
|
28
|
+
tag(pages as unknown as RoutePage[])
|
|
25
29
|
},
|
|
26
30
|
},
|
|
27
31
|
})
|
|
@@ -4,11 +4,6 @@ import type { FBMOptions, TSLNode } from '../../types'
|
|
|
4
4
|
/**
|
|
5
5
|
* Hash function for noise generation
|
|
6
6
|
*/
|
|
7
|
-
const hash21 = Fn(([p]: [TSLNode]) => {
|
|
8
|
-
const p3 = fract(p.mul(vec2(443.8975, 397.2973)))
|
|
9
|
-
const shifted = p3.add(dot(p3, p3.add(19.19)))
|
|
10
|
-
return fract(shifted.x.mul(shifted.y))
|
|
11
|
-
})
|
|
12
7
|
|
|
13
8
|
const hash22 = Fn(([p]: [TSLNode]) => {
|
|
14
9
|
const p3 = fract(p.mul(vec2(443.8975, 397.2973)))
|
|
@@ -76,7 +76,7 @@ export default {}
|
|
|
76
76
|
return {
|
|
77
77
|
name: 'three-webgpu-ssr-stub',
|
|
78
78
|
enforce: 'pre',
|
|
79
|
-
transform(
|
|
79
|
+
transform(_code, id, options) {
|
|
80
80
|
// Only intercept in SSR context
|
|
81
81
|
if (!options?.ssr) return null
|
|
82
82
|
// In three r182+, three/webgpu → three.webgpu.js, three/tsl → three.tsl.js
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
export default defineNuxtPlugin(() => {
|
|
2
|
-
const config = useAppConfig()
|
|
3
|
-
if ((config.layers as Record<string, boolean> | undefined)?.theme === false) return
|
|
4
|
-
|
|
5
2
|
// Initialize shared composables — applies data-theme-colour, data-theme-contrast,
|
|
6
3
|
// data-theme-motion, and data-theme-transparency on <html> on first load.
|
|
7
4
|
useTheme()
|
|
@@ -29,7 +29,20 @@ const resolvedBlobs = computed((): BlobConfig[] => {
|
|
|
29
29
|
<template>
|
|
30
30
|
<component :is="tag" class="relative overflow-clip isolate">
|
|
31
31
|
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
|
|
32
|
-
<AccentBlob
|
|
32
|
+
<AccentBlob
|
|
33
|
+
v-for="(blob, i) in resolvedBlobs"
|
|
34
|
+
:key="i"
|
|
35
|
+
:x="blob.x"
|
|
36
|
+
:y="blob.y"
|
|
37
|
+
v-bind="{
|
|
38
|
+
...(blob.size !== undefined && { size: blob.size }),
|
|
39
|
+
...(blob.blur !== undefined && { blur: blob.blur }),
|
|
40
|
+
...(blob.opacity !== undefined && { opacity: blob.opacity }),
|
|
41
|
+
...(blob.color !== undefined && { color: blob.color }),
|
|
42
|
+
...(blob.shade !== undefined && { shade: blob.shade }),
|
|
43
|
+
...(blob.customColor !== undefined && { customColor: blob.customColor }),
|
|
44
|
+
}"
|
|
45
|
+
/>
|
|
33
46
|
</div>
|
|
34
47
|
<div class="relative z-10">
|
|
35
48
|
<slot />
|
|
@@ -18,8 +18,18 @@ const {
|
|
|
18
18
|
}>()
|
|
19
19
|
|
|
20
20
|
const modelValue = computed(() => (progress != null ? progress * 100 : undefined))
|
|
21
|
+
|
|
22
|
+
const progressProps = computed(() => ({
|
|
23
|
+
...(modelValue.value !== undefined && { modelValue: modelValue.value }),
|
|
24
|
+
...(color !== undefined && { color }),
|
|
25
|
+
...(size !== undefined && { size }),
|
|
26
|
+
...(orientation !== undefined && { orientation }),
|
|
27
|
+
...(status !== undefined && { status }),
|
|
28
|
+
...(animation !== undefined && { animation }),
|
|
29
|
+
...(inverted !== undefined && { inverted }),
|
|
30
|
+
}))
|
|
21
31
|
</script>
|
|
22
32
|
|
|
23
33
|
<template>
|
|
24
|
-
<UProgress
|
|
34
|
+
<UProgress v-bind="progressProps" />
|
|
25
35
|
</template>
|
|
@@ -13,7 +13,6 @@ const props = withDefaults(
|
|
|
13
13
|
class?: string
|
|
14
14
|
}>(),
|
|
15
15
|
{
|
|
16
|
-
language: undefined,
|
|
17
16
|
class: '',
|
|
18
17
|
color: 'default',
|
|
19
18
|
}
|
|
@@ -24,11 +23,13 @@ const colorClass = useColor(props.color, 'text')
|
|
|
24
23
|
<template>
|
|
25
24
|
<Typography
|
|
26
25
|
tag="pre"
|
|
27
|
-
v-bind="
|
|
28
|
-
|
|
26
|
+
v-bind="{
|
|
27
|
+
...$attrs,
|
|
28
|
+
...(props.size !== undefined && { size: props.size }),
|
|
29
|
+
...(props.language !== undefined && { 'data-language': props.language }),
|
|
30
|
+
}"
|
|
29
31
|
class="overflow-x-auto"
|
|
30
32
|
:class="[props.class]"
|
|
31
|
-
:data-language="props.language"
|
|
32
33
|
>
|
|
33
34
|
<Typography
|
|
34
35
|
tag="code"
|
|
@@ -57,7 +57,16 @@ const sizeClass = computed(() => {
|
|
|
57
57
|
return sizes[props.level]
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
-
const { classes } = useTypography(
|
|
60
|
+
const { classes } = useTypography({
|
|
61
|
+
weight: props.weight,
|
|
62
|
+
width: props.width,
|
|
63
|
+
slant: props.slant,
|
|
64
|
+
leading: props.leading,
|
|
65
|
+
tracking: props.tracking,
|
|
66
|
+
align: props.align,
|
|
67
|
+
transform: props.transform,
|
|
68
|
+
...(props.size !== undefined && { size: props.size }),
|
|
69
|
+
})
|
|
61
70
|
const colorClass = useColor(props.color, 'text')
|
|
62
71
|
</script>
|
|
63
72
|
|
|
@@ -71,9 +80,8 @@ const colorClass = useColor(props.color, 'text')
|
|
|
71
80
|
:tracking="props.tracking"
|
|
72
81
|
:align="props.align"
|
|
73
82
|
:transform="props.transform"
|
|
74
|
-
:size="props.size"
|
|
75
83
|
:class="[sizeClass, classes, colorClass, props.class]"
|
|
76
|
-
v-bind="
|
|
84
|
+
v-bind="{ ...(props.size !== undefined && { size: props.size }), ...$attrs }"
|
|
77
85
|
>
|
|
78
86
|
<slot />
|
|
79
87
|
</Typography>
|
|
@@ -10,7 +10,11 @@ const colorClass = useColor(props.color, 'text')
|
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
12
|
<template>
|
|
13
|
-
<Typography
|
|
13
|
+
<Typography
|
|
14
|
+
tag="blockquote"
|
|
15
|
+
:class="colorClass"
|
|
16
|
+
v-bind="{ ...(props.size !== undefined && { size: props.size }), ...$attrs }"
|
|
17
|
+
>
|
|
14
18
|
<slot />
|
|
15
19
|
</Typography>
|
|
16
20
|
</template>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { splitSpaces } from '../utils/regex'
|
|
2
2
|
|
|
3
3
|
export function useSite() {
|
|
4
|
-
const config = useAppConfig().site
|
|
4
|
+
const config = useAppConfig().site ?? {}
|
|
5
5
|
|
|
6
6
|
return {
|
|
7
|
-
title: config.title as string,
|
|
8
|
-
titleWords: splitSpaces(config.title as string) as string[],
|
|
9
|
-
subtitle: config.subtitle as string,
|
|
10
|
-
subtitleWords: splitSpaces(config.subtitle as string) as string[],
|
|
11
|
-
description: config.description as string,
|
|
7
|
+
title: (config.title ?? '') as string,
|
|
8
|
+
titleWords: splitSpaces((config.title ?? '') as string) as string[],
|
|
9
|
+
subtitle: (config.subtitle ?? '') as string,
|
|
10
|
+
subtitleWords: splitSpaces((config.subtitle ?? '') as string) as string[],
|
|
11
|
+
description: (config.description ?? '') as string,
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -24,11 +24,12 @@ export function createModal<P extends Record<string, unknown>>(component: Compon
|
|
|
24
24
|
if (import.meta.server) return { open: () => {}, close: () => {}, patch: () => {} }
|
|
25
25
|
|
|
26
26
|
const overlay = useOverlay()
|
|
27
|
-
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
const modal = overlay.create(component as any)
|
|
28
29
|
return {
|
|
29
|
-
open: (props?: Partial<P>) => modal.open(props),
|
|
30
|
+
open: (props?: Partial<P>) => modal.open(props as never),
|
|
30
31
|
close: () => modal.close(),
|
|
31
|
-
patch: (props: Partial<P>) => modal.patch(props),
|
|
32
|
+
patch: (props: Partial<P>) => modal.patch(props as never),
|
|
32
33
|
}
|
|
33
34
|
})
|
|
34
35
|
}
|
package/layers/ui/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kmcom-nuxt-layers",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.6.
|
|
4
|
+
"version": "1.6.20",
|
|
5
5
|
"description": "Composable Nuxt 4 layers for building scalable Vue applications",
|
|
6
6
|
"files": [
|
|
7
7
|
"layers/*/nuxt.config.ts",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"tailwindcss": "^4.2.4",
|
|
42
42
|
"three": "^0.183.2",
|
|
43
43
|
"v-gsap-nuxt": ">=1.0.0",
|
|
44
|
-
"zod": "^4.3
|
|
44
|
+
"zod": "^4.4.3"
|
|
45
45
|
},
|
|
46
46
|
"peerDependenciesMeta": {
|
|
47
47
|
"@nuxtjs/device": {
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"@perplex-digital/stylelint-config": "^17.4.0",
|
|
108
108
|
"@pinia/nuxt": "^0.11.3",
|
|
109
109
|
"@types/node": "^25.6.0",
|
|
110
|
-
"@typescript-eslint/eslint-plugin": "^8.59.
|
|
111
|
-
"@typescript-eslint/parser": "^8.59.
|
|
110
|
+
"@typescript-eslint/eslint-plugin": "^8.59.2",
|
|
111
|
+
"@typescript-eslint/parser": "^8.59.2",
|
|
112
112
|
"@vue/eslint-config-typescript": "^14.7.0",
|
|
113
113
|
"@vueuse/core": "^14.3.0",
|
|
114
114
|
"@vueuse/nuxt": "^14.3.0",
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"eslint-plugin-prettier": "^5.5.5",
|
|
125
125
|
"eslint-plugin-unicorn": "^64.0.0",
|
|
126
126
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
127
|
-
"eslint-plugin-vue": "^10.9.
|
|
127
|
+
"eslint-plugin-vue": "^10.9.1",
|
|
128
128
|
"npm-check-updates": "^21.0.3",
|
|
129
129
|
"nuxt": "latest",
|
|
130
130
|
"pinia": "^3.0.4",
|
|
@@ -144,14 +144,14 @@
|
|
|
144
144
|
"stylelint-no-unsupported-browser-features": "^8.1.1",
|
|
145
145
|
"stylelint-prettier": "^5.0.3",
|
|
146
146
|
"tailwindcss": "^4.2.4",
|
|
147
|
-
"turbo": "^2.9.
|
|
147
|
+
"turbo": "^2.9.9",
|
|
148
148
|
"typescript": "^6.0.3",
|
|
149
149
|
"vite-plugin-checker": "^0.13.0",
|
|
150
150
|
"vitest": "^4.1.5",
|
|
151
151
|
"vue": "latest",
|
|
152
152
|
"vue-tsc": "^3.2.8",
|
|
153
|
-
"zod": "^4.3
|
|
154
|
-
"zod-to-json-schema": "^3.25.
|
|
153
|
+
"zod": "^4.4.3",
|
|
154
|
+
"zod-to-json-schema": "^3.25.2"
|
|
155
155
|
},
|
|
156
156
|
"browserslist": [
|
|
157
157
|
"last 2 Chrome major versions",
|