@nextsparkjs/theme-blog 0.1.0-beta.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 (64) hide show
  1. package/README.md +65 -0
  2. package/about.md +93 -0
  3. package/api/authors/[username]/route.ts +150 -0
  4. package/api/authors/route.ts +63 -0
  5. package/api/posts/public/route.ts +151 -0
  6. package/components/ExportPostsButton.tsx +102 -0
  7. package/components/ImportPostsDialog.tsx +284 -0
  8. package/components/PostsToolbar.tsx +24 -0
  9. package/components/editor/FeaturedImageUpload.tsx +185 -0
  10. package/components/editor/WysiwygEditor.tsx +340 -0
  11. package/components/index.ts +4 -0
  12. package/components/public/AuthorBio.tsx +105 -0
  13. package/components/public/AuthorCard.tsx +130 -0
  14. package/components/public/BlogFooter.tsx +185 -0
  15. package/components/public/BlogNavbar.tsx +201 -0
  16. package/components/public/PostCard.tsx +306 -0
  17. package/components/public/ReadingProgress.tsx +70 -0
  18. package/components/public/RelatedPosts.tsx +78 -0
  19. package/config/app.config.ts +200 -0
  20. package/config/billing.config.ts +146 -0
  21. package/config/dashboard.config.ts +333 -0
  22. package/config/dev.config.ts +48 -0
  23. package/config/features.config.ts +196 -0
  24. package/config/flows.config.ts +333 -0
  25. package/config/permissions.config.ts +101 -0
  26. package/config/theme.config.ts +128 -0
  27. package/entities/categories/categories.config.ts +60 -0
  28. package/entities/categories/categories.fields.ts +115 -0
  29. package/entities/categories/categories.service.ts +333 -0
  30. package/entities/categories/categories.types.ts +58 -0
  31. package/entities/categories/messages/en.json +33 -0
  32. package/entities/categories/messages/es.json +33 -0
  33. package/entities/posts/messages/en.json +100 -0
  34. package/entities/posts/messages/es.json +100 -0
  35. package/entities/posts/migrations/001_posts_table.sql +110 -0
  36. package/entities/posts/migrations/002_add_featured.sql +19 -0
  37. package/entities/posts/migrations/003_post_categories_pivot.sql +47 -0
  38. package/entities/posts/posts.config.ts +61 -0
  39. package/entities/posts/posts.fields.ts +234 -0
  40. package/entities/posts/posts.service.ts +464 -0
  41. package/entities/posts/posts.types.ts +80 -0
  42. package/lib/selectors.ts +179 -0
  43. package/messages/en.json +113 -0
  44. package/messages/es.json +113 -0
  45. package/migrations/002_author_profile_fields.sql +37 -0
  46. package/migrations/003_categories_table.sql +90 -0
  47. package/migrations/999_sample_data.sql +412 -0
  48. package/migrations/999_theme_sample_data.sql +1070 -0
  49. package/package.json +18 -0
  50. package/permissions-matrix.md +63 -0
  51. package/styles/article.css +333 -0
  52. package/styles/components.css +204 -0
  53. package/styles/globals.css +327 -0
  54. package/styles/theme.css +167 -0
  55. package/templates/(public)/author/[username]/page.tsx +247 -0
  56. package/templates/(public)/authors/page.tsx +161 -0
  57. package/templates/(public)/layout.tsx +44 -0
  58. package/templates/(public)/page.tsx +276 -0
  59. package/templates/(public)/posts/[slug]/page.tsx +342 -0
  60. package/templates/dashboard/(main)/page.tsx +385 -0
  61. package/templates/dashboard/(main)/posts/[id]/edit/page.tsx +529 -0
  62. package/templates/dashboard/(main)/posts/[id]/page.tsx +33 -0
  63. package/templates/dashboard/(main)/posts/create/page.tsx +353 -0
  64. package/templates/dashboard/(main)/posts/page.tsx +833 -0
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Blog Theme - Flows Configuration
3
+ *
4
+ * Defines user journeys/flows that span multiple features.
5
+ * Each flow key becomes a tag: @flow-{key}
6
+ *
7
+ * Flows are enriched at build-time with:
8
+ * - Feature metadata (from features.config.ts)
9
+ * - Test coverage (from tags-registry + test files)
10
+ */
11
+
12
+ import { defineFlows } from '@nextsparkjs/core/lib/config/features-types'
13
+
14
+ export default defineFlows({
15
+ // ===========================================================================
16
+ // ACQUISITION FLOWS
17
+ // User acquisition and onboarding journeys
18
+ // ===========================================================================
19
+
20
+ onboarding: {
21
+ name: 'Author Onboarding',
22
+ description: 'Complete journey from signup to first published post',
23
+ category: 'acquisition',
24
+ icon: 'rocket',
25
+ criticalPath: true,
26
+
27
+ steps: [
28
+ {
29
+ feature: 'auth',
30
+ action: 'signup',
31
+ description: 'Author creates account with email/password',
32
+ },
33
+ {
34
+ feature: 'auth',
35
+ action: 'verify-email',
36
+ description: 'Author verifies email address',
37
+ },
38
+ {
39
+ feature: 'users',
40
+ action: 'setup-profile',
41
+ description: 'Author sets up their profile (bio, avatar)',
42
+ optional: true,
43
+ },
44
+ {
45
+ feature: 'posts',
46
+ action: 'create-first-post',
47
+ description: 'Author creates their first blog post',
48
+ },
49
+ ],
50
+
51
+ features: ['auth', 'users', 'posts'],
52
+ },
53
+
54
+ // ===========================================================================
55
+ // CONTENT CREATION FLOWS
56
+ // Post creation and publishing journeys
57
+ // ===========================================================================
58
+
59
+ 'create-post': {
60
+ name: 'Create Post',
61
+ description: 'Complete journey to create and publish a blog post',
62
+ category: 'content',
63
+ icon: 'edit',
64
+ criticalPath: true,
65
+
66
+ steps: [
67
+ {
68
+ feature: 'posts',
69
+ action: 'create-draft',
70
+ description: 'Author creates a new draft post',
71
+ },
72
+ {
73
+ feature: 'post-editor',
74
+ action: 'write-content',
75
+ description: 'Author writes post content using the editor',
76
+ },
77
+ {
78
+ feature: 'post-editor',
79
+ action: 'add-featured-image',
80
+ description: 'Author adds featured image',
81
+ optional: true,
82
+ },
83
+ {
84
+ feature: 'categories',
85
+ action: 'assign-category',
86
+ description: 'Author assigns categories to the post',
87
+ optional: true,
88
+ },
89
+ {
90
+ feature: 'publishing',
91
+ action: 'publish',
92
+ description: 'Author publishes the post',
93
+ },
94
+ ],
95
+
96
+ features: ['posts', 'post-editor', 'categories', 'publishing'],
97
+ },
98
+
99
+ 'edit-post': {
100
+ name: 'Edit Post',
101
+ description: 'Edit and update an existing post',
102
+ category: 'content',
103
+ icon: 'pencil',
104
+ criticalPath: false,
105
+
106
+ steps: [
107
+ {
108
+ feature: 'posts',
109
+ action: 'select-post',
110
+ description: 'Author selects a post to edit',
111
+ },
112
+ {
113
+ feature: 'post-editor',
114
+ action: 'modify-content',
115
+ description: 'Author modifies post content',
116
+ },
117
+ {
118
+ feature: 'posts',
119
+ action: 'save-changes',
120
+ description: 'Author saves the updated post',
121
+ },
122
+ ],
123
+
124
+ features: ['posts', 'post-editor'],
125
+ },
126
+
127
+ // ===========================================================================
128
+ // PUBLISHING FLOWS
129
+ // Content publishing workflows
130
+ // ===========================================================================
131
+
132
+ 'publish-workflow': {
133
+ name: 'Publishing Workflow',
134
+ description: 'Manage post status from draft to published',
135
+ category: 'content',
136
+ icon: 'send',
137
+ criticalPath: true,
138
+
139
+ steps: [
140
+ {
141
+ feature: 'posts',
142
+ action: 'review-draft',
143
+ description: 'Author reviews draft post',
144
+ },
145
+ {
146
+ feature: 'publishing',
147
+ action: 'set-publish-date',
148
+ description: 'Author sets publish date (optional)',
149
+ optional: true,
150
+ },
151
+ {
152
+ feature: 'publishing',
153
+ action: 'publish',
154
+ description: 'Author publishes the post',
155
+ },
156
+ ],
157
+
158
+ features: ['posts', 'publishing'],
159
+ },
160
+
161
+ unpublish: {
162
+ name: 'Unpublish Post',
163
+ description: 'Take a published post offline',
164
+ category: 'content',
165
+ icon: 'eye-off',
166
+ criticalPath: false,
167
+
168
+ steps: [
169
+ {
170
+ feature: 'posts',
171
+ action: 'select-published-post',
172
+ description: 'Author selects a published post',
173
+ },
174
+ {
175
+ feature: 'publishing',
176
+ action: 'unpublish',
177
+ description: 'Author unpublishes the post (reverts to draft)',
178
+ },
179
+ ],
180
+
181
+ features: ['posts', 'publishing'],
182
+ },
183
+
184
+ // ===========================================================================
185
+ // DATA MANAGEMENT FLOWS
186
+ // Import/export workflows
187
+ // ===========================================================================
188
+
189
+ 'export-content': {
190
+ name: 'Export Content',
191
+ description: 'Export blog content for backup or migration',
192
+ category: 'settings',
193
+ icon: 'download',
194
+ criticalPath: false,
195
+
196
+ steps: [
197
+ {
198
+ feature: 'post-export',
199
+ action: 'select-content',
200
+ description: 'Author selects content to export',
201
+ },
202
+ {
203
+ feature: 'post-export',
204
+ action: 'export',
205
+ description: 'Author downloads the exported JSON file',
206
+ },
207
+ ],
208
+
209
+ features: ['post-export'],
210
+ },
211
+
212
+ 'import-content': {
213
+ name: 'Import Content',
214
+ description: 'Import blog content from backup file',
215
+ category: 'settings',
216
+ icon: 'upload',
217
+ criticalPath: false,
218
+
219
+ steps: [
220
+ {
221
+ feature: 'post-import',
222
+ action: 'select-file',
223
+ description: 'Author selects JSON file to import',
224
+ },
225
+ {
226
+ feature: 'post-import',
227
+ action: 'review-content',
228
+ description: 'Author reviews content to be imported',
229
+ },
230
+ {
231
+ feature: 'post-import',
232
+ action: 'confirm-import',
233
+ description: 'Author confirms and executes import',
234
+ },
235
+ ],
236
+
237
+ features: ['post-import'],
238
+ },
239
+
240
+ // ===========================================================================
241
+ // PUBLIC READING FLOWS
242
+ // Reader-facing journeys
243
+ // ===========================================================================
244
+
245
+ 'read-post': {
246
+ name: 'Read Post',
247
+ description: 'Public reader views a blog post',
248
+ category: 'public',
249
+ icon: 'book-open',
250
+ criticalPath: true,
251
+
252
+ steps: [
253
+ {
254
+ feature: 'public-blog',
255
+ action: 'browse-posts',
256
+ description: 'Reader browses blog homepage or category',
257
+ },
258
+ {
259
+ feature: 'public-blog',
260
+ action: 'select-post',
261
+ description: 'Reader clicks on a post to read',
262
+ },
263
+ {
264
+ feature: 'public-blog',
265
+ action: 'read-content',
266
+ description: 'Reader reads the full post content',
267
+ },
268
+ ],
269
+
270
+ features: ['public-blog'],
271
+ },
272
+
273
+ 'view-author': {
274
+ name: 'View Author',
275
+ description: 'Reader views an author profile and their posts',
276
+ category: 'public',
277
+ icon: 'user',
278
+ criticalPath: false,
279
+
280
+ steps: [
281
+ {
282
+ feature: 'authors',
283
+ action: 'view-profile',
284
+ description: 'Reader views author profile page',
285
+ },
286
+ {
287
+ feature: 'authors',
288
+ action: 'browse-author-posts',
289
+ description: 'Reader browses posts by this author',
290
+ },
291
+ ],
292
+
293
+ features: ['authors', 'public-blog'],
294
+ },
295
+
296
+ // ===========================================================================
297
+ // BILLING FLOWS
298
+ // Subscription and payment journeys
299
+ // ===========================================================================
300
+
301
+ 'upgrade-plan': {
302
+ name: 'Upgrade Plan',
303
+ description: 'Upgrade subscription to a higher tier plan',
304
+ category: 'settings',
305
+ icon: 'trending-up',
306
+ criticalPath: false,
307
+
308
+ steps: [
309
+ {
310
+ feature: 'plans',
311
+ action: 'view-plans',
312
+ description: 'Author views available plans',
313
+ },
314
+ {
315
+ feature: 'plans',
316
+ action: 'select-plan',
317
+ description: 'Author selects a new plan',
318
+ },
319
+ {
320
+ feature: 'billing',
321
+ action: 'enter-payment',
322
+ description: 'Author enters payment information',
323
+ },
324
+ {
325
+ feature: 'billing',
326
+ action: 'confirm-upgrade',
327
+ description: 'Author confirms the upgrade',
328
+ },
329
+ ],
330
+
331
+ features: ['plans', 'billing'],
332
+ },
333
+ })
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Blog Theme - Permissions Configuration
3
+ *
4
+ * SINGLE SOURCE OF TRUTH for all permissions and roles in this theme.
5
+ *
6
+ * This file defines:
7
+ * - entities: Entity CRUD permissions (posts, categories)
8
+ * - features: Theme-specific feature permissions (export, import)
9
+ *
10
+ * All sections use unified format: { action: '...', roles: [...] }
11
+ *
12
+ * Single-user blog permissions:
13
+ * - Owner has all permissions
14
+ * - Team collaboration features are disabled
15
+ * - Export/Import features enabled
16
+ *
17
+ * Use PermissionService.canDoAction(role, action) to check any permission.
18
+ */
19
+
20
+ import type { ThemePermissionsConfig } from '@nextsparkjs/core/lib/permissions/types'
21
+
22
+ export const PERMISSIONS_CONFIG_OVERRIDES: ThemePermissionsConfig = {
23
+ // ==========================================
24
+ // ENTITY PERMISSIONS
25
+ // ==========================================
26
+ // Single-user mode: only owner role
27
+ entities: {
28
+ // ------------------------------------------
29
+ // POSTS
30
+ // ------------------------------------------
31
+ posts: [
32
+ { action: 'create', label: 'Create posts', description: 'Can create new blog posts', roles: ['owner'] },
33
+ { action: 'read', label: 'View posts', description: 'Can view post details', roles: ['owner'] },
34
+ { action: 'list', label: 'List posts', description: 'Can see the posts list', roles: ['owner'] },
35
+ { action: 'update', label: 'Edit posts', description: 'Can modify post content', roles: ['owner'] },
36
+ { action: 'delete', label: 'Delete posts', description: 'Can delete posts', roles: ['owner'], dangerous: true },
37
+ { action: 'publish', label: 'Publish posts', description: 'Can publish posts to make them public', roles: ['owner'] },
38
+ { action: 'unpublish', label: 'Unpublish posts', description: 'Can unpublish posts to hide them', roles: ['owner'] },
39
+ ],
40
+
41
+ // ------------------------------------------
42
+ // CATEGORIES
43
+ // ------------------------------------------
44
+ categories: [
45
+ { action: 'create', label: 'Create categories', description: 'Can create new categories', roles: ['owner'] },
46
+ { action: 'read', label: 'View categories', description: 'Can view category details', roles: ['owner'] },
47
+ { action: 'list', label: 'List categories', description: 'Can see the categories list', roles: ['owner'] },
48
+ { action: 'update', label: 'Edit categories', description: 'Can modify category information', roles: ['owner'] },
49
+ { action: 'delete', label: 'Delete categories', description: 'Can delete categories', roles: ['owner'], dangerous: true },
50
+ ],
51
+ },
52
+
53
+ // ==========================================
54
+ // FEATURE PERMISSIONS
55
+ // ==========================================
56
+ // Unified format: uses 'action' instead of 'id'
57
+ features: [
58
+ {
59
+ action: 'blog.export',
60
+ label: 'Export posts',
61
+ description: 'Export all posts to JSON format for backup or migration',
62
+ category: 'Blog',
63
+ roles: ['owner'],
64
+ },
65
+ {
66
+ action: 'blog.import',
67
+ label: 'Import posts',
68
+ description: 'Import posts from JSON file',
69
+ category: 'Blog',
70
+ roles: ['owner'],
71
+ dangerous: true,
72
+ },
73
+ ],
74
+
75
+ // ==========================================
76
+ // DISABLED FEATURES
77
+ // ==========================================
78
+ // These don't apply in single-user mode
79
+ disabled: [
80
+ 'teams.invite',
81
+ 'teams.remove_member',
82
+ 'teams.change_roles',
83
+ 'teams.delete',
84
+ 'settings.api_keys',
85
+ 'settings.billing',
86
+ ],
87
+
88
+ // ==========================================
89
+ // UI SECTIONS
90
+ // ==========================================
91
+ uiSections: [
92
+ {
93
+ id: 'blog-features',
94
+ label: 'Blog Features',
95
+ description: 'Permissions for blog-specific functionality',
96
+ categories: ['Blog'],
97
+ },
98
+ ],
99
+ }
100
+
101
+ export default PERMISSIONS_CONFIG_OVERRIDES
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Blog Theme Configuration
3
+ *
4
+ * A simple personal blog theme with single-user mode.
5
+ * No collaboration, just a writer and their content.
6
+ */
7
+
8
+ import type { ThemeConfig } from '@nextsparkjs/core/types/theme'
9
+
10
+ export const blogThemeConfig: ThemeConfig = {
11
+ name: 'blog',
12
+ displayName: 'Personal Blog',
13
+ version: '2.0.0',
14
+ description: 'A multi-author blog platform with single-user mode',
15
+ author: 'NextSpark Team',
16
+
17
+ // Teams configuration for multi-author platform with single-user mode
18
+ teams: {
19
+ mode: 'single-user',
20
+ options: {
21
+ maxTeamsPerUser: 1,
22
+ maxMembersPerTeam: 1,
23
+ allowLeaveAllTeams: false
24
+ }
25
+ },
26
+
27
+ plugins: [],
28
+
29
+ // Styles configuration
30
+ styles: {
31
+ globals: 'globals.css',
32
+ components: 'components.css',
33
+ variables: {
34
+ '--spacing-xs': '0.125rem',
35
+ '--spacing-sm': '0.25rem',
36
+ '--spacing-md': '0.5rem',
37
+ '--spacing-lg': '1rem',
38
+ '--spacing-xl': '1.5rem',
39
+ '--spacing-2xl': '2rem'
40
+ }
41
+ },
42
+
43
+ // Google Fonts for editorial typography
44
+ fonts: [
45
+ { family: 'Oxanium', weights: ['400', '500', '600', '700'] },
46
+ { family: 'Merriweather', weights: ['400', '700'], styles: ['normal', 'italic'] },
47
+ { family: 'Fira Code', weights: ['400', '500'] }
48
+ ],
49
+
50
+ // Theme configuration - warm amber/orange editorial aesthetic
51
+ config: {
52
+ colors: {
53
+ // Warm cream background
54
+ background: 'oklch(0.9885 0.0057 84.5659)',
55
+ foreground: 'oklch(0.3660 0.0251 49.6085)',
56
+ card: 'oklch(0.9686 0.0091 78.2818)',
57
+ 'card-foreground': 'oklch(0.3660 0.0251 49.6085)',
58
+ popover: 'oklch(0.9686 0.0091 78.2818)',
59
+ 'popover-foreground': 'oklch(0.3660 0.0251 49.6085)',
60
+ // Warm amber primary
61
+ primary: 'oklch(0.5553 0.1455 48.9975)',
62
+ 'primary-foreground': 'oklch(1.0000 0 0)',
63
+ secondary: 'oklch(0.8276 0.0752 74.4400)',
64
+ 'secondary-foreground': 'oklch(0.4444 0.0096 73.6390)',
65
+ muted: 'oklch(0.9363 0.0218 83.2637)',
66
+ 'muted-foreground': 'oklch(0.5534 0.0116 58.0708)',
67
+ accent: 'oklch(0.9000 0.0500 74.9889)',
68
+ 'accent-foreground': 'oklch(0.4444 0.0096 73.6390)',
69
+ destructive: 'oklch(0.4437 0.1613 26.8994)',
70
+ 'destructive-foreground': 'oklch(1.0000 0 0)',
71
+ border: 'oklch(0.8866 0.0404 89.6994)',
72
+ input: 'oklch(0.8866 0.0404 89.6994)',
73
+ ring: 'oklch(0.5553 0.1455 48.9975)',
74
+
75
+ // Chart colors
76
+ 'chart-1': 'oklch(0.5553 0.1455 48.9975)',
77
+ 'chart-2': 'oklch(0.5534 0.0116 58.0708)',
78
+ 'chart-3': 'oklch(0.5538 0.1207 66.4416)',
79
+ 'chart-4': 'oklch(0.5534 0.0116 58.0708)',
80
+ 'chart-5': 'oklch(0.6806 0.1423 75.8340)',
81
+
82
+ // Sidebar
83
+ sidebar: 'oklch(0.9363 0.0218 83.2637)',
84
+ 'sidebar-foreground': 'oklch(0.3660 0.0251 49.6085)',
85
+ 'sidebar-primary': 'oklch(0.5553 0.1455 48.9975)',
86
+ 'sidebar-primary-foreground': 'oklch(1.0000 0 0)',
87
+ 'sidebar-accent': 'oklch(0.5538 0.1207 66.4416)',
88
+ 'sidebar-accent-foreground': 'oklch(1.0000 0 0)',
89
+ 'sidebar-border': 'oklch(0.8866 0.0404 89.6994)',
90
+ 'sidebar-ring': 'oklch(0.5553 0.1455 48.9975)'
91
+ },
92
+
93
+ // Typography - Oxanium for UI, Merriweather for content
94
+ fonts: {
95
+ sans: 'Oxanium, sans-serif',
96
+ serif: 'Merriweather, serif',
97
+ mono: 'Fira Code, monospace'
98
+ },
99
+
100
+ // Small radius for clean look
101
+ spacing: {
102
+ radius: '0.3rem',
103
+ 'radius-sm': 'calc(0.3rem - 4px)',
104
+ 'radius-md': 'calc(0.3rem - 2px)',
105
+ 'radius-lg': '0.3rem',
106
+ 'radius-xl': 'calc(0.3rem + 4px)'
107
+ },
108
+
109
+ // Warm shadows
110
+ breakpoints: {
111
+ 'shadow-2xs': '0px 2px 3px 0px hsl(28 18% 25% / 0.09)',
112
+ 'shadow-xs': '0px 2px 3px 0px hsl(28 18% 25% / 0.09)',
113
+ 'shadow-sm': '0px 2px 3px 0px hsl(28 18% 25% / 0.18), 0px 1px 2px -1px hsl(28 18% 25% / 0.18)',
114
+ shadow: '0px 2px 3px 0px hsl(28 18% 25% / 0.18), 0px 1px 2px -1px hsl(28 18% 25% / 0.18)',
115
+ 'shadow-md': '0px 2px 3px 0px hsl(28 18% 25% / 0.18), 0px 2px 4px -1px hsl(28 18% 25% / 0.18)',
116
+ 'shadow-lg': '0px 2px 3px 0px hsl(28 18% 25% / 0.18), 0px 4px 6px -1px hsl(28 18% 25% / 0.18)',
117
+ 'shadow-xl': '0px 2px 3px 0px hsl(28 18% 25% / 0.18), 0px 8px 10px -1px hsl(28 18% 25% / 0.18)',
118
+ 'shadow-2xl': '0px 2px 3px 0px hsl(28 18% 25% / 0.45)'
119
+ }
120
+ },
121
+
122
+ components: {
123
+ overrides: {},
124
+ custom: {}
125
+ }
126
+ }
127
+
128
+ export default blogThemeConfig
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Categories Entity Configuration
3
+ *
4
+ * Categories for blog posts in the multi-author platform.
5
+ */
6
+
7
+ import { Tag } from 'lucide-react'
8
+ import type { EntityConfig } from '@nextsparkjs/core/lib/entities/types'
9
+ import { categoryFields } from './categories.fields'
10
+
11
+ export const categoryEntityConfig: EntityConfig = {
12
+ // ==========================================
13
+ // 1. BASIC IDENTIFICATION
14
+ // ==========================================
15
+ slug: 'categories',
16
+ enabled: true,
17
+ names: {
18
+ singular: 'category',
19
+ plural: 'Categories'
20
+ },
21
+ icon: Tag,
22
+
23
+ // ==========================================
24
+ // 2. ACCESS AND SCOPE CONFIGURATION
25
+ // ==========================================
26
+ access: {
27
+ public: true, // Categories are publicly accessible
28
+ api: true, // API access enabled
29
+ metadata: false, // No metadata needed
30
+ shared: false // User-owned categories (each user manages their own)
31
+ },
32
+
33
+ // ==========================================
34
+ // 3. UI/UX FEATURES
35
+ // ==========================================
36
+ ui: {
37
+ dashboard: {
38
+ showInMenu: true,
39
+ showInTopbar: false
40
+ },
41
+ public: {
42
+ hasArchivePage: false, // No dedicated archive page
43
+ hasSinglePage: true // /category/[slug] - posts by category
44
+ },
45
+ features: {
46
+ searchable: true,
47
+ sortable: true,
48
+ filterable: false,
49
+ bulkOperations: true,
50
+ importExport: false
51
+ }
52
+ },
53
+
54
+ // ==========================================
55
+ // FIELDS
56
+ // ==========================================
57
+ fields: categoryFields,
58
+ }
59
+
60
+ export default categoryEntityConfig