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.
Files changed (153) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +93 -83
  3. package/dist/index.js +246 -81
  4. package/dist/index.mjs +30976 -0
  5. package/package.json +35 -15
  6. package/templates/base-nextjs/README.md +53 -205
  7. package/templates/base-nextjs/_env.example +7 -9
  8. package/templates/base-nextjs/_gitignore +41 -1
  9. package/templates/base-nextjs/convex/_generated/api.d.ts +6 -62
  10. package/templates/base-nextjs/convex/_generated/server.d.ts +19 -0
  11. package/templates/base-nextjs/convex/_generated/server.js +8 -0
  12. package/templates/base-nextjs/convex/auth/api.ts +49 -3
  13. package/templates/base-nextjs/convex/auth/db.ts +42 -300
  14. package/templates/base-nextjs/convex/auth/index.ts +11 -7
  15. package/templates/base-nextjs/convex/auth/options.ts +5 -29
  16. package/templates/base-nextjs/convex/auth/plugins/index.ts +15 -5
  17. package/templates/base-nextjs/convex/auth/sessions.ts +9 -15
  18. package/templates/base-nextjs/convex/http.ts +18 -3
  19. package/templates/base-nextjs/convex/schema.ts +104 -2
  20. package/templates/base-nextjs/convex/vex/firstUser.ts +10 -84
  21. package/templates/base-nextjs/convex/vex/globals.ts +19 -82
  22. package/templates/base-nextjs/convex/vex/media.ts +19 -246
  23. package/templates/base-nextjs/convex/vex.schema.ts +138 -0
  24. package/templates/base-nextjs/convex/vex.ts +19 -0
  25. package/templates/base-nextjs/convex.json +6 -0
  26. package/templates/base-nextjs/eslint.config.mjs +1 -21
  27. package/templates/base-nextjs/next.config.ts +10 -0
  28. package/templates/base-nextjs/package.json +47 -48
  29. package/templates/base-nextjs/src/app/(frontend)/@auth/(...)auth/[pathname]/view.tsx +17 -5
  30. package/templates/base-nextjs/src/app/(frontend)/auth/[pathname]/view.tsx +2 -4
  31. package/templates/base-nextjs/src/app/(frontend)/layout.tsx +12 -2
  32. package/templates/base-nextjs/src/app/(frontend)/page.tsx +2 -113
  33. package/templates/base-nextjs/src/app/(vexcms)/admin/[[...path]]/page.tsx +40 -0
  34. package/templates/base-nextjs/src/app/(vexcms)/admin/clientProviders.tsx +22 -0
  35. package/templates/base-nextjs/src/app/(vexcms)/admin/layout.tsx +19 -0
  36. package/templates/base-nextjs/src/app/globals.css +240 -104
  37. package/templates/base-nextjs/src/app/layout.tsx +23 -13
  38. package/templates/base-nextjs/src/app/unauthorized/page.tsx +24 -0
  39. package/templates/base-nextjs/src/auth/access.ts +46 -0
  40. package/templates/base-nextjs/src/auth/client.tsx +17 -5
  41. package/templates/base-nextjs/src/auth/hasPermission.ts +39 -0
  42. package/templates/base-nextjs/src/auth/serverUtils.ts +15 -25
  43. package/templates/base-nextjs/src/components/WelcomePage.tsx +116 -0
  44. package/templates/base-nextjs/src/components/component-example.tsx +56 -464
  45. package/templates/base-nextjs/src/components/providers/auth.tsx +13 -0
  46. package/templates/base-nextjs/src/components/providers/client.tsx +6 -1
  47. package/templates/base-nextjs/src/components/providers/convex.tsx +53 -21
  48. package/templates/base-nextjs/src/components/providers/server.tsx +10 -7
  49. package/templates/{marketing-site → base-nextjs}/src/components/ui/accordion.tsx +30 -32
  50. package/templates/base-nextjs/src/components/ui/badge.tsx +10 -13
  51. package/templates/base-nextjs/src/components/ui/input.tsx +35 -5
  52. package/templates/base-nextjs/src/context/AuthContext.tsx +29 -0
  53. package/templates/base-nextjs/src/db/constants/auth.ts +0 -1
  54. package/templates/base-nextjs/src/db/constants/index.ts +22 -35
  55. package/templates/base-nextjs/src/lib/utils.ts +0 -12
  56. package/templates/base-nextjs/src/proxy.ts +97 -12
  57. package/templates/base-nextjs/src/vex.config.ts +35 -0
  58. package/templates/base-nextjs/src/vex.types.ts +293 -0
  59. package/templates/base-nextjs/src/vexcms/collections/images.ts +15 -0
  60. package/templates/base-nextjs/src/vexcms/collections/index.ts +2 -1
  61. package/templates/base-nextjs/src/vexcms/collections/users.ts +7 -35
  62. package/templates/base-nextjs/tsconfig.json +3 -0
  63. package/templates/marketing-site/convex/_generated/api.d.ts +81 -0
  64. package/templates/marketing-site/convex/_generated/api.js +23 -0
  65. package/templates/marketing-site/convex/_generated/dataModel.d.ts +60 -0
  66. package/templates/marketing-site/convex/_generated/server.d.ts +162 -0
  67. package/templates/marketing-site/convex/_generated/server.js +101 -0
  68. package/templates/marketing-site/convex/footers.ts +11 -7
  69. package/templates/marketing-site/convex/headers.ts +15 -5
  70. package/templates/marketing-site/convex/pages.ts +20 -35
  71. package/templates/marketing-site/convex/schema.ts +119 -0
  72. package/templates/marketing-site/convex/seed.ts +582 -35
  73. package/templates/marketing-site/convex/siteSettings.ts +19 -5
  74. package/templates/marketing-site/convex/theme.ts +55 -61
  75. package/templates/marketing-site/convex/vex.schema.ts +355 -0
  76. package/templates/marketing-site/src/app/(frontend)/PageContent.tsx +27 -160
  77. package/templates/marketing-site/src/app/(frontend)/[slug]/page.tsx +6 -9
  78. package/templates/marketing-site/src/app/(frontend)/layout.tsx +4 -2
  79. package/templates/marketing-site/src/app/(frontend)/page.tsx +2 -5
  80. package/templates/marketing-site/src/components/SiteFooter.tsx +6 -3
  81. package/templates/marketing-site/src/components/SiteHeader.tsx +6 -3
  82. package/templates/marketing-site/src/components/ThemeLive.tsx +59 -0
  83. package/templates/marketing-site/src/components/ThemeStyle.tsx +45 -89
  84. package/templates/marketing-site/src/lib/metadata.ts +51 -72
  85. package/templates/marketing-site/src/vex.config.ts +35 -0
  86. package/templates/marketing-site/src/vex.types.ts +634 -0
  87. package/templates/marketing-site/src/vexcms/api.ts +23 -0
  88. package/templates/marketing-site/src/vexcms/blocks/CTA/config.ts +3 -3
  89. package/templates/marketing-site/src/vexcms/blocks/CTA/index.tsx +2 -2
  90. package/templates/marketing-site/src/vexcms/blocks/FAQ/config.ts +4 -4
  91. package/templates/marketing-site/src/vexcms/blocks/FAQ/index.tsx +2 -2
  92. package/templates/marketing-site/src/vexcms/blocks/Features/config.ts +4 -8
  93. package/templates/marketing-site/src/vexcms/blocks/Features/index.tsx +2 -2
  94. package/templates/marketing-site/src/vexcms/blocks/Footer/config.ts +7 -11
  95. package/templates/marketing-site/src/vexcms/blocks/Footer/index.tsx +1 -1
  96. package/templates/marketing-site/src/vexcms/blocks/Header/config.ts +9 -9
  97. package/templates/marketing-site/src/vexcms/blocks/Header/index.tsx +4 -5
  98. package/templates/marketing-site/src/vexcms/blocks/Hero/config.ts +3 -4
  99. package/templates/marketing-site/src/vexcms/blocks/Hero/index.tsx +10 -19
  100. package/templates/marketing-site/src/vexcms/blocks/HowItWorks/config.ts +4 -9
  101. package/templates/marketing-site/src/vexcms/blocks/HowItWorks/index.tsx +3 -6
  102. package/templates/marketing-site/src/vexcms/blocks/Roadmap/config.ts +28 -68
  103. package/templates/marketing-site/src/vexcms/blocks/Roadmap/index.tsx +13 -43
  104. package/templates/marketing-site/src/vexcms/blocks/config.ts +7 -22
  105. package/templates/marketing-site/src/vexcms/blocks/constants.ts +2 -3
  106. package/templates/marketing-site/src/vexcms/blocks/index.ts +9 -8
  107. package/templates/marketing-site/src/vexcms/collections/footers.ts +1 -1
  108. package/templates/marketing-site/src/vexcms/collections/headers.ts +1 -1
  109. package/templates/marketing-site/src/vexcms/collections/index.ts +2 -1
  110. package/templates/marketing-site/src/vexcms/collections/pages.ts +12 -21
  111. package/templates/marketing-site/src/vexcms/collections/themeColors.ts +118 -0
  112. package/templates/marketing-site/src/vexcms/collections/themes.ts +29 -111
  113. package/templates/marketing-site/src/vexcms/globals/index.ts +1 -1
  114. package/templates/marketing-site/src/vexcms/globals/siteSettings.ts +43 -27
  115. package/templates/base-nextjs/convex/auth/adapter/index.ts +0 -230
  116. package/templates/base-nextjs/convex/auth/adapter/utils.ts +0 -547
  117. package/templates/base-nextjs/convex/auth/config.ts +0 -10
  118. package/templates/base-nextjs/convex/vex/auth.ts +0 -38
  119. package/templates/base-nextjs/convex/vex/collections.ts +0 -333
  120. package/templates/base-nextjs/convex/vex/helpers.ts +0 -33
  121. package/templates/base-nextjs/convex/vex/impersonation.ts +0 -51
  122. package/templates/base-nextjs/convex/vex/migrate.ts +0 -74
  123. package/templates/base-nextjs/convex/vex/model/collections.ts +0 -196
  124. package/templates/base-nextjs/convex/vex/model/media.ts +0 -87
  125. package/templates/base-nextjs/convex/vex/model/versions.ts +0 -254
  126. package/templates/base-nextjs/convex/vex/previewSnapshot.ts +0 -53
  127. package/templates/base-nextjs/convex/vex/versions.ts +0 -648
  128. package/templates/base-nextjs/src/app/admin/AdminLayoutWrapper.tsx +0 -33
  129. package/templates/base-nextjs/src/app/admin/AdminPageWrapper.tsx +0 -38
  130. package/templates/base-nextjs/src/app/admin/RichTextFieldWithMedia.tsx +0 -101
  131. package/templates/base-nextjs/src/app/admin/[[...path]]/page.tsx +0 -15
  132. package/templates/base-nextjs/src/app/admin/layout.tsx +0 -51
  133. package/templates/base-nextjs/src/app/favicon.ico +0 -0
  134. package/templates/base-nextjs/src/components/providers/theme.tsx +0 -11
  135. package/templates/base-nextjs/src/components/ui/theme-toggle.tsx +0 -67
  136. package/templates/base-nextjs/src/db/types.ts +0 -6
  137. package/templates/base-nextjs/src/vexcms/access.ts +0 -44
  138. package/templates/base-nextjs/src/vexcms/auth.ts +0 -4
  139. package/templates/base-nextjs/src/vexcms/collections/media.ts +0 -15
  140. package/templates/base-nextjs/vex.config.ts +0 -25
  141. package/templates/marketing-site/public/favicons/favicon.ico +0 -0
  142. package/templates/marketing-site/src/app/(frontend)/preview/[slug]/PreviewPageContent.tsx +0 -55
  143. package/templates/marketing-site/src/app/(frontend)/preview/[slug]/page.tsx +0 -27
  144. package/templates/marketing-site/src/app/(frontend)/preview/layout.tsx +0 -18
  145. package/templates/marketing-site/src/app/admin/AdminLayoutWrapper.tsx +0 -71
  146. package/templates/marketing-site/src/components/ThemeInjector.tsx +0 -128
  147. package/templates/marketing-site/src/components/admin/IconPickerField.tsx +0 -134
  148. package/templates/marketing-site/src/components/admin/ThemeImport.tsx +0 -174
  149. package/templates/marketing-site/src/components/admin/ThemeImportField.tsx +0 -33
  150. package/templates/marketing-site/src/db/constants/index.ts +0 -52
  151. package/templates/marketing-site/src/lib/colorConvert.ts +0 -171
  152. package/templates/marketing-site/src/vexcms/access.ts +0 -36
  153. package/templates/marketing-site/vex.config.ts +0 -32
@@ -1,4 +1,4 @@
1
- import type { BlockComponentProps } from "@vexcms/ui"
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 "~/components/ui/accordion"
10
+ } from "@vexcms/react"
11
11
 
12
12
  export { faqBlock } from "./config"
13
13
 
@@ -1,6 +1,5 @@
1
- import { array, defineBlock, object, text } from "@vexcms/core"
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: object({
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
- admin: {
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: "layout-grid",
55
+ icon: "LayoutGrid",
60
56
  },
61
57
  })
@@ -1,9 +1,9 @@
1
- import type { BlockComponentProps } from "@vexcms/ui"
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 "~/components/ui/card"
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, object, text, upload } from "@vexcms/core"
1
+ import { array, defineBlock, group, text, upload } from "@vexcms/core"
2
2
 
3
- import IconPickerField from "~/components/admin/IconPickerField"
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: TABLE_SLUG_MEDIA,
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: object({
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: object({
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
- admin: {
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: "panel-bottom",
59
+ icon: "PanelBottom",
64
60
  },
65
61
  })
@@ -1,4 +1,4 @@
1
- import type { BlockComponentProps } from "@vexcms/ui"
1
+ import type { BlockComponentProps } from "@vexcms/react"
2
2
 
3
3
  import { icons } from "lucide-react"
4
4
  import Link from "next/link"
@@ -1,6 +1,6 @@
1
- import { array, defineBlock, object, select, text, upload } from "@vexcms/core"
1
+ import { array, defineBlock, group, select, text, upload } from "@vexcms/core"
2
2
 
3
- import { TABLE_SLUG_MEDIA } from "~/db/constants"
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
- admin: { description: "Text to display as the logo" },
13
+ description: "Text to display as the logo",
14
14
  }),
15
15
  logoImage: upload({
16
16
  label: "Logo Image",
17
- to: TABLE_SLUG_MEDIA,
18
- admin: { description: "Image to display as the logo (overrides text)" },
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: object({
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: object({
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: "panel-top",
63
+ icon: "PanelTop",
64
64
  },
65
65
  })
@@ -1,14 +1,13 @@
1
1
  "use client"
2
2
 
3
- import type { BlockComponentProps } from "@vexcms/ui"
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 "~/lib/utils"
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 isAdmin = session?.user?.role === "admin" ||
31
- (Array.isArray((session?.user as any)?.role) && (session?.user as any)?.role?.includes("admin"))
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
- admin: { description: "Small text shown in the announcement badge" },
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
- admin: { description: "URL the badge links to" },
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: "sparkles",
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/ui"
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, blockStyles }: BlockComponentProps) {
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={cn("overflow-hidden", blockStyles)}>
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 variant type mismatch
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 variant type mismatch
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, object, text } from "@vexcms/core"
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: object({
22
+ items: group({
24
23
  fields: {
25
24
  icon: text({
26
25
  label: "Icon",
27
- admin: {
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: "list-ordered",
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/ui"
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={cn("py-16 md:py-32", blockStyles)}>
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, object, select, text } from "@vexcms/core"
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: object({
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: "16 Field Types",
40
+ feature: "12 Field Types",
41
41
  description:
42
- "Text, number, select, date, relationship, upload, richtext, blocks, color, tabs, and more.",
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: "Admin Panel",
46
+ feature: "Convex Schema Codegen",
47
47
  description:
48
- "Full-featured admin UI with list views, edit forms, media library, and draft/publish workflow.",
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 Queries",
52
+ feature: "Real-Time Admin Panel",
53
53
  description:
54
- "Every query is live via Convex. Content updates appear instantly across all connected clients.",
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: "Live Preview",
58
+ feature: "Media Library",
59
59
  description:
60
- "Side-by-side iframe preview with responsive breakpoints and real-time updates as you edit.",
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: "Block System",
64
+ feature: "RBAC & Access Control",
65
65
  description:
66
- "Compose pages from reusable content blocks with drag-and-drop reordering and inline editing.",
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: "Authentication & RBAC",
70
+ feature: "Custom Theme System",
71
71
  description:
72
- "Better Auth integration with role-based access control at the document and field level.",
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: "Rich Text Editor",
76
+ feature: "Better Auth Integration",
77
77
  description:
78
- "Plate.js-powered editor with media uploads, links, tables, and custom elements.",
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 & Scaffolding",
82
+ feature: "CLI & Scaffolder",
83
83
  description:
84
- "vex dev with watch/generate, and create-vexcms for instant project setup.",
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: "Theme System",
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: "Team Management",
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: "Approval Workflows",
98
+ feature: "Form Builder & Lifecycle Hooks",
137
99
  description:
138
- "Review and sign-off steps before content goes live. Configurable multi-step approval chains.",
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: "Plugin System",
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: "map",
152
- blockStyles: ["container"],
112
+ icon: "Map",
153
113
  },
154
114
  })