@k2b/cloud 0.21.1 → 0.23.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 +4 -3
- package/scripts/README.md +1 -1
- package/scripts/build-canvas-workers.ts +58 -0
- package/scripts/build.ts +4 -5
- package/src/_internal/canvas-worker.ts +24 -0
- package/src/_internal/define-app.ts +81 -7
- package/src/_internal/page-responses.ts +19 -3
- package/src/_internal/registry-validation.ts +6 -0
- package/src/_internal/runtime-context.ts +1 -0
- package/src/_internal/static-assets.ts +18 -3
- package/src/access/ResourceApiKeys.tsx +30 -30
- package/src/ai/capability-execution.ts +5 -0
- package/src/ai/client/controller.ts +17 -3
- package/src/ai/client/transport.ts +47 -3
- package/src/ai/live-routes.ts +2 -2
- package/src/ai/pdf-render.ts +2 -22
- package/src/ai/routes.ts +5 -4
- package/src/ai/stream.ts +89 -65
- package/src/api/app-approval.ts +5 -1
- package/src/api/index.ts +3 -0
- package/src/api/me.ts +19 -5
- package/src/api/pwa-phone.ts +161 -0
- package/src/api/pwa.ts +179 -0
- package/src/browser/app-session.ts +69 -0
- package/src/browser/live-connection.ts +211 -0
- package/src/browser/live-websocket.ts +31 -11
- package/src/browser/live.ts +2 -0
- package/src/contracts/app.ts +10 -0
- package/src/contracts/index.ts +1 -0
- package/src/contracts/pwa-paths.ts +6 -0
- package/src/contracts/pwa.ts +156 -0
- package/src/contracts/registry.ts +7 -0
- package/src/contracts/shared.ts +7 -1
- package/src/events/index.ts +2 -0
- package/src/events/live-engine.ts +826 -0
- package/src/events/live-protocol.ts +31 -0
- package/src/events/live.ts +298 -0
- package/src/server/actor.ts +7 -0
- package/src/server/api-client.ts +23 -2
- package/src/server/index.ts +3 -1
- package/src/server/middleware/auth.ts +80 -8
- package/src/server/middleware/openapi.ts +2 -1
- package/src/server/services/access.ts +49 -0
- package/src/server/services/index.ts +1 -0
- package/src/services/app-approval.ts +6 -25
- package/src/services/audit/index.ts +2 -0
- package/src/services/branding/app-icon-source.ts +40 -0
- package/src/services/branding/app-icons.ts +112 -0
- package/src/services/branding/icon-render-worker.ts +69 -0
- package/src/services/branding/icon-svg.ts +22 -0
- package/src/services/identity/invocation-actor.ts +8 -5
- package/src/services/identity/invocation-authority.ts +1 -0
- package/src/services/identity/invocation-token.ts +6 -0
- package/src/services/index.ts +1 -0
- package/src/services/outbox.ts +150 -30
- package/src/services/pairing-secret.ts +16 -0
- package/src/services/pwa-devices.ts +574 -0
- package/src/services/session/index.ts +212 -57
- package/src/services/session/recent.ts +42 -0
- package/src/services/session/user.ts +15 -5
- package/src/shared/index.ts +1 -0
- package/src/{browser → shared}/locale-preference.ts +1 -1
- package/src/shared/markdown/extensions/info-blocks.ts +18 -47
- package/src/shared/markdown/index.ts +5 -14
- package/src/ssr/AppLaunchpad.island.tsx +8 -1
- package/src/ssr/AppLaunchpadPanel.tsx +1 -1
- package/src/ssr/GlobalAnnouncements.island.tsx +9 -34
- package/src/ssr/Layout.tsx +10 -12
- package/src/ssr/LayoutHeader.tsx +14 -2
- package/src/ssr/LayoutHelp.tsx +2 -4
- package/src/ssr/LayoutRail.tsx +13 -4
- package/src/ssr/MinimalLayoutPreferences.island.tsx +1 -1
- package/src/ssr/MobileProfileActions.tsx +19 -13
- package/src/ssr/PageError.tsx +23 -1
- package/src/ssr/ProfilePreferences.island.tsx +9 -1
- package/src/ssr/PwaLayout.tsx +69 -0
- package/src/ssr/PwaRuntime.island.tsx +105 -0
- package/src/ssr/TimezoneCookie.island.tsx +7 -1
- package/src/ssr/app-navigation.ts +25 -10
- package/src/ssr/index.ts +8 -1
- package/src/ssr/layout-context.ts +1 -1
- package/src/ssr/preference-controller.ts +2 -2
- package/src/ssr/profile-actions.ts +3 -1
- package/src/ssr/profile-preferences-messages.ts +2 -0
- package/src/ssr/pwa-messages.ts +24 -0
- package/src/styles/effects.css +6 -30
- package/src/styles/global.css +11 -0
- package/src/styles/tokens.css +5 -1
- package/src/styles/utilities-feedback.css +15 -5
- package/src/styles/utilities-layout.css +4 -0
- package/src/styles/utilities-markdown-editor.css +20 -2
- package/src/styles/utilities-markdown-table.css +35 -17
- package/scripts/build-pdf-renderer.ts +0 -39
|
@@ -6,7 +6,7 @@ import type { RuntimeContext } from "./runtime";
|
|
|
6
6
|
export type LayoutContext = {
|
|
7
7
|
get(key: "user"): User | undefined;
|
|
8
8
|
get(key: "railPreferences"): RailSnapshot | undefined;
|
|
9
|
-
get(key: "page"): { theme?: "light" | "dark" };
|
|
9
|
+
get(key: "page"): { theme?: "light" | "dark"; title?: string; pwa?: { name: string } };
|
|
10
10
|
get(key: "runtime"): RuntimeContext;
|
|
11
11
|
get(key: "announcements"): LayoutAnnouncementsState | undefined;
|
|
12
12
|
/** Every application settings snapshot includes Core's app metadata. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DropdownItem } from "@k2b/ui";
|
|
2
2
|
import { createMemo, createSignal, onCleanup, onMount } from "solid-js";
|
|
3
|
-
import { profilePreferenceLocale, setLocalePreference } from "../
|
|
3
|
+
import { profilePreferenceLocale, setLocalePreference } from "../shared/locale-preference";
|
|
4
4
|
import { type CloudTheme, getCurrentThemePreference, setThemePreference } from "../shared/theme";
|
|
5
5
|
import { profilePreferencesMessages } from "./profile-preferences-messages";
|
|
6
6
|
|
|
@@ -40,5 +40,5 @@ export const createPreferenceController = (initialTheme: CloudTheme, locale: ()
|
|
|
40
40
|
},
|
|
41
41
|
]);
|
|
42
42
|
|
|
43
|
-
return { items, languageLabel, messages, theme, themeLabel, toggleLanguage, toggleTheme };
|
|
43
|
+
return { items, language, languageLabel, messages, theme, themeLabel, toggleLanguage, toggleTheme };
|
|
44
44
|
};
|
|
@@ -5,7 +5,8 @@ import { apiClient } from "../clients/core";
|
|
|
5
5
|
import type { CloudTheme } from "../shared/theme";
|
|
6
6
|
import { createPreferenceController } from "./preference-controller";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/** `appHref` is set while the installation offers the mobile app; the item then leads to `/me/app`. */
|
|
9
|
+
export function createProfileActions(initialTheme: CloudTheme, appHref?: string) {
|
|
9
10
|
const locale = useLocale();
|
|
10
11
|
const preferences = createPreferenceController(initialTheme, locale);
|
|
11
12
|
const [signingOut, setSigningOut] = createSignal(false);
|
|
@@ -30,6 +31,7 @@ export function createProfileActions(initialTheme: CloudTheme) {
|
|
|
30
31
|
icon: "ti ti-user-circle",
|
|
31
32
|
label: preferences.messages().profileSettings,
|
|
32
33
|
},
|
|
34
|
+
...(appHref ? [{ href: appHref, icon: "ti ti-device-mobile", label: preferences.messages().app }] : []),
|
|
33
35
|
{
|
|
34
36
|
action: signOut,
|
|
35
37
|
icon: "ti ti-logout",
|
|
@@ -9,6 +9,7 @@ export const profilePreferencesMessages = i18n.define({
|
|
|
9
9
|
language: "Language",
|
|
10
10
|
legalLinks: "Legal",
|
|
11
11
|
profileSettings: "Profile settings",
|
|
12
|
+
app: "App",
|
|
12
13
|
signOut: "Sign out",
|
|
13
14
|
signOutFailed: "Sign out failed. Please try again.",
|
|
14
15
|
switchToDark: "Dark mode",
|
|
@@ -22,6 +23,7 @@ export const profilePreferencesMessages = i18n.define({
|
|
|
22
23
|
language: "Sprache",
|
|
23
24
|
legalLinks: "Rechtliches",
|
|
24
25
|
profileSettings: "Profileinstellungen",
|
|
26
|
+
app: "App",
|
|
25
27
|
signOut: "Abmelden",
|
|
26
28
|
signOutFailed: "Abmelden fehlgeschlagen. Bitte versuche es erneut.",
|
|
27
29
|
switchToDark: "Dunkler Modus",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { i18n } from "@k2b/stdlib";
|
|
2
|
+
|
|
3
|
+
/** Strings of the mobile app's frame: the tab bar, the offline notice and the account notice. */
|
|
4
|
+
export const pwaMessages = i18n.define({
|
|
5
|
+
baseLocale: "en",
|
|
6
|
+
messages: {
|
|
7
|
+
en: {
|
|
8
|
+
tabs: "App",
|
|
9
|
+
start: "Start",
|
|
10
|
+
offline: "You're offline",
|
|
11
|
+
otherAccount: ({ cloud, name }: { cloud: string; name: string }) =>
|
|
12
|
+
`Chrome on this phone is signed in to ${cloud} as ${name}. Changes in the app may be saved to that account. Sign out of ${cloud} in Chrome.`,
|
|
13
|
+
errorAction: "Back to Start",
|
|
14
|
+
},
|
|
15
|
+
de: {
|
|
16
|
+
tabs: "App",
|
|
17
|
+
start: "Start",
|
|
18
|
+
offline: "Du bist offline",
|
|
19
|
+
otherAccount: ({ cloud, name }: { cloud: string; name: string }) =>
|
|
20
|
+
`Chrome auf diesem Telefon ist bei ${cloud} als ${name} angemeldet. Änderungen in der App werden womöglich in diesem Konto gespeichert. Melde dich in Chrome von ${cloud} ab.`,
|
|
21
|
+
errorAction: "Zurück zum Start",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
package/src/styles/effects.css
CHANGED
|
@@ -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
|
|
627
|
-
|
|
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
|
-
|
|
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;
|
package/src/styles/global.css
CHANGED
|
@@ -239,6 +239,12 @@ body {
|
|
|
239
239
|
color: rgb(244 244 245); /* zinc-100 */
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/* Pages of the mobile app paint the shell canvas, which their theme-color and
|
|
243
|
+
html background repeat for the status bar. */
|
|
244
|
+
html:has(.k2b-mobile-shell) body {
|
|
245
|
+
background-color: var(--k2b-surface-canvas);
|
|
246
|
+
}
|
|
247
|
+
|
|
242
248
|
.dark {
|
|
243
249
|
color-scheme: dark;
|
|
244
250
|
--color-selection-bg: rgb(59 130 246 / 0.5);
|
|
@@ -294,6 +300,11 @@ solid-island {
|
|
|
294
300
|
border-radius: 0; border: 0; border-bottom: 1px solid var(--ui-border);
|
|
295
301
|
box-shadow: none !important;
|
|
296
302
|
}
|
|
303
|
+
/* Toasts at the top edge of a phone start below the header instead of
|
|
304
|
+
covering its menu and search buttons. */
|
|
305
|
+
:root:has(.cloud-app-canvas .layout-header) {
|
|
306
|
+
--k2b-toast-offset-top: 2.875rem;
|
|
307
|
+
}
|
|
297
308
|
|
|
298
309
|
}
|
|
299
310
|
|
package/src/styles/tokens.css
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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.875rem;
|
|
241
|
+
right: 0.875rem;
|
|
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
|
-
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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-
|
|
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
|
-
/*
|
|
113
|
-
|
|
114
|
-
|
|
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 {
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { cp, mkdir } from "node:fs/promises";
|
|
2
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
|
|
6
|
-
/** Package the decoder and native assets only for bundles importing PDF vision. */
|
|
7
|
-
export async function buildPdfRenderer(dist: string) {
|
|
8
|
-
const framework = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
-
const out = resolve(dist, "pdf-render");
|
|
10
|
-
await mkdir(out, { recursive: true });
|
|
11
|
-
const worker = await Bun.build({
|
|
12
|
-
entrypoints: [resolve(framework, "src/ai/pdf-render-worker.ts")],
|
|
13
|
-
target: "bun",
|
|
14
|
-
outdir: out,
|
|
15
|
-
naming: "worker.js",
|
|
16
|
-
external: ["pdfjs-dist", "@napi-rs/canvas"],
|
|
17
|
-
});
|
|
18
|
-
if (!worker.success) throw new Error(`PDF decoder build failed: ${worker.logs.join("\n")}`);
|
|
19
|
-
for (const name of ["pdfjs-dist", "@napi-rs/canvas"]) {
|
|
20
|
-
const source = dirname(Bun.resolveSync(`${name}/package.json`, framework));
|
|
21
|
-
await cp(source, resolve(out, "node_modules", name), { recursive: true, dereference: true });
|
|
22
|
-
if (name !== "@napi-rs/canvas") continue;
|
|
23
|
-
const manifest = z
|
|
24
|
-
.object({ optionalDependencies: z.record(z.string(), z.string()) })
|
|
25
|
-
.parse(await Bun.file(resolve(source, "package.json")).json());
|
|
26
|
-
let nativePackages = 0;
|
|
27
|
-
for (const dependency of Object.keys(manifest.optionalDependencies)) {
|
|
28
|
-
let location: string;
|
|
29
|
-
try {
|
|
30
|
-
location = dirname(Bun.resolveSync(`${dependency}/package.json`, source));
|
|
31
|
-
} catch {
|
|
32
|
-
continue;
|
|
33
|
-
} // Only the installed target-platform binary is needed.
|
|
34
|
-
await cp(location, resolve(out, "node_modules", dependency), { recursive: true, dereference: true });
|
|
35
|
-
nativePackages++;
|
|
36
|
-
}
|
|
37
|
-
if (!nativePackages) throw new Error("PDF decoder needs an installed native canvas binary for the build platform.");
|
|
38
|
-
}
|
|
39
|
-
}
|