create-vexcms 0.0.19 → 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 -22
- 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 +98 -11
- 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/components/motion-primitives/animated-group.tsx +2 -2
- 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 -321
- 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,4 +1,4 @@
|
|
|
1
|
-
import type { BlockComponentProps } from "@vexcms/
|
|
1
|
+
import type { BlockComponentProps } from "@vexcms/react"
|
|
2
2
|
|
|
3
3
|
import Link from "next/link"
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
AccordionContent,
|
|
8
8
|
AccordionItem,
|
|
9
9
|
AccordionTrigger,
|
|
10
|
-
} from "
|
|
10
|
+
} from "@vexcms/react"
|
|
11
11
|
|
|
12
12
|
export { faqBlock } from "./config"
|
|
13
13
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { array, defineBlock,
|
|
1
|
+
import { array, defineBlock, group, text } from "@vexcms/core"
|
|
2
2
|
|
|
3
|
-
import IconPickerField from "~/components/admin/IconPickerField"
|
|
4
3
|
import { BLOCK_SLUG_FEATURES } from "../constants"
|
|
5
4
|
|
|
6
5
|
export const featuresBlock = defineBlock({
|
|
@@ -20,16 +19,13 @@ export const featuresBlock = defineBlock({
|
|
|
20
19
|
features: array({
|
|
21
20
|
label: "Features",
|
|
22
21
|
required: true,
|
|
23
|
-
items:
|
|
22
|
+
items: group({
|
|
24
23
|
fields: {
|
|
25
24
|
title: text({ label: "Title", required: true }),
|
|
26
25
|
description: text({ label: "Description", required: true }),
|
|
27
26
|
icon: text({
|
|
28
27
|
label: "Icon",
|
|
29
|
-
|
|
30
|
-
description: "Lucide icon name",
|
|
31
|
-
components: { Field: IconPickerField },
|
|
32
|
-
},
|
|
28
|
+
description: "Lucide icon name",
|
|
33
29
|
}),
|
|
34
30
|
},
|
|
35
31
|
}),
|
|
@@ -56,6 +52,6 @@ export const featuresBlock = defineBlock({
|
|
|
56
52
|
}),
|
|
57
53
|
},
|
|
58
54
|
admin: {
|
|
59
|
-
icon: "
|
|
55
|
+
icon: "LayoutGrid",
|
|
60
56
|
},
|
|
61
57
|
})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { BlockComponentProps } from "@vexcms/
|
|
1
|
+
import type { BlockComponentProps } from "@vexcms/react"
|
|
2
2
|
import type { ComponentPropsWithRef } from "react"
|
|
3
3
|
|
|
4
4
|
import { icons } from "lucide-react"
|
|
5
5
|
|
|
6
|
-
import { Card, CardContent, CardHeader } from "
|
|
6
|
+
import { Card, CardContent, CardHeader } from "@vexcms/react"
|
|
7
7
|
|
|
8
8
|
export { featuresBlock } from "./config"
|
|
9
9
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { array, defineBlock,
|
|
1
|
+
import { array, defineBlock, group, text, upload } from "@vexcms/core"
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import { TABLE_SLUG_MEDIA } from "~/db/constants"
|
|
3
|
+
import { TABLE_SLUG_IMAGES } from "~/db/constants"
|
|
5
4
|
import { BLOCK_SLUG_FOOTER } from "../constants"
|
|
6
5
|
|
|
7
6
|
export const footerBlock = defineBlock({
|
|
@@ -14,7 +13,7 @@ export const footerBlock = defineBlock({
|
|
|
14
13
|
}),
|
|
15
14
|
logoImage: upload({
|
|
16
15
|
label: "Logo Image",
|
|
17
|
-
to:
|
|
16
|
+
to: TABLE_SLUG_IMAGES,
|
|
18
17
|
}),
|
|
19
18
|
copyright: text({
|
|
20
19
|
label: "Copyright Text",
|
|
@@ -22,7 +21,7 @@ export const footerBlock = defineBlock({
|
|
|
22
21
|
}),
|
|
23
22
|
links: array({
|
|
24
23
|
label: "Links",
|
|
25
|
-
items:
|
|
24
|
+
items: group({
|
|
26
25
|
fields: {
|
|
27
26
|
label: text({ label: "Label", required: true }),
|
|
28
27
|
href: text({ label: "Link", required: true }),
|
|
@@ -40,16 +39,13 @@ export const footerBlock = defineBlock({
|
|
|
40
39
|
}),
|
|
41
40
|
socialLinks: array({
|
|
42
41
|
label: "Social Links",
|
|
43
|
-
items:
|
|
42
|
+
items: group({
|
|
44
43
|
fields: {
|
|
45
44
|
platform: text({ label: "Platform", required: true }),
|
|
46
45
|
href: text({ label: "URL", required: true }),
|
|
47
46
|
icon: text({
|
|
48
47
|
label: "Icon",
|
|
49
|
-
|
|
50
|
-
description: "Lucide icon name",
|
|
51
|
-
components: { Field: IconPickerField },
|
|
52
|
-
},
|
|
48
|
+
description: "Lucide icon name",
|
|
53
49
|
}),
|
|
54
50
|
},
|
|
55
51
|
}),
|
|
@@ -60,6 +56,6 @@ export const footerBlock = defineBlock({
|
|
|
60
56
|
}),
|
|
61
57
|
},
|
|
62
58
|
admin: {
|
|
63
|
-
icon: "
|
|
59
|
+
icon: "PanelBottom",
|
|
64
60
|
},
|
|
65
61
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { array, defineBlock,
|
|
1
|
+
import { array, defineBlock, group, select, text, upload } from "@vexcms/core"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { TABLE_SLUG_IMAGES } from "~/db/constants"
|
|
4
4
|
import { BLOCK_SLUG_HEADER } from "../constants"
|
|
5
5
|
|
|
6
6
|
export const headerBlock = defineBlock({
|
|
@@ -10,12 +10,12 @@ export const headerBlock = defineBlock({
|
|
|
10
10
|
logoText: text({
|
|
11
11
|
label: "Logo Text",
|
|
12
12
|
defaultValue: "Vex CMS",
|
|
13
|
-
|
|
13
|
+
description: "Text to display as the logo",
|
|
14
14
|
}),
|
|
15
15
|
logoImage: upload({
|
|
16
16
|
label: "Logo Image",
|
|
17
|
-
to:
|
|
18
|
-
|
|
17
|
+
to: TABLE_SLUG_IMAGES,
|
|
18
|
+
description: "Image to display as the logo (overrides text)",
|
|
19
19
|
}),
|
|
20
20
|
logoHref: text({
|
|
21
21
|
label: "Logo Link",
|
|
@@ -23,7 +23,7 @@ export const headerBlock = defineBlock({
|
|
|
23
23
|
}),
|
|
24
24
|
menuItems: array({
|
|
25
25
|
label: "Menu Items",
|
|
26
|
-
items:
|
|
26
|
+
items: group({
|
|
27
27
|
fields: {
|
|
28
28
|
label: text({ label: "Label", required: true }),
|
|
29
29
|
href: text({ label: "Link", required: true }),
|
|
@@ -38,7 +38,7 @@ export const headerBlock = defineBlock({
|
|
|
38
38
|
}),
|
|
39
39
|
actionButtons: array({
|
|
40
40
|
label: "Action Buttons",
|
|
41
|
-
items:
|
|
41
|
+
items: group({
|
|
42
42
|
fields: {
|
|
43
43
|
label: text({ label: "Button Label", required: true }),
|
|
44
44
|
href: text({ label: "Button Link", required: true }),
|
|
@@ -49,7 +49,7 @@ export const headerBlock = defineBlock({
|
|
|
49
49
|
{ label: "Outline", value: "outline" },
|
|
50
50
|
{ label: "Ghost", value: "ghost" },
|
|
51
51
|
],
|
|
52
|
-
defaultValue: "default",
|
|
52
|
+
defaultValue: ["default"],
|
|
53
53
|
}),
|
|
54
54
|
},
|
|
55
55
|
}),
|
|
@@ -60,6 +60,6 @@ export const headerBlock = defineBlock({
|
|
|
60
60
|
}),
|
|
61
61
|
},
|
|
62
62
|
admin: {
|
|
63
|
-
icon: "
|
|
63
|
+
icon: "PanelTop",
|
|
64
64
|
},
|
|
65
65
|
})
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import type { BlockComponentProps } from "@vexcms/
|
|
3
|
+
import type { BlockComponentProps } from "@vexcms/react"
|
|
4
4
|
|
|
5
5
|
import { Menu, Settings, X } from "lucide-react"
|
|
6
6
|
import Link from "next/link"
|
|
7
7
|
import { useEffect, useState } from "react"
|
|
8
8
|
|
|
9
9
|
import { useSession } from "~/auth/client"
|
|
10
|
-
import { cn } from "
|
|
11
|
-
import { buttonVariants } from "~/components/ui/button"
|
|
10
|
+
import { cn, buttonVariants } from "@vexcms/react"
|
|
12
11
|
|
|
13
12
|
export { headerBlock } from "./config"
|
|
14
13
|
|
|
@@ -27,8 +26,8 @@ export default function HeaderBlock({ block }: BlockComponentProps) {
|
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
const { data: session } = useSession()
|
|
30
|
-
const
|
|
31
|
-
|
|
29
|
+
const role = session?.user?.role
|
|
30
|
+
const isAdmin = role === "admin" || (Array.isArray(role) && role.includes("admin"))
|
|
32
31
|
|
|
33
32
|
const [menuState, setMenuState] = useState(false)
|
|
34
33
|
const [isScrolled, setIsScrolled] = useState(false)
|
|
@@ -9,12 +9,12 @@ export const heroBlock = defineBlock({
|
|
|
9
9
|
badgeText: text({
|
|
10
10
|
label: "Badge Text",
|
|
11
11
|
defaultValue: "Now in public beta",
|
|
12
|
-
|
|
12
|
+
description: "Small text shown in the announcement badge",
|
|
13
13
|
}),
|
|
14
14
|
badgeLink: text({
|
|
15
15
|
label: "Badge Link",
|
|
16
16
|
defaultValue: "/docs",
|
|
17
|
-
|
|
17
|
+
description: "URL the badge links to",
|
|
18
18
|
}),
|
|
19
19
|
heading: text({
|
|
20
20
|
label: "Heading",
|
|
@@ -46,7 +46,6 @@ export const heroBlock = defineBlock({
|
|
|
46
46
|
}),
|
|
47
47
|
},
|
|
48
48
|
admin: {
|
|
49
|
-
icon: "
|
|
50
|
-
blockStyles: ["container", "text"],
|
|
49
|
+
icon: "Sparkles",
|
|
51
50
|
},
|
|
52
51
|
})
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import type { BlockComponentProps } from "@vexcms/
|
|
3
|
+
import type { BlockComponentProps } from "@vexcms/react"
|
|
4
4
|
|
|
5
5
|
import { ArrowRight } from "lucide-react"
|
|
6
6
|
import Link from "next/link"
|
|
7
|
+
import { buttonVariants, cn } from "@vexcms/react"
|
|
7
8
|
|
|
8
|
-
import { cn } from "~/lib/utils"
|
|
9
9
|
import { AnimatedGroup } from "~/components/motion-primitives/animated-group"
|
|
10
10
|
import { TextEffect } from "~/components/motion-primitives/text-effect"
|
|
11
|
-
import { buttonVariants } from "~/components/ui/button"
|
|
12
11
|
|
|
13
12
|
export { heroBlock } from "./config"
|
|
14
13
|
|
|
@@ -32,7 +31,7 @@ const transitionVariants = {
|
|
|
32
31
|
},
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
export default function HeroBlock({ block
|
|
34
|
+
export default function HeroBlock({ block }: BlockComponentProps) {
|
|
36
35
|
const {
|
|
37
36
|
badgeText,
|
|
38
37
|
badgeLink,
|
|
@@ -42,10 +41,10 @@ export default function HeroBlock({ block, blockStyles }: BlockComponentProps) {
|
|
|
42
41
|
primaryCtaHref,
|
|
43
42
|
secondaryCtaLabel,
|
|
44
43
|
secondaryCtaHref,
|
|
45
|
-
} = block as Record<string, string>
|
|
44
|
+
} = block as unknown as Record<string, string>
|
|
46
45
|
|
|
47
46
|
return (
|
|
48
|
-
<div className=
|
|
47
|
+
<div className="overflow-hidden">
|
|
49
48
|
<div
|
|
50
49
|
aria-hidden
|
|
51
50
|
className="absolute inset-0 isolate hidden opacity-65 contain-strict lg:block"
|
|
@@ -61,16 +60,14 @@ export default function HeroBlock({ block, blockStyles }: BlockComponentProps) {
|
|
|
61
60
|
<div className="text-center sm:mx-auto lg:mr-auto">
|
|
62
61
|
{badgeText && badgeLink && (
|
|
63
62
|
<AnimatedGroup
|
|
64
|
-
// @ts-expect-error
|
|
63
|
+
// @ts-expect-error motion-primitives Variants type is stricter than the local transitionVariants shape
|
|
65
64
|
variants={transitionVariants}
|
|
66
65
|
>
|
|
67
66
|
<Link
|
|
68
67
|
className="hover:bg-background dark:hover:border-t-border bg-muted group mx-auto flex w-fit items-center gap-4 rounded-full border p-1 pl-4 shadow-md shadow-zinc-950/5 transition-colors duration-300 dark:border-t-white/5 dark:shadow-zinc-950"
|
|
69
68
|
href={badgeLink}
|
|
70
69
|
>
|
|
71
|
-
<span className="text-foreground text-sm">
|
|
72
|
-
{badgeText}
|
|
73
|
-
</span>
|
|
70
|
+
<span className="text-foreground text-sm">{badgeText}</span>
|
|
74
71
|
<span className="dark:border-background block h-4 w-0.5 border-l bg-white dark:bg-zinc-700" />
|
|
75
72
|
<div className="bg-background group-hover:bg-muted size-6 overflow-hidden rounded-full duration-500">
|
|
76
73
|
<div className="flex w-12 -translate-x-1/2 duration-500 ease-in-out group-hover:translate-x-0">
|
|
@@ -107,7 +104,7 @@ export default function HeroBlock({ block, blockStyles }: BlockComponentProps) {
|
|
|
107
104
|
|
|
108
105
|
<AnimatedGroup
|
|
109
106
|
className="mt-12 flex flex-col items-center justify-center gap-2 md:flex-row"
|
|
110
|
-
// @ts-expect-error
|
|
107
|
+
// @ts-expect-error motion-primitives Variants type is stricter than the local transitionVariants shape
|
|
111
108
|
variants={{
|
|
112
109
|
container: {
|
|
113
110
|
visible: {
|
|
@@ -123,10 +120,7 @@ export default function HeroBlock({ block, blockStyles }: BlockComponentProps) {
|
|
|
123
120
|
<div className="bg-foreground/10 rounded-[calc(var(--radius-xl)+0.125rem)] border p-0.5">
|
|
124
121
|
<Link
|
|
125
122
|
href={primaryCtaHref ?? "/"}
|
|
126
|
-
className={cn(
|
|
127
|
-
buttonVariants({ size: "lg" }),
|
|
128
|
-
"rounded-xl px-5 text-base"
|
|
129
|
-
)}
|
|
123
|
+
className={cn(buttonVariants({ size: "lg" }), "rounded-xl px-5 text-base")}
|
|
130
124
|
>
|
|
131
125
|
<span className="text-nowrap">{primaryCtaLabel}</span>
|
|
132
126
|
</Link>
|
|
@@ -134,10 +128,7 @@ export default function HeroBlock({ block, blockStyles }: BlockComponentProps) {
|
|
|
134
128
|
{secondaryCtaLabel && (
|
|
135
129
|
<Link
|
|
136
130
|
href={secondaryCtaHref ?? "/"}
|
|
137
|
-
className={cn(
|
|
138
|
-
buttonVariants({ variant: "ghost", size: "lg" }),
|
|
139
|
-
"h-10.5 rounded-xl px-5"
|
|
140
|
-
)}
|
|
131
|
+
className={cn(buttonVariants({ variant: "ghost", size: "lg" }), "h-10.5 rounded-xl px-5")}
|
|
141
132
|
>
|
|
142
133
|
<span className="text-nowrap">{secondaryCtaLabel}</span>
|
|
143
134
|
</Link>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { array, defineBlock,
|
|
1
|
+
import { array, defineBlock, group, text } from "@vexcms/core"
|
|
2
2
|
|
|
3
|
-
import IconPickerField from "~/components/admin/IconPickerField"
|
|
4
3
|
import { BLOCK_SLUG_HOW_IT_WORKS } from "../constants"
|
|
5
4
|
|
|
6
5
|
export const howItWorksBlock = defineBlock({
|
|
@@ -20,14 +19,11 @@ export const howItWorksBlock = defineBlock({
|
|
|
20
19
|
steps: array({
|
|
21
20
|
label: "Steps",
|
|
22
21
|
required: true,
|
|
23
|
-
items:
|
|
22
|
+
items: group({
|
|
24
23
|
fields: {
|
|
25
24
|
icon: text({
|
|
26
25
|
label: "Icon",
|
|
27
|
-
|
|
28
|
-
description: "Lucide icon name",
|
|
29
|
-
components: { Field: IconPickerField },
|
|
30
|
-
},
|
|
26
|
+
description: "Lucide icon name",
|
|
31
27
|
}),
|
|
32
28
|
title: text({ label: "Title", required: true }),
|
|
33
29
|
description: text({ label: "Description", required: true }),
|
|
@@ -62,7 +58,6 @@ export const howItWorksBlock = defineBlock({
|
|
|
62
58
|
}),
|
|
63
59
|
},
|
|
64
60
|
admin: {
|
|
65
|
-
icon: "
|
|
66
|
-
blockStyles: ["container", "text"],
|
|
61
|
+
icon: "ListOrdered",
|
|
67
62
|
},
|
|
68
63
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import type { BlockComponentProps } from "@vexcms/
|
|
3
|
+
import type { BlockComponentProps } from "@vexcms/react"
|
|
4
4
|
|
|
5
5
|
import { icons } from "lucide-react"
|
|
6
6
|
|
|
@@ -14,10 +14,7 @@ function LucideIcon({ name }: { name: string }) {
|
|
|
14
14
|
return <Icon className="size-5" />
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export default function HowItWorksBlock({
|
|
18
|
-
block,
|
|
19
|
-
blockStyles,
|
|
20
|
-
}: BlockComponentProps) {
|
|
17
|
+
export default function HowItWorksBlock({ block }: BlockComponentProps) {
|
|
21
18
|
const { heading, subheading, steps } = block as unknown as {
|
|
22
19
|
heading: string
|
|
23
20
|
subheading?: string
|
|
@@ -25,7 +22,7 @@ export default function HowItWorksBlock({
|
|
|
25
22
|
}
|
|
26
23
|
|
|
27
24
|
return (
|
|
28
|
-
<section className=
|
|
25
|
+
<section className="py-16 md:py-32">
|
|
29
26
|
<div className="mx-auto max-w-3xl px-6">
|
|
30
27
|
<div className="text-center">
|
|
31
28
|
<h2 className="text-4xl font-semibold text-balance lg:text-5xl">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { array, defineBlock,
|
|
1
|
+
import { array, defineBlock, group, select, text } from "@vexcms/core"
|
|
2
2
|
|
|
3
3
|
import { BLOCK_SLUG_ROADMAP } from "../constants"
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ export const roadmapBlock = defineBlock({
|
|
|
19
19
|
items: array({
|
|
20
20
|
label: "Roadmap Items",
|
|
21
21
|
required: true,
|
|
22
|
-
items:
|
|
22
|
+
items: group({
|
|
23
23
|
fields: {
|
|
24
24
|
feature: text({ label: "Feature Name", required: true }),
|
|
25
25
|
description: text({ label: "Description" }),
|
|
@@ -31,124 +31,84 @@ export const roadmapBlock = defineBlock({
|
|
|
31
31
|
{ label: "Coming Soon", value: "coming-soon" },
|
|
32
32
|
{ label: "Planned", value: "planned" },
|
|
33
33
|
],
|
|
34
|
-
defaultValue: "shipped",
|
|
34
|
+
defaultValue: ["shipped"],
|
|
35
35
|
}),
|
|
36
36
|
},
|
|
37
37
|
}),
|
|
38
38
|
defaultValue: [
|
|
39
39
|
{
|
|
40
|
-
feature: "
|
|
40
|
+
feature: "12 Field Types",
|
|
41
41
|
description:
|
|
42
|
-
"
|
|
42
|
+
"text, url, color, number, checkbox, date, select, relationship, array, group, blocks, and upload — no richtext, json, or tabs yet.",
|
|
43
43
|
status: "shipped",
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
|
-
feature: "
|
|
46
|
+
feature: "Convex Schema Codegen",
|
|
47
47
|
description:
|
|
48
|
-
"
|
|
48
|
+
"vex dev / vex generate write your Convex schema, TypeScript types, and Zod validators from defineCollection() — no hand-written schema.ts.",
|
|
49
49
|
status: "shipped",
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
|
-
feature: "Real-Time
|
|
52
|
+
feature: "Real-Time Admin Panel",
|
|
53
53
|
description:
|
|
54
|
-
"
|
|
54
|
+
"DataTable with pagination, live totalDocs, and bulk operations — every list view is a Convex subscription.",
|
|
55
55
|
status: "shipped",
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
|
-
feature: "
|
|
58
|
+
feature: "Media Library",
|
|
59
59
|
description:
|
|
60
|
-
"
|
|
60
|
+
"Convex file storage adapter with a searchable, paginated media picker built into every upload field.",
|
|
61
61
|
status: "shipped",
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
|
-
feature: "
|
|
64
|
+
feature: "RBAC & Access Control",
|
|
65
65
|
description:
|
|
66
|
-
"
|
|
66
|
+
"Document-level access rules, indexed constraints that compile to withIndex ranges, per-call access.action/bypass overrides, and an anonRole fallback for public reads.",
|
|
67
67
|
status: "shipped",
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
|
-
feature: "
|
|
70
|
+
feature: "Custom Theme System",
|
|
71
71
|
description:
|
|
72
|
-
"
|
|
72
|
+
"Database-driven themes with light/dark mode, 32 shadcn tokens per mode, and OKLCH color support — live-updates with zero page reload.",
|
|
73
73
|
status: "shipped",
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
|
-
feature: "
|
|
76
|
+
feature: "Better Auth Integration",
|
|
77
77
|
description:
|
|
78
|
-
"
|
|
78
|
+
"Email/password and OAuth out of the box, with organizations and API keys as opt-in plugins.",
|
|
79
79
|
status: "shipped",
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
|
-
feature: "CLI &
|
|
82
|
+
feature: "CLI & Scaffolder",
|
|
83
83
|
description:
|
|
84
|
-
"vex dev
|
|
84
|
+
"vex dev, vex generate, and create-vexcms for instant project setup — bare or full marketing-site templates.",
|
|
85
85
|
status: "shipped",
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
|
-
feature: "
|
|
89
|
-
description:
|
|
90
|
-
"Database-driven themes with light/dark mode, CSS variables, and OKLCH color support.",
|
|
91
|
-
status: "shipped",
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
feature: "Block Styles",
|
|
95
|
-
description:
|
|
96
|
-
"Per-block responsive styling with Tailwind presets — margin, padding, typography, layout, and more.",
|
|
97
|
-
status: "shipped",
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
feature: "Content Scheduling",
|
|
101
|
-
description:
|
|
102
|
-
"Set a publishAt timestamp and content goes live automatically via Convex scheduled functions.",
|
|
88
|
+
feature: "Versioning & Drafts",
|
|
89
|
+
description: "Draft/publish workflow with live preview — in active development.",
|
|
103
90
|
status: "coming-soon",
|
|
104
91
|
},
|
|
105
92
|
{
|
|
106
|
-
feature: "
|
|
107
|
-
description:
|
|
108
|
-
"Invite users, assign roles, and manage pending invitations from the admin panel.",
|
|
109
|
-
status: "coming-soon",
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
feature: "API Keys",
|
|
113
|
-
description:
|
|
114
|
-
"Read-only API tokens for external integrations with configurable rate limiting.",
|
|
115
|
-
status: "coming-soon",
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
feature: "Audit Log",
|
|
119
|
-
description:
|
|
120
|
-
"Track who changed what and when across all collections and documents.",
|
|
121
|
-
status: "coming-soon",
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
feature: "Environments",
|
|
125
|
-
description:
|
|
126
|
-
"Project-level content branching with staging and production environments and atomic promotion.",
|
|
127
|
-
status: "planned",
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
feature: "Localization",
|
|
131
|
-
description:
|
|
132
|
-
"i18n field variants with per-locale versioning and content translation workflows.",
|
|
93
|
+
feature: "Richtext, JSON, Email & Textarea Fields",
|
|
94
|
+
description: "Plate.js-powered rich text, plus structured JSON, email, and multi-line text inputs.",
|
|
133
95
|
status: "planned",
|
|
134
96
|
},
|
|
135
97
|
{
|
|
136
|
-
feature: "
|
|
98
|
+
feature: "Form Builder & Lifecycle Hooks",
|
|
137
99
|
description:
|
|
138
|
-
"
|
|
100
|
+
"Composable form fields beyond content editing, plus beforeChange/afterChange hooks for custom side effects.",
|
|
139
101
|
status: "planned",
|
|
140
102
|
},
|
|
141
103
|
{
|
|
142
|
-
feature: "
|
|
143
|
-
description:
|
|
144
|
-
"Extend VEX with community plugins for custom fields, integrations, and admin panel features.",
|
|
104
|
+
feature: "Team Management & API Keys",
|
|
105
|
+
description: "Invite users, assign roles, and issue scoped read-only API tokens for external integrations.",
|
|
145
106
|
status: "planned",
|
|
146
107
|
},
|
|
147
108
|
],
|
|
148
109
|
}),
|
|
149
110
|
},
|
|
150
111
|
admin: {
|
|
151
|
-
icon: "
|
|
152
|
-
blockStyles: ["container"],
|
|
112
|
+
icon: "Map",
|
|
153
113
|
},
|
|
154
114
|
})
|