srcdev-nuxt-components 9.4.5 → 9.4.7

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 (104) hide show
  1. package/.claude/commands/migrate-component.md +74 -5
  2. package/.claude/component-ledger/audit.json +1 -1
  3. package/.claude/component-ledger/build.mjs +27 -0
  4. package/.claude/component-ledger/output.html +8 -3
  5. package/.claude/component-ledger/template.html +7 -2
  6. package/.claude/skills/components/breadcrumb.md +1 -0
  7. package/.claude/skills/components/column-flow-grid.md +93 -0
  8. package/.claude/skills/components/content-docs.md +2 -0
  9. package/.claude/skills/components/display-tooltip-defined.md +3 -0
  10. package/.claude/skills/components/display-tooltip.md +1 -0
  11. package/.claude/skills/components/entry-animation.md +88 -0
  12. package/.claude/skills/components/input-copy.md +2 -0
  13. package/.claude/skills/components/input-text-core.md +186 -0
  14. package/.claude/skills/components/marquee-scroller.md +130 -0
  15. package/.claude/skills/components/masonry-grid.md +153 -0
  16. package/.claude/skills/components/navigation-items.md +1 -0
  17. package/.claude/skills/components/pop-over.md +100 -0
  18. package/.claude/skills/components/responsive-header.md +3 -0
  19. package/.claude/skills/components/site-header.md +4 -0
  20. package/.claude/skills/components/site-navigation.md +1 -0
  21. package/.claude/skills/components/tab-navigation.md +1 -0
  22. package/.claude/skills/index.md +7 -1
  23. package/.vscode/srcdev-component-breadcrumb.code-snippets +13 -0
  24. package/.vscode/srcdev-component-column-flow-grid.code-snippets +39 -0
  25. package/.vscode/srcdev-component-content-docs.code-snippets +18 -0
  26. package/.vscode/srcdev-component-display-tooltip-defined.code-snippets +15 -0
  27. package/.vscode/srcdev-component-display-tooltip.code-snippets +11 -0
  28. package/.vscode/srcdev-component-entry-animation.code-snippets +29 -0
  29. package/.vscode/srcdev-component-input-text.code-snippets +107 -0
  30. package/.vscode/srcdev-component-marquee-scroller.code-snippets +93 -0
  31. package/.vscode/srcdev-component-masonry-grid.code-snippets +51 -0
  32. package/.vscode/srcdev-component-pop-over.code-snippets +44 -0
  33. package/.vscode/srcdev-component-responsive-header.code-snippets +12 -0
  34. package/.vscode/srcdev-component-site-header.code-snippets +17 -0
  35. package/.vscode/srcdev-component-site-navigation.code-snippets +30 -0
  36. package/.vscode/srcdev-component-slider-gallery.code-snippets +38 -0
  37. package/.vscode/srcdev-component-tab-navigation.code-snippets +30 -0
  38. package/app/components/01.atoms/animations/entry/EntryAnimation.vue +7 -1
  39. package/app/components/01.atoms/animations/entry/stories/EntryAnimation.stories.ts +47 -0
  40. package/app/components/01.atoms/animations/entry/tests/EntryAnimation.spec.ts +57 -0
  41. package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +94 -0
  42. package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +331 -0
  43. package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +151 -0
  44. package/app/components/01.atoms/animations/marquee-scroller/tests/MarqueeScroller.spec.ts +315 -0
  45. package/app/components/01.atoms/animations/marquee-scroller/tests/__snapshots__/MarqueeScroller.spec.ts.snap +28 -0
  46. package/app/components/01.atoms/canvas-switcher/stories/CanvasSwitcher.stories.ts +9 -10
  47. package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +8 -2
  48. package/app/components/01.atoms/content-wrappers/docs-pages/stories/ContentDocs.stories.ts +12 -13
  49. package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +4 -1
  50. package/app/components/01.atoms/grids/column-flow-grid/CONSUMER-STYLING.md +33 -0
  51. package/app/components/01.atoms/grids/column-flow-grid/ColumnFlowGrid.vue +55 -0
  52. package/app/components/01.atoms/grids/column-flow-grid/stories/ColumnFlowGrid.stories.ts +178 -0
  53. package/app/components/01.atoms/grids/column-flow-grid/tests/ColumnFlowGrid.spec.ts +75 -0
  54. package/app/components/01.atoms/grids/masonry-grid/CONSUMER-STYLING.md +35 -0
  55. package/app/components/01.atoms/grids/masonry-grid/MasonryGrid.vue +178 -0
  56. package/app/components/01.atoms/grids/masonry-grid/stories/MasonryGrid.stories.ts +199 -0
  57. package/app/components/01.atoms/grids/masonry-grid/tests/MasonryGrid.spec.ts +158 -0
  58. package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +4 -1
  59. package/app/components/01.atoms/pop-over/CONSUMER-STYLING.md +54 -0
  60. package/app/components/01.atoms/pop-over/PopOver.vue +201 -0
  61. package/app/components/01.atoms/pop-over/stories/PopOver.stories.ts +141 -0
  62. package/app/components/01.atoms/pop-over/tests/PopOver.spec.ts +195 -0
  63. package/app/components/01.atoms/pop-over/tests/__snapshots__/PopOver.spec.ts.snap +11 -0
  64. package/app/components/02.molecules/action-menu/stories/ActionMenu.stories.ts +8 -2
  65. package/app/components/02.molecules/display-tooltip-defined/DisplayTooltipDefined.vue +16 -3
  66. package/app/components/02.molecules/display-tooltip-defined/tests/__snapshots__/DisplayTooltipDefined.spec.ts.snap +1 -1
  67. package/app/components/02.molecules/input-copy/InputCopy.vue +14 -0
  68. package/app/components/02.molecules/input-copy/stories/InputCopy.stories.ts +15 -0
  69. package/app/components/02.molecules/input-copy/tests/InputCopy.spec.ts +41 -0
  70. package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +4 -1
  71. package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +4 -1
  72. package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +16 -4
  73. package/app/components/03.organisms/responsive-header/NavigationItems.vue +4 -1
  74. package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +16 -3
  75. package/app/components/03.organisms/site-header/SiteHeader.vue +16 -1
  76. package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +1 -1
  77. package/app/components/05.forms/input-select/InputSelectCore.vue +1 -1
  78. package/app/components/05.forms/input-text/InputTextCore.vue +6 -0
  79. package/app/components/05.forms/input-text/stories/InputPasswordWithLabel.stories.ts +49 -20
  80. package/app/components/05.forms/input-text/stories/InputTextAsNumberWithLabel.stories.ts +41 -22
  81. package/app/components/05.forms/input-text/stories/InputTextCore.stories.ts +48 -22
  82. package/app/components/05.forms/input-text/stories/InputTextWithLabel.stories.ts +43 -17
  83. package/app/components/05.forms/input-text/tests/InputPasswordWithLabel.spec.ts +56 -0
  84. package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +61 -0
  85. package/app/components/05.forms/input-text/tests/InputTextCore.spec.ts +60 -0
  86. package/app/components/05.forms/input-text/tests/InputTextWithLabel.spec.ts +46 -0
  87. package/app/components/05.forms/input-text/variants/InputPasswordWithLabel.vue +7 -1
  88. package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +8 -2
  89. package/app/components/05.forms/input-text/variants/InputTextWithLabel.vue +6 -0
  90. package/app/components/05.forms/input-textarea/stories/InputTextareaCore.stories.ts +20 -20
  91. package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +32 -26
  92. package/app/types/components/index.ts +1 -0
  93. package/app/types/components/marquee-scroller.d.ts +10 -0
  94. package/app/types/forms/types.forms.d.ts +1 -1
  95. package/package.json +1 -1
  96. package/app/components/marquee-scroller/MarqueeScroller.vue +0 -289
  97. package/app/components/masonry-grid/MasonryGrid.vue +0 -68
  98. package/app/components/masonry-grid-ordered/MasonryGridOrdered.vue +0 -163
  99. package/app/components/masonry-grid-ordered/MasonryGridOrderedGridExperiment.vue +0 -259
  100. package/app/components/masonry-grid-ordered/stories/MasonryGridOrdered.stories.ts +0 -354
  101. package/app/components/masonry-grid-sorted/MasonryGridSorted.vue +0 -120
  102. package/app/components/pop-over/PopOver.vue +0 -90
  103. package/app/layouts/default.vue +0 -308
  104. package/app/layouts/site-navigation-demo.vue +0 -188
@@ -1,120 +0,0 @@
1
- <template>
2
- <div
3
- class="masonry-grid-wrapper"
4
- :class="[elementClasses]"
5
- :style="`--_masonry-grid-gap: ${gap}${unit}; --_item-min-width: ${itemMinWidth}px`"
6
- ref="gridWrapper"
7
- >
8
- <template v-for="item in rearrangedItems" :key="item.id">
9
- <div class="masonry-grid-item">
10
- <slot :name="item.id"></slot>
11
- </div>
12
- </template>
13
- </div>
14
- </template>
15
-
16
- <script setup lang="ts">
17
- const props = defineProps({
18
- gridData: {
19
- type: Array as PropType<any[]>,
20
- default: () => [],
21
- },
22
- itemMinWidth: {
23
- type: Number,
24
- default: 300,
25
- },
26
- gap: {
27
- type: Number,
28
- default: 1.2,
29
- },
30
- unit: {
31
- type: String,
32
- default: "rem",
33
- },
34
- styleClassPassthrough: {
35
- type: [String, Array] as PropType<string | string[]>,
36
- default: () => [],
37
- },
38
- })
39
-
40
- const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
41
-
42
- const gridData = toRef(() => props.gridData)
43
-
44
- const gridWrapper = ref<HTMLDivElement>()
45
-
46
- const getColumnCountWithinGridWrapper = () => {
47
- return gridWrapper.value ? Math.floor(gridWrapper.value.clientWidth / props.itemMinWidth) : 0
48
- }
49
-
50
- // const columns = ref(4);
51
- const columns = computed(() => {
52
- return gridWrapper.value ? Math.floor(gridWrapper.value.clientWidth / props.itemMinWidth) : 0
53
- })
54
-
55
- const rearrangeArray = (items: any[], columns: number): any[] => {
56
- const rows = Math.ceil(items.length / columns)
57
- const rearrangedArray = []
58
-
59
- for (let col = 0; col < columns; col++) {
60
- for (let row = 0; row < rows; row++) {
61
- const index = row * columns + col
62
- if (index < items.length) {
63
- rearrangedArray.push(items[index])
64
- }
65
- }
66
- }
67
-
68
- return rearrangedArray
69
- }
70
-
71
- const rearrangedItems = computed(() => rearrangeArray(props.gridData, columns.value))
72
- // const rearrangedItems = computed(() => {
73
- // const rows = Math.ceil(props.gridData.length / columns.value);
74
- // const rearrangedArray = [];
75
-
76
- // for (let col = 0; col < columns.value; col++) {
77
- // for (let row = 0; row < rows; row++) {
78
- // const index = row * columns.value + col;
79
- // if (index < props.gridData.length) {
80
- // rearrangedArray.push(props.gridData[index]);
81
- // }
82
- // }
83
- // }
84
-
85
- // return rearrangedArray;
86
- // });
87
-
88
- watch(
89
- () => props.styleClassPassthrough,
90
- () => {
91
- resetElementClasses(props.styleClassPassthrough)
92
- }
93
- )
94
-
95
- // onMounted(() => {
96
- // console.log(getColumnCountWithinGridWrapper());
97
- // });
98
-
99
- // useResizeObserver(gridWrapper, () => {
100
- // console.log(getColumnCountWithinGridWrapper());
101
- // });
102
- </script>
103
-
104
- <style lang="css">
105
- @layer components {
106
- .masonry-grid-wrapper {
107
- --_border-color: light-dark(hsl(0, 29%, 3%), hsl(0, 0%, 92%));
108
-
109
- columns: var(--_item-min-width);
110
- gap: var(--_masonry-grid-gap);
111
-
112
- .masonry-grid-item {
113
- break-inside: avoid;
114
- outline: 0.1rem solid var(--_border-color);
115
- padding: 1.2rem;
116
- margin-block-end: var(--_masonry-grid-gap);
117
- }
118
- }
119
- }
120
- </style>
@@ -1,90 +0,0 @@
1
- <template>
2
- <ClientOnly>
3
- <button :popovertarget popovertargetaction="toggle" class="popover-trigger" :class="[elementClasses]">
4
- <slot name="trigger"></slot>
5
- </button>
6
-
7
- <div class="dialog" popover role="tooltip" :id="popovertarget" :class="[elementClasses]">
8
- <button :popovertarget popovertargetaction="hide">x</button>
9
- <slot name="popoverCotent"></slot>
10
- </div>
11
- </ClientOnly>
12
- </template>
13
-
14
- <script setup lang="ts">
15
- const props = defineProps({
16
- popovertarget: {
17
- type: String,
18
- required: true,
19
- },
20
- styleClassPassthrough: {
21
- type: [String, Array] as PropType<string | string[]>,
22
- default: () => [],
23
- },
24
- })
25
-
26
- const anchorName = `--anchor-${useId()}`
27
-
28
- const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
29
- </script>
30
-
31
- <style scoped lang="css">
32
- @layer components {
33
- @layer popover-setup {
34
- /* @position-try --right {
35
- inset: auto;
36
- top: anchor(top);
37
- left: calc(anchor(right) + 10px);
38
- }
39
-
40
- @position-try --left {
41
- inset: auto;
42
- top: anchor(top);
43
- right: calc(anchor(left) + 10px);
44
- } */
45
-
46
- .popover-trigger {
47
- anchor-name: v-bind(anchorName);
48
- }
49
-
50
- .dialog {
51
- display: none;
52
- position: absolute;
53
- position-anchor: v-bind(anchorName);
54
- margin: 0;
55
- inset: auto;
56
- top: calc(anchor(top) + 0px);
57
- left: calc(anchor(right) + 10px);
58
- opacity: 0;
59
- transition: opacity 200ms, display 200ms, overlay 200ms;
60
- transition-behavior: allow-discrete;
61
-
62
- position-try-fallbacks: flip-inline;
63
-
64
- &:popover-open {
65
- display: block;
66
- opacity: 1;
67
-
68
- @starting-style {
69
- display: block;
70
- opacity: 0;
71
- }
72
- }
73
- }
74
-
75
- @position-try --top-left {
76
- top: anchor(top);
77
- right: calc(anchor(left + 10px));
78
- left: unset;
79
- /* width: revert; */
80
- }
81
-
82
- @position-try --bottom-right {
83
- top: anchor(bottom);
84
- /* right: calc(anchor(left + 10px)); */
85
- /* left: unset; */
86
- /* width: revert; */
87
- }
88
- }
89
- }
90
- </style>
@@ -1,308 +0,0 @@
1
- <template>
2
- <div class="page-layout">
3
- <SiteHeader
4
- :responsive-nav-links
5
- :gap-between-first-and-second-nav="12"
6
- page-row-variant="full"
7
- :style-class-passthrough="['header']"
8
- :nav-style-class-passthrough="['site-header-nav']"
9
- :overflow-details-summary-icons="{
10
- more: 'gravity-ui:ellipsis',
11
- burger: 'gravity-ui:bars',
12
- }"
13
- :collapse-at-main-nav-intersection="false"
14
- :allow-expand-on-gesture="false"
15
- >
16
- <template #branding>
17
- <NuxtLink to="/" class="home-link">
18
- SRCDEV
19
- <span>components</span>
20
- </NuxtLink>
21
- </template>
22
- <template #secondaryNavigation>
23
- <ul class="secondary-navigation-list">
24
- <li class="secondary-navigation-item">
25
- <NuxtLink class="secondary-navigation-link" to="/">
26
- <Icon name="material-symbols:settings-outline-rounded" class="icon" aria-hidden="true" />
27
- <span class="sr-only">Settings</span>
28
- </NuxtLink>
29
- </li>
30
- </ul>
31
- </template>
32
- </SiteHeader>
33
- <PageRow id="main-content" class="main-content" tag="main" variant="full" :is-landmark="true">
34
- <template #default>
35
- <slot name="layout-content">Page content goes here</slot>
36
- </template>
37
- </PageRow>
38
- <PageRow id="footer-content" tag="footer" variant="full" :is-landmark="true">
39
- <template #default>
40
- <p>Footer content here</p>
41
- </template>
42
- </PageRow>
43
- </div>
44
- </template>
45
-
46
- <script setup lang="ts">
47
- import type { ResponsiveHeaderProp } from "~/types/components";
48
-
49
- const responsiveNavLinks = {
50
- firstNav: [
51
- {
52
- name: "Components",
53
- iconName: "material-symbols:widgets",
54
- childLinksTitle: "UI Components",
55
- childLinks: [
56
- { name: "Wipe Away Vertical", path: "/ui/wipe-away-vertical" },
57
- { name: "Scroll Reveal Image", path: "/ui/scroll-reveal-image" },
58
- { name: "Tooltips", path: "/ui/tooltips" },
59
- { name: "Marquee Scroller", path: "/ui/marquee-scroller" },
60
- { name: "Banner", path: "/ui/display-banner" },
61
- { name: "Banner Video", path: "/banner-video" },
62
- { name: "Section Parallax", path: "/ui/section-parallax" },
63
- { name: "Animated SVG Text", path: "/ui/animated-svg-text" },
64
- { name: "Carousel (Basic)", path: "/ui/carousel-basic" },
65
- { name: "Carousel (Infinite)", path: "/ui/carousel-infinite" },
66
- { name: "Carousel (Flip)", path: "/ui/carousel-flip" },
67
- { name: "Slider Gallery", path: "/ui/slider-gallery" },
68
- { name: "Container Glow", path: "/ui/container-glow" },
69
- { name: "Accordian", path: "/ui/accordian" },
70
- { name: "Display Details", path: "/ui/display-details" },
71
- { name: "Card Core", path: "/ui/card-core" },
72
- { name: "Glowing Border", path: "/ui/glowing-border" },
73
- { name: "Display Toast", path: "/ui/display-toast" },
74
- { name: "Prompts", path: "/ui/display-prompt" },
75
- { name: "Masked Alert", path: "/ui/mask-element" },
76
- { name: "Expanding Panel", path: "/ui/expanding-panel" },
77
- { name: "Dialogs", path: "/ui/display-dialog" },
78
- { name: "Tabs X", path: "/ui/tabs" },
79
- { name: "Tabs Y", path: "/ui/tabs-y" },
80
- { name: "Rotating Carousel", path: "/ui/rotating-carousel" },
81
- { name: "Clipped Panels", path: "/ui/clipped-panels" },
82
- { name: "Display Chip", path: "/ui/display-chip" },
83
- { name: "Display Avatar", path: "/ui/display-avatar" },
84
- { name: "Display Pill", path: "/ui/display-pill" },
85
- { name: "Qr Codes", path: "/ui/qr-code/display" },
86
- { name: "Anchor Scroll", path: "/ui/anchor-scroll" },
87
- { name: "Anchor Scroll (TabNavigation)", path: "/ui/anchor-scroll-tab-navigation" },
88
- ],
89
- },
90
- {
91
- name: "Layouts",
92
- iconName: "material-symbols:responsive-layout",
93
- childLinksTitle: "UI Layouts",
94
- childLinks: [
95
- { name: "Block Decorators", path: "/ui/block-decorators" },
96
- { name: "Navigation Horizontal", path: "/ui/navigation/navigation-horizontal" },
97
- { name: "Site Navigation", path: "/ui/navigation/site-navigation" },
98
- { name: "Tab Navigation", path: "/ui/navigation/tab-navigation" },
99
- { name: "Deep Expanding Menu", path: "/ui/deep-expanding-menu" },
100
- { name: "Magnetic Navigation", path: "/ui/magnetic-navigation" },
101
- { name: "Page Row", path: "/ui/page-row" },
102
- { name: "Layout Grid A", path: "/ui/layout-grid-a" },
103
- { name: "Layout Grid B", path: "/ui/layout-grid-b" },
104
- { name: "Simple Grid", path: "/ui/simple-grid" },
105
- { name: "Layout Content Docs", path: "/ui/layout-content-docs" },
106
- { name: "Masonry Grid Simple", path: "/ui/masonry-grid" },
107
- { name: "Masonry Grid Sorted", path: "/ui/masonry-grid-sorted" },
108
- { name: "Masonry Grid Ordered", path: "/ui/masonry-grid-ordered" },
109
- { name: "Masonry Columns", path: "/ui/masonry-columns" },
110
- { name: "Page Hero Highlights", path: "/page-hero-highlights" },
111
- ],
112
- },
113
- {
114
- name: "Forms",
115
- iconName: "material-symbols:custom-typography",
116
- childLinksTitle: "Forms & Inputs",
117
- childLinks: [
118
- { name: "Buttons", path: "/forms/examples/buttons" },
119
- { name: "Example Form", path: "/forms/examples/material/text-fields" },
120
- { name: "Example Form", path: "/forms/examples/material/text-fields" },
121
- ],
122
- },
123
- {
124
- name: "Typography",
125
- iconName: "material-symbols:custom-typography",
126
- childLinksTitle: "Typography",
127
- childLinks: [
128
- { name: "Hero Text", path: "/typography/hero-text" },
129
- { name: "Page Headings", path: "/typography/page-heading" },
130
- { name: "Page Body", path: "/typography/page-body" },
131
- { name: "Page Links", path: "/typography/page-link" },
132
- ],
133
- },
134
- ],
135
- secondNav: [
136
- { name: "Some other link", iconName: "material-symbols:widgets", path: "#link-description" },
137
- {
138
- name: "Help",
139
- childLinksTitle: "Find Help",
140
- childLinks: [
141
- { name: "FAQs", path: "#" },
142
- { name: "Contact Us", path: "#" },
143
- { name: "Logout", path: "#" },
144
- ],
145
- },
146
- {
147
- name: "Account",
148
- childLinksTitle: "Manage Your Account",
149
- childLinks: [
150
- { name: "Your Profile", path: "#" },
151
- { name: "Settings", path: "/ui/settings" },
152
- { name: "Logout", path: "#" },
153
- ],
154
- },
155
- ],
156
- } as ResponsiveHeaderProp;
157
-
158
- // *** COLOR SCHEME INITIALIZATION ***
159
- onMounted(() => {
160
- const getSystemPreference = () => {
161
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
162
- };
163
-
164
- const applyColorScheme = (scheme: string) => {
165
- const htmlElement = document.documentElement;
166
- htmlElement.classList.remove("system", "dark", "light");
167
-
168
- // If scheme is "system", use the actual system preference
169
- const actualScheme = scheme === "system" ? getSystemPreference() : scheme;
170
- htmlElement.classList.add(actualScheme);
171
- };
172
-
173
- // Listen for system preference changes
174
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
175
- const handleSystemChange = () => {
176
- const storedValue = localStorage.getItem("useSettingsStore");
177
- if (storedValue) {
178
- const parsed = JSON.parse(storedValue);
179
- // Only update if user has "system" selected
180
- if (parsed.colourScheme === "system") {
181
- applyColorScheme("system");
182
- }
183
- }
184
- };
185
-
186
- mediaQuery.addEventListener("change", handleSystemChange);
187
-
188
- try {
189
- const storedValue = localStorage.getItem("useSettingsStore");
190
-
191
- if (storedValue) {
192
- const parsed = JSON.parse(storedValue);
193
- applyColorScheme(parsed.colourScheme || "system");
194
- } else {
195
- // For new users, detect and apply system preference
196
- const systemPreference = getSystemPreference();
197
- applyColorScheme(systemPreference);
198
- }
199
- } catch {
200
- // Fallback to system preference
201
- const systemPreference = getSystemPreference();
202
- applyColorScheme(systemPreference);
203
- }
204
- });
205
- </script>
206
- <style lang="css">
207
- .page-layout {
208
- display: grid;
209
- grid-template-columns: 1fr;
210
- grid-template-rows: auto 1fr auto;
211
- align-items: start;
212
-
213
- .main-content {
214
- container-type: inline-size;
215
- }
216
- }
217
-
218
- /* ─── Header row layout ─────────────────────────────────────────────────── */
219
- .header {
220
- .debug-grid {
221
- display: none !important;
222
- }
223
-
224
- width: 100%;
225
-
226
- /* SiteHeader token overrides — see .claude/skills/components/site-header.md */
227
- --site-header-gap: 2.4rem;
228
- --site-header-padding-inline: 2.4rem;
229
- --site-header-bg: #000;
230
- --site-header-position: relative;
231
- --site-header-z-index: 9;
232
-
233
- .home-link {
234
- display: flex;
235
- flex-direction: column;
236
- text-wrap-mode: nowrap;
237
- font-size: var(--step-5);
238
- letter-spacing: 0.2em;
239
- color: var(--slate-00);
240
- text-decoration: none;
241
-
242
- span {
243
- font-size: var(--step-3);
244
- letter-spacing: initial;
245
- }
246
-
247
- &:hover {
248
- border-radius: 0.4rem;
249
- outline: 2px solid var(--green-08);
250
- outline-offset: 0.4rem;
251
- }
252
- }
253
- }
254
-
255
- /* ─── ResponsiveHeader token overrides for this layout ──────────────────── */
256
- .site-header-nav {
257
- --responsive-header-margin: 1.2rem;
258
- --responsive-header-bg: #efefef05;
259
- --responsive-header-border: 1px solid transparent;
260
- --responsive-header-border-radius: 0.8rem;
261
- --responsive-header-padding-block: 1rem;
262
- --responsive-header-padding-inline: 1.2rem;
263
- --responsive-header-max-height: 6.4rem;
264
- --responsive-header-inline-size: 100%;
265
-
266
- --responsive-header-color: var(--slate-00);
267
- --responsive-header-link-color: var(--slate-00);
268
-
269
- /* Fixed (non-fluid) nav-link font-size — deliberately NOT var(--step-*).
270
- A vw-based clamp() here drifts with the scrollbar (see
271
- ResponsiveHeader.vue's token comment) without ever re-triggering the
272
- overflow-collapse ResizeObserver, silently letting one extra item fit
273
- that shouldn't. Values TBC after a visual pass. */
274
- --responsive-header-link-font-size: 1.2rem;
275
- @media (min-width: 768px) {
276
- --responsive-header-link-font-size: 1.4rem;
277
- }
278
- @media (min-width: 1024px) {
279
- --responsive-header-link-font-size: 1.5rem;
280
- }
281
-
282
- --responsive-header-sub-nav-bg: #000;
283
- --responsive-header-sub-nav-border: 1px solid #efefef75;
284
-
285
- --responsive-header-overflow-btn-bg: var(--slate-08);
286
- --responsive-header-overflow-btn-size: 3rem;
287
- --responsive-header-overflow-btn-border: 1px solid #ffffff90;
288
- --responsive-header-overflow-btn-outline: 1px solid #ffffff10;
289
- --responsive-header-overflow-btn-icon-color: var(--slate-00);
290
- --responsive-header-overflow-btn-hover-outline: 2px solid var(--green-08);
291
-
292
- --responsive-header-overflow-nav-bg: #000;
293
- --responsive-header-overflow-nav-border: 0.1rem solid #ffffff90;
294
- --responsive-header-overflow-nav-padding-block: 0;
295
-
296
- --overflow-nav-link-color: var(--slate-00);
297
- --overflow-nav-link-border-color: #efefef75;
298
- --overflow-nav-sub-item-color: var(--slate-00);
299
- --overflow-nav-sub-item-font-size: var(--step-4);
300
-
301
- --responsive-nav-decorator-indicator-color: var(--slate-00);
302
- --responsive-nav-decorator-hovered-indicator-color: var(--green-08);
303
- --responsive-nav-decorator-hovered-bg: oklch(100% 0 0 / 8%);
304
- --overflow-nav-decorator-indicator-color: var(--slate-00);
305
- --overflow-nav-decorator-hovered-indicator-color: var(--green-08);
306
- --overflow-nav-decorator-hovered-bg: oklch(100% 0 0 / 6%);
307
- }
308
- </style>
@@ -1,188 +0,0 @@
1
- <template>
2
- <div class="site-nav-demo-layout">
3
- <header class="site-nav-demo-header">
4
- <NuxtLink to="/" class="site-nav-demo-logo">SiteNav Demo</NuxtLink>
5
- <SiteNavigation :nav-item-data="navItemData" nav-align="right" />
6
- </header>
7
- <main class="site-nav-demo-main">
8
- <slot></slot>
9
- </main>
10
- </div>
11
- </template>
12
-
13
- <script setup lang="ts">
14
- import type { NavItemData } from "~/types/components/navigation-horizontal.d";
15
-
16
- const navItemData: NavItemData = {
17
- main: [
18
- { text: "Home", href: "/ui/navigation/site-navigation" },
19
- { text: "About", href: "/ui/navigation/site-navigation/about" },
20
- { text: "Services", href: "/ui/navigation/site-navigation/services" },
21
- { text: "Portfolio", href: "/ui/navigation/site-navigation/portfolio" },
22
- { text: "Contact", href: "/ui/navigation/site-navigation/contact" },
23
- ],
24
- };
25
- </script>
26
-
27
- <style lang="css">
28
- .site-nav-demo-layout {
29
- min-height: 100dvh;
30
- display: flex;
31
- flex-direction: column;
32
-
33
- .site-nav-demo-header {
34
- display: flex;
35
- align-items: center;
36
- gap: 2.4rem;
37
- padding-block: 1.2rem;
38
- padding-inline: 2.4rem;
39
- background-color: #0e0e0e;
40
- border-block-end: 1px solid oklch(100% 0 0 / 10%);
41
- position: sticky;
42
- top: 0;
43
- z-index: 10;
44
- }
45
-
46
- .site-nav-demo-logo {
47
- font-size: 1.6rem;
48
- font-weight: 600;
49
- letter-spacing: 0.05em;
50
- color: var(--warm-01, #fff);
51
- text-decoration: none;
52
- text-wrap: nowrap;
53
- flex-shrink: 0;
54
- }
55
-
56
- .site-navigation {
57
- flex: 1;
58
- min-width: 0;
59
- }
60
-
61
- .site-nav-demo-main {
62
- flex: 1;
63
- padding: 4rem 2.4rem;
64
- max-width: 80rem;
65
- margin-inline: auto;
66
- width: 100%;
67
- }
68
- }
69
-
70
- /* Shared demo page styles */
71
- .snav-demo-page {
72
- h1,
73
- h2,
74
- h3 {
75
- margin-block-end: 1.6rem;
76
- }
77
- h2 {
78
- margin-block-start: 4rem;
79
- }
80
- > p {
81
- margin-block-end: 2.4rem;
82
- line-height: 1.6;
83
- }
84
- ul {
85
- padding-inline-start: 2rem;
86
- margin-block-end: 2.4rem;
87
- line-height: 2;
88
- }
89
- }
90
-
91
- .snav-demo-hero {
92
- width: 100%;
93
- height: auto;
94
- aspect-ratio: 2 / 1;
95
- object-fit: cover;
96
- border-radius: 0.8rem;
97
- display: block;
98
- margin-block-end: 2.4rem;
99
- }
100
-
101
- .snav-demo-grid {
102
- display: grid;
103
- grid-template-columns: repeat(3, 1fr);
104
- gap: 1.6rem;
105
-
106
- @media (max-width: 600px) {
107
- grid-template-columns: repeat(2, 1fr);
108
- }
109
- }
110
-
111
- .snav-demo-grid--wide {
112
- grid-template-columns: repeat(2, 1fr);
113
-
114
- @media (max-width: 600px) {
115
- grid-template-columns: 1fr;
116
- }
117
- }
118
-
119
- .snav-demo-img {
120
- width: 100%;
121
- height: auto;
122
- aspect-ratio: 3 / 2;
123
- object-fit: cover;
124
- border-radius: 0.4rem;
125
- display: block;
126
- }
127
-
128
- .snav-demo-split {
129
- display: grid;
130
- grid-template-columns: 1fr 1fr;
131
- gap: 3.2rem;
132
- align-items: start;
133
- margin-block-end: 4rem;
134
-
135
- @media (max-width: 650px) {
136
- grid-template-columns: 1fr;
137
- }
138
- }
139
-
140
- .snav-demo-split__text {
141
- h2,
142
- h3 {
143
- margin-block-start: 2.4rem;
144
- }
145
- p {
146
- line-height: 1.6;
147
- margin-block-end: 1.6rem;
148
- }
149
- }
150
-
151
- .snav-demo-split__img {
152
- width: 100%;
153
- height: auto;
154
- aspect-ratio: 3 / 4;
155
- object-fit: cover;
156
- border-radius: 0.4rem;
157
- display: block;
158
- }
159
-
160
- .snav-demo-services {
161
- display: grid;
162
- grid-template-columns: repeat(3, 1fr);
163
- gap: 2.4rem;
164
-
165
- @media (max-width: 650px) {
166
- grid-template-columns: 1fr;
167
- }
168
- }
169
-
170
- .snav-demo-service-card {
171
- border-radius: 0.8rem;
172
- overflow: hidden;
173
- background: oklch(100% 0 0 / 5%);
174
- }
175
-
176
- .snav-demo-service-card__body {
177
- padding: 1.6rem;
178
-
179
- h3 {
180
- margin-block-end: 0.8rem;
181
- }
182
- p {
183
- font-size: 1.4rem;
184
- line-height: 1.6;
185
- opacity: 0.8;
186
- }
187
- }
188
- </style>