website-catalog.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { z } from "zod";
  2. const linkSchema = z.object({
  3. label: z.string(),
  4. href: z.string(),
  5. });
  6. const ctaSchema = z.object({
  7. label: z.string(),
  8. href: z.string(),
  9. });
  10. export const websiteComponentDefinitions = {
  11. Header: {
  12. props: z.object({
  13. brand: z.string(),
  14. links: z.array(linkSchema),
  15. variant: z.enum(["simple", "centered"]).nullable(),
  16. }),
  17. description:
  18. "Site header / navigation bar. Simple: brand left, links right. Centered: brand centered above links.",
  19. example: {
  20. brand: "Acme Inc",
  21. links: [
  22. { label: "Home", href: "/" },
  23. { label: "About", href: "/about" },
  24. { label: "Contact", href: "/contact" },
  25. ],
  26. variant: "simple",
  27. },
  28. },
  29. Hero: {
  30. props: z.object({
  31. headline: z.string(),
  32. description: z.string(),
  33. primaryCta: ctaSchema.nullable(),
  34. secondaryCta: ctaSchema.nullable(),
  35. badge: z.string().nullable(),
  36. variant: z.enum(["centered", "left-aligned"]).nullable(),
  37. }),
  38. description:
  39. "Landing hero section with headline, description, and call-to-action buttons.",
  40. example: {
  41. headline: "Build something great",
  42. description: "A modern platform for modern teams.",
  43. primaryCta: { label: "Get Started", href: "/contact" },
  44. variant: "centered",
  45. },
  46. },
  47. Features: {
  48. props: z.object({
  49. headline: z.string().nullable(),
  50. description: z.string().nullable(),
  51. items: z.array(
  52. z.object({
  53. title: z.string(),
  54. description: z.string(),
  55. }),
  56. ),
  57. columns: z.number().nullable(),
  58. variant: z.enum(["cards", "simple"]).nullable(),
  59. }),
  60. description:
  61. "Feature highlights section. Cards: bordered cards per item. Simple: clean text layout.",
  62. example: {
  63. headline: "Why choose us",
  64. items: [
  65. { title: "Fast", description: "Blazing performance." },
  66. { title: "Secure", description: "Enterprise-grade security." },
  67. { title: "Simple", description: "Easy to use." },
  68. ],
  69. columns: 3,
  70. variant: "cards",
  71. },
  72. },
  73. Team: {
  74. props: z.object({
  75. headline: z.string().nullable(),
  76. description: z.string().nullable(),
  77. members: z.array(
  78. z.object({
  79. name: z.string(),
  80. role: z.string(),
  81. bio: z.string().nullable(),
  82. }),
  83. ),
  84. variant: z.enum(["grid", "list"]).nullable(),
  85. }),
  86. description: "Team members section. Grid: card grid. List: vertical list.",
  87. example: {
  88. headline: "Our Team",
  89. members: [
  90. { name: "Alice", role: "CEO", bio: null },
  91. { name: "Bob", role: "CTO", bio: null },
  92. ],
  93. variant: "grid",
  94. },
  95. },
  96. Testimonials: {
  97. props: z.object({
  98. headline: z.string().nullable(),
  99. items: z.array(
  100. z.object({
  101. quote: z.string(),
  102. author: z.string(),
  103. role: z.string().nullable(),
  104. }),
  105. ),
  106. }),
  107. description: "Customer testimonials / quotes section.",
  108. example: {
  109. headline: "What people say",
  110. items: [
  111. {
  112. quote: "Amazing product!",
  113. author: "Jane",
  114. role: "CEO at Startup",
  115. },
  116. ],
  117. },
  118. },
  119. ContactForm: {
  120. props: z.object({
  121. headline: z.string().nullable(),
  122. description: z.string().nullable(),
  123. fields: z.array(
  124. z.object({
  125. label: z.string(),
  126. type: z.enum(["text", "email", "textarea"]),
  127. placeholder: z.string().nullable(),
  128. }),
  129. ),
  130. submitLabel: z.string(),
  131. }),
  132. description: "Contact form section with configurable fields.",
  133. example: {
  134. headline: "Get in Touch",
  135. fields: [
  136. { label: "Name", type: "text", placeholder: "Your name" },
  137. { label: "Email", type: "email", placeholder: "you@example.com" },
  138. { label: "Message", type: "textarea", placeholder: "Your message" },
  139. ],
  140. submitLabel: "Send",
  141. },
  142. },
  143. Footer: {
  144. props: z.object({
  145. brand: z.string().nullable(),
  146. links: z.array(linkSchema).nullable(),
  147. copyright: z.string().nullable(),
  148. variant: z.enum(["simple", "columns"]).nullable(),
  149. }),
  150. description:
  151. "Site footer. Simple: centered single row. Columns: multi-column layout.",
  152. example: {
  153. brand: "Acme Inc",
  154. copyright: "2026 Acme Inc.",
  155. variant: "simple",
  156. },
  157. },
  158. CTA: {
  159. props: z.object({
  160. headline: z.string(),
  161. description: z.string().nullable(),
  162. buttonLabel: z.string(),
  163. buttonHref: z.string(),
  164. variant: z.enum(["banner", "centered"]).nullable(),
  165. }),
  166. description:
  167. "Call-to-action section. Banner: full-width colored background. Centered: clean centered layout.",
  168. example: {
  169. headline: "Ready to get started?",
  170. buttonLabel: "Contact Us",
  171. buttonHref: "/contact",
  172. variant: "centered",
  173. },
  174. },
  175. };
  176. export type WebsiteProps<K extends keyof typeof websiteComponentDefinitions> =
  177. z.output<(typeof websiteComponentDefinitions)[K]["props"]>;