webspresso 0.0.62 → 0.0.64
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.
- package/README.md +95 -3
- package/core/compileSchema.js +6 -2
- package/core/orm/index.js +3 -1
- package/core/orm/model.js +6 -0
- package/core/orm/types.js +9 -0
- package/core/orm/utils/nanoid.js +53 -0
- package/index.d.ts +482 -0
- package/index.js +2 -1
- package/package.json +7 -1
- package/plugins/admin-panel/components.js +120 -120
- package/plugins/admin-panel/field-renderers/array.js +2 -2
- package/plugins/admin-panel/field-renderers/basic.js +6 -6
- package/plugins/admin-panel/field-renderers/file-upload.js +2 -2
- package/plugins/admin-panel/field-renderers/json.js +1 -1
- package/plugins/admin-panel/field-renderers/relations.js +2 -2
- package/plugins/admin-panel/field-renderers/rich-text.js +3 -3
- package/plugins/admin-panel/index.js +35 -4
- package/plugins/admin-panel/modules/bulk-actions.js +6 -6
- package/plugins/admin-panel/modules/custom-pages.js +7 -7
- package/plugins/admin-panel/modules/dashboard.js +14 -14
- package/plugins/admin-panel/modules/menu.js +71 -26
- package/plugins/index.js +2 -0
- package/plugins/rest-resources/index.js +350 -0
- package/src/file-router.js +27 -0
- package/src/server.js +128 -36
- package/templates/skills/webspresso-usage/SKILL.md +4 -2
|
@@ -84,7 +84,7 @@ const Breadcrumb = {
|
|
|
84
84
|
m('ol.flex.items-center.space-x-2.text-sm', [
|
|
85
85
|
// Home link
|
|
86
86
|
m('li', [
|
|
87
|
-
m('a.text-gray-500.hover:text-gray-700', {
|
|
87
|
+
m('a.text-gray-500 dark:text-slate-400.hover:text-gray-700 dark:hover:text-slate-200 dark:hover:text-slate-200', {
|
|
88
88
|
href: '/',
|
|
89
89
|
onclick: (e) => {
|
|
90
90
|
e.preventDefault();
|
|
@@ -99,12 +99,12 @@ const Breadcrumb = {
|
|
|
99
99
|
// Dynamic items
|
|
100
100
|
...items.map((item, idx) => [
|
|
101
101
|
m('li.flex.items-center', [
|
|
102
|
-
m('svg.w-4.h-4.text-gray-400.mx-1', { fill: 'currentColor', viewBox: '0 0 20 20' }, [
|
|
102
|
+
m('svg.w-4.h-4.text-gray-400 dark:text-slate-500.mx-1', { fill: 'currentColor', viewBox: '0 0 20 20' }, [
|
|
103
103
|
m('path', { 'fill-rule': 'evenodd', d: 'M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z', 'clip-rule': 'evenodd' }),
|
|
104
104
|
]),
|
|
105
105
|
idx === items.length - 1
|
|
106
|
-
? m('span.text-gray-700.font-medium', item.label)
|
|
107
|
-
: m('a.text-gray-500.hover:text-gray-700', {
|
|
106
|
+
? m('span.text-gray-700 dark:text-slate-300.font-medium', item.label)
|
|
107
|
+
: m('a.text-gray-500 dark:text-slate-400.hover:text-gray-700 dark:hover:text-slate-200 dark:hover:text-slate-200', {
|
|
108
108
|
href: item.href,
|
|
109
109
|
onclick: (e) => {
|
|
110
110
|
e.preventDefault();
|
|
@@ -211,12 +211,12 @@ const ActiveFiltersBar = {
|
|
|
211
211
|
if (filterEntries.length === 0) return null;
|
|
212
212
|
|
|
213
213
|
return m('.flex.items-center.gap-2.py-2.flex-wrap', [
|
|
214
|
-
m('span.text-xs.font-medium.text-gray-500.uppercase.tracking-wide', 'Active filters:'),
|
|
214
|
+
m('span.text-xs.font-medium.text-gray-500 dark:text-slate-400.uppercase.tracking-wide', 'Active filters:'),
|
|
215
215
|
...filterEntries.map(([colName, filter]) => {
|
|
216
216
|
const col = modelMeta?.columns?.find(c => c.name === colName);
|
|
217
217
|
return m(FilterBadge, { colName, filter, colMeta: col, onRemove });
|
|
218
218
|
}),
|
|
219
|
-
filterEntries.length > 1 ? m('button.text-xs.text-gray-500.hover:text-gray-700.underline.ml-2', {
|
|
219
|
+
filterEntries.length > 1 ? m('button.text-xs.text-gray-500 dark:text-slate-400.hover:text-gray-700 dark:hover:text-slate-200 dark:hover:text-slate-200.underline.ml-2', {
|
|
220
220
|
onclick: onClearAll,
|
|
221
221
|
type: 'button',
|
|
222
222
|
}, 'Clear all') : null,
|
|
@@ -235,13 +235,13 @@ const QuickFilterInput = {
|
|
|
235
235
|
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z' }),
|
|
236
236
|
]),
|
|
237
237
|
]),
|
|
238
|
-
m('input.block.w-full.pl-9.pr-8.py-2.text-sm.border.border-gray-300.rounded-lg.bg-white.placeholder-gray-400.focus:outline-none.focus:ring-2.focus:ring-indigo-500.focus:border-transparent', {
|
|
238
|
+
m('input.block.w-full.pl-9.pr-8.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.bg-white dark:bg-slate-800.placeholder-gray-400 dark:placeholder-slate-500.focus:outline-none.focus:ring-2.focus:ring-indigo-500.focus:border-transparent', {
|
|
239
239
|
type: 'text',
|
|
240
240
|
placeholder: placeholder || 'Quick search...',
|
|
241
241
|
value: value || '',
|
|
242
242
|
oninput: (e) => onChange(e.target.value),
|
|
243
243
|
}),
|
|
244
|
-
value ? m('button.absolute.inset-y-0.right-0.pr-3.flex.items-center.text-gray-400.hover:text-gray-600', {
|
|
244
|
+
value ? m('button.absolute.inset-y-0.right-0.pr-3.flex.items-center.text-gray-400 dark:text-slate-500.hover:text-gray-600 dark:hover:text-slate-300 dark:hover:text-slate-300', {
|
|
245
245
|
onclick: onClear,
|
|
246
246
|
type: 'button',
|
|
247
247
|
}, [
|
|
@@ -271,7 +271,7 @@ const QuickFiltersBar = {
|
|
|
271
271
|
const quickSearchCol = searchableColumns[0];
|
|
272
272
|
const quickSearchFilter = quickSearchCol ? filters[quickSearchCol.name] : null;
|
|
273
273
|
|
|
274
|
-
return m('.bg-white.border.border-gray-200.rounded-lg.p-3.mb-4.shadow-sm', [
|
|
274
|
+
return m('.bg-white dark:bg-slate-800.border.border-gray-200 dark:border-slate-600.rounded-lg.p-3.mb-4.shadow-sm', [
|
|
275
275
|
m('.flex.items-center.gap-3.flex-wrap', [
|
|
276
276
|
quickSearchCol ? m(QuickFilterInput, {
|
|
277
277
|
placeholder: 'Search by ' + (quickSearchCol.ui?.label || formatColumnLabel(quickSearchCol.name)).toLowerCase() + '...',
|
|
@@ -297,14 +297,14 @@ const QuickFiltersBar = {
|
|
|
297
297
|
m('button.px-2.py-1.text-xs.rounded-md.transition-colors', {
|
|
298
298
|
class: !currentValue
|
|
299
299
|
? 'bg-gray-200 text-gray-800'
|
|
300
|
-
: 'bg-gray-100 text-gray-600 hover:bg-gray-200',
|
|
300
|
+
: 'bg-gray-100 text-gray-600 dark:text-slate-400 hover:bg-gray-200 dark:hover:bg-slate-600 dark:hover:bg-slate-600',
|
|
301
301
|
onclick: () => onFilterChange(col.name, null),
|
|
302
302
|
}, 'All'),
|
|
303
303
|
...col.enumValues.map(val =>
|
|
304
304
|
m('button.px-2.py-1.text-xs.rounded-md.transition-colors', {
|
|
305
305
|
class: currentValue === val
|
|
306
306
|
? 'bg-indigo-600 text-white'
|
|
307
|
-
: 'bg-gray-100 text-gray-600 hover:bg-gray-200',
|
|
307
|
+
: 'bg-gray-100 text-gray-600 dark:text-slate-400 hover:bg-gray-200 dark:hover:bg-slate-600 dark:hover:bg-slate-600',
|
|
308
308
|
onclick: () => onFilterChange(col.name, { op: 'equals', value: val }),
|
|
309
309
|
}, val)
|
|
310
310
|
),
|
|
@@ -314,7 +314,7 @@ const QuickFiltersBar = {
|
|
|
314
314
|
|
|
315
315
|
m('.flex-1'),
|
|
316
316
|
|
|
317
|
-
m('button.inline-flex.items-center.gap-2.px-3.py-2.text-sm.font-medium.text-gray-700.bg-white.border.border-gray-300.rounded-lg.hover:bg-gray-50.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
317
|
+
m('button.inline-flex.items-center.gap-2.px-3.py-2.text-sm.font-medium.text-gray-700 dark:text-slate-300.bg-white dark:bg-slate-800.border.border-gray-300 dark:border-slate-600.rounded-lg.hover:bg-gray-50 dark:hover:bg-slate-800/50 dark:hover:bg-slate-800/50.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
318
318
|
onclick: onOpenDrawer,
|
|
319
319
|
type: 'button',
|
|
320
320
|
}, [
|
|
@@ -343,7 +343,7 @@ const FilterField = {
|
|
|
343
343
|
['true', 'false', ''].map((val, idx) => {
|
|
344
344
|
const labels = ['Yes', 'No', 'Any'];
|
|
345
345
|
return m('label.inline-flex.items-center.cursor-pointer', [
|
|
346
|
-
m('input.w-4.h-4.text-indigo-600.border-gray-300.focus:ring-indigo-500', {
|
|
346
|
+
m('input.w-4.h-4.text-indigo-600.border-gray-300 dark:border-slate-600.focus:ring-indigo-500', {
|
|
347
347
|
type: 'radio',
|
|
348
348
|
name: 'filter_bool_' + col.name,
|
|
349
349
|
checked: (currentFilter.value || '') === val,
|
|
@@ -370,7 +370,7 @@ const FilterField = {
|
|
|
370
370
|
type: 'button',
|
|
371
371
|
class: isSelected
|
|
372
372
|
? 'bg-indigo-100 border-indigo-300 text-indigo-700'
|
|
373
|
-
: 'bg-white border-gray-300 text-gray-700 hover:bg-gray-50',
|
|
373
|
+
: 'bg-white border-gray-300 dark:border-slate-600 text-gray-700 dark:text-slate-300 hover:bg-gray-50 dark:hover:bg-slate-800/50 dark:hover:bg-slate-800/50',
|
|
374
374
|
onclick: () => {
|
|
375
375
|
const newSelected = isSelected
|
|
376
376
|
? selectedValues.filter(v => v !== val)
|
|
@@ -390,7 +390,7 @@ const FilterField = {
|
|
|
390
390
|
return m('.space-y-2', [
|
|
391
391
|
m('label.block.text-sm.font-medium.text-gray-700', label),
|
|
392
392
|
m('.flex.items-start.gap-2.flex-wrap', [
|
|
393
|
-
m('select.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.bg-white.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
393
|
+
m('select.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.bg-white dark:bg-slate-800.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
394
394
|
value: currentFilter.op || 'eq',
|
|
395
395
|
onchange: (e) => {
|
|
396
396
|
const op = e.target.value;
|
|
@@ -402,18 +402,18 @@ const FilterField = {
|
|
|
402
402
|
},
|
|
403
403
|
}, ops.map(o => m('option', { value: o.value }, o.label))),
|
|
404
404
|
currentFilter.op === 'between' ? [
|
|
405
|
-
m('input.flex-1.min-w-32.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
405
|
+
m('input.flex-1.min-w-32.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
406
406
|
type: inputType,
|
|
407
407
|
value: currentFilter.from || '',
|
|
408
408
|
oninput: (e) => onChange({ op: 'between', from: e.target.value, to: currentFilter.to || '' }),
|
|
409
409
|
}),
|
|
410
|
-
m('span.text-gray-400.self-center', 'to'),
|
|
411
|
-
m('input.flex-1.min-w-32.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
410
|
+
m('span.text-gray-400 dark:text-slate-500.self-center', 'to'),
|
|
411
|
+
m('input.flex-1.min-w-32.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
412
412
|
type: inputType,
|
|
413
413
|
value: currentFilter.to || '',
|
|
414
414
|
oninput: (e) => onChange({ op: 'between', from: currentFilter.from || '', to: e.target.value }),
|
|
415
415
|
}),
|
|
416
|
-
] : m('input.flex-1.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
416
|
+
] : m('input.flex-1.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
417
417
|
type: inputType,
|
|
418
418
|
value: currentFilter.value || '',
|
|
419
419
|
oninput: (e) => onChange({ op: currentFilter.op || 'eq', value: e.target.value }),
|
|
@@ -428,7 +428,7 @@ const FilterField = {
|
|
|
428
428
|
return m('.space-y-2', [
|
|
429
429
|
m('label.block.text-sm.font-medium.text-gray-700', label),
|
|
430
430
|
m('.flex.items-start.gap-2', [
|
|
431
|
-
m('select.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.bg-white.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
431
|
+
m('select.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.bg-white dark:bg-slate-800.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
432
432
|
value: currentFilter.op || 'eq',
|
|
433
433
|
onchange: (e) => {
|
|
434
434
|
const op = e.target.value;
|
|
@@ -440,20 +440,20 @@ const FilterField = {
|
|
|
440
440
|
},
|
|
441
441
|
}, ops.map(o => m('option', { value: o.value }, o.label))),
|
|
442
442
|
currentFilter.op === 'between' ? [
|
|
443
|
-
m('input.w-24.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
443
|
+
m('input.w-24.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
444
444
|
type: 'number',
|
|
445
445
|
value: currentFilter.from || '',
|
|
446
446
|
placeholder: 'Min',
|
|
447
447
|
oninput: (e) => onChange({ op: 'between', from: e.target.value, to: currentFilter.to || '' }),
|
|
448
448
|
}),
|
|
449
|
-
m('span.text-gray-400.self-center', 'to'),
|
|
450
|
-
m('input.w-24.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
449
|
+
m('span.text-gray-400 dark:text-slate-500.self-center', 'to'),
|
|
450
|
+
m('input.w-24.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
451
451
|
type: 'number',
|
|
452
452
|
value: currentFilter.to || '',
|
|
453
453
|
placeholder: 'Max',
|
|
454
454
|
oninput: (e) => onChange({ op: 'between', from: currentFilter.from || '', to: e.target.value }),
|
|
455
455
|
}),
|
|
456
|
-
] : m('input.flex-1.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
456
|
+
] : m('input.flex-1.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
457
457
|
type: 'number',
|
|
458
458
|
value: currentFilter.value || '',
|
|
459
459
|
placeholder: 'Enter value',
|
|
@@ -469,11 +469,11 @@ const FilterField = {
|
|
|
469
469
|
return m('.space-y-2', [
|
|
470
470
|
m('label.block.text-sm.font-medium.text-gray-700', label),
|
|
471
471
|
m('.flex.items-center.gap-2', [
|
|
472
|
-
m('select.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.bg-white.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
472
|
+
m('select.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.bg-white dark:bg-slate-800.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
473
473
|
value: currentFilter.op || 'contains',
|
|
474
474
|
onchange: (e) => onChange({ op: e.target.value, value: currentFilter.value || '' }),
|
|
475
475
|
}, ops.map(o => m('option', { value: o.value }, o.label))),
|
|
476
|
-
m('input.flex-1.px-3.py-2.text-sm.border.border-gray-300.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
476
|
+
m('input.flex-1.px-3.py-2.text-sm.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:outline-none.focus:ring-2.focus:ring-indigo-500', {
|
|
477
477
|
type: 'text',
|
|
478
478
|
value: currentFilter.value || '',
|
|
479
479
|
placeholder: 'Enter search term',
|
|
@@ -506,7 +506,7 @@ const FilterDrawer = {
|
|
|
506
506
|
const renderGroup = (title, columns) => {
|
|
507
507
|
if (columns.length === 0) return null;
|
|
508
508
|
return m('.mb-6', [
|
|
509
|
-
m('h4.text-xs.font-semibold.text-gray-400.uppercase.tracking-wider.mb-3', title),
|
|
509
|
+
m('h4.text-xs.font-semibold.text-gray-400 dark:text-slate-500.uppercase.tracking-wider.mb-3', title),
|
|
510
510
|
m('.space-y-4', columns.map(col =>
|
|
511
511
|
m(FilterField, {
|
|
512
512
|
col,
|
|
@@ -519,7 +519,7 @@ const FilterDrawer = {
|
|
|
519
519
|
|
|
520
520
|
return [
|
|
521
521
|
m('.fixed.inset-0.bg-black.bg-opacity-25.z-40.transition-opacity', { onclick: onClose }),
|
|
522
|
-
m('.fixed.inset-y-0.right-0.w-full.max-w-md.bg-white.shadow-xl.z-50.flex.flex-col', {
|
|
522
|
+
m('.fixed.inset-y-0.right-0.w-full.max-w-md.bg-white dark:bg-slate-800.shadow-xl.z-50.flex.flex-col', {
|
|
523
523
|
style: 'animation: filterDrawerSlideIn 0.2s ease-out;',
|
|
524
524
|
}, [
|
|
525
525
|
m('.flex.items-center.justify-between.px-6.py-4.border-b.border-gray-200', [
|
|
@@ -527,7 +527,7 @@ const FilterDrawer = {
|
|
|
527
527
|
m('h3.text-lg.font-semibold.text-gray-900', 'Advanced Filters'),
|
|
528
528
|
m('p.text-sm.text-gray-500', 'Filter records by multiple criteria'),
|
|
529
529
|
]),
|
|
530
|
-
m('button.p-2.text-gray-400.hover:text-gray-600.rounded-lg.hover:bg-gray-100', {
|
|
530
|
+
m('button.p-2.text-gray-400 dark:text-slate-500.hover:text-gray-600 dark:hover:text-slate-300 dark:hover:text-slate-300.rounded-lg.hover:bg-gray-100 dark:hover:bg-slate-700 dark:hover:bg-slate-700', {
|
|
531
531
|
onclick: onClose,
|
|
532
532
|
type: 'button',
|
|
533
533
|
}, [
|
|
@@ -542,13 +542,13 @@ const FilterDrawer = {
|
|
|
542
542
|
renderGroup('Numbers', numericColumns),
|
|
543
543
|
renderGroup('Dates', dateColumns),
|
|
544
544
|
]),
|
|
545
|
-
m('.flex.items-center.justify-between.gap-3.px-6.py-4.border-t.border-gray-200.bg-gray-50', [
|
|
546
|
-
m('button.px-4.py-2.text-sm.font-medium.text-gray-700.hover:text-gray-900', {
|
|
545
|
+
m('.flex.items-center.justify-between.gap-3.px-6.py-4.border-t.border-gray-200 dark:border-slate-600.bg-gray-50', [
|
|
546
|
+
m('button.px-4.py-2.text-sm.font-medium.text-gray-700 dark:text-slate-300.hover:text-gray-900 dark:hover:text-slate-100 dark:hover:text-slate-100', {
|
|
547
547
|
onclick: onClear,
|
|
548
548
|
type: 'button',
|
|
549
549
|
}, 'Clear all'),
|
|
550
550
|
m('.flex.gap-3', [
|
|
551
|
-
m('button.px-4.py-2.text-sm.font-medium.text-gray-700.bg-white.border.border-gray-300.rounded-lg.hover:bg-gray-50', {
|
|
551
|
+
m('button.px-4.py-2.text-sm.font-medium.text-gray-700 dark:text-slate-300.bg-white dark:bg-slate-800.border.border-gray-300 dark:border-slate-600.rounded-lg.hover:bg-gray-50 dark:hover:bg-slate-800/50 dark:hover:bg-slate-800/50', {
|
|
552
552
|
onclick: onClose,
|
|
553
553
|
type: 'button',
|
|
554
554
|
}, 'Cancel'),
|
|
@@ -592,7 +592,7 @@ const Pagination = {
|
|
|
592
592
|
pages.push(i);
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
-
return m('.flex.items-center.justify-between.px-4.py-3.bg-white.border-t', [
|
|
595
|
+
return m('.flex.items-center.justify-between.px-4.py-3.bg-white dark:bg-slate-800.border-t', [
|
|
596
596
|
m('.text-sm.text-gray-700', [
|
|
597
597
|
'Showing ',
|
|
598
598
|
m('span.font-medium', ((page - 1) * perPage) + 1),
|
|
@@ -606,13 +606,13 @@ const Pagination = {
|
|
|
606
606
|
// Previous button
|
|
607
607
|
m('button.px-3.py-1.rounded.border.text-sm', {
|
|
608
608
|
disabled: page <= 1,
|
|
609
|
-
class: page <= 1 ? 'text-gray-300 cursor-not-allowed' : 'text-gray-700 hover:bg-gray-100',
|
|
609
|
+
class: page <= 1 ? 'text-gray-300 cursor-not-allowed' : 'text-gray-700 hover:bg-gray-100 dark:hover:bg-slate-700 dark:hover:bg-slate-700',
|
|
610
610
|
onclick: () => page > 1 && onPageChange(page - 1),
|
|
611
611
|
}, '← Prev'),
|
|
612
612
|
|
|
613
613
|
// Page numbers
|
|
614
614
|
start > 1 ? [
|
|
615
|
-
m('button.px-3.py-1.rounded.text-sm.text-gray-700.hover:bg-gray-100', {
|
|
615
|
+
m('button.px-3.py-1.rounded.text-sm.text-gray-700 dark:text-slate-300.hover:bg-gray-100 dark:hover:bg-slate-700 dark:hover:bg-slate-700', {
|
|
616
616
|
onclick: () => onPageChange(1),
|
|
617
617
|
}, '1'),
|
|
618
618
|
start > 2 ? m('span.px-2.text-gray-400', '...') : null,
|
|
@@ -622,14 +622,14 @@ const Pagination = {
|
|
|
622
622
|
m('button.px-3.py-1.rounded.text-sm', {
|
|
623
623
|
class: p === page
|
|
624
624
|
? 'bg-blue-600 text-white'
|
|
625
|
-
: 'text-gray-700 hover:bg-gray-100',
|
|
625
|
+
: 'text-gray-700 hover:bg-gray-100 dark:hover:bg-slate-700 dark:hover:bg-slate-700',
|
|
626
626
|
onclick: () => onPageChange(p),
|
|
627
627
|
}, p)
|
|
628
628
|
),
|
|
629
629
|
|
|
630
630
|
end < totalPages ? [
|
|
631
631
|
end < totalPages - 1 ? m('span.px-2.text-gray-400', '...') : null,
|
|
632
|
-
m('button.px-3.py-1.rounded.text-sm.text-gray-700.hover:bg-gray-100', {
|
|
632
|
+
m('button.px-3.py-1.rounded.text-sm.text-gray-700 dark:text-slate-300.hover:bg-gray-100 dark:hover:bg-slate-700 dark:hover:bg-slate-700', {
|
|
633
633
|
onclick: () => onPageChange(totalPages),
|
|
634
634
|
}, totalPages),
|
|
635
635
|
] : null,
|
|
@@ -637,7 +637,7 @@ const Pagination = {
|
|
|
637
637
|
// Next button
|
|
638
638
|
m('button.px-3.py-1.rounded.border.text-sm', {
|
|
639
639
|
disabled: page >= totalPages,
|
|
640
|
-
class: page >= totalPages ? 'text-gray-300 cursor-not-allowed' : 'text-gray-700 hover:bg-gray-100',
|
|
640
|
+
class: page >= totalPages ? 'text-gray-300 cursor-not-allowed' : 'text-gray-700 hover:bg-gray-100 dark:hover:bg-slate-700 dark:hover:bg-slate-700',
|
|
641
641
|
onclick: () => page < totalPages && onPageChange(page + 1),
|
|
642
642
|
}, 'Next →'),
|
|
643
643
|
]),
|
|
@@ -657,8 +657,8 @@ const FieldRenderers = {
|
|
|
657
657
|
const hint = ui.hint || '';
|
|
658
658
|
|
|
659
659
|
return m('.mb-4', [
|
|
660
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
661
|
-
m('input.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
660
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
661
|
+
m('input.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
662
662
|
id: col.name,
|
|
663
663
|
name: col.name,
|
|
664
664
|
type: inputType,
|
|
@@ -673,7 +673,7 @@ const FieldRenderers = {
|
|
|
673
673
|
class: readonly ? 'bg-gray-100 cursor-not-allowed' : '',
|
|
674
674
|
oninput: (e) => onChange(e.target.value),
|
|
675
675
|
}),
|
|
676
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
676
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
677
677
|
]);
|
|
678
678
|
},
|
|
679
679
|
|
|
@@ -687,8 +687,8 @@ const FieldRenderers = {
|
|
|
687
687
|
const rows = ui.rows || 4;
|
|
688
688
|
|
|
689
689
|
return m('.mb-4', [
|
|
690
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
691
|
-
m('textarea.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
690
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
691
|
+
m('textarea.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
692
692
|
id: col.name,
|
|
693
693
|
name: col.name,
|
|
694
694
|
rows: rows,
|
|
@@ -701,7 +701,7 @@ const FieldRenderers = {
|
|
|
701
701
|
class: readonly ? 'bg-gray-100 cursor-not-allowed' : '',
|
|
702
702
|
oninput: (e) => onChange(e.target.value),
|
|
703
703
|
}, value || ''),
|
|
704
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
704
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
705
705
|
]);
|
|
706
706
|
},
|
|
707
707
|
|
|
@@ -714,8 +714,8 @@ const FieldRenderers = {
|
|
|
714
714
|
const hint = ui.hint || '';
|
|
715
715
|
|
|
716
716
|
return m('.mb-4', [
|
|
717
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
718
|
-
m('input.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
717
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
718
|
+
m('input.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
719
719
|
id: col.name,
|
|
720
720
|
name: col.name,
|
|
721
721
|
type: 'number',
|
|
@@ -730,7 +730,7 @@ const FieldRenderers = {
|
|
|
730
730
|
class: readonly ? 'bg-gray-100 cursor-not-allowed' : '',
|
|
731
731
|
oninput: (e) => onChange(e.target.value === '' ? null : parseInt(e.target.value, 10)),
|
|
732
732
|
}),
|
|
733
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
733
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
734
734
|
]);
|
|
735
735
|
},
|
|
736
736
|
|
|
@@ -743,8 +743,8 @@ const FieldRenderers = {
|
|
|
743
743
|
const hint = ui.hint || '';
|
|
744
744
|
|
|
745
745
|
return m('.mb-4', [
|
|
746
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
747
|
-
m('input.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
746
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
747
|
+
m('input.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
748
748
|
id: col.name,
|
|
749
749
|
name: col.name,
|
|
750
750
|
type: 'number',
|
|
@@ -759,7 +759,7 @@ const FieldRenderers = {
|
|
|
759
759
|
class: readonly ? 'bg-gray-100 cursor-not-allowed' : '',
|
|
760
760
|
oninput: (e) => onChange(e.target.value === '' ? null : parseFloat(e.target.value)),
|
|
761
761
|
}),
|
|
762
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
762
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
763
763
|
]);
|
|
764
764
|
},
|
|
765
765
|
|
|
@@ -780,7 +780,7 @@ const FieldRenderers = {
|
|
|
780
780
|
}),
|
|
781
781
|
m('span.text-sm.font-medium.text-gray-700', label),
|
|
782
782
|
]),
|
|
783
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
783
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
784
784
|
]);
|
|
785
785
|
},
|
|
786
786
|
|
|
@@ -794,8 +794,8 @@ const FieldRenderers = {
|
|
|
794
794
|
const dateValue = value ? new Date(value).toISOString().split('T')[0] : '';
|
|
795
795
|
|
|
796
796
|
return m('.mb-4', [
|
|
797
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
798
|
-
m('input.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
797
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
798
|
+
m('input.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
799
799
|
id: col.name,
|
|
800
800
|
name: col.name,
|
|
801
801
|
type: 'date',
|
|
@@ -809,7 +809,7 @@ const FieldRenderers = {
|
|
|
809
809
|
class: readonly ? 'bg-gray-100 cursor-not-allowed' : '',
|
|
810
810
|
oninput: (e) => onChange(e.target.value),
|
|
811
811
|
}),
|
|
812
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
812
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
813
813
|
]);
|
|
814
814
|
},
|
|
815
815
|
|
|
@@ -823,8 +823,8 @@ const FieldRenderers = {
|
|
|
823
823
|
const dateTimeValue = value ? new Date(value).toISOString().slice(0, 16) : '';
|
|
824
824
|
|
|
825
825
|
return m('.mb-4', [
|
|
826
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
827
|
-
m('input.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
826
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
827
|
+
m('input.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
828
828
|
id: col.name,
|
|
829
829
|
name: col.name,
|
|
830
830
|
type: 'datetime-local',
|
|
@@ -838,7 +838,7 @@ const FieldRenderers = {
|
|
|
838
838
|
class: readonly ? 'bg-gray-100 cursor-not-allowed' : '',
|
|
839
839
|
oninput: (e) => onChange(e.target.value),
|
|
840
840
|
}),
|
|
841
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
841
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
842
842
|
]);
|
|
843
843
|
},
|
|
844
844
|
|
|
@@ -850,8 +850,8 @@ const FieldRenderers = {
|
|
|
850
850
|
const options = col.enumValues || [];
|
|
851
851
|
|
|
852
852
|
return m('.mb-4', [
|
|
853
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
854
|
-
m('select.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
853
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
854
|
+
m('select.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
855
855
|
id: col.name,
|
|
856
856
|
name: col.name,
|
|
857
857
|
value: value || '',
|
|
@@ -863,7 +863,7 @@ const FieldRenderers = {
|
|
|
863
863
|
col.nullable ? m('option', { value: '' }, '-- Select --') : null,
|
|
864
864
|
...options.map(opt => m('option', { value: opt, selected: value === opt }, opt)),
|
|
865
865
|
]),
|
|
866
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
866
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
867
867
|
]);
|
|
868
868
|
},
|
|
869
869
|
|
|
@@ -877,8 +877,8 @@ const FieldRenderers = {
|
|
|
877
877
|
const jsonString = value ? (typeof value === 'string' ? value : JSON.stringify(value, null, 2)) : '';
|
|
878
878
|
|
|
879
879
|
return m('.mb-4', [
|
|
880
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
881
|
-
m('textarea.w-full.px-3.py-2.border.border-gray-300.rounded.font-mono.text-sm.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
880
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
881
|
+
m('textarea.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.font-mono.text-sm.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
882
882
|
id: col.name,
|
|
883
883
|
name: col.name,
|
|
884
884
|
rows: rows,
|
|
@@ -896,7 +896,7 @@ const FieldRenderers = {
|
|
|
896
896
|
}
|
|
897
897
|
},
|
|
898
898
|
}, jsonString),
|
|
899
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
899
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
900
900
|
]);
|
|
901
901
|
},
|
|
902
902
|
|
|
@@ -910,8 +910,8 @@ const FieldRenderers = {
|
|
|
910
910
|
const arrayValue = Array.isArray(value) ? value.join(', ') : (value || '');
|
|
911
911
|
|
|
912
912
|
return m('.mb-4', [
|
|
913
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: col.name }, label),
|
|
914
|
-
m('input.w-full.px-3.py-2.border.border-gray-300.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
913
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: col.name }, label),
|
|
914
|
+
m('input.w-full.px-3.py-2.border.border-gray-300 dark:border-slate-600.rounded.focus:outline-none.focus:ring-2.focus:ring-blue-500', {
|
|
915
915
|
id: col.name,
|
|
916
916
|
name: col.name,
|
|
917
917
|
type: 'text',
|
|
@@ -928,7 +928,7 @@ const FieldRenderers = {
|
|
|
928
928
|
onChange(arr);
|
|
929
929
|
},
|
|
930
930
|
}),
|
|
931
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
931
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
932
932
|
]);
|
|
933
933
|
},
|
|
934
934
|
};
|
|
@@ -1030,11 +1030,11 @@ const RichTextField = {
|
|
|
1030
1030
|
const required = !col.nullable && !readonly;
|
|
1031
1031
|
|
|
1032
1032
|
return m('.mb-4', [
|
|
1033
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-1', { for: name },
|
|
1033
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-1', { for: name },
|
|
1034
1034
|
label,
|
|
1035
1035
|
required ? m('span.text-red-500', ' *') : null
|
|
1036
1036
|
),
|
|
1037
|
-
m('div.border.border-gray-300.rounded', {
|
|
1037
|
+
m('div.border.border-gray-300 dark:border-slate-600.rounded', {
|
|
1038
1038
|
id: editorId,
|
|
1039
1039
|
class: readonly ? 'bg-gray-100 opacity-50' : '',
|
|
1040
1040
|
style: 'min-height: 200px;'
|
|
@@ -1044,7 +1044,7 @@ const RichTextField = {
|
|
|
1044
1044
|
id: name + '-value',
|
|
1045
1045
|
value: value || '',
|
|
1046
1046
|
}),
|
|
1047
|
-
hint ? m('p.text-xs.text-gray-500.mt-1', hint) : null,
|
|
1047
|
+
hint ? m('p.text-xs.text-gray-500 dark:text-slate-400.mt-1', hint) : null,
|
|
1048
1048
|
]);
|
|
1049
1049
|
}
|
|
1050
1050
|
};
|
|
@@ -1112,10 +1112,10 @@ function isRichTextEmpty(value) {
|
|
|
1112
1112
|
const LoginForm = {
|
|
1113
1113
|
view: () => m('.min-h-screen.flex.items-center.justify-center.p-4.sm:p-6.bg-gradient-to-br.from-blue-600.via-indigo-600.to-purple-700', [
|
|
1114
1114
|
m('.w-full.max-w-md', [
|
|
1115
|
-
m('.bg-white.rounded-2xl.shadow-2xl.p-6.sm:p-8', [
|
|
1115
|
+
m('.bg-white dark:bg-slate-800.rounded-2xl.shadow-2xl.p-6.sm:p-8', [
|
|
1116
1116
|
m('div.text-center.mb-6', [
|
|
1117
1117
|
m('h1.text-2xl.sm:text-3xl.font-bold.text-gray-900', 'Admin Login'),
|
|
1118
|
-
m('p.text-gray-500.text-sm.mt-1', 'Sign in to your account'),
|
|
1118
|
+
m('p.text-gray-500 dark:text-slate-400.text-sm.mt-1', 'Sign in to your account'),
|
|
1119
1119
|
]),
|
|
1120
1120
|
m('form', {
|
|
1121
1121
|
onsubmit: async (e) => {
|
|
@@ -1139,8 +1139,8 @@ const LoginForm = {
|
|
|
1139
1139
|
}, [
|
|
1140
1140
|
state.error ? m('.bg-red-50.border.border-red-200.text-red-700.px-4.py-3.rounded-lg.mb-4.text-sm', state.error) : null,
|
|
1141
1141
|
m('.mb-4', [
|
|
1142
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-2', { for: 'email' }, 'Email'),
|
|
1143
|
-
m('input#email.w-full.px-3.py-2.5.border.border-gray-300.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1142
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-2', { for: 'email' }, 'Email'),
|
|
1143
|
+
m('input#email.w-full.px-3.py-2.5.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1144
1144
|
type: 'email',
|
|
1145
1145
|
name: 'email',
|
|
1146
1146
|
required: true,
|
|
@@ -1148,8 +1148,8 @@ const LoginForm = {
|
|
|
1148
1148
|
}),
|
|
1149
1149
|
]),
|
|
1150
1150
|
m('.mb-6', [
|
|
1151
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-2', { for: 'password' }, 'Password'),
|
|
1152
|
-
m('input#password.w-full.px-3.py-2.5.border.border-gray-300.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1151
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-2', { for: 'password' }, 'Password'),
|
|
1152
|
+
m('input#password.w-full.px-3.py-2.5.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1153
1153
|
type: 'password',
|
|
1154
1154
|
name: 'password',
|
|
1155
1155
|
required: true,
|
|
@@ -1169,10 +1169,10 @@ const LoginForm = {
|
|
|
1169
1169
|
const SetupForm = {
|
|
1170
1170
|
view: () => m('.min-h-screen.flex.items-center.justify-center.p-4.sm:p-6.bg-gradient-to-br.from-blue-600.via-indigo-600.to-purple-700', [
|
|
1171
1171
|
m('.w-full.max-w-md', [
|
|
1172
|
-
m('.bg-white.rounded-2xl.shadow-2xl.p-6.sm:p-8', [
|
|
1172
|
+
m('.bg-white dark:bg-slate-800.rounded-2xl.shadow-2xl.p-6.sm:p-8', [
|
|
1173
1173
|
m('div.text-center.mb-6', [
|
|
1174
1174
|
m('h1.text-2xl.sm:text-3xl.font-bold.text-gray-900', 'Setup Admin Account'),
|
|
1175
|
-
m('p.text-gray-500.text-sm.mt-1', 'Create the first admin user account.'),
|
|
1175
|
+
m('p.text-gray-500 dark:text-slate-400.text-sm.mt-1', 'Create the first admin user account.'),
|
|
1176
1176
|
]),
|
|
1177
1177
|
m('form', {
|
|
1178
1178
|
onsubmit: async (e) => {
|
|
@@ -1198,16 +1198,16 @@ const SetupForm = {
|
|
|
1198
1198
|
}, [
|
|
1199
1199
|
state.error ? m('.bg-red-50.border.border-red-200.text-red-700.px-4.py-3.rounded-lg.mb-4.text-sm', state.error) : null,
|
|
1200
1200
|
m('.mb-4', [
|
|
1201
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-2', { for: 'name' }, 'Name'),
|
|
1202
|
-
m('input#name.w-full.px-3.py-2.5.border.border-gray-300.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1201
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-2', { for: 'name' }, 'Name'),
|
|
1202
|
+
m('input#name.w-full.px-3.py-2.5.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1203
1203
|
type: 'text',
|
|
1204
1204
|
name: 'name',
|
|
1205
1205
|
required: true,
|
|
1206
1206
|
}),
|
|
1207
1207
|
]),
|
|
1208
1208
|
m('.mb-4', [
|
|
1209
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-2', { for: 'email' }, 'Email'),
|
|
1210
|
-
m('input#email.w-full.px-3.py-2.5.border.border-gray-300.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1209
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-2', { for: 'email' }, 'Email'),
|
|
1210
|
+
m('input#email.w-full.px-3.py-2.5.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1211
1211
|
type: 'email',
|
|
1212
1212
|
name: 'email',
|
|
1213
1213
|
required: true,
|
|
@@ -1215,8 +1215,8 @@ const SetupForm = {
|
|
|
1215
1215
|
}),
|
|
1216
1216
|
]),
|
|
1217
1217
|
m('.mb-6', [
|
|
1218
|
-
m('label.block.text-sm.font-medium.text-gray-700.mb-2', { for: 'password' }, 'Password'),
|
|
1219
|
-
m('input#password.w-full.px-3.py-2.5.border.border-gray-300.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1218
|
+
m('label.block.text-sm.font-medium.text-gray-700 dark:text-slate-300.mb-2', { for: 'password' }, 'Password'),
|
|
1219
|
+
m('input#password.w-full.px-3.py-2.5.border.border-gray-300 dark:border-slate-600.rounded-lg.focus:ring-2.focus:ring-blue-500.focus:border-blue-500.transition-colors', {
|
|
1220
1220
|
type: 'password',
|
|
1221
1221
|
name: 'password',
|
|
1222
1222
|
required: true,
|
|
@@ -1260,7 +1260,7 @@ const ModelList = {
|
|
|
1260
1260
|
? m('p.text-gray-600', 'No models enabled in admin panel. Make sure your models have admin: { enabled: true }')
|
|
1261
1261
|
: m('.grid.grid-cols-1.md:grid-cols-2.lg:grid-cols-3.gap-4',
|
|
1262
1262
|
state.models.map(model =>
|
|
1263
|
-
m('a.bg-white.p-6.rounded.shadow.hover:shadow-lg.transition', {
|
|
1263
|
+
m('a.bg-white dark:bg-slate-800.p-6.rounded.shadow.hover:shadow-lg.transition', {
|
|
1264
1264
|
href: '/models/' + model.name,
|
|
1265
1265
|
onclick: (e) => {
|
|
1266
1266
|
e.preventDefault();
|
|
@@ -1269,7 +1269,7 @@ const ModelList = {
|
|
|
1269
1269
|
}, [
|
|
1270
1270
|
model.icon ? m('span.text-2xl.mb-2.block', model.icon) : null,
|
|
1271
1271
|
m('h3.font-semibold.text-lg', model.label || model.name),
|
|
1272
|
-
m('p.text-sm.text-gray-600.mt-2', model.table),
|
|
1272
|
+
m('p.text-sm.text-gray-600 dark:text-slate-400.mt-2', model.table),
|
|
1273
1273
|
])
|
|
1274
1274
|
)
|
|
1275
1275
|
),
|
|
@@ -1279,14 +1279,14 @@ const ModelList = {
|
|
|
1279
1279
|
// Format cell value based on column type
|
|
1280
1280
|
function formatCellValue(value, col) {
|
|
1281
1281
|
if (value === null || value === undefined) {
|
|
1282
|
-
return m('span.text-gray-400.italic', 'null');
|
|
1282
|
+
return m('span.text-gray-400 dark:text-slate-500.italic', 'null');
|
|
1283
1283
|
}
|
|
1284
1284
|
|
|
1285
1285
|
switch (col?.type) {
|
|
1286
1286
|
case 'boolean':
|
|
1287
1287
|
return value
|
|
1288
1288
|
? m('span.inline-flex.items-center.px-2.py-1.rounded-full.text-xs.font-medium.bg-green-100.text-green-800', '✓ Yes')
|
|
1289
|
-
: m('span.inline-flex.items-center.px-2.py-1.rounded-full.text-xs.font-medium.bg-gray-100.text-gray-600', '✗ No');
|
|
1289
|
+
: m('span.inline-flex.items-center.px-2.py-1.rounded-full.text-xs.font-medium.bg-gray-100 dark:bg-slate-800.text-gray-600', '✗ No');
|
|
1290
1290
|
|
|
1291
1291
|
case 'datetime':
|
|
1292
1292
|
case 'timestamp':
|
|
@@ -1305,11 +1305,11 @@ function formatCellValue(value, col) {
|
|
|
1305
1305
|
case 'array':
|
|
1306
1306
|
if (Array.isArray(value)) {
|
|
1307
1307
|
return value.length > 0
|
|
1308
|
-
? m('span.text-xs.bg-gray-100.px-2.py-1.rounded', value.slice(0, 3).join(', ') + (value.length > 3 ? '...' : ''))
|
|
1308
|
+
? m('span.text-xs.bg-gray-100 dark:bg-slate-800.px-2.py-1.rounded', value.slice(0, 3).join(', ') + (value.length > 3 ? '...' : ''))
|
|
1309
1309
|
: m('span.text-gray-400', '[]');
|
|
1310
1310
|
}
|
|
1311
1311
|
if (typeof value === 'object') {
|
|
1312
|
-
return m('span.text-xs.bg-gray-100.px-2.py-1.rounded.font-mono', '{...}');
|
|
1312
|
+
return m('span.text-xs.bg-gray-100 dark:bg-slate-800.px-2.py-1.rounded.font-mono', '{...}');
|
|
1313
1313
|
}
|
|
1314
1314
|
return String(value);
|
|
1315
1315
|
|
|
@@ -1373,7 +1373,7 @@ const BulkFieldUpdateDropdown = {
|
|
|
1373
1373
|
|
|
1374
1374
|
return m('.relative.inline-block', [
|
|
1375
1375
|
// Dropdown trigger
|
|
1376
|
-
m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-purple-600.bg-white.border.border-purple-200.rounded.hover:bg-purple-50.transition-colors', {
|
|
1376
|
+
m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-purple-600.bg-white dark:bg-slate-800.border.border-purple-200.rounded.hover:bg-purple-50.transition-colors', {
|
|
1377
1377
|
disabled: state.bulkActionInProgress,
|
|
1378
1378
|
onclick: (e) => {
|
|
1379
1379
|
e.stopPropagation();
|
|
@@ -1392,7 +1392,7 @@ const BulkFieldUpdateDropdown = {
|
|
|
1392
1392
|
]),
|
|
1393
1393
|
|
|
1394
1394
|
// Dropdown menu
|
|
1395
|
-
state.bulkFieldDropdownOpen && m('.absolute.z-50.mt-1.w-64.bg-white.rounded-lg.shadow-lg.border.border-gray-200.overflow-hidden', {
|
|
1395
|
+
state.bulkFieldDropdownOpen && m('.absolute.z-50.mt-1.w-64.bg-white dark:bg-slate-800.rounded-lg.shadow-lg.border.border-gray-200 dark:border-slate-600.overflow-hidden', {
|
|
1396
1396
|
style: 'left: 0; top: 100%;',
|
|
1397
1397
|
onclick: (e) => e.stopPropagation(),
|
|
1398
1398
|
}, [
|
|
@@ -1408,8 +1408,8 @@ const BulkFieldUpdateDropdown = {
|
|
|
1408
1408
|
// Dropdown content
|
|
1409
1409
|
m('.relative.z-50.bg-white', [
|
|
1410
1410
|
// Header
|
|
1411
|
-
m('.px-3.py-2.bg-gray-50.border-b.border-gray-200', [
|
|
1412
|
-
m('span.text-xs.font-medium.text-gray-500.uppercase.tracking-wider',
|
|
1411
|
+
m('.px-3.py-2.bg-gray-50 dark:bg-slate-900.border-b.border-gray-200', [
|
|
1412
|
+
m('span.text-xs.font-medium.text-gray-500 dark:text-slate-400.uppercase.tracking-wider',
|
|
1413
1413
|
state.selectedBulkField ? 'Select Value' : 'Select Field'
|
|
1414
1414
|
),
|
|
1415
1415
|
]),
|
|
@@ -1441,7 +1441,7 @@ const BulkFieldUpdateDropdown = {
|
|
|
1441
1441
|
state.selectedBulkField.type === 'boolean' && m('span.ml-2',
|
|
1442
1442
|
option.value === true
|
|
1443
1443
|
? m('span.inline-flex.items-center.px-2.py-0.5.rounded-full.text-xs.font-medium.bg-green-100.text-green-800', '✓')
|
|
1444
|
-
: m('span.inline-flex.items-center.px-2.py-0.5.rounded-full.text-xs.font-medium.bg-gray-100.text-gray-600', '✗')
|
|
1444
|
+
: m('span.inline-flex.items-center.px-2.py-0.5.rounded-full.text-xs.font-medium.bg-gray-100 dark:bg-slate-800.text-gray-600', '✗')
|
|
1445
1445
|
),
|
|
1446
1446
|
])
|
|
1447
1447
|
)
|
|
@@ -1455,7 +1455,7 @@ const BulkFieldUpdateDropdown = {
|
|
|
1455
1455
|
}, [
|
|
1456
1456
|
m('.flex.items-center.gap-2', [
|
|
1457
1457
|
m('span.text-gray-700', formatColumnLabel(field.label || field.name)),
|
|
1458
|
-
m('span.text-xs.text-gray-400.uppercase', field.type),
|
|
1458
|
+
m('span.text-xs.text-gray-400 dark:text-slate-500.uppercase', field.type),
|
|
1459
1459
|
]),
|
|
1460
1460
|
m('svg.w-4.h-4.text-gray-400', { fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
1461
1461
|
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M9 5l7 7-7 7' })
|
|
@@ -1464,7 +1464,7 @@ const BulkFieldUpdateDropdown = {
|
|
|
1464
1464
|
),
|
|
1465
1465
|
|
|
1466
1466
|
// Back button when viewing values
|
|
1467
|
-
state.selectedBulkField && m('button.w-full.px-3.py-2.text-left.text-sm.text-gray-500.hover:bg-gray-50.border-t.border-gray-100.flex.items-center.gap-1', {
|
|
1467
|
+
state.selectedBulkField && m('button.w-full.px-3.py-2.text-left.text-sm.text-gray-500 dark:text-slate-400.hover:bg-gray-50 dark:hover:bg-slate-800/50 dark:hover:bg-slate-800/50.border-t.border-gray-100 dark:border-slate-700.flex.items-center.gap-1', {
|
|
1468
1468
|
onclick: () => {
|
|
1469
1469
|
state.selectedBulkField = null;
|
|
1470
1470
|
m.redraw();
|
|
@@ -1736,16 +1736,16 @@ const RecordList = {
|
|
|
1736
1736
|
m('.flex.items-center.justify-between.mb-4', [
|
|
1737
1737
|
m('.flex.items-center.gap-3', [
|
|
1738
1738
|
m('h2.text-2xl.font-bold', modelMeta?.label || modelName),
|
|
1739
|
-
modelMeta?.softDelete ? m('.flex.rounded-lg.border.border-gray-200.p-0.5', [
|
|
1739
|
+
modelMeta?.softDelete ? m('.flex.rounded-lg.border.border-gray-200 dark:border-slate-600.p-0.5', [
|
|
1740
1740
|
m('button.px-3.py-1.5.text-sm.font-medium.rounded-md.transition-colors', {
|
|
1741
|
-
class: !state.trashedView ? 'bg-indigo-600.text-white' : 'text-gray-600.hover:text-gray-900',
|
|
1741
|
+
class: !state.trashedView ? 'bg-indigo-600.text-white' : 'text-gray-600.hover:text-gray-900 dark:hover:text-slate-100 dark:hover:text-slate-100',
|
|
1742
1742
|
onclick: () => {
|
|
1743
1743
|
state.trashedView = false;
|
|
1744
1744
|
loadRecords(modelName, 1);
|
|
1745
1745
|
},
|
|
1746
1746
|
}, 'Active'),
|
|
1747
1747
|
m('button.px-3.py-1.5.text-sm.font-medium.rounded-md.transition-colors', {
|
|
1748
|
-
class: state.trashedView ? 'bg-indigo-600.text-white' : 'text-gray-600.hover:text-gray-900',
|
|
1748
|
+
class: state.trashedView ? 'bg-indigo-600.text-white' : 'text-gray-600.hover:text-gray-900 dark:hover:text-slate-100 dark:hover:text-slate-100',
|
|
1749
1749
|
onclick: () => {
|
|
1750
1750
|
state.trashedView = true;
|
|
1751
1751
|
loadRecords(modelName, 1);
|
|
@@ -1820,14 +1820,14 @@ const RecordList = {
|
|
|
1820
1820
|
m('.animate-spin.rounded-full.h-8.w-8.border-b-2.border-indigo-600'),
|
|
1821
1821
|
])
|
|
1822
1822
|
: state.records.length === 0
|
|
1823
|
-
? m('.bg-white.rounded-lg.shadow-sm.border.border-gray-200.p-12.text-center', [
|
|
1824
|
-
m('svg.w-12.h-12.mx-auto.text-gray-400.mb-4', { fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' }, [
|
|
1823
|
+
? m('.bg-white dark:bg-slate-800.rounded-lg.shadow-sm.border.border-gray-200 dark:border-slate-600.p-12.text-center', [
|
|
1824
|
+
m('svg.w-12.h-12.mx-auto.text-gray-400 dark:text-slate-500.mb-4', { fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' }, [
|
|
1825
1825
|
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '1.5', d: 'M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4' }),
|
|
1826
1826
|
]),
|
|
1827
|
-
m('h3.text-lg.font-medium.text-gray-900.mb-1', 'No records found'),
|
|
1827
|
+
m('h3.text-lg.font-medium.text-gray-900 dark:text-slate-100.mb-1', 'No records found'),
|
|
1828
1828
|
m('p.text-gray-500', activeFilterCount > 0 ? 'Try adjusting your filters' : 'Get started by creating your first record'),
|
|
1829
1829
|
])
|
|
1830
|
-
: m('.bg-white.rounded-lg.shadow-sm.border.border-gray-200.overflow-hidden', [
|
|
1830
|
+
: m('.bg-white dark:bg-slate-800.rounded-lg.shadow-sm.border.border-gray-200 dark:border-slate-600.overflow-hidden', [
|
|
1831
1831
|
// Bulk Actions Toolbar (shown when items selected)
|
|
1832
1832
|
(state.selectedRecords && state.selectedRecords.size > 0) || state.selectAllMode ? m('.bg-indigo-50.border-b.border-indigo-100.px-4.py-3.flex.items-center.justify-between', [
|
|
1833
1833
|
m('.flex.items-center.gap-3', [
|
|
@@ -1853,7 +1853,7 @@ const RecordList = {
|
|
|
1853
1853
|
]),
|
|
1854
1854
|
m('.flex.items-center.gap-2', [
|
|
1855
1855
|
state.trashedView && modelMeta?.softDelete
|
|
1856
|
-
? m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-green-600.bg-white.border.border-green-200.rounded.hover:bg-green-50.transition-colors', {
|
|
1856
|
+
? m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-green-600.bg-white dark:bg-slate-800.border.border-green-200.rounded.hover:bg-green-50.transition-colors', {
|
|
1857
1857
|
disabled: state.bulkActionInProgress,
|
|
1858
1858
|
onclick: async () => {
|
|
1859
1859
|
if (!confirm('Restore the selected records?')) return;
|
|
@@ -1880,7 +1880,7 @@ const RecordList = {
|
|
|
1880
1880
|
),
|
|
1881
1881
|
'Restore',
|
|
1882
1882
|
])
|
|
1883
|
-
: m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-red-600.bg-white.border.border-red-200.rounded.hover:bg-red-50.transition-colors', {
|
|
1883
|
+
: m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-red-600.bg-white dark:bg-slate-800.border.border-red-200.rounded.hover:bg-red-50.transition-colors', {
|
|
1884
1884
|
disabled: state.bulkActionInProgress,
|
|
1885
1885
|
onclick: async () => {
|
|
1886
1886
|
const count = state.selectAllMode ? state.pagination.total : state.selectedRecords.size;
|
|
@@ -1908,7 +1908,7 @@ const RecordList = {
|
|
|
1908
1908
|
),
|
|
1909
1909
|
'Delete',
|
|
1910
1910
|
]),
|
|
1911
|
-
!state.trashedView ? m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-blue-600.bg-white.border.border-blue-200.rounded.hover:bg-blue-50.transition-colors', {
|
|
1911
|
+
!state.trashedView ? m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-blue-600.bg-white dark:bg-slate-800.border.border-blue-200.rounded.hover:bg-blue-50.transition-colors', {
|
|
1912
1912
|
disabled: state.bulkActionInProgress,
|
|
1913
1913
|
onclick: async () => {
|
|
1914
1914
|
state.bulkActionInProgress = true;
|
|
@@ -1939,7 +1939,7 @@ const RecordList = {
|
|
|
1939
1939
|
),
|
|
1940
1940
|
'Export JSON',
|
|
1941
1941
|
]) : null,
|
|
1942
|
-
!state.trashedView ? m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-green-600.bg-white.border.border-green-200.rounded.hover:bg-green-50.transition-colors', {
|
|
1942
|
+
!state.trashedView ? m('button.inline-flex.items-center.gap-1.px-3.py-1.5.text-sm.font-medium.text-green-600.bg-white dark:bg-slate-800.border.border-green-200.rounded.hover:bg-green-50.transition-colors', {
|
|
1943
1943
|
disabled: state.bulkActionInProgress,
|
|
1944
1944
|
onclick: async () => {
|
|
1945
1945
|
state.bulkActionInProgress = true;
|
|
@@ -1981,7 +1981,7 @@ const RecordList = {
|
|
|
1981
1981
|
loadRecords(modelName, state.pagination.page);
|
|
1982
1982
|
},
|
|
1983
1983
|
}) : null,
|
|
1984
|
-
m('button.px-3.py-1.5.text-sm.text-gray-500.hover:text-gray-700', {
|
|
1984
|
+
m('button.px-3.py-1.5.text-sm.text-gray-500 dark:text-slate-400.hover:text-gray-700 dark:hover:text-slate-200 dark:hover:text-slate-200', {
|
|
1985
1985
|
onclick: () => {
|
|
1986
1986
|
state.selectedRecords = new Set();
|
|
1987
1987
|
state.selectAllMode = false;
|
|
@@ -1996,11 +1996,11 @@ const RecordList = {
|
|
|
1996
1996
|
m('.overflow-auto.max-h-[calc(100vh-380px)]', { style: 'position: relative;' }, [
|
|
1997
1997
|
m('table.w-full.border-collapse', { style: 'min-width: 100%;' }, [
|
|
1998
1998
|
// Sticky header
|
|
1999
|
-
m('thead.bg-gray-50', { style: 'position: sticky; top: 0; z-index: 20;
|
|
1999
|
+
m('thead.bg-gray-50.dark:bg-slate-900', { style: 'position: sticky; top: 0; z-index: 20;' }, [
|
|
2000
2000
|
m('tr', [
|
|
2001
2001
|
// Checkbox column header (sticky left, box-shadow on right)
|
|
2002
|
-
m('th.px-4.py-3.text-left.bg-gray-50.border-b.border-gray-200', { style: 'width: 40px; position: sticky; left: 0; z-index: 15; box-shadow: 4px 0 8px -4px rgba(0,0,0,0.08);' }, [
|
|
2003
|
-
m('input[type=checkbox].rounded.border-gray-300.text-indigo-600.focus:ring-indigo-500', {
|
|
2002
|
+
m('th.px-4.py-3.text-left.bg-gray-50 dark:bg-slate-900.border-b.border-gray-200', { style: 'width: 40px; position: sticky; left: 0; z-index: 15; box-shadow: 4px 0 8px -4px rgba(0,0,0,0.08);' }, [
|
|
2003
|
+
m('input[type=checkbox].rounded.border-gray-300 dark:border-slate-600.text-indigo-600.focus:ring-indigo-500', {
|
|
2004
2004
|
checked: state.records.length > 0 && state.selectedRecords && state.selectedRecords.size === state.records.length,
|
|
2005
2005
|
indeterminate: state.selectedRecords && state.selectedRecords.size > 0 && state.selectedRecords.size < state.records.length,
|
|
2006
2006
|
onchange: (e) => {
|
|
@@ -2015,26 +2015,26 @@ const RecordList = {
|
|
|
2015
2015
|
]),
|
|
2016
2016
|
// Dynamic column headers (first column sticky left with box-shadow)
|
|
2017
2017
|
...displayColumns.map((col, i) =>
|
|
2018
|
-
m('th.px-4.py-3.text-left.text-xs.font-medium.text-gray-500.uppercase.tracking-wider.whitespace-nowrap.bg-gray-50.border-b.border-gray-200',
|
|
2018
|
+
m('th.px-4.py-3.text-left.text-xs.font-medium.text-gray-500 dark:text-slate-400.uppercase.tracking-wider.whitespace-nowrap.bg-gray-50 dark:bg-slate-900.border-b.border-gray-200',
|
|
2019
2019
|
i === 0 ? { style: 'position: sticky; left: 40px; z-index: 15; box-shadow: 4px 0 8px -4px rgba(0,0,0,0.08);' } : {},
|
|
2020
2020
|
formatColumnLabel(col.name)
|
|
2021
2021
|
)
|
|
2022
2022
|
),
|
|
2023
2023
|
// Sticky actions header (sticky right, box-shadow on left)
|
|
2024
|
-
m('th.px-4.py-3.text-right.text-xs.font-medium.text-gray-500.uppercase.tracking-wider.bg-gray-50.border-b.border-gray-200', {
|
|
2024
|
+
m('th.px-4.py-3.text-right.text-xs.font-medium.text-gray-500 dark:text-slate-400.uppercase.tracking-wider.bg-gray-50 dark:bg-slate-900.border-b.border-gray-200', {
|
|
2025
2025
|
style: 'position: sticky; right: 0; min-width: 120px; z-index: 15; box-shadow: -4px 0 8px -4px rgba(0,0,0,0.08);',
|
|
2026
2026
|
}, 'Actions'),
|
|
2027
2027
|
]),
|
|
2028
2028
|
]),
|
|
2029
2029
|
m('tbody.divide-y.divide-gray-100', state.records.map(record =>
|
|
2030
|
-
m('tr.hover:bg-gray-50.transition-colors', {
|
|
2030
|
+
m('tr.hover:bg-gray-50 dark:hover:bg-slate-800/50 dark:hover:bg-slate-800/50.transition-colors', {
|
|
2031
2031
|
class: state.selectedRecords && state.selectedRecords.has(record[primaryKey]) ? 'bg-indigo-50' : '',
|
|
2032
2032
|
}, [
|
|
2033
2033
|
// Checkbox cell (sticky left, box-shadow on right)
|
|
2034
2034
|
m('td.px-4.py-3.bg-white', {
|
|
2035
2035
|
style: 'position: sticky; left: 0; z-index: 5; box-shadow: 4px 0 8px -4px rgba(0,0,0,0.08);',
|
|
2036
2036
|
}, [
|
|
2037
|
-
m('input[type=checkbox].rounded.border-gray-300.text-indigo-600.focus:ring-indigo-500', {
|
|
2037
|
+
m('input[type=checkbox].rounded.border-gray-300 dark:border-slate-600.text-indigo-600.focus:ring-indigo-500', {
|
|
2038
2038
|
checked: state.selectedRecords && state.selectedRecords.has(record[primaryKey]),
|
|
2039
2039
|
onchange: (e) => {
|
|
2040
2040
|
if (!state.selectedRecords) state.selectedRecords = new Set();
|
|
@@ -2049,7 +2049,7 @@ const RecordList = {
|
|
|
2049
2049
|
]),
|
|
2050
2050
|
// Dynamic cell values (first column sticky left with box-shadow)
|
|
2051
2051
|
...displayColumns.map((col, i) =>
|
|
2052
|
-
m('td.px-4.py-3.text-sm.whitespace-nowrap.text-gray-700.bg-white',
|
|
2052
|
+
m('td.px-4.py-3.text-sm.whitespace-nowrap.text-gray-700 dark:text-slate-300.bg-white',
|
|
2053
2053
|
i === 0 ? { style: 'position: sticky; left: 40px; z-index: 5; box-shadow: 4px 0 8px -4px rgba(0,0,0,0.08);' } : {},
|
|
2054
2054
|
formatCellValue(record[col.name], col)
|
|
2055
2055
|
)
|
|
@@ -2172,7 +2172,7 @@ const RecordForm = {
|
|
|
2172
2172
|
state.loading ? m('p.text-gray-600', 'Loading...') :
|
|
2173
2173
|
state.error && !modelMeta ? m('.bg-red-100.border.border-red-400.text-red-700.px-4.py-3.rounded', state.error) :
|
|
2174
2174
|
|
|
2175
|
-
m('form.bg-white.rounded.shadow.flex.flex-col', {
|
|
2175
|
+
m('form.bg-white dark:bg-slate-800.rounded.shadow.flex.flex-col', {
|
|
2176
2176
|
style: 'min-height: calc(100vh - 280px);',
|
|
2177
2177
|
onsubmit: async (e) => {
|
|
2178
2178
|
e.preventDefault();
|
|
@@ -2261,16 +2261,16 @@ const RecordForm = {
|
|
|
2261
2261
|
};
|
|
2262
2262
|
|
|
2263
2263
|
return renderer(col, value, onChange, isReadonly);
|
|
2264
|
-
}) : m('p.text-gray-600.mb-4', 'Loading form fields...'),
|
|
2264
|
+
}) : m('p.text-gray-600 dark:text-slate-400.mb-4', 'Loading form fields...'),
|
|
2265
2265
|
]),
|
|
2266
2266
|
|
|
2267
2267
|
// Sticky footer buttons
|
|
2268
|
-
m('.flex.gap-4.p-4.border-t.bg-gray-50.sticky.bottom-0', [
|
|
2268
|
+
m('.flex.gap-4.p-4.border-t.bg-gray-50 dark:bg-slate-900.sticky.bottom-0', [
|
|
2269
2269
|
m('button.bg-blue-600.text-white.px-6.py-2.rounded.hover:bg-blue-700.disabled:opacity-50', {
|
|
2270
2270
|
type: 'submit',
|
|
2271
2271
|
disabled: state.loading,
|
|
2272
2272
|
}, state.loading ? 'Saving...' : 'Save'),
|
|
2273
|
-
m('button.bg-gray-200.text-gray-800.px-6.py-2.rounded.hover:bg-gray-300[type=button]', {
|
|
2273
|
+
m('button.bg-gray-200 dark:bg-slate-700.text-gray-800 dark:text-slate-200.px-6.py-2.rounded.hover:bg-gray-300 dark:hover:bg-slate-600 dark:hover:bg-slate-600[type=button]', {
|
|
2274
2274
|
onclick: () => m.route.set('/models/' + modelName),
|
|
2275
2275
|
}, 'Cancel'),
|
|
2276
2276
|
]),
|