@nextsparkjs/theme-productivity 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 (57) hide show
  1. package/README.md +76 -0
  2. package/about.md +123 -0
  3. package/components/CardDetailModal.tsx +318 -0
  4. package/components/KanbanBoard.tsx +612 -0
  5. package/components/KanbanCard.tsx +218 -0
  6. package/components/KanbanColumn.tsx +264 -0
  7. package/components/SortableList.tsx +46 -0
  8. package/components/index.ts +4 -0
  9. package/config/app.config.ts +172 -0
  10. package/config/billing.config.ts +187 -0
  11. package/config/dashboard.config.ts +357 -0
  12. package/config/dev.config.ts +55 -0
  13. package/config/features.config.ts +256 -0
  14. package/config/flows.config.ts +484 -0
  15. package/config/permissions.config.ts +167 -0
  16. package/config/theme.config.ts +106 -0
  17. package/entities/boards/boards.config.ts +61 -0
  18. package/entities/boards/boards.fields.ts +154 -0
  19. package/entities/boards/boards.service.ts +256 -0
  20. package/entities/boards/boards.types.ts +57 -0
  21. package/entities/boards/messages/en.json +80 -0
  22. package/entities/boards/messages/es.json +80 -0
  23. package/entities/boards/migrations/001_boards_table.sql +83 -0
  24. package/entities/cards/cards.config.ts +61 -0
  25. package/entities/cards/cards.fields.ts +242 -0
  26. package/entities/cards/cards.service.ts +336 -0
  27. package/entities/cards/cards.types.ts +79 -0
  28. package/entities/cards/messages/en.json +114 -0
  29. package/entities/cards/messages/es.json +114 -0
  30. package/entities/cards/migrations/020_cards_table.sql +92 -0
  31. package/entities/lists/lists.config.ts +61 -0
  32. package/entities/lists/lists.fields.ts +105 -0
  33. package/entities/lists/lists.service.ts +252 -0
  34. package/entities/lists/lists.types.ts +55 -0
  35. package/entities/lists/messages/en.json +60 -0
  36. package/entities/lists/messages/es.json +60 -0
  37. package/entities/lists/migrations/010_lists_table.sql +79 -0
  38. package/lib/selectors.ts +206 -0
  39. package/messages/en.json +79 -0
  40. package/messages/es.json +79 -0
  41. package/migrations/999_theme_sample_data.sql +922 -0
  42. package/migrations/999a_initial_sample_data.sql +377 -0
  43. package/migrations/999b_abundant_sample_data.sql +346 -0
  44. package/package.json +17 -0
  45. package/permissions-matrix.md +122 -0
  46. package/styles/components.css +460 -0
  47. package/styles/globals.css +560 -0
  48. package/templates/dashboard/(main)/boards/[id]/[cardId]/page.tsx +238 -0
  49. package/templates/dashboard/(main)/boards/[id]/edit/page.tsx +390 -0
  50. package/templates/dashboard/(main)/boards/[id]/page.tsx +236 -0
  51. package/templates/dashboard/(main)/boards/create/page.tsx +236 -0
  52. package/templates/dashboard/(main)/boards/page.tsx +335 -0
  53. package/templates/dashboard/(main)/layout.tsx +32 -0
  54. package/templates/dashboard/(main)/page.tsx +592 -0
  55. package/templates/shared/ProductivityMobileNav.tsx +410 -0
  56. package/templates/shared/ProductivitySidebar.tsx +538 -0
  57. package/templates/shared/ProductivityTopBar.tsx +317 -0
@@ -0,0 +1,80 @@
1
+ {
2
+ "title": "Tableros",
3
+ "singular": "Tablero",
4
+ "plural": "Tableros",
5
+ "description": "Organiza tu trabajo en tableros",
6
+
7
+ "fields": {
8
+ "name": {
9
+ "label": "Nombre",
10
+ "placeholder": "Ingresa el nombre del tablero...",
11
+ "description": "Nombre del tablero"
12
+ },
13
+ "description": {
14
+ "label": "Descripción",
15
+ "placeholder": "Describe para qué es este tablero...",
16
+ "description": "Descripción opcional del tablero"
17
+ },
18
+ "color": {
19
+ "label": "Color",
20
+ "placeholder": "Seleccionar color...",
21
+ "description": "Color de fondo del tablero",
22
+ "options": {
23
+ "blue": "Azul",
24
+ "green": "Verde",
25
+ "purple": "Morado",
26
+ "orange": "Naranja",
27
+ "red": "Rojo",
28
+ "pink": "Rosa",
29
+ "gray": "Gris"
30
+ }
31
+ },
32
+ "archived": {
33
+ "label": "Archivado",
34
+ "description": "Archivar este tablero"
35
+ },
36
+ "position": {
37
+ "label": "Posición",
38
+ "description": "Orden de visualización"
39
+ },
40
+ "createdAt": {
41
+ "label": "Creado",
42
+ "description": "Cuándo se creó el tablero"
43
+ },
44
+ "updatedAt": {
45
+ "label": "Actualizado",
46
+ "description": "Cuándo se modificó por última vez"
47
+ }
48
+ },
49
+
50
+ "actions": {
51
+ "create": "Nuevo Tablero",
52
+ "edit": "Editar Tablero",
53
+ "delete": "Eliminar Tablero",
54
+ "archive": "Archivar Tablero",
55
+ "unarchive": "Desarchivar Tablero",
56
+ "duplicate": "Duplicar Tablero"
57
+ },
58
+
59
+ "messages": {
60
+ "created": "Tablero creado exitosamente",
61
+ "updated": "Tablero actualizado exitosamente",
62
+ "deleted": "Tablero eliminado exitosamente",
63
+ "archived": "Tablero archivado",
64
+ "unarchived": "Tablero desarchivado",
65
+ "confirmDelete": "¿Estás seguro de que quieres eliminar este tablero? Todas las listas y tarjetas serán eliminadas permanentemente."
66
+ },
67
+
68
+ "empty": {
69
+ "title": "Aún no hay tableros",
70
+ "description": "Crea tu primer tablero para comenzar a organizar tu trabajo.",
71
+ "action": "Crear tu primer tablero"
72
+ },
73
+
74
+ "filters": {
75
+ "all": "Todos los Tableros",
76
+ "active": "Activos",
77
+ "archived": "Archivados"
78
+ }
79
+ }
80
+
@@ -0,0 +1,83 @@
1
+ -- ============================================================================
2
+ -- Boards Table Migration
3
+ -- Productivity theme: Trello-style boards
4
+ -- ============================================================================
5
+
6
+ CREATE TABLE IF NOT EXISTS "boards" (
7
+ "id" TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
8
+ "name" VARCHAR(255) NOT NULL,
9
+ "description" TEXT,
10
+ "color" VARCHAR(20) DEFAULT 'blue',
11
+ "archived" BOOLEAN DEFAULT FALSE,
12
+ "position" INTEGER DEFAULT 0,
13
+ "userId" TEXT NOT NULL REFERENCES "users"("id") ON DELETE CASCADE,
14
+ "teamId" TEXT NOT NULL REFERENCES "teams"("id") ON DELETE CASCADE,
15
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
16
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW()
17
+ );
18
+
19
+ -- Indexes
20
+ CREATE INDEX IF NOT EXISTS "boards_teamId_idx" ON "boards" ("teamId");
21
+ CREATE INDEX IF NOT EXISTS "boards_userId_idx" ON "boards" ("userId");
22
+ CREATE INDEX IF NOT EXISTS "boards_archived_idx" ON "boards" ("archived") WHERE "archived" = FALSE;
23
+ CREATE INDEX IF NOT EXISTS "boards_position_idx" ON "boards" ("teamId", "position");
24
+
25
+ -- Enable RLS
26
+ ALTER TABLE "boards" ENABLE ROW LEVEL SECURITY;
27
+
28
+ -- Drop existing policies
29
+ DROP POLICY IF EXISTS "boards_select_policy" ON "boards";
30
+ DROP POLICY IF EXISTS "boards_insert_policy" ON "boards";
31
+ DROP POLICY IF EXISTS "boards_update_policy" ON "boards";
32
+ DROP POLICY IF EXISTS "boards_delete_policy" ON "boards";
33
+
34
+ -- Policy: Team members can view boards
35
+ CREATE POLICY "boards_select_policy" ON "boards"
36
+ FOR SELECT TO authenticated
37
+ USING (
38
+ "teamId" = ANY(public.get_user_team_ids())
39
+ OR public.is_superadmin()
40
+ );
41
+
42
+ -- Policy: Team members can create boards (owner only at app level)
43
+ CREATE POLICY "boards_insert_policy" ON "boards"
44
+ FOR INSERT TO authenticated
45
+ WITH CHECK (
46
+ "teamId" = ANY(public.get_user_team_ids())
47
+ );
48
+
49
+ -- Policy: Team members can update boards (owner only at app level)
50
+ CREATE POLICY "boards_update_policy" ON "boards"
51
+ FOR UPDATE TO authenticated
52
+ USING (
53
+ "teamId" = ANY(public.get_user_team_ids())
54
+ OR public.is_superadmin()
55
+ );
56
+
57
+ -- Policy: Team members can delete boards (owner only at app level)
58
+ CREATE POLICY "boards_delete_policy" ON "boards"
59
+ FOR DELETE TO authenticated
60
+ USING (
61
+ "teamId" = ANY(public.get_user_team_ids())
62
+ OR public.is_superadmin()
63
+ );
64
+
65
+ -- Trigger for updatedAt
66
+ CREATE OR REPLACE FUNCTION update_boards_updated_at()
67
+ RETURNS TRIGGER AS $$
68
+ BEGIN
69
+ NEW."updatedAt" = NOW();
70
+ RETURN NEW;
71
+ END;
72
+ $$ LANGUAGE plpgsql;
73
+
74
+ DROP TRIGGER IF EXISTS boards_updated_at_trigger ON "boards";
75
+ CREATE TRIGGER boards_updated_at_trigger
76
+ BEFORE UPDATE ON "boards"
77
+ FOR EACH ROW
78
+ EXECUTE FUNCTION update_boards_updated_at();
79
+
80
+ -- Comments
81
+ COMMENT ON TABLE "boards" IS 'Trello-style boards for organizing lists and cards';
82
+ COMMENT ON COLUMN "boards"."color" IS 'Board background color theme';
83
+ COMMENT ON COLUMN "boards"."position" IS 'Display order for boards';
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Cards Entity Configuration
3
+ *
4
+ * Task cards within lists (the main work items).
5
+ */
6
+
7
+ import { CreditCard } from 'lucide-react'
8
+ import type { EntityConfig } from '@nextsparkjs/core/lib/entities/types'
9
+ import { cardFields } from './cards.fields'
10
+
11
+ export const cardEntityConfig: EntityConfig = {
12
+ // ==========================================
13
+ // 1. BASIC IDENTIFICATION
14
+ // ==========================================
15
+ slug: 'cards',
16
+ enabled: true,
17
+ names: {
18
+ singular: 'card',
19
+ plural: 'Cards'
20
+ },
21
+ icon: CreditCard,
22
+
23
+ // ==========================================
24
+ // 2. ACCESS AND SCOPE CONFIGURATION
25
+ // ==========================================
26
+ access: {
27
+ public: false,
28
+ api: true,
29
+ metadata: false,
30
+ shared: true
31
+ },
32
+
33
+ // ==========================================
34
+ // 3. UI/UX FEATURES
35
+ // ==========================================
36
+ ui: {
37
+ dashboard: {
38
+ showInMenu: true, // Show "My Cards" in menu
39
+ showInTopbar: true
40
+ },
41
+ public: {
42
+ hasArchivePage: false,
43
+ hasSinglePage: false
44
+ },
45
+ features: {
46
+ searchable: true,
47
+ sortable: true,
48
+ filterable: true,
49
+ bulkOperations: true,
50
+ importExport: false
51
+ }
52
+ },
53
+
54
+ // ==========================================
55
+ // FIELDS
56
+ // ==========================================
57
+ fields: cardFields,
58
+ }
59
+
60
+ export default cardEntityConfig
61
+
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Cards Entity Fields Configuration
3
+ */
4
+
5
+ import type { EntityField } from '@nextsparkjs/core/lib/entities/types'
6
+
7
+ export const cardFields: EntityField[] = [
8
+ {
9
+ name: 'title',
10
+ type: 'text',
11
+ required: true,
12
+ display: {
13
+ label: 'Title',
14
+ description: 'Card title',
15
+ placeholder: 'Enter card title...',
16
+ showInList: true,
17
+ showInDetail: true,
18
+ showInForm: true,
19
+ order: 1,
20
+ columnWidth: 12,
21
+ },
22
+ api: {
23
+ readOnly: false,
24
+ searchable: true,
25
+ sortable: true,
26
+ },
27
+ },
28
+ {
29
+ name: 'description',
30
+ type: 'textarea',
31
+ required: false,
32
+ display: {
33
+ label: 'Description',
34
+ description: 'Detailed description of the task',
35
+ placeholder: 'Add a more detailed description...',
36
+ showInList: false,
37
+ showInDetail: true,
38
+ showInForm: true,
39
+ order: 2,
40
+ columnWidth: 12,
41
+ },
42
+ api: {
43
+ readOnly: false,
44
+ searchable: true,
45
+ sortable: false,
46
+ },
47
+ },
48
+ {
49
+ name: 'position',
50
+ type: 'number',
51
+ required: false,
52
+ defaultValue: 0,
53
+ display: {
54
+ label: 'Position',
55
+ description: 'Display order within list',
56
+ showInList: false,
57
+ showInDetail: false,
58
+ showInForm: false,
59
+ order: 3,
60
+ },
61
+ api: {
62
+ readOnly: false,
63
+ searchable: false,
64
+ sortable: true,
65
+ },
66
+ },
67
+ {
68
+ name: 'dueDate',
69
+ type: 'date',
70
+ required: false,
71
+ display: {
72
+ label: 'Due Date',
73
+ description: 'When this task is due',
74
+ placeholder: 'Select due date...',
75
+ showInList: true,
76
+ showInDetail: true,
77
+ showInForm: true,
78
+ order: 4,
79
+ columnWidth: 6,
80
+ },
81
+ api: {
82
+ readOnly: false,
83
+ searchable: false,
84
+ sortable: true,
85
+ },
86
+ },
87
+ {
88
+ name: 'priority',
89
+ type: 'select',
90
+ required: false,
91
+ options: [
92
+ { value: 'low', label: 'Low' },
93
+ { value: 'medium', label: 'Medium' },
94
+ { value: 'high', label: 'High' },
95
+ { value: 'urgent', label: 'Urgent' },
96
+ ],
97
+ display: {
98
+ label: 'Priority',
99
+ description: 'Task priority level',
100
+ placeholder: 'Select priority...',
101
+ showInList: true,
102
+ showInDetail: true,
103
+ showInForm: true,
104
+ order: 5,
105
+ columnWidth: 6,
106
+ },
107
+ api: {
108
+ readOnly: false,
109
+ searchable: false,
110
+ sortable: true,
111
+ filterable: true,
112
+ },
113
+ },
114
+ {
115
+ name: 'labels',
116
+ type: 'multiselect',
117
+ required: false,
118
+ options: [
119
+ { value: 'urgent', label: 'Urgent' },
120
+ { value: 'important', label: 'Important' },
121
+ { value: 'bug', label: 'Bug' },
122
+ { value: 'feature', label: 'Feature' },
123
+ { value: 'enhancement', label: 'Enhancement' },
124
+ { value: 'documentation', label: 'Documentation' },
125
+ ],
126
+ display: {
127
+ label: 'Labels',
128
+ description: 'Tags to categorize this card',
129
+ placeholder: 'Select labels...',
130
+ showInList: true,
131
+ showInDetail: true,
132
+ showInForm: true,
133
+ order: 5,
134
+ columnWidth: 6,
135
+ },
136
+ api: {
137
+ readOnly: false,
138
+ searchable: false,
139
+ sortable: false,
140
+ },
141
+ },
142
+ {
143
+ name: 'assigneeId',
144
+ type: 'reference',
145
+ required: false,
146
+ referenceEntity: 'users',
147
+ display: {
148
+ label: 'Assignee',
149
+ description: 'Team member assigned to this card',
150
+ placeholder: 'Assign to...',
151
+ showInList: true,
152
+ showInDetail: true,
153
+ showInForm: true,
154
+ order: 6,
155
+ columnWidth: 6,
156
+ },
157
+ api: {
158
+ readOnly: false,
159
+ searchable: false,
160
+ sortable: false,
161
+ },
162
+ },
163
+ {
164
+ name: 'listId',
165
+ type: 'reference',
166
+ required: true,
167
+ referenceEntity: 'lists',
168
+ display: {
169
+ label: 'List',
170
+ description: 'Parent list',
171
+ placeholder: 'Select list...',
172
+ showInList: true,
173
+ showInDetail: true,
174
+ showInForm: true,
175
+ order: 7,
176
+ columnWidth: 6,
177
+ },
178
+ api: {
179
+ readOnly: false,
180
+ searchable: false,
181
+ sortable: false,
182
+ },
183
+ },
184
+ {
185
+ name: 'boardId',
186
+ type: 'reference',
187
+ required: true,
188
+ referenceEntity: 'boards',
189
+ display: {
190
+ label: 'Board',
191
+ description: 'Parent board',
192
+ placeholder: 'Select board...',
193
+ showInList: false,
194
+ showInDetail: true,
195
+ showInForm: true,
196
+ order: 8,
197
+ columnWidth: 12,
198
+ },
199
+ api: {
200
+ readOnly: false,
201
+ searchable: false,
202
+ sortable: false,
203
+ },
204
+ },
205
+ {
206
+ name: 'createdAt',
207
+ type: 'datetime',
208
+ required: false,
209
+ display: {
210
+ label: 'Created At',
211
+ description: 'When the card was created',
212
+ showInList: false,
213
+ showInDetail: true,
214
+ showInForm: false,
215
+ order: 98,
216
+ },
217
+ api: {
218
+ readOnly: true,
219
+ searchable: false,
220
+ sortable: true,
221
+ },
222
+ },
223
+ {
224
+ name: 'updatedAt',
225
+ type: 'datetime',
226
+ required: false,
227
+ display: {
228
+ label: 'Updated At',
229
+ description: 'When the card was last modified',
230
+ showInList: false,
231
+ showInDetail: true,
232
+ showInForm: false,
233
+ order: 99,
234
+ },
235
+ api: {
236
+ readOnly: true,
237
+ searchable: false,
238
+ sortable: true,
239
+ },
240
+ },
241
+ ]
242
+