create-vexcms 0.0.20 → 0.1.0-alpha.2
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/LICENSE +202 -0
- package/README.md +93 -83
- package/dist/index.js +246 -81
- package/dist/index.mjs +30976 -0
- package/package.json +35 -15
- package/templates/base-nextjs/README.md +53 -205
- package/templates/base-nextjs/_env.example +7 -9
- package/templates/base-nextjs/_gitignore +41 -1
- package/templates/base-nextjs/convex/_generated/api.d.ts +6 -62
- package/templates/base-nextjs/convex/_generated/server.d.ts +19 -0
- package/templates/base-nextjs/convex/_generated/server.js +8 -0
- package/templates/base-nextjs/convex/auth/api.ts +49 -3
- package/templates/base-nextjs/convex/auth/db.ts +42 -300
- package/templates/base-nextjs/convex/auth/index.ts +11 -7
- package/templates/base-nextjs/convex/auth/options.ts +5 -29
- package/templates/base-nextjs/convex/auth/plugins/index.ts +15 -5
- package/templates/base-nextjs/convex/auth/sessions.ts +9 -15
- package/templates/base-nextjs/convex/http.ts +18 -3
- package/templates/base-nextjs/convex/schema.ts +104 -2
- package/templates/base-nextjs/convex/vex/firstUser.ts +10 -84
- package/templates/base-nextjs/convex/vex/globals.ts +19 -82
- package/templates/base-nextjs/convex/vex/media.ts +19 -246
- package/templates/base-nextjs/convex/vex.schema.ts +138 -0
- package/templates/base-nextjs/convex/vex.ts +19 -0
- package/templates/base-nextjs/convex.json +6 -0
- package/templates/base-nextjs/eslint.config.mjs +1 -21
- package/templates/base-nextjs/next.config.ts +10 -0
- package/templates/base-nextjs/package.json +47 -48
- package/templates/base-nextjs/src/app/(frontend)/@auth/(...)auth/[pathname]/view.tsx +17 -5
- package/templates/base-nextjs/src/app/(frontend)/auth/[pathname]/view.tsx +2 -4
- package/templates/base-nextjs/src/app/(frontend)/layout.tsx +12 -2
- package/templates/base-nextjs/src/app/(frontend)/page.tsx +2 -113
- package/templates/base-nextjs/src/app/(vexcms)/admin/[[...path]]/page.tsx +40 -0
- package/templates/base-nextjs/src/app/(vexcms)/admin/clientProviders.tsx +22 -0
- package/templates/base-nextjs/src/app/(vexcms)/admin/layout.tsx +19 -0
- package/templates/base-nextjs/src/app/globals.css +240 -104
- package/templates/base-nextjs/src/app/layout.tsx +23 -13
- package/templates/base-nextjs/src/app/unauthorized/page.tsx +24 -0
- package/templates/base-nextjs/src/auth/access.ts +46 -0
- package/templates/base-nextjs/src/auth/client.tsx +17 -5
- package/templates/base-nextjs/src/auth/hasPermission.ts +39 -0
- package/templates/base-nextjs/src/auth/serverUtils.ts +15 -25
- package/templates/base-nextjs/src/components/WelcomePage.tsx +116 -0
- package/templates/base-nextjs/src/components/component-example.tsx +56 -464
- package/templates/base-nextjs/src/components/providers/auth.tsx +13 -0
- package/templates/base-nextjs/src/components/providers/client.tsx +6 -1
- package/templates/base-nextjs/src/components/providers/convex.tsx +53 -21
- package/templates/base-nextjs/src/components/providers/server.tsx +10 -7
- package/templates/{marketing-site → base-nextjs}/src/components/ui/accordion.tsx +30 -32
- package/templates/base-nextjs/src/components/ui/badge.tsx +10 -13
- package/templates/base-nextjs/src/components/ui/input.tsx +35 -5
- package/templates/base-nextjs/src/context/AuthContext.tsx +29 -0
- package/templates/base-nextjs/src/db/constants/auth.ts +0 -1
- package/templates/base-nextjs/src/db/constants/index.ts +22 -35
- package/templates/base-nextjs/src/lib/utils.ts +0 -12
- package/templates/base-nextjs/src/proxy.ts +97 -12
- package/templates/base-nextjs/src/vex.config.ts +35 -0
- package/templates/base-nextjs/src/vex.types.ts +293 -0
- package/templates/base-nextjs/src/vexcms/collections/images.ts +15 -0
- package/templates/base-nextjs/src/vexcms/collections/index.ts +2 -1
- package/templates/base-nextjs/src/vexcms/collections/users.ts +7 -35
- package/templates/base-nextjs/tsconfig.json +3 -0
- package/templates/marketing-site/convex/_generated/api.d.ts +81 -0
- package/templates/marketing-site/convex/_generated/api.js +23 -0
- package/templates/marketing-site/convex/_generated/dataModel.d.ts +60 -0
- package/templates/marketing-site/convex/_generated/server.d.ts +162 -0
- package/templates/marketing-site/convex/_generated/server.js +101 -0
- package/templates/marketing-site/convex/footers.ts +11 -7
- package/templates/marketing-site/convex/headers.ts +15 -5
- package/templates/marketing-site/convex/pages.ts +20 -35
- package/templates/marketing-site/convex/schema.ts +119 -0
- package/templates/marketing-site/convex/seed.ts +582 -35
- package/templates/marketing-site/convex/siteSettings.ts +19 -5
- package/templates/marketing-site/convex/theme.ts +55 -61
- package/templates/marketing-site/convex/vex.schema.ts +355 -0
- package/templates/marketing-site/src/app/(frontend)/PageContent.tsx +27 -160
- package/templates/marketing-site/src/app/(frontend)/[slug]/page.tsx +6 -9
- package/templates/marketing-site/src/app/(frontend)/layout.tsx +4 -2
- package/templates/marketing-site/src/app/(frontend)/page.tsx +2 -5
- package/templates/marketing-site/src/components/SiteFooter.tsx +6 -3
- package/templates/marketing-site/src/components/SiteHeader.tsx +6 -3
- package/templates/marketing-site/src/components/ThemeLive.tsx +59 -0
- package/templates/marketing-site/src/components/ThemeStyle.tsx +45 -89
- package/templates/marketing-site/src/lib/metadata.ts +51 -72
- package/templates/marketing-site/src/vex.config.ts +35 -0
- package/templates/marketing-site/src/vex.types.ts +634 -0
- package/templates/marketing-site/src/vexcms/api.ts +23 -0
- package/templates/marketing-site/src/vexcms/blocks/CTA/config.ts +3 -3
- package/templates/marketing-site/src/vexcms/blocks/CTA/index.tsx +2 -2
- package/templates/marketing-site/src/vexcms/blocks/FAQ/config.ts +4 -4
- package/templates/marketing-site/src/vexcms/blocks/FAQ/index.tsx +2 -2
- package/templates/marketing-site/src/vexcms/blocks/Features/config.ts +4 -8
- package/templates/marketing-site/src/vexcms/blocks/Features/index.tsx +2 -2
- package/templates/marketing-site/src/vexcms/blocks/Footer/config.ts +7 -11
- package/templates/marketing-site/src/vexcms/blocks/Footer/index.tsx +1 -1
- package/templates/marketing-site/src/vexcms/blocks/Header/config.ts +9 -9
- package/templates/marketing-site/src/vexcms/blocks/Header/index.tsx +4 -5
- package/templates/marketing-site/src/vexcms/blocks/Hero/config.ts +3 -4
- package/templates/marketing-site/src/vexcms/blocks/Hero/index.tsx +10 -19
- package/templates/marketing-site/src/vexcms/blocks/HowItWorks/config.ts +4 -9
- package/templates/marketing-site/src/vexcms/blocks/HowItWorks/index.tsx +3 -6
- package/templates/marketing-site/src/vexcms/blocks/Roadmap/config.ts +28 -68
- package/templates/marketing-site/src/vexcms/blocks/Roadmap/index.tsx +13 -43
- package/templates/marketing-site/src/vexcms/blocks/config.ts +7 -22
- package/templates/marketing-site/src/vexcms/blocks/constants.ts +2 -3
- package/templates/marketing-site/src/vexcms/blocks/index.ts +9 -8
- package/templates/marketing-site/src/vexcms/collections/footers.ts +1 -1
- package/templates/marketing-site/src/vexcms/collections/headers.ts +1 -1
- package/templates/marketing-site/src/vexcms/collections/index.ts +2 -1
- package/templates/marketing-site/src/vexcms/collections/pages.ts +12 -21
- package/templates/marketing-site/src/vexcms/collections/themeColors.ts +118 -0
- package/templates/marketing-site/src/vexcms/collections/themes.ts +29 -111
- package/templates/marketing-site/src/vexcms/globals/index.ts +1 -1
- package/templates/marketing-site/src/vexcms/globals/siteSettings.ts +43 -27
- package/templates/base-nextjs/convex/auth/adapter/index.ts +0 -230
- package/templates/base-nextjs/convex/auth/adapter/utils.ts +0 -547
- package/templates/base-nextjs/convex/auth/config.ts +0 -10
- package/templates/base-nextjs/convex/vex/auth.ts +0 -38
- package/templates/base-nextjs/convex/vex/collections.ts +0 -333
- package/templates/base-nextjs/convex/vex/helpers.ts +0 -33
- package/templates/base-nextjs/convex/vex/impersonation.ts +0 -51
- package/templates/base-nextjs/convex/vex/migrate.ts +0 -74
- package/templates/base-nextjs/convex/vex/model/collections.ts +0 -196
- package/templates/base-nextjs/convex/vex/model/media.ts +0 -87
- package/templates/base-nextjs/convex/vex/model/versions.ts +0 -254
- package/templates/base-nextjs/convex/vex/previewSnapshot.ts +0 -53
- package/templates/base-nextjs/convex/vex/versions.ts +0 -648
- package/templates/base-nextjs/src/app/admin/AdminLayoutWrapper.tsx +0 -33
- package/templates/base-nextjs/src/app/admin/AdminPageWrapper.tsx +0 -38
- package/templates/base-nextjs/src/app/admin/RichTextFieldWithMedia.tsx +0 -101
- package/templates/base-nextjs/src/app/admin/[[...path]]/page.tsx +0 -15
- package/templates/base-nextjs/src/app/admin/layout.tsx +0 -51
- package/templates/base-nextjs/src/app/favicon.ico +0 -0
- package/templates/base-nextjs/src/components/providers/theme.tsx +0 -11
- package/templates/base-nextjs/src/components/ui/theme-toggle.tsx +0 -67
- package/templates/base-nextjs/src/db/types.ts +0 -6
- package/templates/base-nextjs/src/vexcms/access.ts +0 -44
- package/templates/base-nextjs/src/vexcms/auth.ts +0 -4
- package/templates/base-nextjs/src/vexcms/collections/media.ts +0 -15
- package/templates/base-nextjs/vex.config.ts +0 -25
- package/templates/marketing-site/public/favicons/favicon.ico +0 -0
- package/templates/marketing-site/src/app/(frontend)/preview/[slug]/PreviewPageContent.tsx +0 -55
- package/templates/marketing-site/src/app/(frontend)/preview/[slug]/page.tsx +0 -27
- package/templates/marketing-site/src/app/(frontend)/preview/layout.tsx +0 -18
- package/templates/marketing-site/src/app/admin/AdminLayoutWrapper.tsx +0 -71
- package/templates/marketing-site/src/components/ThemeInjector.tsx +0 -128
- package/templates/marketing-site/src/components/admin/IconPickerField.tsx +0 -134
- package/templates/marketing-site/src/components/admin/ThemeImport.tsx +0 -174
- package/templates/marketing-site/src/components/admin/ThemeImportField.tsx +0 -33
- package/templates/marketing-site/src/db/constants/index.ts +0 -52
- package/templates/marketing-site/src/lib/colorConvert.ts +0 -171
- package/templates/marketing-site/src/vexcms/access.ts +0 -36
- package/templates/marketing-site/vex.config.ts +0 -32
|
@@ -1,17 +1,328 @@
|
|
|
1
|
+
import { getGlobal, upsertGlobal } from "@vexcms/core/server"
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
GLOBAL_SLUG_SITE_SETTINGS,
|
|
5
|
+
TABLE_SLUG_FOOTERS,
|
|
6
|
+
TABLE_SLUG_HEADERS,
|
|
7
|
+
TABLE_SLUG_PAGES,
|
|
8
|
+
TABLE_SLUG_THEMES,
|
|
9
|
+
} from "~/db/constants"
|
|
10
|
+
import config from "~/vex.config"
|
|
11
|
+
|
|
1
12
|
import { internalMutation } from "./_generated/server"
|
|
2
13
|
|
|
3
14
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
15
|
+
* The 4 tweakcn theme presets, lifted verbatim from
|
|
16
|
+
* `apps/test/convex/seed.ts`'s `THEME_PRESETS` (32-token light/dark palettes
|
|
17
|
+
* matching `themeColors.ts`'s `ThemeColorTokenKey` set).
|
|
18
|
+
*/
|
|
19
|
+
const THEME_PRESETS = [
|
|
20
|
+
{
|
|
21
|
+
name: "Stark × Ember",
|
|
22
|
+
fontFamily: "Geist, Inter, system-ui, sans-serif",
|
|
23
|
+
radius: "4px",
|
|
24
|
+
light: {
|
|
25
|
+
background: "oklch(96.1% 0 0)",
|
|
26
|
+
foreground: "oklch(13.7% 0 0)",
|
|
27
|
+
card: "oklch(100% 0 0)",
|
|
28
|
+
cardForeground: "oklch(13.7% 0 0)",
|
|
29
|
+
popover: "oklch(100% 0 0)",
|
|
30
|
+
popoverForeground: "oklch(13.7% 0 0)",
|
|
31
|
+
primary: "oklch(60.5% 0.175 42)",
|
|
32
|
+
primaryForeground: "oklch(100% 0 0)",
|
|
33
|
+
secondary: "oklch(98% 0 0)",
|
|
34
|
+
secondaryForeground: "oklch(13.7% 0 0)",
|
|
35
|
+
muted: "oklch(98% 0 0)",
|
|
36
|
+
mutedForeground: "oklch(50.5% 0 0)",
|
|
37
|
+
accent: "oklch(96% 0.025 42)",
|
|
38
|
+
accentForeground: "oklch(52% 0.180 40)",
|
|
39
|
+
destructive: "oklch(57.7% 0.198 27)",
|
|
40
|
+
destructiveForeground: "oklch(98% 0 0)",
|
|
41
|
+
border: "oklch(85% 0 0)",
|
|
42
|
+
input: "oklch(54.6% 0 0)",
|
|
43
|
+
ring: "oklch(60.5% 0.175 42)",
|
|
44
|
+
chart1: "oklch(60.5% 0.175 42)",
|
|
45
|
+
chart2: "oklch(45% 0 0)",
|
|
46
|
+
chart3: "oklch(72% 0.100 60)",
|
|
47
|
+
chart4: "oklch(60% 0.040 30)",
|
|
48
|
+
chart5: "oklch(78% 0 0)",
|
|
49
|
+
sidebar: "oklch(98% 0 0)",
|
|
50
|
+
sidebarForeground: "oklch(13.7% 0 0)",
|
|
51
|
+
sidebarPrimary: "oklch(60.5% 0.175 42)",
|
|
52
|
+
sidebarPrimaryForeground: "oklch(100% 0 0)",
|
|
53
|
+
sidebarAccent: "oklch(96.1% 0 0)",
|
|
54
|
+
sidebarAccentForeground: "oklch(13.7% 0 0)",
|
|
55
|
+
sidebarBorder: "oklch(85% 0 0)",
|
|
56
|
+
sidebarRing: "oklch(60.5% 0.175 42)",
|
|
57
|
+
},
|
|
58
|
+
dark: {
|
|
59
|
+
background: "oklch(13.7% 0 0)",
|
|
60
|
+
foreground: "oklch(95% 0 0)",
|
|
61
|
+
card: "oklch(17.4% 0 0)",
|
|
62
|
+
cardForeground: "oklch(95% 0 0)",
|
|
63
|
+
popover: "oklch(17.4% 0 0)",
|
|
64
|
+
popoverForeground: "oklch(95% 0 0)",
|
|
65
|
+
primary: "oklch(72% 0.175 50)",
|
|
66
|
+
primaryForeground: "oklch(13.7% 0 0)",
|
|
67
|
+
secondary: "oklch(20% 0 0)",
|
|
68
|
+
secondaryForeground: "oklch(95% 0 0)",
|
|
69
|
+
muted: "oklch(20% 0 0)",
|
|
70
|
+
mutedForeground: "oklch(70% 0 0)",
|
|
71
|
+
accent: "oklch(72% 0.175 50 / 0.12)",
|
|
72
|
+
accentForeground: "oklch(72% 0.175 50)",
|
|
73
|
+
destructive: "oklch(63% 0.210 27)",
|
|
74
|
+
destructiveForeground: "oklch(95% 0 0)",
|
|
75
|
+
border: "oklch(25% 0 0)",
|
|
76
|
+
input: "oklch(40% 0 0)",
|
|
77
|
+
ring: "oklch(72% 0.175 50)",
|
|
78
|
+
chart1: "oklch(72% 0.175 50)",
|
|
79
|
+
chart2: "oklch(78% 0 0)",
|
|
80
|
+
chart3: "oklch(78% 0.120 65)",
|
|
81
|
+
chart4: "oklch(60% 0.060 30)",
|
|
82
|
+
chart5: "oklch(45% 0 0)",
|
|
83
|
+
sidebar: "oklch(7% 0 0)",
|
|
84
|
+
sidebarForeground: "oklch(95% 0 0)",
|
|
85
|
+
sidebarPrimary: "oklch(72% 0.175 50)",
|
|
86
|
+
sidebarPrimaryForeground: "oklch(13.7% 0 0)",
|
|
87
|
+
sidebarAccent: "oklch(20% 0 0)",
|
|
88
|
+
sidebarAccentForeground: "oklch(95% 0 0)",
|
|
89
|
+
sidebarBorder: "oklch(25% 0 0)",
|
|
90
|
+
sidebarRing: "oklch(72% 0.175 50)",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "Modern Minimal",
|
|
95
|
+
fontFamily: "Inter, sans-serif",
|
|
96
|
+
radius: "0.375rem",
|
|
97
|
+
light: {
|
|
98
|
+
background: "oklch(100% 0 0)",
|
|
99
|
+
foreground: "oklch(32.11% 0 0)",
|
|
100
|
+
card: "oklch(100% 0 0)",
|
|
101
|
+
cardForeground: "oklch(32.11% 0 0)",
|
|
102
|
+
popover: "oklch(100% 0 0)",
|
|
103
|
+
popoverForeground: "oklch(32.11% 0 0)",
|
|
104
|
+
primary: "oklch(62.31% 0.18801 259.81)",
|
|
105
|
+
primaryForeground: "oklch(100% 0 0)",
|
|
106
|
+
secondary: "oklch(96.7% 0.00287 264.54)",
|
|
107
|
+
secondaryForeground: "oklch(44.61% 0.02631 256.8)",
|
|
108
|
+
muted: "oklch(98.46% 0.00171 247.84)",
|
|
109
|
+
mutedForeground: "oklch(55.1% 0.02336 264.36)",
|
|
110
|
+
accent: "oklch(95.14% 0.02503 236.82)",
|
|
111
|
+
accentForeground: "oklch(37.91% 0.13776 265.52)",
|
|
112
|
+
destructive: "oklch(63.68% 0.20785 25.33)",
|
|
113
|
+
destructiveForeground: "oklch(100% 0 0)",
|
|
114
|
+
border: "oklch(92.76% 0.00581 264.53)",
|
|
115
|
+
input: "oklch(92.76% 0.00581 264.53)",
|
|
116
|
+
ring: "oklch(62.31% 0.18801 259.81)",
|
|
117
|
+
chart1: "oklch(62.31% 0.18801 259.81)",
|
|
118
|
+
chart2: "oklch(54.61% 0.21521 262.88)",
|
|
119
|
+
chart3: "oklch(48.82% 0.21717 264.38)",
|
|
120
|
+
chart4: "oklch(42.44% 0.18087 265.64)",
|
|
121
|
+
chart5: "oklch(37.91% 0.13776 265.52)",
|
|
122
|
+
sidebar: "oklch(98.46% 0.00171 247.84)",
|
|
123
|
+
sidebarForeground: "oklch(32.11% 0 0)",
|
|
124
|
+
sidebarPrimary: "oklch(62.31% 0.18801 259.81)",
|
|
125
|
+
sidebarPrimaryForeground: "oklch(100% 0 0)",
|
|
126
|
+
sidebarAccent: "oklch(95.14% 0.02503 236.82)",
|
|
127
|
+
sidebarAccentForeground: "oklch(37.91% 0.13776 265.52)",
|
|
128
|
+
sidebarBorder: "oklch(92.76% 0.00581 264.53)",
|
|
129
|
+
sidebarRing: "oklch(62.31% 0.18801 259.81)",
|
|
130
|
+
},
|
|
131
|
+
dark: {
|
|
132
|
+
background: "oklch(20.46% 0 0)",
|
|
133
|
+
foreground: "oklch(92.19% 0 0)",
|
|
134
|
+
card: "oklch(26.86% 0 0)",
|
|
135
|
+
cardForeground: "oklch(92.19% 0 0)",
|
|
136
|
+
popover: "oklch(26.86% 0 0)",
|
|
137
|
+
popoverForeground: "oklch(92.19% 0 0)",
|
|
138
|
+
primary: "oklch(62.31% 0.18801 259.81)",
|
|
139
|
+
primaryForeground: "oklch(100% 0 0)",
|
|
140
|
+
secondary: "oklch(26.86% 0 0)",
|
|
141
|
+
secondaryForeground: "oklch(92.19% 0 0)",
|
|
142
|
+
muted: "oklch(23.93% 0 0)",
|
|
143
|
+
mutedForeground: "oklch(71.55% 0 0)",
|
|
144
|
+
accent: "oklch(37.91% 0.13776 265.52)",
|
|
145
|
+
accentForeground: "oklch(88.23% 0.05706 254.13)",
|
|
146
|
+
destructive: "oklch(63.68% 0.20785 25.33)",
|
|
147
|
+
destructiveForeground: "oklch(100% 0 0)",
|
|
148
|
+
border: "oklch(37.15% 0 0)",
|
|
149
|
+
input: "oklch(37.15% 0 0)",
|
|
150
|
+
ring: "oklch(62.31% 0.18801 259.81)",
|
|
151
|
+
chart1: "oklch(71.37% 0.14338 254.62)",
|
|
152
|
+
chart2: "oklch(62.31% 0.18801 259.81)",
|
|
153
|
+
chart3: "oklch(54.61% 0.21521 262.88)",
|
|
154
|
+
chart4: "oklch(48.82% 0.21717 264.38)",
|
|
155
|
+
chart5: "oklch(42.44% 0.18087 265.64)",
|
|
156
|
+
sidebar: "oklch(20.46% 0 0)",
|
|
157
|
+
sidebarForeground: "oklch(92.19% 0 0)",
|
|
158
|
+
sidebarPrimary: "oklch(62.31% 0.18801 259.81)",
|
|
159
|
+
sidebarPrimaryForeground: "oklch(100% 0 0)",
|
|
160
|
+
sidebarAccent: "oklch(37.91% 0.13776 265.52)",
|
|
161
|
+
sidebarAccentForeground: "oklch(88.23% 0.05706 254.13)",
|
|
162
|
+
sidebarBorder: "oklch(37.15% 0 0)",
|
|
163
|
+
sidebarRing: "oklch(62.31% 0.18801 259.81)",
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "Violet Bloom",
|
|
168
|
+
fontFamily: "Plus Jakarta Sans, sans-serif",
|
|
169
|
+
radius: "1.4rem",
|
|
170
|
+
light: {
|
|
171
|
+
background: "oklch(99.4% 0 0)",
|
|
172
|
+
foreground: "oklch(0% 0 0)",
|
|
173
|
+
card: "oklch(99.4% 0 0)",
|
|
174
|
+
cardForeground: "oklch(0% 0 0)",
|
|
175
|
+
popover: "oklch(99.11% 0 0)",
|
|
176
|
+
popoverForeground: "oklch(0% 0 0)",
|
|
177
|
+
primary: "oklch(53.93% 0.27129 286.75)",
|
|
178
|
+
primaryForeground: "oklch(100% 0 0)",
|
|
179
|
+
secondary: "oklch(95.4% 0.00626 255.48)",
|
|
180
|
+
secondaryForeground: "oklch(13.44% 0 0)",
|
|
181
|
+
muted: "oklch(97.02% 0 0)",
|
|
182
|
+
mutedForeground: "oklch(43.86% 0 0)",
|
|
183
|
+
accent: "oklch(93.93% 0.02876 266.37)",
|
|
184
|
+
accentForeground: "oklch(54.45% 0.19034 259.48)",
|
|
185
|
+
destructive: "oklch(62.9% 0.19024 23.07)",
|
|
186
|
+
destructiveForeground: "oklch(100% 0 0)",
|
|
187
|
+
border: "oklch(93% 0.00939 286.22)",
|
|
188
|
+
input: "oklch(94.01% 0 0)",
|
|
189
|
+
ring: "oklch(0% 0 0)",
|
|
190
|
+
chart1: "oklch(74.59% 0.14834 156.45)",
|
|
191
|
+
chart2: "oklch(53.93% 0.27129 286.75)",
|
|
192
|
+
chart3: "oklch(73.36% 0.17578 50.55)",
|
|
193
|
+
chart4: "oklch(58.28% 0.18094 259.73)",
|
|
194
|
+
chart5: "oklch(55.9% 0 0)",
|
|
195
|
+
sidebar: "oklch(97.77% 0.00513 247.88)",
|
|
196
|
+
sidebarForeground: "oklch(0% 0 0)",
|
|
197
|
+
sidebarPrimary: "oklch(0% 0 0)",
|
|
198
|
+
sidebarPrimaryForeground: "oklch(100% 0 0)",
|
|
199
|
+
sidebarAccent: "oklch(94.01% 0 0)",
|
|
200
|
+
sidebarAccentForeground: "oklch(0% 0 0)",
|
|
201
|
+
sidebarBorder: "oklch(94.01% 0 0)",
|
|
202
|
+
sidebarRing: "oklch(0% 0 0)",
|
|
203
|
+
},
|
|
204
|
+
dark: {
|
|
205
|
+
background: "oklch(22.23% 0.00601 271.14)",
|
|
206
|
+
foreground: "oklch(95.51% 0 0)",
|
|
207
|
+
card: "oklch(25.68% 0.00762 274.65)",
|
|
208
|
+
cardForeground: "oklch(95.51% 0 0)",
|
|
209
|
+
popover: "oklch(25.68% 0.00762 274.65)",
|
|
210
|
+
popoverForeground: "oklch(95.51% 0 0)",
|
|
211
|
+
primary: "oklch(61.32% 0.22941 291.74)",
|
|
212
|
+
primaryForeground: "oklch(100% 0 0)",
|
|
213
|
+
secondary: "oklch(29.4% 0.01301 272.93)",
|
|
214
|
+
secondaryForeground: "oklch(95.51% 0 0)",
|
|
215
|
+
muted: "oklch(29.4% 0.01301 272.93)",
|
|
216
|
+
mutedForeground: "oklch(70.58% 0 0)",
|
|
217
|
+
accent: "oklch(27.95% 0.03685 260.03)",
|
|
218
|
+
accentForeground: "oklch(78.57% 0.11535 246.66)",
|
|
219
|
+
destructive: "oklch(71.06% 0.16615 22.22)",
|
|
220
|
+
destructiveForeground: "oklch(100% 0 0)",
|
|
221
|
+
border: "oklch(32.89% 0.00922 268.38)",
|
|
222
|
+
input: "oklch(32.89% 0.00922 268.38)",
|
|
223
|
+
ring: "oklch(61.32% 0.22941 291.74)",
|
|
224
|
+
chart1: "oklch(80.03% 0.18206 151.71)",
|
|
225
|
+
chart2: "oklch(61.32% 0.22941 291.74)",
|
|
226
|
+
chart3: "oklch(80.77% 0.10349 19.57)",
|
|
227
|
+
chart4: "oklch(66.91% 0.15686 260.11)",
|
|
228
|
+
chart5: "oklch(70.58% 0 0)",
|
|
229
|
+
sidebar: "oklch(20.11% 0.00394 286.04)",
|
|
230
|
+
sidebarForeground: "oklch(95.51% 0 0)",
|
|
231
|
+
sidebarPrimary: "oklch(61.32% 0.22941 291.74)",
|
|
232
|
+
sidebarPrimaryForeground: "oklch(100% 0 0)",
|
|
233
|
+
sidebarAccent: "oklch(29.4% 0.01301 272.93)",
|
|
234
|
+
sidebarAccentForeground: "oklch(61.32% 0.22941 291.74)",
|
|
235
|
+
sidebarBorder: "oklch(32.89% 0.00922 268.38)",
|
|
236
|
+
sidebarRing: "oklch(61.32% 0.22941 291.74)",
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: "T3 Chat",
|
|
241
|
+
fontFamily: "Geist, Inter, system-ui, sans-serif",
|
|
242
|
+
radius: "0.5rem",
|
|
243
|
+
light: {
|
|
244
|
+
background: "oklch(97.54% 0.00844 325.64)",
|
|
245
|
+
foreground: "oklch(32.57% 0.11612 325.04)",
|
|
246
|
+
card: "oklch(97.54% 0.00844 325.64)",
|
|
247
|
+
cardForeground: "oklch(32.57% 0.11612 325.04)",
|
|
248
|
+
popover: "oklch(100% 0 0)",
|
|
249
|
+
popoverForeground: "oklch(32.57% 0.11612 325.04)",
|
|
250
|
+
primary: "oklch(53.16% 0.14089 355.2)",
|
|
251
|
+
primaryForeground: "oklch(100% 0 0)",
|
|
252
|
+
secondary: "oklch(86.96% 0.06751 334.9)",
|
|
253
|
+
secondaryForeground: "oklch(44.48% 0.13406 324.8)",
|
|
254
|
+
muted: "oklch(93.95% 0.02604 331.55)",
|
|
255
|
+
mutedForeground: "oklch(49.24% 0.12445 324.45)",
|
|
256
|
+
accent: "oklch(86.96% 0.06751 334.9)",
|
|
257
|
+
accentForeground: "oklch(44.48% 0.13406 324.8)",
|
|
258
|
+
destructive: "oklch(52.48% 0.13678 20.83)",
|
|
259
|
+
destructiveForeground: "oklch(100% 0 0)",
|
|
260
|
+
border: "oklch(85.68% 0.08288 328.91)",
|
|
261
|
+
input: "oklch(85.17% 0.05582 336.6)",
|
|
262
|
+
ring: "oklch(59.16% 0.21798 0.58)",
|
|
263
|
+
chart1: "oklch(60.38% 0.23628 344.47)",
|
|
264
|
+
chart2: "oklch(44.45% 0.22507 300.62)",
|
|
265
|
+
chart3: "oklch(37.9% 0.04376 226.15)",
|
|
266
|
+
chart4: "oklch(83.3% 0.11852 88.35)",
|
|
267
|
+
chart5: "oklch(78.43% 0.12563 59)",
|
|
268
|
+
sidebar: "oklch(93.6% 0.02881 320.58)",
|
|
269
|
+
sidebarForeground: "oklch(49.48% 0.19094 354.54)",
|
|
270
|
+
sidebarPrimary: "oklch(39.63% 0.02513 285.2)",
|
|
271
|
+
sidebarPrimaryForeground: "oklch(96.68% 0.01243 337.52)",
|
|
272
|
+
sidebarAccent: "oklch(97.89% 0.00132 106.42)",
|
|
273
|
+
sidebarAccentForeground: "oklch(39.63% 0.02513 285.2)",
|
|
274
|
+
sidebarBorder: "oklch(93.83% 0.00255 48.72)",
|
|
275
|
+
sidebarRing: "oklch(59.16% 0.21798 0.58)",
|
|
276
|
+
},
|
|
277
|
+
dark: {
|
|
278
|
+
background: "oklch(24.09% 0.0201 307.53)",
|
|
279
|
+
foreground: "oklch(83.98% 0.03874 309.54)",
|
|
280
|
+
card: "oklch(28.03% 0.02323 307.54)",
|
|
281
|
+
cardForeground: "oklch(84.56% 0.03016 341.46)",
|
|
282
|
+
popover: "oklch(15.48% 0.01316 338.9)",
|
|
283
|
+
popoverForeground: "oklch(96.47% 0.00914 341.8)",
|
|
284
|
+
primary: "oklch(46.07% 0.18535 4.1)",
|
|
285
|
+
primaryForeground: "oklch(85.6% 0.06185 346.37)",
|
|
286
|
+
secondary: "oklch(31.37% 0.03057 310.06)",
|
|
287
|
+
secondaryForeground: "oklch(84.83% 0.03825 307.96)",
|
|
288
|
+
muted: "oklch(26.34% 0.02189 309.47)",
|
|
289
|
+
mutedForeground: "oklch(79.4% 0.0372 307.1)",
|
|
290
|
+
accent: "oklch(36.49% 0.05079 308.49)",
|
|
291
|
+
accentForeground: "oklch(96.47% 0.00914 341.8)",
|
|
292
|
+
destructive: "oklch(22.58% 0.05243 12.61)",
|
|
293
|
+
destructiveForeground: "oklch(100% 0 0)",
|
|
294
|
+
border: "oklch(32.86% 0.01535 343.45)",
|
|
295
|
+
input: "oklch(33.87% 0.0195 332.83)",
|
|
296
|
+
ring: "oklch(59.16% 0.21798 0.58)",
|
|
297
|
+
chart1: "oklch(53.16% 0.14089 355.2)",
|
|
298
|
+
chart2: "oklch(56.33% 0.19123 306.86)",
|
|
299
|
+
chart3: "oklch(72.27% 0.1502 60.58)",
|
|
300
|
+
chart4: "oklch(61.93% 0.20294 312.74)",
|
|
301
|
+
chart5: "oklch(61.18% 0.2093 6.14)",
|
|
302
|
+
sidebar: "oklch(18.93% 0.01632 331.05)",
|
|
303
|
+
sidebarForeground: "oklch(86.07% 0.02927 343.66)",
|
|
304
|
+
sidebarPrimary: "oklch(48.82% 0.21717 264.38)",
|
|
305
|
+
sidebarPrimaryForeground: "oklch(100% 0 0)",
|
|
306
|
+
sidebarAccent: "oklch(23.37% 0.02608 338.2)",
|
|
307
|
+
sidebarAccentForeground: "oklch(96.74% 0.00133 286.38)",
|
|
308
|
+
sidebarBorder: "oklch(0% 0 0)",
|
|
309
|
+
sidebarRing: "oklch(59.16% 0.21798 0.58)",
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Initialize a fresh scaffold with a complete marketing site: the 4 theme
|
|
316
|
+
* presets ("Stark × Ember" active by default), site settings, a header, a
|
|
317
|
+
* footer, and a fully assembled home page built from every block's shipped
|
|
318
|
+
* defaults.
|
|
8
319
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
320
|
+
* Safe to run repeatedly — every insert is guarded by an existence check
|
|
321
|
+
* keyed on a natural identifier (theme/header/footer name, page slug, or the
|
|
322
|
+
* `siteSettings` singleton), so re-running after hand-edits in the admin
|
|
323
|
+
* panel never duplicates or clobbers them.
|
|
13
324
|
*
|
|
14
|
-
*
|
|
325
|
+
* Run from terminal: `npx convex run seed:init`
|
|
15
326
|
*/
|
|
16
327
|
export const init = internalMutation({
|
|
17
328
|
args: {},
|
|
@@ -19,44 +330,69 @@ export const init = internalMutation({
|
|
|
19
330
|
const created: string[] = []
|
|
20
331
|
const skipped: string[] = []
|
|
21
332
|
|
|
22
|
-
|
|
23
|
-
const
|
|
333
|
+
let activeThemeId: string | null = null
|
|
334
|
+
for (const preset of THEME_PRESETS) {
|
|
335
|
+
const existing = await ctx.db
|
|
336
|
+
.query(TABLE_SLUG_THEMES)
|
|
337
|
+
.withIndex("by_name", (q) => q.eq("name", preset.name))
|
|
338
|
+
.first()
|
|
339
|
+
if (existing) {
|
|
340
|
+
skipped.push(`theme:${preset.name}`)
|
|
341
|
+
if (preset.name === "Stark × Ember") activeThemeId = existing._id
|
|
342
|
+
continue
|
|
343
|
+
}
|
|
344
|
+
const id = await ctx.db.insert(TABLE_SLUG_THEMES, preset)
|
|
345
|
+
created.push(`theme:${preset.name}`)
|
|
346
|
+
if (preset.name === "Stark × Ember") activeThemeId = id
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const existingSettings = await getGlobal({
|
|
350
|
+
ctx,
|
|
351
|
+
config,
|
|
352
|
+
slug: GLOBAL_SLUG_SITE_SETTINGS,
|
|
353
|
+
access: { bypass: true },
|
|
354
|
+
})
|
|
24
355
|
if (existingSettings) {
|
|
25
|
-
skipped.push("
|
|
356
|
+
skipped.push("siteSettings")
|
|
26
357
|
} else {
|
|
27
|
-
await
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
358
|
+
await upsertGlobal({
|
|
359
|
+
ctx,
|
|
360
|
+
config,
|
|
361
|
+
slug: GLOBAL_SLUG_SITE_SETTINGS,
|
|
362
|
+
data: {
|
|
363
|
+
name: "My Site",
|
|
364
|
+
description: "Built with Vex CMS.",
|
|
365
|
+
activeTheme: activeThemeId ? [activeThemeId] : [],
|
|
366
|
+
},
|
|
367
|
+
access: { bypass: true },
|
|
32
368
|
})
|
|
33
|
-
created.push("
|
|
369
|
+
created.push("siteSettings")
|
|
34
370
|
}
|
|
35
371
|
|
|
36
|
-
// Default Header
|
|
37
372
|
const existingHeader = await ctx.db
|
|
38
|
-
.query(
|
|
373
|
+
.query(TABLE_SLUG_HEADERS)
|
|
39
374
|
.withIndex("by_name", (q) => q.eq("name", "Main Header"))
|
|
40
375
|
.first()
|
|
41
376
|
if (existingHeader) {
|
|
42
377
|
skipped.push("header")
|
|
43
378
|
} else {
|
|
44
|
-
await ctx.db.insert(
|
|
379
|
+
await ctx.db.insert(TABLE_SLUG_HEADERS, {
|
|
45
380
|
name: "Main Header",
|
|
46
|
-
vex_status: "published",
|
|
47
381
|
content: [
|
|
48
382
|
{
|
|
49
383
|
blockType: "header",
|
|
50
384
|
blockName: "Site Header",
|
|
51
|
-
|
|
385
|
+
id: "main-header",
|
|
52
386
|
logoText: "My Site",
|
|
53
387
|
logoHref: "/",
|
|
54
388
|
menuItems: [
|
|
55
389
|
{ label: "Features", href: "/features" },
|
|
390
|
+
{ label: "Roadmap", href: "/roadmap" },
|
|
56
391
|
{ label: "Docs", href: "/docs" },
|
|
57
392
|
],
|
|
58
393
|
actionButtons: [
|
|
59
|
-
{ label: "
|
|
394
|
+
{ label: "GitHub", href: "https://github.com/vexcms/vex", variant: ["ghost"] },
|
|
395
|
+
{ label: "Get Started", href: "/docs", variant: ["default"] },
|
|
60
396
|
],
|
|
61
397
|
},
|
|
62
398
|
],
|
|
@@ -64,38 +400,249 @@ export const init = internalMutation({
|
|
|
64
400
|
created.push("header")
|
|
65
401
|
}
|
|
66
402
|
|
|
67
|
-
// Default Footer
|
|
68
403
|
const existingFooter = await ctx.db
|
|
69
|
-
.query(
|
|
404
|
+
.query(TABLE_SLUG_FOOTERS)
|
|
70
405
|
.withIndex("by_name", (q) => q.eq("name", "Main Footer"))
|
|
71
406
|
.first()
|
|
72
407
|
if (existingFooter) {
|
|
73
408
|
skipped.push("footer")
|
|
74
409
|
} else {
|
|
75
|
-
await ctx.db.insert(
|
|
410
|
+
await ctx.db.insert(TABLE_SLUG_FOOTERS, {
|
|
76
411
|
name: "Main Footer",
|
|
77
|
-
vex_status: "published",
|
|
78
412
|
content: [
|
|
79
413
|
{
|
|
80
414
|
blockType: "footer",
|
|
81
415
|
blockName: "Site Footer",
|
|
82
|
-
|
|
416
|
+
id: "main-footer",
|
|
83
417
|
logoText: "My Site",
|
|
84
418
|
copyright: "My Site. All rights reserved.",
|
|
85
419
|
links: [
|
|
86
|
-
{ label: "
|
|
420
|
+
{ label: "Features", href: "/features" },
|
|
421
|
+
{ label: "Roadmap", href: "/roadmap" },
|
|
422
|
+
{ label: "Documentation", href: "/docs" },
|
|
87
423
|
],
|
|
88
|
-
socialLinks: [],
|
|
424
|
+
socialLinks: [{ platform: "GitHub", href: "https://github.com/vexcms/vex", icon: "Github" }],
|
|
89
425
|
},
|
|
90
426
|
],
|
|
91
427
|
})
|
|
92
428
|
created.push("footer")
|
|
93
429
|
}
|
|
94
430
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
431
|
+
const existingHome = await ctx.db
|
|
432
|
+
.query(TABLE_SLUG_PAGES)
|
|
433
|
+
.withIndex("by_slug", (q) => q.eq("slug", "home"))
|
|
434
|
+
.first()
|
|
435
|
+
if (existingHome) {
|
|
436
|
+
skipped.push("page:home")
|
|
437
|
+
} else {
|
|
438
|
+
await ctx.db.insert(TABLE_SLUG_PAGES, {
|
|
439
|
+
title: "Home",
|
|
440
|
+
slug: "home",
|
|
441
|
+
blocks: [
|
|
442
|
+
{
|
|
443
|
+
blockType: "hero",
|
|
444
|
+
blockName: "Hero",
|
|
445
|
+
id: "home-hero",
|
|
446
|
+
badgeText: "Now in public beta",
|
|
447
|
+
badgeLink: "/docs",
|
|
448
|
+
heading: "The CMS built for Convex",
|
|
449
|
+
subheading:
|
|
450
|
+
"Vex CMS gives you a full-featured content management system powered by Convex — real-time data, type-safe schemas, and a beautiful admin panel out of the box.",
|
|
451
|
+
primaryCtaLabel: "Get Started",
|
|
452
|
+
primaryCtaHref: "/docs",
|
|
453
|
+
secondaryCtaLabel: "View on GitHub",
|
|
454
|
+
secondaryCtaHref: "https://github.com/vexcms/vex",
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
blockType: "features",
|
|
458
|
+
blockName: "Features",
|
|
459
|
+
id: "home-features",
|
|
460
|
+
heading: "Everything you need to manage content",
|
|
461
|
+
subheading:
|
|
462
|
+
"Built on Convex's real-time infrastructure with a developer experience that doesn't compromise on power.",
|
|
463
|
+
features: [
|
|
464
|
+
{
|
|
465
|
+
title: "Real-Time by Default",
|
|
466
|
+
description:
|
|
467
|
+
"Every query is live. Content updates appear instantly across all connected clients — no polling, no webhooks.",
|
|
468
|
+
icon: "Zap",
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
title: "Type-Safe Schemas",
|
|
472
|
+
description:
|
|
473
|
+
"Define your collections with TypeScript. Vex generates Convex schemas, Zod validators, and typed queries automatically.",
|
|
474
|
+
icon: "Shield",
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
title: "Developer First",
|
|
478
|
+
description:
|
|
479
|
+
"Code-first configuration, CLI tooling, and a clean API. Build with the tools you already know and love.",
|
|
480
|
+
icon: "Code",
|
|
481
|
+
},
|
|
482
|
+
],
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
blockType: "how_it_works",
|
|
486
|
+
blockName: "How It Works",
|
|
487
|
+
id: "home-how-it-works",
|
|
488
|
+
heading: "Get started in minutes",
|
|
489
|
+
subheading: "From zero to a fully functional CMS in four steps. No boilerplate, no config files to wrestle with.",
|
|
490
|
+
steps: [
|
|
491
|
+
{
|
|
492
|
+
icon: "Terminal",
|
|
493
|
+
title: "Scaffold your project",
|
|
494
|
+
description:
|
|
495
|
+
"Run npx create-vexcms@latest to get a Next.js app with Convex, authentication, and the admin panel pre-configured.",
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
icon: "Code",
|
|
499
|
+
title: "Define your schema",
|
|
500
|
+
description:
|
|
501
|
+
"Use defineCollection() and field helpers to declare your content model in TypeScript. Vex generates your Convex schema, types, and queries automatically.",
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
icon: "LayoutGrid",
|
|
505
|
+
title: "Build with blocks",
|
|
506
|
+
description:
|
|
507
|
+
"Compose pages from reusable content blocks. Each block is a React component with a typed config — drag, drop, and edit inline from the admin panel.",
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
icon: "Rocket",
|
|
511
|
+
title: "Deploy and go live",
|
|
512
|
+
description:
|
|
513
|
+
"Push to Convex and deploy your Next.js app. Real-time content updates flow to every connected client instantly.",
|
|
514
|
+
},
|
|
515
|
+
],
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
blockType: "roadmap",
|
|
519
|
+
blockName: "Roadmap",
|
|
520
|
+
id: "home-roadmap",
|
|
521
|
+
heading: "Roadmap",
|
|
522
|
+
subheading:
|
|
523
|
+
"What we've shipped and what's coming next. Vex CMS is actively developed — here's where we're headed.",
|
|
524
|
+
items: [
|
|
525
|
+
{
|
|
526
|
+
feature: "12 Field Types",
|
|
527
|
+
description:
|
|
528
|
+
"text, url, color, number, checkbox, date, select, relationship, array, group, blocks, and upload — no richtext, json, or tabs yet.",
|
|
529
|
+
status: ["shipped"],
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
feature: "Convex Schema Codegen",
|
|
533
|
+
description:
|
|
534
|
+
"vex dev / vex generate write your Convex schema, TypeScript types, and Zod validators from defineCollection() — no hand-written schema.ts.",
|
|
535
|
+
status: ["shipped"],
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
feature: "Real-Time Admin Panel",
|
|
539
|
+
description:
|
|
540
|
+
"DataTable with pagination, live totalDocs, and bulk operations — every list view is a Convex subscription.",
|
|
541
|
+
status: ["shipped"],
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
feature: "Media Library",
|
|
545
|
+
description:
|
|
546
|
+
"Convex file storage adapter with a searchable, paginated media picker built into every upload field.",
|
|
547
|
+
status: ["shipped"],
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
feature: "RBAC & Access Control",
|
|
551
|
+
description:
|
|
552
|
+
"Document-level access rules, indexed constraints that compile to withIndex ranges, per-call access.action/bypass overrides, and an anonRole fallback for public reads.",
|
|
553
|
+
status: ["shipped"],
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
feature: "Custom Theme System",
|
|
557
|
+
description:
|
|
558
|
+
"Database-driven themes with light/dark mode, 32 shadcn tokens per mode, and OKLCH color support — live-updates with zero page reload.",
|
|
559
|
+
status: ["shipped"],
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
feature: "Better Auth Integration",
|
|
563
|
+
description: "Email/password and OAuth out of the box, with organizations and API keys as opt-in plugins.",
|
|
564
|
+
status: ["shipped"],
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
feature: "CLI & Scaffolder",
|
|
568
|
+
description:
|
|
569
|
+
"vex dev, vex generate, and create-vexcms for instant project setup — bare or full marketing-site templates.",
|
|
570
|
+
status: ["shipped"],
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
feature: "Versioning & Drafts",
|
|
574
|
+
description: "Draft/publish workflow with live preview — in active development.",
|
|
575
|
+
status: ["coming-soon"],
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
feature: "Richtext, JSON, Email & Textarea Fields",
|
|
579
|
+
description: "Plate.js-powered rich text, plus structured JSON, email, and multi-line text inputs.",
|
|
580
|
+
status: ["planned"],
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
feature: "Form Builder & Lifecycle Hooks",
|
|
584
|
+
description:
|
|
585
|
+
"Composable form fields beyond content editing, plus beforeChange/afterChange hooks for custom side effects.",
|
|
586
|
+
status: ["planned"],
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
feature: "Team Management & API Keys",
|
|
590
|
+
description: "Invite users, assign roles, and issue scoped read-only API tokens for external integrations.",
|
|
591
|
+
status: ["planned"],
|
|
592
|
+
},
|
|
593
|
+
],
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
blockType: "faq",
|
|
597
|
+
blockName: "FAQ",
|
|
598
|
+
id: "home-faq",
|
|
599
|
+
heading: "Frequently Asked Questions",
|
|
600
|
+
subheading: "Everything you need to know about Vex CMS and building with Convex.",
|
|
601
|
+
supportLink: "https://github.com/vexcms/vex/issues",
|
|
602
|
+
items: [
|
|
603
|
+
{
|
|
604
|
+
question: "What is Vex CMS?",
|
|
605
|
+
answer:
|
|
606
|
+
"Vex CMS is a headless content management system built on Convex. It provides real-time data, type-safe schemas, RBAC, and a beautiful admin panel — all configured with TypeScript.",
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
question: "How is Vex different from other headless CMS platforms?",
|
|
610
|
+
answer:
|
|
611
|
+
"Vex is powered by Convex's real-time database, so content updates are instant across all clients — no polling, no webhooks. Your schema is defined in code, giving you full type safety from database to frontend.",
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
question: "Do I need to know Convex to use Vex CMS?",
|
|
615
|
+
answer:
|
|
616
|
+
"Basic familiarity helps, but Vex handles most of the complexity for you. The CLI generates your Convex schema, queries, and types automatically from your collection definitions.",
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
question: "Is Vex CMS free?",
|
|
620
|
+
answer:
|
|
621
|
+
"Yes — Vex CMS is open source and free to use. You only pay for your Convex usage, which has a generous free tier for most projects.",
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
question: "How do I get started?",
|
|
625
|
+
answer:
|
|
626
|
+
"Run npx create-vexcms@latest to scaffold a new project with Vex CMS pre-configured — Next.js app, Convex backend, authentication, and admin panel in under a minute.",
|
|
627
|
+
},
|
|
628
|
+
],
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
blockType: "cta",
|
|
632
|
+
blockName: "CTA",
|
|
633
|
+
id: "home-cta",
|
|
634
|
+
heading: "Ready to build with Vex CMS?",
|
|
635
|
+
subheading: "Get started in minutes with create-vexcms. Real-time content management powered by Convex.",
|
|
636
|
+
actions: [
|
|
637
|
+
{ label: "Get Started", href: "/docs" },
|
|
638
|
+
{ label: "View on GitHub", href: "https://github.com/vexcms/vex" },
|
|
639
|
+
],
|
|
640
|
+
},
|
|
641
|
+
],
|
|
642
|
+
})
|
|
643
|
+
created.push("page:home")
|
|
99
644
|
}
|
|
645
|
+
|
|
646
|
+
return { created, skipped }
|
|
100
647
|
},
|
|
101
648
|
})
|