@tower_74/cms-app 0.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.
Files changed (189) hide show
  1. package/README.md +102 -0
  2. package/package.json +49 -0
  3. package/src/components/AppContent.vue +21 -0
  4. package/src/components/AppLogoIcon.vue +24 -0
  5. package/src/components/AppShell.vue +37 -0
  6. package/src/components/AppearanceTabs.vue +37 -0
  7. package/src/components/AuthBar.vue +58 -0
  8. package/src/components/BlockEditor.vue +95 -0
  9. package/src/components/DeleteUser.vue +87 -0
  10. package/src/components/FieldBuilder.vue +105 -0
  11. package/src/components/Heading.vue +20 -0
  12. package/src/components/HeadingSmall.vue +17 -0
  13. package/src/components/Icon.vue +30 -0
  14. package/src/components/InputError.vue +13 -0
  15. package/src/components/MenuItemsEditor.vue +59 -0
  16. package/src/components/NavUser.vue +30 -0
  17. package/src/components/Pagination.vue +28 -0
  18. package/src/components/PlaceholderPattern.vue +16 -0
  19. package/src/components/Seo.vue +28 -0
  20. package/src/components/TextLink.vue +24 -0
  21. package/src/components/UserInfo.vue +34 -0
  22. package/src/components/UserMenuContent.vue +37 -0
  23. package/src/components/commerce/OptionsEditor.vue +55 -0
  24. package/src/components/commerce/VariantsEditor.vue +71 -0
  25. package/src/components/ui/avatar/Avatar.vue +24 -0
  26. package/src/components/ui/avatar/AvatarFallback.vue +11 -0
  27. package/src/components/ui/avatar/AvatarImage.vue +9 -0
  28. package/src/components/ui/avatar/index.ts +24 -0
  29. package/src/components/ui/breadcrumb/Breadcrumb.vue +13 -0
  30. package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +18 -0
  31. package/src/components/ui/breadcrumb/BreadcrumbItem.vue +14 -0
  32. package/src/components/ui/breadcrumb/BreadcrumbLink.vue +15 -0
  33. package/src/components/ui/breadcrumb/BreadcrumbList.vue +14 -0
  34. package/src/components/ui/breadcrumb/BreadcrumbPage.vue +14 -0
  35. package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +17 -0
  36. package/src/components/ui/breadcrumb/index.ts +7 -0
  37. package/src/components/ui/button/Button.vue +22 -0
  38. package/src/components/ui/button/index.ts +31 -0
  39. package/src/components/ui/card/Card.vue +14 -0
  40. package/src/components/ui/card/CardContent.vue +14 -0
  41. package/src/components/ui/card/CardDescription.vue +14 -0
  42. package/src/components/ui/card/CardFooter.vue +14 -0
  43. package/src/components/ui/card/CardHeader.vue +14 -0
  44. package/src/components/ui/card/CardTitle.vue +14 -0
  45. package/src/components/ui/card/index.ts +6 -0
  46. package/src/components/ui/checkbox/Checkbox.vue +36 -0
  47. package/src/components/ui/checkbox/index.ts +1 -0
  48. package/src/components/ui/collapsible/Collapsible.vue +15 -0
  49. package/src/components/ui/collapsible/CollapsibleContent.vue +14 -0
  50. package/src/components/ui/collapsible/CollapsibleTrigger.vue +11 -0
  51. package/src/components/ui/collapsible/index.ts +3 -0
  52. package/src/components/ui/dialog/Dialog.vue +14 -0
  53. package/src/components/ui/dialog/DialogClose.vue +11 -0
  54. package/src/components/ui/dialog/DialogContent.vue +51 -0
  55. package/src/components/ui/dialog/DialogDescription.vue +21 -0
  56. package/src/components/ui/dialog/DialogFooter.vue +12 -0
  57. package/src/components/ui/dialog/DialogHeader.vue +14 -0
  58. package/src/components/ui/dialog/DialogScrollContent.vue +59 -0
  59. package/src/components/ui/dialog/DialogTitle.vue +21 -0
  60. package/src/components/ui/dialog/DialogTrigger.vue +11 -0
  61. package/src/components/ui/dialog/index.ts +9 -0
  62. package/src/components/ui/dropdown-menu/DropdownMenu.vue +14 -0
  63. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +42 -0
  64. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +40 -0
  65. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +11 -0
  66. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +30 -0
  67. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +21 -0
  68. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +14 -0
  69. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +43 -0
  70. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +21 -0
  71. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +14 -0
  72. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +14 -0
  73. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +30 -0
  74. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +31 -0
  75. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +13 -0
  76. package/src/components/ui/dropdown-menu/index.ts +16 -0
  77. package/src/components/ui/input/Input.vue +32 -0
  78. package/src/components/ui/input/index.ts +1 -0
  79. package/src/components/ui/label/Label.vue +22 -0
  80. package/src/components/ui/label/index.ts +1 -0
  81. package/src/components/ui/navigation-menu/NavigationMenu.vue +25 -0
  82. package/src/components/ui/navigation-menu/NavigationMenuContent.vue +31 -0
  83. package/src/components/ui/navigation-menu/NavigationMenuIndicator.vue +29 -0
  84. package/src/components/ui/navigation-menu/NavigationMenuItem.vue +11 -0
  85. package/src/components/ui/navigation-menu/NavigationMenuLink.vue +14 -0
  86. package/src/components/ui/navigation-menu/NavigationMenuList.vue +21 -0
  87. package/src/components/ui/navigation-menu/NavigationMenuTrigger.vue +24 -0
  88. package/src/components/ui/navigation-menu/NavigationMenuViewport.vue +29 -0
  89. package/src/components/ui/navigation-menu/index.ts +14 -0
  90. package/src/components/ui/separator/Separator.vue +31 -0
  91. package/src/components/ui/separator/index.ts +1 -0
  92. package/src/components/ui/sheet/Sheet.vue +14 -0
  93. package/src/components/ui/sheet/SheetClose.vue +11 -0
  94. package/src/components/ui/sheet/SheetContent.vue +53 -0
  95. package/src/components/ui/sheet/SheetDescription.vue +19 -0
  96. package/src/components/ui/sheet/SheetFooter.vue +12 -0
  97. package/src/components/ui/sheet/SheetHeader.vue +12 -0
  98. package/src/components/ui/sheet/SheetTitle.vue +19 -0
  99. package/src/components/ui/sheet/SheetTrigger.vue +11 -0
  100. package/src/components/ui/sheet/index.ts +29 -0
  101. package/src/components/ui/sidebar/Sidebar.vue +99 -0
  102. package/src/components/ui/sidebar/SidebarContent.vue +17 -0
  103. package/src/components/ui/sidebar/SidebarFooter.vue +14 -0
  104. package/src/components/ui/sidebar/SidebarGroup.vue +14 -0
  105. package/src/components/ui/sidebar/SidebarGroupAction.vue +31 -0
  106. package/src/components/ui/sidebar/SidebarGroupContent.vue +14 -0
  107. package/src/components/ui/sidebar/SidebarGroupLabel.vue +29 -0
  108. package/src/components/ui/sidebar/SidebarHeader.vue +14 -0
  109. package/src/components/ui/sidebar/SidebarInput.vue +15 -0
  110. package/src/components/ui/sidebar/SidebarInset.vue +22 -0
  111. package/src/components/ui/sidebar/SidebarMenu.vue +14 -0
  112. package/src/components/ui/sidebar/SidebarMenuAction.vue +41 -0
  113. package/src/components/ui/sidebar/SidebarMenuBadge.vue +27 -0
  114. package/src/components/ui/sidebar/SidebarMenuButton.vue +52 -0
  115. package/src/components/ui/sidebar/SidebarMenuButtonChild.vue +33 -0
  116. package/src/components/ui/sidebar/SidebarMenuItem.vue +14 -0
  117. package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +22 -0
  118. package/src/components/ui/sidebar/SidebarMenuSub.vue +23 -0
  119. package/src/components/ui/sidebar/SidebarMenuSubButton.vue +42 -0
  120. package/src/components/ui/sidebar/SidebarMenuSubItem.vue +7 -0
  121. package/src/components/ui/sidebar/SidebarProvider.vue +89 -0
  122. package/src/components/ui/sidebar/SidebarRail.vue +34 -0
  123. package/src/components/ui/sidebar/SidebarSeparator.vue +15 -0
  124. package/src/components/ui/sidebar/SidebarTrigger.vue +20 -0
  125. package/src/components/ui/sidebar/index.ts +51 -0
  126. package/src/components/ui/sidebar/utils.ts +19 -0
  127. package/src/components/ui/skeleton/Skeleton.vue +14 -0
  128. package/src/components/ui/skeleton/index.ts +1 -0
  129. package/src/components/ui/tooltip/Tooltip.vue +14 -0
  130. package/src/components/ui/tooltip/TooltipContent.vue +39 -0
  131. package/src/components/ui/tooltip/TooltipProvider.vue +11 -0
  132. package/src/components/ui/tooltip/TooltipTrigger.vue +11 -0
  133. package/src/components/ui/tooltip/index.ts +4 -0
  134. package/src/composables/useAppearance.ts +53 -0
  135. package/src/composables/useInitials.ts +14 -0
  136. package/src/index.ts +22 -0
  137. package/src/layouts/AdminLayout.vue +170 -0
  138. package/src/layouts/AuthLayout.vue +14 -0
  139. package/src/layouts/PublicLayout.vue +53 -0
  140. package/src/layouts/auth/AuthCardLayout.vue +36 -0
  141. package/src/layouts/auth/AuthSimpleLayout.vue +31 -0
  142. package/src/layouts/auth/AuthSplitLayout.vue +40 -0
  143. package/src/layouts/settings/Layout.vue +56 -0
  144. package/src/lib/utils.ts +6 -0
  145. package/src/pages/Admin/Appearance/Theme.vue +58 -0
  146. package/src/pages/Admin/Appearance/Widgets.vue +48 -0
  147. package/src/pages/Admin/Commerce/Orders/Index.vue +80 -0
  148. package/src/pages/Admin/Commerce/Orders/Show.vue +200 -0
  149. package/src/pages/Admin/Commerce/Products/Edit.vue +167 -0
  150. package/src/pages/Admin/Commerce/Products/Index.vue +65 -0
  151. package/src/pages/Admin/Content/Edit.vue +170 -0
  152. package/src/pages/Admin/Content/Index.vue +88 -0
  153. package/src/pages/Admin/Content/Preview.vue +25 -0
  154. package/src/pages/Admin/Dashboard.vue +26 -0
  155. package/src/pages/Admin/Forms/Edit.vue +98 -0
  156. package/src/pages/Admin/Forms/Index.vue +68 -0
  157. package/src/pages/Admin/Forms/Submissions/Index.vue +68 -0
  158. package/src/pages/Admin/Forms/Submissions/Show.vue +47 -0
  159. package/src/pages/Admin/Media/Index.vue +75 -0
  160. package/src/pages/Admin/Menus/Create.vue +37 -0
  161. package/src/pages/Admin/Menus/Edit.vue +54 -0
  162. package/src/pages/Admin/Menus/Index.vue +52 -0
  163. package/src/pages/Admin/Settings/Index.vue +184 -0
  164. package/src/pages/Admin/Taxonomy/Edit.vue +83 -0
  165. package/src/pages/Admin/Taxonomy/Index.vue +68 -0
  166. package/src/pages/Admin/Users/Edit.vue +82 -0
  167. package/src/pages/Admin/Users/Index.vue +74 -0
  168. package/src/pages/Public/Cart/Index.vue +108 -0
  169. package/src/pages/Public/Checkout/Confirmation.vue +110 -0
  170. package/src/pages/Public/Checkout/Index.vue +174 -0
  171. package/src/pages/Public/Index.vue +54 -0
  172. package/src/pages/Public/Shop/Index.vue +39 -0
  173. package/src/pages/Public/Shop/Show.vue +46 -0
  174. package/src/pages/Public/Show.vue +41 -0
  175. package/src/pages/Setup/Complete.vue +53 -0
  176. package/src/pages/Setup/Index.vue +85 -0
  177. package/src/pages/Welcome.vue +787 -0
  178. package/src/pages/auth/ConfirmPassword.vue +53 -0
  179. package/src/pages/auth/ForgotPassword.vue +54 -0
  180. package/src/pages/auth/Login.vue +91 -0
  181. package/src/pages/auth/Register.vue +83 -0
  182. package/src/pages/auth/ResetPassword.vue +81 -0
  183. package/src/pages/auth/VerifyEmail.vue +36 -0
  184. package/src/pages/settings/Appearance.vue +23 -0
  185. package/src/pages/settings/Password.vue +120 -0
  186. package/src/pages/settings/Profile.vue +105 -0
  187. package/src/pages.ts +9 -0
  188. package/src/types/index.ts +42 -0
  189. package/src/types/ziggy.ts +12 -0
@@ -0,0 +1,39 @@
1
+ <script setup lang="ts">
2
+ import Pagination from '@/components/Pagination.vue';
3
+ import Seo from '@/components/Seo.vue';
4
+ import PublicLayout from '@/layouts/PublicLayout.vue';
5
+ import { type Block, ProductGrid } from '@tower_74/cms-ui';
6
+
7
+ interface ProductItem {
8
+ name: string;
9
+ url: string;
10
+ price: string | null;
11
+ image: { src: string; alt?: string } | null;
12
+ }
13
+ interface PageLink {
14
+ url: string | null;
15
+ label: string;
16
+ active: boolean;
17
+ }
18
+
19
+ defineProps<{
20
+ site: { name: string };
21
+ menu: Array<{ label: string; url: string }>;
22
+ footerWidgets: Block[];
23
+ cartCount?: number | null;
24
+ products: { data: ProductItem[]; links: PageLink[] };
25
+ seo: { title: string; description?: string | null; url?: string | null; image?: string | null; type?: string | null };
26
+ }>();
27
+ </script>
28
+
29
+ <template>
30
+ <Seo :seo="seo" />
31
+
32
+ <PublicLayout :site="site" :menu="menu" :footer-widgets="footerWidgets" :cart-count="cartCount">
33
+ <div class="mx-auto max-w-6xl px-4 py-12 sm:px-6">
34
+ <h1 class="mb-8 text-3xl font-bold tracking-tight">Shop</h1>
35
+ <ProductGrid :products="products.data" :columns="3" empty="No products available yet." />
36
+ <Pagination :links="products.links" />
37
+ </div>
38
+ </PublicLayout>
39
+ </template>
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ import Seo from '@/components/Seo.vue';
3
+ import PublicLayout from '@/layouts/PublicLayout.vue';
4
+ import { router } from '@inertiajs/vue3';
5
+ import { type Block, BlockRenderer, ProductOverview } from '@tower_74/cms-ui';
6
+
7
+ interface ProductData {
8
+ name: string;
9
+ description: string | null;
10
+ image: { src: string; alt?: string } | null;
11
+ blocks: Block[];
12
+ options: Array<{ name: string; values: string[] }>;
13
+ variants: Array<{ id: number; options: Record<string, string>; price: string; available: boolean }>;
14
+ }
15
+
16
+ defineProps<{
17
+ site: { name: string };
18
+ menu: Array<{ label: string; url: string }>;
19
+ footerWidgets: Block[];
20
+ cartCount?: number | null;
21
+ product: ProductData;
22
+ seo: { title: string; description?: string | null; url?: string | null; image?: string | null; type?: string | null };
23
+ }>();
24
+
25
+ const addToCart = (payload: { variantId: number | string; quantity: number }) => {
26
+ // Wired to the cart in Phase 8.3. For now this posts to the (future) cart endpoint.
27
+ router.post('/cart', { variant_id: payload.variantId, quantity: payload.quantity }, { preserveScroll: true });
28
+ };
29
+ </script>
30
+
31
+ <template>
32
+ <Seo :seo="seo" />
33
+
34
+ <PublicLayout :site="site" :menu="menu" :footer-widgets="footerWidgets" :cart-count="cartCount">
35
+ <ProductOverview
36
+ :name="product.name"
37
+ :description="product.description ?? undefined"
38
+ :image="product.image ?? undefined"
39
+ :options="product.options"
40
+ :variants="product.variants"
41
+ @add-to-cart="addToCart"
42
+ />
43
+
44
+ <BlockRenderer v-if="product.blocks.length" :blocks="product.blocks" />
45
+ </PublicLayout>
46
+ </template>
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import Seo from '@/components/Seo.vue';
3
+ import PublicLayout from '@/layouts/PublicLayout.vue';
4
+ import { type Block, DetailPageTemplate, LandingPageTemplate } from '@tower_74/cms-ui';
5
+
6
+ defineProps<{
7
+ site: { name: string };
8
+ menu: Array<{ label: string; url: string }>;
9
+ footerWidgets: Block[];
10
+ cartCount?: number | null;
11
+ edit?: { url: string; label: string } | null;
12
+ page: {
13
+ title: string;
14
+ template: 'landing' | 'detail';
15
+ showTitle?: boolean;
16
+ header?: { title: string; subtitle?: string | null };
17
+ featuredImage?: { src: string; alt?: string } | null;
18
+ blocks: Block[];
19
+ };
20
+ seo: { title: string; description?: string | null; url?: string | null; image?: string | null; type?: string | null };
21
+ }>();
22
+ </script>
23
+
24
+ <template>
25
+ <Seo :seo="seo" />
26
+
27
+ <PublicLayout :site="site" :menu="menu" :footer-widgets="footerWidgets" :cart-count="cartCount" :edit="edit">
28
+ <template v-if="page.template === 'landing'">
29
+ <div v-if="page.showTitle" class="mx-auto max-w-6xl px-4 pb-2 pt-10 sm:px-6">
30
+ <h1 class="text-3xl font-bold tracking-tight text-text">{{ page.title }}</h1>
31
+ </div>
32
+ <LandingPageTemplate :blocks="page.blocks" />
33
+ </template>
34
+ <template v-else>
35
+ <div v-if="page.featuredImage" class="mx-auto max-w-3xl px-4 pt-8 sm:px-6">
36
+ <img :src="page.featuredImage.src" :alt="page.featuredImage.alt ?? ''" class="w-full rounded-lg object-cover" />
37
+ </div>
38
+ <DetailPageTemplate :header="page.header" :blocks="page.blocks" />
39
+ </template>
40
+ </PublicLayout>
41
+ </template>
@@ -0,0 +1,53 @@
1
+ <script setup lang="ts">
2
+ import { Head, Link } from '@inertiajs/vue3';
3
+ import { Button, Card } from '@tower_74/cms-ui';
4
+
5
+ defineProps<{
6
+ summary: { email: string; commerceEnabled: boolean; demoSeeded: boolean; version: string } | null;
7
+ loginUrl: string;
8
+ }>();
9
+ </script>
10
+
11
+ <template>
12
+ <Head title="Setup complete" />
13
+
14
+ <div class="flex min-h-screen items-center justify-center bg-surface px-4 py-12">
15
+ <div class="w-full max-w-lg">
16
+ <Card>
17
+ <div class="text-center">
18
+ <div class="bg-success/15 mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full text-2xl text-success">✓</div>
19
+ <h1 class="text-2xl font-bold tracking-tight">You're all set!</h1>
20
+ <p class="mt-1 text-sm text-muted">Your site has been installed and is ready to use.</p>
21
+ </div>
22
+
23
+ <dl v-if="summary" class="my-6 space-y-2 rounded-lg border border-border bg-background p-4 text-sm">
24
+ <div class="flex justify-between">
25
+ <dt class="text-muted">Admin email</dt>
26
+ <dd class="font-medium">{{ summary.email }}</dd>
27
+ </div>
28
+ <div class="flex justify-between">
29
+ <dt class="text-muted">Commerce</dt>
30
+ <dd>{{ summary.commerceEnabled ? 'Enabled' : 'Disabled' }}</dd>
31
+ </div>
32
+ <div v-if="summary.demoSeeded" class="flex justify-between">
33
+ <dt class="text-muted">Demo content</dt>
34
+ <dd>Seeded</dd>
35
+ </div>
36
+ <div class="flex justify-between">
37
+ <dt class="text-muted">Version</dt>
38
+ <dd>{{ summary.version }}</dd>
39
+ </div>
40
+ </dl>
41
+
42
+ <Link :href="loginUrl" class="block">
43
+ <Button size="lg" class="w-full">Log in to your admin</Button>
44
+ </Link>
45
+ </Card>
46
+
47
+ <p class="mt-4 text-center text-xs text-muted">
48
+ Remember to build front-end assets if you haven't yet:
49
+ <code class="rounded bg-background px-1">npm ci && npm run build</code>.
50
+ </p>
51
+ </div>
52
+ </div>
53
+ </template>
@@ -0,0 +1,85 @@
1
+ <script setup lang="ts">
2
+ import { Head, useForm } from '@inertiajs/vue3';
3
+ import { Button, Card, Checkbox, FormField, Input } from '@tower_74/cms-ui';
4
+
5
+ const props = defineProps<{
6
+ appName: string;
7
+ siteName: string;
8
+ siteUrl: string | null;
9
+ commerceAvailable: boolean;
10
+ version: string;
11
+ }>();
12
+
13
+ const form = useForm({
14
+ admin_name: '',
15
+ admin_email: '',
16
+ admin_password: '',
17
+ site_name: props.siteName,
18
+ site_url: props.siteUrl ?? '',
19
+ with_commerce: false,
20
+ demo: false,
21
+ });
22
+
23
+ const submit = () => form.post('/setup');
24
+ </script>
25
+
26
+ <template>
27
+ <Head title="Set up your site" />
28
+
29
+ <div class="flex min-h-screen items-center justify-center bg-surface px-4 py-12">
30
+ <div class="w-full max-w-lg">
31
+ <div class="mb-6 text-center">
32
+ <h1 class="text-2xl font-bold tracking-tight">Welcome to {{ appName }}</h1>
33
+ <p class="mt-1 text-sm text-muted">Let's get your site set up. (v{{ version }})</p>
34
+ </div>
35
+
36
+ <Card>
37
+ <p v-if="form.errors.install" class="border-danger/40 bg-danger/10 mb-4 rounded border px-3 py-2 text-sm text-danger">
38
+ {{ form.errors.install }}
39
+ </p>
40
+
41
+ <form class="space-y-6" @submit.prevent="submit">
42
+ <div>
43
+ <h2 class="mb-3 text-sm font-semibold uppercase tracking-wide text-muted">Administrator</h2>
44
+ <div class="space-y-4">
45
+ <FormField label="Your name" :error="form.errors.admin_name" required>
46
+ <Input v-model="form.admin_name" :invalid="!!form.errors.admin_name" />
47
+ </FormField>
48
+ <FormField label="Email" :error="form.errors.admin_email" required>
49
+ <Input v-model="form.admin_email" type="email" :invalid="!!form.errors.admin_email" />
50
+ </FormField>
51
+ <FormField label="Password" :error="form.errors.admin_password" help="At least 8 characters." required>
52
+ <Input v-model="form.admin_password" type="password" :invalid="!!form.errors.admin_password" />
53
+ </FormField>
54
+ </div>
55
+ </div>
56
+
57
+ <div>
58
+ <h2 class="mb-3 text-sm font-semibold uppercase tracking-wide text-muted">Site</h2>
59
+ <div class="space-y-4">
60
+ <FormField label="Site name" :error="form.errors.site_name" required>
61
+ <Input v-model="form.site_name" :invalid="!!form.errors.site_name" />
62
+ </FormField>
63
+ <FormField label="Site URL" :error="form.errors.site_url" help="Optional — written to APP_URL.">
64
+ <Input v-model="form.site_url" type="url" placeholder="https://example.com" :invalid="!!form.errors.site_url" />
65
+ </FormField>
66
+ </div>
67
+ </div>
68
+
69
+ <div class="space-y-3 border-t border-border pt-4">
70
+ <Checkbox v-if="commerceAvailable" v-model="form.with_commerce" label="Enable commerce (storefront + cart)" />
71
+ <Checkbox v-model="form.demo" label="Seed demo content to explore" />
72
+ </div>
73
+
74
+ <Button type="submit" size="lg" class="w-full" :disabled="form.processing">
75
+ {{ form.processing ? 'Installing…' : 'Install' }}
76
+ </Button>
77
+ </form>
78
+ </Card>
79
+
80
+ <p class="mt-4 text-center text-xs text-muted">
81
+ Prefer the CLI? Run <code class="rounded bg-background px-1">php artisan cms:install</code>.
82
+ </p>
83
+ </div>
84
+ </div>
85
+ </template>