@xenterprises/nuxt-x-marketing 0.0.24 → 1.0.1

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 (114) hide show
  1. package/.playground/app.config.ts +44 -45
  2. package/.playground/app.vue +263 -0
  3. package/.playground/components/AppFooter.vue +103 -0
  4. package/.playground/components/AppHeader.vue +41 -0
  5. package/.playground/components/CodeExample.vue +70 -0
  6. package/.playground/components/ComponentPlayground.vue +117 -0
  7. package/.playground/components/DocsHeader.vue +19 -0
  8. package/.playground/layouts/default.vue +13 -3
  9. package/.playground/layouts/docs-layout.vue +161 -0
  10. package/.playground/layouts/docs.vue +11 -0
  11. package/.playground/pages/blog/author.vue +145 -0
  12. package/.playground/pages/blog/card.vue +149 -0
  13. package/.playground/pages/blog/cta.vue +131 -0
  14. package/.playground/pages/blog/detail.vue +471 -0
  15. package/.playground/pages/blog/list.vue +261 -0
  16. package/.playground/pages/blog/navigation.vue +228 -0
  17. package/.playground/pages/blog/sidebar.vue +279 -0
  18. package/.playground/pages/config.vue +289 -0
  19. package/.playground/pages/content/comparison.vue +253 -0
  20. package/.playground/pages/content/cta.vue +245 -0
  21. package/.playground/pages/content/features.vue +217 -0
  22. package/.playground/pages/content/newsletter-section.vue +260 -0
  23. package/.playground/pages/content/newsletter.vue +200 -0
  24. package/.playground/pages/content/pricing.vue +335 -0
  25. package/.playground/pages/content/testimonials.vue +188 -0
  26. package/.playground/pages/hero.vue +257 -0
  27. package/.playground/pages/index.vue +379 -2
  28. package/.playground/pages/layout/footer.vue +210 -0
  29. package/.playground/pages/layout/legal-footer.vue +121 -0
  30. package/.playground/pages/layout/navbar.vue +285 -0
  31. package/.playground/pages/layout/section.vue +266 -0
  32. package/.playground/pages/layout/x-legal.vue +199 -0
  33. package/.playground/pages/modals/feature-modal.vue +320 -0
  34. package/.playground/pages/modals/image-lightbox.vue +277 -0
  35. package/.playground/pages/modals/video-modal.vue +222 -0
  36. package/.playground/pages/notifications/announcement-bar.vue +164 -0
  37. package/.playground/pages/notifications/cookie-banner.vue +210 -0
  38. package/.playground/pages/notifications/cookie-toast.vue +143 -0
  39. package/.playground/pages/notifications/gdpr.vue +276 -0
  40. package/.playground/pages/notifications/social-proof-toast.vue +515 -0
  41. package/.playground/pages/ui/badge.vue +161 -0
  42. package/.playground/pages/ui/bg-pattern.vue +177 -0
  43. package/.playground/pages/ui/glass-card.vue +179 -0
  44. package/.playground/pages/ui/glow-divider.vue +179 -0
  45. package/.playground/pages/ui/promo-card.vue +259 -0
  46. package/.playground/pages/ui/section-stitch.vue +411 -0
  47. package/.playground/pages/utilities/back-to-top.vue +153 -0
  48. package/.playground/pages/utilities/popup-chat.vue +224 -0
  49. package/README.md +799 -164
  50. package/app/app.config.ts +88 -2
  51. package/app/app.vue +106 -11
  52. package/app/assets/css/x-marketing.css +669 -0
  53. package/app/components/X/Footer/XLegal/index.vue +63 -26
  54. package/app/components/X/Footer/index.vue +89 -89
  55. package/app/components/X/Header/App.vue +63 -0
  56. package/app/components/X/Mark/Blog/Author.vue +170 -0
  57. package/app/components/X/Mark/Blog/CTANewsletter.vue +197 -0
  58. package/app/components/X/Mark/Blog/Card.vue +117 -0
  59. package/app/components/X/Mark/Blog/Detail.vue +187 -0
  60. package/app/components/X/Mark/Blog/List.vue +156 -0
  61. package/app/components/X/Mark/Blog/Navigation.vue +100 -0
  62. package/app/components/X/Mark/Blog/Sidebar.vue +160 -0
  63. package/app/components/X/Mark/Button/BackToTop.vue +99 -0
  64. package/app/components/X/Mark/CTA/index.vue +294 -0
  65. package/app/components/X/Mark/Card/Glass.vue +64 -0
  66. package/app/components/X/Mark/Card/Promo.vue +164 -0
  67. package/app/components/X/Mark/CodeBlock/index.vue +69 -0
  68. package/app/components/X/Mark/Divider/Glow.vue +113 -0
  69. package/app/components/X/Mark/Features/index.vue +194 -0
  70. package/app/components/X/Mark/Hero/index.vue +217 -0
  71. package/app/components/X/Mark/Layout/AnnouncementBar.vue +139 -0
  72. package/app/components/X/Mark/Layout/Footer.vue +160 -0
  73. package/app/components/X/Mark/Layout/FooterLegal.vue +42 -0
  74. package/app/components/X/Mark/Layout/Navbar.vue +267 -0
  75. package/app/components/X/Mark/Modal/Chat.vue +151 -0
  76. package/app/components/X/Mark/Modal/Feature.vue +197 -0
  77. package/app/components/X/Mark/Modal/Image.vue +226 -0
  78. package/app/components/X/Mark/Modal/Video.vue +203 -0
  79. package/app/components/X/Mark/Modal/index.vue +133 -0
  80. package/app/components/X/Mark/Newsletter/Form.vue +174 -0
  81. package/app/components/X/Mark/Pattern/Bg.vue +86 -0
  82. package/app/components/X/Mark/Pricing/Comparison.vue +126 -0
  83. package/app/components/X/Mark/Pricing/Plans.vue +181 -0
  84. package/app/components/X/Mark/Privacy/CookieBanner.vue +112 -0
  85. package/app/components/X/Mark/Privacy/CookieToast.vue +43 -0
  86. package/app/components/X/Mark/Privacy/GDPR.vue +245 -0
  87. package/app/components/X/Mark/Section/Newsletter.vue +183 -0
  88. package/app/components/X/Mark/Section/Stitch.vue +156 -0
  89. package/app/components/X/Mark/Section/index.vue +151 -0
  90. package/app/components/X/Mark/SocialProof/Badge.vue +102 -0
  91. package/app/components/X/Mark/SocialProof/Testimonials.vue +326 -0
  92. package/app/components/X/Mark/SocialProof/Toast.vue +181 -0
  93. package/app/components/X/Mark/_archive/Pattern/Background.vue +83 -0
  94. package/app/components/X/Mark/_archive/Pattern/CheckBg.vue +35 -0
  95. package/app/components/X/Mark/_archive/Pattern/CircuitBg.vue +41 -0
  96. package/app/components/X/Mark/_archive/Pattern/DotsBg.vue +35 -0
  97. package/app/components/X/Mark/_archive/Pattern/GlowDivider.vue +86 -0
  98. package/app/components/X/Mark/_archive/Pattern/HexBg.vue +35 -0
  99. package/app/components/X/Mark/_archive/Pattern/PlaidBg.vue +47 -0
  100. package/app/components/X/Mark/_archive/Pattern/SectionStitch.vue +168 -0
  101. package/app/components/X/Mark/_archive/Pattern/WaveBg.vue +41 -0
  102. package/app/components/X/_archive/Newsletter/Form.vue +123 -0
  103. package/app/components/X/_archive/Newsletter/Section.vue +131 -0
  104. package/app/composables/useParallax.ts +124 -0
  105. package/app/composables/useScrollReveal.ts +92 -0
  106. package/app/pages/index.vue +210 -0
  107. package/app/plugins/marketing.client.ts +13 -0
  108. package/app/types/marketing.d.ts +268 -0
  109. package/componentList.json +511 -0
  110. package/nuxt.config.ts +14 -8
  111. package/package.json +24 -10
  112. package/.editorconfig +0 -12
  113. package/app/assets/css/main.css +0 -9
  114. package/app/components/X/Marketing/Sections/EmailSubscription/index.vue +0 -129
@@ -0,0 +1,117 @@
1
+ <template>
2
+ <div class="space-y-6">
3
+ <!-- Props Editor -->
4
+ <div class="border border-default rounded-lg overflow-hidden">
5
+ <div class="bg-slate-50 dark:bg-slate-900 px-4 py-3 border-b border-default">
6
+ <h3 class="text-sm font-semibold text-slate-700 dark:text-slate-300">
7
+ Customize Props
8
+ </h3>
9
+ </div>
10
+ <div class="p-4 space-y-4">
11
+ <div v-for="(value, key) in editableProps" :key="key" class="space-y-2">
12
+ <label class="text-sm font-medium text-slate-700 dark:text-slate-300">
13
+ {{ key }}
14
+ </label>
15
+ <div v-if="typeof value === 'boolean'" class="flex items-center gap-2">
16
+ <UToggle v-model="editableProps[key]" />
17
+ <span class="text-xs text-slate-500">{{ value ? 'true' : 'false' }}</span>
18
+ </div>
19
+ <UInput
20
+ v-else-if="typeof value === 'string'"
21
+ v-model="editableProps[key]"
22
+ :placeholder="`Enter ${key}`"
23
+ size="sm"
24
+ />
25
+ <UInput
26
+ v-else-if="typeof value === 'number'"
27
+ v-model.number="editableProps[key]"
28
+ type="number"
29
+ :placeholder="`Enter ${key}`"
30
+ size="sm"
31
+ />
32
+ <div v-else class="text-xs text-slate-500">
33
+ {{ typeof value }} (not editable)
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <!-- Live Preview -->
40
+ <div class="border border-default rounded-lg overflow-hidden">
41
+ <div class="bg-slate-50 dark:bg-slate-900 px-4 py-3 border-b border-default">
42
+ <h3 class="text-sm font-semibold text-slate-700 dark:text-slate-300">
43
+ Live Preview
44
+ </h3>
45
+ </div>
46
+ <div class="p-6 bg-white dark:bg-slate-950">
47
+ <slot :props="editableProps" />
48
+ </div>
49
+ </div>
50
+
51
+ <!-- Generated Code -->
52
+ <div class="border border-default rounded-lg overflow-hidden">
53
+ <div class="bg-slate-50 dark:bg-slate-900 px-4 py-3 border-b border-default flex items-center justify-between">
54
+ <h3 class="text-sm font-semibold text-slate-700 dark:text-slate-300">
55
+ Generated Code
56
+ </h3>
57
+ <UButton
58
+ icon="i-lucide-copy"
59
+ variant="ghost"
60
+ size="xs"
61
+ @click="copyGeneratedCode"
62
+ >
63
+ {{ codeCopied ? 'Copied!' : 'Copy' }}
64
+ </UButton>
65
+ </div>
66
+ <div class="overflow-x-auto bg-white dark:bg-slate-950">
67
+ <pre class="p-4 text-sm leading-relaxed text-slate-800 dark:text-slate-200 font-mono"><code>{{ generatedCode }}</code></pre>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </template>
72
+
73
+ <script setup>
74
+ const props = defineProps({
75
+ componentName: {
76
+ type: String,
77
+ required: true,
78
+ },
79
+ initialProps: {
80
+ type: Object,
81
+ default: () => ({}),
82
+ },
83
+ });
84
+
85
+ const editableProps = ref({ ...props.initialProps });
86
+ const codeCopied = ref(false);
87
+
88
+ const generatedCode = computed(() => {
89
+ const propsStr = Object.entries(editableProps.value)
90
+ .map(([key, value]) => {
91
+ if (typeof value === 'string') {
92
+ return ` ${key}="${value}"`;
93
+ } else if (typeof value === 'boolean') {
94
+ return value ? ` :${key}="true"` : ` :${key}="false"`;
95
+ } else if (typeof value === 'number') {
96
+ return ` :${key}="${value}"`;
97
+ }
98
+ return ` :${key}="${JSON.stringify(value)}"`;
99
+ })
100
+ .join('\n');
101
+
102
+ return `<${props.componentName}\n${propsStr}\n/>`;
103
+ });
104
+
105
+ const copyGeneratedCode = async () => {
106
+ try {
107
+ await navigator.clipboard.writeText(generatedCode.value);
108
+ codeCopied.value = true;
109
+ setTimeout(() => {
110
+ codeCopied.value = false;
111
+ }, 2000);
112
+ } catch (err) {
113
+ console.error('Failed to copy:', err);
114
+ }
115
+ };
116
+ </script>
117
+
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <header class="sticky top-0 z-40 border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-950">
3
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
4
+ <div class="flex justify-between items-center h-14">
5
+ <!-- Logo -->
6
+ <NuxtLink to="/" class="flex items-center gap-2 font-semibold text-base">
7
+ <UIcon name="i-lucide-layers" class="w-5 h-5 text-primary" />
8
+ <span>X Marketing</span>
9
+ <span class="text-xs text-gray-500 dark:text-gray-400 font-normal ml-1">/ Docs</span>
10
+ </NuxtLink>
11
+
12
+ <!-- Right Actions -->
13
+ <div class="flex items-center gap-3">
14
+ <UColorModeButton />
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </header>
19
+ </template>
@@ -1,5 +1,15 @@
1
1
  <template>
2
- <slot />
2
+ <UApp>
3
+ <NuxtLoadingIndicator />
4
+
5
+ <AppHeader />
6
+
7
+ <UMain>
8
+ <slot />
9
+ </UMain>
10
+
11
+ <AppFooter />
12
+ </UApp>
3
13
  </template>
4
- <script setup>
5
- </script>
14
+
15
+ <script setup></script>
@@ -0,0 +1,161 @@
1
+ <template>
2
+ <div class="min-h-screen bg-white dark:bg-gray-950">
3
+ <NuxtLoadingIndicator />
4
+
5
+ <DocsHeader />
6
+
7
+ <div class="flex h-[calc(100vh-3.5rem)]">
8
+ <!-- Collapsible Sidebar -->
9
+ <aside
10
+ class="hidden lg:flex lg:flex-col lg:border-r lg:border-gray-200 dark:lg:border-gray-800 transition-all duration-300"
11
+ :class="sidebarCollapsed ? 'lg:w-20' : 'lg:w-64'"
12
+ >
13
+ <!-- Toggle Button -->
14
+ <div
15
+ class="flex items-center justify-between px-4 py-4 border-b border-gray-200 dark:border-gray-800"
16
+ >
17
+ <span
18
+ v-if="!sidebarCollapsed"
19
+ class="text-sm font-semibold text-gray-900 dark:text-white"
20
+ >
21
+ Navigation
22
+ </span>
23
+ <button
24
+ @click="sidebarCollapsed = !sidebarCollapsed"
25
+ class="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-md transition-colors"
26
+ :title="sidebarCollapsed ? 'Expand' : 'Collapse'"
27
+ >
28
+ <UIcon
29
+ :name="
30
+ sidebarCollapsed
31
+ ? 'i-lucide-chevron-right'
32
+ : 'i-lucide-chevron-left'
33
+ "
34
+ class="w-5 h-5"
35
+ />
36
+ </button>
37
+ </div>
38
+
39
+ <!-- Navigation Menu -->
40
+ <nav class="flex-1 overflow-y-auto">
41
+ <UNavigationMenu
42
+ :items="navigationItems"
43
+ orientation="vertical"
44
+ :collapsed="sidebarCollapsed"
45
+ :tooltip="sidebarCollapsed"
46
+ :popover="sidebarCollapsed"
47
+ variant="link"
48
+ class="w-full"
49
+ />
50
+ </nav>
51
+
52
+ <!-- Sidebar Footer -->
53
+ <div class="border-t border-gray-200 dark:border-gray-800 px-4 py-4">
54
+ <NuxtLink
55
+ to="/"
56
+ class="flex items-center gap-2 px-2 py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
57
+ :title="sidebarCollapsed ? 'Back to Demo' : ''"
58
+ >
59
+ <UIcon name="i-lucide-arrow-left" class="w-4 h-4 shrink-0" />
60
+ <span v-if="!sidebarCollapsed">Back to Demo</span>
61
+ </NuxtLink>
62
+ </div>
63
+ </aside>
64
+
65
+ <!-- Main Content - Full Screen -->
66
+ <main class="flex-1 overflow-y-auto">
67
+ <div class="w-full h-full px-4 sm:px-6 lg:px-8 py-8">
68
+ <slot />
69
+ </div>
70
+ </main>
71
+ </div>
72
+ </div>
73
+ </template>
74
+
75
+ <script setup lang="ts">
76
+ import type { NavigationMenuItem } from "@nuxt/ui";
77
+
78
+ const route = useRoute();
79
+ const sidebarCollapsed = ref(false);
80
+
81
+ const navigationItems: NavigationMenuItem[][] = [
82
+ [
83
+ {
84
+ label: "Getting Started",
85
+ icon: "i-lucide-book-open",
86
+ defaultOpen: true,
87
+ children: [
88
+ { label: "Introduction", to: "/docs" },
89
+ { label: "Quick Start", to: "/docs/quick-start" },
90
+ { label: "Installation", to: "/docs/installation" },
91
+ ],
92
+ },
93
+ {
94
+ label: "Hero Sections",
95
+ icon: "i-lucide-image",
96
+ children: [
97
+ { label: "Hero Centered", to: "/docs/components/hero/centered" },
98
+ { label: "Hero Split", to: "/docs/components/hero/split" },
99
+ { label: "Hero Image", to: "/docs/components/hero/image" },
100
+ { label: "Hero Video", to: "/docs/components/hero/video" },
101
+ { label: "Hero Slider", to: "/docs/components/hero/slider" },
102
+ ],
103
+ },
104
+ {
105
+ label: "Features",
106
+ icon: "i-lucide-sparkles",
107
+ children: [
108
+ { label: "Feature Grid", to: "/docs/components/feature/grid" },
109
+ { label: "Feature Card", to: "/docs/components/feature/card" },
110
+ { label: "Feature Showcase", to: "/docs/components/feature/showcase" },
111
+ { label: "Feature Preview", to: "/docs/components/feature/preview" },
112
+ ],
113
+ },
114
+ {
115
+ label: "CTA & Conversion",
116
+ icon: "i-lucide-zap",
117
+ children: [
118
+ { label: "CTA Section", to: "/docs/components/cta/section" },
119
+ { label: "CTA Card", to: "/docs/components/cta/card" },
120
+ { label: "CTA Banner", to: "/docs/components/cta/banner" },
121
+ ],
122
+ },
123
+ {
124
+ label: "Content",
125
+ icon: "i-lucide-file-text",
126
+ children: [
127
+ { label: "Testimonials", to: "/docs/components/testimonial" },
128
+ { label: "Blog Grid", to: "/docs/components/blog/grid" },
129
+ { label: "Blog Card", to: "/docs/components/blog/card" },
130
+ { label: "FAQ", to: "/docs/components/faq" },
131
+ ],
132
+ },
133
+ {
134
+ label: "Stats & Metrics",
135
+ icon: "i-lucide-bar-chart-3",
136
+ children: [
137
+ { label: "Stats Section", to: "/docs/components/stats/section" },
138
+ { label: "Stats Grid", to: "/docs/components/stats/grid" },
139
+ ],
140
+ },
141
+ {
142
+ label: "Navigation & Layout",
143
+ icon: "i-lucide-layout",
144
+ children: [
145
+ { label: "Header App", to: "/docs/components/header/app" },
146
+ { label: "Header Nav", to: "/docs/components/header/nav" },
147
+ { label: "Footer", to: "/docs/components/footer" },
148
+ ],
149
+ },
150
+ {
151
+ label: "State",
152
+ icon: "i-lucide-inbox",
153
+ children: [
154
+ { label: "Empty State", to: "/docs/components/state/empty" },
155
+ { label: "Loading State", to: "/docs/components/state/loading" },
156
+ ],
157
+ },
158
+ ],
159
+ ];
160
+ </script>
161
+
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div>
3
+ <script setup>
4
+ definePageMeta({
5
+ layout: "docs-layout",
6
+ });
7
+ </script>
8
+ <slot />
9
+ </div>
10
+ </template>
11
+
@@ -0,0 +1,145 @@
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">Blog Author</h1>
5
+ <p class="mt-2 text-neutral-600 dark:text-neutral-400">Author bios in inline, card, and full variants.</p>
6
+ </div>
7
+
8
+ <div class="space-y-0">
9
+ <!-- Inline Variant -->
10
+ <XMarkSection bg="default">
11
+ <div class="text-center mb-8">
12
+ <span class="inline-block px-3 py-1 rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 text-xs font-medium mb-4">variant="inline"</span>
13
+ <h2 class="xText-headline">Inline Variant</h2>
14
+ <p class="mt-4 text-neutral-600 dark:text-neutral-400">Compact author info for post headers and bylines</p>
15
+ </div>
16
+ <div class="max-w-2xl mx-auto">
17
+ <XMarkBlogAuthor :author="author" variant="inline" />
18
+ </div>
19
+ </XMarkSection>
20
+
21
+ <!-- Card Variant -->
22
+ <XMarkSection bg="subtle">
23
+ <div class="text-center mb-8">
24
+ <span class="inline-block px-3 py-1 rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 text-xs font-medium mb-4">variant="card"</span>
25
+ <h2 class="xText-headline">Card Variant</h2>
26
+ <p class="mt-4 text-neutral-600 dark:text-neutral-400">Author card for sidebars or author grids</p>
27
+ </div>
28
+ <div class="max-w-sm mx-auto">
29
+ <XMarkBlogAuthor :author="author" variant="card" />
30
+ </div>
31
+ </XMarkSection>
32
+
33
+ <!-- Full Variant -->
34
+ <XMarkSection bg="default">
35
+ <div class="text-center mb-8">
36
+ <span class="inline-block px-3 py-1 rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 text-xs font-medium mb-4">variant="full"</span>
37
+ <h2 class="xText-headline">Full Variant</h2>
38
+ <p class="mt-4 text-neutral-600 dark:text-neutral-400">Complete author bio for post footers</p>
39
+ </div>
40
+ <div class="max-w-2xl mx-auto">
41
+ <XMarkBlogAuthor :author="author" variant="full" />
42
+ </div>
43
+ </XMarkSection>
44
+
45
+ <!-- Props -->
46
+ <XMarkSection bg="subtle">
47
+ <h2 class="text-lg font-semibold mb-6">Props</h2>
48
+ <div class="overflow-x-auto">
49
+ <table class="w-full text-sm">
50
+ <thead>
51
+ <tr class="border-b border-neutral-200 dark:border-neutral-700">
52
+ <th class="text-left py-3 px-4 font-medium">Prop</th>
53
+ <th class="text-left py-3 px-4 font-medium">Type</th>
54
+ <th class="text-left py-3 px-4 font-medium">Default</th>
55
+ <th class="text-left py-3 px-4 font-medium">Description</th>
56
+ </tr>
57
+ </thead>
58
+ <tbody class="divide-y divide-neutral-200 dark:divide-neutral-700">
59
+ <tr>
60
+ <td class="py-3 px-4 font-mono text-xs">author</td>
61
+ <td class="py-3 px-4">Object</td>
62
+ <td class="py-3 px-4">required</td>
63
+ <td class="py-3 px-4 text-neutral-600 dark:text-neutral-400">Author data object</td>
64
+ </tr>
65
+ <tr>
66
+ <td class="py-3 px-4 font-mono text-xs">variant</td>
67
+ <td class="py-3 px-4">String</td>
68
+ <td class="py-3 px-4">'inline'</td>
69
+ <td class="py-3 px-4 text-neutral-600 dark:text-neutral-400">inline, sm, full, card</td>
70
+ </tr>
71
+ </tbody>
72
+ </table>
73
+ </div>
74
+ </XMarkSection>
75
+
76
+ <!-- Author Object Structure -->
77
+ <XMarkSection bg="default">
78
+ <h2 class="text-lg font-semibold mb-4">Author Object Structure</h2>
79
+ <div class="bg-neutral-100 dark:bg-neutral-800 rounded-lg p-4 text-sm font-mono overflow-x-auto">
80
+ <pre>{
81
+ name: "Sarah Chen",
82
+ avatar: "https://...",
83
+ title: "Senior Developer",
84
+ bio: "Sarah specializes in Vue.js and Nuxt...",
85
+ social: {
86
+ twitter: "https://twitter.com/sarahchen",
87
+ linkedin: "https://linkedin.com/in/sarahchen",
88
+ github: "https://github.com/sarahchen"
89
+ }
90
+ }</pre>
91
+ </div>
92
+ </XMarkSection>
93
+
94
+ <!-- Code Example -->
95
+ <XMarkSection bg="subtle">
96
+ <h2 class="text-lg font-semibold mb-4">Code Example</h2>
97
+ <CodeExample title="Blog Author Usage" :code="codeExample" />
98
+ </XMarkSection>
99
+ </div>
100
+ </div>
101
+ </template>
102
+
103
+ <script setup>
104
+ // Initialize scroll reveal animations
105
+ useScrollReveal()
106
+
107
+ const codeExample = `<!-- Inline - for post headers -->
108
+ <XMarkBlogAuthor :author="author" variant="inline" />
109
+
110
+ <!-- Small - compact byline -->
111
+ <XMarkBlogAuthor :author="author" variant="sm" />
112
+
113
+ <!-- Card - for sidebars -->
114
+ <XMarkBlogAuthor :author="author" variant="card" />
115
+
116
+ <!-- Full - for post footers -->
117
+ <XMarkBlogAuthor :author="author" variant="full" />
118
+
119
+ <!-- Author data structure -->
120
+ <script setup>
121
+ const author = {
122
+ name: 'Sarah Chen',
123
+ avatar: 'https://...',
124
+ title: 'Senior Developer',
125
+ bio: 'Sarah specializes in Vue.js and Nuxt...',
126
+ social: {
127
+ twitter: 'https://twitter.com/sarahchen',
128
+ linkedin: 'https://linkedin.com/in/sarahchen',
129
+ github: 'https://github.com/sarahchen'
130
+ }
131
+ }
132
+ <\/script>`
133
+
134
+ const author = {
135
+ name: 'Sarah Chen',
136
+ avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop',
137
+ title: 'Senior Developer',
138
+ bio: 'Sarah is a frontend developer with 8+ years of experience. She specializes in Vue.js and Nuxt, and loves creating beautiful, performant web applications. When not coding, she enjoys hiking and photography.',
139
+ social: {
140
+ twitter: 'https://twitter.com/sarahchen',
141
+ linkedin: 'https://linkedin.com/in/sarahchen',
142
+ github: 'https://github.com/sarahchen'
143
+ }
144
+ }
145
+ </script>
@@ -0,0 +1,149 @@
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">Blog Card</h1>
5
+ <p class="mt-2 text-neutral-600 dark:text-neutral-400">Blog post cards with image, metadata, and excerpts.</p>
6
+ </div>
7
+
8
+ <div class="p-8">
9
+ <!-- Default Cards -->
10
+ <section>
11
+ <h2 class="text-lg font-semibold mb-4">Default Cards</h2>
12
+ <div class="grid md:grid-cols-3 gap-8 max-w-6xl">
13
+ <XMarkBlogCard
14
+ v-for="post in posts"
15
+ :key="post.slug"
16
+ :post="post"
17
+ />
18
+ </div>
19
+ </section>
20
+
21
+ <!-- With Button -->
22
+ <section class="mt-12">
23
+ <h2 class="text-lg font-semibold mb-4">With Button</h2>
24
+ <p class="text-sm text-neutral-500 mb-4">Add a full-width button below the card content</p>
25
+ <div class="grid md:grid-cols-3 gap-8 max-w-6xl">
26
+ <XMarkBlogCard
27
+ v-for="post in posts"
28
+ :key="`btn-${post.slug}`"
29
+ :post="post"
30
+ :button="{ label: 'Read More', icon: 'i-lucide-arrow-right' }"
31
+ />
32
+ </div>
33
+ </section>
34
+
35
+ <div class="mt-12">
36
+ <h2 class="text-lg font-semibold mb-4">Post Object Shape</h2>
37
+ <div class="bg-neutral-100 dark:bg-neutral-800 rounded-lg p-4 text-sm font-mono overflow-x-auto">
38
+ <pre>{
39
+ title: "Post Title",
40
+ description: "Brief description...",
41
+ img: { src: "https://...", alt: "Image description" },
42
+ slug: "post-slug",
43
+ date: "2024-01-15",
44
+ readingTime: 5,
45
+ author: { name: "Author", avatar: "https://..." },
46
+ category: "Tutorial"
47
+ }</pre>
48
+ </div>
49
+ </div>
50
+
51
+ <div class="mt-8">
52
+ <h2 class="text-lg font-semibold mb-4">Component Props</h2>
53
+ <table class="w-full text-sm">
54
+ <thead>
55
+ <tr class="border-b border-neutral-200 dark:border-neutral-700">
56
+ <th class="text-left py-3 px-4">Prop</th>
57
+ <th class="text-left py-3 px-4">Type</th>
58
+ <th class="text-left py-3 px-4">Default</th>
59
+ <th class="text-left py-3 px-4">Description</th>
60
+ </tr>
61
+ </thead>
62
+ <tbody class="divide-y divide-neutral-200 dark:divide-neutral-700">
63
+ <tr><td class="py-3 px-4 font-mono text-xs">post</td><td class="py-3 px-4">Object</td><td class="py-3 px-4">required</td><td class="py-3 px-4">Blog post object (see shape above)</td></tr>
64
+ <tr><td class="py-3 px-4 font-mono text-xs">hasCategory</td><td class="py-3 px-4">Boolean</td><td class="py-3 px-4">true</td><td class="py-3 px-4">Show category badge</td></tr>
65
+ <tr><td class="py-3 px-4 font-mono text-xs">hasAuthor</td><td class="py-3 px-4">Boolean</td><td class="py-3 px-4">true</td><td class="py-3 px-4">Show author info</td></tr>
66
+ <tr><td class="py-3 px-4 font-mono text-xs">hasExcerpt</td><td class="py-3 px-4">Boolean</td><td class="py-3 px-4">true</td><td class="py-3 px-4">Show description</td></tr>
67
+ <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">null</td><td class="py-3 px-4">{ label, color?, variant?, icon? }</td></tr>
68
+ </tbody>
69
+ </table>
70
+ </div>
71
+
72
+ <!-- Code Example -->
73
+ <section class="mt-12">
74
+ <h2 class="text-lg font-semibold mb-4">Code Example</h2>
75
+ <CodeExample title="Blog Card Usage" :code="codeExample" />
76
+ </section>
77
+ </div>
78
+ </div>
79
+ </template>
80
+
81
+ <script setup>
82
+ // Initialize scroll reveal animations
83
+ useScrollReveal()
84
+
85
+ const codeExample = `<!-- Single blog card -->
86
+ <XMarkBlogCard
87
+ :post="{
88
+ title: 'Getting Started with Nuxt',
89
+ description: 'Learn the basics of building modern web apps.',
90
+ img: { src: 'https://images.unsplash.com/...', alt: 'Code on screen' },
91
+ slug: 'getting-started',
92
+ date: '2024-01-15',
93
+ readingTime: 5,
94
+ author: { name: 'Sarah Chen', avatar: 'https://...' },
95
+ category: 'Tutorial'
96
+ }"
97
+ />
98
+
99
+ <!-- With button -->
100
+ <XMarkBlogCard
101
+ :post="post"
102
+ :button="{ label: 'Read More', icon: 'i-lucide-arrow-right' }"
103
+ />
104
+
105
+ <!-- Without author -->
106
+ <XMarkBlogCard :post="post" :has-author="false" />
107
+
108
+ <!-- Grid of blog cards -->
109
+ <div class="grid md:grid-cols-3 gap-8">
110
+ <XMarkBlogCard
111
+ v-for="post in posts"
112
+ :key="post.slug"
113
+ :post="post"
114
+ />
115
+ </div>`
116
+
117
+ const posts = [
118
+ {
119
+ title: 'Getting Started with Nuxt',
120
+ description: 'Learn the basics of building modern web applications with Nuxt 3.',
121
+ img: { src: 'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=400&h=300&fit=crop', alt: 'Code on laptop' },
122
+ slug: 'getting-started',
123
+ date: '2024-01-15',
124
+ readingTime: 5,
125
+ author: { name: 'Sarah Chen', avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=50&h=50&fit=crop' },
126
+ category: 'Tutorial'
127
+ },
128
+ {
129
+ title: 'Vue 3 Composition API',
130
+ description: 'Mastering the composition API for cleaner, more reusable code.',
131
+ img: { src: 'https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=400&h=300&fit=crop', alt: 'Programming code' },
132
+ slug: 'composition-api',
133
+ date: '2024-01-10',
134
+ readingTime: 8,
135
+ author: { name: 'Michael Torres', avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=50&h=50&fit=crop' },
136
+ category: 'Development'
137
+ },
138
+ {
139
+ title: 'Building Design Systems',
140
+ description: 'Create consistent, scalable design systems for your projects.',
141
+ img: { src: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=400&h=300&fit=crop', alt: 'Design dashboard' },
142
+ slug: 'design-systems',
143
+ date: '2024-01-05',
144
+ readingTime: 6,
145
+ author: { name: 'Emma Williams', avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=50&h=50&fit=crop' },
146
+ category: 'Design'
147
+ }
148
+ ]
149
+ </script>