@fnd-platform/cms 1.0.0-alpha.1

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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/lib/cms-project.d.ts +127 -0
  4. package/lib/cms-project.d.ts.map +1 -0
  5. package/lib/cms-project.js +343 -0
  6. package/lib/cms-project.js.map +1 -0
  7. package/lib/index.d.ts +11 -0
  8. package/lib/index.d.ts.map +1 -0
  9. package/lib/index.js +20 -0
  10. package/lib/index.js.map +1 -0
  11. package/lib/options.d.ts +59 -0
  12. package/lib/options.d.ts.map +1 -0
  13. package/lib/options.js +3 -0
  14. package/lib/options.js.map +1 -0
  15. package/lib/templates/admin-breadcrumbs.d.ts +13 -0
  16. package/lib/templates/admin-breadcrumbs.d.ts.map +1 -0
  17. package/lib/templates/admin-breadcrumbs.js +80 -0
  18. package/lib/templates/admin-breadcrumbs.js.map +1 -0
  19. package/lib/templates/admin-content-route.d.ts +18 -0
  20. package/lib/templates/admin-content-route.d.ts.map +1 -0
  21. package/lib/templates/admin-content-route.js +100 -0
  22. package/lib/templates/admin-content-route.js.map +1 -0
  23. package/lib/templates/admin-content-type-route.d.ts +9 -0
  24. package/lib/templates/admin-content-type-route.d.ts.map +1 -0
  25. package/lib/templates/admin-content-type-route.js +96 -0
  26. package/lib/templates/admin-content-type-route.js.map +1 -0
  27. package/lib/templates/admin-header.d.ts +13 -0
  28. package/lib/templates/admin-header.d.ts.map +1 -0
  29. package/lib/templates/admin-header.js +123 -0
  30. package/lib/templates/admin-header.js.map +1 -0
  31. package/lib/templates/admin-index.d.ts +9 -0
  32. package/lib/templates/admin-index.d.ts.map +1 -0
  33. package/lib/templates/admin-index.js +60 -0
  34. package/lib/templates/admin-index.js.map +1 -0
  35. package/lib/templates/admin-layout.d.ts +10 -0
  36. package/lib/templates/admin-layout.d.ts.map +1 -0
  37. package/lib/templates/admin-layout.js +46 -0
  38. package/lib/templates/admin-layout.js.map +1 -0
  39. package/lib/templates/admin-sidebar.d.ts +13 -0
  40. package/lib/templates/admin-sidebar.d.ts.map +1 -0
  41. package/lib/templates/admin-sidebar.js +149 -0
  42. package/lib/templates/admin-sidebar.js.map +1 -0
  43. package/lib/templates/content-editor.d.ts +10 -0
  44. package/lib/templates/content-editor.d.ts.map +1 -0
  45. package/lib/templates/content-editor.js +354 -0
  46. package/lib/templates/content-editor.js.map +1 -0
  47. package/lib/templates/content-schema.d.ts +10 -0
  48. package/lib/templates/content-schema.d.ts.map +1 -0
  49. package/lib/templates/content-schema.js +274 -0
  50. package/lib/templates/content-schema.js.map +1 -0
  51. package/lib/templates/content-table.d.ts +13 -0
  52. package/lib/templates/content-table.d.ts.map +1 -0
  53. package/lib/templates/content-table.js +177 -0
  54. package/lib/templates/content-table.js.map +1 -0
  55. package/lib/templates/content-types-examples.d.ts +19 -0
  56. package/lib/templates/content-types-examples.d.ts.map +1 -0
  57. package/lib/templates/content-types-examples.js +275 -0
  58. package/lib/templates/content-types-examples.js.map +1 -0
  59. package/lib/templates/content-types-registry.d.ts +10 -0
  60. package/lib/templates/content-types-registry.d.ts.map +1 -0
  61. package/lib/templates/content-types-registry.js +87 -0
  62. package/lib/templates/content-types-registry.js.map +1 -0
  63. package/lib/templates/content-types.d.ts +10 -0
  64. package/lib/templates/content-types.d.ts.map +1 -0
  65. package/lib/templates/content-types.js +384 -0
  66. package/lib/templates/content-types.js.map +1 -0
  67. package/lib/templates/dashboard-stats.d.ts +13 -0
  68. package/lib/templates/dashboard-stats.d.ts.map +1 -0
  69. package/lib/templates/dashboard-stats.js +117 -0
  70. package/lib/templates/dashboard-stats.js.map +1 -0
  71. package/lib/templates/editor/index.d.ts +6 -0
  72. package/lib/templates/editor/index.d.ts.map +1 -0
  73. package/lib/templates/editor/index.js +21 -0
  74. package/lib/templates/editor/index.js.map +1 -0
  75. package/lib/templates/editor/rich-text-editor.d.ts +7 -0
  76. package/lib/templates/editor/rich-text-editor.d.ts.map +1 -0
  77. package/lib/templates/editor/rich-text-editor.js +115 -0
  78. package/lib/templates/editor/rich-text-editor.js.map +1 -0
  79. package/lib/templates/editor/toolbar.d.ts +7 -0
  80. package/lib/templates/editor/toolbar.d.ts.map +1 -0
  81. package/lib/templates/editor/toolbar.js +272 -0
  82. package/lib/templates/editor/toolbar.js.map +1 -0
  83. package/lib/templates/form-fields/boolean-field.d.ts +7 -0
  84. package/lib/templates/form-fields/boolean-field.d.ts.map +1 -0
  85. package/lib/templates/form-fields/boolean-field.js +76 -0
  86. package/lib/templates/form-fields/boolean-field.js.map +1 -0
  87. package/lib/templates/form-fields/date-field.d.ts +7 -0
  88. package/lib/templates/form-fields/date-field.d.ts.map +1 -0
  89. package/lib/templates/form-fields/date-field.js +61 -0
  90. package/lib/templates/form-fields/date-field.js.map +1 -0
  91. package/lib/templates/form-fields/datetime-field.d.ts +7 -0
  92. package/lib/templates/form-fields/datetime-field.d.ts.map +1 -0
  93. package/lib/templates/form-fields/datetime-field.js +87 -0
  94. package/lib/templates/form-fields/datetime-field.js.map +1 -0
  95. package/lib/templates/form-fields/index.d.ts +23 -0
  96. package/lib/templates/form-fields/index.d.ts.map +1 -0
  97. package/lib/templates/form-fields/index.js +275 -0
  98. package/lib/templates/form-fields/index.js.map +1 -0
  99. package/lib/templates/form-fields/media-field.d.ts +10 -0
  100. package/lib/templates/form-fields/media-field.d.ts.map +1 -0
  101. package/lib/templates/form-fields/media-field.js +225 -0
  102. package/lib/templates/form-fields/media-field.js.map +1 -0
  103. package/lib/templates/form-fields/multiselect-field.d.ts +7 -0
  104. package/lib/templates/form-fields/multiselect-field.d.ts.map +1 -0
  105. package/lib/templates/form-fields/multiselect-field.js +121 -0
  106. package/lib/templates/form-fields/multiselect-field.js.map +1 -0
  107. package/lib/templates/form-fields/number-field.d.ts +7 -0
  108. package/lib/templates/form-fields/number-field.d.ts.map +1 -0
  109. package/lib/templates/form-fields/number-field.js +87 -0
  110. package/lib/templates/form-fields/number-field.js.map +1 -0
  111. package/lib/templates/form-fields/reference-field.d.ts +9 -0
  112. package/lib/templates/form-fields/reference-field.d.ts.map +1 -0
  113. package/lib/templates/form-fields/reference-field.js +145 -0
  114. package/lib/templates/form-fields/reference-field.js.map +1 -0
  115. package/lib/templates/form-fields/richtext-field.d.ts +9 -0
  116. package/lib/templates/form-fields/richtext-field.d.ts.map +1 -0
  117. package/lib/templates/form-fields/richtext-field.js +60 -0
  118. package/lib/templates/form-fields/richtext-field.js.map +1 -0
  119. package/lib/templates/form-fields/select-field.d.ts +7 -0
  120. package/lib/templates/form-fields/select-field.d.ts.map +1 -0
  121. package/lib/templates/form-fields/select-field.js +70 -0
  122. package/lib/templates/form-fields/select-field.js.map +1 -0
  123. package/lib/templates/form-fields/slug-field.d.ts +7 -0
  124. package/lib/templates/form-fields/slug-field.d.ts.map +1 -0
  125. package/lib/templates/form-fields/slug-field.js +143 -0
  126. package/lib/templates/form-fields/slug-field.js.map +1 -0
  127. package/lib/templates/form-fields/tags-field.d.ts +7 -0
  128. package/lib/templates/form-fields/tags-field.d.ts.map +1 -0
  129. package/lib/templates/form-fields/tags-field.js +172 -0
  130. package/lib/templates/form-fields/tags-field.js.map +1 -0
  131. package/lib/templates/form-fields/text-field.d.ts +7 -0
  132. package/lib/templates/form-fields/text-field.d.ts.map +1 -0
  133. package/lib/templates/form-fields/text-field.js +63 -0
  134. package/lib/templates/form-fields/text-field.js.map +1 -0
  135. package/lib/templates/form-fields/textarea-field.d.ts +7 -0
  136. package/lib/templates/form-fields/textarea-field.d.ts.map +1 -0
  137. package/lib/templates/form-fields/textarea-field.js +64 -0
  138. package/lib/templates/form-fields/textarea-field.js.map +1 -0
  139. package/lib/templates/index.d.ts +34 -0
  140. package/lib/templates/index.d.ts.map +1 -0
  141. package/lib/templates/index.js +92 -0
  142. package/lib/templates/index.js.map +1 -0
  143. package/lib/templates/media/index.d.ts +12 -0
  144. package/lib/templates/media/index.d.ts.map +1 -0
  145. package/lib/templates/media/index.js +50 -0
  146. package/lib/templates/media/index.js.map +1 -0
  147. package/lib/templates/media/media-api.d.ts +13 -0
  148. package/lib/templates/media/media-api.d.ts.map +1 -0
  149. package/lib/templates/media/media-api.js +274 -0
  150. package/lib/templates/media/media-api.js.map +1 -0
  151. package/lib/templates/media/media-grid.d.ts +14 -0
  152. package/lib/templates/media/media-grid.d.ts.map +1 -0
  153. package/lib/templates/media/media-grid.js +314 -0
  154. package/lib/templates/media/media-grid.js.map +1 -0
  155. package/lib/templates/media/media-library-route.d.ts +13 -0
  156. package/lib/templates/media/media-library-route.d.ts.map +1 -0
  157. package/lib/templates/media/media-library-route.js +105 -0
  158. package/lib/templates/media/media-library-route.js.map +1 -0
  159. package/lib/templates/media/media-picker.d.ts +13 -0
  160. package/lib/templates/media/media-picker.d.ts.map +1 -0
  161. package/lib/templates/media/media-picker.js +152 -0
  162. package/lib/templates/media/media-picker.js.map +1 -0
  163. package/lib/templates/media/media-uploader.d.ts +14 -0
  164. package/lib/templates/media/media-uploader.d.ts.map +1 -0
  165. package/lib/templates/media/media-uploader.js +318 -0
  166. package/lib/templates/media/media-uploader.js.map +1 -0
  167. package/lib/templates/recent-content.d.ts +13 -0
  168. package/lib/templates/recent-content.d.ts.map +1 -0
  169. package/lib/templates/recent-content.js +138 -0
  170. package/lib/templates/recent-content.js.map +1 -0
  171. package/lib/templates/slug-utils.d.ts +10 -0
  172. package/lib/templates/slug-utils.d.ts.map +1 -0
  173. package/lib/templates/slug-utils.js +194 -0
  174. package/lib/templates/slug-utils.js.map +1 -0
  175. package/lib/templates/ui-avatar.d.ts +8 -0
  176. package/lib/templates/ui-avatar.d.ts.map +1 -0
  177. package/lib/templates/ui-avatar.js +60 -0
  178. package/lib/templates/ui-avatar.js.map +1 -0
  179. package/lib/templates/ui-badge.d.ts +8 -0
  180. package/lib/templates/ui-badge.d.ts.map +1 -0
  181. package/lib/templates/ui-badge.js +52 -0
  182. package/lib/templates/ui-badge.js.map +1 -0
  183. package/lib/templates/ui-dialog.d.ts +10 -0
  184. package/lib/templates/ui-dialog.d.ts.map +1 -0
  185. package/lib/templates/ui-dialog.js +134 -0
  186. package/lib/templates/ui-dialog.js.map +1 -0
  187. package/lib/templates/ui-dropdown-menu.d.ts +8 -0
  188. package/lib/templates/ui-dropdown-menu.d.ts.map +1 -0
  189. package/lib/templates/ui-dropdown-menu.js +210 -0
  190. package/lib/templates/ui-dropdown-menu.js.map +1 -0
  191. package/lib/templates/ui-popover.d.ts +8 -0
  192. package/lib/templates/ui-popover.d.ts.map +1 -0
  193. package/lib/templates/ui-popover.js +43 -0
  194. package/lib/templates/ui-popover.js.map +1 -0
  195. package/lib/templates/ui-progress.d.ts +10 -0
  196. package/lib/templates/ui-progress.d.ts.map +1 -0
  197. package/lib/templates/ui-progress.js +40 -0
  198. package/lib/templates/ui-progress.js.map +1 -0
  199. package/lib/templates/ui-table.d.ts +8 -0
  200. package/lib/templates/ui-table.d.ts.map +1 -0
  201. package/lib/templates/ui-table.js +129 -0
  202. package/lib/templates/ui-table.js.map +1 -0
  203. package/lib/templates/ui-tabs.d.ts +10 -0
  204. package/lib/templates/ui-tabs.d.ts.map +1 -0
  205. package/lib/templates/ui-tabs.js +67 -0
  206. package/lib/templates/ui-tabs.js.map +1 -0
  207. package/package.json +52 -0
@@ -0,0 +1,177 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.getContentTableTemplate = getContentTableTemplate;
4
+ /**
5
+ * Generates the content table component template.
6
+ *
7
+ * This component displays:
8
+ * - Table of content items for a specific type
9
+ * - Status badges
10
+ * - Edit/Delete actions
11
+ * - Empty state
12
+ *
13
+ * @returns Template string for app/components/admin/content-table.tsx
14
+ */
15
+ function getContentTableTemplate() {
16
+ return `import { Link } from '@remix-run/react';
17
+ import { Pencil, Trash2, MoreHorizontal, Plus } from 'lucide-react';
18
+ import { Button } from '~/components/ui/button';
19
+ import { Badge } from '~/components/ui/badge';
20
+ import {
21
+ Table,
22
+ TableBody,
23
+ TableCell,
24
+ TableHead,
25
+ TableHeader,
26
+ TableRow,
27
+ } from '~/components/ui/table';
28
+ import {
29
+ DropdownMenu,
30
+ DropdownMenuContent,
31
+ DropdownMenuItem,
32
+ DropdownMenuTrigger,
33
+ } from '~/components/ui/dropdown-menu';
34
+
35
+ export interface ContentItem {
36
+ id: string;
37
+ title: string;
38
+ status: 'draft' | 'published' | 'scheduled' | 'archived';
39
+ createdAt: string;
40
+ updatedAt: string;
41
+ }
42
+
43
+ export interface ContentType {
44
+ name: string;
45
+ label: string;
46
+ }
47
+
48
+ interface ContentTableProps {
49
+ contentType: ContentType;
50
+ items: ContentItem[];
51
+ canEdit?: boolean;
52
+ canDelete?: boolean;
53
+ }
54
+
55
+ function getStatusBadgeVariant(
56
+ status: string
57
+ ): 'default' | 'secondary' | 'success' | 'warning' | 'outline' {
58
+ switch (status) {
59
+ case 'published':
60
+ return 'success';
61
+ case 'draft':
62
+ return 'secondary';
63
+ case 'scheduled':
64
+ return 'warning';
65
+ case 'archived':
66
+ return 'outline';
67
+ default:
68
+ return 'default';
69
+ }
70
+ }
71
+
72
+ function formatDate(dateString: string): string {
73
+ return new Date(dateString).toLocaleDateString(undefined, {
74
+ year: 'numeric',
75
+ month: 'short',
76
+ day: 'numeric',
77
+ });
78
+ }
79
+
80
+ export function ContentTable({
81
+ contentType,
82
+ items,
83
+ canEdit = true,
84
+ canDelete = true,
85
+ }: ContentTableProps) {
86
+ if (items.length === 0) {
87
+ return (
88
+ <div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-12 text-center">
89
+ <p className="text-sm text-muted-foreground">
90
+ No {contentType.label.toLowerCase()} found.
91
+ </p>
92
+ <Button asChild className="mt-4">
93
+ <Link to={\`/admin/content/\${contentType.name}/new\`}>
94
+ <Plus className="mr-2 h-4 w-4" />
95
+ Create {contentType.label}
96
+ </Link>
97
+ </Button>
98
+ </div>
99
+ );
100
+ }
101
+
102
+ return (
103
+ <div className="rounded-md border">
104
+ <Table>
105
+ <TableHeader>
106
+ <TableRow>
107
+ <TableHead className="w-[40%]">Title</TableHead>
108
+ <TableHead>Status</TableHead>
109
+ <TableHead>Created</TableHead>
110
+ <TableHead>Updated</TableHead>
111
+ <TableHead className="w-[70px]">Actions</TableHead>
112
+ </TableRow>
113
+ </TableHeader>
114
+ <TableBody>
115
+ {items.map((item) => (
116
+ <TableRow key={item.id}>
117
+ <TableCell className="font-medium">
118
+ <Link
119
+ to={\`/admin/content/\${contentType.name}/\${item.id}\`}
120
+ className="hover:underline"
121
+ >
122
+ {item.title}
123
+ </Link>
124
+ </TableCell>
125
+ <TableCell>
126
+ <Badge
127
+ variant={getStatusBadgeVariant(item.status)}
128
+ className="capitalize"
129
+ >
130
+ {item.status}
131
+ </Badge>
132
+ </TableCell>
133
+ <TableCell className="text-muted-foreground">
134
+ {formatDate(item.createdAt)}
135
+ </TableCell>
136
+ <TableCell className="text-muted-foreground">
137
+ {formatDate(item.updatedAt)}
138
+ </TableCell>
139
+ <TableCell>
140
+ <DropdownMenu>
141
+ <DropdownMenuTrigger asChild>
142
+ <Button variant="ghost" size="icon">
143
+ <MoreHorizontal className="h-4 w-4" />
144
+ <span className="sr-only">Open menu</span>
145
+ </Button>
146
+ </DropdownMenuTrigger>
147
+ <DropdownMenuContent align="end">
148
+ {canEdit && (
149
+ <DropdownMenuItem asChild>
150
+ <Link
151
+ to={\`/admin/content/\${contentType.name}/\${item.id}\`}
152
+ className="flex items-center"
153
+ >
154
+ <Pencil className="mr-2 h-4 w-4" />
155
+ Edit
156
+ </Link>
157
+ </DropdownMenuItem>
158
+ )}
159
+ {canDelete && (
160
+ <DropdownMenuItem className="text-destructive focus:text-destructive">
161
+ <Trash2 className="mr-2 h-4 w-4" />
162
+ Delete
163
+ </DropdownMenuItem>
164
+ )}
165
+ </DropdownMenuContent>
166
+ </DropdownMenu>
167
+ </TableCell>
168
+ </TableRow>
169
+ ))}
170
+ </TableBody>
171
+ </Table>
172
+ </div>
173
+ );
174
+ }
175
+ `;
176
+ }
177
+ //# sourceMappingURL=content-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-table.js","sourceRoot":"","sources":["../../src/templates/content-table.ts"],"names":[],"mappings":";;AAWA,0DAiKC;AA5KD;;;;;;;;;;GAUG;AACH,SAAgB,uBAAuB;IACrC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+JR,CAAC;AACF,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Generates example content type definition templates.
3
+ *
4
+ * These templates provide example content types (blog-post, page)
5
+ * that demonstrate how to use the content type system.
6
+ */
7
+ /**
8
+ * Generates the blog post content type template.
9
+ *
10
+ * @returns Template string for app/content-types/blog-post.ts
11
+ */
12
+ export declare function getBlogPostContentTypeTemplate(): string;
13
+ /**
14
+ * Generates the page content type template.
15
+ *
16
+ * @returns Template string for app/content-types/page.ts
17
+ */
18
+ export declare function getPageContentTypeTemplate(): string;
19
+ //# sourceMappingURL=content-types-examples.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-types-examples.d.ts","sourceRoot":"","sources":["../../src/templates/content-types-examples.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CAmIvD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAyHnD"}
@@ -0,0 +1,275 @@
1
+ 'use strict';
2
+ /**
3
+ * Generates example content type definition templates.
4
+ *
5
+ * These templates provide example content types (blog-post, page)
6
+ * that demonstrate how to use the content type system.
7
+ */
8
+ Object.defineProperty(exports, '__esModule', { value: true });
9
+ exports.getBlogPostContentTypeTemplate = getBlogPostContentTypeTemplate;
10
+ exports.getPageContentTypeTemplate = getPageContentTypeTemplate;
11
+ /**
12
+ * Generates the blog post content type template.
13
+ *
14
+ * @returns Template string for app/content-types/blog-post.ts
15
+ */
16
+ function getBlogPostContentTypeTemplate() {
17
+ return `/**
18
+ * Blog Post Content Type
19
+ *
20
+ * Defines the structure for blog posts in the CMS.
21
+ */
22
+
23
+ import { defineContentType } from '~/lib/content-types';
24
+
25
+ /**
26
+ * Blog post content type definition.
27
+ *
28
+ * Fields:
29
+ * - title: Post title (required)
30
+ * - slug: URL-friendly identifier (auto-generated from title)
31
+ * - excerpt: Short summary for listings
32
+ * - content: Main post content (rich text)
33
+ * - featuredImage: Hero image for the post
34
+ * - category: Post category
35
+ * - tags: Post tags for organization
36
+ * - author: Post author reference
37
+ * - publishedAt: Publication date
38
+ * - featured: Whether to feature on homepage
39
+ */
40
+ export const blogPost = defineContentType({
41
+ name: 'blog-post',
42
+ label: 'Blog Posts',
43
+ singularLabel: 'Blog Post',
44
+ description: 'Blog articles and news posts',
45
+ icon: 'FileText',
46
+ titleField: 'title',
47
+ subtitleField: 'excerpt',
48
+ fields: [
49
+ {
50
+ type: 'text',
51
+ name: 'title',
52
+ label: 'Title',
53
+ description: 'The title of your blog post',
54
+ required: true,
55
+ placeholder: 'Enter post title...',
56
+ minLength: 3,
57
+ maxLength: 200,
58
+ },
59
+ {
60
+ type: 'slug',
61
+ name: 'slug',
62
+ label: 'URL Slug',
63
+ description: 'URL-friendly identifier (auto-generated from title)',
64
+ required: true,
65
+ sourceField: 'title',
66
+ prefix: '/blog/',
67
+ },
68
+ {
69
+ type: 'textarea',
70
+ name: 'excerpt',
71
+ label: 'Excerpt',
72
+ description: 'A short summary shown in post listings',
73
+ placeholder: 'Write a brief summary...',
74
+ rows: 3,
75
+ maxLength: 300,
76
+ },
77
+ {
78
+ type: 'richtext',
79
+ name: 'content',
80
+ label: 'Content',
81
+ description: 'The main content of your blog post',
82
+ required: true,
83
+ },
84
+ {
85
+ type: 'media',
86
+ name: 'featuredImage',
87
+ label: 'Featured Image',
88
+ description: 'Hero image displayed at the top of the post',
89
+ accept: ['image/*'],
90
+ maxSize: 5 * 1024 * 1024, // 5MB
91
+ },
92
+ {
93
+ type: 'select',
94
+ name: 'category',
95
+ label: 'Category',
96
+ description: 'Select a category for this post',
97
+ placeholder: 'Choose category...',
98
+ options: [
99
+ { value: 'news', label: 'News' },
100
+ { value: 'tutorials', label: 'Tutorials' },
101
+ { value: 'announcements', label: 'Announcements' },
102
+ { value: 'case-studies', label: 'Case Studies' },
103
+ { value: 'other', label: 'Other' },
104
+ ],
105
+ },
106
+ {
107
+ type: 'tags',
108
+ name: 'tags',
109
+ label: 'Tags',
110
+ description: 'Add tags to help organize your content',
111
+ placeholder: 'Add a tag...',
112
+ suggestions: ['javascript', 'typescript', 'react', 'aws', 'serverless', 'tutorial'],
113
+ max: 10,
114
+ },
115
+ {
116
+ type: 'datetime',
117
+ name: 'publishedAt',
118
+ label: 'Publish Date',
119
+ description: 'When should this post be published?',
120
+ },
121
+ {
122
+ type: 'boolean',
123
+ name: 'featured',
124
+ label: 'Featured Post',
125
+ description: 'Feature this post on the homepage',
126
+ defaultValue: false,
127
+ },
128
+ ] as const,
129
+ });
130
+
131
+ export type BlogPostData = {
132
+ id: string;
133
+ status: string;
134
+ title: string;
135
+ slug: string;
136
+ excerpt?: string;
137
+ content: string;
138
+ featuredImage?: string;
139
+ category?: string;
140
+ tags?: string[];
141
+ publishedAt?: string;
142
+ featured: boolean;
143
+ createdAt: string;
144
+ updatedAt: string;
145
+ };
146
+ `;
147
+ }
148
+ /**
149
+ * Generates the page content type template.
150
+ *
151
+ * @returns Template string for app/content-types/page.ts
152
+ */
153
+ function getPageContentTypeTemplate() {
154
+ return `/**
155
+ * Page Content Type
156
+ *
157
+ * Defines the structure for static pages in the CMS.
158
+ */
159
+
160
+ import { defineContentType } from '~/lib/content-types';
161
+
162
+ /**
163
+ * Page content type definition.
164
+ *
165
+ * Fields:
166
+ * - title: Page title (required)
167
+ * - slug: URL path (auto-generated from title)
168
+ * - description: SEO description
169
+ * - content: Main page content (rich text)
170
+ * - featuredImage: OG image for social sharing
171
+ * - template: Page template/layout
172
+ * - showInNav: Whether to show in navigation
173
+ * - navOrder: Order in navigation
174
+ */
175
+ export const page = defineContentType({
176
+ name: 'page',
177
+ label: 'Pages',
178
+ singularLabel: 'Page',
179
+ description: 'Static pages like About, Contact, etc.',
180
+ icon: 'File',
181
+ titleField: 'title',
182
+ fields: [
183
+ {
184
+ type: 'text',
185
+ name: 'title',
186
+ label: 'Title',
187
+ description: 'The page title (shown in browser tab and header)',
188
+ required: true,
189
+ placeholder: 'Enter page title...',
190
+ minLength: 2,
191
+ maxLength: 100,
192
+ },
193
+ {
194
+ type: 'slug',
195
+ name: 'slug',
196
+ label: 'URL Path',
197
+ description: 'The URL path for this page (e.g., "about" for /about)',
198
+ required: true,
199
+ sourceField: 'title',
200
+ prefix: '/',
201
+ },
202
+ {
203
+ type: 'textarea',
204
+ name: 'description',
205
+ label: 'Meta Description',
206
+ description: 'SEO description shown in search results',
207
+ placeholder: 'Write a description for search engines...',
208
+ rows: 2,
209
+ maxLength: 160,
210
+ },
211
+ {
212
+ type: 'richtext',
213
+ name: 'content',
214
+ label: 'Content',
215
+ description: 'The main content of the page',
216
+ required: true,
217
+ },
218
+ {
219
+ type: 'media',
220
+ name: 'featuredImage',
221
+ label: 'Social Image',
222
+ description: 'Image shown when page is shared on social media',
223
+ accept: ['image/*'],
224
+ maxSize: 2 * 1024 * 1024, // 2MB
225
+ },
226
+ {
227
+ type: 'select',
228
+ name: 'template',
229
+ label: 'Page Template',
230
+ description: 'Select a layout template for this page',
231
+ placeholder: 'Choose template...',
232
+ options: [
233
+ { value: 'default', label: 'Default' },
234
+ { value: 'full-width', label: 'Full Width' },
235
+ { value: 'sidebar', label: 'With Sidebar' },
236
+ { value: 'landing', label: 'Landing Page' },
237
+ ],
238
+ defaultValue: 'default',
239
+ },
240
+ {
241
+ type: 'boolean',
242
+ name: 'showInNav',
243
+ label: 'Show in Navigation',
244
+ description: 'Include this page in the main navigation menu',
245
+ defaultValue: false,
246
+ },
247
+ {
248
+ type: 'number',
249
+ name: 'navOrder',
250
+ label: 'Navigation Order',
251
+ description: 'Order in the navigation menu (lower = earlier)',
252
+ min: 0,
253
+ max: 100,
254
+ defaultValue: 50,
255
+ },
256
+ ] as const,
257
+ });
258
+
259
+ export type PageData = {
260
+ id: string;
261
+ status: string;
262
+ title: string;
263
+ slug: string;
264
+ description?: string;
265
+ content: string;
266
+ featuredImage?: string;
267
+ template?: string;
268
+ showInNav: boolean;
269
+ navOrder: number;
270
+ createdAt: string;
271
+ updatedAt: string;
272
+ };
273
+ `;
274
+ }
275
+ //# sourceMappingURL=content-types-examples.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-types-examples.js","sourceRoot":"","sources":["../../src/templates/content-types-examples.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAOH,wEAmIC;AAOD,gEAyHC;AAxQD;;;;GAIG;AACH,SAAgB,8BAA8B;IAC5C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiIR,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,SAAgB,0BAA0B;IACxC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuHR,CAAC;AACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Generates the content types registry template.
3
+ *
4
+ * This template provides a registry for managing content types
5
+ * and provides functions to access them.
6
+ *
7
+ * @returns Template string for app/content-types/index.ts
8
+ */
9
+ export declare function getContentTypesRegistryTemplate(): string;
10
+ //# sourceMappingURL=content-types-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-types-registry.d.ts","sourceRoot":"","sources":["../../src/templates/content-types-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,CA0ExD"}
@@ -0,0 +1,87 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.getContentTypesRegistryTemplate = getContentTypesRegistryTemplate;
4
+ /**
5
+ * Generates the content types registry template.
6
+ *
7
+ * This template provides a registry for managing content types
8
+ * and provides functions to access them.
9
+ *
10
+ * @returns Template string for app/content-types/index.ts
11
+ */
12
+ function getContentTypesRegistryTemplate() {
13
+ return `/**
14
+ * Content Types Registry
15
+ *
16
+ * This module provides a central registry for all content types
17
+ * and utilities for accessing them.
18
+ */
19
+
20
+ import type { ContentType } from '~/lib/content-types';
21
+ import { blogPost } from './blog-post';
22
+ import { page } from './page';
23
+
24
+ // ============================================================================
25
+ // Registry
26
+ // ============================================================================
27
+
28
+ /**
29
+ * Registry of all content types.
30
+ */
31
+ const contentTypeRegistry = new Map<string, ContentType>();
32
+
33
+ /**
34
+ * Register a content type in the registry.
35
+ */
36
+ export function registerContentType(contentType: ContentType): void {
37
+ if (contentTypeRegistry.has(contentType.name)) {
38
+ console.warn(\`Content type "\${contentType.name}" is already registered. Overwriting.\`);
39
+ }
40
+ contentTypeRegistry.set(contentType.name, contentType);
41
+ }
42
+
43
+ /**
44
+ * Get a content type by name.
45
+ */
46
+ export function getContentType(name: string): ContentType | undefined {
47
+ return contentTypeRegistry.get(name);
48
+ }
49
+
50
+ /**
51
+ * Get all registered content types.
52
+ */
53
+ export function getAllContentTypes(): ContentType[] {
54
+ return Array.from(contentTypeRegistry.values());
55
+ }
56
+
57
+ /**
58
+ * Check if a content type exists.
59
+ */
60
+ export function hasContentType(name: string): boolean {
61
+ return contentTypeRegistry.has(name);
62
+ }
63
+
64
+ /**
65
+ * Get content type names.
66
+ */
67
+ export function getContentTypeNames(): string[] {
68
+ return Array.from(contentTypeRegistry.keys());
69
+ }
70
+
71
+ // ============================================================================
72
+ // Register Default Content Types
73
+ // ============================================================================
74
+
75
+ // Register the built-in content types
76
+ registerContentType(blogPost);
77
+ registerContentType(page);
78
+
79
+ // ============================================================================
80
+ // Exports
81
+ // ============================================================================
82
+
83
+ export { blogPost } from './blog-post';
84
+ export { page } from './page';
85
+ `;
86
+ }
87
+ //# sourceMappingURL=content-types-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-types-registry.js","sourceRoot":"","sources":["../../src/templates/content-types-registry.ts"],"names":[],"mappings":";;AAQA,0EA0EC;AAlFD;;;;;;;GAOG;AACH,SAAgB,+BAA+B;IAC7C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwER,CAAC;AACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Generates the content types definition template.
3
+ *
4
+ * This template provides the `defineContentType()` helper function and
5
+ * TypeScript interfaces for defining custom content structures.
6
+ *
7
+ * @returns Template string for app/lib/content-types.ts
8
+ */
9
+ export declare function getContentTypesTemplate(): string;
10
+ //# sourceMappingURL=content-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-types.d.ts","sourceRoot":"","sources":["../../src/templates/content-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAmXhD"}