create-nuxt-base 0.3.15 → 0.3.17

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 (41) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/nuxt-base-template/.env.example +2 -1
  3. package/nuxt-base-template/CLAUDE.md +361 -0
  4. package/nuxt-base-template/README.md +127 -13
  5. package/nuxt-base-template/app/app.config.ts +67 -0
  6. package/nuxt-base-template/app/app.vue +10 -2
  7. package/nuxt-base-template/app/assets/css/tailwind.css +124 -84
  8. package/nuxt-base-template/app/components/Modal/ModalBase.vue +65 -0
  9. package/nuxt-base-template/app/components/Transition/TransitionSlide.vue +0 -2
  10. package/nuxt-base-template/app/components/Transition/TransitionSlideBottom.vue +0 -2
  11. package/nuxt-base-template/app/components/Transition/TransitionSlideRevert.vue +0 -2
  12. package/nuxt-base-template/app/composables/use-file.ts +19 -3
  13. package/nuxt-base-template/app/composables/use-share.ts +26 -10
  14. package/nuxt-base-template/app/error.vue +7 -43
  15. package/nuxt-base-template/app/layouts/default.vue +76 -4
  16. package/nuxt-base-template/app/layouts/slim.vue +5 -0
  17. package/nuxt-base-template/app/pages/auth/forgot-password.vue +64 -0
  18. package/nuxt-base-template/app/pages/auth/login.vue +71 -0
  19. package/nuxt-base-template/app/pages/auth/reset-password/[token].vue +110 -0
  20. package/nuxt-base-template/app/pages/index.vue +139 -2
  21. package/nuxt-base-template/app/public/favicon.ico +0 -0
  22. package/nuxt-base-template/docs/nuxt.config.ts +4 -0
  23. package/nuxt-base-template/docs/pages/docs.vue +663 -0
  24. package/nuxt-base-template/eslint.config.mjs +2 -1
  25. package/nuxt-base-template/nuxt.config.ts +73 -31
  26. package/nuxt-base-template/openapi-ts.config.ts +18 -0
  27. package/nuxt-base-template/package-lock.json +9781 -15157
  28. package/nuxt-base-template/package.json +30 -35
  29. package/nuxt-base-template/tsconfig.json +1 -1
  30. package/package.json +3 -3
  31. package/nuxt-base-template/app/composables/use-context-menu.ts +0 -19
  32. package/nuxt-base-template/app/composables/use-form-helper.ts +0 -41
  33. package/nuxt-base-template/app/composables/use-modal.ts +0 -84
  34. package/nuxt-base-template/app/composables/use-notification.ts +0 -29
  35. package/nuxt-base-template/app/middleware/admin.global.ts +0 -9
  36. package/nuxt-base-template/app/middleware/auth.global.ts +0 -9
  37. package/nuxt-base-template/app/middleware/logged-in.global.ts +0 -9
  38. package/nuxt-base-template/app/plugins/auth.server.ts +0 -72
  39. package/nuxt-base-template/app/plugins/form.plugin.ts +0 -21
  40. package/nuxt-base-template/app/plugins/pwa.plugin.ts +0 -114
  41. package/nuxt-base-template/tailwind.config.js +0 -21
@@ -0,0 +1,663 @@
1
+ <script lang="ts" setup>
2
+ import type { RadioGroupItem } from '#ui/components/RadioGroup.vue';
3
+ import type { SelectItem } from '#ui/components/Select.vue';
4
+ import type { SelectMenuItem } from '#ui/components/SelectMenu.vue';
5
+ // ============================================================================
6
+ // Imports
7
+ // ============================================================================
8
+ import type { InferOutput } from 'valibot';
9
+
10
+ import { ModalBase } from '#components';
11
+ import * as v from 'valibot';
12
+
13
+ // ============================================================================
14
+ // Composables
15
+ // ============================================================================
16
+ const toast = useToast();
17
+ const colorMode = useColorMode();
18
+ const overlay = useOverlay();
19
+
20
+ // ============================================================================
21
+ // Page Meta
22
+ // ============================================================================
23
+ definePageMeta({
24
+ middleware: () => {
25
+ const config = useRuntimeConfig();
26
+ if (config.public.appEnv === 'production') {
27
+ return navigateTo('/');
28
+ }
29
+ },
30
+ });
31
+
32
+ // ============================================================================
33
+ // Variables
34
+ // ============================================================================
35
+ // Button variants for showcase
36
+ const buttonVariants: Array<'ghost' | 'link' | 'outline' | 'soft' | 'solid'> = ['solid', 'outline', 'soft', 'ghost', 'link'];
37
+ const buttonColors: Array<'error' | 'info' | 'neutral' | 'primary' | 'secondary' | 'success' | 'warning'> = [
38
+ 'primary',
39
+ 'secondary',
40
+ 'success',
41
+ 'error',
42
+ 'warning',
43
+ 'info',
44
+ 'neutral',
45
+ ];
46
+
47
+ // Form Schema and State
48
+ // Valibot validation schema - demonstrates various validation patterns
49
+ const formSchema = v.object({
50
+ // Boolean with custom validation - checkbox must be checked (true)
51
+ acceptTerms: v.pipe(
52
+ v.boolean(),
53
+ v.custom((value) => value === true, 'You must accept the terms and conditions'),
54
+ ),
55
+ // Number with range and type validation
56
+ age: v.pipe(
57
+ v.number('Age must be a number'),
58
+ v.minValue(18, 'You must be at least 18 years old'),
59
+ v.maxValue(120, 'Please enter a valid age'),
60
+ v.integer('Age must be a whole number'),
61
+ ),
62
+ // Optional field with max length
63
+ bio: v.optional(v.pipe(v.string(), v.maxLength(500, 'Bio must not exceed 500 characters'))),
64
+ // Required string (select value)
65
+ country: v.pipe(v.string(), v.minLength(1, 'Please select a country')),
66
+ // Email validation
67
+ email: v.pipe(v.string(), v.email('Please enter a valid email address')),
68
+ // Optional file upload with custom validation (type and size)
69
+ image: v.optional(
70
+ v.custom<File>(
71
+ (value) => value instanceof File && ['image/gif', 'image/jpeg', 'image/png'].includes(value.type) && value.size <= 2 * 1024 * 1024,
72
+ 'Please upload an image file (JPG, PNG, GIF) with max. 2MB',
73
+ ),
74
+ ),
75
+ // Array validation - at least one item required
76
+ interests: v.pipe(v.array(v.string()), v.minLength(1, 'Please select at least one interest')),
77
+ // String with min and max length
78
+ name: v.pipe(v.string(), v.minLength(2, 'Name must be at least 2 characters'), v.maxLength(50, 'Name must not exceed 50 characters')),
79
+ // Simple boolean without custom validation
80
+ newsletter: v.boolean(),
81
+ // Password with minimum length
82
+ password: v.pipe(v.string(), v.minLength(8, 'Password must be at least 8 characters')),
83
+ // Required radio group selection
84
+ preferredContact: v.pipe(v.string(), v.minLength(1, 'Please select a preferred contact method')),
85
+ // Number (slider) with minimum value
86
+ salary: v.pipe(v.number(), v.minValue(0, 'Salary must be positive'), v.integer()),
87
+ });
88
+
89
+ type FormSchema = InferOutput<typeof formSchema>;
90
+
91
+ const formState = reactive<FormSchema>({
92
+ acceptTerms: false,
93
+ age: 25,
94
+ bio: '',
95
+ country: 'de',
96
+ email: '',
97
+ image: undefined,
98
+ interests: [],
99
+ name: '',
100
+ newsletter: false,
101
+ password: '',
102
+ preferredContact: '',
103
+ salary: 50000,
104
+ });
105
+
106
+ const countryOptions = ref<SelectItem[]>([
107
+ {
108
+ label: 'Germany',
109
+ value: 'de',
110
+ },
111
+ {
112
+ label: 'United Kingdom',
113
+ value: 'en',
114
+ },
115
+ {
116
+ label: 'Spain',
117
+ value: 'es',
118
+ },
119
+ {
120
+ label: 'Italy',
121
+ value: 'it',
122
+ },
123
+ ]);
124
+
125
+ const interestOptions = ref<SelectMenuItem[]>([
126
+ {
127
+ label: 'Frontend Development',
128
+ value: 'frontend',
129
+ },
130
+ {
131
+ label: 'Backend Development',
132
+ value: 'backend',
133
+ },
134
+ {
135
+ label: 'DevOps',
136
+ value: 'devops',
137
+ },
138
+ {
139
+ label: 'UI/UX Design',
140
+ value: 'design',
141
+ },
142
+ {
143
+ label: 'Mobile Development',
144
+ value: 'mobile',
145
+ },
146
+ ]);
147
+
148
+ const contactMethodOptions = ref<RadioGroupItem[]>([
149
+ {
150
+ description: 'Email as option.',
151
+ label: 'Email',
152
+ value: 'email',
153
+ },
154
+ {
155
+ description: 'Phone as option.',
156
+ label: 'Phone',
157
+ value: 'phone',
158
+ },
159
+ {
160
+ description: 'SMS as option.',
161
+ label: 'SMS',
162
+ value: 'sms',
163
+ },
164
+ {
165
+ description: 'Pigeon as option.',
166
+ label: 'Pigeon',
167
+ value: 'pigeon',
168
+ },
169
+ ]);
170
+
171
+ // ============================================================================
172
+ // Functions
173
+ // ============================================================================
174
+ async function handleFormSubmit(): Promise<void> {
175
+ toast.add({
176
+ color: 'success',
177
+ description: 'All form fields are valid! Check the browser console for the submitted data.',
178
+ title: 'Form Submitted',
179
+ });
180
+
181
+ console.info('Form Data:', formState);
182
+ }
183
+
184
+ async function handleShare(): Promise<void> {
185
+ const { share } = useShare();
186
+ await share('Nuxt Base Starter', 'Check out this Nuxt Base Starter Template!', window.location.href);
187
+
188
+ toast.add({
189
+ color: 'success',
190
+ description: 'Content shared successfully or copied to clipboard!',
191
+ title: 'Shared',
192
+ });
193
+ }
194
+
195
+ async function openModal(): Promise<void> {
196
+ const modal = overlay.create(ModalBase);
197
+ const instance = modal.open({
198
+ description: 'This demonstrates the useOverlay composable for programmatic modal control.',
199
+ title: 'Programmatic Modal',
200
+ });
201
+
202
+ const result = await instance.result;
203
+
204
+ if (result) {
205
+ toast.add({
206
+ color: 'success',
207
+ description: 'You confirmed the modal action.',
208
+ title: 'Confirmed',
209
+ });
210
+ } else {
211
+ toast.add({
212
+ color: 'neutral',
213
+ description: 'Modal was dismissed.',
214
+ title: 'Dismissed',
215
+ });
216
+ }
217
+ }
218
+
219
+ function showToast(type: 'error' | 'info' | 'success' | 'warning'): void {
220
+ const messages: Record<string, { description: string; title: string }> = {
221
+ error: {
222
+ description: 'Something went wrong.',
223
+ title: 'Error',
224
+ },
225
+ info: {
226
+ description: 'Here is some information.',
227
+ title: 'Info',
228
+ },
229
+ success: {
230
+ description: 'Your action was successful!',
231
+ title: 'Success',
232
+ },
233
+ warning: {
234
+ description: 'Please be careful.',
235
+ title: 'Warning',
236
+ },
237
+ };
238
+
239
+ toast.add({
240
+ color: type,
241
+ description: messages[type].description,
242
+ title: messages[type].title,
243
+ });
244
+ }
245
+
246
+ function toggleColorMode(): void {
247
+ colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark';
248
+ }
249
+ </script>
250
+
251
+ <template>
252
+ <div>
253
+ <div class="mx-auto max-w-7xl px-6 py-16 lg:px-8">
254
+ <!-- Header -->
255
+ <div class="mb-12">
256
+ <div class="flex items-center justify-between mb-4">
257
+ <div>
258
+ <UBadge color="warning" variant="subtle" size="lg" class="mb-4"> Development Only </UBadge>
259
+ <h1 class="text-4xl font-bold tracking-tight text-neutral-900 dark:text-white sm:text-5xl">Interactive Examples</h1>
260
+ <p class="mt-4 text-lg text-neutral-600 dark:text-neutral-400">
261
+ This page is only available in development mode and showcases some interactive examples of the template.
262
+ </p>
263
+ </div>
264
+ <UButton to="/" icon="i-lucide-arrow-left" variant="outline" color="neutral" size="lg"> Back to Home </UButton>
265
+ </div>
266
+ </div>
267
+
268
+ <!-- Interactive Examples -->
269
+ <div class="space-y-8">
270
+ <UAlert
271
+ title="Note"
272
+ description="These examples demonstrate the most important UI components and composables of the template. Perfect for testing and as a reference for new projects."
273
+ icon="i-lucide-lightbulb"
274
+ color="primary"
275
+ variant="subtle"
276
+ />
277
+
278
+ <!-- Button Showcase -->
279
+ <UCard variant="outline">
280
+ <template #header>
281
+ <div class="flex items-center justify-between">
282
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white">Buttons</h3>
283
+ <UButton to="https://ui.nuxt.com/components/button" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs"> Docs </UButton>
284
+ </div>
285
+ </template>
286
+
287
+ <div class="space-y-6">
288
+ <p class="text-sm text-neutral-600 dark:text-neutral-400">Interactive buttons with multiple variants, sizes, and states. Essential for all user interactions.</p>
289
+
290
+ <!-- Variants -->
291
+ <div>
292
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white mb-3">Variants</h4>
293
+ <div class="flex flex-wrap gap-2">
294
+ <UButton v-for="variant in buttonVariants" :key="variant" :variant="variant" color="primary"> {{ variant }} </UButton>
295
+ </div>
296
+ </div>
297
+
298
+ <USeparator />
299
+
300
+ <!-- Colors -->
301
+ <div>
302
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white mb-3">Colors (Solid Variant)</h4>
303
+ <div class="flex flex-wrap gap-2">
304
+ <UButton v-for="color in buttonColors" :key="color" :color="color"> {{ color }} </UButton>
305
+ </div>
306
+ </div>
307
+
308
+ <USeparator />
309
+
310
+ <!-- Sizes & Icons -->
311
+ <div>
312
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white mb-3">Sizes & Icons</h4>
313
+ <div class="flex flex-wrap items-center gap-2">
314
+ <UButton size="xs" icon="i-lucide-star"> Extra Small </UButton>
315
+ <UButton size="sm" icon="i-lucide-star"> Small </UButton>
316
+ <UButton size="md" icon="i-lucide-star"> Medium </UButton>
317
+ <UButton size="lg" icon="i-lucide-star"> Large </UButton>
318
+ <UButton size="xl" icon="i-lucide-star"> Extra Large </UButton>
319
+ </div>
320
+ </div>
321
+
322
+ <USeparator />
323
+
324
+ <!-- States -->
325
+ <div>
326
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white mb-3">States</h4>
327
+ <div class="flex flex-wrap gap-2">
328
+ <UButton color="primary"> Normal </UButton>
329
+ <UButton color="primary" loading> Loading </UButton>
330
+ <UButton color="primary" disabled> Disabled </UButton>
331
+ <UButton color="primary" icon="i-lucide-download" trailing-icon="i-lucide-arrow-right"> With Icons </UButton>
332
+ </div>
333
+ </div>
334
+ </div>
335
+ </UCard>
336
+
337
+ <!-- Interactive Components -->
338
+ <UCard variant="outline">
339
+ <template #header>
340
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white">Interactive Components</h3>
341
+ </template>
342
+
343
+ <div class="space-y-6">
344
+ <!-- Toast Notifications -->
345
+ <div>
346
+ <div class="flex items-center justify-between mb-3">
347
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white">Toast Notifications</h4>
348
+ <UButton to="https://ui.nuxt.com/composables/use-toast" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
349
+ Docs
350
+ </UButton>
351
+ </div>
352
+ <p class="text-sm text-neutral-600 dark:text-neutral-400 mb-3">
353
+ Use <code class="px-1.5 py-0.5 bg-neutral-100 dark:bg-neutral-800 rounded text-xs">useToast()</code> for notifications.
354
+ </p>
355
+ <div class="flex flex-wrap gap-2 mb-3">
356
+ <UButton color="success" size="sm" @click="showToast('success')"> Success </UButton>
357
+ <UButton color="error" size="sm" @click="showToast('error')"> Error </UButton>
358
+ <UButton color="info" size="sm" @click="showToast('info')"> Info </UButton>
359
+ <UButton color="warning" size="sm" @click="showToast('warning')"> Warning </UButton>
360
+ </div>
361
+ </div>
362
+
363
+ <USeparator />
364
+
365
+ <!-- Color Mode Toggle -->
366
+ <div>
367
+ <div class="flex items-center justify-between mb-3">
368
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white">Color Mode</h4>
369
+ <UButton to="https://ui.nuxt.com/getting-started/color-mode" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
370
+ Docs
371
+ </UButton>
372
+ </div>
373
+ <p class="text-sm text-neutral-600 dark:text-neutral-400 mb-3">
374
+ Use <code class="px-1.5 py-0.5 bg-neutral-100 dark:bg-neutral-800 rounded text-xs">useColorMode()</code> for Dark/Light Mode.
375
+ </p>
376
+ <div class="flex items-center gap-4 mb-3">
377
+ <UButton :icon="colorMode.value === 'dark' ? 'i-lucide-sun' : 'i-lucide-moon'" color="neutral" variant="outline" size="sm" @click="toggleColorMode">
378
+ Toggle {{ colorMode.value === 'dark' ? 'Light' : 'Dark' }} Mode
379
+ </UButton>
380
+ <UBadge :color="colorMode.value === 'dark' ? 'primary' : 'warning'" size="md"> Current: {{ colorMode.value }} </UBadge>
381
+ </div>
382
+ </div>
383
+
384
+ <USeparator />
385
+
386
+ <!-- Badges -->
387
+ <div>
388
+ <div class="flex items-center justify-between mb-3">
389
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white">Badges & Variants</h4>
390
+ <UButton to="https://ui.nuxt.com/components/badge" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs"> Docs </UButton>
391
+ </div>
392
+ <p class="text-sm text-neutral-600 dark:text-neutral-400 mb-3">Various badge variants and colors for different purposes.</p>
393
+ <div class="flex flex-wrap gap-2 mb-3">
394
+ <UBadge color="primary" variant="solid"> Primary </UBadge>
395
+ <UBadge color="secondary" variant="solid"> Secondary </UBadge>
396
+ <UBadge color="success" variant="outline"> Success </UBadge>
397
+ <UBadge color="error" variant="soft"> Error </UBadge>
398
+ <UBadge color="info" variant="subtle" icon="i-lucide-info"> Info </UBadge>
399
+ </div>
400
+ </div>
401
+
402
+ <USeparator />
403
+
404
+ <!-- Modal -->
405
+ <div>
406
+ <div class="flex items-center justify-between mb-3">
407
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white">Programmatic Modal</h4>
408
+ <UButton
409
+ to="https://ui.nuxt.com/docs/components/modal#programmatic-usage"
410
+ target="_blank"
411
+ trailing-icon="i-lucide-external-link"
412
+ variant="ghost"
413
+ color="neutral"
414
+ size="xs"
415
+ >
416
+ Docs
417
+ </UButton>
418
+ </div>
419
+ <p class="text-sm text-neutral-600 dark:text-neutral-400 mb-3">
420
+ Use the <code class="px-1.5 py-0.5 bg-neutral-100 dark:bg-neutral-800 rounded text-xs">useOverlay()</code> composable to open modals programmatically and await the
421
+ result.
422
+ </p>
423
+ <UButton icon="i-lucide-square-dashed-mouse-pointer" color="primary" size="sm" variant="outline" class="mb-3" @click="openModal"> Open Modal </UButton>
424
+ </div>
425
+ </div>
426
+ </UCard>
427
+
428
+ <!-- Form Example with Valibot -->
429
+ <UCard variant="outline">
430
+ <template #header>
431
+ <div class="flex items-center justify-between">
432
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white">Form Validation with Valibot</h3>
433
+ <UButton to="https://ui.nuxt.com/components/form" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs"> Docs </UButton>
434
+ </div>
435
+ </template>
436
+
437
+ <div class="space-y-4">
438
+ <p class="text-sm text-neutral-600 dark:text-neutral-400 mb-4">
439
+ This form demonstrates all important Nuxt UI input components with Valibot validation. Fill in all required fields and observe the real-time validation.
440
+ </p>
441
+
442
+ <UForm :state="formState" :schema="formSchema" class="space-y-6" @submit="handleFormSubmit">
443
+ <!-- Basic Text Inputs -->
444
+ <div class="space-y-4">
445
+ <h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
446
+ Text Inputs
447
+ <UButton to="https://ui.nuxt.com/components/input" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
448
+ Docs
449
+ </UButton>
450
+ </h4>
451
+ <div class="grid md:grid-cols-2 gap-4">
452
+ <UFormField label="Full Name" name="name" required>
453
+ <UInput v-model="formState.name" placeholder="Enter your full name" icon="i-lucide-user" />
454
+ </UFormField>
455
+
456
+ <UFormField label="Email Address" name="email" required>
457
+ <UInput v-model="formState.email" type="email" placeholder="your.email@example.com" icon="i-lucide-mail" />
458
+ </UFormField>
459
+
460
+ <UFormField label="Password" name="password" required help="At least 8 characters">
461
+ <UInput v-model="formState.password" type="password" placeholder="Enter a secure password" icon="i-lucide-lock" />
462
+ </UFormField>
463
+
464
+ <UFormField label="Age" name="age" required help="You must be at least 18 years old">
465
+ <UInput v-model.number="formState.age" type="number" placeholder="Enter your age" icon="i-lucide-calendar" />
466
+ </UFormField>
467
+ </div>
468
+ </div>
469
+
470
+ <USeparator />
471
+
472
+ <!-- Textarea -->
473
+ <div class="space-y-4">
474
+ <h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
475
+ Textarea
476
+ <UButton to="https://ui.nuxt.com/components/textarea" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
477
+ Docs
478
+ </UButton>
479
+ </h4>
480
+ <UFormField label="Bio" name="bio" help="Optional - maximum 500 characters">
481
+ <UTextarea v-model="formState.bio" placeholder="Tell us about yourself..." :rows="4" />
482
+ </UFormField>
483
+ </div>
484
+
485
+ <USeparator />
486
+
487
+ <!-- Selection Components -->
488
+ <div class="space-y-4">
489
+ <h4 class="text-sm font-semibold text-neutral-900 dark:text-white">Selection Components</h4>
490
+ <div class="grid md:grid-cols-2 gap-4">
491
+ <UFormField label="Country" name="country" required>
492
+ <template #help>
493
+ <span class="flex items-center gap-1">
494
+ Select
495
+ <UButton to="https://ui.nuxt.com/components/select" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
496
+ Docs
497
+ </UButton>
498
+ </span>
499
+ </template>
500
+ <USelect v-model="formState.country" :items="countryOptions" placeholder="Select your country" />
501
+ </UFormField>
502
+
503
+ <UFormField label="Areas of Interest" name="interests" required>
504
+ <template #help>
505
+ <span class="flex items-center gap-1">
506
+ Select Menu
507
+ <UButton to="https://ui.nuxt.com/components/select-menu" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
508
+ Docs
509
+ </UButton>
510
+ </span>
511
+ </template>
512
+ <USelectMenu v-model="formState.interests" :items="interestOptions" value-key="value" multiple placeholder="Select your interests" />
513
+ </UFormField>
514
+ </div>
515
+ </div>
516
+
517
+ <USeparator />
518
+
519
+ <!-- Slider & Toggles -->
520
+ <div class="space-y-4">
521
+ <h4 class="text-sm font-semibold text-neutral-900 dark:text-white">Slider & Toggles</h4>
522
+ <div class="grid md:grid-cols-2 gap-4">
523
+ <UFormField label="Expected Salary (USD)" name="salary" :help="`$${formState.salary.toLocaleString()} per year`">
524
+ <template #label>
525
+ <span class="flex items-center gap-1">
526
+ Expected Salary (USD)
527
+ <UButton to="https://ui.nuxt.com/components/slider" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
528
+ Docs
529
+ </UButton>
530
+ </span>
531
+ </template>
532
+ <USlider v-model="formState.salary" :min="0" :max="200000" :step="1000" />
533
+ </UFormField>
534
+
535
+ <UFormField label="Newsletter Subscription" name="newsletter" help="Receive updates about new features">
536
+ <template #label>
537
+ <span class="flex items-center gap-1">
538
+ Newsletter Subscription
539
+ <UButton to="https://ui.nuxt.com/components/switch" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
540
+ Docs
541
+ </UButton>
542
+ </span>
543
+ </template>
544
+ <USwitch v-model="formState.newsletter" />
545
+ </UFormField>
546
+ </div>
547
+ </div>
548
+
549
+ <USeparator />
550
+
551
+ <!-- Radio Group -->
552
+ <div class="space-y-4">
553
+ <h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
554
+ Radio Group
555
+ <UButton to="https://ui.nuxt.com/components/radio-group" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
556
+ Docs
557
+ </UButton>
558
+ </h4>
559
+ <UFormField label="Preferred Contact Method" name="preferredContact" required>
560
+ <URadioGroup v-model="formState.preferredContact" :items="contactMethodOptions" />
561
+ </UFormField>
562
+ </div>
563
+
564
+ <USeparator />
565
+
566
+ <!-- File Upload -->
567
+ <div class="space-y-4">
568
+ <h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
569
+ File Upload
570
+ <UButton to="https://ui.nuxt.com/components/file-upload" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
571
+ Docs
572
+ </UButton>
573
+ </h4>
574
+ <UFormField name="image" label="Image" description="JPG, GIF or PNG. 2MB Max.">
575
+ <UFileUpload v-model="formState.image" accept="image/*" class="min-h-48" />
576
+ </UFormField>
577
+ </div>
578
+
579
+ <USeparator />
580
+
581
+ <!-- Checkbox -->
582
+ <div class="space-y-4">
583
+ <h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
584
+ Checkbox
585
+ <UButton to="https://ui.nuxt.com/components/checkbox" target="_blank" trailing-icon="i-lucide-external-link" variant="ghost" color="neutral" size="xs">
586
+ Docs
587
+ </UButton>
588
+ </h4>
589
+ <UFormField name="acceptTerms" required>
590
+ <UCheckbox v-model="formState.acceptTerms" label="I accept the terms and conditions" />
591
+ </UFormField>
592
+ </div>
593
+
594
+ <USeparator />
595
+
596
+ <!-- Submit Button -->
597
+ <div class="flex items-center gap-3 pt-4">
598
+ <UButton type="submit" color="primary" size="lg" icon="i-lucide-send"> Submit Form </UButton>
599
+ <p class="text-xs text-neutral-500">All data will be logged to the console</p>
600
+ </div>
601
+ </UForm>
602
+ </div>
603
+ </UCard>
604
+
605
+ <!-- Custom Composables -->
606
+ <UCard variant="outline">
607
+ <template #header>
608
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white">Template Composables</h3>
609
+ </template>
610
+
611
+ <div class="space-y-6">
612
+ <p class="text-sm text-neutral-600 dark:text-neutral-400">This template includes custom composables for common tasks. These are auto-imported and ready to use.</p>
613
+
614
+ <!-- useShare -->
615
+ <div>
616
+ <div class="flex items-center justify-between mb-3">
617
+ <h4 class="text-sm font-medium text-neutral-900 dark:text-white">useShare</h4>
618
+ <UBadge color="primary" variant="subtle"> Auto-imported </UBadge>
619
+ </div>
620
+ <p class="text-sm text-neutral-600 dark:text-neutral-400 mb-3">Share content using the Web Share API with automatic fallback.</p>
621
+ <UButton size="sm" icon="i-lucide-share-2" class="mb-3" @click="handleShare"> Share Content </UButton>
622
+ </div>
623
+ </div>
624
+ </UCard>
625
+
626
+ <!-- Documentation Links -->
627
+ <UCard variant="outline">
628
+ <template #header>
629
+ <h3 class="text-xl font-semibold text-neutral-900 dark:text-white">Additional Resources</h3>
630
+ </template>
631
+
632
+ <div class="space-y-3">
633
+ <div class="flex items-center justify-between p-3 bg-neutral-50 dark:bg-neutral-900 rounded-lg">
634
+ <div>
635
+ <h4 class="font-medium text-neutral-900 dark:text-white">Nuxt UI Documentation</h4>
636
+ <p class="text-sm text-neutral-600 dark:text-neutral-400">All available components and their props</p>
637
+ </div>
638
+ <UButton to="https://ui.nuxt.com" target="_blank" trailing-icon="i-lucide-external-link" variant="outline" color="neutral" size="sm"> Docs </UButton>
639
+ </div>
640
+
641
+ <div class="flex items-center justify-between p-3 bg-neutral-50 dark:bg-neutral-900 rounded-lg">
642
+ <div>
643
+ <h4 class="font-medium text-neutral-900 dark:text-white">GitHub Repository</h4>
644
+ <p class="text-sm text-neutral-600 dark:text-neutral-400">Source code and additional examples</p>
645
+ </div>
646
+ <UButton to="https://github.com/lenneTech/nuxt-base-starter" target="_blank" trailing-icon="i-lucide-external-link" variant="outline" color="neutral" size="sm">
647
+ GitHub
648
+ </UButton>
649
+ </div>
650
+
651
+ <div class="flex items-center justify-between p-3 bg-neutral-50 dark:bg-neutral-900 rounded-lg">
652
+ <div>
653
+ <h4 class="font-medium text-neutral-900 dark:text-white">CLAUDE.md</h4>
654
+ <p class="text-sm text-neutral-600 dark:text-neutral-400">Detailed project documentation</p>
655
+ </div>
656
+ <UBadge color="primary" variant="subtle"> Included in project </UBadge>
657
+ </div>
658
+ </div>
659
+ </UCard>
660
+ </div>
661
+ </div>
662
+ </div>
663
+ </template>
@@ -1,3 +1,4 @@
1
1
  import vue from '@lenne.tech/eslint-config-vue';
2
2
 
3
- export default vue;
3
+ // Override the problematic rule configuration
4
+ export default vue