nexus-shared 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +704 -446
  2. package/LICENSE +21 -21
  3. package/README.md +44 -5
  4. package/dist/Client.Index.d.ts +3 -0
  5. package/dist/Client.Index.js +3 -0
  6. package/dist/Components/Forms/Crud.js +322 -161
  7. package/dist/Components/Forms/CrudHistory.d.ts +66 -0
  8. package/dist/Components/Forms/CrudHistory.js +140 -0
  9. package/dist/Components/Forms/CrudParts.js +2 -1
  10. package/dist/Components/Forms/Form.js +4 -1
  11. package/dist/Components/Inputs/CodeBox.d.ts +69 -0
  12. package/dist/Components/Inputs/CodeBox.js +316 -0
  13. package/dist/Components/Inputs/DatePicker.js +4 -1
  14. package/dist/Components/Inputs/DateRangePicker.js +4 -1
  15. package/dist/Components/Inputs/DateTimePicker.js +4 -1
  16. package/dist/Components/Inputs/Dropdown.js +4 -1
  17. package/dist/Components/Inputs/InputRenderer.js +3 -0
  18. package/dist/Components/Inputs/NumberBox.js +4 -2
  19. package/dist/Components/Inputs/TextArea.js +4 -1
  20. package/dist/Components/Inputs/TextBox.js +4 -1
  21. package/dist/Components/Inputs/TimePicker.js +4 -1
  22. package/dist/Components/Inputs/TreeView.d.ts +55 -5
  23. package/dist/Components/Inputs/TreeView.js +372 -23
  24. package/dist/Components/Layouts/ThemePicker.d.ts +3 -2
  25. package/dist/Components/Layouts/ThemePicker.js +16 -4
  26. package/dist/Components/Viewers/DataTable.js +63 -21
  27. package/dist/Components/Viewers/DataTableParts.d.ts +26 -8
  28. package/dist/Components/Viewers/DataTableParts.js +39 -10
  29. package/dist/Helpers/ApiModules.d.ts +3 -34
  30. package/dist/Helpers/ApiModules.js +3 -3
  31. package/dist/Helpers/ApiRoutes.d.ts +68 -26
  32. package/dist/Helpers/ApiRoutes.js +31 -27
  33. package/dist/Helpers/ArrayHelpers.d.ts +0 -0
  34. package/dist/Helpers/ArrayHelpers.js +2 -0
  35. package/dist/Helpers/CodeHelpers.d.ts +97 -0
  36. package/dist/Helpers/CodeHelpers.js +332 -0
  37. package/dist/Helpers/CrudBackend.d.ts +94 -4
  38. package/dist/Helpers/CrudBackend.js +168 -9
  39. package/dist/Helpers/CrudColumns.d.ts +51 -0
  40. package/dist/Helpers/CrudColumns.js +69 -0
  41. package/dist/Helpers/CrudHelpers.d.ts +50 -5
  42. package/dist/Helpers/CrudHelpers.js +109 -12
  43. package/dist/Helpers/InputParamsHelpers.js +8 -0
  44. package/dist/Helpers/MessageBuilder.js +2 -0
  45. package/dist/Helpers/NexusHelpers.d.ts +0 -0
  46. package/dist/Helpers/NexusHelpers.js +1 -0
  47. package/dist/Helpers/RequestCache.d.ts +35 -0
  48. package/dist/Helpers/RequestCache.js +113 -0
  49. package/dist/Helpers/TableExport.js +12 -12
  50. package/dist/Helpers/TableHelpers.d.ts +1 -1
  51. package/dist/Helpers/TableHelpers.js +7 -2
  52. package/dist/Helpers/TableJoins.d.ts +70 -0
  53. package/dist/Helpers/TableJoins.js +250 -0
  54. package/dist/Helpers/TableStore.d.ts +5 -0
  55. package/dist/Helpers/TableStore.js +9 -0
  56. package/dist/Helpers/TreeStore.d.ts +225 -11
  57. package/dist/Helpers/TreeStore.js +683 -90
  58. package/dist/Helpers/UserPreferences.d.ts +8 -0
  59. package/dist/Helpers/UserPreferences.js +17 -0
  60. package/dist/Interfaces/CrudInterfaces.d.ts +47 -9
  61. package/dist/Interfaces/FormInterfaces.d.ts +4 -1
  62. package/dist/Interfaces/InputInterfaces.d.ts +24 -0
  63. package/dist/Interfaces/MessageInterfaces.d.ts +1 -1
  64. package/dist/Interfaces/PreferenceInterfaces.d.ts +8 -0
  65. package/dist/Interfaces/PreferenceInterfaces.js +2 -5
  66. package/dist/Interfaces/TableInterfaces.d.ts +86 -4
  67. package/dist/Services/ApiProxy.d.ts +36 -1
  68. package/dist/Services/ApiProxy.js +182 -52
  69. package/dist/Services/ApiProxyRules.d.ts +203 -0
  70. package/dist/Services/ApiProxyRules.js +426 -0
  71. package/dist/Services/JoinSources.d.ts +48 -0
  72. package/dist/Services/JoinSources.js +74 -0
  73. package/dist/Services/ServerApi.d.ts +13 -2
  74. package/dist/Services/ServerApi.js +8 -3
  75. package/dist/Shared.Index.d.ts +4 -0
  76. package/dist/Shared.Index.js +4 -0
  77. package/package.json +87 -85
  78. package/src/Styles/Nexus.Avatar.css +79 -79
  79. package/src/Styles/Nexus.Base.css +117 -117
  80. package/src/Styles/Nexus.Button.css +180 -180
  81. package/src/Styles/Nexus.Calendar.css +273 -273
  82. package/src/Styles/Nexus.Chat.css +1443 -1443
  83. package/src/Styles/Nexus.Choice.css +343 -343
  84. package/src/Styles/Nexus.Crud.css +168 -168
  85. package/src/Styles/Nexus.DateTime.css +81 -81
  86. package/src/Styles/Nexus.Dropdown.css +725 -725
  87. package/src/Styles/Nexus.Editor.css +295 -295
  88. package/src/Styles/Nexus.Excel.css +389 -389
  89. package/src/Styles/Nexus.Form.css +279 -279
  90. package/src/Styles/Nexus.Index.css +37 -37
  91. package/src/Styles/Nexus.Input.css +196 -4
  92. package/src/Styles/Nexus.Markdown.css +237 -237
  93. package/src/Styles/Nexus.Menu.css +237 -237
  94. package/src/Styles/Nexus.Popup.css +724 -724
  95. package/src/Styles/Nexus.Rows.css +637 -637
  96. package/src/Styles/Nexus.Slider.css +276 -276
  97. package/src/Styles/Nexus.Tab.Buttons.css +432 -432
  98. package/src/Styles/Nexus.Table.css +31 -30
  99. package/src/Styles/Nexus.Theme.Picker.css +59 -3
  100. package/src/Styles/Nexus.Themes.css +194 -194
  101. package/src/Styles/Nexus.Time.css +144 -144
  102. package/src/Styles/Nexus.Toast.css +263 -263
  103. package/src/Styles/Nexus.Tokens.css +89 -89
  104. package/src/Styles/Nexus.Tree.css +500 -431
@@ -447,21 +447,17 @@
447
447
  }
448
448
 
449
449
  /*
450
- * The pinned section above the page: a row across the table whose button folds the records the user pinned open and
451
- * shut, and the rows themselves, which show in the list below as well. A pinned row wears a pin where the rows of the
452
- * page show their number.
450
+ * The sections above the page: a row across the table whose button folds a set of the user's records open and shut -
451
+ * the ones they pinned, their favourites - and the rows themselves, which show in the list below as well. A section's
452
+ * row wears the section's icon where the rows of the page show their number.
453
453
  */
454
- .nx-table__pins {
455
- border-bottom: 2px solid var(--nx-table-line);
456
- }
457
-
458
- .nx-table__pin-cell {
454
+ .nx-table__section-cell {
459
455
  padding: 0;
460
456
  border-bottom: 1px solid var(--nx-table-line);
461
457
  background: var(--nx-table-head-bg);
462
458
  }
463
459
 
464
- .nx-table__pin-toggle {
460
+ .nx-table__section-toggle {
465
461
  display: flex;
466
462
  align-items: center;
467
463
  gap: var(--nx-space-2);
@@ -479,54 +475,54 @@
479
475
  transition: background-color var(--nx-duration);
480
476
  }
481
477
 
482
- .nx-table__pin-toggle:hover {
478
+ .nx-table__section-toggle:hover {
483
479
  background: color-mix(in oklab, var(--nx-text) 5%, transparent);
484
480
  }
485
481
 
486
- .nx-table__pin-toggle:focus-visible {
482
+ .nx-table__section-toggle:focus-visible {
487
483
  outline: none;
488
484
  box-shadow: inset 0 0 0 2px var(--nx-primary);
489
485
  }
490
486
 
491
- .nx-table__pin-caret {
487
+ .nx-table__section-caret,
488
+ .nx-table__section-icon,
489
+ .nx-table__mark {
492
490
  flex-shrink: 0;
493
491
  width: 15px;
494
492
  height: 15px;
495
493
  color: var(--nx-text-muted);
496
- transition: transform var(--nx-duration);
497
494
  }
498
495
 
499
- .nx-table__pins[data-open] .nx-table__pin-caret {
500
- transform: rotate(90deg);
496
+ /* A row's marks, where its number would be: one under the other, in the line a single mark takes. */
497
+ .nx-table__marks {
498
+ display: inline-flex;
499
+ flex-direction: column;
500
+ align-items: center;
501
+ gap: 2px;
501
502
  }
502
503
 
503
- .nx-table__pin-icon {
504
- flex-shrink: 0;
505
- width: 15px;
506
- height: 15px;
507
- color: var(--nx-text-muted);
504
+ .nx-table__section-caret {
505
+ transition: transform var(--nx-duration);
506
+ }
507
+
508
+ .nx-table__section[data-open] .nx-table__section-caret {
509
+ transform: rotate(90deg);
508
510
  }
509
511
 
510
- .nx-table__pin-count {
512
+ .nx-table__section-count {
511
513
  color: var(--nx-text-muted);
512
514
  font-weight: 400;
513
515
  font-variant-numeric: tabular-nums;
514
516
  }
515
517
 
516
- .nx-table__pin-loading {
518
+ .nx-table__section-loading {
517
519
  width: 14px;
518
520
  height: 14px;
519
521
  color: var(--nx-text-muted);
520
522
  }
521
523
 
522
- .nx-table__pin-mark {
523
- width: 15px;
524
- height: 15px;
525
- color: var(--nx-text-muted);
526
- }
527
-
528
- [data-nx-motion="reduce"] .nx-table__pin-caret,
529
- [data-nx-motion="reduce"] .nx-table__pin-toggle {
524
+ [data-nx-motion="reduce"] .nx-table__section-caret,
525
+ [data-nx-motion="reduce"] .nx-table__section-toggle {
530
526
  transition: none;
531
527
  }
532
528
 
@@ -859,6 +855,11 @@
859
855
  --nx-tag-tone: var(--nx-info);
860
856
  }
861
857
 
858
+ /* A tag after a value (a column's `tag`): "Asia" then "Trashed", a word's space apart. */
859
+ .nx-table__tag--after {
860
+ margin-inline-start: var(--nx-space-2);
861
+ }
862
+
862
863
  /* Placeholders while the first rows load. */
863
864
  .nx-table__bone {
864
865
  display: block;
@@ -55,6 +55,11 @@
55
55
  * The scroller runs to the panel's right wall, so its scroll bar is the wall's and not a padding's width inside it,
56
56
  * and it carries the panel's right padding inside itself; the panel's other children keep the same inset with a
57
57
  * margin. Its right corners take the panel's rounding, so the bar is cut by the curve instead of drawn over it.
58
+ * A scroller cuts off what reaches past its edge, and a focus ring is drawn outside its box (3px; a checkbox's
59
+ * outline 4px). So on its other three sides it reaches 4px into the panel's padding and pads itself by as much:
60
+ * what it holds stays where it was, and a field at its edge shows its whole ring (every panel's padding is 4px or
61
+ * more). Focus scrolls a field as far clear of the edges (`scroll-padding`), so one left flush with an edge by a
62
+ * scroll shows its ring too.
58
63
  */
59
64
  .nx-popover:has(> .nx-popover__scroll) {
60
65
  max-height: var(--nx-popover-room, calc(100vh - 16px));
@@ -74,12 +79,31 @@
74
79
  .nx-popover__scroll {
75
80
  flex: 1 1 auto;
76
81
  min-height: 0;
82
+ margin: calc(var(--nx-space-1) * -1);
83
+ margin-right: 0;
84
+ padding: var(--nx-space-1);
77
85
  padding-right: var(--nx-popover-pad, var(--nx-space-4));
86
+ scroll-padding: var(--nx-space-1);
78
87
  overflow: hidden auto;
79
88
  overscroll-behavior: contain;
80
89
  border-radius: 0 calc(var(--nx-radius-lg) - 1px) calc(var(--nx-radius-lg) - 1px) 0;
81
90
  }
82
91
 
92
+ /*
93
+ * Where the scroller reaches one of the panel's left corners (it is the panel's first or last child, as a menu's
94
+ * list is), its own corner follows the panel's curve: the panel's inner radius less the room between their edges,
95
+ * which is the panel's padding less the 4px taken back. A menu's 4px puts the two edges together, so its corner takes
96
+ * the whole 9px; an 8px padding leaves 5px, the theme panel's 16px none. Square, a scrolled item's highlight ran
97
+ * over the rounded border.
98
+ */
99
+ .nx-popover > .nx-popover__scroll:first-child {
100
+ border-top-left-radius: max(0px, var(--nx-radius-lg) - 1px - (var(--nx-popover-pad, var(--nx-space-4)) - var(--nx-space-1)));
101
+ }
102
+
103
+ .nx-popover > .nx-popover__scroll:last-child {
104
+ border-bottom-left-radius: max(0px, var(--nx-radius-lg) - 1px - (var(--nx-popover-pad, var(--nx-space-4)) - var(--nx-space-1)));
105
+ }
106
+
83
107
  /*
84
108
  * The arrow that ties a panel to the button or the place it opened from: an isosceles tail, 26px across and 11px
85
109
  * deep, with a slightly rounded tip. It is drawn in two layers, because a shape with a line along two of its sides
@@ -130,19 +154,45 @@
130
154
  transform: scaleY(-1);
131
155
  }
132
156
 
157
+ /* Wide enough for the sections to sit two to a row. */
133
158
  .nx-theme-switcher__panel {
134
159
  position: fixed;
135
160
  inset: auto;
136
- width: min(340px, calc(100vw - 16px));
161
+ width: min(680px, calc(100vw - 16px));
137
162
  }
138
163
 
139
164
  .nx-theme-picker,
140
- .nx-theme-switcher__body {
165
+ .nx-theme-switcher__body,
166
+ .nx-theme-picker__block {
141
167
  display: grid;
142
168
  gap: var(--nx-space-4);
143
169
  }
144
170
 
145
- /* A section of the preferences: a line above it and its name, a step stronger than the small headings under it. */
171
+ /*
172
+ * In the panel every section is a cell of one grid: two to a row, the theme across both, and one under the other
173
+ * where the window is narrow. The two pickers' own wrappers step aside so their sections share that grid.
174
+ */
175
+ .nx-theme-switcher__body {
176
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
177
+ align-items: start;
178
+ column-gap: var(--nx-space-6);
179
+ }
180
+
181
+ .nx-theme-switcher__body > .nx-theme-picker {
182
+ display: contents;
183
+ }
184
+
185
+ .nx-theme-picker__block {
186
+ align-content: start;
187
+ min-width: 0;
188
+ gap: var(--nx-space-3);
189
+ }
190
+
191
+ .nx-theme-picker__block--wide {
192
+ grid-column: 1 / -1;
193
+ }
194
+
195
+ /* A section's name, a line above it, a step stronger than the small headings under it. */
146
196
  .nx-theme-picker__section {
147
197
  margin: 0;
148
198
  padding-top: var(--nx-space-4);
@@ -152,6 +202,12 @@
152
202
  font-weight: 600;
153
203
  }
154
204
 
205
+ /* The first section starts at the top of its picker, with nothing above it to set it off from. */
206
+ .nx-theme-picker:first-child > .nx-theme-picker__block:first-child > .nx-theme-picker__section {
207
+ padding-top: 0;
208
+ border-top: 0;
209
+ }
210
+
155
211
  .nx-theme-picker__group {
156
212
  min-width: 0;
157
213
  margin: 0;
@@ -1,194 +1,194 @@
1
- /*
2
- * Color themes. Each sets its base palette once per color as light-dark(light, dark); the page's color-scheme
3
- * (light, dark, or the system setting) picks the side. Hover colors, soft backgrounds, and the focus ring are
4
- * derived from these in Nexus.Tokens.css.
5
- *
6
- * Colors follow each theme's official palette, darkened or lightened where needed to meet WCAG AA contrast.
7
- * --nx-primary and --nx-danger are the accent as text and lines (light in dark mode, for contrast on dark panels);
8
- * --nx-primary-solid and --nx-danger-solid are the same hue as a fill behind white text (buttons, selected days,
9
- * checks), a darker shade in dark mode. --nx-primary-text and --nx-danger-text sit on the solid fills.
10
- * After changing a color, run: npm run check:themes
11
- *
12
- * A new theme is one more block with its own data-nx-theme value, added to NEXUS_THEMES or passed to the theme components.
13
- */
14
- @layer nexus.themes {
15
- /* Nexus: neutral grays with a confident blue. The default. */
16
- :root,
17
- [data-nx-theme="nexus"] {
18
- --nx-bg: light-dark(#f5f6f8, #0f1115);
19
- --nx-surface: light-dark(#ffffff, #171a20);
20
- --nx-surface-2: light-dark(#f0f2f5, #1e222a);
21
- --nx-surface-hover: light-dark(#e9ecf1, #262b35);
22
- --nx-border: light-dark(#dde1e7, #2c323d);
23
- --nx-border-strong: light-dark(#c3cad4, #3d4552);
24
- --nx-text: light-dark(#171c26, #e6e9ef);
25
- --nx-text-muted: light-dark(#5a6375, #a1a9b7);
26
- --nx-text-subtle: light-dark(#8b93a2, #6f7888);
27
- --nx-primary: light-dark(#1c5cea, #4f8fff);
28
- --nx-primary-solid: light-dark(#1c5cea, #3270dd);
29
- --nx-primary-text: light-dark(#ffffff, #ffffff);
30
- --nx-danger: light-dark(#c5291d, #f26b5e);
31
- --nx-danger-solid: light-dark(#c5291d, #cb473d);
32
- --nx-danger-text: light-dark(#ffffff, #ffffff);
33
- --nx-success: light-dark(#147739, #4cc27a);
34
- --nx-warning: light-dark(#b34608, #f2a54a);
35
- --nx-info: light-dark(#0b6aa2, #5bb3e6);
36
- }
37
-
38
- /* GitHub: Primer grays with GitHub green. */
39
- [data-nx-theme="github"] {
40
- --nx-bg: light-dark(#f6f8fa, #010409);
41
- --nx-surface: light-dark(#ffffff, #0d1117);
42
- --nx-surface-2: light-dark(#f6f8fa, #151b23);
43
- --nx-surface-hover: light-dark(#eef1f4, #212830);
44
- --nx-border: light-dark(#d1d9e0, #3d444d);
45
- --nx-border-strong: light-dark(#b1bac4, #656c76);
46
- --nx-text: light-dark(#1f2328, #f0f6fc);
47
- --nx-text-muted: light-dark(#59636e, #9198a1);
48
- --nx-text-subtle: light-dark(#818b98, #6e7681);
49
- --nx-primary: light-dark(#1b7736, #3fb950);
50
- --nx-primary-solid: light-dark(#1b7736, #388441);
51
- --nx-primary-text: light-dark(#ffffff, #ffffff);
52
- --nx-danger: light-dark(#c8212d, #f85149);
53
- --nx-danger-solid: light-dark(#c8212d, #db3330);
54
- --nx-danger-text: light-dark(#ffffff, #ffffff);
55
- --nx-success: light-dark(#197934, #3fb950);
56
- --nx-warning: light-dark(#8d5e00, #d29922);
57
- --nx-info: light-dark(#0964d0, #4493f8);
58
- }
59
-
60
- /* Nord: arctic, north-bluish calm. */
61
- [data-nx-theme="nord"] {
62
- --nx-bg: light-dark(#e5e9f0, #242933);
63
- --nx-surface: light-dark(#eceff4, #2e3440);
64
- --nx-surface-2: light-dark(#e5e9f0, #3b4252);
65
- --nx-surface-hover: light-dark(#d8dee9, #434c5e);
66
- --nx-border: light-dark(#d8dee9, #434c5e);
67
- --nx-border-strong: light-dark(#b8c2d3, #4c566a);
68
- --nx-text: light-dark(#2e3440, #eceff4);
69
- --nx-text-muted: light-dark(#4c566a, #b9c2d0);
70
- --nx-text-subtle: light-dark(#7b88a1, #7b88a1);
71
- --nx-primary: light-dark(#446184, #88c0d0);
72
- --nx-primary-solid: light-dark(#446184, #4b717c);
73
- --nx-primary-text: light-dark(#eceff4, #eceff4);
74
- --nx-danger: light-dark(#9e4049, #dba6ab);
75
- --nx-danger-solid: light-dark(#9e4049, #8e5e63);
76
- --nx-danger-text: light-dark(#eceff4, #eceff4);
77
- --nx-success: light-dark(#4e6639, #a3be8c);
78
- --nx-warning: light-dark(#954931, #ebcb8b);
79
- --nx-info: light-dark(#406283, #9cb5ce);
80
- }
81
-
82
- /* Dracula: the dark purple classic, with its Alucard palette for light. */
83
- [data-nx-theme="dracula"] {
84
- --nx-bg: light-dark(#f3eed9, #21222c);
85
- --nx-surface: light-dark(#fffbeb, #282a36);
86
- --nx-surface-2: light-dark(#f7f1dc, #303241);
87
- --nx-surface-hover: light-dark(#efe8cf, #44475a);
88
- --nx-border: light-dark(#e4dcc0, #44475a);
89
- --nx-border-strong: light-dark(#cfc49f, #6272a4);
90
- --nx-text: light-dark(#1f1f1f, #f8f8f2);
91
- --nx-text-muted: light-dark(#635d97, #c5c8d8);
92
- --nx-text-subtle: light-dark(#8e89ae, #6272a4);
93
- --nx-primary: light-dark(#644ac9, #bd93f9);
94
- --nx-primary-solid: light-dark(#644ac9, #8a60c1);
95
- --nx-primary-text: light-dark(#ffffff, #ffffff);
96
- --nx-danger: light-dark(#ba3527, #ff7b7b);
97
- --nx-danger-solid: light-dark(#ba3527, #c8494d);
98
- --nx-danger-text: light-dark(#ffffff, #ffffff);
99
- --nx-success: light-dark(#14710a, #50fa7b);
100
- --nx-warning: light-dark(#a34d14, #ffb86c);
101
- --nx-info: light-dark(#036a96, #8be9fd);
102
- }
103
-
104
- /* Solarized: warm cream or deep teal, with precise accents. */
105
- [data-nx-theme="solarized"] {
106
- --nx-bg: light-dark(#eee8d5, #00212b);
107
- --nx-surface: light-dark(#fdf6e3, #002b36);
108
- --nx-surface-2: light-dark(#f5efdc, #073642);
109
- --nx-surface-hover: light-dark(#eee8d5, #0b4453);
110
- --nx-border: light-dark(#e4ddc8, #0d3f4c);
111
- --nx-border-strong: light-dark(#cdc5ab, #2a5561);
112
- --nx-text: light-dark(#073642, #eee8d5);
113
- --nx-text-muted: light-dark(#566b72, #93a1a1);
114
- --nx-text-subtle: light-dark(#809294, #657b83);
115
- --nx-primary: light-dark(#1c679c, #55a7e0);
116
- --nx-primary-solid: light-dark(#1c679c, #247bb2);
117
- --nx-primary-text: light-dark(#ffffff, #ffffff);
118
- --nx-danger: light-dark(#bd2320, #e9807e);
119
- --nx-danger-solid: light-dark(#bd2320, #b95555);
120
- --nx-danger-text: light-dark(#ffffff, #ffffff);
121
- --nx-success: light-dark(#5b6900, #92a800);
122
- --nx-warning: light-dark(#7d5e00, #c69700);
123
- --nx-info: light-dark(#1d6e68, #2fb3a9);
124
- }
125
-
126
- /* Catppuccin: soothing pastels, Latte for light and Mocha for dark. */
127
- [data-nx-theme="catppuccin"] {
128
- --nx-bg: light-dark(#e6e9ef, #11111b);
129
- --nx-surface: light-dark(#eff1f5, #1e1e2e);
130
- --nx-surface-2: light-dark(#e6e9ef, #313244);
131
- --nx-surface-hover: light-dark(#dce0e8, #45475a);
132
- --nx-border: light-dark(#ccd0da, #45475a);
133
- --nx-border-strong: light-dark(#acb0be, #585b70);
134
- --nx-text: light-dark(#42455c, #dce2f7);
135
- --nx-text-muted: light-dark(#65687d, #a6adc8);
136
- --nx-text-subtle: light-dark(#868a9c, #7f849c);
137
- --nx-primary: light-dark(#7a21ed, #cba6f7);
138
- --nx-primary-solid: light-dark(#7a21ed, #8965b1);
139
- --nx-primary-text: light-dark(#ffffff, #ffffff);
140
- --nx-danger: light-dark(#ba0d33, #f38ba8);
141
- --nx-danger-solid: light-dark(#ba0d33, #b75573);
142
- --nx-danger-text: light-dark(#ffffff, #ffffff);
143
- --nx-success: light-dark(#2c6e1d, #a6e3a1);
144
- --nx-warning: light-dark(#875612, #f9e2af);
145
- --nx-info: light-dark(#0a52e0, #89b4fa);
146
- }
147
-
148
- /* Rosé Pine: muted pine, iris, and rose; Dawn for light. */
149
- [data-nx-theme="rose-pine"] {
150
- --nx-bg: light-dark(#faf4ed, #191724);
151
- --nx-surface: light-dark(#fffaf3, #1f1d2e);
152
- --nx-surface-2: light-dark(#f2e9e1, #26233a);
153
- --nx-surface-hover: light-dark(#ebe2da, #2a2740);
154
- --nx-border: light-dark(#dfdad9, #403d52);
155
- --nx-border-strong: light-dark(#cecacd, #524f67);
156
- --nx-text: light-dark(#494565, #e0def4);
157
- --nx-text-muted: light-dark(#6a6683, #908caa);
158
- --nx-text-subtle: light-dark(#948fa2, #6e6a86);
159
- --nx-primary: light-dark(#745c8f, #c4a7e7);
160
- --nx-primary-solid: light-dark(#745c8f, #8166a1);
161
- --nx-primary-text: light-dark(#fffaf3, #fffaf3);
162
- --nx-danger: light-dark(#9d4c63, #eb6f92);
163
- --nx-danger-solid: light-dark(#9d4c63, #bf476c);
164
- --nx-danger-text: light-dark(#fffaf3, #fffaf3);
165
- --nx-success: light-dark(#286983, #9ccfd8);
166
- --nx-warning: light-dark(#90590f, #f6c177);
167
- --nx-info: light-dark(#406d76, #4da0c2);
168
- }
169
-
170
- /* Browsers without light-dark() (before 2024) get the Nexus light palette. */
171
- @supports not (color: light-dark(#fff, #000)) {
172
- :root,
173
- [data-nx-theme] {
174
- --nx-bg: #f5f6f8;
175
- --nx-surface: #ffffff;
176
- --nx-surface-2: #f0f2f5;
177
- --nx-surface-hover: #e9ecf1;
178
- --nx-border: #dde1e7;
179
- --nx-border-strong: #c3cad4;
180
- --nx-text: #171c26;
181
- --nx-text-muted: #5a6375;
182
- --nx-text-subtle: #8b93a2;
183
- --nx-primary: #1c5cea;
184
- --nx-primary-solid: #1c5cea;
185
- --nx-primary-text: #ffffff;
186
- --nx-danger: #c5291d;
187
- --nx-danger-solid: #c5291d;
188
- --nx-danger-text: #ffffff;
189
- --nx-success: #147739;
190
- --nx-warning: #b34608;
191
- --nx-info: #0b6aa2;
192
- }
193
- }
194
- }
1
+ /*
2
+ * Color themes. Each sets its base palette once per color as light-dark(light, dark); the page's color-scheme
3
+ * (light, dark, or the system setting) picks the side. Hover colors, soft backgrounds, and the focus ring are
4
+ * derived from these in Nexus.Tokens.css.
5
+ *
6
+ * Colors follow each theme's official palette, darkened or lightened where needed to meet WCAG AA contrast.
7
+ * --nx-primary and --nx-danger are the accent as text and lines (light in dark mode, for contrast on dark panels);
8
+ * --nx-primary-solid and --nx-danger-solid are the same hue as a fill behind white text (buttons, selected days,
9
+ * checks), a darker shade in dark mode. --nx-primary-text and --nx-danger-text sit on the solid fills.
10
+ * After changing a color, run: npm run check:themes
11
+ *
12
+ * A new theme is one more block with its own data-nx-theme value, added to NEXUS_THEMES or passed to the theme components.
13
+ */
14
+ @layer nexus.themes {
15
+ /* Nexus: neutral grays with a confident blue. The default. */
16
+ :root,
17
+ [data-nx-theme="nexus"] {
18
+ --nx-bg: light-dark(#f5f6f8, #0f1115);
19
+ --nx-surface: light-dark(#ffffff, #171a20);
20
+ --nx-surface-2: light-dark(#f0f2f5, #1e222a);
21
+ --nx-surface-hover: light-dark(#e9ecf1, #262b35);
22
+ --nx-border: light-dark(#dde1e7, #2c323d);
23
+ --nx-border-strong: light-dark(#c3cad4, #3d4552);
24
+ --nx-text: light-dark(#171c26, #e6e9ef);
25
+ --nx-text-muted: light-dark(#5a6375, #a1a9b7);
26
+ --nx-text-subtle: light-dark(#8b93a2, #6f7888);
27
+ --nx-primary: light-dark(#1c5cea, #4f8fff);
28
+ --nx-primary-solid: light-dark(#1c5cea, #3270dd);
29
+ --nx-primary-text: light-dark(#ffffff, #ffffff);
30
+ --nx-danger: light-dark(#c5291d, #f26b5e);
31
+ --nx-danger-solid: light-dark(#c5291d, #cb473d);
32
+ --nx-danger-text: light-dark(#ffffff, #ffffff);
33
+ --nx-success: light-dark(#147739, #4cc27a);
34
+ --nx-warning: light-dark(#b34608, #f2a54a);
35
+ --nx-info: light-dark(#0b6aa2, #5bb3e6);
36
+ }
37
+
38
+ /* GitHub: Primer grays with GitHub green. */
39
+ [data-nx-theme="github"] {
40
+ --nx-bg: light-dark(#f6f8fa, #010409);
41
+ --nx-surface: light-dark(#ffffff, #0d1117);
42
+ --nx-surface-2: light-dark(#f6f8fa, #151b23);
43
+ --nx-surface-hover: light-dark(#eef1f4, #212830);
44
+ --nx-border: light-dark(#d1d9e0, #3d444d);
45
+ --nx-border-strong: light-dark(#b1bac4, #656c76);
46
+ --nx-text: light-dark(#1f2328, #f0f6fc);
47
+ --nx-text-muted: light-dark(#59636e, #9198a1);
48
+ --nx-text-subtle: light-dark(#818b98, #6e7681);
49
+ --nx-primary: light-dark(#1b7736, #3fb950);
50
+ --nx-primary-solid: light-dark(#1b7736, #388441);
51
+ --nx-primary-text: light-dark(#ffffff, #ffffff);
52
+ --nx-danger: light-dark(#c8212d, #f85149);
53
+ --nx-danger-solid: light-dark(#c8212d, #db3330);
54
+ --nx-danger-text: light-dark(#ffffff, #ffffff);
55
+ --nx-success: light-dark(#197934, #3fb950);
56
+ --nx-warning: light-dark(#8d5e00, #d29922);
57
+ --nx-info: light-dark(#0964d0, #4493f8);
58
+ }
59
+
60
+ /* Nord: arctic, north-bluish calm. */
61
+ [data-nx-theme="nord"] {
62
+ --nx-bg: light-dark(#e5e9f0, #242933);
63
+ --nx-surface: light-dark(#eceff4, #2e3440);
64
+ --nx-surface-2: light-dark(#e5e9f0, #3b4252);
65
+ --nx-surface-hover: light-dark(#d8dee9, #434c5e);
66
+ --nx-border: light-dark(#d8dee9, #434c5e);
67
+ --nx-border-strong: light-dark(#b8c2d3, #4c566a);
68
+ --nx-text: light-dark(#2e3440, #eceff4);
69
+ --nx-text-muted: light-dark(#4c566a, #b9c2d0);
70
+ --nx-text-subtle: light-dark(#7b88a1, #7b88a1);
71
+ --nx-primary: light-dark(#446184, #88c0d0);
72
+ --nx-primary-solid: light-dark(#446184, #4b717c);
73
+ --nx-primary-text: light-dark(#eceff4, #eceff4);
74
+ --nx-danger: light-dark(#9e4049, #dba6ab);
75
+ --nx-danger-solid: light-dark(#9e4049, #8e5e63);
76
+ --nx-danger-text: light-dark(#eceff4, #eceff4);
77
+ --nx-success: light-dark(#4e6639, #a3be8c);
78
+ --nx-warning: light-dark(#954931, #ebcb8b);
79
+ --nx-info: light-dark(#406283, #9cb5ce);
80
+ }
81
+
82
+ /* Dracula: the dark purple classic, with its Alucard palette for light. */
83
+ [data-nx-theme="dracula"] {
84
+ --nx-bg: light-dark(#f3eed9, #21222c);
85
+ --nx-surface: light-dark(#fffbeb, #282a36);
86
+ --nx-surface-2: light-dark(#f7f1dc, #303241);
87
+ --nx-surface-hover: light-dark(#efe8cf, #44475a);
88
+ --nx-border: light-dark(#e4dcc0, #44475a);
89
+ --nx-border-strong: light-dark(#cfc49f, #6272a4);
90
+ --nx-text: light-dark(#1f1f1f, #f8f8f2);
91
+ --nx-text-muted: light-dark(#635d97, #c5c8d8);
92
+ --nx-text-subtle: light-dark(#8e89ae, #6272a4);
93
+ --nx-primary: light-dark(#644ac9, #bd93f9);
94
+ --nx-primary-solid: light-dark(#644ac9, #8a60c1);
95
+ --nx-primary-text: light-dark(#ffffff, #ffffff);
96
+ --nx-danger: light-dark(#ba3527, #ff7b7b);
97
+ --nx-danger-solid: light-dark(#ba3527, #c8494d);
98
+ --nx-danger-text: light-dark(#ffffff, #ffffff);
99
+ --nx-success: light-dark(#14710a, #50fa7b);
100
+ --nx-warning: light-dark(#a34d14, #ffb86c);
101
+ --nx-info: light-dark(#036a96, #8be9fd);
102
+ }
103
+
104
+ /* Solarized: warm cream or deep teal, with precise accents. */
105
+ [data-nx-theme="solarized"] {
106
+ --nx-bg: light-dark(#eee8d5, #00212b);
107
+ --nx-surface: light-dark(#fdf6e3, #002b36);
108
+ --nx-surface-2: light-dark(#f5efdc, #073642);
109
+ --nx-surface-hover: light-dark(#eee8d5, #0b4453);
110
+ --nx-border: light-dark(#e4ddc8, #0d3f4c);
111
+ --nx-border-strong: light-dark(#cdc5ab, #2a5561);
112
+ --nx-text: light-dark(#073642, #eee8d5);
113
+ --nx-text-muted: light-dark(#566b72, #93a1a1);
114
+ --nx-text-subtle: light-dark(#809294, #657b83);
115
+ --nx-primary: light-dark(#1c679c, #55a7e0);
116
+ --nx-primary-solid: light-dark(#1c679c, #247bb2);
117
+ --nx-primary-text: light-dark(#ffffff, #ffffff);
118
+ --nx-danger: light-dark(#bd2320, #e9807e);
119
+ --nx-danger-solid: light-dark(#bd2320, #b95555);
120
+ --nx-danger-text: light-dark(#ffffff, #ffffff);
121
+ --nx-success: light-dark(#5b6900, #92a800);
122
+ --nx-warning: light-dark(#7d5e00, #c69700);
123
+ --nx-info: light-dark(#1d6e68, #2fb3a9);
124
+ }
125
+
126
+ /* Catppuccin: soothing pastels, Latte for light and Mocha for dark. */
127
+ [data-nx-theme="catppuccin"] {
128
+ --nx-bg: light-dark(#e6e9ef, #11111b);
129
+ --nx-surface: light-dark(#eff1f5, #1e1e2e);
130
+ --nx-surface-2: light-dark(#e6e9ef, #313244);
131
+ --nx-surface-hover: light-dark(#dce0e8, #45475a);
132
+ --nx-border: light-dark(#ccd0da, #45475a);
133
+ --nx-border-strong: light-dark(#acb0be, #585b70);
134
+ --nx-text: light-dark(#42455c, #dce2f7);
135
+ --nx-text-muted: light-dark(#65687d, #a6adc8);
136
+ --nx-text-subtle: light-dark(#868a9c, #7f849c);
137
+ --nx-primary: light-dark(#7a21ed, #cba6f7);
138
+ --nx-primary-solid: light-dark(#7a21ed, #8965b1);
139
+ --nx-primary-text: light-dark(#ffffff, #ffffff);
140
+ --nx-danger: light-dark(#ba0d33, #f38ba8);
141
+ --nx-danger-solid: light-dark(#ba0d33, #b75573);
142
+ --nx-danger-text: light-dark(#ffffff, #ffffff);
143
+ --nx-success: light-dark(#2c6e1d, #a6e3a1);
144
+ --nx-warning: light-dark(#875612, #f9e2af);
145
+ --nx-info: light-dark(#0a52e0, #89b4fa);
146
+ }
147
+
148
+ /* Rosé Pine: muted pine, iris, and rose; Dawn for light. */
149
+ [data-nx-theme="rose-pine"] {
150
+ --nx-bg: light-dark(#faf4ed, #191724);
151
+ --nx-surface: light-dark(#fffaf3, #1f1d2e);
152
+ --nx-surface-2: light-dark(#f2e9e1, #26233a);
153
+ --nx-surface-hover: light-dark(#ebe2da, #2a2740);
154
+ --nx-border: light-dark(#dfdad9, #403d52);
155
+ --nx-border-strong: light-dark(#cecacd, #524f67);
156
+ --nx-text: light-dark(#494565, #e0def4);
157
+ --nx-text-muted: light-dark(#6a6683, #908caa);
158
+ --nx-text-subtle: light-dark(#948fa2, #6e6a86);
159
+ --nx-primary: light-dark(#745c8f, #c4a7e7);
160
+ --nx-primary-solid: light-dark(#745c8f, #8166a1);
161
+ --nx-primary-text: light-dark(#fffaf3, #fffaf3);
162
+ --nx-danger: light-dark(#9d4c63, #eb6f92);
163
+ --nx-danger-solid: light-dark(#9d4c63, #bf476c);
164
+ --nx-danger-text: light-dark(#fffaf3, #fffaf3);
165
+ --nx-success: light-dark(#286983, #9ccfd8);
166
+ --nx-warning: light-dark(#90590f, #f6c177);
167
+ --nx-info: light-dark(#406d76, #4da0c2);
168
+ }
169
+
170
+ /* Browsers without light-dark() (before 2024) get the Nexus light palette. */
171
+ @supports not (color: light-dark(#fff, #000)) {
172
+ :root,
173
+ [data-nx-theme] {
174
+ --nx-bg: #f5f6f8;
175
+ --nx-surface: #ffffff;
176
+ --nx-surface-2: #f0f2f5;
177
+ --nx-surface-hover: #e9ecf1;
178
+ --nx-border: #dde1e7;
179
+ --nx-border-strong: #c3cad4;
180
+ --nx-text: #171c26;
181
+ --nx-text-muted: #5a6375;
182
+ --nx-text-subtle: #8b93a2;
183
+ --nx-primary: #1c5cea;
184
+ --nx-primary-solid: #1c5cea;
185
+ --nx-primary-text: #ffffff;
186
+ --nx-danger: #c5291d;
187
+ --nx-danger-solid: #c5291d;
188
+ --nx-danger-text: #ffffff;
189
+ --nx-success: #147739;
190
+ --nx-warning: #b34608;
191
+ --nx-info: #0b6aa2;
192
+ }
193
+ }
194
+ }