kmcom-nuxt-layers 6.4.0 → 6.5.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.
Files changed (129) hide show
  1. package/docs/MIGRATION-v6.5.0.md +87 -0
  2. package/docs/MIGRATION.md +2 -1
  3. package/docs/USAGE.md +35 -10
  4. package/layers/content/app/components/content/Figure.vue +1 -1
  5. package/layers/content/app/composables/useContentSection.ts +1 -1
  6. package/layers/core/app/app.config.ts +7 -3
  7. package/layers/core/app/components/LoadingScreen.vue +35 -21
  8. package/layers/core/app/composables/useCache.ts +2 -2
  9. package/layers/core/app/composables/useErrorLog.ts +5 -5
  10. package/layers/core/app/composables/useLoading.ts +19 -10
  11. package/layers/core/app/plugins/loading.client.ts +11 -3
  12. package/layers/core/app/types/loading.ts +10 -3
  13. package/layers/core/app/utils/loading.ts +6 -15
  14. package/layers/core/nuxt.config.ts +14 -14
  15. package/layers/core/server/utils/app-config.ts +17 -0
  16. package/layers/data/auth/app/middleware/auth.ts +1 -1
  17. package/layers/data/forms/app/components/Form/Contact.vue +1 -1
  18. package/layers/data/forms/server/api/contact.post.ts +16 -8
  19. package/layers/data/forms/server/api/forms/status.get.ts +3 -0
  20. package/layers/data/forms/{app → shared}/utils/contact-schema.ts +2 -1
  21. package/layers/data/metadata/server/api/metadata/search.get.ts +27 -7
  22. package/layers/data/metadata/server/api/metadata/status.get.ts +4 -1
  23. package/layers/data/metadata/server/api/metadata/sync.post.ts +13 -3
  24. package/layers/data/metadata/server/utils/metadata/resolve-record.ts +3 -3
  25. package/layers/delivery/feeds/nuxt.config.ts +6 -1
  26. package/layers/delivery/feeds/package.json +2 -2
  27. package/layers/delivery/feeds/server/routes/feed/demo.get.ts +2 -2
  28. package/layers/delivery/feeds/server/utils/content-adapter.ts +1 -1
  29. package/layers/delivery/feeds/server/utils/feed-service.ts +2 -2
  30. package/layers/design-system/theming/app/plugins/theme.client.ts +7 -0
  31. package/layers/design-system/theming/nuxt.config.ts +0 -2
  32. package/layers/motion/scroll/app/plugins/locomotive-scroll.client.ts +3 -2
  33. package/layers/render/canvas/nuxt.config.ts +0 -4
  34. package/layers/render/shader/nuxt.config.ts +0 -4
  35. package/layers/structure/routing/app/middleware/01.maintenance.global.ts +4 -1
  36. package/layers/structure/routing/app/middleware/02.governance.global.ts +1 -1
  37. package/layers/structure/routing/nuxt.config.ts +19 -12
  38. package/layers/structure/routing/server/api/feature-flags.get.ts +4 -2
  39. package/package.json +35 -5
  40. package/docs/FALLOW-COMPLEXITY-DUPLICATION-AUDIT.md +0 -64
  41. package/docs/IMPROVE-AUDIT-README.md +0 -29
  42. package/docs/IMPROVE-AUDIT-RESULTS.md +0 -51
  43. package/docs/IMPROVE-DEEP-AUDIT-RESULTS.md +0 -81
  44. package/docs/fallow-refactor/apps-debug.md +0 -27
  45. package/docs/fallow-refactor/apps-playground.md +0 -46
  46. package/docs/fallow-refactor/apps-visual-identity.md +0 -41
  47. package/docs/fallow-refactor/layers-animations.md +0 -34
  48. package/docs/fallow-refactor/layers-canvas.md +0 -32
  49. package/docs/fallow-refactor/layers-content.md +0 -33
  50. package/docs/fallow-refactor/layers-core.md +0 -39
  51. package/docs/fallow-refactor/layers-feeds.md +0 -39
  52. package/docs/fallow-refactor/layers-forms.md +0 -30
  53. package/docs/fallow-refactor/layers-layout.md +0 -42
  54. package/docs/fallow-refactor/layers-mailer.md +0 -32
  55. package/docs/fallow-refactor/layers-motion.md +0 -27
  56. package/docs/fallow-refactor/layers-navigation.md +0 -31
  57. package/docs/fallow-refactor/layers-page-transitions.md +0 -30
  58. package/docs/fallow-refactor/layers-routing.md +0 -33
  59. package/docs/fallow-refactor/layers-scripts.md +0 -35
  60. package/docs/fallow-refactor/layers-scroll.md +0 -38
  61. package/docs/fallow-refactor/layers-seo.md +0 -32
  62. package/docs/fallow-refactor/layers-shader.md +0 -53
  63. package/docs/fallow-refactor/layers-theme.md +0 -33
  64. package/docs/fallow-refactor/layers-transitions.md +0 -27
  65. package/docs/fallow-refactor/layers-typography.md +0 -29
  66. package/docs/fallow-refactor/layers-visual.md +0 -34
  67. package/docs/superpowers/plans/2026-09-03-layout-layer-fluid-rebuild.md +0 -1850
  68. package/docs/superpowers/plans/2026-09-03-vue-element-system.md +0 -1019
  69. package/docs/superpowers/plans/2026-09-04-grid-layer.md +0 -977
  70. package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-0-1-design.md +0 -533
  71. package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-2-design.md +0 -154
  72. package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-3-design.md +0 -109
  73. package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-4-design.md +0 -124
  74. package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-5-design.md +0 -121
  75. package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-6-design.md +0 -77
  76. package/docs/superpowers/specs/2026-08-30-layer-taxonomy-tier-7-design.md +0 -73
  77. package/docs/superpowers/specs/2026-08-31-swiss-grid-layer-design.md +0 -190
  78. package/docs/superpowers/specs/2026-09-03-layout-layer-fluid-rebuild-design.md +0 -312
  79. package/docs/superpowers/specs/2026-09-03-vue-element-system-design.md +0 -342
  80. package/docs/superpowers/specs/2026-09-04-grid-layer-design.md +0 -236
  81. package/layers/content/app/utils/galleryImageMeta.test.ts +0 -30
  82. package/layers/core/app/components/Element.test.ts +0 -90
  83. package/layers/core/app/components/ElementTw.test.ts +0 -64
  84. package/layers/core/app/composables/useLayoutAttrs.test.ts +0 -77
  85. package/layers/core/app/utils/browserInfo.test.ts +0 -81
  86. package/layers/core/app/utils/featureClasses.test.ts +0 -101
  87. package/layers/core/app/utils/loading.test.ts +0 -48
  88. package/layers/core/app/utils/resolveElementStyle.test.ts +0 -99
  89. package/layers/core/app/utils/scrollGuardClamp.test.ts +0 -36
  90. package/layers/core/app/utils/styleToTailwindClasses.test.ts +0 -31
  91. package/layers/data/forms/app/utils/contact-schema.test.ts +0 -75
  92. package/layers/data/forms/app/utils/fieldProps.test.ts +0 -141
  93. package/layers/data/metadata/providers/comicvine/server/utils/metadata-comicvine/normalise.test.ts +0 -201
  94. package/layers/data/metadata/providers/google-books/server/utils/metadata-google-books/client.test.ts +0 -76
  95. package/layers/data/metadata/providers/google-books/server/utils/metadata-google-books/normalise.test.ts +0 -144
  96. package/layers/data/metadata/providers/openlibrary/server/utils/metadata-openlibrary/client.test.ts +0 -25
  97. package/layers/data/metadata/providers/openlibrary/server/utils/metadata-openlibrary/normalise.test.ts +0 -144
  98. package/layers/data/metadata/providers/themoviedb/server/utils/metadata-tmdb/client.test.ts +0 -29
  99. package/layers/data/metadata/providers/themoviedb/server/utils/metadata-tmdb/normalise.test.ts +0 -162
  100. package/layers/data/metadata/server/utils/metadata/cache.test.ts +0 -39
  101. package/layers/data/metadata/server/utils/metadata/provider-fetch.test.ts +0 -27
  102. package/layers/data/metadata/server/utils/metadata/provider-registry.test.ts +0 -54
  103. package/layers/data/metadata/server/utils/metadata/resolve-record.test.ts +0 -87
  104. package/layers/data/metadata/server/utils/metadata/search.test.ts +0 -204
  105. package/layers/delivery/feeds/server/utils/content-adapter.test.ts +0 -67
  106. package/layers/delivery/feeds/server/utils/feed-author.test.ts +0 -71
  107. package/layers/delivery/feeds/server/utils/feed-config.test.ts +0 -184
  108. package/layers/delivery/feeds/server/utils/formats.test.ts +0 -71
  109. package/layers/delivery/seo/app/utils/seoConfig.test.ts +0 -58
  110. package/layers/design-system/theming/server/utils/accent-css.test.ts +0 -71
  111. package/layers/design-system/theming/server/utils/fouc-config.test.ts +0 -78
  112. package/layers/design-system/typography/app/components/Typography/Headline.test.ts +0 -36
  113. package/layers/design-system/typography/app/components/Typography/index.test.ts +0 -31
  114. package/layers/design-system/typography/app/composables/color.test.ts +0 -30
  115. package/layers/design-system/typography/app/composables/typography.test.ts +0 -53
  116. package/layers/design-system/visual/app/components/HoverDimGroup.test.ts +0 -38
  117. package/layers/design-system/visual/app/composables/tint.test.ts +0 -22
  118. package/layers/design-system/visual/app/utils/colorTokens.test.ts +0 -51
  119. package/layers/design-system/visual/app/utils/gradientStyle.test.ts +0 -75
  120. package/layers/design-system/visual/app/utils/responsiveSizes.test.ts +0 -71
  121. package/layers/motion/animations/app/components/Motion/Staggered.test.ts +0 -40
  122. package/layers/motion/scroll/app/composables/useReducedMotion.test.ts +0 -23
  123. package/layers/motion/scroll/app/utils/parallax.test.ts +0 -24
  124. package/layers/structure/grid/app/composables/useGridTracks.test.ts +0 -94
  125. package/layers/structure/grid/app/types/tracks.test.ts +0 -32
  126. package/layers/structure/grid/app/utils/placement.test.ts +0 -19
  127. package/layers/structure/layout/app/utils/gridPlacementStyle.test.ts +0 -269
  128. package/layers/structure/navigation/app/utils/site.test.ts +0 -39
  129. package/layers/structure/routing/app/utils/resolveRoute.test.ts +0 -47
@@ -1,94 +0,0 @@
1
- import { describe, expect, it } from 'vite-plus/test'
2
-
3
- import type { GridPreset, TrackConfig } from '../types/tracks'
4
- import { resolve, toColumnsCss } from './useGridTracks'
5
-
6
- describe('toColumnsCss', () => {
7
- it('renders equal segments with no line names', () => {
8
- const config: TrackConfig = { columns: [{ size: 1 }, { size: 1 }, { size: 1 }] }
9
- expect(toColumnsCss(config)).toBe(
10
- 'minmax(var(--measure-min), 1fr) minmax(var(--measure-min), 1fr) ' +
11
- 'minmax(var(--measure-min), 1fr)'
12
- )
13
- })
14
-
15
- it('renders mixed sizes (8 equal + double + triple)', () => {
16
- const config: TrackConfig = {
17
- columns: [
18
- { size: 1 },
19
- { size: 1 },
20
- { size: 1 },
21
- { size: 1 },
22
- { size: 1 },
23
- { size: 1 },
24
- { size: 1 },
25
- { size: 2 },
26
- { size: 3 },
27
- ],
28
- }
29
- const css = toColumnsCss(config)
30
- expect(css.split(' ').filter((s) => s.startsWith('minmax'))).toHaveLength(9)
31
- expect(css).toContain('minmax(var(--measure-min), 2fr)')
32
- expect(css).toContain('minmax(var(--measure-min), 3fr)')
33
- })
34
-
35
- it('brackets a leading lineStart and trailing lineEnd', () => {
36
- const config: TrackConfig = {
37
- columns: [{ size: 1, lineStart: 'a-start', lineEnd: 'a-end' }],
38
- }
39
- expect(toColumnsCss(config)).toBe('[a-start] minmax(var(--measure-min), 1fr) [a-end]')
40
- })
41
-
42
- it('merges an adjacent lineEnd and lineStart into one bracket', () => {
43
- const config: TrackConfig = {
44
- columns: [
45
- { size: 2, lineStart: 'feature-start', lineEnd: 'feature-end' },
46
- { size: 1, lineStart: 'aside-start', lineEnd: 'aside-end' },
47
- ],
48
- }
49
- expect(toColumnsCss(config)).toBe(
50
- '[feature-start] minmax(var(--measure-min), 2fr) ' +
51
- '[feature-end aside-start] minmax(var(--measure-min), 1fr) [aside-end]'
52
- )
53
- })
54
-
55
- it('supports a segment with only lineStart set', () => {
56
- const config: TrackConfig = {
57
- columns: [{ size: 1, lineStart: 'only-start' }, { size: 1 }],
58
- }
59
- expect(toColumnsCss(config)).toBe(
60
- '[only-start] minmax(var(--measure-min), 1fr) minmax(var(--measure-min), 1fr)'
61
- )
62
- })
63
-
64
- it('accepts an array of line names', () => {
65
- const config: TrackConfig = {
66
- columns: [{ size: 1, lineStart: ['a', 'b'] }],
67
- }
68
- expect(toColumnsCss(config)).toBe('[a b] minmax(var(--measure-min), 1fr)')
69
- })
70
-
71
- it('uses minTrackWidth override instead of the --measure-min default', () => {
72
- const config: TrackConfig = { columns: [{ size: 1 }], minTrackWidth: '20rem' }
73
- expect(toColumnsCss(config)).toBe('minmax(20rem, 1fr)')
74
- })
75
- })
76
-
77
- describe('resolve', () => {
78
- const presets: Record<string, GridPreset> = {
79
- swiss: { name: 'swiss', columns: [{ size: 1 }] },
80
- }
81
-
82
- it('looks up a named preset from the registry', () => {
83
- expect(resolve('swiss', presets)).toBe(presets.swiss)
84
- })
85
-
86
- it('throws for an unknown preset name', () => {
87
- expect(() => resolve('nope', presets)).toThrow('Unknown grid preset: "nope"')
88
- })
89
-
90
- it('passes a TrackConfig object through unchanged', () => {
91
- const custom: TrackConfig = { columns: [{ size: 1 }, { size: 2 }] }
92
- expect(resolve(custom, presets)).toBe(custom)
93
- })
94
- })
@@ -1,32 +0,0 @@
1
- import { describe, expect, it } from 'vite-plus/test'
2
-
3
- import type { GridPreset, TrackConfig, TrackSegment } from './tracks'
4
-
5
- describe('track types', () => {
6
- it('accepts a minimal equal-width segment', () => {
7
- const segment: TrackSegment = { size: 1 }
8
- expect(segment.size).toBe(1)
9
- })
10
-
11
- it('accepts a segment with named lines', () => {
12
- const segment: TrackSegment = {
13
- size: 2,
14
- lineStart: 'feature-start',
15
- lineEnd: ['feature-end', 'aside-start'],
16
- }
17
- expect(segment.lineEnd).toEqual(['feature-end', 'aside-start'])
18
- })
19
-
20
- it('accepts a TrackConfig with optional minTrackWidth', () => {
21
- const config: TrackConfig = {
22
- columns: [{ size: 1 }, { size: 2 }],
23
- minTrackWidth: '20rem',
24
- }
25
- expect(config.columns).toHaveLength(2)
26
- })
27
-
28
- it('a GridPreset is a named TrackConfig', () => {
29
- const preset: GridPreset = { name: 'swiss', columns: [{ size: 1 }] }
30
- expect(preset.name).toBe('swiss')
31
- })
32
- })
@@ -1,19 +0,0 @@
1
- import { describe, expect, it } from 'vite-plus/test'
2
-
3
- import { placementFromIndex, placementFromLines } from './placement'
4
-
5
- describe('placementFromLines', () => {
6
- it('joins two named lines with a slash', () => {
7
- expect(placementFromLines('feature-start', 'aside-end')).toBe('feature-start / aside-end')
8
- })
9
- })
10
-
11
- describe('placementFromIndex', () => {
12
- it('builds a numeric span from colStart and colSpan', () => {
13
- expect(placementFromIndex(2, 3)).toBe('2 / span 3')
14
- })
15
-
16
- it('spans to the last line when colSpan is "full"', () => {
17
- expect(placementFromIndex(4, 'full')).toBe('4 / -1')
18
- })
19
- })
@@ -1,269 +0,0 @@
1
- import { describe, expect, it } from 'vite-plus/test'
2
-
3
- import {
4
- buildGridPlacementClasses,
5
- buildGridPlacementStyle,
6
- layerZIndex,
7
- resolveAlignmentStyles,
8
- resolveBleedStyles,
9
- resolveDefaultPlacement,
10
- resolveLayerStyles,
11
- resolveResponsivePlacementVars,
12
- resolveRhythmStyles,
13
- } from './gridPlacementStyle'
14
-
15
- describe('layerZIndex map', () => {
16
- it('assigns ascending z-index values', () => {
17
- expect(layerZIndex).toEqual({ back: 0, mid: 10, front: 20, top: 30 })
18
- })
19
- })
20
-
21
- describe('resolveDefaultPlacement', () => {
22
- it('returns the fallback when value is undefined', () => {
23
- expect(resolveDefaultPlacement(undefined, 'full')).toBe('full')
24
- expect(resolveDefaultPlacement<number>(undefined, undefined)).toBeUndefined()
25
- })
26
-
27
- it('returns the plain value unchanged', () => {
28
- expect(resolveDefaultPlacement(3, undefined)).toBe(3)
29
- expect(resolveDefaultPlacement<string>('full', 'other')).toBe('full')
30
- })
31
-
32
- it('unwraps a responsive value default', () => {
33
- expect(resolveDefaultPlacement({ default: 2, md: 4 }, undefined)).toBe(2)
34
- })
35
- })
36
-
37
- describe('resolveResponsivePlacementVars', () => {
38
- it('returns no vars for a plain value', () => {
39
- expect(resolveResponsivePlacementVars(3, 'cs')).toEqual({})
40
- })
41
-
42
- it('returns no vars when value is undefined', () => {
43
- expect(resolveResponsivePlacementVars(undefined, 'cs')).toEqual({})
44
- })
45
-
46
- it('sets only the md var when only md is provided', () => {
47
- expect(resolveResponsivePlacementVars({ default: 1, md: 2 }, 'cs')).toEqual({
48
- '--_md-cs': '2',
49
- })
50
- })
51
-
52
- it('sets only the lg var when only lg is provided', () => {
53
- expect(resolveResponsivePlacementVars({ default: 1, lg: 5 }, 're')).toEqual({
54
- '--_lg-re': '5',
55
- })
56
- })
57
-
58
- it('sets both md and lg vars when both are provided', () => {
59
- expect(resolveResponsivePlacementVars({ default: 1, md: 2, lg: 5 }, 'ce')).toEqual({
60
- '--_md-ce': '2',
61
- '--_lg-ce': '5',
62
- })
63
- })
64
- })
65
-
66
- describe('resolveBleedStyles', () => {
67
- it('returns no styles when bleed is not set', () => {
68
- expect(resolveBleedStyles({})).toEqual({})
69
- })
70
-
71
- it('handles "both" bleed direction', () => {
72
- expect(resolveBleedStyles({ bleed: 'both', rowStart: 1, rowSpan: 3 })).toEqual({
73
- gridColumn: '1 / -1',
74
- marginInline: 'calc(-1 * var(--grid-padding))',
75
- gridRow: '1 / span 3',
76
- })
77
- })
78
-
79
- it('handles "left" bleed direction with a numeric colSpan', () => {
80
- expect(resolveBleedStyles({ bleed: 'left', colSpan: 4, rowStart: 2, rowSpan: 1 })).toEqual({
81
- gridColumn: '1 / span 4',
82
- marginInlineStart: 'calc(-1 * var(--grid-padding))',
83
- gridRow: '2 / span 1',
84
- })
85
- })
86
-
87
- it('handles "left" bleed direction without a numeric colSpan', () => {
88
- expect(resolveBleedStyles({ bleed: 'left', colSpan: 'full', rowSpan: 1 })).toEqual({
89
- gridColumn: '1 / -1',
90
- marginInlineStart: 'calc(-1 * var(--grid-padding))',
91
- gridRow: 'auto / span 1',
92
- })
93
- })
94
-
95
- it('handles "right" bleed direction', () => {
96
- expect(resolveBleedStyles({ bleed: 'right', colStart: 3, rowSpan: 2 })).toEqual({
97
- gridColumn: '3 / -1',
98
- marginInlineEnd: 'calc(-1 * var(--grid-padding))',
99
- gridRow: 'auto / span 2',
100
- })
101
- })
102
-
103
- it('defaults gridRow parts to "auto" when start/span are missing', () => {
104
- expect(resolveBleedStyles({ bleed: 'right' })).toEqual({
105
- gridColumn: 'auto / -1',
106
- marginInlineEnd: 'calc(-1 * var(--grid-padding))',
107
- gridRow: 'auto / span undefined',
108
- })
109
- })
110
- })
111
-
112
- describe('resolveAlignmentStyles', () => {
113
- it('returns no styles when neither align nor justify is set', () => {
114
- expect(resolveAlignmentStyles()).toEqual({})
115
- })
116
-
117
- it('defaults the missing axis to stretch', () => {
118
- expect(resolveAlignmentStyles('center')).toEqual({
119
- display: 'grid',
120
- width: '100%',
121
- height: '100%',
122
- placeItems: 'center stretch',
123
- })
124
- expect(resolveAlignmentStyles(undefined, 'end')).toEqual({
125
- display: 'grid',
126
- width: '100%',
127
- height: '100%',
128
- placeItems: 'stretch end',
129
- })
130
- })
131
-
132
- it('combines align and justify', () => {
133
- expect(resolveAlignmentStyles('start', 'end')).toEqual({
134
- display: 'grid',
135
- width: '100%',
136
- height: '100%',
137
- placeItems: 'start end',
138
- })
139
- })
140
- })
141
-
142
- describe('resolveRhythmStyles', () => {
143
- it('returns no styles when density is undefined', () => {
144
- expect(resolveRhythmStyles()).toEqual({})
145
- })
146
-
147
- it.each([
148
- ['compact', '0.125rem'],
149
- ['normal', '0.25rem'],
150
- ['relaxed', '0.5rem'],
151
- ] as const)('maps %s density to the expected rhythm value', (density, value) => {
152
- expect(resolveRhythmStyles(density)).toEqual({ '--rhythm': value })
153
- })
154
- })
155
-
156
- describe('resolveLayerStyles', () => {
157
- it('returns no styles when layer is not set', () => {
158
- expect(resolveLayerStyles()).toEqual({})
159
- })
160
-
161
- it('looks up the z-index for the given layer', () => {
162
- expect(resolveLayerStyles('front')).toEqual({ zIndex: '20' })
163
- })
164
- })
165
-
166
- describe('buildGridPlacementStyle', () => {
167
- it('applies defaults for an empty input', () => {
168
- expect(buildGridPlacementStyle({})).toEqual({
169
- gridColumn: '1 / -1',
170
- '--_rs': 'auto',
171
- '--_re': '1',
172
- })
173
- })
174
-
175
- it('returns early for a full colSpan and skips alignment/rhythm/layer/gap', () => {
176
- const style = buildGridPlacementStyle({
177
- colSpan: 'full',
178
- align: 'center',
179
- density: 'compact',
180
- layer: 'front',
181
- gap: '1rem',
182
- })
183
-
184
- expect(style).toEqual({
185
- gridColumn: '1 / -1',
186
- '--_rs': 'auto',
187
- '--_re': '1',
188
- })
189
- expect(style).not.toHaveProperty('zIndex')
190
- expect(style).not.toHaveProperty('--rhythm')
191
- expect(style).not.toHaveProperty('--grid-gap')
192
- })
193
-
194
- it('builds explicit column/row vars for a non-full colSpan and applies alignment/rhythm/layer/gap', () => {
195
- const style = buildGridPlacementStyle({
196
- colStart: 2,
197
- colSpan: 3,
198
- rowStart: 1,
199
- rowSpan: 2,
200
- align: 'center',
201
- justify: 'end',
202
- density: 'relaxed',
203
- layer: 'front',
204
- gap: '2rem',
205
- })
206
-
207
- expect(style).toEqual({
208
- '--_cs': '2',
209
- '--_ce': '3',
210
- '--_rs': '1',
211
- '--_re': '2',
212
- display: 'grid',
213
- width: '100%',
214
- height: '100%',
215
- placeItems: 'center end',
216
- '--rhythm': '0.5rem',
217
- zIndex: '20',
218
- '--grid-gap': '2rem',
219
- })
220
- })
221
-
222
- it('includes responsive vars for responsive-value inputs on a non-full colSpan', () => {
223
- const style = buildGridPlacementStyle({
224
- colStart: { default: 1, md: 2 },
225
- colSpan: { default: 3, lg: 6 },
226
- })
227
-
228
- expect(style['--_md-cs']).toBe('2')
229
- expect(style['--_lg-ce']).toBe('6')
230
- })
231
-
232
- it('applies bleed styles and skips the column/row var block entirely', () => {
233
- const style = buildGridPlacementStyle({
234
- bleed: 'both',
235
- rowStart: 1,
236
- rowSpan: 3,
237
- align: 'start',
238
- })
239
-
240
- expect(style).toEqual({
241
- gridColumn: '1 / -1',
242
- marginInline: 'calc(-1 * var(--grid-padding))',
243
- gridRow: '1 / span 3',
244
- display: 'grid',
245
- width: '100%',
246
- height: '100%',
247
- placeItems: 'start stretch',
248
- })
249
- expect(style).not.toHaveProperty('--_cs')
250
- expect(style).not.toHaveProperty('--_rs')
251
- })
252
-
253
- it('omits --grid-gap when gap is not provided', () => {
254
- const style = buildGridPlacementStyle({ colStart: 1, colSpan: 2 })
255
- expect(style).not.toHaveProperty('--grid-gap')
256
- })
257
- })
258
-
259
- describe('buildGridPlacementClasses', () => {
260
- it('returns the base classes when no container is set', () => {
261
- expect(buildGridPlacementClasses({})).toBe('gi-placed @container @container/item')
262
- })
263
-
264
- it('appends the container class when container is set', () => {
265
- expect(buildGridPlacementClasses({ container: 'wide' })).toBe(
266
- 'gi-placed @container @container/item layout-container-wide'
267
- )
268
- })
269
- })
@@ -1,39 +0,0 @@
1
- import { describe, expect, it } from 'vite-plus/test'
2
-
3
- import { resolveSiteConfig } from './site'
4
-
5
- describe('resolveSiteConfig', () => {
6
- it('defaults title, subtitle, and description to empty values when omitted', () => {
7
- expect(resolveSiteConfig({})).toEqual({
8
- title: '',
9
- titleWords: [''],
10
- subtitle: '',
11
- subtitleWords: [''],
12
- description: '',
13
- })
14
- })
15
-
16
- it('splits the title and subtitle into words', () => {
17
- expect(resolveSiteConfig({ title: 'Nuxt Layers', subtitle: 'Composable Vue apps' })).toEqual({
18
- title: 'Nuxt Layers',
19
- titleWords: ['Nuxt', 'Layers'],
20
- subtitle: 'Composable Vue apps',
21
- subtitleWords: ['Composable', 'Vue', 'apps'],
22
- description: '',
23
- })
24
- })
25
-
26
- it('passes description through unchanged when provided', () => {
27
- expect(resolveSiteConfig({ description: 'A monorepo of Nuxt layers' })).toEqual({
28
- title: '',
29
- titleWords: [''],
30
- subtitle: '',
31
- subtitleWords: [''],
32
- description: 'A monorepo of Nuxt layers',
33
- })
34
- })
35
-
36
- it('handles a single-word title with no spaces', () => {
37
- expect(resolveSiteConfig({ title: 'Solo' }).titleWords).toEqual(['Solo'])
38
- })
39
- })
@@ -1,47 +0,0 @@
1
- import { describe, expect, it } from 'vite-plus/test'
2
-
3
- import type { FeatureValue, RouteResolution, RoutingLayerConfig } from '../types/routing'
4
- import { resolveRoute } from './resolveRoute'
5
-
6
- function createConfig(overrides: Partial<RoutingLayerConfig> = {}): RoutingLayerConfig {
7
- return {
8
- preset: 'marketing',
9
- strictDefaultDeny: false,
10
- layerDefaultDeny: false,
11
- betaRedirect: '/coming-soon',
12
- runtimeFlags: false,
13
- debug: false,
14
- maintenance: { enabled: false, allowRoutes: ['/maintenance'] },
15
- scrollRouting: { enabled: false, mode: 'replace' },
16
- features: {},
17
- ...overrides,
18
- }
19
- }
20
-
21
- describe('resolveRoute', () => {
22
- it('allows routes without a feature by default', () => {
23
- expect(resolveRoute({}, createConfig(), () => 'enabled')).toEqual({ outcome: 'allow' })
24
- })
25
-
26
- it('denies routes when strict default deny is enabled', () => {
27
- expect(resolveRoute({}, createConfig({ strictDefaultDeny: true }), () => 'enabled')).toEqual({
28
- outcome: 'deny',
29
- })
30
- })
31
-
32
- it('denies layer-owned routes without a feature when layer default deny is enabled', () => {
33
- expect(
34
- resolveRoute({ __fromLayer: true }, createConfig({ layerDefaultDeny: true }), () => 'enabled')
35
- ).toEqual({ outcome: 'deny' })
36
- })
37
-
38
- const featureCases: Array<[FeatureValue, RouteResolution]> = [
39
- ['disabled', { outcome: 'deny' }],
40
- ['beta', { outcome: 'redirect', to: '/coming-soon' }],
41
- ['coming-soon', { outcome: 'redirect', to: '/coming-soon' }],
42
- ]
43
-
44
- it.each(featureCases)('handles %s feature variants', (variant, expected) => {
45
- expect(resolveRoute({ feature: 'feature-x' }, createConfig(), () => variant)).toEqual(expected)
46
- })
47
- })