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.
- package/.claude/commands/migrate-component.md +74 -5
- package/.claude/component-ledger/audit.json +1 -1
- package/.claude/component-ledger/build.mjs +27 -0
- package/.claude/component-ledger/output.html +8 -3
- package/.claude/component-ledger/template.html +7 -2
- package/.claude/skills/components/breadcrumb.md +1 -0
- package/.claude/skills/components/column-flow-grid.md +93 -0
- package/.claude/skills/components/content-docs.md +2 -0
- package/.claude/skills/components/display-tooltip-defined.md +3 -0
- package/.claude/skills/components/display-tooltip.md +1 -0
- package/.claude/skills/components/entry-animation.md +88 -0
- package/.claude/skills/components/input-copy.md +2 -0
- package/.claude/skills/components/input-text-core.md +186 -0
- package/.claude/skills/components/marquee-scroller.md +130 -0
- package/.claude/skills/components/masonry-grid.md +153 -0
- package/.claude/skills/components/navigation-items.md +1 -0
- package/.claude/skills/components/pop-over.md +100 -0
- package/.claude/skills/components/responsive-header.md +3 -0
- package/.claude/skills/components/site-header.md +4 -0
- package/.claude/skills/components/site-navigation.md +1 -0
- package/.claude/skills/components/tab-navigation.md +1 -0
- package/.claude/skills/index.md +7 -1
- package/.vscode/srcdev-component-breadcrumb.code-snippets +13 -0
- package/.vscode/srcdev-component-column-flow-grid.code-snippets +39 -0
- package/.vscode/srcdev-component-content-docs.code-snippets +18 -0
- package/.vscode/srcdev-component-display-tooltip-defined.code-snippets +15 -0
- package/.vscode/srcdev-component-display-tooltip.code-snippets +11 -0
- package/.vscode/srcdev-component-entry-animation.code-snippets +29 -0
- package/.vscode/srcdev-component-input-text.code-snippets +107 -0
- package/.vscode/srcdev-component-marquee-scroller.code-snippets +93 -0
- package/.vscode/srcdev-component-masonry-grid.code-snippets +51 -0
- package/.vscode/srcdev-component-pop-over.code-snippets +44 -0
- package/.vscode/srcdev-component-responsive-header.code-snippets +12 -0
- package/.vscode/srcdev-component-site-header.code-snippets +17 -0
- package/.vscode/srcdev-component-site-navigation.code-snippets +30 -0
- package/.vscode/srcdev-component-slider-gallery.code-snippets +38 -0
- package/.vscode/srcdev-component-tab-navigation.code-snippets +30 -0
- package/app/components/01.atoms/animations/entry/EntryAnimation.vue +7 -1
- package/app/components/01.atoms/animations/entry/stories/EntryAnimation.stories.ts +47 -0
- package/app/components/01.atoms/animations/entry/tests/EntryAnimation.spec.ts +57 -0
- package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +94 -0
- package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +331 -0
- package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +151 -0
- package/app/components/01.atoms/animations/marquee-scroller/tests/MarqueeScroller.spec.ts +315 -0
- package/app/components/01.atoms/animations/marquee-scroller/tests/__snapshots__/MarqueeScroller.spec.ts.snap +28 -0
- package/app/components/01.atoms/canvas-switcher/stories/CanvasSwitcher.stories.ts +9 -10
- package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +8 -2
- package/app/components/01.atoms/content-wrappers/docs-pages/stories/ContentDocs.stories.ts +12 -13
- package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +4 -1
- package/app/components/01.atoms/grids/column-flow-grid/CONSUMER-STYLING.md +33 -0
- package/app/components/01.atoms/grids/column-flow-grid/ColumnFlowGrid.vue +55 -0
- package/app/components/01.atoms/grids/column-flow-grid/stories/ColumnFlowGrid.stories.ts +178 -0
- package/app/components/01.atoms/grids/column-flow-grid/tests/ColumnFlowGrid.spec.ts +75 -0
- package/app/components/01.atoms/grids/masonry-grid/CONSUMER-STYLING.md +35 -0
- package/app/components/01.atoms/grids/masonry-grid/MasonryGrid.vue +178 -0
- package/app/components/01.atoms/grids/masonry-grid/stories/MasonryGrid.stories.ts +199 -0
- package/app/components/01.atoms/grids/masonry-grid/tests/MasonryGrid.spec.ts +158 -0
- package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +4 -1
- package/app/components/01.atoms/pop-over/CONSUMER-STYLING.md +54 -0
- package/app/components/01.atoms/pop-over/PopOver.vue +201 -0
- package/app/components/01.atoms/pop-over/stories/PopOver.stories.ts +141 -0
- package/app/components/01.atoms/pop-over/tests/PopOver.spec.ts +195 -0
- package/app/components/01.atoms/pop-over/tests/__snapshots__/PopOver.spec.ts.snap +11 -0
- package/app/components/02.molecules/action-menu/stories/ActionMenu.stories.ts +8 -2
- package/app/components/02.molecules/display-tooltip-defined/DisplayTooltipDefined.vue +16 -3
- package/app/components/02.molecules/display-tooltip-defined/tests/__snapshots__/DisplayTooltipDefined.spec.ts.snap +1 -1
- package/app/components/02.molecules/input-copy/InputCopy.vue +14 -0
- package/app/components/02.molecules/input-copy/stories/InputCopy.stories.ts +15 -0
- package/app/components/02.molecules/input-copy/tests/InputCopy.spec.ts +41 -0
- package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +4 -1
- package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +4 -1
- package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +16 -4
- package/app/components/03.organisms/responsive-header/NavigationItems.vue +4 -1
- package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +16 -3
- package/app/components/03.organisms/site-header/SiteHeader.vue +16 -1
- package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +1 -1
- package/app/components/05.forms/input-select/InputSelectCore.vue +1 -1
- package/app/components/05.forms/input-text/InputTextCore.vue +6 -0
- package/app/components/05.forms/input-text/stories/InputPasswordWithLabel.stories.ts +49 -20
- package/app/components/05.forms/input-text/stories/InputTextAsNumberWithLabel.stories.ts +41 -22
- package/app/components/05.forms/input-text/stories/InputTextCore.stories.ts +48 -22
- package/app/components/05.forms/input-text/stories/InputTextWithLabel.stories.ts +43 -17
- package/app/components/05.forms/input-text/tests/InputPasswordWithLabel.spec.ts +56 -0
- package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +61 -0
- package/app/components/05.forms/input-text/tests/InputTextCore.spec.ts +60 -0
- package/app/components/05.forms/input-text/tests/InputTextWithLabel.spec.ts +46 -0
- package/app/components/05.forms/input-text/variants/InputPasswordWithLabel.vue +7 -1
- package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +8 -2
- package/app/components/05.forms/input-text/variants/InputTextWithLabel.vue +6 -0
- package/app/components/05.forms/input-textarea/stories/InputTextareaCore.stories.ts +20 -20
- package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +32 -26
- package/app/types/components/index.ts +1 -0
- package/app/types/components/marquee-scroller.d.ts +10 -0
- package/app/types/forms/types.forms.d.ts +1 -1
- package/package.json +1 -1
- package/app/components/marquee-scroller/MarqueeScroller.vue +0 -289
- package/app/components/masonry-grid/MasonryGrid.vue +0 -68
- package/app/components/masonry-grid-ordered/MasonryGridOrdered.vue +0 -163
- package/app/components/masonry-grid-ordered/MasonryGridOrderedGridExperiment.vue +0 -259
- package/app/components/masonry-grid-ordered/stories/MasonryGridOrdered.stories.ts +0 -354
- package/app/components/masonry-grid-sorted/MasonryGridSorted.vue +0 -120
- package/app/components/pop-over/PopOver.vue +0 -90
- package/app/layouts/default.vue +0 -308
- package/app/layouts/site-navigation-demo.vue +0 -188
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="masonry-grid-ordered" :class="[elementClasses]">
|
|
3
|
-
<div
|
|
4
|
-
ref="gridWrapper"
|
|
5
|
-
class="masonry-grid-ordered-wrapper"
|
|
6
|
-
:class="[{ 'multiple-cols': !isSingleColumn, 'setup-complete': isSetupComplete }]"
|
|
7
|
-
>
|
|
8
|
-
<div v-for="item in props.gridData" :key="item.id" ref="gridItemsRefs" class="masonry-grid-ordered-item">
|
|
9
|
-
<div ref="gridContentRefs" class="masonry-grid-ordered-content">
|
|
10
|
-
<slot :name="item.id"></slot>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
</div>
|
|
14
|
-
</div>
|
|
15
|
-
</template>
|
|
16
|
-
|
|
17
|
-
<script setup lang="ts">
|
|
18
|
-
import { useElementSize, useResizeObserver } from "@vueuse/core";
|
|
19
|
-
|
|
20
|
-
const props = defineProps({
|
|
21
|
-
gridData: {
|
|
22
|
-
type: Array as PropType<{ id: string }[]>,
|
|
23
|
-
default: () => [],
|
|
24
|
-
},
|
|
25
|
-
minTileWidth: {
|
|
26
|
-
type: Number,
|
|
27
|
-
default: 312,
|
|
28
|
-
},
|
|
29
|
-
gap: {
|
|
30
|
-
type: Number,
|
|
31
|
-
default: 12,
|
|
32
|
-
},
|
|
33
|
-
styleClassPassthrough: {
|
|
34
|
-
type: [String, Array] as PropType<string | string[]>,
|
|
35
|
-
default: () => [],
|
|
36
|
-
},
|
|
37
|
-
fixedWidth: {
|
|
38
|
-
type: Boolean,
|
|
39
|
-
default: false,
|
|
40
|
-
},
|
|
41
|
-
justify: {
|
|
42
|
-
type: String as PropType<"left" | "center" | "right">,
|
|
43
|
-
default: "left",
|
|
44
|
-
validator: (val: string) => ["left", "center", "right"].includes(val),
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
49
|
-
|
|
50
|
-
const gridWrapper = ref<null | HTMLDivElement>(null);
|
|
51
|
-
const gridItemsRefs = ref<HTMLDivElement[]>([]);
|
|
52
|
-
const gridContentRefs = ref<HTMLDivElement[]>([]);
|
|
53
|
-
const { width } = useElementSize(gridWrapper);
|
|
54
|
-
|
|
55
|
-
// Track item properties for masonry positioning
|
|
56
|
-
interface ItemData {
|
|
57
|
-
height: number;
|
|
58
|
-
column: number;
|
|
59
|
-
row: number;
|
|
60
|
-
top: number;
|
|
61
|
-
bottom: number;
|
|
62
|
-
translateY: number;
|
|
63
|
-
}
|
|
64
|
-
const itemDataArray = ref<ItemData[]>([]);
|
|
65
|
-
const isSetupComplete = ref(false);
|
|
66
|
-
|
|
67
|
-
const columnCount = computed(() => {
|
|
68
|
-
if (width.value === 0) return 1;
|
|
69
|
-
// Match the CSS container query breakpoint (636px hard-coded for now)
|
|
70
|
-
// if (width.value < 636) return 1
|
|
71
|
-
return Math.max(1, Math.floor(width.value / (props.minTileWidth + props.gap)));
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const isSingleColumn = computed(() => columnCount.value === 1);
|
|
75
|
-
|
|
76
|
-
const gapStr = computed(() => `${props.gap}px`);
|
|
77
|
-
|
|
78
|
-
const minTileWidthStr = computed(() => `${props.minTileWidth}px`);
|
|
79
|
-
|
|
80
|
-
const updateGrid = () => {
|
|
81
|
-
if (gridWrapper.value !== null && columnCount.value > 1) {
|
|
82
|
-
// Initialize or reset the item data array
|
|
83
|
-
itemDataArray.value = Array(props.gridData.length)
|
|
84
|
-
.fill(null)
|
|
85
|
-
.map(() => ({ height: 0, column: 0, row: 0, top: 0, bottom: 0, translateY: 0 }));
|
|
86
|
-
|
|
87
|
-
// Step 1: Hide items for measurement
|
|
88
|
-
gridItemsRefs.value.forEach((itemEl) => {
|
|
89
|
-
if (itemEl) {
|
|
90
|
-
itemEl.style.setProperty("--_opacity", "0");
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Force a reflow to get accurate measurements in grid layout
|
|
95
|
-
void gridWrapper.value.offsetHeight;
|
|
96
|
-
|
|
97
|
-
// Step 2: Measure heights and store in array
|
|
98
|
-
gridContentRefs.value.forEach((contentEl, index) => {
|
|
99
|
-
if (!contentEl || !gridItemsRefs.value[index] || !itemDataArray.value[index]) return;
|
|
100
|
-
|
|
101
|
-
const itemEl = gridItemsRefs.value[index];
|
|
102
|
-
const contentHeight = contentEl.offsetHeight;
|
|
103
|
-
|
|
104
|
-
// Calculate which column this item would be in based on CSS Grid's auto-fit
|
|
105
|
-
const column = index % columnCount.value;
|
|
106
|
-
|
|
107
|
-
// Calculate which row this item would be in based on CSS Grid's auto-fit
|
|
108
|
-
const row = Math.floor(index / columnCount.value);
|
|
109
|
-
|
|
110
|
-
let top: number;
|
|
111
|
-
let bottom: number;
|
|
112
|
-
let translateY: number;
|
|
113
|
-
|
|
114
|
-
// Always get the actual measured position first
|
|
115
|
-
const wrapperRect = gridWrapper.value!.getBoundingClientRect();
|
|
116
|
-
const itemRect = itemEl.getBoundingClientRect();
|
|
117
|
-
const actualTop = itemRect.top - wrapperRect.top;
|
|
118
|
-
|
|
119
|
-
if (row === 0) {
|
|
120
|
-
// First row: use natural CSS Grid position
|
|
121
|
-
top = actualTop;
|
|
122
|
-
bottom = top + contentHeight;
|
|
123
|
-
translateY = 0; // No transform needed for first row
|
|
124
|
-
} else {
|
|
125
|
-
// Subsequent rows: position based on item above in same column
|
|
126
|
-
const itemAboveIndex = index - columnCount.value;
|
|
127
|
-
const itemAbove = itemDataArray.value[itemAboveIndex];
|
|
128
|
-
|
|
129
|
-
if (itemAbove) {
|
|
130
|
-
top = itemAbove.bottom + props.gap;
|
|
131
|
-
bottom = top + contentHeight;
|
|
132
|
-
// Calculate the transform needed to move from actual position to desired position
|
|
133
|
-
translateY = top - actualTop;
|
|
134
|
-
} else {
|
|
135
|
-
// Fallback to natural position if no item above found
|
|
136
|
-
top = actualTop;
|
|
137
|
-
bottom = top + contentHeight;
|
|
138
|
-
translateY = 0;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Store the data in our tracking array
|
|
143
|
-
itemDataArray.value[index].height = contentHeight;
|
|
144
|
-
itemDataArray.value[index].column = column;
|
|
145
|
-
itemDataArray.value[index].row = row;
|
|
146
|
-
itemDataArray.value[index].top = top;
|
|
147
|
-
itemDataArray.value[index].bottom = bottom;
|
|
148
|
-
itemDataArray.value[index].translateY = translateY;
|
|
149
|
-
|
|
150
|
-
// Set the CSS custom properties
|
|
151
|
-
itemEl.style.setProperty("--_item-height", `${contentHeight}px`);
|
|
152
|
-
itemEl.style.setProperty("--_translate-y", `${translateY}px`);
|
|
153
|
-
itemEl.style.setProperty("--_opacity", "1");
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// Log the complete item data array when calculations are complete
|
|
157
|
-
// console.log("📊 Item data array:", itemDataArray.value)
|
|
158
|
-
|
|
159
|
-
// Mark setup as complete
|
|
160
|
-
isSetupComplete.value = true;
|
|
161
|
-
} else {
|
|
162
|
-
// Reset setup state for single column
|
|
163
|
-
isSetupComplete.value = false;
|
|
164
|
-
|
|
165
|
-
// Reset item data array
|
|
166
|
-
itemDataArray.value = [];
|
|
167
|
-
|
|
168
|
-
// Single column: reset to normal flow
|
|
169
|
-
gridItemsRefs.value.forEach((itemEl) => {
|
|
170
|
-
if (itemEl) {
|
|
171
|
-
itemEl.style.removeProperty("--_opacity");
|
|
172
|
-
itemEl.style.removeProperty("--_item-height");
|
|
173
|
-
itemEl.style.removeProperty("--_translate-y");
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
gridWrapper.value?.style.removeProperty("--_wrapper-height");
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
useResizeObserver(gridWrapper, async () => {
|
|
181
|
-
// console.log("useResizeObserver triggered")
|
|
182
|
-
// itemDataArray.value = [] // Clear previous data
|
|
183
|
-
// await useSleep(100)
|
|
184
|
-
// console.log("useResizeObserver after sleep")
|
|
185
|
-
nextTick(() => updateGrid());
|
|
186
|
-
|
|
187
|
-
// requestAnimationFrame(() => {
|
|
188
|
-
// updateGrid()
|
|
189
|
-
// nextTick(() => updateGrid())
|
|
190
|
-
// })
|
|
191
|
-
|
|
192
|
-
// Add a small delay to ensure DOM is fully rendered and measured
|
|
193
|
-
// setTimeout(() => {
|
|
194
|
-
// nextTick(() => updateGrid())
|
|
195
|
-
// }, 100)
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
onMounted(() => {
|
|
199
|
-
// Add a small delay to ensure DOM is fully rendered and measured
|
|
200
|
-
setTimeout(() => {
|
|
201
|
-
nextTick(() => updateGrid());
|
|
202
|
-
}, 100);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
watch(
|
|
206
|
-
() => props.fixedWidth,
|
|
207
|
-
() => {
|
|
208
|
-
updateGrid();
|
|
209
|
-
}
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
watch(
|
|
213
|
-
() => props.gridData,
|
|
214
|
-
() => {
|
|
215
|
-
// nextTick(() => updateGrid())
|
|
216
|
-
}
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
watch(
|
|
220
|
-
() => width.value,
|
|
221
|
-
(newWidth) => {
|
|
222
|
-
if (newWidth > 0) {
|
|
223
|
-
// nextTick(() => updateGrid())
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
watch(
|
|
229
|
-
() => props.styleClassPassthrough,
|
|
230
|
-
() => {
|
|
231
|
-
resetElementClasses(props.styleClassPassthrough);
|
|
232
|
-
}
|
|
233
|
-
);
|
|
234
|
-
</script>
|
|
235
|
-
|
|
236
|
-
<style lang="css">
|
|
237
|
-
@layer components {
|
|
238
|
-
.masonry-grid-ordered {
|
|
239
|
-
--_transition-duration: 0.3s;
|
|
240
|
-
|
|
241
|
-
.masonry-grid-ordered-wrapper {
|
|
242
|
-
display: grid;
|
|
243
|
-
gap: v-bind(gapStr);
|
|
244
|
-
grid-template-columns: repeat(auto-fit, minmax(v-bind(minTileWidthStr), 1fr));
|
|
245
|
-
|
|
246
|
-
height: var(--_wrapper-height, auto);
|
|
247
|
-
|
|
248
|
-
&.multiple-cols {
|
|
249
|
-
.masonry-grid-ordered-item {
|
|
250
|
-
height: var(--_item-height, auto);
|
|
251
|
-
opacity: var(--_opacity, 1);
|
|
252
|
-
transform: translateY(var(--_translate-y, 0px));
|
|
253
|
-
transition: transform var(--_transition-duration) ease;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
</style>
|
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryFn } from "@nuxtjs/storybook";
|
|
2
|
-
import StorybookComponent from "../MasonryGridOrdered.vue";
|
|
3
|
-
import type { IQuote } from "~/types/types.quotes";
|
|
4
|
-
|
|
5
|
-
// Custom interface for story args
|
|
6
|
-
interface MasonryGridOrderedStoryArgs {
|
|
7
|
-
gridData: IQuote[];
|
|
8
|
-
gap: number;
|
|
9
|
-
minTileWidth: number;
|
|
10
|
-
fixedWidth: boolean;
|
|
11
|
-
styleClassPassthrough: string[];
|
|
12
|
-
// Display options for stories
|
|
13
|
-
showBorders: boolean;
|
|
14
|
-
showNumbers: boolean;
|
|
15
|
-
itemVariant: "simple" | "card" | "detailed";
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Sample data for stories
|
|
19
|
-
const sampleQuotes: IQuote[] = [
|
|
20
|
-
{
|
|
21
|
-
id: 1,
|
|
22
|
-
quote: "The only way to do great work is to love what you do.",
|
|
23
|
-
author: "Steve Jobs",
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
id: 2,
|
|
27
|
-
quote: "Life is what happens to you while you're busy making other plans.",
|
|
28
|
-
author: "John Lennon",
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: 3,
|
|
32
|
-
quote: "The future belongs to those who believe in the beauty of their dreams.",
|
|
33
|
-
author: "Eleanor Roosevelt",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
id: 4,
|
|
37
|
-
quote: "It is during our darkest moments that we must focus to see the light.",
|
|
38
|
-
author: "Aristotle",
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
id: 5,
|
|
42
|
-
quote: "The way to get started is to quit talking and begin doing.",
|
|
43
|
-
author: "Walt Disney",
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
id: 6,
|
|
47
|
-
quote: "Don't let yesterday take up too much of today.",
|
|
48
|
-
author: "Will Rogers",
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: 7,
|
|
52
|
-
quote: "You learn more from failure than from success. Don't let it stop you. Failure builds character.",
|
|
53
|
-
author: "Unknown",
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
id: 8,
|
|
57
|
-
quote: "It's not whether you get knocked down, it's whether you get up.",
|
|
58
|
-
author: "Vince Lombardi",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: 9,
|
|
62
|
-
quote:
|
|
63
|
-
"If you are working on something that you really care about, you don't have to be pushed. The vision pulls you.",
|
|
64
|
-
author: "Steve Jobs",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: 10,
|
|
68
|
-
quote: "People who are crazy enough to think they can change the world, are the ones who do.",
|
|
69
|
-
author: "Rob Siltanen",
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
id: 11,
|
|
73
|
-
quote: "We don't make mistakes, just happy little accidents.",
|
|
74
|
-
author: "Bob Ross",
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
id: 12,
|
|
78
|
-
quote: "In the middle of every difficulty lies opportunity.",
|
|
79
|
-
author: "Albert Einstein",
|
|
80
|
-
},
|
|
81
|
-
];
|
|
82
|
-
|
|
83
|
-
export default {
|
|
84
|
-
title: "Components/UI/MasonryGridOrdered",
|
|
85
|
-
component: StorybookComponent,
|
|
86
|
-
argTypes: {
|
|
87
|
-
// Layout Configuration
|
|
88
|
-
gap: {
|
|
89
|
-
control: { type: "range", min: 0, max: 50, step: 2 },
|
|
90
|
-
description: "Gap between grid items in pixels",
|
|
91
|
-
table: {
|
|
92
|
-
category: "Layout",
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
minTileWidth: {
|
|
96
|
-
control: { type: "range", min: 200, max: 500, step: 10 },
|
|
97
|
-
description: "Minimum width for each grid tile",
|
|
98
|
-
table: {
|
|
99
|
-
category: "Layout",
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
fixedWidth: {
|
|
103
|
-
control: { type: "boolean" },
|
|
104
|
-
description: "Whether to use fixed width for tiles",
|
|
105
|
-
table: {
|
|
106
|
-
category: "Layout",
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
styleClassPassthrough: {
|
|
110
|
-
control: { type: "object" },
|
|
111
|
-
description: "Additional CSS classes to pass through",
|
|
112
|
-
table: {
|
|
113
|
-
category: "Layout",
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
// Data Configuration
|
|
117
|
-
gridData: {
|
|
118
|
-
control: { type: "object" },
|
|
119
|
-
description: "Array of quote objects to display in the grid",
|
|
120
|
-
table: {
|
|
121
|
-
category: "Data",
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
// Display Options (for stories only)
|
|
125
|
-
showBorders: {
|
|
126
|
-
control: { type: "boolean" },
|
|
127
|
-
description: "Show borders around grid items",
|
|
128
|
-
table: {
|
|
129
|
-
category: "Display Options",
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
showNumbers: {
|
|
133
|
-
control: { type: "boolean" },
|
|
134
|
-
description: "Show index numbers on grid items",
|
|
135
|
-
table: {
|
|
136
|
-
category: "Display Options",
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
itemVariant: {
|
|
140
|
-
control: { type: "select" },
|
|
141
|
-
options: ["simple", "card", "detailed"],
|
|
142
|
-
description: "Style variant for grid items",
|
|
143
|
-
table: {
|
|
144
|
-
category: "Display Options",
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
},
|
|
148
|
-
args: {
|
|
149
|
-
gridData: sampleQuotes.slice(0, 8),
|
|
150
|
-
gap: 12,
|
|
151
|
-
minTileWidth: 300,
|
|
152
|
-
fixedWidth: true,
|
|
153
|
-
styleClassPassthrough: ["mi-auto"],
|
|
154
|
-
showBorders: true,
|
|
155
|
-
showNumbers: true,
|
|
156
|
-
itemVariant: "card",
|
|
157
|
-
},
|
|
158
|
-
} as Meta<MasonryGridOrderedStoryArgs>;
|
|
159
|
-
|
|
160
|
-
const Template: StoryFn<MasonryGridOrderedStoryArgs> = (args) => ({
|
|
161
|
-
components: {
|
|
162
|
-
StorybookComponent,
|
|
163
|
-
},
|
|
164
|
-
setup() {
|
|
165
|
-
const getItemClasses = (variant: string, showBorders: boolean) => {
|
|
166
|
-
const baseClasses = ["p-10"];
|
|
167
|
-
|
|
168
|
-
if (showBorders) {
|
|
169
|
-
baseClasses.push("border", "border-1", "border-grey-dark");
|
|
170
|
-
|
|
171
|
-
if (variant === "card") {
|
|
172
|
-
baseClasses.push("border-r-4");
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (variant === "detailed") {
|
|
177
|
-
baseClasses.push("bg-gray-1", "rounded-4");
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return baseClasses.join(" ");
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
return { args, getItemClasses };
|
|
184
|
-
},
|
|
185
|
-
template: `
|
|
186
|
-
<div style="padding: 20px; max-width: 1200px; margin: 0 auto;">
|
|
187
|
-
<div style="margin-bottom: 20px;">
|
|
188
|
-
<h3 style="margin-bottom: 10px;">MasonryGridOrdered Component</h3>
|
|
189
|
-
<p style="color: #666; margin-bottom: 20px;">
|
|
190
|
-
Displaying {{ args.gridData.length }} items with {{ args.gap }}px gap and {{ args.minTileWidth }}px minimum width
|
|
191
|
-
</p>
|
|
192
|
-
</div>
|
|
193
|
-
|
|
194
|
-
<StorybookComponent
|
|
195
|
-
:gridData="args.gridData"
|
|
196
|
-
:gap="args.gap"
|
|
197
|
-
:min-tile-width="args.minTileWidth"
|
|
198
|
-
:fixed-width="args.fixedWidth"
|
|
199
|
-
:styleClassPassthrough="args.styleClassPassthrough"
|
|
200
|
-
>
|
|
201
|
-
<template v-for="(item, index) in args.gridData" v-slot:[item.id]>
|
|
202
|
-
<div :class="getItemClasses(args.itemVariant, args.showBorders)">
|
|
203
|
-
<p v-if="args.showNumbers" class="text-normal wght-700" style="margin-bottom: 8px;">
|
|
204
|
-
{{ index + 1 }}: {{ item.author }}
|
|
205
|
-
</p>
|
|
206
|
-
<p v-else class="text-normal wght-700" style="margin-bottom: 8px;">
|
|
207
|
-
{{ item.author }}
|
|
208
|
-
</p>
|
|
209
|
-
<p class="text-normal">{{ item.quote }}</p>
|
|
210
|
-
</div>
|
|
211
|
-
</template>
|
|
212
|
-
</StorybookComponent>
|
|
213
|
-
</div>
|
|
214
|
-
`,
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
export const Default = Template.bind({});
|
|
218
|
-
|
|
219
|
-
export const SmallGap = Template.bind({});
|
|
220
|
-
SmallGap.args = {
|
|
221
|
-
gap: 4,
|
|
222
|
-
minTileWidth: 250,
|
|
223
|
-
fixedWidth: false,
|
|
224
|
-
itemVariant: "simple",
|
|
225
|
-
showBorders: false,
|
|
226
|
-
showNumbers: false,
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
export const LargeGap = Template.bind({});
|
|
230
|
-
LargeGap.args = {
|
|
231
|
-
gap: 24,
|
|
232
|
-
minTileWidth: 320,
|
|
233
|
-
fixedWidth: true,
|
|
234
|
-
itemVariant: "card",
|
|
235
|
-
showBorders: true,
|
|
236
|
-
showNumbers: true,
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
export const WideItems = Template.bind({});
|
|
240
|
-
WideItems.args = {
|
|
241
|
-
gap: 16,
|
|
242
|
-
minTileWidth: 400,
|
|
243
|
-
fixedWidth: false,
|
|
244
|
-
itemVariant: "detailed",
|
|
245
|
-
showBorders: true,
|
|
246
|
-
showNumbers: false,
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
export const NarrowItems = Template.bind({});
|
|
250
|
-
NarrowItems.args = {
|
|
251
|
-
gap: 8,
|
|
252
|
-
minTileWidth: 200,
|
|
253
|
-
fixedWidth: true,
|
|
254
|
-
itemVariant: "simple",
|
|
255
|
-
showBorders: true,
|
|
256
|
-
showNumbers: true,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
export const ManyItems = Template.bind({});
|
|
260
|
-
ManyItems.args = {
|
|
261
|
-
gridData: sampleQuotes, // All 12 items
|
|
262
|
-
gap: 12,
|
|
263
|
-
minTileWidth: 280,
|
|
264
|
-
fixedWidth: true,
|
|
265
|
-
itemVariant: "card",
|
|
266
|
-
showBorders: true,
|
|
267
|
-
showNumbers: true,
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
export const FewItems = Template.bind({});
|
|
271
|
-
FewItems.args = {
|
|
272
|
-
gridData: sampleQuotes.slice(0, 4),
|
|
273
|
-
gap: 20,
|
|
274
|
-
minTileWidth: 350,
|
|
275
|
-
fixedWidth: false,
|
|
276
|
-
itemVariant: "detailed",
|
|
277
|
-
showBorders: true,
|
|
278
|
-
showNumbers: false,
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
export const MinimalStyle = Template.bind({});
|
|
282
|
-
MinimalStyle.args = {
|
|
283
|
-
gap: 16,
|
|
284
|
-
minTileWidth: 300,
|
|
285
|
-
fixedWidth: false,
|
|
286
|
-
styleClassPassthrough: [],
|
|
287
|
-
itemVariant: "simple",
|
|
288
|
-
showBorders: false,
|
|
289
|
-
showNumbers: false,
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
export const CustomStyles = Template.bind({});
|
|
293
|
-
CustomStyles.args = {
|
|
294
|
-
gap: 12,
|
|
295
|
-
minTileWidth: 320,
|
|
296
|
-
fixedWidth: true,
|
|
297
|
-
styleClassPassthrough: ["mi-auto", "mb-20"],
|
|
298
|
-
itemVariant: "detailed",
|
|
299
|
-
showBorders: true,
|
|
300
|
-
showNumbers: true,
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
// Example with different content structure
|
|
304
|
-
const Template2: StoryFn<MasonryGridOrderedStoryArgs> = (args) => ({
|
|
305
|
-
components: {
|
|
306
|
-
StorybookComponent,
|
|
307
|
-
},
|
|
308
|
-
setup() {
|
|
309
|
-
return { args };
|
|
310
|
-
},
|
|
311
|
-
template: `
|
|
312
|
-
<div style="padding: 20px; max-width: 1200px; margin: 0 auto;">
|
|
313
|
-
<div style="margin-bottom: 20px;">
|
|
314
|
-
<h3 style="margin-bottom: 10px;">Custom Content Example</h3>
|
|
315
|
-
<p style="color: #666; margin-bottom: 20px;">
|
|
316
|
-
Showing how different content can be displayed in the masonry grid
|
|
317
|
-
</p>
|
|
318
|
-
</div>
|
|
319
|
-
|
|
320
|
-
<StorybookComponent
|
|
321
|
-
:gridData="args.gridData"
|
|
322
|
-
:gap="args.gap"
|
|
323
|
-
:min-tile-width="args.minTileWidth"
|
|
324
|
-
:fixed-width="args.fixedWidth"
|
|
325
|
-
:styleClassPassthrough="args.styleClassPassthrough"
|
|
326
|
-
>
|
|
327
|
-
<template v-for="(item, index) in args.gridData" v-slot:[item.id]>
|
|
328
|
-
<div class="p-16 bg-gray-1 rounded-8 border border-1 border-gray-6">
|
|
329
|
-
<div style="display: flex; align-items: center; margin-bottom: 12px;">
|
|
330
|
-
<div
|
|
331
|
-
style="width: 32px; height: 32px; border-radius: 50%; background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; margin-right: 12px; font-size: 14px;"
|
|
332
|
-
>
|
|
333
|
-
{{ index + 1 }}
|
|
334
|
-
</div>
|
|
335
|
-
<h4 class="text-normal wght-700" style="margin: 0;">{{ item.author }}</h4>
|
|
336
|
-
</div>
|
|
337
|
-
<blockquote class="text-normal" style="font-style: italic; border-left: 3px solid #667eea; padding-left: 12px; margin: 0;">
|
|
338
|
-
"{{ item.quote }}"
|
|
339
|
-
</blockquote>
|
|
340
|
-
</div>
|
|
341
|
-
</template>
|
|
342
|
-
</StorybookComponent>
|
|
343
|
-
</div>
|
|
344
|
-
`,
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
export const RichContent = Template2.bind({});
|
|
348
|
-
RichContent.args = {
|
|
349
|
-
gridData: sampleQuotes.slice(0, 6),
|
|
350
|
-
gap: 16,
|
|
351
|
-
minTileWidth: 320,
|
|
352
|
-
fixedWidth: false,
|
|
353
|
-
styleClassPassthrough: ["mi-auto"],
|
|
354
|
-
};
|