kmcom-nuxt-layers 2.2.11 → 2.2.13
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/docs/FALLOW-COMPLEXITY-DUPLICATION-AUDIT.md +65 -0
- package/docs/FEEDS.md +1 -2
- package/docs/IMPROVE-AUDIT-README.md +30 -0
- package/docs/IMPROVE-AUDIT-RESULTS.md +52 -0
- package/docs/IMPROVE-DEEP-AUDIT-RESULTS.md +81 -0
- package/docs/fallow-refactor/apps-debug.md +27 -0
- package/docs/fallow-refactor/apps-playground.md +46 -0
- package/docs/fallow-refactor/apps-visual-identity.md +41 -0
- package/docs/fallow-refactor/layers-animations.md +34 -0
- package/docs/fallow-refactor/layers-canvas.md +32 -0
- package/docs/fallow-refactor/layers-content.md +33 -0
- package/docs/fallow-refactor/layers-core.md +39 -0
- package/docs/fallow-refactor/layers-feeds.md +39 -0
- package/docs/fallow-refactor/layers-forms.md +30 -0
- package/docs/fallow-refactor/layers-layout.md +42 -0
- package/docs/fallow-refactor/layers-mailer.md +32 -0
- package/docs/fallow-refactor/layers-motion.md +27 -0
- package/docs/fallow-refactor/layers-navigation.md +31 -0
- package/docs/fallow-refactor/layers-page-transitions.md +30 -0
- package/docs/fallow-refactor/layers-routing.md +33 -0
- package/docs/fallow-refactor/layers-scripts.md +35 -0
- package/docs/fallow-refactor/layers-scroll.md +38 -0
- package/docs/fallow-refactor/layers-seo.md +32 -0
- package/docs/fallow-refactor/layers-shader.md +53 -0
- package/docs/fallow-refactor/layers-theme.md +33 -0
- package/docs/fallow-refactor/layers-transitions.md +27 -0
- package/docs/fallow-refactor/layers-typography.md +29 -0
- package/docs/fallow-refactor/layers-ui.md +27 -0
- package/docs/fallow-refactor/layers-visual.md +34 -0
- package/layers/animations/app/composables/useMagneticElement.ts +11 -9
- package/layers/animations/app/composables/useTiltEffect.ts +11 -9
- package/layers/animations/app/utils/pointerMotion.ts +31 -0
- package/layers/canvas/app/components/ShaderCanvas.vue +2 -2
- package/layers/content/app/composables/useCollectionItems.ts +28 -0
- package/layers/content/app/composables/useGalleryItems.ts +8 -14
- package/layers/content/app/composables/usePortfolioItems.ts +10 -18
- package/layers/core/app/composables/useBrowser.ts +9 -82
- package/layers/core/app/composables/useFeatures.ts +3 -27
- package/layers/core/app/plugins/init.ts +157 -135
- package/layers/core/app/utils/browserInfo.ts +115 -0
- package/layers/core/app/utils/featureClasses.ts +40 -0
- package/layers/core/app/utils/helpers.test.ts +51 -0
- package/layers/feeds/app/app.config.ts +4 -2
- package/layers/feeds/app/components/Feeds/Index.vue +229 -0
- package/layers/feeds/app/components/Feeds/RouteCard.vue +75 -0
- package/layers/feeds/app/plugins/feed-head.ts +27 -49
- package/layers/feeds/app/utils/feed-catalog.ts +184 -0
- package/layers/feeds/nuxt.config.ts +0 -1
- package/layers/feeds/package.json +1 -0
- package/layers/feeds/server/utils/content-adapter.test.ts +68 -0
- package/layers/feeds/server/utils/content-adapter.ts +2 -22
- package/layers/feeds/server/utils/feed-author.ts +32 -0
- package/layers/feeds/server/utils/feed-config.ts +88 -0
- package/layers/feeds/server/utils/feed-service.ts +11 -30
- package/layers/feeds/server/utils/feed-xml.ts +26 -0
- package/layers/feeds/server/utils/formats/rss.ts +10 -15
- package/layers/feeds/server/utils/formats.test.ts +71 -0
- package/layers/forms/app/components/Form/Field.vue +42 -30
- package/layers/forms/app/utils/fieldProps.ts +65 -0
- package/layers/layout/app/components/Layout/Grid/Item.vue +29 -146
- package/layers/layout/app/utils/gridPlacementStyle.ts +195 -0
- package/layers/mailer/app/types/mailer.ts +7 -25
- package/layers/mailer/server/utils/email.ts +28 -13
- package/layers/mailer/server/utils/hooks.ts +1 -20
- package/layers/navigation/app/composables/useSite.ts +2 -9
- package/layers/navigation/app/utils/site.ts +26 -0
- package/layers/routing/app/utils/resolveRoute.test.ts +47 -0
- package/layers/routing/app/utils/resolveRoute.ts +19 -10
- package/layers/scripts/app/composables/useAnalytics.ts +8 -41
- package/layers/scripts/app/composables/useGtm.ts +6 -13
- package/layers/scripts/app/utils/scriptClients.ts +70 -0
- package/layers/scroll/app/composables/useSmoothScroll.ts +9 -43
- package/layers/scroll/app/utils/scroll.ts +103 -0
- package/layers/seo/app/composables/useSeoConfig.ts +3 -9
- package/layers/seo/app/utils/seoConfig.ts +38 -0
- package/layers/shader/app/components/Material/AmbientAurora.client.vue +11 -33
- package/layers/shader/app/components/Material/AmbientFlow.client.vue +10 -37
- package/layers/shader/app/components/Material/AmbientGradientMesh.client.vue +10 -37
- package/layers/shader/app/components/Material/AmbientNebula.client.vue +12 -37
- package/layers/shader/app/components/Material/AmbientOcean.client.vue +9 -33
- package/layers/shader/app/components/Material/Gradient.client.vue +25 -46
- package/layers/shader/app/components/Material/Image.client.vue +10 -55
- package/layers/shader/app/components/Material/Node.client.vue +18 -5
- package/layers/shader/app/components/Material/Noise.client.vue +9 -43
- package/layers/shader/app/components/Preset/ThemeBubble.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeFlow.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeGradient.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeLavaLamp.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemePlasma.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeWave.client.vue +2 -1
- package/layers/shader/app/components/Shader/Background.client.vue +44 -24
- package/layers/shader/app/composables/useAmbientMaterials.ts +5 -1
- package/layers/shader/app/composables/useShader.ts +38 -23
- package/layers/shader/app/composables/useShaderGraph.ts +11 -6
- package/layers/shader/app/composables/useShaderMixBlend.ts +4 -4
- package/layers/shader/app/composables/useShaderRuntime.ts +0 -1
- package/layers/shader/app/composables/useShaderVec2.ts +2 -4
- package/layers/shader/app/composables/useThemePreset.ts +34 -8
- package/layers/shader/app/composables/useUniformWatchers.ts +15 -0
- package/layers/shader/app/composables/useUniforms.ts +0 -1
- package/layers/shader/app/shaders/common/blend.ts +4 -4
- package/layers/shader/app/shaders/common/effects.ts +38 -21
- package/layers/shader/app/shaders/common/grain.ts +46 -49
- package/layers/shader/app/shaders/common/lighting.ts +17 -15
- package/layers/shader/app/shaders/common/math.ts +2 -4
- package/layers/shader/app/shaders/common/nodes.ts +17 -0
- package/layers/shader/app/shaders/common/palette.ts +21 -11
- package/layers/shader/app/shaders/common/patterns.ts +25 -14
- package/layers/shader/app/shaders/common/shapes.ts +97 -88
- package/layers/shader/app/shaders/common/uv.ts +33 -34
- package/layers/shader/app/shaders/createMaterial.ts +92 -78
- package/layers/shader/app/shaders/layers/paperShading.ts +22 -10
- package/layers/shader/app/shaders/layers/shaderGradient.ts +46 -21
- package/layers/shader/app/utils/tsl/tween.ts +2 -4
- package/layers/shader/package.json +5 -1
- package/layers/theme/app/components/ThemePicker/Menu.vue +3 -25
- package/layers/theme/app/composables/useThemePreferenceModels.ts +39 -0
- package/layers/theme/server/plugins/theme-fouc.ts +1 -92
- package/layers/theme/server/utils/accent-css.ts +75 -0
- package/layers/typography/app/composables/typography.ts +3 -7
- package/layers/visual/app/composables/accent.ts +2 -9
- package/layers/visual/app/composables/gradient.ts +33 -46
- package/layers/visual/app/composables/picture.ts +2 -79
- package/layers/visual/app/utils/colorTokens.ts +23 -0
- package/layers/visual/app/utils/gradientStyle.ts +41 -0
- package/layers/visual/app/utils/responsiveSizes.ts +49 -0
- package/package.json +17 -5
- package/layers/feeds/server/routes/feed/discovery.get.ts +0 -29
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ComputedRef, CSSProperties, MaybeRefOrGetter } from 'vue'
|
|
2
2
|
|
|
3
|
-
import type { GradientConfig
|
|
3
|
+
import type { GradientConfig } from '../types/gradient'
|
|
4
|
+
import { buildGradientStyle } from '../utils/gradientStyle'
|
|
4
5
|
|
|
5
6
|
const DEFAULT_CONFIG: GradientConfig = {
|
|
6
7
|
shape: 'linear',
|
|
@@ -9,44 +10,41 @@ const DEFAULT_CONFIG: GradientConfig = {
|
|
|
9
10
|
to: { color: 'secondary', shade: 500 },
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
'to-bl': 'to bottom left',
|
|
19
|
-
'to-l': 'to left',
|
|
20
|
-
'to-tl': 'to top left',
|
|
13
|
+
function resolveGradientConfig(
|
|
14
|
+
raw: GradientConfig | string,
|
|
15
|
+
override: Partial<GradientConfig> | undefined,
|
|
16
|
+
appConfig: ReturnType<typeof useAppConfig>
|
|
17
|
+
): GradientConfig {
|
|
18
|
+
return mergeGradientOverride(resolveGradientPreset(raw, appConfig), override)
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return
|
|
21
|
+
function resolveGradientPreset(
|
|
22
|
+
raw: GradientConfig | string,
|
|
23
|
+
appConfig: ReturnType<typeof useAppConfig>
|
|
24
|
+
): GradientConfig {
|
|
25
|
+
if (typeof raw !== 'string') return raw
|
|
26
|
+
|
|
27
|
+
return resolveGradientPresetByName(raw, getGradientPresetMap(appConfig))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getGradientPresetMap(appConfig: ReturnType<typeof useAppConfig>) {
|
|
31
|
+
return (appConfig.uiLayer as Record<string, unknown> | undefined)?.['gradients'] as
|
|
32
|
+
| Record<string, GradientConfig>
|
|
33
|
+
| undefined
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
function resolveGradientPresetByName(
|
|
37
|
+
name: string,
|
|
38
|
+
presets: Record<string, GradientConfig> | undefined
|
|
39
|
+
) {
|
|
40
|
+
return presets?.[name] ?? DEFAULT_CONFIG
|
|
41
|
+
}
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
const dir = DIRECTION_MAP[cfg.direction ?? 'to-br'] ?? 'to bottom right'
|
|
49
|
-
return { backgroundImage: `linear-gradient(${dir}, ${stops})` }
|
|
43
|
+
function mergeGradientOverride(
|
|
44
|
+
resolved: GradientConfig,
|
|
45
|
+
override: Partial<GradientConfig> | undefined
|
|
46
|
+
): GradientConfig {
|
|
47
|
+
return override ? { ...resolved, ...override } : resolved
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
export function useGradient(
|
|
@@ -58,18 +56,7 @@ export function useGradient(
|
|
|
58
56
|
const style = computed((): CSSProperties => {
|
|
59
57
|
const raw = toValue(config)
|
|
60
58
|
const override = overrides ? toValue(overrides) : undefined
|
|
61
|
-
|
|
62
|
-
const presets = (appConfig.uiLayer as Record<string, unknown> | undefined)?.['gradients'] as
|
|
63
|
-
| Record<string, GradientConfig>
|
|
64
|
-
| undefined
|
|
65
|
-
let resolved: GradientConfig =
|
|
66
|
-
typeof raw === 'string' ? (presets?.[raw] ?? DEFAULT_CONFIG) : raw
|
|
67
|
-
|
|
68
|
-
if (override) {
|
|
69
|
-
resolved = { ...resolved, ...override }
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return buildStyle(resolved)
|
|
59
|
+
return buildGradientStyle(resolveGradientConfig(raw, override, appConfig))
|
|
73
60
|
})
|
|
74
61
|
|
|
75
62
|
return { style }
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import type { MaybeRefOrGetter } from 'vue'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
BREAKPOINT_VALUES,
|
|
5
|
-
DEVICE_BREAKPOINT_VALUES,
|
|
6
|
-
PHONE_BREAKPOINT_VALUES,
|
|
7
|
-
TABLET_BREAKPOINT_VALUES,
|
|
8
|
-
} from '../types/breakpoints'
|
|
9
3
|
import type { PictureProps, ResponsiveSizes, UsePictureReturn } from '../types/media'
|
|
4
|
+
import { buildResponsiveSizesQueries } from '../utils/responsiveSizes'
|
|
10
5
|
|
|
11
6
|
/**
|
|
12
7
|
* Convert ResponsiveSizes object to CSS sizes attribute string
|
|
@@ -32,79 +27,7 @@ import type { PictureProps, ResponsiveSizes, UsePictureReturn } from '../types/m
|
|
|
32
27
|
* ```
|
|
33
28
|
*/
|
|
34
29
|
function responsiveSizesToString(sizes: ResponsiveSizes): string {
|
|
35
|
-
|
|
36
|
-
const breakpointEntries: Array<{ key: keyof ResponsiveSizes; value: number }> = []
|
|
37
|
-
|
|
38
|
-
// Add Tailwind breakpoints
|
|
39
|
-
const tailwindBreakpoints: Array<keyof typeof BREAKPOINT_VALUES> = ['2xl', 'xl', 'lg', 'md', 'sm']
|
|
40
|
-
for (const bp of tailwindBreakpoints) {
|
|
41
|
-
if (sizes[bp]) {
|
|
42
|
-
breakpointEntries.push({ key: bp, value: BREAKPOINT_VALUES[bp] })
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Add device breakpoints (skip mobile as it's 0px - handled by default)
|
|
47
|
-
const deviceBreakpoints: Array<keyof typeof DEVICE_BREAKPOINT_VALUES> = [
|
|
48
|
-
'wide',
|
|
49
|
-
'desktop',
|
|
50
|
-
'tablet',
|
|
51
|
-
]
|
|
52
|
-
for (const bp of deviceBreakpoints) {
|
|
53
|
-
if (sizes[bp]) {
|
|
54
|
-
breakpointEntries.push({ key: bp, value: DEVICE_BREAKPOINT_VALUES[bp] })
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Add phone breakpoints
|
|
59
|
-
const phoneBreakpoints: Array<keyof typeof PHONE_BREAKPOINT_VALUES> = [
|
|
60
|
-
'phone-lg',
|
|
61
|
-
'phone-md',
|
|
62
|
-
'phone-sm',
|
|
63
|
-
]
|
|
64
|
-
for (const bp of phoneBreakpoints) {
|
|
65
|
-
if (sizes[bp]) {
|
|
66
|
-
breakpointEntries.push({ key: bp, value: PHONE_BREAKPOINT_VALUES[bp] })
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Add tablet breakpoints
|
|
71
|
-
const tabletBreakpoints: Array<keyof typeof TABLET_BREAKPOINT_VALUES> = [
|
|
72
|
-
'tablet-lg',
|
|
73
|
-
'tablet-md',
|
|
74
|
-
'tablet-sm',
|
|
75
|
-
]
|
|
76
|
-
for (const bp of tabletBreakpoints) {
|
|
77
|
-
if (sizes[bp]) {
|
|
78
|
-
breakpointEntries.push({ key: bp, value: TABLET_BREAKPOINT_VALUES[bp] })
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Sort by value descending (largest to smallest)
|
|
83
|
-
breakpointEntries.sort((a, b) => b.value - a.value)
|
|
84
|
-
|
|
85
|
-
// Build media queries
|
|
86
|
-
const mediaQueries: string[] = []
|
|
87
|
-
|
|
88
|
-
// Add orientation breakpoints first (these are feature queries, not min-width)
|
|
89
|
-
if (sizes.landscape) {
|
|
90
|
-
mediaQueries.push(`(orientation: landscape) ${sizes.landscape}`)
|
|
91
|
-
}
|
|
92
|
-
if (sizes.portrait) {
|
|
93
|
-
mediaQueries.push(`(orientation: portrait) ${sizes.portrait}`)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Add min-width breakpoints
|
|
97
|
-
for (const entry of breakpointEntries) {
|
|
98
|
-
const size = sizes[entry.key]
|
|
99
|
-
if (size) {
|
|
100
|
-
mediaQueries.push(`(min-width: ${entry.value}px) ${size}`)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Add default size at the end (no media query)
|
|
105
|
-
mediaQueries.push(sizes.default)
|
|
106
|
-
|
|
107
|
-
return mediaQueries.join(', ')
|
|
30
|
+
return buildResponsiveSizesQueries(sizes).join(', ')
|
|
108
31
|
}
|
|
109
32
|
|
|
110
33
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type ResolvableColorToken = {
|
|
2
|
+
color?: string | undefined
|
|
3
|
+
shade?: number | undefined
|
|
4
|
+
opacity?: number | undefined
|
|
5
|
+
customColor?: string | undefined
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// fallow-ignore-next-line complexity
|
|
9
|
+
export function resolveUiColorToken(token: ResolvableColorToken): string {
|
|
10
|
+
const { color = 'primary', shade = 500, opacity, customColor } = token
|
|
11
|
+
|
|
12
|
+
if (color === 'custom') return customColor ?? 'transparent'
|
|
13
|
+
if (color === 'transparent') return 'transparent'
|
|
14
|
+
if (color === 'white') {
|
|
15
|
+
return opacity !== undefined ? `rgb(255 255 255 / ${opacity / 100})` : '#ffffff'
|
|
16
|
+
}
|
|
17
|
+
if (color === 'black') {
|
|
18
|
+
return opacity !== undefined ? `rgb(0 0 0 / ${opacity / 100})` : '#000000'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const value = `var(--ui-color-${color}-${shade})`
|
|
22
|
+
return opacity !== undefined ? `color-mix(in srgb, ${value} ${opacity}%, transparent)` : value
|
|
23
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { CSSProperties } from 'vue'
|
|
2
|
+
|
|
3
|
+
import type { GradientConfig, GradientStop } from '../types/gradient'
|
|
4
|
+
import { resolveUiColorToken } from './colorTokens'
|
|
5
|
+
|
|
6
|
+
const DIRECTION_MAP: Record<string, string> = {
|
|
7
|
+
'to-t': 'to top',
|
|
8
|
+
'to-tr': 'to top right',
|
|
9
|
+
'to-r': 'to right',
|
|
10
|
+
'to-br': 'to bottom right',
|
|
11
|
+
'to-b': 'to bottom',
|
|
12
|
+
'to-bl': 'to bottom left',
|
|
13
|
+
'to-l': 'to left',
|
|
14
|
+
'to-tl': 'to top left',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function resolveGradientColor(stop: GradientStop): string {
|
|
18
|
+
return resolveUiColorToken(stop)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveGradientStops(cfg: GradientConfig) {
|
|
22
|
+
const from = resolveGradientColor(cfg.from)
|
|
23
|
+
const to = resolveGradientColor(cfg.to)
|
|
24
|
+
const via = cfg.via ? resolveGradientColor(cfg.via) : undefined
|
|
25
|
+
return via ? `${from}, ${via}, ${to}` : `${from}, ${to}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// fallow-ignore-next-line complexity
|
|
29
|
+
export function buildGradientStyle(cfg: GradientConfig): CSSProperties {
|
|
30
|
+
const stops = resolveGradientStops(cfg)
|
|
31
|
+
|
|
32
|
+
if (cfg.shape === 'radial') {
|
|
33
|
+
return { backgroundImage: `radial-gradient(circle, ${stops})` }
|
|
34
|
+
}
|
|
35
|
+
if (cfg.shape === 'conic') {
|
|
36
|
+
return { backgroundImage: `conic-gradient(${stops})` }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const direction = DIRECTION_MAP[cfg.direction ?? 'to-br'] ?? 'to bottom right'
|
|
40
|
+
return { backgroundImage: `linear-gradient(${direction}, ${stops})` }
|
|
41
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BREAKPOINT_VALUES,
|
|
3
|
+
DEVICE_BREAKPOINT_VALUES,
|
|
4
|
+
PHONE_BREAKPOINT_VALUES,
|
|
5
|
+
TABLET_BREAKPOINT_VALUES,
|
|
6
|
+
} from '../types/breakpoints'
|
|
7
|
+
|
|
8
|
+
import type { ResponsiveSizes } from '../types/media'
|
|
9
|
+
|
|
10
|
+
type BreakpointGroup = readonly [keyof ResponsiveSizes, number]
|
|
11
|
+
|
|
12
|
+
const BREAKPOINT_GROUPS = [
|
|
13
|
+
['2xl', BREAKPOINT_VALUES['2xl']],
|
|
14
|
+
['xl', BREAKPOINT_VALUES.xl],
|
|
15
|
+
['lg', BREAKPOINT_VALUES.lg],
|
|
16
|
+
['md', BREAKPOINT_VALUES.md],
|
|
17
|
+
['sm', BREAKPOINT_VALUES.sm],
|
|
18
|
+
['wide', DEVICE_BREAKPOINT_VALUES.wide],
|
|
19
|
+
['desktop', DEVICE_BREAKPOINT_VALUES.desktop],
|
|
20
|
+
['tablet', DEVICE_BREAKPOINT_VALUES.tablet],
|
|
21
|
+
['phone-lg', PHONE_BREAKPOINT_VALUES['phone-lg']],
|
|
22
|
+
['phone-md', PHONE_BREAKPOINT_VALUES['phone-md']],
|
|
23
|
+
['phone-sm', PHONE_BREAKPOINT_VALUES['phone-sm']],
|
|
24
|
+
['tablet-lg', TABLET_BREAKPOINT_VALUES['tablet-lg']],
|
|
25
|
+
['tablet-md', TABLET_BREAKPOINT_VALUES['tablet-md']],
|
|
26
|
+
['tablet-sm', TABLET_BREAKPOINT_VALUES['tablet-sm']],
|
|
27
|
+
] as const satisfies readonly BreakpointGroup[]
|
|
28
|
+
|
|
29
|
+
// fallow-ignore-next-line complexity
|
|
30
|
+
export function buildResponsiveSizesQueries(sizes: ResponsiveSizes): string[] {
|
|
31
|
+
const breakpoints = BREAKPOINT_GROUPS.filter(([key]) => sizes[key])
|
|
32
|
+
.map(([key, value]) => ({ key, value }))
|
|
33
|
+
.sort((a, b) => b.value - a.value)
|
|
34
|
+
|
|
35
|
+
const queries: string[] = []
|
|
36
|
+
|
|
37
|
+
if (sizes.landscape) queries.push(`(orientation: landscape) ${sizes.landscape}`)
|
|
38
|
+
if (sizes.portrait) queries.push(`(orientation: portrait) ${sizes.portrait}`)
|
|
39
|
+
|
|
40
|
+
for (const breakpoint of breakpoints) {
|
|
41
|
+
const size = sizes[breakpoint.key]
|
|
42
|
+
if (size) {
|
|
43
|
+
queries.push(`(min-width: ${breakpoint.value}px) ${size}`)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
queries.push(sizes.default)
|
|
48
|
+
return queries
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kmcom-nuxt-layers",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.13",
|
|
5
5
|
"description": "Composable Nuxt 4 layers for building scalable Vue applications",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./layers/core": "./layers/core/nuxt.config.ts",
|
|
@@ -139,16 +139,20 @@
|
|
|
139
139
|
"@nuxt/eslint": "^1.15.2",
|
|
140
140
|
"@nuxt/fonts": "^0.14.0",
|
|
141
141
|
"@nuxt/image": "^2.0.0",
|
|
142
|
+
"@nuxt/test-utils": "^4.0.3",
|
|
143
|
+
"@playwright/test": "1.61.0",
|
|
142
144
|
"@nuxt/ui": "latest",
|
|
143
145
|
"@nuxtjs/device": "^4.0.0",
|
|
144
146
|
"@oxc-parser/binding-darwin-arm64": "^0.134.0",
|
|
145
147
|
"@perplex-digital/stylelint-config": "^17.4.0",
|
|
146
148
|
"@pinia/nuxt": "^0.11.3",
|
|
149
|
+
"@vitejs/plugin-vue": "^6.0.7",
|
|
147
150
|
"@types/node": "^25.9.1",
|
|
148
151
|
"@types/three": "^0.184.1",
|
|
149
152
|
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
|
150
153
|
"@typescript-eslint/parser": "^8.60.1",
|
|
151
154
|
"@vue/eslint-config-typescript": "^14.7.0",
|
|
155
|
+
"@vue/test-utils": "^2.4.10",
|
|
152
156
|
"@vueuse/core": "^14.3.0",
|
|
153
157
|
"@vueuse/nuxt": "^14.3.0",
|
|
154
158
|
"@webgpu/glslang": "^0.0.15",
|
|
@@ -167,11 +171,11 @@
|
|
|
167
171
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
168
172
|
"eslint-plugin-vue": "^10.9.2",
|
|
169
173
|
"fallow": "^2.92.1",
|
|
174
|
+
"happy-dom": "^20.10.3",
|
|
170
175
|
"netlify-cli": "^26.1.0",
|
|
171
176
|
"npm-check-updates": "^22.2.2",
|
|
172
177
|
"nuxt": "^4.4.7",
|
|
173
178
|
"pinia": "^3.0.4",
|
|
174
|
-
"playwright": "^1.60.0",
|
|
175
179
|
"postcss-html": "^1.8.1",
|
|
176
180
|
"prettier": "^3.8.3",
|
|
177
181
|
"prettier-plugin-css-order": "^2.2.0",
|
|
@@ -201,11 +205,11 @@
|
|
|
201
205
|
"last 2 Chrome major versions",
|
|
202
206
|
"last 2 Firefox major versions",
|
|
203
207
|
"last 2 Safari major versions",
|
|
204
|
-
"last 2 Edge major versions"
|
|
208
|
+
"last 2 Edge major versions",
|
|
209
|
+
"baseline widely available"
|
|
205
210
|
],
|
|
206
211
|
"dependencies": {
|
|
207
212
|
"node-gyp": "^12.3.0",
|
|
208
|
-
"pnpm": "11.5.3",
|
|
209
213
|
"skills": "^1.5.10"
|
|
210
214
|
},
|
|
211
215
|
"engines": {
|
|
@@ -213,7 +217,7 @@
|
|
|
213
217
|
},
|
|
214
218
|
"volta": {
|
|
215
219
|
"node": "24.16.0",
|
|
216
|
-
"pnpm": "11.5.
|
|
220
|
+
"pnpm": "11.5.3"
|
|
217
221
|
},
|
|
218
222
|
"scripts": {
|
|
219
223
|
"dev": "pnpm -F playground dev",
|
|
@@ -232,6 +236,14 @@
|
|
|
232
236
|
"fix:layer": "f(){ pnpm turbo run lint --filter \"./layers/$1\" -- --fix && prettier --write \"layers/$1\"; }; f",
|
|
233
237
|
"fix:app": "f(){ pnpm turbo run lint --filter \"./apps/$1\" -- --fix && prettier --write \"apps/$1\"; }; f",
|
|
234
238
|
"typecheck": "vue-tsc --noEmit -p tsconfig.typecheck.json",
|
|
239
|
+
"test": "vitest run",
|
|
240
|
+
"test:watch": "vitest",
|
|
241
|
+
"test:unit": "vitest run --project unit",
|
|
242
|
+
"test:vitest": "vitest run --project vitest",
|
|
243
|
+
"test:vue": "vitest run --project vue",
|
|
244
|
+
"test:nuxt": "vitest run --project nuxt",
|
|
245
|
+
"test:playwright": "playwright test",
|
|
246
|
+
"test:e2e": "playwright test",
|
|
235
247
|
"clean": "pnpm -r exec rm -rf node_modules .nuxt .output .data && pnpm store prune && pnpm install",
|
|
236
248
|
"cleancache": "pnpm store prune --force",
|
|
237
249
|
"update": "ncu -i",
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export default defineEventHandler((event) => {
|
|
2
|
-
const appConfig = useAppConfig()
|
|
3
|
-
const feedConfig = appConfig.feedsLayer?.feed ?? {}
|
|
4
|
-
const collections: string[] = feedConfig.collections ?? ['blog']
|
|
5
|
-
|
|
6
|
-
const requestUrl = getRequestURL(event)
|
|
7
|
-
// Always use the request origin so discovery URLs are reachable from wherever
|
|
8
|
-
// the request came from, not the configured canonical site URL.
|
|
9
|
-
const baseUrl = `${requestUrl.protocol}//${requestUrl.host}`
|
|
10
|
-
|
|
11
|
-
setHeader(event, 'Cache-Control', 'public, max-age=300, s-maxage=3600')
|
|
12
|
-
|
|
13
|
-
const formats = [
|
|
14
|
-
{ format: 'RSS 2.0', ext: 'rss', contentType: 'application/rss+xml' },
|
|
15
|
-
{ format: 'Atom 1.0', ext: 'atom', contentType: 'application/atom+xml' },
|
|
16
|
-
{ format: 'JSON Feed 1.1', ext: 'json', contentType: 'application/feed+json' },
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
feeds: collections.flatMap((collection) =>
|
|
21
|
-
formats.map(({ format, ext, contentType }) => ({
|
|
22
|
-
collection,
|
|
23
|
-
format,
|
|
24
|
-
url: `${baseUrl}/feed/${collection}/${ext}`,
|
|
25
|
-
contentType,
|
|
26
|
-
}))
|
|
27
|
-
),
|
|
28
|
-
}
|
|
29
|
-
})
|