@xenterprises/nuxt-x-marketing 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -11
- package/app/components/X/Mark/CodeBlock/index.vue +19 -7
- package/app/components/X/Mark/Divider/Glow.vue +25 -19
- package/app/components/X/Mark/Section/Stitch.vue +45 -31
- package/app/composables/{useParallax.ts → useParallax.js} +6 -7
- package/app/composables/{useScrollReveal.ts → useScrollReveal.js} +4 -4
- package/nuxt.config.ts +1 -11
- package/package.json +1 -1
- package/.claude/settings.local.json +0 -23
- package/.nuxtrc +0 -1
- package/.playground/app.config.ts +0 -74
- package/.playground/app.vue +0 -269
- package/.playground/components/AppFooter.vue +0 -103
- package/.playground/components/AppHeader.vue +0 -41
- package/.playground/components/CodeExample.vue +0 -70
- package/.playground/components/ComponentPlayground.vue +0 -117
- package/.playground/components/DocsHeader.vue +0 -19
- package/.playground/layouts/default.vue +0 -15
- package/.playground/layouts/docs-layout.vue +0 -161
- package/.playground/layouts/docs.vue +0 -11
- package/.playground/nuxt.config.ts +0 -5
- package/.playground/package-lock.json +0 -6
- package/.playground/pages/blog/author.vue +0 -145
- package/.playground/pages/blog/card.vue +0 -149
- package/.playground/pages/blog/cta.vue +0 -131
- package/.playground/pages/blog/detail.vue +0 -471
- package/.playground/pages/blog/list.vue +0 -261
- package/.playground/pages/blog/navigation.vue +0 -228
- package/.playground/pages/blog/sidebar.vue +0 -279
- package/.playground/pages/config.vue +0 -289
- package/.playground/pages/content/comparison.vue +0 -253
- package/.playground/pages/content/cta.vue +0 -245
- package/.playground/pages/content/features.vue +0 -217
- package/.playground/pages/content/newsletter-section.vue +0 -260
- package/.playground/pages/content/newsletter.vue +0 -200
- package/.playground/pages/content/pricing.vue +0 -335
- package/.playground/pages/content/testimonials.vue +0 -188
- package/.playground/pages/hero.vue +0 -257
- package/.playground/pages/index.vue +0 -381
- package/.playground/pages/layout/footer.vue +0 -210
- package/.playground/pages/layout/legal-footer.vue +0 -121
- package/.playground/pages/layout/navbar.vue +0 -285
- package/.playground/pages/layout/section.vue +0 -266
- package/.playground/pages/layout/x-legal.vue +0 -199
- package/.playground/pages/modals/feature-modal.vue +0 -320
- package/.playground/pages/modals/image-lightbox.vue +0 -277
- package/.playground/pages/modals/video-modal.vue +0 -222
- package/.playground/pages/notifications/announcement-bar.vue +0 -164
- package/.playground/pages/notifications/cookie-banner.vue +0 -210
- package/.playground/pages/notifications/cookie-toast.vue +0 -143
- package/.playground/pages/notifications/gdpr.vue +0 -276
- package/.playground/pages/notifications/social-proof-toast.vue +0 -515
- package/.playground/pages/ui/badge.vue +0 -161
- package/.playground/pages/ui/bg-pattern.vue +0 -177
- package/.playground/pages/ui/glass-card.vue +0 -179
- package/.playground/pages/ui/glow-divider.vue +0 -179
- package/.playground/pages/ui/promo-card.vue +0 -259
- package/.playground/pages/ui/section-stitch.vue +0 -411
- package/.playground/pages/utilities/back-to-top.vue +0 -153
- package/.playground/pages/utilities/popup-chat.vue +0 -224
- package/componentList.json +0 -2129
- package/screenshots/playground-home.png +0 -0
- package/tsconfig.json +0 -3
- /package/app/composables/{useXBlog.ts → useXBlog.js} +0 -0
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="min-h-screen">
|
|
3
|
-
<div class="bg-white dark:bg-neutral-900 border-b border-neutral-200 dark:border-neutral-800 px-8 py-6">
|
|
4
|
-
<h1 class="text-2xl font-bold text-neutral-900 dark:text-white">Feature Modal</h1>
|
|
5
|
-
<p class="mt-2 text-neutral-600 dark:text-neutral-400">Full-screen scrollable modal for detailed feature showcases with Apple-style presentation.</p>
|
|
6
|
-
</div>
|
|
7
|
-
|
|
8
|
-
<div class="p-8 space-y-12">
|
|
9
|
-
<!-- Demo Trigger -->
|
|
10
|
-
<section>
|
|
11
|
-
<h2 class="text-lg font-semibold mb-4">Feature Showcase Modal</h2>
|
|
12
|
-
<p class="text-sm text-neutral-500 mb-4">Opens a full-screen scrollable presentation with hero, content blocks, and CTA.</p>
|
|
13
|
-
<XMarkModalFeature
|
|
14
|
-
:hero="hero"
|
|
15
|
-
:blocks="blocks"
|
|
16
|
-
:cta="cta"
|
|
17
|
-
:button="{ label: 'Explore Feature', size: 'lg', icon: 'i-lucide-maximize-2' }"
|
|
18
|
-
@cta-click="handleCtaClick"
|
|
19
|
-
/>
|
|
20
|
-
</section>
|
|
21
|
-
|
|
22
|
-
<!-- Button Object -->
|
|
23
|
-
<section>
|
|
24
|
-
<h2 class="text-lg font-semibold mb-4">Button Object</h2>
|
|
25
|
-
<p class="text-sm text-neutral-500 mb-4">Configure the trigger button with a single object prop.</p>
|
|
26
|
-
<div class="flex flex-wrap gap-4">
|
|
27
|
-
<XMarkModalFeature
|
|
28
|
-
:hero="hero"
|
|
29
|
-
:blocks="blocks"
|
|
30
|
-
:button="{ label: 'Learn More', color: 'primary' }"
|
|
31
|
-
/>
|
|
32
|
-
<XMarkModalFeature
|
|
33
|
-
:hero="hero"
|
|
34
|
-
:blocks="blocks"
|
|
35
|
-
:button="{ label: 'View Details', color: 'secondary', variant: 'outline' }"
|
|
36
|
-
/>
|
|
37
|
-
<XMarkModalFeature
|
|
38
|
-
:hero="hero"
|
|
39
|
-
:blocks="blocks"
|
|
40
|
-
:button="{ label: 'Explore', color: 'neutral', size: 'lg', icon: 'i-lucide-sparkles' }"
|
|
41
|
-
/>
|
|
42
|
-
</div>
|
|
43
|
-
</section>
|
|
44
|
-
|
|
45
|
-
<!-- Custom Trigger -->
|
|
46
|
-
<section>
|
|
47
|
-
<h2 class="text-lg font-semibold mb-4">Custom Trigger (Slot)</h2>
|
|
48
|
-
<p class="text-sm text-neutral-500 mb-4">Use the default slot for a completely custom trigger.</p>
|
|
49
|
-
<XMarkModalFeature
|
|
50
|
-
:hero="hero"
|
|
51
|
-
:blocks="blocks"
|
|
52
|
-
:cta="cta"
|
|
53
|
-
>
|
|
54
|
-
<UButton size="xl" label="Advanced Analytics" leading-icon="i-lucide-layers" trailing-icon="i-lucide-arrow-right" />
|
|
55
|
-
</XMarkModalFeature>
|
|
56
|
-
</section>
|
|
57
|
-
|
|
58
|
-
<!-- Block Types -->
|
|
59
|
-
<section>
|
|
60
|
-
<h2 class="text-lg font-semibold mb-4">Available Block Types</h2>
|
|
61
|
-
<div class="grid md:grid-cols-3 gap-6">
|
|
62
|
-
<article class="p-6 rounded-lg bg-neutral-100 dark:bg-neutral-800">
|
|
63
|
-
<h3 class="font-semibold mb-2">Image Block</h3>
|
|
64
|
-
<p class="text-sm text-neutral-600 dark:text-neutral-400">Full-screen image section</p>
|
|
65
|
-
<pre class="mt-4 text-xs bg-neutral-200 dark:bg-neutral-700 p-2 rounded overflow-x-auto"><code>{
|
|
66
|
-
type: 'image',
|
|
67
|
-
image: 'url',
|
|
68
|
-
alt: 'description'
|
|
69
|
-
}</code></pre>
|
|
70
|
-
</article>
|
|
71
|
-
<article class="p-6 rounded-lg bg-neutral-100 dark:bg-neutral-800">
|
|
72
|
-
<h3 class="font-semibold mb-2">Text Block</h3>
|
|
73
|
-
<p class="text-sm text-neutral-600 dark:text-neutral-400">Centered text content</p>
|
|
74
|
-
<pre class="mt-4 text-xs bg-neutral-200 dark:bg-neutral-700 p-2 rounded overflow-x-auto"><code>{
|
|
75
|
-
type: 'text',
|
|
76
|
-
title: 'Heading',
|
|
77
|
-
body: 'Content...',
|
|
78
|
-
bg: 'bg-white'
|
|
79
|
-
}</code></pre>
|
|
80
|
-
</article>
|
|
81
|
-
<article class="p-6 rounded-lg bg-neutral-100 dark:bg-neutral-800">
|
|
82
|
-
<h3 class="font-semibold mb-2">Split Block</h3>
|
|
83
|
-
<p class="text-sm text-neutral-600 dark:text-neutral-400">Image + text side by side</p>
|
|
84
|
-
<pre class="mt-4 text-xs bg-neutral-200 dark:bg-neutral-700 p-2 rounded overflow-x-auto"><code>{
|
|
85
|
-
type: 'split',
|
|
86
|
-
title: 'Feature',
|
|
87
|
-
body: 'Details...',
|
|
88
|
-
image: 'url',
|
|
89
|
-
imagePosition: 'left',
|
|
90
|
-
features: [...]
|
|
91
|
-
}</code></pre>
|
|
92
|
-
</article>
|
|
93
|
-
</div>
|
|
94
|
-
</section>
|
|
95
|
-
|
|
96
|
-
<!-- Props -->
|
|
97
|
-
<section>
|
|
98
|
-
<h2 class="text-lg font-semibold mb-4">Props</h2>
|
|
99
|
-
<table class="w-full text-sm">
|
|
100
|
-
<thead>
|
|
101
|
-
<tr class="border-b border-neutral-200 dark:border-neutral-700">
|
|
102
|
-
<th class="text-left py-3 px-4">Prop</th>
|
|
103
|
-
<th class="text-left py-3 px-4">Type</th>
|
|
104
|
-
<th class="text-left py-3 px-4">Default</th>
|
|
105
|
-
<th class="text-left py-3 px-4">Description</th>
|
|
106
|
-
</tr>
|
|
107
|
-
</thead>
|
|
108
|
-
<tbody class="divide-y divide-neutral-200 dark:divide-neutral-700">
|
|
109
|
-
<tr><td class="py-3 px-4 font-mono text-xs">hero</td><td class="py-3 px-4">Object</td><td class="py-3 px-4">null</td><td class="py-3 px-4">Hero section { image, title, subtitle }</td></tr>
|
|
110
|
-
<tr><td class="py-3 px-4 font-mono text-xs">blocks</td><td class="py-3 px-4">Array</td><td class="py-3 px-4">[]</td><td class="py-3 px-4">Array of content blocks</td></tr>
|
|
111
|
-
<tr><td class="py-3 px-4 font-mono text-xs">cta</td><td class="py-3 px-4">Object</td><td class="py-3 px-4">null</td><td class="py-3 px-4">CTA section { title, subtitle, button, bg }</td></tr>
|
|
112
|
-
<tr><td class="py-3 px-4 font-mono text-xs">button</td><td class="py-3 px-4">Object</td><td class="py-3 px-4">{}</td><td class="py-3 px-4">{ label, color, variant, size, icon }</td></tr>
|
|
113
|
-
</tbody>
|
|
114
|
-
</table>
|
|
115
|
-
</section>
|
|
116
|
-
|
|
117
|
-
<!-- Button Object Properties -->
|
|
118
|
-
<section>
|
|
119
|
-
<h2 class="text-lg font-semibold mb-4">Button Object Properties</h2>
|
|
120
|
-
<table class="w-full text-sm">
|
|
121
|
-
<thead>
|
|
122
|
-
<tr class="border-b border-neutral-200 dark:border-neutral-700">
|
|
123
|
-
<th class="text-left py-3 px-4">Property</th>
|
|
124
|
-
<th class="text-left py-3 px-4">Type</th>
|
|
125
|
-
<th class="text-left py-3 px-4">Default</th>
|
|
126
|
-
</tr>
|
|
127
|
-
</thead>
|
|
128
|
-
<tbody class="divide-y divide-neutral-200 dark:divide-neutral-700">
|
|
129
|
-
<tr><td class="py-3 px-4 font-mono text-xs">label</td><td class="py-3 px-4">String</td><td class="py-3 px-4">'Learn More'</td></tr>
|
|
130
|
-
<tr><td class="py-3 px-4 font-mono text-xs">color</td><td class="py-3 px-4">String</td><td class="py-3 px-4">'primary'</td></tr>
|
|
131
|
-
<tr><td class="py-3 px-4 font-mono text-xs">variant</td><td class="py-3 px-4">String</td><td class="py-3 px-4">'solid'</td></tr>
|
|
132
|
-
<tr><td class="py-3 px-4 font-mono text-xs">size</td><td class="py-3 px-4">String</td><td class="py-3 px-4">'md'</td></tr>
|
|
133
|
-
<tr><td class="py-3 px-4 font-mono text-xs">icon</td><td class="py-3 px-4">String</td><td class="py-3 px-4">''</td></tr>
|
|
134
|
-
</tbody>
|
|
135
|
-
</table>
|
|
136
|
-
</section>
|
|
137
|
-
|
|
138
|
-
<!-- Hero Configuration -->
|
|
139
|
-
<section>
|
|
140
|
-
<h2 class="text-lg font-semibold mb-4">Hero Configuration</h2>
|
|
141
|
-
<pre class="bg-neutral-100 dark:bg-neutral-800 p-4 rounded-lg text-sm overflow-x-auto"><code>hero: {
|
|
142
|
-
image: 'https://example.com/hero.jpg',
|
|
143
|
-
title: 'Feature Name',
|
|
144
|
-
subtitle: 'Feature description'
|
|
145
|
-
}</code></pre>
|
|
146
|
-
</section>
|
|
147
|
-
|
|
148
|
-
<!-- Blocks Configuration -->
|
|
149
|
-
<section>
|
|
150
|
-
<h2 class="text-lg font-semibold mb-4">Blocks Configuration</h2>
|
|
151
|
-
<pre class="bg-neutral-100 dark:bg-neutral-800 p-4 rounded-lg text-sm overflow-x-auto"><code>blocks: [
|
|
152
|
-
// Full-width image
|
|
153
|
-
{
|
|
154
|
-
type: 'image',
|
|
155
|
-
image: 'https://example.com/showcase.jpg',
|
|
156
|
-
alt: 'Feature showcase'
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
// Centered text section
|
|
160
|
-
{
|
|
161
|
-
type: 'text',
|
|
162
|
-
title: 'Section Title',
|
|
163
|
-
body: 'Detailed explanation of the feature...',
|
|
164
|
-
bg: 'bg-neutral-50' // Optional background class
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
// Split layout with image
|
|
168
|
-
{
|
|
169
|
-
type: 'split',
|
|
170
|
-
title: 'Feature Highlight',
|
|
171
|
-
body: 'Description of this specific feature...',
|
|
172
|
-
image: 'https://example.com/feature.jpg',
|
|
173
|
-
imagePosition: 'left', // 'left' or 'right'
|
|
174
|
-
features: [ // Optional bullet points
|
|
175
|
-
'Benefit one',
|
|
176
|
-
'Benefit two',
|
|
177
|
-
'Benefit three'
|
|
178
|
-
],
|
|
179
|
-
bg: 'bg-white'
|
|
180
|
-
}
|
|
181
|
-
]</code></pre>
|
|
182
|
-
</section>
|
|
183
|
-
|
|
184
|
-
<!-- CTA Configuration -->
|
|
185
|
-
<section>
|
|
186
|
-
<h2 class="text-lg font-semibold mb-4">CTA Configuration</h2>
|
|
187
|
-
<pre class="bg-neutral-100 dark:bg-neutral-800 p-4 rounded-lg text-sm overflow-x-auto"><code>cta: {
|
|
188
|
-
title: 'Ready to get started?',
|
|
189
|
-
subtitle: 'Join thousands of satisfied customers',
|
|
190
|
-
button: { label: 'Start Free Trial', color: 'primary' },
|
|
191
|
-
bg: 'bg-neutral-950' // Optional background class
|
|
192
|
-
}</code></pre>
|
|
193
|
-
</section>
|
|
194
|
-
|
|
195
|
-
<!-- Events -->
|
|
196
|
-
<section>
|
|
197
|
-
<h2 class="text-lg font-semibold mb-4">Events</h2>
|
|
198
|
-
<table class="w-full text-sm">
|
|
199
|
-
<thead>
|
|
200
|
-
<tr class="border-b border-neutral-200 dark:border-neutral-700">
|
|
201
|
-
<th class="text-left py-3 px-4">Event</th>
|
|
202
|
-
<th class="text-left py-3 px-4">Description</th>
|
|
203
|
-
</tr>
|
|
204
|
-
</thead>
|
|
205
|
-
<tbody class="divide-y divide-neutral-200 dark:divide-neutral-700">
|
|
206
|
-
<tr><td class="py-3 px-4 font-mono text-xs">@open</td><td class="py-3 px-4">Emitted when modal opens</td></tr>
|
|
207
|
-
<tr><td class="py-3 px-4 font-mono text-xs">@close</td><td class="py-3 px-4">Emitted when modal closes</td></tr>
|
|
208
|
-
<tr><td class="py-3 px-4 font-mono text-xs">@cta-click</td><td class="py-3 px-4">Emitted when CTA button is clicked</td></tr>
|
|
209
|
-
</tbody>
|
|
210
|
-
</table>
|
|
211
|
-
</section>
|
|
212
|
-
|
|
213
|
-
<!-- Code Example -->
|
|
214
|
-
<section>
|
|
215
|
-
<h2 class="text-lg font-semibold mb-4">Code Example</h2>
|
|
216
|
-
<CodeExample title="Feature Modal Usage" :code="codeExample" />
|
|
217
|
-
</section>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
</template>
|
|
221
|
-
|
|
222
|
-
<script setup>
|
|
223
|
-
const codeExample = `<!-- With button trigger (object) -->
|
|
224
|
-
<XMarkModalFeature
|
|
225
|
-
:hero="{
|
|
226
|
-
image: '/images/hero.jpg',
|
|
227
|
-
title: 'Advanced Analytics',
|
|
228
|
-
subtitle: 'Gain deep insights into your data'
|
|
229
|
-
}"
|
|
230
|
-
:blocks="[
|
|
231
|
-
{ type: 'text', title: 'Overview', body: 'Description...' },
|
|
232
|
-
{ type: 'image', image: '/showcase.jpg', alt: 'Feature showcase' },
|
|
233
|
-
{
|
|
234
|
-
type: 'split',
|
|
235
|
-
title: 'Key Feature',
|
|
236
|
-
body: 'Feature details...',
|
|
237
|
-
image: '/feature.jpg',
|
|
238
|
-
imagePosition: 'right',
|
|
239
|
-
features: ['Benefit 1', 'Benefit 2', 'Benefit 3']
|
|
240
|
-
}
|
|
241
|
-
]"
|
|
242
|
-
:cta="{
|
|
243
|
-
title: 'Ready to start?',
|
|
244
|
-
subtitle: 'Free 14-day trial',
|
|
245
|
-
button: { label: 'Start Free Trial', color: 'primary' }
|
|
246
|
-
}"
|
|
247
|
-
:button="{ label: 'Learn More', size: 'lg', icon: 'i-lucide-maximize-2' }"
|
|
248
|
-
@cta-click="handleCtaClick"
|
|
249
|
-
/>
|
|
250
|
-
|
|
251
|
-
<!-- Custom trigger (slot) -->
|
|
252
|
-
<XMarkModalFeature :hero="hero" :blocks="blocks">
|
|
253
|
-
<UButton size="lg" label="Explore Feature" leading-icon="i-lucide-layers" />
|
|
254
|
-
</XMarkModalFeature>
|
|
255
|
-
|
|
256
|
-
<!-- Minimal (no hero/CTA) -->
|
|
257
|
-
<XMarkModalFeature
|
|
258
|
-
:blocks="blocks"
|
|
259
|
-
:button="{ label: 'View Feature' }"
|
|
260
|
-
/>`
|
|
261
|
-
|
|
262
|
-
const hero = {
|
|
263
|
-
image: 'https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=1920&h=1080&fit=crop',
|
|
264
|
-
title: 'Advanced Analytics',
|
|
265
|
-
subtitle: 'Gain deep insights into your data with powerful visualization tools'
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const blocks = [
|
|
269
|
-
{
|
|
270
|
-
type: 'text',
|
|
271
|
-
title: 'Understand Your Data Like Never Before',
|
|
272
|
-
body: 'Our analytics platform transforms raw data into actionable insights. With real-time dashboards and customizable reports, you can make data-driven decisions faster than ever before.',
|
|
273
|
-
bg: 'bg-white dark:bg-neutral-950'
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
type: 'image',
|
|
277
|
-
image: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=1920&h=1080&fit=crop',
|
|
278
|
-
alt: 'Analytics dashboard'
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
type: 'split',
|
|
282
|
-
title: 'Real-Time Monitoring',
|
|
283
|
-
body: 'Track your key metrics as they happen. Our real-time monitoring system ensures you never miss an important trend or anomaly.',
|
|
284
|
-
image: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&h=600&fit=crop',
|
|
285
|
-
imagePosition: 'right',
|
|
286
|
-
features: [
|
|
287
|
-
'Live data streaming',
|
|
288
|
-
'Customizable alerts',
|
|
289
|
-
'Trend detection',
|
|
290
|
-
'Anomaly identification'
|
|
291
|
-
],
|
|
292
|
-
bg: 'bg-neutral-50 dark:bg-neutral-900'
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
type: 'split',
|
|
296
|
-
title: 'Powerful Reporting',
|
|
297
|
-
body: 'Generate beautiful, shareable reports with just a few clicks. Export to PDF, Excel, or share via link with your team.',
|
|
298
|
-
image: 'https://images.unsplash.com/photo-1551434678-e076c223a692?w=800&h=600&fit=crop',
|
|
299
|
-
imagePosition: 'left',
|
|
300
|
-
features: [
|
|
301
|
-
'Automated report generation',
|
|
302
|
-
'Custom branding options',
|
|
303
|
-
'Scheduled delivery',
|
|
304
|
-
'Interactive charts'
|
|
305
|
-
],
|
|
306
|
-
bg: 'bg-white dark:bg-neutral-950'
|
|
307
|
-
}
|
|
308
|
-
]
|
|
309
|
-
|
|
310
|
-
const cta = {
|
|
311
|
-
title: 'Ready to Transform Your Data?',
|
|
312
|
-
subtitle: 'Start your free 14-day trial today. No credit card required.',
|
|
313
|
-
button: { label: 'Start Free Trial', color: 'primary' },
|
|
314
|
-
bg: 'bg-primary-600'
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const handleCtaClick = () => {
|
|
318
|
-
console.log('CTA clicked!')
|
|
319
|
-
}
|
|
320
|
-
</script>
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="min-h-screen">
|
|
3
|
-
<div class="bg-white dark:bg-neutral-900 border-b border-neutral-200 dark:border-neutral-800 px-8 py-6">
|
|
4
|
-
<h1 class="text-2xl font-bold text-neutral-900 dark:text-white">Image Lightbox</h1>
|
|
5
|
-
<p class="mt-2 text-neutral-600 dark:text-neutral-400">Full-screen image viewer with gallery navigation.</p>
|
|
6
|
-
</div>
|
|
7
|
-
|
|
8
|
-
<div class="p-8 space-y-12">
|
|
9
|
-
<!-- Single Image -->
|
|
10
|
-
<section>
|
|
11
|
-
<h2 class="text-lg font-semibold mb-4">Single Image</h2>
|
|
12
|
-
<p class="text-sm text-neutral-500 mb-4">Click to open lightbox</p>
|
|
13
|
-
<button
|
|
14
|
-
class="rounded-xl overflow-hidden cursor-zoom-in"
|
|
15
|
-
@click="openSingle"
|
|
16
|
-
>
|
|
17
|
-
<img
|
|
18
|
-
:src="singleImage[0].src"
|
|
19
|
-
:alt="singleImage[0].alt"
|
|
20
|
-
class="w-80 h-60 object-cover hover:opacity-90 transition-opacity"
|
|
21
|
-
/>
|
|
22
|
-
</button>
|
|
23
|
-
<XMarkModalImage
|
|
24
|
-
v-model="singleOpen"
|
|
25
|
-
:images="singleImage"
|
|
26
|
-
/>
|
|
27
|
-
</section>
|
|
28
|
-
|
|
29
|
-
<!-- Gallery Grid -->
|
|
30
|
-
<section>
|
|
31
|
-
<h2 class="text-lg font-semibold mb-4">Gallery with Navigation</h2>
|
|
32
|
-
<p class="text-sm text-neutral-500 mb-4">Click any image to open gallery. Use arrows or keyboard to navigate.</p>
|
|
33
|
-
<div class="grid grid-cols-4 gap-4">
|
|
34
|
-
<button
|
|
35
|
-
v-for="(image, index) in galleryImages"
|
|
36
|
-
:key="index"
|
|
37
|
-
class="rounded-lg overflow-hidden aspect-square cursor-zoom-in"
|
|
38
|
-
@click="openGallery(index)"
|
|
39
|
-
>
|
|
40
|
-
<img
|
|
41
|
-
:src="image.src"
|
|
42
|
-
:alt="image.alt"
|
|
43
|
-
class="w-full h-full object-cover hover:opacity-90 transition-opacity"
|
|
44
|
-
/>
|
|
45
|
-
</button>
|
|
46
|
-
</div>
|
|
47
|
-
<XMarkModalImage
|
|
48
|
-
v-model="galleryOpen"
|
|
49
|
-
:images="galleryImages"
|
|
50
|
-
:start-index="galleryIndex"
|
|
51
|
-
:has-counter="true"
|
|
52
|
-
/>
|
|
53
|
-
</section>
|
|
54
|
-
|
|
55
|
-
<!-- With Thumbnails -->
|
|
56
|
-
<section>
|
|
57
|
-
<h2 class="text-lg font-semibold mb-4">With Thumbnail Navigation</h2>
|
|
58
|
-
<div class="grid grid-cols-6 gap-2">
|
|
59
|
-
<button
|
|
60
|
-
v-for="(image, index) in thumbnailImages"
|
|
61
|
-
:key="index"
|
|
62
|
-
class="rounded-lg overflow-hidden aspect-square cursor-zoom-in"
|
|
63
|
-
@click="openThumbnails(index)"
|
|
64
|
-
>
|
|
65
|
-
<img
|
|
66
|
-
:src="image.src"
|
|
67
|
-
:alt="image.alt"
|
|
68
|
-
class="w-full h-full object-cover hover:opacity-90 transition-opacity"
|
|
69
|
-
/>
|
|
70
|
-
</button>
|
|
71
|
-
</div>
|
|
72
|
-
<XMarkModalImage
|
|
73
|
-
v-model="thumbnailOpen"
|
|
74
|
-
:images="thumbnailImages"
|
|
75
|
-
:start-index="thumbnailIndex"
|
|
76
|
-
:has-counter="true"
|
|
77
|
-
:has-thumbnails="true"
|
|
78
|
-
/>
|
|
79
|
-
</section>
|
|
80
|
-
|
|
81
|
-
<!-- With Captions -->
|
|
82
|
-
<section>
|
|
83
|
-
<h2 class="text-lg font-semibold mb-4">With Captions</h2>
|
|
84
|
-
<div class="flex gap-4">
|
|
85
|
-
<button
|
|
86
|
-
v-for="(image, index) in captionImages"
|
|
87
|
-
:key="index"
|
|
88
|
-
class="rounded-lg overflow-hidden w-48 h-32 cursor-zoom-in"
|
|
89
|
-
@click="openCaptions(index)"
|
|
90
|
-
>
|
|
91
|
-
<img
|
|
92
|
-
:src="image.src"
|
|
93
|
-
:alt="image.alt"
|
|
94
|
-
class="w-full h-full object-cover hover:opacity-90 transition-opacity"
|
|
95
|
-
/>
|
|
96
|
-
</button>
|
|
97
|
-
</div>
|
|
98
|
-
<XMarkModalImage
|
|
99
|
-
v-model="captionOpen"
|
|
100
|
-
:images="captionImages"
|
|
101
|
-
:start-index="captionIndex"
|
|
102
|
-
/>
|
|
103
|
-
</section>
|
|
104
|
-
|
|
105
|
-
<!-- Props -->
|
|
106
|
-
<section>
|
|
107
|
-
<h2 class="text-lg font-semibold mb-4">Props</h2>
|
|
108
|
-
<div class="overflow-x-auto">
|
|
109
|
-
<table class="w-full text-sm">
|
|
110
|
-
<thead>
|
|
111
|
-
<tr class="border-b border-neutral-200 dark:border-neutral-700">
|
|
112
|
-
<th class="text-left py-3 px-4 font-medium">Prop</th>
|
|
113
|
-
<th class="text-left py-3 px-4 font-medium">Type</th>
|
|
114
|
-
<th class="text-left py-3 px-4 font-medium">Default</th>
|
|
115
|
-
<th class="text-left py-3 px-4 font-medium">Description</th>
|
|
116
|
-
</tr>
|
|
117
|
-
</thead>
|
|
118
|
-
<tbody class="divide-y divide-neutral-200 dark:divide-neutral-700">
|
|
119
|
-
<tr>
|
|
120
|
-
<td class="py-3 px-4 font-mono text-xs">v-model</td>
|
|
121
|
-
<td class="py-3 px-4">Boolean</td>
|
|
122
|
-
<td class="py-3 px-4">false</td>
|
|
123
|
-
<td class="py-3 px-4 text-neutral-600 dark:text-neutral-400">Lightbox visibility state</td>
|
|
124
|
-
</tr>
|
|
125
|
-
<tr>
|
|
126
|
-
<td class="py-3 px-4 font-mono text-xs">images</td>
|
|
127
|
-
<td class="py-3 px-4">Array</td>
|
|
128
|
-
<td class="py-3 px-4">[]</td>
|
|
129
|
-
<td class="py-3 px-4 text-neutral-600 dark:text-neutral-400">Array of { src, alt, caption? }</td>
|
|
130
|
-
</tr>
|
|
131
|
-
<tr>
|
|
132
|
-
<td class="py-3 px-4 font-mono text-xs">startIndex</td>
|
|
133
|
-
<td class="py-3 px-4">Number</td>
|
|
134
|
-
<td class="py-3 px-4">0</td>
|
|
135
|
-
<td class="py-3 px-4 text-neutral-600 dark:text-neutral-400">Starting image index for gallery</td>
|
|
136
|
-
</tr>
|
|
137
|
-
<tr>
|
|
138
|
-
<td class="py-3 px-4 font-mono text-xs">hasCounter</td>
|
|
139
|
-
<td class="py-3 px-4">Boolean</td>
|
|
140
|
-
<td class="py-3 px-4">true</td>
|
|
141
|
-
<td class="py-3 px-4 text-neutral-600 dark:text-neutral-400">Show image counter (1/5)</td>
|
|
142
|
-
</tr>
|
|
143
|
-
<tr>
|
|
144
|
-
<td class="py-3 px-4 font-mono text-xs">hasThumbnails</td>
|
|
145
|
-
<td class="py-3 px-4">Boolean</td>
|
|
146
|
-
<td class="py-3 px-4">false</td>
|
|
147
|
-
<td class="py-3 px-4 text-neutral-600 dark:text-neutral-400">Show thumbnail navigation strip</td>
|
|
148
|
-
</tr>
|
|
149
|
-
</tbody>
|
|
150
|
-
</table>
|
|
151
|
-
</div>
|
|
152
|
-
</section>
|
|
153
|
-
|
|
154
|
-
<!-- Image Object -->
|
|
155
|
-
<section>
|
|
156
|
-
<h2 class="text-lg font-semibold mb-4">Image Object Structure</h2>
|
|
157
|
-
<pre class="bg-neutral-100 dark:bg-neutral-800 p-4 rounded-lg text-sm overflow-x-auto"><code>{
|
|
158
|
-
src: 'https://example.com/image.jpg', // Required
|
|
159
|
-
alt: 'Image description', // Required
|
|
160
|
-
caption: 'Optional caption text' // Optional
|
|
161
|
-
}</code></pre>
|
|
162
|
-
</section>
|
|
163
|
-
|
|
164
|
-
<!-- Keyboard Navigation -->
|
|
165
|
-
<section>
|
|
166
|
-
<h2 class="text-lg font-semibold mb-4">Keyboard Navigation</h2>
|
|
167
|
-
<div class="grid md:grid-cols-3 gap-4">
|
|
168
|
-
<div class="p-4 rounded-lg bg-neutral-100 dark:bg-neutral-800 text-center">
|
|
169
|
-
<kbd class="px-2 py-1 bg-neutral-200 dark:bg-neutral-700 rounded text-sm">Arrow Left</kbd>
|
|
170
|
-
<p class="mt-2 text-sm text-neutral-600 dark:text-neutral-400">Previous image</p>
|
|
171
|
-
</div>
|
|
172
|
-
<div class="p-4 rounded-lg bg-neutral-100 dark:bg-neutral-800 text-center">
|
|
173
|
-
<kbd class="px-2 py-1 bg-neutral-200 dark:bg-neutral-700 rounded text-sm">Arrow Right</kbd>
|
|
174
|
-
<p class="mt-2 text-sm text-neutral-600 dark:text-neutral-400">Next image</p>
|
|
175
|
-
</div>
|
|
176
|
-
<div class="p-4 rounded-lg bg-neutral-100 dark:bg-neutral-800 text-center">
|
|
177
|
-
<kbd class="px-2 py-1 bg-neutral-200 dark:bg-neutral-700 rounded text-sm">Escape</kbd>
|
|
178
|
-
<p class="mt-2 text-sm text-neutral-600 dark:text-neutral-400">Close lightbox</p>
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
</section>
|
|
182
|
-
|
|
183
|
-
<!-- Code Example -->
|
|
184
|
-
<section>
|
|
185
|
-
<h2 class="text-lg font-semibold mb-4">Code Example</h2>
|
|
186
|
-
<CodeExample title="Image Lightbox Usage" :code="codeExample" />
|
|
187
|
-
</section>
|
|
188
|
-
</div>
|
|
189
|
-
</div>
|
|
190
|
-
</template>
|
|
191
|
-
|
|
192
|
-
<script setup>
|
|
193
|
-
const codeExample = `<!-- Single image -->
|
|
194
|
-
<button @click="lightboxOpen = true">
|
|
195
|
-
<img :src="images[0].src" :alt="images[0].alt" />
|
|
196
|
-
</button>
|
|
197
|
-
<XMarkModalImage
|
|
198
|
-
v-model="lightboxOpen"
|
|
199
|
-
:images="images"
|
|
200
|
-
/>
|
|
201
|
-
|
|
202
|
-
<!-- Gallery with thumbnails -->
|
|
203
|
-
<div class="grid grid-cols-4 gap-4">
|
|
204
|
-
<button
|
|
205
|
-
v-for="(image, index) in images"
|
|
206
|
-
:key="index"
|
|
207
|
-
@click="openGallery(index)"
|
|
208
|
-
>
|
|
209
|
-
<img :src="image.src" :alt="image.alt" />
|
|
210
|
-
</button>
|
|
211
|
-
</div>
|
|
212
|
-
<XMarkModalImage
|
|
213
|
-
v-model="galleryOpen"
|
|
214
|
-
:images="images"
|
|
215
|
-
:start-index="startIndex"
|
|
216
|
-
:has-counter="true"
|
|
217
|
-
:has-thumbnails="true"
|
|
218
|
-
/>
|
|
219
|
-
|
|
220
|
-
<!-- Image data structure -->
|
|
221
|
-
const images = [
|
|
222
|
-
{ src: 'https://...', alt: 'Image 1', caption: 'Optional caption' },
|
|
223
|
-
{ src: 'https://...', alt: 'Image 2' }
|
|
224
|
-
]`
|
|
225
|
-
|
|
226
|
-
const singleOpen = ref(false)
|
|
227
|
-
const singleImage = [
|
|
228
|
-
{ src: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1200&h=800&fit=crop', alt: 'Mountain landscape' }
|
|
229
|
-
]
|
|
230
|
-
|
|
231
|
-
const openSingle = () => {
|
|
232
|
-
singleOpen.value = true
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const galleryOpen = ref(false)
|
|
236
|
-
const galleryIndex = ref(0)
|
|
237
|
-
const galleryImages = [
|
|
238
|
-
{ src: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=1200&h=800&fit=crop', alt: 'Nature 1' },
|
|
239
|
-
{ src: 'https://images.unsplash.com/photo-1447752875215-b2761acb3c5d?w=1200&h=800&fit=crop', alt: 'Nature 2' },
|
|
240
|
-
{ src: 'https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=1200&h=800&fit=crop', alt: 'Nature 3' },
|
|
241
|
-
{ src: 'https://images.unsplash.com/photo-1501854140801-50d01698950b?w=1200&h=800&fit=crop', alt: 'Nature 4' }
|
|
242
|
-
]
|
|
243
|
-
|
|
244
|
-
const openGallery = (index) => {
|
|
245
|
-
galleryIndex.value = index
|
|
246
|
-
galleryOpen.value = true
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const thumbnailOpen = ref(false)
|
|
250
|
-
const thumbnailIndex = ref(0)
|
|
251
|
-
const thumbnailImages = [
|
|
252
|
-
{ src: 'https://images.unsplash.com/photo-1519681393784-d120267933ba?w=1200&h=800&fit=crop', alt: 'Mountain 1' },
|
|
253
|
-
{ src: 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=1200&h=800&fit=crop', alt: 'Mountain 2' },
|
|
254
|
-
{ src: 'https://images.unsplash.com/photo-1486870591958-9b9d0d1dda99?w=1200&h=800&fit=crop', alt: 'Mountain 3' },
|
|
255
|
-
{ src: 'https://images.unsplash.com/photo-1454496522488-7a8e488e8606?w=1200&h=800&fit=crop', alt: 'Mountain 4' },
|
|
256
|
-
{ src: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=1200&h=800&fit=crop', alt: 'Mountain 5' },
|
|
257
|
-
{ src: 'https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=1200&h=800&fit=crop', alt: 'Mountain 6' }
|
|
258
|
-
]
|
|
259
|
-
|
|
260
|
-
const openThumbnails = (index) => {
|
|
261
|
-
thumbnailIndex.value = index
|
|
262
|
-
thumbnailOpen.value = true
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const captionOpen = ref(false)
|
|
266
|
-
const captionIndex = ref(0)
|
|
267
|
-
const captionImages = [
|
|
268
|
-
{ src: 'https://images.unsplash.com/photo-1551524164-687a55dd1126?w=1200&h=800&fit=crop', alt: 'Architecture 1', caption: 'Modern Architecture in Downtown' },
|
|
269
|
-
{ src: 'https://images.unsplash.com/photo-1487958449943-2429e8be8625?w=1200&h=800&fit=crop', alt: 'Architecture 2', caption: 'Glass and Steel Office Building' },
|
|
270
|
-
{ src: 'https://images.unsplash.com/photo-1479839672679-a46483c0e7c8?w=1200&h=800&fit=crop', alt: 'Architecture 3', caption: 'Historic Church Exterior' }
|
|
271
|
-
]
|
|
272
|
-
|
|
273
|
-
const openCaptions = (index) => {
|
|
274
|
-
captionIndex.value = index
|
|
275
|
-
captionOpen.value = true
|
|
276
|
-
}
|
|
277
|
-
</script>
|