@k2b/cloud 0.21.0 → 0.22.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k2b/cloud",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Application platform library for independently deployed Hono and SolidJS services behind a dynamic gateway.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "repository": {
@@ -98,7 +98,7 @@
98
98
  "@tailwindcss/typography": "0.5.20",
99
99
  "@k2b/nessi": "0.12.1",
100
100
  "@k2b/ssr": "0.14.0",
101
- "@k2b/ui": "0.10.0",
101
+ "@k2b/ui": "0.12.0",
102
102
  "@k2b/stdlib": "0.27.0",
103
103
  "@k2b/sync": "7.0.0",
104
104
  "@nats-io/jetstream": "3.4.0",
@@ -1,4 +1,4 @@
1
- import { Button, dialogCore, MarkdownView, PanelDialog, panelDialogOptions, useLocale } from "@k2b/ui";
1
+ import { Button, dialogCore, IconButton, MarkdownView, NoticeCard, PanelDialog, panelDialogOptions, useLocale } from "@k2b/ui";
2
2
  import { createSignal, For, onMount, Show } from "solid-js";
3
3
  import {
4
4
  ANNOUNCEMENTS_COOKIE,
@@ -21,22 +21,6 @@ const writeCookieState = (state: AnnouncementCookieState) => {
21
21
  document.cookie = `${ANNOUNCEMENTS_COOKIE}=${serializeAnnouncementCookieState(state)}; Path=/; Max-Age=${ANNOUNCEMENTS_COOKIE_MAX_AGE_SECONDS}; SameSite=Lax`;
22
22
  };
23
23
 
24
- const toneClass = (tone: AnnouncementDisplayEntry["tone"]) => {
25
- if (tone === "success")
26
- return "border-emerald-200 bg-emerald-50 text-emerald-900 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-100";
27
- if (tone === "warning")
28
- return "border-amber-200 bg-amber-50 text-amber-950 dark:border-amber-900/60 dark:bg-amber-950/40 dark:text-amber-100";
29
- if (tone === "danger") return "border-red-200 bg-red-50 text-red-950 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-100";
30
- return "border-blue-200 bg-blue-50 text-blue-950 dark:border-blue-900/60 dark:bg-blue-950/40 dark:text-blue-100";
31
- };
32
-
33
- const toneIcon = (tone: AnnouncementDisplayEntry["tone"]) => {
34
- if (tone === "success") return "ti ti-circle-check";
35
- if (tone === "warning") return "ti ti-alert-triangle";
36
- if (tone === "danger") return "ti ti-alert-circle";
37
- return "ti ti-info-circle";
38
- };
39
-
40
24
  export default function GlobalAnnouncements(props: Props) {
41
25
  const locale = useLocale();
42
26
  const t = () => platformMessages.resolve([locale()]).t;
@@ -113,27 +97,18 @@ export default function GlobalAnnouncements(props: Props) {
113
97
  <div class="flex shrink-0 flex-col gap-1">
114
98
  <For each={banners()}>
115
99
  {(banner) => (
116
- <section
117
- class={`flex max-h-[min(40vh,14rem)] items-start gap-2 rounded-lg border px-3 py-2 text-xs shadow-sm ${toneClass(banner.tone)}`}
118
- >
119
- <i class={`${toneIcon(banner.tone)} mt-0.5 shrink-0`} />
120
- <div class="min-h-0 min-w-0 flex-1">
121
- <p class="font-semibold">{banner.title}</p>
100
+ <div class="cloud-announcement">
101
+ <NoticeCard tone={banner.tone} title={banner.title}>
122
102
  <MarkdownView
123
103
  trustedHtml={banner.bodyHtml}
124
104
  headingScale="compact"
125
105
  class="mt-1 max-h-36 overflow-y-auto overscroll-contain pr-1 [&_p]:my-0"
126
106
  />
127
- </div>
128
- <button
129
- type="button"
130
- class="ml-auto inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md opacity-70 hover:bg-black/5 hover:opacity-100 dark:hover:bg-white/10"
131
- aria-label={t().dismissBanner}
132
- onClick={() => dismissBanner(banner.version)}
133
- >
134
- <i class="ti ti-x" />
135
- </button>
136
- </section>
107
+ </NoticeCard>
108
+ <IconButton size="sm" label={t().dismissBanner} onClick={() => dismissBanner(banner.version)}>
109
+ <i class="ti ti-x" aria-hidden="true" />
110
+ </IconButton>
111
+ </div>
137
112
  )}
138
113
  </For>
139
114
  </div>
@@ -514,12 +514,10 @@
514
514
  display: none;
515
515
  }
516
516
 
517
+ /* The fill without a frame comes from the shared `.md-code-block pre` rule;
518
+ Help keeps its own spacing and syntax colours. */
517
519
  .help-document .md-code-block pre {
518
520
  margin: 0;
519
- border: 0 !important;
520
- border-radius: var(--ui-radius-surface) !important;
521
- background: var(--ui-surface-subtle) !important;
522
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-border) 72%, transparent);
523
521
  padding: 0.875rem 1rem;
524
522
  }
525
523
 
@@ -602,15 +600,6 @@
602
600
  padding: 0;
603
601
  }
604
602
 
605
- .help-document :where(blockquote) {
606
- margin: 1.25rem 0;
607
- border: 0;
608
- border-radius: var(--ui-radius-surface);
609
- background: var(--ui-surface-subtle);
610
- color: var(--color-zinc-600);
611
- padding: 0.875rem 1rem;
612
- }
613
-
614
603
  .help-document .md-table-wrap {
615
604
  overflow: hidden;
616
605
  margin-block: 0.875rem 1.5rem;
@@ -623,13 +612,11 @@
623
612
  border-spacing: 0;
624
613
  }
625
614
 
626
- /* `MarkdownView` contributes its generic cell border with element specificity.
627
- Keep the Help frame as the only edge owner so those cell borders cannot show
628
- through the wrapper's rounded clipping corners. */
615
+ /* Help renders inside `MarkdownView`, which draws the table's row lines. The
616
+ inner `.md-table-cell` owns the padding. */
629
617
  .help-document .md-table :is(th, td) {
630
618
  min-width: 0;
631
619
  height: auto;
632
- border: 0;
633
620
  padding: 0;
634
621
  }
635
622
 
@@ -651,10 +638,6 @@
651
638
  word-break: normal;
652
639
  }
653
640
 
654
- .help-document .md-table thead {
655
- background: var(--ui-surface-subtle);
656
- }
657
-
658
641
  .help-document .md-table thead .md-table-cell {
659
642
  color: var(--color-zinc-700);
660
643
  font-size: 0.75rem;
@@ -672,7 +655,8 @@
672
655
  font-weight: 400;
673
656
  }
674
657
 
675
- .help-document .md-table-cell :where(code) {
658
+ /* Element specificity, so it outranks MarkdownView's inline-code fill. */
659
+ .help-document .md-table-cell code {
676
660
  border-radius: 0;
677
661
  background: transparent;
678
662
  color: inherit;
@@ -681,18 +665,10 @@
681
665
  padding: 0;
682
666
  }
683
667
 
684
- .dark .help-document .md-table thead {
685
- background: var(--ui-surface-subtle);
686
- }
687
-
688
668
  .dark .help-document .md-table thead .md-table-cell {
689
669
  color: var(--color-zinc-200);
690
670
  }
691
671
 
692
- .dark .help-document :where(blockquote) {
693
- color: var(--color-zinc-400);
694
- }
695
-
696
672
  .help-document :where(hr) {
697
673
  height: 0;
698
674
  margin-block: 2rem;
@@ -294,6 +294,11 @@ solid-island {
294
294
  border-radius: 0; border: 0; border-bottom: 1px solid var(--ui-border);
295
295
  box-shadow: none !important;
296
296
  }
297
+ /* Toasts at the top edge of a phone start below the header instead of
298
+ covering its menu and search buttons. */
299
+ :root:has(.cloud-app-canvas .layout-header) {
300
+ --k2b-toast-offset-top: 2.875rem;
301
+ }
297
302
 
298
303
  }
299
304
 
@@ -7,6 +7,9 @@
7
7
  --ui-surface-subtle: rgb(248 248 248 / 0.96);
8
8
  --ui-surface-muted: rgb(243 244 243 / 0.96);
9
9
  --ui-surface-raised: rgb(255 255 255 / 0.99);
10
+ /* Dimmed text stays at WCAG AA on the muted surfaces it often sits on, such
11
+ as dialog section groups, not only on the plain surface. */
12
+ --ui-text-dimmed: color-mix(in srgb, var(--color-zinc-500) 80%, var(--color-zinc-600));
10
13
  --ui-border: rgb(218 220 219 / 0.68);
11
14
  --ui-border-strong: rgb(207 210 208 / 0.9);
12
15
  --ui-hover: rgb(239 240 239 / 0.9);
@@ -135,6 +138,7 @@
135
138
  --ui-surface-subtle: color-mix(in srgb, var(--ui-surface) 68%, var(--ui-surface-muted));
136
139
  --ui-surface-muted: #20242a;
137
140
  --ui-surface-raised: #181d24;
141
+ --ui-text-dimmed: color-mix(in srgb, var(--color-zinc-500) 40%, var(--color-zinc-400));
138
142
  --ui-border: #29313a;
139
143
  --ui-border-strong: #3a4552;
140
144
  --ui-hover: #252c35;
@@ -222,7 +226,7 @@
222
226
  }
223
227
 
224
228
  @utility text-dimmed {
225
- @apply text-zinc-500 dark:text-zinc-500;
229
+ color: var(--ui-text-dimmed);
226
230
  }
227
231
 
228
232
  @utility text-label {
@@ -224,11 +224,21 @@
224
224
  }
225
225
  }
226
226
 
227
- #ui-toast-container > div {
228
- border: 1px solid var(--ui-border-strong);
229
- border-radius: var(--ui-radius-surface);
230
- background: var(--ui-surface-raised);
231
- box-shadow: var(--ui-shadow-float) !important;
227
+ /* Operator banners: a NoticeCard with its close button in the top corner. */
228
+ .k2b-ui .cloud-announcement {
229
+ position: relative;
230
+ }
231
+ .k2b-ui .cloud-announcement .k2b-notice-card__content {
232
+ padding-right: 1.75rem;
233
+ }
234
+ .k2b-ui .cloud-announcement .k2b-content-markdown {
235
+ font-size: inherit;
236
+ line-height: inherit;
237
+ }
238
+ .k2b-ui .cloud-announcement > .k2b-icon-button {
239
+ position: absolute;
240
+ top: 0.4375rem;
241
+ right: 0.4375rem;
232
242
  }
233
243
 
234
244
  /* Approval prose follows the surrounding review fields, not document typography. */
@@ -22,6 +22,10 @@
22
22
  background: var(--ui-surface);
23
23
  /* Shared surface depth stays consistent with the Layout header. */
24
24
  box-shadow: var(--ui-shadow-surface);
25
+ /* A paper card inside a dialog section group paints its own surface, so its
26
+ fields return to the muted well instead of the group's white one. */
27
+ --k2b-field-surface: initial;
28
+ --k2b-field-hover: initial;
25
29
  }
26
30
 
27
31
  @utility dialog-panel {
@@ -431,6 +431,12 @@
431
431
  color: var(--ui-app-accent-text);
432
432
  }
433
433
 
434
+ /* The brackets, weight and icon already mark the widget as a link, so it
435
+ keeps no underline inside MarkdownView, the same as in Assistant chat. */
436
+ .k2b-ui .k2b-content-markdown a.md-link-widget {
437
+ text-decoration: none;
438
+ }
439
+
434
440
  .md-link-widget:focus-visible {
435
441
  border-radius: 0.125rem;
436
442
  outline: var(--k2b-focus-width) solid var(--ui-app-accent-border);
@@ -464,7 +470,20 @@
464
470
  @apply bg-zinc-200/40 dark:bg-zinc-800;
465
471
  }
466
472
 
467
- .md-code-block pre,
473
+ /* Rendered code blocks match MarkdownView: a fill without a frame that
474
+ follows `--k2b-field-surface`, so it stays visible on a tinted group. The
475
+ transparent border keeps the edge visible in forced colours. The rendered
476
+ wrapper shares the editor's line class, so it drops the line fill. */
477
+ .md-code-block:has(> pre) {
478
+ background: transparent;
479
+ }
480
+
481
+ .md-code-block pre {
482
+ border: 1px solid transparent !important;
483
+ border-radius: var(--ui-radius-control) !important;
484
+ background: var(--k2b-field-surface, var(--ui-surface-muted)) !important;
485
+ }
486
+
468
487
  .md-mermaid-block,
469
488
  .md-katex-block {
470
489
  border: 1px solid rgb(228 228 231 / 0.72) !important;
@@ -479,7 +498,6 @@
479
498
  padding: 0.75rem;
480
499
  }
481
500
 
482
- .dark .md-code-block pre,
483
501
  .dark .md-mermaid-block,
484
502
  .dark .md-katex-block {
485
503
  border-color: rgb(63 63 70 / 0.72) !important;
@@ -1,7 +1,8 @@
1
- /* Markdown tables use the same quiet visual language as DataTable: one
2
- contained surface, one header band, and hairline row separators. Used by
3
- both the server-side `marked` renderer and the CodeMirror table widget so
4
- read-mode and edit-mode look identical.
1
+ /* Markdown tables use the same hairline language as @k2b/ui MarkdownView:
2
+ no frame or header fill, a stronger line under the header, hairline row
3
+ separators, and the outer columns flush with the prose. Used by both the
4
+ server-side `marked` renderer and the CodeMirror table widget so read-mode
5
+ and edit-mode look identical.
5
6
 
6
7
  Three-layer markup:
7
8
  <div class="md-table-wrap"> ← horizontal scroll owner
@@ -13,10 +14,13 @@
13
14
  overflow: clip;
14
15
  margin-top: 0.5rem;
15
16
  margin-bottom: 0.5rem;
16
- border: 1px solid var(--ui-border);
17
- border-radius: var(--ui-radius-surface);
18
- background: var(--ui-surface);
19
- box-shadow: var(--ui-shadow-surface);
17
+ }
18
+
19
+ /* Inside MarkdownView a table takes the same block spacing as its own
20
+ tables, so two tables in a row do not read as one. Hosts such as Help keep
21
+ their own spacing. */
22
+ :where(.k2b-ui .k2b-content-markdown) .md-table-wrap {
23
+ margin-block: 1em;
20
24
  }
21
25
 
22
26
  .md-table {
@@ -39,12 +43,8 @@
39
43
  border: 0;
40
44
  }
41
45
 
42
- .md-table thead {
43
- background: var(--ui-data-header);
44
- }
45
-
46
46
  .md-table thead tr {
47
- border-bottom: 1px solid var(--ui-data-divider);
47
+ border-bottom: 1px solid var(--ui-border-strong);
48
48
  }
49
49
 
50
50
  .md-table tbody tr:not(:last-child) {
@@ -87,12 +87,29 @@
87
87
  color: inherit;
88
88
  }
89
89
 
90
- /* Headers inherit the single shared band instead of drawing per-cell fills. */
91
90
  .md-table thead .md-table-cell {
91
+ padding-top: 0;
92
92
  background: transparent;
93
93
  font-weight: 600;
94
94
  }
95
95
 
96
+ .md-table th:first-child > .md-table-cell,
97
+ .md-table td:first-child > .md-table-cell {
98
+ padding-left: 0;
99
+ }
100
+
101
+ .md-table th:last-child > .md-table-cell,
102
+ .md-table td:last-child > .md-table-cell {
103
+ padding-right: 0;
104
+ }
105
+
106
+ /* Inside MarkdownView the span stays the only padding owner. */
107
+ .k2b-ui .k2b-content-markdown .md-table th,
108
+ .k2b-ui .k2b-content-markdown .md-table td {
109
+ padding: 0;
110
+ font-size: inherit;
111
+ }
112
+
96
113
  .dark .md-table thead .md-table-cell {
97
114
  background: transparent;
98
115
  }
@@ -109,9 +126,10 @@
109
126
  justify-content: center;
110
127
  }
111
128
 
112
- /* Summary rows use the same quiet band as a DataTable footer. */
113
- .md-table tbody tr.md-table-total-row {
114
- background: var(--ui-data-header);
129
+ /* A summary row sits under the same stronger line as the header. The line is
130
+ on the cells, so it also wins over a row separator or MarkdownView's. */
131
+ .k2b-ui .md-table tbody tr.md-table-total-row > td {
132
+ border-top: 1px solid var(--ui-border-strong);
115
133
  }
116
134
 
117
135
  .md-table tbody tr.md-table-total-row .md-table-cell {