@nocobase/app-template-default 1.0.0-beta.67 → 1.0.0-beta.69
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/.agents/rules/components.md +2 -2
- package/.agents/rules/shell.md +5 -1
- package/AGENTS.md +5 -3
- package/Dockerfile.dockerignore +0 -1
- package/README.MD +3 -1
- package/client/app.ts +15 -0
- package/client/components/data-table/column-header.tsx +91 -0
- package/client/components/data-table/data-table.tsx +216 -0
- package/client/components/data-table/index.ts +13 -0
- package/client/components/data-table/pagination.tsx +165 -0
- package/client/components/data-table/view-options.tsx +77 -0
- package/client/components/page-header.tsx +1 -1
- package/client/components/permission-editor.tsx +589 -0
- package/client/components/permission-filter.tsx +455 -0
- package/client/components/route-overlay.tsx +26 -13
- package/client/components/status-badge.tsx +7 -1
- package/client/components/ui/checkbox.tsx +25 -0
- package/client/components/ui/sidebar.tsx +1 -4
- package/client/components/ui/switch.tsx +30 -0
- package/client/components/ui/table.tsx +113 -0
- package/client/extensions/nocobase-inbox/inbox-item.tsx +44 -58
- package/client/extensions/nocobase-inbox/inbox-list.tsx +73 -75
- package/client/index.tsx +4 -0
- package/client/layouts/components/app-sidebar.tsx +6 -6
- package/client/layouts/components/layout-header.tsx +1 -1
- package/client/layouts/components/navigation-menu.tsx +223 -12
- package/client/layouts/components/sidebar-footer.tsx +1 -1
- package/client/layouts/components/user-menu.tsx +1 -1
- package/client/layouts/use-sidebar-preference.ts +62 -42
- package/client/lib/navigation-transform.ts +8 -0
- package/client/lib/scrollbar.ts +88 -0
- package/client/locales/system/en-US.ts +11 -0
- package/client/locales/system/settings-en-US.ts +141 -0
- package/client/locales/system/settings-zh-CN.ts +135 -0
- package/client/locales/system/zh-CN.ts +22 -12
- package/client/pages/auth/auth-page.css +52 -0
- package/client/pages/auth/login.tsx +1 -1
- package/client/pages/auth/reset-password.tsx +57 -14
- package/client/pages/auth/shared.tsx +26 -24
- package/client/pages/home/index.tsx +2 -2
- package/client/pages/settings/hooks.tsx +137 -0
- package/client/pages/settings/permission-filters.tsx +119 -0
- package/client/pages/settings/permissions-model.ts +260 -0
- package/client/pages/settings/role-form.tsx +426 -0
- package/client/pages/settings/roles.tsx +163 -0
- package/client/pages/settings/routes.ts +79 -0
- package/client/pages/settings/shared.tsx +119 -0
- package/client/pages/settings/user-detail.tsx +268 -0
- package/client/pages/settings/user-form.tsx +427 -0
- package/client/pages/settings/users.tsx +451 -0
- package/client/routing/app-router.tsx +4 -1
- package/client/routing/route-navigation.ts +10 -1
- package/client/routing/session-preparation.tsx +65 -0
- package/client/styles.css +257 -24
- package/client/theme/theme-settings.tsx +12 -7
- package/client/theme/themes/compact.css +9 -14
- package/client/theme/themes/default.css +7 -12
- package/package.json +26 -25
- package/server/app.ts +2 -0
- package/server/config/notification.ts +4 -7
- package/tests/components/app-layout-routes.test.tsx +14 -7
- package/tests/components/auth-i18n.test.tsx +57 -5
- package/tests/components/data-table.test.tsx +127 -0
- package/tests/components/layout-i18n.test.tsx +10 -3
- package/tests/components/navigation-menu.test.tsx +155 -16
- package/tests/components/permission-editor.test.tsx +477 -0
- package/tests/components/permission-filter-binding.test.tsx +150 -0
- package/tests/components/permission-filter.test.tsx +202 -0
- package/tests/components/settings.test.tsx +294 -0
- package/tests/components/sidebar-permissions.test.tsx +17 -19
- package/tests/components/sidebar-preference.test.tsx +209 -14
- package/tests/components/status-badge.test.tsx +22 -0
- package/tests/components/user-permissions.test.tsx +142 -0
- package/tests/fixtures/theme-tokens.tsx +9 -1
- package/tests/logic/asset-url-build.test.ts +0 -1
- package/tests/logic/client-routes.test.ts +40 -0
- package/tests/logic/client-shell.test.tsx +10 -2
- package/tests/logic/config-example.test.ts +30 -0
- package/tests/logic/dev-client-watch.test.ts +8 -1
- package/tests/logic/route-overlay.test.tsx +42 -0
- package/tests/logic/scrollbar.test.ts +88 -0
- package/tests/logic/session-preparation.test.tsx +223 -0
- package/tests/logic/settings-permissions.test.ts +168 -0
- package/tests/logic/theme-tokens.test.ts +1 -0
- package/vite.config.ts +0 -22
- package/vitest.config.ts +1 -0
- package/client/agent-annotations-host.ts +0 -25
package/client/styles.css
CHANGED
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
--color-muted-foreground: var(--muted-foreground);
|
|
51
51
|
--color-accent: var(--accent);
|
|
52
52
|
--color-accent-foreground: var(--accent-foreground);
|
|
53
|
+
--color-hover: var(--hover);
|
|
53
54
|
--color-destructive: var(--destructive);
|
|
54
55
|
--color-border: var(--border);
|
|
55
56
|
--color-input: var(--input);
|
|
@@ -138,16 +139,28 @@
|
|
|
138
139
|
|
|
139
140
|
/* Application-wide interaction and badge treatment, outside generated primitives. */
|
|
140
141
|
@layer base {
|
|
142
|
+
/* Whatever may be clicked shows the pointer, the plugins' pages included.
|
|
143
|
+
Tailwind 4 leaves buttons with the arrow; a control disabled (natively,
|
|
144
|
+
or as Base UI and ARIA mark it) keeps it, and a utility on an element
|
|
145
|
+
(`cursor-default`, `cursor-not-allowed`) still wins over this layer. */
|
|
141
146
|
:is(
|
|
142
147
|
button,
|
|
143
148
|
[role='button'],
|
|
144
149
|
[role='menuitem'],
|
|
150
|
+
[role='menuitemcheckbox'],
|
|
151
|
+
[role='menuitemradio'],
|
|
145
152
|
[role='option'],
|
|
146
153
|
[role='tab'],
|
|
147
154
|
[role='checkbox'],
|
|
148
155
|
[role='radio'],
|
|
149
156
|
[role='switch'],
|
|
150
157
|
[role='combobox'],
|
|
158
|
+
summary,
|
|
159
|
+
select,
|
|
160
|
+
label[for],
|
|
161
|
+
input[type='checkbox'],
|
|
162
|
+
input[type='radio'],
|
|
163
|
+
input[type='file'],
|
|
151
164
|
a[href]
|
|
152
165
|
):not(:disabled):not([aria-disabled='true']):not([data-disabled]) {
|
|
153
166
|
cursor: pointer;
|
|
@@ -161,14 +174,64 @@
|
|
|
161
174
|
padding-inline: calc(var(--spacing) * 2.5);
|
|
162
175
|
line-height: 1.4;
|
|
163
176
|
}
|
|
177
|
+
/* The small badge, `data-size='sm'`: beside a title or a name, on a card or
|
|
178
|
+
a board's card, wherever several sit in a dense row. The default one is a
|
|
179
|
+
status standing on its own, as in a table's column or a record's
|
|
180
|
+
particulars. */
|
|
181
|
+
[data-slot='badge'][data-size='sm'] {
|
|
182
|
+
min-height: calc(var(--spacing) * 5.5);
|
|
183
|
+
padding-block: 0;
|
|
184
|
+
padding-inline: calc(var(--spacing) * 1.5);
|
|
185
|
+
font-size: var(--text-xs);
|
|
186
|
+
line-height: 1.3;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* One focus for every control, across the application and the plugins'
|
|
190
|
+
pages: a half-strength border and a 2px halo at a fifth of the ring colour,
|
|
191
|
+
in place of the 3px ring at half of it that the primitives and pages draw,
|
|
192
|
+
which reads heavy. Unlayered, so it wins over their utilities without
|
|
193
|
+
editing them. A label wrapping a visually hidden control, such as an
|
|
194
|
+
option card, and a rich text editor's frame show their control's focus.
|
|
195
|
+
An invalid field keeps its red, and a destructive button its own colour. */
|
|
196
|
+
:is(
|
|
197
|
+
[data-slot='input'],
|
|
198
|
+
[data-slot='textarea'],
|
|
199
|
+
[data-slot='select-trigger'],
|
|
200
|
+
button,
|
|
201
|
+
[role='button'],
|
|
202
|
+
[role='tab'],
|
|
203
|
+
[role='menuitem'],
|
|
204
|
+
[role='checkbox'],
|
|
205
|
+
[role='switch'],
|
|
206
|
+
[role='radio'],
|
|
207
|
+
input[type='checkbox'],
|
|
208
|
+
input[type='radio'],
|
|
209
|
+
a[href]
|
|
210
|
+
):focus-visible:not([aria-invalid='true']),
|
|
211
|
+
label:has(> .sr-only:focus-visible),
|
|
212
|
+
[data-slot='rich-text-editor']:focus-within,
|
|
213
|
+
[data-slot='input-group']:has(
|
|
214
|
+
[data-slot='input-group-control']:focus-visible
|
|
215
|
+
):not(:has([aria-invalid='true'])) {
|
|
216
|
+
border-color: color-mix(in oklch, var(--ring) 50%, transparent);
|
|
217
|
+
box-shadow: 0 0 0 2px color-mix(in oklch, var(--ring) 20%, transparent);
|
|
218
|
+
}
|
|
219
|
+
[data-slot='button'].text-destructive:focus-visible:not([aria-invalid='true']) {
|
|
220
|
+
border-color: color-mix(in oklch, var(--destructive) 40%, transparent);
|
|
221
|
+
box-shadow: 0 0 0 2px color-mix(in oklch, var(--destructive) 20%, transparent);
|
|
222
|
+
}
|
|
164
223
|
|
|
165
|
-
/*
|
|
224
|
+
/* Overlays in a light frame: a faint, blurred backdrop, and the content
|
|
225
|
+
framed by the general border alone, as a card is, without the primitive's
|
|
226
|
+
ring or a heavy shadow. The plugins' copies of these primitives take it
|
|
227
|
+
too; unlayered, so it wins over their utilities. */
|
|
166
228
|
:is(
|
|
167
229
|
[data-slot='dialog-overlay'],
|
|
168
230
|
[data-slot='alert-dialog-overlay'],
|
|
169
231
|
[data-slot='sheet-overlay']
|
|
170
232
|
) {
|
|
171
|
-
background:
|
|
233
|
+
background: rgb(0 0 0 / 0.1);
|
|
234
|
+
backdrop-filter: blur(4px);
|
|
172
235
|
}
|
|
173
236
|
:is(
|
|
174
237
|
[data-slot='dialog-content'],
|
|
@@ -176,7 +239,7 @@
|
|
|
176
239
|
[data-slot='route-overlay-content']
|
|
177
240
|
) {
|
|
178
241
|
border: 1px solid var(--border);
|
|
179
|
-
box-shadow:
|
|
242
|
+
box-shadow: none;
|
|
180
243
|
}
|
|
181
244
|
[data-slot='route-overlay-content'][data-presentation='dialog'] {
|
|
182
245
|
border-radius: var(--radius-xl);
|
|
@@ -189,16 +252,13 @@
|
|
|
189
252
|
:is([data-slot='dialog-description'], [data-slot='alert-dialog-description']) {
|
|
190
253
|
line-height: 1.65;
|
|
191
254
|
}
|
|
192
|
-
:is(
|
|
193
|
-
[data-slot='dialog-footer'],
|
|
194
|
-
[data-slot='alert-dialog-footer'],
|
|
195
|
-
[data-slot='route-overlay-footer']
|
|
196
|
-
)
|
|
197
|
-
> button {
|
|
255
|
+
:is([data-slot='dialog-footer'], [data-slot='alert-dialog-footer']) > button {
|
|
198
256
|
min-height: calc(var(--spacing) * 10);
|
|
199
257
|
padding-inline: calc(var(--spacing) * 4);
|
|
200
258
|
}
|
|
201
|
-
|
|
259
|
+
/* Route overlays compose the dialog primitives, so their close button sits where a dialog's does. */
|
|
260
|
+
:is([data-slot='dialog-content'], [data-slot='route-overlay-content'])
|
|
261
|
+
> [data-slot='dialog-close'] {
|
|
202
262
|
top: calc(var(--spacing) * 4);
|
|
203
263
|
right: calc(var(--spacing) * 4);
|
|
204
264
|
}
|
|
@@ -308,14 +368,65 @@
|
|
|
308
368
|
padding-right: calc(var(--spacing) * 24);
|
|
309
369
|
}
|
|
310
370
|
|
|
311
|
-
/*
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
371
|
+
/* The navigation's rows are roomier than the sidebar primitive's: 10 units
|
|
372
|
+
high with half a unit between them, nested rows 8.5 high, in a sidebar 64
|
|
373
|
+
units wide (layouts/components/app-sidebar.tsx). The primitive's important
|
|
374
|
+
icon-mode sizes still control the collapsed rail. */
|
|
375
|
+
.app-navigation [data-slot='sidebar-menu'] {
|
|
376
|
+
gap: calc(var(--spacing) * 0.5);
|
|
377
|
+
}
|
|
378
|
+
/* Top-level groups only: a section nested in a menu sits flush. */
|
|
379
|
+
.app-navigation > nav > [data-slot='sidebar-group'] {
|
|
380
|
+
padding: calc(var(--spacing) * 2);
|
|
381
|
+
}
|
|
382
|
+
/* A section's heading reads as a heading over its entries, not as one of
|
|
383
|
+
them: half the menu's foreground, mixed toward its ground, so both colour
|
|
384
|
+
schemes follow. */
|
|
385
|
+
.app-navigation [data-sidebar='group-label'] {
|
|
386
|
+
height: calc(var(--spacing) * 8);
|
|
387
|
+
padding-inline: calc(var(--spacing) * 3.5);
|
|
388
|
+
color: color-mix(in oklch, var(--sidebar-foreground) 50%, var(--sidebar));
|
|
389
|
+
}
|
|
390
|
+
.app-navigation [data-slot='sidebar-menu-button'] {
|
|
391
|
+
height: calc(var(--spacing) * 10);
|
|
392
|
+
gap: calc(var(--spacing) * 2);
|
|
393
|
+
padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3.5);
|
|
394
|
+
}
|
|
395
|
+
/* The primitive places a row's count and its expand button for 8-unit rows;
|
|
396
|
+
both are 5 units high, so this centres them on the taller rows. */
|
|
397
|
+
.app-navigation
|
|
398
|
+
[data-slot='sidebar-menu-item']
|
|
399
|
+
> :is([data-slot='sidebar-menu-badge'], [data-slot='sidebar-menu-action']) {
|
|
400
|
+
top: calc(var(--spacing) * 2.5);
|
|
401
|
+
}
|
|
402
|
+
.app-navigation
|
|
403
|
+
[data-slot='sidebar-menu-sub-item']
|
|
404
|
+
> [data-slot='sidebar-menu-action'] {
|
|
405
|
+
top: calc(var(--spacing) * 1.75);
|
|
406
|
+
}
|
|
407
|
+
.app-navigation [data-slot='sidebar-menu-button'] > svg {
|
|
408
|
+
width: calc(var(--spacing) * 4);
|
|
409
|
+
height: calc(var(--spacing) * 4);
|
|
410
|
+
}
|
|
411
|
+
/* An entry with a count (navigation-menu.tsx) leaves room for it at the
|
|
412
|
+
row's end, so a long label truncates before reaching it. */
|
|
413
|
+
.app-navigation
|
|
414
|
+
[data-slot='sidebar-menu-item']:has(> [data-slot='sidebar-menu-badge'])
|
|
415
|
+
> [data-slot='sidebar-menu-button'] {
|
|
416
|
+
padding-right: calc(var(--spacing) * 10);
|
|
316
417
|
}
|
|
317
|
-
|
|
318
|
-
gap: calc(var(--spacing) *
|
|
418
|
+
.app-navigation [data-slot='sidebar-menu-sub'] {
|
|
419
|
+
gap: calc(var(--spacing) * 0.5);
|
|
420
|
+
padding-block: calc(var(--spacing) * 1);
|
|
421
|
+
}
|
|
422
|
+
.app-navigation [data-slot='sidebar-menu-sub-button'] {
|
|
423
|
+
height: calc(var(--spacing) * 8.5);
|
|
424
|
+
gap: calc(var(--spacing) * 2);
|
|
425
|
+
padding-inline: calc(var(--spacing) * 2.5);
|
|
426
|
+
}
|
|
427
|
+
.app-navigation [data-slot='sidebar-menu-sub-button'] > svg {
|
|
428
|
+
width: calc(var(--spacing) * 4);
|
|
429
|
+
height: calc(var(--spacing) * 4);
|
|
319
430
|
}
|
|
320
431
|
|
|
321
432
|
/* Brand tint belongs to the application shell, independent of each page's content. */
|
|
@@ -331,11 +442,20 @@
|
|
|
331
442
|
|
|
332
443
|
/* Shared table hierarchy stays neutral so semantic status colors remain distinct. */
|
|
333
444
|
[data-slot='table-header'] {
|
|
334
|
-
background:
|
|
445
|
+
background: var(--hover);
|
|
335
446
|
}
|
|
336
447
|
[data-slot='table-header'] [data-slot='table-row']:hover {
|
|
337
448
|
background: transparent;
|
|
338
449
|
}
|
|
450
|
+
/* A row under the pointer takes the --hover grey, as every hovered row and
|
|
451
|
+
list item does, rather than the primitive's half of --muted. Matched by
|
|
452
|
+
that class, so a row given another hover keeps it, and a selected row
|
|
453
|
+
keeps its own ground. */
|
|
454
|
+
[data-slot='table-row'][class~='hover:bg-muted/50']:hover:not(
|
|
455
|
+
[data-state='selected']
|
|
456
|
+
) {
|
|
457
|
+
background: var(--hover);
|
|
458
|
+
}
|
|
339
459
|
[data-slot='table-head'] {
|
|
340
460
|
height: calc(var(--spacing) * 12);
|
|
341
461
|
padding-inline: calc(var(--spacing) * 3);
|
|
@@ -355,12 +475,125 @@
|
|
|
355
475
|
color: var(--primary);
|
|
356
476
|
}
|
|
357
477
|
|
|
358
|
-
/*
|
|
359
|
-
|
|
478
|
+
/* A card's frame in the general border, as every other line: the card
|
|
479
|
+
primitive and the plugins' copies draw their ring at a tenth of the
|
|
480
|
+
foreground. Matched by that class, so a card given another ring colour
|
|
481
|
+
keeps it; unlayered, so it wins over the utility. */
|
|
482
|
+
[data-slot='card'][class~='ring-foreground/10'] {
|
|
483
|
+
--tw-ring-color: var(--border);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/* Line tabs as a record page's tabs: from the left, the open one in the
|
|
487
|
+
foreground over a 2px line that sits on a thin rule under the row, the
|
|
488
|
+
others muted until hovered. Unlayered, so it wins over the primitive's
|
|
489
|
+
utilities. A row whose tabs keep off its edges sets --tabs-inset; its rule
|
|
490
|
+
still runs edge to edge. */
|
|
491
|
+
[data-slot='tabs-list'][data-variant='line'][data-orientation='horizontal'] {
|
|
492
|
+
width: 100%;
|
|
493
|
+
height: auto;
|
|
494
|
+
justify-content: flex-start;
|
|
495
|
+
gap: calc(var(--spacing) * 5);
|
|
496
|
+
padding: 0 var(--tabs-inset, 0px);
|
|
497
|
+
border-bottom: 1px solid var(--border);
|
|
498
|
+
}
|
|
499
|
+
[data-slot='tabs-list'][data-variant='line'][data-orientation='horizontal']
|
|
500
|
+
> [data-slot='tabs-trigger'] {
|
|
501
|
+
flex: none;
|
|
360
502
|
height: calc(var(--spacing) * 10);
|
|
361
|
-
padding-inline:
|
|
503
|
+
padding-inline: 0;
|
|
504
|
+
border-inline-width: 0;
|
|
505
|
+
color: var(--muted-foreground);
|
|
362
506
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
507
|
+
[data-slot='tabs-list'][data-variant='line'][data-orientation='horizontal']
|
|
508
|
+
> [data-slot='tabs-trigger']:is(:hover, [data-active]) {
|
|
509
|
+
color: var(--foreground);
|
|
510
|
+
}
|
|
511
|
+
[data-slot='tabs-list'][data-variant='line'][data-orientation='horizontal']
|
|
512
|
+
> [data-slot='tabs-trigger']::after {
|
|
513
|
+
bottom: -1px;
|
|
514
|
+
height: 2px;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* Every scrollbar, across and down: a thin rounded bar in a faint grey on no
|
|
518
|
+
track, drawn only while its element scrolls or the mouse is near the edge
|
|
519
|
+
it runs along (revealScrollbarsWhileScrolling
|
|
520
|
+
in client/lib/scrollbar.ts marks it `data-scrolling` until it has been
|
|
521
|
+
still for a moment) and transparent otherwise, so showing it moves nothing;
|
|
522
|
+
a little firmer under the pointer. Chromium and Safari draw it through the
|
|
523
|
+
-webkit- pseudo-elements, which allow a thinner bar than
|
|
524
|
+
`scrollbar-width: thin`; they ignore those wherever the standard properties
|
|
525
|
+
are set (scrollbar-color is inherited), so the standard ones are given only
|
|
526
|
+
to a browser without them (Firefox). */
|
|
527
|
+
::-webkit-scrollbar {
|
|
528
|
+
width: 6px;
|
|
529
|
+
height: 6px;
|
|
530
|
+
}
|
|
531
|
+
::-webkit-scrollbar-track,
|
|
532
|
+
::-webkit-scrollbar-corner {
|
|
533
|
+
background: transparent;
|
|
534
|
+
}
|
|
535
|
+
::-webkit-scrollbar-thumb {
|
|
536
|
+
border-radius: 9999px;
|
|
537
|
+
background-color: transparent;
|
|
538
|
+
}
|
|
539
|
+
[data-scrolling]::-webkit-scrollbar-thumb {
|
|
540
|
+
background-color: color-mix(
|
|
541
|
+
in oklab,
|
|
542
|
+
var(--muted-foreground) 20%,
|
|
543
|
+
transparent
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
[data-scrolling]::-webkit-scrollbar-thumb:hover {
|
|
547
|
+
background-color: color-mix(
|
|
548
|
+
in oklab,
|
|
549
|
+
var(--muted-foreground) 30%,
|
|
550
|
+
transparent
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
554
|
+
* {
|
|
555
|
+
scrollbar-width: thin;
|
|
556
|
+
scrollbar-color: transparent transparent;
|
|
557
|
+
}
|
|
558
|
+
[data-scrolling] {
|
|
559
|
+
scrollbar-color: color-mix(
|
|
560
|
+
in oklab,
|
|
561
|
+
var(--muted-foreground) 20%,
|
|
562
|
+
transparent
|
|
563
|
+
)
|
|
564
|
+
transparent;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/* A scroller whose bar always shows, thicker, to be dragged: one wider than
|
|
569
|
+
the page, such as a board, which a mouse without a sideways wheel moves
|
|
570
|
+
only by its bar. Plain rules beside the ones above rather than a utility,
|
|
571
|
+
which their unlayered rules would outrank. */
|
|
572
|
+
.scroll-shown::-webkit-scrollbar {
|
|
573
|
+
width: 8px;
|
|
574
|
+
height: 8px;
|
|
575
|
+
}
|
|
576
|
+
.scroll-shown::-webkit-scrollbar-thumb {
|
|
577
|
+
background-color: color-mix(
|
|
578
|
+
in oklab,
|
|
579
|
+
var(--muted-foreground) 25%,
|
|
580
|
+
transparent
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
.scroll-shown::-webkit-scrollbar-thumb:hover {
|
|
584
|
+
background-color: color-mix(
|
|
585
|
+
in oklab,
|
|
586
|
+
var(--muted-foreground) 40%,
|
|
587
|
+
transparent
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
591
|
+
.scroll-shown {
|
|
592
|
+
scrollbar-color: color-mix(
|
|
593
|
+
in oklab,
|
|
594
|
+
var(--muted-foreground) 25%,
|
|
595
|
+
transparent
|
|
596
|
+
)
|
|
597
|
+
transparent;
|
|
598
|
+
}
|
|
366
599
|
}
|
|
@@ -36,7 +36,7 @@ export function ThemeSettings(): ReactElement {
|
|
|
36
36
|
aria-label={title}
|
|
37
37
|
size='icon'
|
|
38
38
|
variant='outline'
|
|
39
|
-
className='size-10 rounded-xl border-border
|
|
39
|
+
className='size-10 rounded-xl border-border bg-background/60 hover:bg-accent/50'
|
|
40
40
|
/>
|
|
41
41
|
}
|
|
42
42
|
>
|
|
@@ -70,13 +70,15 @@ export function ThemeSettings(): ReactElement {
|
|
|
70
70
|
<label
|
|
71
71
|
key={mode}
|
|
72
72
|
className={cn(
|
|
73
|
-
'relative flex min-w-0 cursor-pointer items-center justify-center gap-1.5 rounded-md px-2 py-1.5 text-xs font-medium transition-colors select-none
|
|
73
|
+
'relative flex min-w-0 cursor-pointer items-center justify-center gap-1.5 rounded-md px-2 py-1.5 text-xs font-medium transition-colors select-none',
|
|
74
74
|
isSelected
|
|
75
75
|
? 'bg-background text-foreground shadow-xs'
|
|
76
76
|
: 'text-muted-foreground hover:bg-background/40 hover:text-foreground',
|
|
77
77
|
)}
|
|
78
78
|
>
|
|
79
|
-
|
|
79
|
+
{/* `absolute` over the primitive's `relative`, which would keep
|
|
80
|
+
the hidden radio in the row and push the words aside. */}
|
|
81
|
+
<RadioGroupItem value={mode} className='absolute sr-only' />
|
|
80
82
|
<ModeIcon aria-hidden='true' className='size-3.5 shrink-0' />
|
|
81
83
|
<span className='whitespace-nowrap'>
|
|
82
84
|
{t('appearance.' + mode, {
|
|
@@ -109,18 +111,21 @@ export function ThemeSettings(): ReactElement {
|
|
|
109
111
|
<label
|
|
110
112
|
key={item.id}
|
|
111
113
|
className={cn(
|
|
112
|
-
'group relative flex cursor-pointer flex-col rounded-xl border p-2 text-left transition-all select-none
|
|
114
|
+
'group relative flex cursor-pointer flex-col rounded-xl border p-2 text-left transition-all select-none',
|
|
113
115
|
isSelected
|
|
114
116
|
? 'border-primary ring-2 ring-primary/20 bg-primary/5 shadow-xs'
|
|
115
|
-
: 'border-border
|
|
117
|
+
: 'border-border hover:bg-muted/30',
|
|
116
118
|
)}
|
|
117
119
|
>
|
|
118
|
-
<RadioGroupItem
|
|
120
|
+
<RadioGroupItem
|
|
121
|
+
value={item.id}
|
|
122
|
+
className='absolute sr-only'
|
|
123
|
+
/>
|
|
119
124
|
<div className='mb-2 h-16 w-full'>
|
|
120
125
|
<div
|
|
121
126
|
aria-hidden='true'
|
|
122
127
|
data-theme={item.id}
|
|
123
|
-
className='theme-preview relative flex h-full overflow-hidden rounded-lg border border-border
|
|
128
|
+
className='theme-preview relative flex h-full overflow-hidden rounded-lg border border-border bg-background shadow-2xs'
|
|
124
129
|
>
|
|
125
130
|
{/* Mini Sidebar */}
|
|
126
131
|
<div className='flex w-6 flex-col gap-1 border-r border-sidebar-border/50 bg-sidebar p-1'>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
|
|
10
10
|
'Courier New', monospace;
|
|
11
11
|
--font-heading: var(--font-sans);
|
|
12
|
-
--spacing: 0.
|
|
12
|
+
--spacing: 0.225rem;
|
|
13
13
|
--text-xs: 0.75rem;
|
|
14
14
|
--text-xs--line-height: calc(1 / 0.75);
|
|
15
15
|
--text-sm: 0.875rem;
|
|
@@ -45,15 +45,11 @@
|
|
|
45
45
|
--shadow-xl:
|
|
46
46
|
0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
47
47
|
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
48
|
-
--radius: 0.
|
|
48
|
+
--radius: 0.5rem;
|
|
49
49
|
--background: oklch(0.985 0 0);
|
|
50
50
|
--foreground: oklch(0.16 0 0);
|
|
51
51
|
--card: oklch(1 0 0);
|
|
52
52
|
--card-foreground: oklch(0.16 0 0);
|
|
53
|
-
--overlay-backdrop: rgb(15 23 42 / 0.28);
|
|
54
|
-
--overlay-shadow:
|
|
55
|
-
0 24px 64px -16px rgb(15 23 42 / 0.22),
|
|
56
|
-
0 8px 24px -12px rgb(15 23 42 / 0.16);
|
|
57
53
|
--popover: oklch(1 0 0);
|
|
58
54
|
--popover-foreground: oklch(0.16 0 0);
|
|
59
55
|
--primary: #002ad1;
|
|
@@ -71,8 +67,9 @@
|
|
|
71
67
|
--muted-foreground: oklch(0.52 0 0);
|
|
72
68
|
--accent: rgb(237 242 255);
|
|
73
69
|
--accent-foreground: rgb(0 42 209);
|
|
70
|
+
--hover: color-mix(in srgb, var(--muted) 70%, var(--card));
|
|
74
71
|
--destructive: oklch(0.577 0.245 27.325);
|
|
75
|
-
--border: oklch(0.9 0 0);
|
|
72
|
+
--border: oklch(0.9 0 0 / 60%);
|
|
76
73
|
--input: oklch(0.9 0 0);
|
|
77
74
|
--ring: var(--primary);
|
|
78
75
|
--chart-1: oklch(0.646 0.222 41.116);
|
|
@@ -84,8 +81,8 @@
|
|
|
84
81
|
--sidebar-foreground: var(--card-foreground);
|
|
85
82
|
--sidebar-primary: color-mix(in srgb, var(--primary) 8%, var(--sidebar));
|
|
86
83
|
--sidebar-primary-foreground: var(--primary);
|
|
87
|
-
--sidebar-accent: var(--
|
|
88
|
-
--sidebar-accent-foreground: var(--
|
|
84
|
+
--sidebar-accent: var(--hover);
|
|
85
|
+
--sidebar-accent-foreground: var(--sidebar-foreground);
|
|
89
86
|
--sidebar-border: var(--border);
|
|
90
87
|
--sidebar-ring: var(--ring);
|
|
91
88
|
}
|
|
@@ -96,9 +93,6 @@
|
|
|
96
93
|
--foreground: oklch(0.96 0 0);
|
|
97
94
|
--card: oklch(0.18 0 0);
|
|
98
95
|
--card-foreground: oklch(0.985 0 0);
|
|
99
|
-
--overlay-backdrop: rgb(0 0 0 / 0.58);
|
|
100
|
-
--overlay-shadow:
|
|
101
|
-
0 24px 64px -16px rgb(0 0 0 / 0.6), 0 8px 24px -12px rgb(0 0 0 / 0.4);
|
|
102
96
|
--popover: oklch(0.18 0 0);
|
|
103
97
|
--popover-foreground: oklch(0.985 0 0);
|
|
104
98
|
--primary: #8ca9ff;
|
|
@@ -113,6 +107,7 @@
|
|
|
113
107
|
--muted-foreground: oklch(0.7 0 0);
|
|
114
108
|
--accent: rgb(30 42 72);
|
|
115
109
|
--accent-foreground: rgb(174 194 255);
|
|
110
|
+
--hover: color-mix(in srgb, var(--muted) 70%, var(--card));
|
|
116
111
|
--destructive: oklch(0.704 0.191 22.216);
|
|
117
112
|
--border: oklch(1 0 0 / 10%);
|
|
118
113
|
--input: oklch(1 0 0 / 15%);
|
|
@@ -126,8 +121,8 @@
|
|
|
126
121
|
--sidebar-foreground: var(--card-foreground);
|
|
127
122
|
--sidebar-primary: color-mix(in srgb, var(--primary) 8%, var(--sidebar));
|
|
128
123
|
--sidebar-primary-foreground: var(--primary);
|
|
129
|
-
--sidebar-accent: var(--
|
|
130
|
-
--sidebar-accent-foreground: var(--
|
|
124
|
+
--sidebar-accent: var(--hover);
|
|
125
|
+
--sidebar-accent-foreground: var(--sidebar-foreground);
|
|
131
126
|
--sidebar-border: var(--border);
|
|
132
127
|
--sidebar-ring: var(--ring);
|
|
133
128
|
}
|
|
@@ -51,10 +51,6 @@
|
|
|
51
51
|
--foreground: oklch(0.16 0 0);
|
|
52
52
|
--card: oklch(1 0 0);
|
|
53
53
|
--card-foreground: oklch(0.16 0 0);
|
|
54
|
-
--overlay-backdrop: rgb(15 23 42 / 0.28);
|
|
55
|
-
--overlay-shadow:
|
|
56
|
-
0 24px 64px -16px rgb(15 23 42 / 0.22),
|
|
57
|
-
0 8px 24px -12px rgb(15 23 42 / 0.16);
|
|
58
54
|
--popover: oklch(1 0 0);
|
|
59
55
|
--popover-foreground: oklch(0.16 0 0);
|
|
60
56
|
--primary: #002ad1;
|
|
@@ -72,8 +68,9 @@
|
|
|
72
68
|
--muted-foreground: oklch(0.52 0 0);
|
|
73
69
|
--accent: rgb(237 242 255);
|
|
74
70
|
--accent-foreground: rgb(0 42 209);
|
|
71
|
+
--hover: color-mix(in srgb, var(--muted) 70%, var(--card));
|
|
75
72
|
--destructive: oklch(0.577 0.245 27.325);
|
|
76
|
-
--border: oklch(0.9 0 0);
|
|
73
|
+
--border: oklch(0.9 0 0 / 60%);
|
|
77
74
|
--input: oklch(0.9 0 0);
|
|
78
75
|
--ring: var(--primary);
|
|
79
76
|
--chart-1: oklch(0.646 0.222 41.116);
|
|
@@ -85,8 +82,8 @@
|
|
|
85
82
|
--sidebar-foreground: var(--card-foreground);
|
|
86
83
|
--sidebar-primary: color-mix(in srgb, var(--primary) 8%, var(--sidebar));
|
|
87
84
|
--sidebar-primary-foreground: var(--primary);
|
|
88
|
-
--sidebar-accent: var(--
|
|
89
|
-
--sidebar-accent-foreground: var(--
|
|
85
|
+
--sidebar-accent: var(--hover);
|
|
86
|
+
--sidebar-accent-foreground: var(--sidebar-foreground);
|
|
90
87
|
--sidebar-border: var(--border);
|
|
91
88
|
--sidebar-ring: var(--ring);
|
|
92
89
|
}
|
|
@@ -98,9 +95,6 @@
|
|
|
98
95
|
--foreground: oklch(0.96 0 0);
|
|
99
96
|
--card: oklch(0.18 0 0);
|
|
100
97
|
--card-foreground: oklch(0.985 0 0);
|
|
101
|
-
--overlay-backdrop: rgb(0 0 0 / 0.58);
|
|
102
|
-
--overlay-shadow:
|
|
103
|
-
0 24px 64px -16px rgb(0 0 0 / 0.6), 0 8px 24px -12px rgb(0 0 0 / 0.4);
|
|
104
98
|
--popover: oklch(0.18 0 0);
|
|
105
99
|
--popover-foreground: oklch(0.985 0 0);
|
|
106
100
|
--primary: #8ca9ff;
|
|
@@ -115,6 +109,7 @@
|
|
|
115
109
|
--muted-foreground: oklch(0.7 0 0);
|
|
116
110
|
--accent: rgb(30 42 72);
|
|
117
111
|
--accent-foreground: rgb(174 194 255);
|
|
112
|
+
--hover: color-mix(in srgb, var(--muted) 70%, var(--card));
|
|
118
113
|
--destructive: oklch(0.704 0.191 22.216);
|
|
119
114
|
--border: oklch(1 0 0 / 10%);
|
|
120
115
|
--input: oklch(1 0 0 / 15%);
|
|
@@ -128,8 +123,8 @@
|
|
|
128
123
|
--sidebar-foreground: var(--card-foreground);
|
|
129
124
|
--sidebar-primary: color-mix(in srgb, var(--primary) 8%, var(--sidebar));
|
|
130
125
|
--sidebar-primary-foreground: var(--primary);
|
|
131
|
-
--sidebar-accent: var(--
|
|
132
|
-
--sidebar-accent-foreground: var(--
|
|
126
|
+
--sidebar-accent: var(--hover);
|
|
127
|
+
--sidebar-accent-foreground: var(--sidebar-foreground);
|
|
133
128
|
--sidebar-border: var(--border);
|
|
134
129
|
--sidebar-ring: var(--ring);
|
|
135
130
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/app-template-default",
|
|
3
3
|
"displayName": "Default Template",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.69",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"prettier": "@nocobase/dev-config/prettier",
|
|
7
7
|
"engines": {
|
|
@@ -9,13 +9,12 @@
|
|
|
9
9
|
},
|
|
10
10
|
"nocobase": {
|
|
11
11
|
"templateKind": "app",
|
|
12
|
-
"defaultTemplateVersion": "1.0.0-beta.
|
|
12
|
+
"defaultTemplateVersion": "1.0.0-beta.69"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@ai-sdk/react": "2.0.0",
|
|
16
16
|
"@base-ui/react": "^1.6.0",
|
|
17
17
|
"@dicebear/core": "^9.4.3",
|
|
18
|
-
"@gchust/agent-annotations": "0.1.9",
|
|
19
18
|
"@hookform/resolvers": "^5.0.1",
|
|
20
19
|
"@playwright/test": "^1.62.1",
|
|
21
20
|
"@refinedev/cli": "^2.16.48",
|
|
@@ -27,6 +26,7 @@
|
|
|
27
26
|
"@tailwindcss/postcss": "^4.1.4",
|
|
28
27
|
"@tailwindcss/vite": "^4.1.8",
|
|
29
28
|
"@tanstack/react-query": "^5.81.5",
|
|
29
|
+
"@tanstack/react-table": "^8.2.6",
|
|
30
30
|
"@testing-library/jest-dom": "^7.0.0",
|
|
31
31
|
"@testing-library/react": "^16.3.2",
|
|
32
32
|
"@testing-library/user-event": "^14.6.3",
|
|
@@ -75,13 +75,13 @@
|
|
|
75
75
|
"vite": "^6.3.5",
|
|
76
76
|
"vitest": "^4.1.10",
|
|
77
77
|
"tar": "^7.5.22",
|
|
78
|
-
"@nocobase/app-client": "^3.0.0-beta.
|
|
78
|
+
"@nocobase/app-client": "^3.0.0-beta.2",
|
|
79
79
|
"@nocobase/app-plugin-template-print": "0.0.2-beta.2",
|
|
80
|
-
"@nocobase/app-skills": "0.1.0-beta.
|
|
81
|
-
"@nocobase/app-testing": "0.1.0-beta.
|
|
80
|
+
"@nocobase/app-skills": "0.1.0-beta.37",
|
|
81
|
+
"@nocobase/app-testing": "0.1.0-beta.4",
|
|
82
82
|
"@nocobase/app-websocket": "^0.0.2-beta.0",
|
|
83
|
-
"@nocobase/
|
|
84
|
-
"@nocobase/
|
|
83
|
+
"@nocobase/drive": "^0.1.0-beta.6",
|
|
84
|
+
"@nocobase/dev-config": "0.1.0-beta.23",
|
|
85
85
|
"@nocobase/logging": "^0.1.0-beta.7",
|
|
86
86
|
"@nocobase/session": "^0.1.0-beta.3"
|
|
87
87
|
},
|
|
@@ -142,35 +142,35 @@
|
|
|
142
142
|
"@oclif/core": "^4.14.0",
|
|
143
143
|
"better-auth": "1.7.5",
|
|
144
144
|
"hono": "^4.13.2",
|
|
145
|
-
"@nocobase/app-plugin-api-keys": "^1.0.0-beta.
|
|
146
|
-
"@nocobase/app-plugin-authentication": "^2.0.0-beta.
|
|
147
|
-
"@nocobase/app-plugin-authorization": "^1.0.0-beta.
|
|
148
|
-
"@nocobase/app-plugin-database-explorer": "^1.0.0-beta.
|
|
149
|
-
"@nocobase/app-plugin-file": "^1.0.0-beta.23",
|
|
145
|
+
"@nocobase/app-plugin-api-keys": "^1.0.0-beta.17",
|
|
146
|
+
"@nocobase/app-plugin-authentication": "^2.0.0-beta.10",
|
|
147
|
+
"@nocobase/app-plugin-authorization": "^1.0.0-beta.28",
|
|
148
|
+
"@nocobase/app-plugin-database-explorer": "^1.0.0-beta.15",
|
|
150
149
|
"@nocobase/app-plugin-i18n": "^1.0.0-beta.16",
|
|
151
|
-
"@nocobase/app-plugin-mail": "^1.0.0-beta.
|
|
150
|
+
"@nocobase/app-plugin-mail": "^1.0.0-beta.14",
|
|
151
|
+
"@nocobase/app-plugin-file": "^1.0.0-beta.24",
|
|
152
152
|
"@nocobase/app-plugin-notification": "^1.0.0-beta.27",
|
|
153
|
-
"@nocobase/app-plugin-notification-in-app": "^1.0.0-beta.
|
|
154
|
-
"@nocobase/app-plugin-notification-providers": "^0.2.0-beta.
|
|
153
|
+
"@nocobase/app-plugin-notification-in-app": "^1.0.0-beta.25",
|
|
154
|
+
"@nocobase/app-plugin-notification-providers": "^0.2.0-beta.12",
|
|
155
155
|
"@nocobase/app-plugin-scheduler": "^1.0.0-beta.17",
|
|
156
|
-
"@nocobase/app-plugin-users": "^2.0.0-beta.
|
|
157
|
-
"@nocobase/app-server": "^2.0.0-beta.5",
|
|
156
|
+
"@nocobase/app-plugin-users": "^2.0.0-beta.5",
|
|
158
157
|
"@nocobase/config": "^0.1.0-beta.3",
|
|
159
|
-
"@nocobase/
|
|
160
|
-
"@nocobase/db
|
|
158
|
+
"@nocobase/app-server": "^2.0.0-beta.8",
|
|
159
|
+
"@nocobase/db": "^1.0.0-beta.21",
|
|
161
160
|
"@nocobase/service-provider": "^0.0.2-beta.2",
|
|
161
|
+
"@nocobase/db-sqlite": "^0.1.0-beta.6",
|
|
162
162
|
"@nocobase/snowflake": "^1.0.0-beta.4",
|
|
163
163
|
"@nocobase/app-plugin-authz-default-access": "^1.0.0-beta.13",
|
|
164
164
|
"@nocobase/app-plugin-authz-sharing-rules": "^1.0.0-beta.13",
|
|
165
165
|
"@nocobase/app-plugin-authz-restriction-rules": "^1.0.0-beta.12",
|
|
166
|
-
"@nocobase/authorization": "^1.0.0-beta.
|
|
166
|
+
"@nocobase/authorization": "^1.0.0-beta.14",
|
|
167
167
|
"@nocobase/queue": "^0.1.0-beta.9",
|
|
168
168
|
"@nocobase/jobs": "^0.1.0-beta.3",
|
|
169
|
-
"@nocobase/lifecycle": "^0.1.0-beta.
|
|
169
|
+
"@nocobase/lifecycle": "^0.1.0-beta.2",
|
|
170
170
|
"@nocobase/i18n": "^1.0.0-beta.7",
|
|
171
|
-
"@nocobase/caching": "^0.1.0-beta.3",
|
|
172
171
|
"@nocobase/repository-input": "^0.1.0-beta.3",
|
|
173
|
-
"@nocobase/
|
|
172
|
+
"@nocobase/caching": "^0.1.0-beta.3",
|
|
173
|
+
"@nocobase/app-cli": "^1.0.0-beta.23"
|
|
174
174
|
},
|
|
175
175
|
"description": "NocoBase 3 application template with the standard product capabilities.",
|
|
176
176
|
"imports": {
|
|
@@ -178,7 +178,8 @@
|
|
|
178
178
|
"#hooks/*": "./client/hooks/*.js",
|
|
179
179
|
"#lib/*": "./client/lib/*.js",
|
|
180
180
|
"#extensions/*": "./client/extensions/*.js",
|
|
181
|
-
"#pages/*": "./client/pages/*.js"
|
|
181
|
+
"#pages/*": "./client/pages/*.js",
|
|
182
|
+
"#components/data-table": "./client/components/data-table/index.js"
|
|
182
183
|
},
|
|
183
184
|
"scripts": {
|
|
184
185
|
"postinstall": "nocobase skills sync",
|
package/server/app.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MailerProvider } from '@nocobase/app-server/mailer';
|
|
1
2
|
import type { Application } from '@nocobase/app-server/application';
|
|
2
3
|
import { DatabaseProvider } from '@nocobase/app-server/database';
|
|
3
4
|
import { I18nProvider, i18nHttpMiddleware } from '@nocobase/app-server/i18n';
|
|
@@ -33,6 +34,7 @@ export function createApp(runtime: AppRuntimeContext): Application {
|
|
|
33
34
|
app.addServiceProvider(SecretsProvider);
|
|
34
35
|
app.addServiceProvider(SessionProvider);
|
|
35
36
|
app.addServiceProvider(DriveProvider);
|
|
37
|
+
app.addServiceProvider(MailerProvider);
|
|
36
38
|
app.addServiceProvider(QueueServiceProvider, {
|
|
37
39
|
nodeEnv: runtime.env.NODE_ENV,
|
|
38
40
|
});
|