kmcom-nuxt-layers 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/layers/content/app/components/Blog/List.vue +5 -1
- package/layers/content/app/components/Gallery/AmbientImage.vue +5 -12
- package/layers/content/app/components/Gallery/Detail.vue +8 -6
- package/layers/content/app/components/Gallery/Grid.vue +11 -3
- package/layers/content/app/components/Portfolio/ColorPalette.vue +1 -4
- package/layers/content/app/components/Portfolio/Detail.vue +6 -1
- package/layers/content/app/components/Portfolio/List.vue +5 -1
- package/layers/content/app/components/content/Figure.vue +1 -7
- package/layers/content/package.json +5 -5
- package/layers/core/app/assets/css/main.css +5 -0
- package/layers/core/app/composables/useCache.ts +8 -4
- package/layers/core/app/composables/useErrorLog.ts +9 -5
- package/layers/core/app/composables/useScrollGuard.ts +4 -2
- package/layers/core/app/plugins/feature-detection.client.ts +1 -1
- package/layers/core/app/plugins/init.ts +2 -1
- package/layers/core/app/plugins/scroll-guard.client.ts +4 -1
- package/layers/core/app.config.ts +0 -9
- package/layers/forms/app/components/Form/Contact.vue +16 -7
- package/layers/forms/nuxt.config.ts +18 -0
- package/layers/forms/package.json +2 -0
- package/layers/layout/app/components/Layout/Container.vue +1 -4
- package/layers/layout/app/components/Layout/Grid/Debug.vue +0 -1
- package/layers/layout/app/components/Layout/Grid/Item.vue +12 -6
- package/layers/layout/app/components/Layout/Main.vue +1 -4
- package/layers/layout/app/components/Layout/Page/Container.vue +3 -1
- package/layers/layout/app/components/Layout/Page/Header.vue +16 -5
- package/layers/layout/app/components/Layout/Section/Grid.vue +1 -4
- package/layers/layout/app/components/Layout/Section/Sidebar.vue +6 -1
- package/layers/layout/app/components/Layout/Section/Stack.vue +1 -1
- package/layers/layout/app/components/Layout/Section/Title.vue +33 -0
- package/layers/layout/app/composables/useGridConfig.ts +6 -1
- package/layers/motion/app/components/Motion/HorizontalScroll.vue +61 -0
- package/layers/motion/app/components/Motion/PinnedSection.vue +77 -0
- package/layers/motion/app/components/Motion/ScrollProgress.vue +8 -56
- package/layers/motion/app/components/Motion/ScrollScene.vue +121 -0
- package/layers/motion/app/components/Motion/ScrollStep.vue +45 -0
- package/layers/motion/app/components/Motion/TextReveal.vue +28 -63
- package/layers/motion/app/composables/useScrollSteps.ts +41 -0
- package/layers/motion/app/composables/useSectionProgress.ts +58 -0
- package/layers/motion/app/composables/useSmoothScroll.ts +3 -2
- package/layers/motion/app/plugins/locomotive-scroll.client.ts +6 -6
- package/layers/motion/nuxt.config.ts +6 -0
- package/layers/motion/package.json +2 -1
- package/layers/shader/app/components/Preset/ThemeAurora.client.vue +86 -0
- package/layers/shader/app/components/Preset/ThemeFlow.client.vue +86 -0
- package/layers/shader/app/components/Preset/ThemeGradient.client.vue +87 -0
- package/layers/shader/app/components/Shader/Background.client.vue +6 -0
- package/layers/shader/app/composables/useAmbientMaterials.ts +150 -0
- package/layers/shader/app/composables/useThemeColors.ts +43 -0
- package/layers/shader/app/utils/tsl/oklch.ts +12 -6
- package/layers/theme/app/assets/css/theme.css +19 -14
- package/layers/theme/app/components/ThemePicker/AccentButton.vue +2 -2
- package/layers/theme/app/components/ThemePicker/Colors.vue +2 -4
- package/layers/theme/app/components/ThemePicker/Menu.vue +4 -13
- package/layers/theme/app/components/ThemePicker/MenuButton.vue +1 -7
- package/layers/theme/app/composables/useAccentColor.ts +38 -0
- package/layers/theme/app/composables/useTheme.ts +14 -0
- package/layers/theme/app/composables/useThemeContrast.ts +34 -0
- package/layers/theme/app/composables/useThemeMotion.ts +34 -0
- package/layers/theme/app/composables/useThemePreferences.ts +3 -156
- package/layers/theme/app/composables/useThemeTransparency.ts +41 -0
- package/layers/theme/app/plugins/theme.client.ts +3 -3
- package/layers/theme/app/types/theme.ts +4 -0
- package/layers/theme/nuxt.config.ts +7 -0
- package/layers/ui/app/app.config.ts +44 -0
- package/layers/ui/app/assets/css/main.css +14 -0
- package/layers/ui/app/components/Accent/Blob.vue +29 -0
- package/layers/ui/app/components/Accent/Scene.vue +38 -0
- package/layers/ui/app/components/Gradient/Background.vue +22 -0
- package/layers/ui/app/components/Gradient/Text.vue +22 -0
- package/layers/ui/app/components/Progress/Bar.vue +25 -0
- package/layers/ui/app/components/Progress/Circular.vue +69 -0
- package/layers/ui/app/components/Tint/Overlay.vue +25 -0
- package/layers/ui/app/components/Typography/CodeBlock.vue +2 -1
- package/layers/ui/app/components/Typography/Headline.vue +2 -1
- package/layers/ui/app/components/Typography/QuoteBlock.vue +2 -1
- package/layers/ui/app/components/Typography/TextStroke.vue +18 -16
- package/layers/ui/app/composables/accent.ts +51 -0
- package/layers/ui/app/composables/gradient.ts +79 -0
- package/layers/ui/app/composables/tint.ts +20 -0
- package/layers/ui/app/types/accent.ts +17 -0
- package/layers/ui/app/types/gradient.ts +27 -0
- package/layers/ui/app/types/tint.ts +25 -0
- package/package.json +32 -30
- package/layers/motion/app/utils/gsapAnimations.ts +0 -122
- package/layers/ui/app.config.ts +0 -12
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
defineOptions({ inheritAttrs: false })
|
|
3
2
|
import { useColor } from '../../composables/color'
|
|
4
3
|
import { useTypography } from '../../composables/typography'
|
|
5
4
|
import type { UiColors } from '../../types/colors'
|
|
@@ -14,6 +13,8 @@ import type {
|
|
|
14
13
|
TextTransform,
|
|
15
14
|
} from '../../types/typography'
|
|
16
15
|
|
|
16
|
+
defineOptions({ inheritAttrs: false })
|
|
17
|
+
|
|
17
18
|
const props = withDefaults(
|
|
18
19
|
defineProps<{
|
|
19
20
|
level?: 1 | 2 | 3 | 4 | 5 | 6
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
defineOptions({ inheritAttrs: false })
|
|
3
2
|
import { useColor } from '../../composables/color'
|
|
4
3
|
import type { UiColors } from '../../types/colors'
|
|
5
4
|
import type { FontSize } from '../../types/typography'
|
|
6
5
|
|
|
6
|
+
defineOptions({ inheritAttrs: false })
|
|
7
|
+
|
|
7
8
|
const props = defineProps<{ color?: UiColors; size?: FontSize }>()
|
|
8
9
|
const colorClass = useColor(props.color, 'text')
|
|
9
10
|
</script>
|
|
@@ -35,7 +35,9 @@ const effectiveStrokeWidth = computed(() =>
|
|
|
35
35
|
v-bind="$attrs"
|
|
36
36
|
>
|
|
37
37
|
<!-- Sizer: transparent text for natural sizing + selectable -->
|
|
38
|
-
<span class="text-stroke-sizer text-transparent whitespace-nowrap" aria-hidden="true">{{
|
|
38
|
+
<span class="text-stroke-sizer text-transparent whitespace-nowrap" aria-hidden="true">{{
|
|
39
|
+
text
|
|
40
|
+
}}</span>
|
|
39
41
|
|
|
40
42
|
<!-- Visual SVG stroke -->
|
|
41
43
|
<svg
|
|
@@ -50,18 +52,16 @@ const effectiveStrokeWidth = computed(() =>
|
|
|
50
52
|
<defs v-if="fill === 'none'">
|
|
51
53
|
<mask :id="`stroke-mask-${id}`">
|
|
52
54
|
<rect x="-9999" y="-9999" width="99999" height="99999" fill="white" />
|
|
53
|
-
<text
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
fill="black"
|
|
57
|
-
style="font: inherit"
|
|
58
|
-
>{{ text }}</text>
|
|
55
|
+
<text x="0" y="0" dominant-baseline="text-before-edge" fill="black" style="font: inherit">
|
|
56
|
+
{{ text }}
|
|
57
|
+
</text>
|
|
59
58
|
</mask>
|
|
60
59
|
</defs>
|
|
61
60
|
|
|
62
61
|
<text
|
|
63
62
|
v-if="fill === 'none'"
|
|
64
|
-
x="0"
|
|
63
|
+
x="0"
|
|
64
|
+
y="0"
|
|
65
65
|
dominant-baseline="text-before-edge"
|
|
66
66
|
fill="none"
|
|
67
67
|
:stroke="strokeColor"
|
|
@@ -70,12 +70,15 @@ const effectiveStrokeWidth = computed(() =>
|
|
|
70
70
|
vector-effect="non-scaling-stroke"
|
|
71
71
|
:mask="`url(#stroke-mask-${id})`"
|
|
72
72
|
style="font: inherit"
|
|
73
|
-
>
|
|
73
|
+
>
|
|
74
|
+
{{ text }}
|
|
75
|
+
</text>
|
|
74
76
|
|
|
75
77
|
<!-- Fill+stroke mode: paint-order renders stroke behind fill -->
|
|
76
78
|
<text
|
|
77
79
|
v-else
|
|
78
|
-
x="0"
|
|
80
|
+
x="0"
|
|
81
|
+
y="0"
|
|
79
82
|
dominant-baseline="text-before-edge"
|
|
80
83
|
:fill="fill"
|
|
81
84
|
:stroke="strokeColor"
|
|
@@ -84,24 +87,23 @@ const effectiveStrokeWidth = computed(() =>
|
|
|
84
87
|
vector-effect="non-scaling-stroke"
|
|
85
88
|
paint-order="stroke"
|
|
86
89
|
style="font: inherit"
|
|
87
|
-
>
|
|
90
|
+
>
|
|
91
|
+
{{ text }}
|
|
92
|
+
</text>
|
|
88
93
|
</svg>
|
|
89
94
|
|
|
90
95
|
<!-- Accessible label for screen readers -->
|
|
91
|
-
<span
|
|
92
|
-
:id="`stroke-text-${id}`"
|
|
93
|
-
class="sr-only"
|
|
94
|
-
>{{ text }}</span>
|
|
96
|
+
<span :id="`stroke-text-${id}`" class="sr-only">{{ text }}</span>
|
|
95
97
|
</component>
|
|
96
98
|
</template>
|
|
97
99
|
|
|
98
100
|
<style scoped>
|
|
99
|
-
|
|
100
101
|
@media (forced-colors: active) {
|
|
101
102
|
.text-stroke-sizer {
|
|
102
103
|
visibility: visible;
|
|
103
104
|
color: CanvasText;
|
|
104
105
|
}
|
|
106
|
+
|
|
105
107
|
.text-stroke-svg {
|
|
106
108
|
display: none;
|
|
107
109
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ComputedRef, CSSProperties } from 'vue'
|
|
2
|
+
import type { BlobBlur, BlobConfig } from '../types/accent'
|
|
3
|
+
|
|
4
|
+
const BLUR_PX_MAP: Record<string, number> = {
|
|
5
|
+
none: 0,
|
|
6
|
+
sm: 8,
|
|
7
|
+
md: 12,
|
|
8
|
+
lg: 16,
|
|
9
|
+
xl: 24,
|
|
10
|
+
'2xl': 40,
|
|
11
|
+
'3xl': 64,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function resolveBlurPx(blur: BlobBlur = '3xl'): number {
|
|
15
|
+
if (typeof blur === 'number') return blur
|
|
16
|
+
return BLUR_PX_MAP[blur] ?? 64
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function resolveColor(config: BlobConfig): string {
|
|
20
|
+
const { color = 'primary', shade = 500, customColor } = config
|
|
21
|
+
if (color === 'custom') return customColor ?? 'transparent'
|
|
22
|
+
if (color === 'white') return '#ffffff'
|
|
23
|
+
if (color === 'black') return '#000000'
|
|
24
|
+
return `var(--ui-color-${color}-${shade})`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function useAccentBlob(config: BlobConfig): {
|
|
28
|
+
style: ComputedRef<CSSProperties>
|
|
29
|
+
} {
|
|
30
|
+
const style = computed((): CSSProperties => {
|
|
31
|
+
const size = config.size ?? '40rem'
|
|
32
|
+
const opacity = (config.opacity ?? 25) / 100
|
|
33
|
+
const blurPx = resolveBlurPx(config.blur)
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
position: 'absolute',
|
|
37
|
+
left: `${config.x}%`,
|
|
38
|
+
top: `${config.y}%`,
|
|
39
|
+
transform: 'translate(-50%, -50%)',
|
|
40
|
+
width: size,
|
|
41
|
+
height: size,
|
|
42
|
+
backgroundColor: resolveColor(config),
|
|
43
|
+
opacity,
|
|
44
|
+
borderRadius: '9999px',
|
|
45
|
+
filter: blurPx > 0 ? `blur(${blurPx}px)` : undefined,
|
|
46
|
+
pointerEvents: 'none',
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return { style }
|
|
51
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ComputedRef, CSSProperties, MaybeRefOrGetter } from 'vue'
|
|
2
|
+
import type { GradientConfig, GradientStop } from '../types/gradient'
|
|
3
|
+
|
|
4
|
+
const DEFAULT_CONFIG: GradientConfig = {
|
|
5
|
+
shape: 'linear',
|
|
6
|
+
direction: 'to-br',
|
|
7
|
+
from: { color: 'primary', shade: 500 },
|
|
8
|
+
to: { color: 'secondary', shade: 500 },
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const DIRECTION_MAP: Record<string, string> = {
|
|
12
|
+
'to-t': 'to top',
|
|
13
|
+
'to-tr': 'to top right',
|
|
14
|
+
'to-r': 'to right',
|
|
15
|
+
'to-br': 'to bottom right',
|
|
16
|
+
'to-b': 'to bottom',
|
|
17
|
+
'to-bl': 'to bottom left',
|
|
18
|
+
'to-l': 'to left',
|
|
19
|
+
'to-tl': 'to top left',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function resolveColor(stop: GradientStop): string {
|
|
23
|
+
const { color, shade = 500, opacity } = stop
|
|
24
|
+
if (color === 'transparent') return 'transparent'
|
|
25
|
+
if (color === 'white') {
|
|
26
|
+
return opacity !== undefined ? `rgb(255 255 255 / ${opacity / 100})` : '#ffffff'
|
|
27
|
+
}
|
|
28
|
+
if (color === 'black') {
|
|
29
|
+
return opacity !== undefined ? `rgb(0 0 0 / ${opacity / 100})` : '#000000'
|
|
30
|
+
}
|
|
31
|
+
const v = `var(--ui-color-${color}-${shade})`
|
|
32
|
+
return opacity !== undefined ? `color-mix(in srgb, ${v} ${opacity}%, transparent)` : v
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function buildStyle(cfg: GradientConfig): CSSProperties {
|
|
36
|
+
const from = resolveColor(cfg.from)
|
|
37
|
+
const to = resolveColor(cfg.to)
|
|
38
|
+
const via = cfg.via ? resolveColor(cfg.via) : undefined
|
|
39
|
+
const stops = via ? `${from}, ${via}, ${to}` : `${from}, ${to}`
|
|
40
|
+
|
|
41
|
+
if (cfg.shape === 'radial') {
|
|
42
|
+
return { backgroundImage: `radial-gradient(circle, ${stops})` }
|
|
43
|
+
}
|
|
44
|
+
if (cfg.shape === 'conic') {
|
|
45
|
+
return { backgroundImage: `conic-gradient(${stops})` }
|
|
46
|
+
}
|
|
47
|
+
const dir = DIRECTION_MAP[cfg.direction ?? 'to-br'] ?? 'to bottom right'
|
|
48
|
+
return { backgroundImage: `linear-gradient(${dir}, ${stops})` }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function useGradient(
|
|
52
|
+
config: MaybeRefOrGetter<GradientConfig | string>,
|
|
53
|
+
overrides?: MaybeRefOrGetter<Partial<GradientConfig>>
|
|
54
|
+
): { style: ComputedRef<CSSProperties> } {
|
|
55
|
+
const appConfig = useAppConfig()
|
|
56
|
+
|
|
57
|
+
const style = computed((): CSSProperties => {
|
|
58
|
+
const raw = toValue(config)
|
|
59
|
+
const override = overrides ? toValue(overrides) : undefined
|
|
60
|
+
|
|
61
|
+
let resolved: GradientConfig
|
|
62
|
+
if (typeof raw === 'string') {
|
|
63
|
+
const preset = (appConfig.uiLayer as Record<string, unknown> | undefined)?.gradients as
|
|
64
|
+
| Record<string, GradientConfig>
|
|
65
|
+
| undefined
|
|
66
|
+
resolved = preset?.[raw] ?? DEFAULT_CONFIG
|
|
67
|
+
} else {
|
|
68
|
+
resolved = raw
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (override) {
|
|
72
|
+
resolved = { ...resolved, ...override }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return buildStyle(resolved)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return { style }
|
|
79
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ComputedRef, CSSProperties } from 'vue'
|
|
2
|
+
import { TINT_LEVEL_OPACITY } from '../types/tint'
|
|
3
|
+
import type { TintConfig } from '../types/tint'
|
|
4
|
+
|
|
5
|
+
export function useTint(config: TintConfig): {
|
|
6
|
+
style: ComputedRef<CSSProperties>
|
|
7
|
+
} {
|
|
8
|
+
const style = computed((): CSSProperties => {
|
|
9
|
+
const { color, shade = 500 } = config
|
|
10
|
+
let backgroundColor: string
|
|
11
|
+
if (color === 'white') backgroundColor = '#ffffff'
|
|
12
|
+
else if (color === 'black') backgroundColor = '#000000'
|
|
13
|
+
else backgroundColor = `var(--ui-color-${color}-${shade})`
|
|
14
|
+
|
|
15
|
+
const opacity = TINT_LEVEL_OPACITY[config.level] / 100
|
|
16
|
+
return { backgroundColor, opacity }
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
return { style }
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type AccentBlobColor = 'primary' | 'secondary' | 'info' | 'white' | 'black' | 'custom'
|
|
2
|
+
export type BlobBlur = 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | number
|
|
3
|
+
|
|
4
|
+
export interface BlobConfig {
|
|
5
|
+
x: number
|
|
6
|
+
y: number
|
|
7
|
+
size?: string
|
|
8
|
+
blur?: BlobBlur
|
|
9
|
+
opacity?: number
|
|
10
|
+
color?: AccentBlobColor
|
|
11
|
+
shade?: 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950
|
|
12
|
+
customColor?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AccentSceneConfig {
|
|
16
|
+
blobs: BlobConfig[]
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type GradientColorSlot = 'primary' | 'secondary' | 'info' | 'white' | 'black' | 'transparent'
|
|
2
|
+
export type GradientDirection =
|
|
3
|
+
| 'to-t'
|
|
4
|
+
| 'to-tr'
|
|
5
|
+
| 'to-r'
|
|
6
|
+
| 'to-br'
|
|
7
|
+
| 'to-b'
|
|
8
|
+
| 'to-bl'
|
|
9
|
+
| 'to-l'
|
|
10
|
+
| 'to-tl'
|
|
11
|
+
export type GradientShape = 'linear' | 'radial' | 'conic'
|
|
12
|
+
export type GradientOpacity = 0 | 10 | 20 | 25 | 30 | 40 | 50 | 60 | 70 | 75 | 80 | 90 | 100
|
|
13
|
+
export type ColorShade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950
|
|
14
|
+
|
|
15
|
+
export interface GradientStop {
|
|
16
|
+
color: GradientColorSlot
|
|
17
|
+
shade?: ColorShade
|
|
18
|
+
opacity?: GradientOpacity
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface GradientConfig {
|
|
22
|
+
shape?: GradientShape
|
|
23
|
+
direction?: GradientDirection
|
|
24
|
+
from: GradientStop
|
|
25
|
+
via?: GradientStop
|
|
26
|
+
to: GradientStop
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type TintLevel = 'subtle' | 'light' | 'medium' | 'strong' | 'heavy'
|
|
2
|
+
export type TintColorSlot =
|
|
3
|
+
| 'primary'
|
|
4
|
+
| 'secondary'
|
|
5
|
+
| 'info'
|
|
6
|
+
| 'success'
|
|
7
|
+
| 'warning'
|
|
8
|
+
| 'error'
|
|
9
|
+
| 'white'
|
|
10
|
+
| 'black'
|
|
11
|
+
export type ColorShade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950
|
|
12
|
+
|
|
13
|
+
export const TINT_LEVEL_OPACITY: Record<TintLevel, number> = {
|
|
14
|
+
subtle: 5,
|
|
15
|
+
light: 10,
|
|
16
|
+
medium: 20,
|
|
17
|
+
strong: 35,
|
|
18
|
+
heavy: 50,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TintConfig {
|
|
22
|
+
color: TintColorSlot
|
|
23
|
+
level: TintLevel
|
|
24
|
+
shade?: ColorShade
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kmcom-nuxt-layers",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"description": "Composable Nuxt 4 layers for building scalable Vue applications",
|
|
6
6
|
"files": [
|
|
7
7
|
"layers/*/nuxt.config.ts",
|
|
@@ -21,26 +21,26 @@
|
|
|
21
21
|
"packages/*"
|
|
22
22
|
],
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@nuxt/content": "^3.
|
|
25
|
-
"@nuxt/eslint": "^1.
|
|
24
|
+
"@nuxt/content": "^3.12.0",
|
|
25
|
+
"@nuxt/eslint": "^1.15.2",
|
|
26
26
|
"@nuxt/image": "^2.0.0",
|
|
27
|
-
"@nuxt/ui": "^4.5.
|
|
27
|
+
"@nuxt/ui": "^4.5.1",
|
|
28
28
|
"@nuxtjs/device": "^4.0.0",
|
|
29
|
-
"@tresjs/cientos": "^5.
|
|
30
|
-
"@tresjs/core": "^5.
|
|
31
|
-
"@tresjs/nuxt": "^5.
|
|
32
|
-
"@tresjs/post-processing": "^3.
|
|
33
|
-
"@vite-pwa/nuxt": "^1.
|
|
34
|
-
"@vueuse/nuxt": "^14.
|
|
35
|
-
"better-sqlite3": "^12.
|
|
36
|
-
"gsap": "^3.
|
|
37
|
-
"locomotive-scroll": "^5.0.
|
|
29
|
+
"@tresjs/cientos": "^5.4.0",
|
|
30
|
+
"@tresjs/core": "^5.5.0",
|
|
31
|
+
"@tresjs/nuxt": "^5.3.0",
|
|
32
|
+
"@tresjs/post-processing": "^3.4.0",
|
|
33
|
+
"@vite-pwa/nuxt": "^1.1.1",
|
|
34
|
+
"@vueuse/nuxt": "^14.2.1",
|
|
35
|
+
"better-sqlite3": "^12.6.2",
|
|
36
|
+
"gsap": "^3.14.2",
|
|
37
|
+
"locomotive-scroll": "^5.0.1",
|
|
38
38
|
"nuxt": "^4.3.1",
|
|
39
|
-
"nuxt-studio": "^1.
|
|
40
|
-
"pinia": "^3.0.
|
|
39
|
+
"nuxt-studio": "^1.4.0",
|
|
40
|
+
"pinia": "^3.0.4",
|
|
41
41
|
"tailwindcss": "^4.2.1",
|
|
42
|
-
"three": "^0.
|
|
43
|
-
"zod": "^3.
|
|
42
|
+
"three": "^0.183.2",
|
|
43
|
+
"zod": "^4.3.6"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"@nuxtjs/device": {
|
|
@@ -87,21 +87,21 @@
|
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@commitlint/cli": "^20.4.
|
|
91
|
-
"@commitlint/config-conventional": "^20.4.
|
|
92
|
-
"@culur/config-stylelint": "^1.6.
|
|
90
|
+
"@commitlint/cli": "^20.4.3",
|
|
91
|
+
"@commitlint/config-conventional": "^20.4.3",
|
|
92
|
+
"@culur/config-stylelint": "^1.6.5",
|
|
93
93
|
"@eslint/json": "^1.0.1",
|
|
94
94
|
"@eslint/markdown": "^7.5.1",
|
|
95
95
|
"@ianvs/prettier-plugin-sort-imports": "^4.7.1",
|
|
96
|
-
"@iconify-json/lucide": "^1.2.
|
|
96
|
+
"@iconify-json/lucide": "^1.2.95",
|
|
97
97
|
"@nuxt/eslint": "^1.15.2",
|
|
98
|
-
"@nuxt/fonts": "^0.
|
|
98
|
+
"@nuxt/fonts": "^0.14.0",
|
|
99
99
|
"@nuxt/image": "^2.0.0",
|
|
100
100
|
"@nuxt/ui": "latest",
|
|
101
101
|
"@nuxtjs/device": "^4.0.0",
|
|
102
102
|
"@perplex-digital/stylelint-config": "^17.3.0",
|
|
103
103
|
"@pinia/nuxt": "^0.11.3",
|
|
104
|
-
"@types/node": "^25.3.
|
|
104
|
+
"@types/node": "^25.3.3",
|
|
105
105
|
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
106
106
|
"@typescript-eslint/parser": "^8.56.1",
|
|
107
107
|
"@vue/eslint-config-typescript": "^14.7.0",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"cypress": "^15.10.0",
|
|
114
114
|
"depcheck": "^1.4.7",
|
|
115
115
|
"eslint": "^10.0.2",
|
|
116
|
-
"eslint-plugin-compat": "^6.2.
|
|
116
|
+
"eslint-plugin-compat": "^6.2.1",
|
|
117
117
|
"eslint-plugin-glsl": "0.0.0-wip",
|
|
118
118
|
"eslint-plugin-oxlint": "^1.50.0",
|
|
119
119
|
"eslint-plugin-pnpm": "^1.6.0",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"eslint-plugin-unicorn": "^63.0.0",
|
|
122
122
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
123
123
|
"eslint-plugin-vue": "^10.8.0",
|
|
124
|
-
"npm-check-updates": "^19.
|
|
124
|
+
"npm-check-updates": "^19.6.3",
|
|
125
125
|
"nuxt": "latest",
|
|
126
126
|
"oxlint": "^1.43.0",
|
|
127
127
|
"pinia": "^3.0.4",
|
|
@@ -129,11 +129,11 @@
|
|
|
129
129
|
"postcss-html": "^1.8.1",
|
|
130
130
|
"prettier": "^3.8.1",
|
|
131
131
|
"prettier-plugin-css-order": "^2.2.0",
|
|
132
|
-
"prettier-plugin-glsl": "^0.2.
|
|
132
|
+
"prettier-plugin-glsl": "^0.2.4",
|
|
133
133
|
"prettier-plugin-organize-attributes": "^1.0.0",
|
|
134
134
|
"prettier-plugin-tailwind-styled-components": "^2.0.2",
|
|
135
135
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
136
|
-
"stylelint": "^17.
|
|
136
|
+
"stylelint": "^17.4.0",
|
|
137
137
|
"stylelint-config-recommended-vue": "^1.6.1",
|
|
138
138
|
"stylelint-config-standard": "^40.0.0",
|
|
139
139
|
"stylelint-config-standard-vue": "^1.0.0",
|
|
@@ -141,12 +141,14 @@
|
|
|
141
141
|
"stylelint-no-unsupported-browser-features": "^8.1.1",
|
|
142
142
|
"stylelint-prettier": "^5.0.3",
|
|
143
143
|
"tailwindcss": "^4.2.1",
|
|
144
|
-
"turbo": "^2.8.
|
|
144
|
+
"turbo": "^2.8.13",
|
|
145
145
|
"typescript": "^5.9.3",
|
|
146
146
|
"vite-plugin-checker": "^0.12.0",
|
|
147
147
|
"vitest": "^4.0.18",
|
|
148
148
|
"vue": "latest",
|
|
149
|
-
"vue-tsc": "^3.2.5"
|
|
149
|
+
"vue-tsc": "^3.2.5",
|
|
150
|
+
"zod": "^4.3.6",
|
|
151
|
+
"zod-to-json-schema": "^3.25.1"
|
|
150
152
|
},
|
|
151
153
|
"browserslist": [
|
|
152
154
|
"last 2 Chrome major versions",
|
|
@@ -155,7 +157,7 @@
|
|
|
155
157
|
"last 2 Edge major versions"
|
|
156
158
|
],
|
|
157
159
|
"dependencies": {
|
|
158
|
-
"skills": "^1.4.
|
|
160
|
+
"skills": "^1.4.3"
|
|
159
161
|
},
|
|
160
162
|
"scripts": {
|
|
161
163
|
"dev": "pnpm -F playground dev",
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import type { gsap as GsapType } from 'gsap'
|
|
2
|
-
import type { ScrollTrigger as ScrollTriggerType } from 'gsap/ScrollTrigger'
|
|
3
|
-
|
|
4
|
-
type GsapInstance = typeof GsapType
|
|
5
|
-
type ScrollTriggerInstance = typeof ScrollTriggerType
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Create a fade-in animation with scroll trigger
|
|
9
|
-
*/
|
|
10
|
-
export function createFadeIn(
|
|
11
|
-
gsap: GsapInstance,
|
|
12
|
-
target: string | Element,
|
|
13
|
-
options?: {
|
|
14
|
-
duration?: number
|
|
15
|
-
delay?: number
|
|
16
|
-
y?: number
|
|
17
|
-
start?: string
|
|
18
|
-
toggleActions?: string
|
|
19
|
-
}
|
|
20
|
-
) {
|
|
21
|
-
const {
|
|
22
|
-
duration = 1,
|
|
23
|
-
delay = 0,
|
|
24
|
-
y = 30,
|
|
25
|
-
start = 'top 85%',
|
|
26
|
-
toggleActions = 'play none none none',
|
|
27
|
-
} = options ?? {}
|
|
28
|
-
|
|
29
|
-
gsap.set(target, { opacity: 0, y })
|
|
30
|
-
|
|
31
|
-
return gsap.to(target, {
|
|
32
|
-
opacity: 1,
|
|
33
|
-
y: 0,
|
|
34
|
-
duration,
|
|
35
|
-
delay,
|
|
36
|
-
ease: 'power2.out',
|
|
37
|
-
scrollTrigger: {
|
|
38
|
-
trigger: target,
|
|
39
|
-
start,
|
|
40
|
-
toggleActions,
|
|
41
|
-
},
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Create a parallax effect
|
|
47
|
-
*/
|
|
48
|
-
export function createParallax(
|
|
49
|
-
gsap: GsapInstance,
|
|
50
|
-
target: string | Element,
|
|
51
|
-
options?: {
|
|
52
|
-
speed?: number
|
|
53
|
-
trigger?: string | Element
|
|
54
|
-
}
|
|
55
|
-
) {
|
|
56
|
-
const { speed = 0.5, trigger } = options ?? {}
|
|
57
|
-
|
|
58
|
-
return gsap.to(target, {
|
|
59
|
-
y: () => window.innerHeight * speed,
|
|
60
|
-
ease: 'none',
|
|
61
|
-
scrollTrigger: {
|
|
62
|
-
trigger: trigger ?? target,
|
|
63
|
-
start: 'top bottom',
|
|
64
|
-
end: 'bottom top',
|
|
65
|
-
scrub: true,
|
|
66
|
-
},
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Create a pinned section
|
|
72
|
-
*/
|
|
73
|
-
export function createPin(
|
|
74
|
-
ScrollTrigger: ScrollTriggerInstance,
|
|
75
|
-
target: string | Element,
|
|
76
|
-
options?: {
|
|
77
|
-
start?: string
|
|
78
|
-
end?: string
|
|
79
|
-
pinSpacing?: boolean
|
|
80
|
-
}
|
|
81
|
-
) {
|
|
82
|
-
const { start = 'top top', end = '+=100%', pinSpacing = true } = options ?? {}
|
|
83
|
-
|
|
84
|
-
return ScrollTrigger.create({
|
|
85
|
-
trigger: target,
|
|
86
|
-
start,
|
|
87
|
-
end,
|
|
88
|
-
pin: true,
|
|
89
|
-
pinSpacing,
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Create staggered fade-in for multiple elements
|
|
95
|
-
*/
|
|
96
|
-
export function createStaggeredFadeIn(
|
|
97
|
-
gsap: GsapInstance,
|
|
98
|
-
targets: string | Element[],
|
|
99
|
-
options?: {
|
|
100
|
-
duration?: number
|
|
101
|
-
stagger?: number
|
|
102
|
-
y?: number
|
|
103
|
-
start?: string
|
|
104
|
-
}
|
|
105
|
-
) {
|
|
106
|
-
const { duration = 0.8, stagger = 0.1, y = 30, start = 'top 85%' } = options ?? {}
|
|
107
|
-
|
|
108
|
-
gsap.set(targets, { opacity: 0, y })
|
|
109
|
-
|
|
110
|
-
return gsap.to(targets, {
|
|
111
|
-
opacity: 1,
|
|
112
|
-
y: 0,
|
|
113
|
-
duration,
|
|
114
|
-
stagger,
|
|
115
|
-
ease: 'power2.out',
|
|
116
|
-
scrollTrigger: {
|
|
117
|
-
trigger: typeof targets === 'string' ? targets : targets[0],
|
|
118
|
-
start,
|
|
119
|
-
toggleActions: 'play none none none',
|
|
120
|
-
},
|
|
121
|
-
})
|
|
122
|
-
}
|