@k2b/cloud 0.38.0 → 0.40.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/README.md +8 -0
- package/package.json +12 -5
- package/scripts/build-canvas-workers.ts +109 -29
- package/scripts/build.ts +3 -5
- package/src/_internal/app-favicon.ts +4 -2
- package/src/_internal/app-path.ts +25 -0
- package/src/_internal/app-presentation.ts +4 -0
- package/src/_internal/canvas-worker.ts +5 -3
- package/src/_internal/capabilities.ts +72 -48
- package/src/_internal/capability-reviews.ts +81 -0
- package/src/_internal/capability-schemas.ts +29 -0
- package/src/_internal/capability-sentences.ts +216 -1
- package/src/_internal/capability-streams.ts +7 -0
- package/src/_internal/define-app.ts +63 -16
- package/src/_internal/font-preloads.ts +2 -1
- package/src/_internal/panel-cookie.ts +39 -0
- package/src/_internal/registry-validation.ts +21 -26
- package/src/_internal/runtime-context.ts +1 -0
- package/src/_internal/runtime-watcher.ts +6 -0
- package/src/_internal/static-assets.ts +52 -3
- package/src/_internal/status-preserving-ssr.ts +2 -0
- package/src/access/PermissionEditor.browser-harness.tsx +57 -38
- package/src/access/PermissionEditor.tsx +32 -7
- package/src/access/ResourceApiKeys.tsx +5 -1
- package/src/account/EntitySearch.tsx +1 -1
- package/src/ai/action-review.ts +101 -0
- package/src/ai/approval-routes.ts +5 -2
- package/src/ai/approvals.ts +139 -28
- package/src/ai/background-review.ts +72 -0
- package/src/ai/browser.ts +10 -0
- package/src/ai/capabilities.ts +29 -11
- package/src/ai/capability-execution.ts +76 -43
- package/src/ai/capability-result.ts +95 -0
- package/src/ai/chat/action-card.ts +398 -0
- package/src/ai/chat/action-messages.ts +129 -0
- package/src/ai/chat/action-question.browser-harness.tsx +245 -0
- package/src/ai/chat/action-question.fixtures.ts +733 -0
- package/src/ai/chat/action-question.tsx +669 -0
- package/src/ai/chat/action-sentences.ts +1 -44
- package/src/ai/chat/blocks.tsx +19 -25
- package/src/ai/chat/message-actions.tsx +6 -0
- package/src/ai/chat/tool-action.tsx +481 -0
- package/src/ai/chat/turn-view.tsx +45 -163
- package/src/ai/chat/view-block.tsx +22 -7
- package/src/ai/chat-task-contracts.ts +31 -3
- package/src/ai/chat-task-reasons-migrate.ts +75 -0
- package/src/ai/chat-task-reasons.ts +92 -0
- package/src/ai/chat-tasks.ts +438 -78
- package/src/ai/client/controller.ts +59 -0
- package/src/ai/default-tools.ts +9 -1
- package/src/ai/executor.ts +190 -39
- package/src/ai/index.ts +14 -0
- package/src/ai/migrate.ts +39 -4
- package/src/ai/projects-routes.ts +3 -0
- package/src/ai/protocol.ts +14 -2
- package/src/ai/recent-resources.ts +240 -0
- package/src/ai/recent-sent-refs.ts +38 -0
- package/src/ai/request-context.ts +7 -1
- package/src/ai/routes.ts +172 -2
- package/src/ai/runtime.ts +13 -27
- package/src/ai/skills-routes.ts +3 -0
- package/src/ai/skills.ts +10 -1
- package/src/ai/store.ts +232 -27
- package/src/ai/timeline.ts +9 -1
- package/src/ai/tool-audit.ts +8 -0
- package/src/ai/tool-wording.ts +67 -0
- package/src/ai/turn-abort.ts +33 -0
- package/src/ai/types.ts +40 -4
- package/src/api/accounts-entities.ts +2 -1
- package/src/api/admin-ai-projects.ts +2 -0
- package/src/api/admin-ai-skills.ts +2 -0
- package/src/api/admin-ai-usage.ts +2 -0
- package/src/api/admin-core-settings.ts +190 -139
- package/src/api/admin-geoip.ts +80 -0
- package/src/api/admin-identity.ts +3 -0
- package/src/api/admin-lifecycle.ts +3 -0
- package/src/api/admin-outgoing-mail.ts +6 -2
- package/src/api/app-approval.ts +54 -6
- package/src/api/approvals-loader.ts +23 -1
- package/src/api/approvals.ts +3 -1
- package/src/api/auth.ts +25 -6
- package/src/api/capabilities.ts +44 -11
- package/src/api/capability-streams.ts +12 -0
- package/src/api/help.ts +4 -28
- package/src/api/index.ts +7 -1
- package/src/api/lasting-access-messages.ts +17 -0
- package/src/api/mcp.ts +3 -0
- package/src/api/me-panel-consent.ts +71 -0
- package/src/api/me.ts +80 -33
- package/src/api/search.ts +3 -1
- package/src/api/sync-ops.ts +2 -0
- package/src/api/widgets.ts +3 -0
- package/src/approvals/Approvals.tsx +180 -238
- package/src/approvals/messages.ts +12 -24
- package/src/browser/CloudResourceSearch.browser-harness.tsx +10 -2
- package/src/browser/CloudResourceSearch.tsx +10 -6
- package/src/browser/app-approval.ts +60 -6
- package/src/browser/commands.ts +22 -6
- package/src/browser/composer-catalog.ts +145 -0
- package/src/browser/composer-insert-messages.ts +31 -0
- package/src/browser/composer-insert.ts +160 -0
- package/src/browser/composer-open-messages.ts +17 -0
- package/src/browser/composer-open.ts +110 -0
- package/src/browser/discoverable-command.ts +6 -0
- package/src/browser/hints.ts +6 -0
- package/src/browser/live-connection.ts +26 -2
- package/src/browser/navigation-apps.ts +7 -0
- package/src/browser/panel-context-bridge.ts +30 -0
- package/src/browser/panel-context-receiver.ts +53 -0
- package/src/browser/panel-menu.tsx +56 -0
- package/src/browser/panel-messages.ts +35 -0
- package/src/browser/panel-shortcuts.ts +31 -0
- package/src/browser/panel-slot.ts +756 -0
- package/src/browser/panel.ts +65 -0
- package/src/browser/resource-picker.tsx +12 -1
- package/src/browser/search-commands.ts +6 -3
- package/src/capabilities/client.ts +8 -2
- package/src/capabilities/reviews.ts +205 -0
- package/src/capabilities/server.ts +10 -3
- package/src/capabilities/testing.ts +47 -0
- package/src/capabilities/types.ts +2 -2
- package/src/cli/account.ts +13 -3
- package/src/cli/admin/geoip.ts +115 -0
- package/src/cli/admin/index.ts +3 -0
- package/src/contracts/app-approval.ts +159 -12
- package/src/contracts/app.ts +14 -0
- package/src/contracts/approvals.ts +2 -2
- package/src/contracts/capabilities.ts +410 -18
- package/src/contracts/geoip.ts +42 -0
- package/src/contracts/index.ts +3 -0
- package/src/contracts/panel-context-plain.ts +99 -0
- package/src/contracts/panel-context.ts +93 -0
- package/src/contracts/registry.ts +3 -1
- package/src/contracts/seen-hints.ts +35 -0
- package/src/contracts/shared.ts +2 -0
- package/src/server/client-ip.ts +5 -0
- package/src/server/help-payload.ts +38 -0
- package/src/server/middleware/auth.ts +11 -1
- package/src/server/middleware/middleware.ts +9 -0
- package/src/server/middleware/no-transform.ts +19 -0
- package/src/server/middleware/rate-limit.ts +4 -6
- package/src/server/request-context/address.ts +45 -0
- package/src/server/request-context/geoip.ts +380 -0
- package/src/server/request-context/index.ts +33 -0
- package/src/server/request-context/user-agent.ts +95 -0
- package/src/server/services/access.ts +5 -1
- package/src/services/accounts/posix.ts +2 -1
- package/src/services/app-approval.ts +533 -90
- package/src/services/approvals/device.ts +9 -5
- package/src/services/approvals/index.ts +6 -5
- package/src/services/approvals/list.ts +26 -5
- package/src/services/auth-flows/notification-sender.ts +3 -0
- package/src/services/geoip/index.ts +164 -0
- package/src/services/geoip/store.ts +30 -0
- package/src/services/geoip/upload.ts +150 -0
- package/src/services/identity/routes.ts +5 -1
- package/src/services/index.ts +32 -3
- package/src/services/known-browsers.ts +312 -0
- package/src/services/login-address-store.ts +51 -0
- package/src/services/login-context.ts +118 -0
- package/src/services/mandates/index.ts +3 -0
- package/src/services/mandates/policy.ts +15 -3
- package/src/services/notifications/browser.ts +16 -5
- package/src/services/notifications/email-frame.ts +1 -1
- package/src/services/oauth-tokens.ts +16 -2
- package/src/services/panel-context-consent.ts +58 -0
- package/src/services/pdf/image-protocol.ts +135 -0
- package/src/services/pdf/image-variants.ts +124 -0
- package/src/services/pdf/image-worker.ts +31 -0
- package/src/services/pdf/image.ts +109 -0
- package/src/services/pdf/index.ts +9 -0
- package/src/services/service-account-credentials.ts +21 -0
- package/src/services/session/index.ts +97 -16
- package/src/services/session/recent.ts +13 -0
- package/src/services/settings/api.ts +11 -6
- package/src/services/settings/app.ts +5 -4
- package/src/services/settings/core-settings.ts +4 -3
- package/src/services/settings/index.ts +19 -17
- package/src/services/settings/namespace.ts +2 -1
- package/src/services/settings/store.ts +83 -11
- package/src/services/webauthn.ts +12 -0
- package/src/shared/ai-platform-prompt.ts +1 -1
- package/src/shared/app-presentation.ts +1 -0
- package/src/shared/email-html.ts +2 -0
- package/src/shared/help.ts +3 -0
- package/src/shared/redirect.ts +12 -0
- package/src/shared-text/cursor.ts +22 -0
- package/src/shared-text/documents.ts +142 -0
- package/src/shared-text/events.ts +43 -0
- package/src/shared-text/index.ts +12 -0
- package/src/shared-text/log.ts +48 -0
- package/src/shared-text/text-diff.ts +23 -0
- package/src/shared-text/types.ts +41 -0
- package/src/ssr/AdminLayout.tsx +2 -0
- package/src/ssr/AppLaunchpadPanel.tsx +2 -2
- package/src/ssr/CloudShell.island.tsx +95 -10
- package/src/ssr/Layout.tsx +66 -10
- package/src/ssr/LayoutHeader.tsx +15 -9
- package/src/ssr/LayoutHelp.browser-harness.tsx +2 -0
- package/src/ssr/LayoutHelp.tsx +435 -274
- package/src/ssr/LayoutHelpPanel.browser-harness.tsx +136 -0
- package/src/ssr/LayoutHelpTrigger.tsx +27 -2
- package/src/ssr/LayoutRail.tsx +2 -2
- package/src/ssr/LayoutTabBar.tsx +29 -0
- package/src/ssr/MobileNavigation.tsx +2 -2
- package/src/ssr/PanelLayout.tsx +35 -0
- package/src/ssr/PanelRuntime.island.tsx +94 -0
- package/src/ssr/PanelSlot.tsx +158 -0
- package/src/ssr/PanelTrigger.tsx +49 -0
- package/src/ssr/ShellRuntime.island.tsx +69 -5
- package/src/ssr/app-appearance.ts +3 -2
- package/src/ssr/app-color.ts +105 -0
- package/src/ssr/app-launchpad.tsx +18 -1
- package/src/ssr/app-navigation.ts +28 -0
- package/src/ssr/compact-shell.baseline.json +5270 -0
- package/src/ssr/compact-shell.browser-harness.ts +439 -0
- package/src/ssr/dialog-app-colors.browser-harness.tsx +43 -0
- package/src/ssr/help-messages.ts +4 -0
- package/src/ssr/help.ts +20 -0
- package/src/ssr/hints.ts +25 -0
- package/src/ssr/index.ts +5 -0
- package/src/ssr/islands/index.ts +4 -3
- package/src/ssr/layout-context.ts +2 -0
- package/src/ssr/layout-help-article.server.ts +50 -0
- package/src/ssr/layout-help-start.ts +33 -7
- package/src/ssr/panel-consent.ts +29 -0
- package/src/ssr/panel-context.ts +10 -0
- package/src/ssr/panel-slot.browser-harness.tsx +159 -0
- package/src/ssr/platform-messages.ts +48 -0
- package/src/ssr/rail-navigation.ts +44 -0
- package/src/ssr/shell-data.tsx +5 -0
- package/src/ssr/shell-shortcuts.ts +13 -2
- package/src/styles/effects.css +201 -11
- package/src/styles/file-chooser.css +2 -1
- package/src/styles/global.css +314 -63
- package/src/styles/panel.css +416 -0
- package/src/styles/resource-search.css +6 -2
- package/src/styles/tokens.css +36 -13
- package/src/styles/utilities-buttons.css +3 -2
- package/src/styles/utilities-data.css +2 -1
- package/src/styles/utilities-feedback.css +2 -2
- package/src/styles/utilities-layout.css +3 -13
- package/src/styles/utilities-markdown-editor.css +6 -6
- package/src/styles/utilities-navigation.css +22 -43
package/src/styles/global.css
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
@import "./input.css";
|
|
33
33
|
@import "./resource-search.css";
|
|
34
34
|
@import "./file-chooser.css";
|
|
35
|
+
@import "./panel.css";
|
|
35
36
|
|
|
36
37
|
@theme {
|
|
37
38
|
--color-dark: rgb(9 9 11);
|
|
@@ -52,17 +53,19 @@
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
.cloud-app-canvas {
|
|
56
|
+
--cloud-canvas-strength: var(--app-canvas-strength, 0%);
|
|
57
|
+
--cloud-canvas-dark-strength: var(--app-canvas-dark-strength, 0%);
|
|
55
58
|
padding: var(--ui-space-shell);
|
|
56
59
|
background: linear-gradient(
|
|
57
60
|
var(--app-canvas-angle, 135deg),
|
|
58
|
-
color-mix(in srgb, var(--app-canvas-from, var(--color-zinc-50)) var(--
|
|
61
|
+
color-mix(in srgb, var(--app-canvas-from, var(--color-zinc-50)) var(--cloud-canvas-strength), var(--color-zinc-50)),
|
|
59
62
|
color-mix(
|
|
60
63
|
in srgb,
|
|
61
|
-
var(--app-canvas-via, var(--app-canvas-from, var(--color-zinc-50))) var(--
|
|
64
|
+
var(--app-canvas-via, var(--app-canvas-from, var(--color-zinc-50))) var(--cloud-canvas-strength),
|
|
62
65
|
var(--color-zinc-50)
|
|
63
66
|
)
|
|
64
67
|
50%,
|
|
65
|
-
color-mix(in srgb, var(--app-canvas-to, var(--color-zinc-50)) var(--
|
|
68
|
+
color-mix(in srgb, var(--app-canvas-to, var(--color-zinc-50)) var(--cloud-canvas-strength), var(--color-zinc-50))
|
|
66
69
|
);
|
|
67
70
|
}
|
|
68
71
|
|
|
@@ -88,12 +91,47 @@ html:has(.cloud-app-canvas[data-layout-full-page="true"]) {
|
|
|
88
91
|
.dark .cloud-app-canvas {
|
|
89
92
|
background: linear-gradient(
|
|
90
93
|
var(--app-canvas-angle, 135deg),
|
|
91
|
-
color-mix(in srgb, var(--app-canvas-from, var(--ui-canvas)) var(--
|
|
92
|
-
color-mix(in srgb, var(--app-canvas-via-dark, var(--ui-canvas)) var(--
|
|
93
|
-
color-mix(in srgb, var(--app-canvas-to, var(--ui-canvas)) var(--
|
|
94
|
+
color-mix(in srgb, var(--app-canvas-from, var(--ui-canvas)) var(--cloud-canvas-dark-strength), var(--ui-canvas)),
|
|
95
|
+
color-mix(in srgb, var(--app-canvas-via-dark, var(--ui-canvas)) var(--cloud-canvas-dark-strength), var(--ui-canvas)) 50%,
|
|
96
|
+
color-mix(in srgb, var(--app-canvas-to, var(--ui-canvas)) var(--cloud-canvas-dark-strength), var(--ui-canvas))
|
|
94
97
|
);
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
/* The shell's own colored surfaces, the tablet rail's container and the
|
|
101
|
+
phone's bottom bar, carry the app color alone in a narrow shape. A white
|
|
102
|
+
middle, the canvas's default `via`, would make their edge vanish halfway,
|
|
103
|
+
so they mix the middle from the app's two colors and take a stronger tint:
|
|
104
|
+
34 % light and 22 % dark, with a 16 % and 12 % middle. A page without an app
|
|
105
|
+
color gets a neutral tint. The app declaration stays the same. */
|
|
106
|
+
.cloud-app-canvas {
|
|
107
|
+
--cloud-shell-strength: 34%;
|
|
108
|
+
--cloud-shell-via-strength: 16%;
|
|
109
|
+
--cloud-shell-gradient: linear-gradient(
|
|
110
|
+
160deg,
|
|
111
|
+
color-mix(in srgb, var(--app-canvas-from, var(--color-zinc-400)) var(--cloud-shell-strength), var(--ui-canvas)),
|
|
112
|
+
color-mix(
|
|
113
|
+
in srgb,
|
|
114
|
+
color-mix(in srgb, var(--app-canvas-from, var(--color-zinc-400)) 45%, var(--app-canvas-to, var(--color-zinc-400)))
|
|
115
|
+
var(--cloud-shell-via-strength),
|
|
116
|
+
var(--ui-canvas)
|
|
117
|
+
)
|
|
118
|
+
55%,
|
|
119
|
+
color-mix(in srgb, var(--app-canvas-to, var(--color-zinc-400)) var(--cloud-shell-strength), var(--ui-canvas))
|
|
120
|
+
);
|
|
121
|
+
/* On color the open item is the surface in light and tinted in dark. Its
|
|
122
|
+
label is the app ink, which app-color.ts keeps at AA on both fills. */
|
|
123
|
+
--cloud-shell-selected: var(--k2b-surface);
|
|
124
|
+
--cloud-shell-selected-text: var(--ui-app-accent-text);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.dark .cloud-app-canvas {
|
|
128
|
+
--cloud-shell-strength: 22%;
|
|
129
|
+
--cloud-shell-via-strength: 12%;
|
|
130
|
+
/* The navigation share over the muted surface, which stays apart from the
|
|
131
|
+
dark bar; app-color.ts derives the same fill as shellSelected. */
|
|
132
|
+
--cloud-shell-selected: color-mix(in srgb, var(--app-accent, var(--color-blue-500)) 17%, var(--ui-surface-muted));
|
|
133
|
+
}
|
|
134
|
+
|
|
97
135
|
:root {
|
|
98
136
|
color-scheme: light;
|
|
99
137
|
}
|
|
@@ -243,6 +281,21 @@ body {
|
|
|
243
281
|
color: rgb(244 244 245); /* zinc-100 */
|
|
244
282
|
}
|
|
245
283
|
|
|
284
|
+
/* The root paints the screen's page color as well. @k2b/ui makes it the
|
|
285
|
+
default `k2b-app-area` container, and containment stops a body background
|
|
286
|
+
from reaching the canvas that overscroll and short pages show. Zero
|
|
287
|
+
specificity, so the PWA canvas style and syncThemeColor still win; screen
|
|
288
|
+
only, so paper stays white. */
|
|
289
|
+
@media screen {
|
|
290
|
+
:where(html) {
|
|
291
|
+
background-color: rgb(250 250 250); /* zinc-50 */
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
:where(html.dark) {
|
|
295
|
+
background-color: rgb(9 9 11); /* zinc-950 */
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
246
299
|
/* Pages of the mobile app paint the shell canvas, which their theme-color and
|
|
247
300
|
html background repeat for the status bar. */
|
|
248
301
|
html:has(.k2b-mobile-shell) body {
|
|
@@ -295,31 +348,37 @@ solid-island {
|
|
|
295
348
|
|
|
296
349
|
/* Cloud has three shell modes. Phones, below md, get the header and no rail.
|
|
297
350
|
From md, signed-in people get the 56 px rail instead of the header: up to
|
|
298
|
-
1023 px the
|
|
299
|
-
from 1024 px
|
|
300
|
-
and the card from md. Each query is the exact opposite of
|
|
301
|
-
every width, also a fractional one under browser zoom,
|
|
302
|
-
one mode. */
|
|
351
|
+
1023 px the rail sits in a rounded container beside the app as a rounded
|
|
352
|
+
card, and from 1024 px the app is a card beside the rail. Anonymous pages
|
|
353
|
+
keep the header and the card from md. Each query is the exact opposite of
|
|
354
|
+
the next one, so every width, also a fractional one under browser zoom,
|
|
355
|
+
falls into exactly one mode. */
|
|
303
356
|
@media not all and (min-width: 768px) {
|
|
304
357
|
.cloud-app-canvas {
|
|
305
358
|
padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
|
|
306
359
|
}
|
|
307
|
-
/*
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
.
|
|
360
|
+
/* Anonymous pages: the flat surface replaces the app gradient in both
|
|
361
|
+
themes, and the document is the page scroller. The dark selector matches
|
|
362
|
+
the specificity of the dark gradient above. */
|
|
363
|
+
.cloud-app-canvas:not([data-layout-authenticated]),
|
|
364
|
+
.dark .cloud-app-canvas:not([data-layout-authenticated]) {
|
|
311
365
|
background: var(--ui-surface);
|
|
312
366
|
}
|
|
313
|
-
/*
|
|
314
|
-
|
|
315
|
-
inner scrolling
|
|
316
|
-
|
|
367
|
+
/* Reserve the page scroller's gutter so short and long pages keep the same
|
|
368
|
+
width: the document's, or the card's for signed-in people. Full-page
|
|
369
|
+
surfaces, workspaces, and scroll areas own their inner scrolling, so the
|
|
370
|
+
card reserves no second gutter beside theirs. */
|
|
371
|
+
html:has(.cloud-app-canvas:not([data-layout-full-page], [data-layout-authenticated])) { scrollbar-gutter: stable; }
|
|
372
|
+
.cloud-app-canvas[data-layout-authenticated]:not([data-layout-full-page])
|
|
373
|
+
.layout-content-main:not(:has(> .k2b-scroll-area, > .k2b-app-workspace, > :is(solid-island, solid-client) > .k2b-app-workspace)) {
|
|
374
|
+
scrollbar-gutter: stable;
|
|
375
|
+
}
|
|
317
376
|
/* A page that scrolls its content in a ScrollArea grows with it here, so
|
|
318
377
|
the area does not scroll and reserves no second gutter beside the
|
|
319
378
|
document's. From md, `main` bounds its height and it scrolls. */
|
|
320
|
-
.cloud-app-canvas:not([data-layout-full-page]) .layout-content-main > .k2b-scroll-area { scrollbar-gutter: auto; }
|
|
379
|
+
.cloud-app-canvas:not([data-layout-full-page], [data-layout-authenticated]) .layout-content-main > .k2b-scroll-area { scrollbar-gutter: auto; }
|
|
321
380
|
.cloud-app-canvas > .layout-shell-content { gap: 0; }
|
|
322
|
-
.cloud-app-canvas .layout-header {
|
|
381
|
+
.cloud-app-canvas:not([data-layout-authenticated]) .layout-header {
|
|
323
382
|
border-radius: 0; border: 0; border-bottom: 1px solid var(--ui-border);
|
|
324
383
|
box-shadow: none !important;
|
|
325
384
|
}
|
|
@@ -329,6 +388,174 @@ solid-island {
|
|
|
329
388
|
--k2b-toast-offset-top: 2.875rem;
|
|
330
389
|
}
|
|
331
390
|
|
|
391
|
+
/* Signed-in phones: the app gradient is the page. The title row sits on it
|
|
392
|
+
without a line, and the content is one soft card with 28 px top corners
|
|
393
|
+
that scrolls itself, so its rounded edge stays while it scrolls. The bar
|
|
394
|
+
with the person's apps floats over the card's end; the card keeps that
|
|
395
|
+
space free at its end and in its scroll padding, so the bar never covers
|
|
396
|
+
the last row or a focused control. The window never scrolls. */
|
|
397
|
+
.cloud-app-canvas[data-layout-authenticated] {
|
|
398
|
+
/* Text sits on the gradient here, so its tint stays at most 30 % light
|
|
399
|
+
and 15 % dark: then the title and controls read at 4.5:1 on any app
|
|
400
|
+
color. Built-in apps declare less. */
|
|
401
|
+
--cloud-canvas-strength: min(var(--app-canvas-strength, 0%), 30%);
|
|
402
|
+
--cloud-canvas-dark-strength: min(var(--app-canvas-dark-strength, 0%), 15%);
|
|
403
|
+
height: 100dvh;
|
|
404
|
+
overflow: hidden;
|
|
405
|
+
padding-bottom: 0;
|
|
406
|
+
}
|
|
407
|
+
.cloud-app-canvas[data-layout-authenticated] .layout-header {
|
|
408
|
+
border: 0;
|
|
409
|
+
border-radius: 0;
|
|
410
|
+
background: transparent;
|
|
411
|
+
box-shadow: none !important;
|
|
412
|
+
}
|
|
413
|
+
.cloud-app-canvas[data-layout-authenticated] .layout-header .font-semibold {
|
|
414
|
+
font-size: 1.125rem;
|
|
415
|
+
}
|
|
416
|
+
/* Content wider than the card scrolls sideways in it, as from md; the
|
|
417
|
+
rounded corners still clip. */
|
|
418
|
+
.cloud-app-canvas[data-layout-authenticated] .layout-content-main {
|
|
419
|
+
overflow: auto;
|
|
420
|
+
border-top: 1px solid transparent;
|
|
421
|
+
border-radius: 1.75rem 1.75rem 0 0;
|
|
422
|
+
background: var(--k2b-surface);
|
|
423
|
+
box-shadow: 0 -10px 30px -24px rgb(15 23 19 / 0.3);
|
|
424
|
+
}
|
|
425
|
+
/* Dark: a faint top edge keeps the card apart from the dark gradient. */
|
|
426
|
+
.dark .cloud-app-canvas[data-layout-authenticated] .layout-content-main {
|
|
427
|
+
border-top-color: var(--k2b-border);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/* The bar and the room it takes switch with `md`, as the header and the rail
|
|
432
|
+
do, so Home stays reachable also where a larger default font size moves
|
|
433
|
+
that switch above 768 px. */
|
|
434
|
+
.cloud-app-canvas[data-layout-authenticated] {
|
|
435
|
+
--cloud-tab-bar-height: 3.875rem;
|
|
436
|
+
--cloud-tab-bar-end: calc(env(safe-area-inset-bottom, 0px) + 0.5rem);
|
|
437
|
+
--cloud-tab-bar-space: calc(var(--cloud-tab-bar-end) + var(--cloud-tab-bar-height) + 0.75rem);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* A page whose app has its own navigation (a mailbox, a Space, a book) makes
|
|
441
|
+
its title the menu "Name ⌄" on phones. It opens the same app menu as the
|
|
442
|
+
menu button beside it. The navigation's server-rendered snapshot decides,
|
|
443
|
+
so the first frame already shows the right title. */
|
|
444
|
+
.layout-header-title-menu {
|
|
445
|
+
display: none;
|
|
446
|
+
min-width: 0;
|
|
447
|
+
min-height: 2rem;
|
|
448
|
+
align-items: center;
|
|
449
|
+
gap: 0.25rem;
|
|
450
|
+
margin-inline-start: -0.5rem;
|
|
451
|
+
padding: 0 0.5rem;
|
|
452
|
+
border-radius: var(--k2b-radius-control);
|
|
453
|
+
color: inherit;
|
|
454
|
+
background: transparent;
|
|
455
|
+
cursor: pointer;
|
|
456
|
+
}
|
|
457
|
+
.layout-header-title-menu:hover {
|
|
458
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
459
|
+
}
|
|
460
|
+
.layout-header-title-menu:focus-visible {
|
|
461
|
+
outline: var(--k2b-focus-width) solid var(--k2b-focus-ring);
|
|
462
|
+
outline-offset: 1px;
|
|
463
|
+
}
|
|
464
|
+
.layout-header-title-menu > i {
|
|
465
|
+
flex: none;
|
|
466
|
+
font-size: 1rem;
|
|
467
|
+
opacity: 0.7;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
@media not all and (min-width: 48rem) {
|
|
471
|
+
:root:has(script[data-cloud-workspace-navigation]) .layout-header-title {
|
|
472
|
+
display: none;
|
|
473
|
+
}
|
|
474
|
+
:root:has(script[data-cloud-workspace-navigation]) .layout-header-title-menu {
|
|
475
|
+
display: inline-flex;
|
|
476
|
+
}
|
|
477
|
+
.cloud-app-canvas[data-layout-authenticated] .layout-content-main {
|
|
478
|
+
padding-bottom: var(--cloud-tab-bar-space);
|
|
479
|
+
scroll-padding-bottom: var(--cloud-tab-bar-space);
|
|
480
|
+
}
|
|
481
|
+
.cloud-app-canvas[data-layout-authenticated] > .cloud-tab-bar {
|
|
482
|
+
position: fixed;
|
|
483
|
+
right: 0;
|
|
484
|
+
bottom: 0;
|
|
485
|
+
left: 0;
|
|
486
|
+
z-index: 10;
|
|
487
|
+
display: flex;
|
|
488
|
+
justify-content: center;
|
|
489
|
+
align-items: flex-end;
|
|
490
|
+
height: var(--cloud-tab-bar-space);
|
|
491
|
+
padding: 0 calc(env(safe-area-inset-right, 0px) + 0.75rem) var(--cloud-tab-bar-end) calc(env(safe-area-inset-left, 0px) + 0.75rem);
|
|
492
|
+
/* Content that scrolls past fades flat into the card above the bar and is
|
|
493
|
+
gone where the bar begins: no glass, and no text beside or under it. */
|
|
494
|
+
background: linear-gradient(to bottom, color-mix(in srgb, var(--k2b-surface) 0%, transparent), var(--k2b-surface) 0.75rem);
|
|
495
|
+
pointer-events: none;
|
|
496
|
+
}
|
|
497
|
+
/* The app's one primary action (the primary of `AppWorkspace.Head`) is the
|
|
498
|
+
round button in that free place beside the bar: the bar's height, its end
|
|
499
|
+
edge, and its shadow. The card keeps the bar's space free at its end and in
|
|
500
|
+
its scroll padding, so the button never covers the last row or a focused
|
|
501
|
+
control either. Only the outermost workspace's head offers it. */
|
|
502
|
+
.cloud-app-canvas[data-layout-authenticated]:has(> .cloud-tab-bar)
|
|
503
|
+
.k2b-app-workspace:not(.k2b-app-workspace *)
|
|
504
|
+
> .k2b-app-workspace__head
|
|
505
|
+
.k2b-app-workspace__head-primary {
|
|
506
|
+
position: fixed;
|
|
507
|
+
z-index: 11;
|
|
508
|
+
right: max(calc(env(safe-area-inset-right, 0px) + 0.75rem), calc((100vw - 33.75rem) / 2));
|
|
509
|
+
bottom: var(--cloud-tab-bar-end);
|
|
510
|
+
width: var(--cloud-tab-bar-height);
|
|
511
|
+
min-width: var(--cloud-tab-bar-height);
|
|
512
|
+
height: var(--cloud-tab-bar-height);
|
|
513
|
+
min-height: var(--cloud-tab-bar-height);
|
|
514
|
+
box-shadow:
|
|
515
|
+
0 10px 28px -14px rgb(9 9 11 / 0.34),
|
|
516
|
+
0 0 0 1px rgb(9 9 11 / 0.06);
|
|
517
|
+
}
|
|
518
|
+
.dark .cloud-app-canvas[data-layout-authenticated]:has(> .cloud-tab-bar)
|
|
519
|
+
.k2b-app-workspace:not(.k2b-app-workspace *)
|
|
520
|
+
> .k2b-app-workspace__head
|
|
521
|
+
.k2b-app-workspace__head-primary {
|
|
522
|
+
box-shadow:
|
|
523
|
+
0 12px 30px -14px rgb(0 0 0 / 0.7),
|
|
524
|
+
0 0 0 1px var(--k2b-border);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/* The bar exists only on signed-in phones. Its row keeps the place of the
|
|
529
|
+
app's primary action free at its end. */
|
|
530
|
+
.cloud-tab-bar {
|
|
531
|
+
display: none;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.cloud-tab-bar__row {
|
|
535
|
+
display: flex;
|
|
536
|
+
width: 100%;
|
|
537
|
+
max-width: 33.75rem;
|
|
538
|
+
padding-inline-end: calc(var(--cloud-tab-bar-height) + 0.625rem);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/* The shell's live bar replaces the server's once the bar's content changes
|
|
542
|
+
in the browser. */
|
|
543
|
+
.cloud-tab-bar__row:has(.cloud-tab-bar__live) > .k2b-tab-bar {
|
|
544
|
+
display: none;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.cloud-tab-bar__row > div:has(> .cloud-tab-bar__live) {
|
|
548
|
+
display: contents;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.cloud-tab-bar .k2b-tab-bar {
|
|
552
|
+
flex: 1;
|
|
553
|
+
min-width: 0;
|
|
554
|
+
pointer-events: auto;
|
|
555
|
+
--k2b-tab-bar-background: var(--cloud-shell-gradient);
|
|
556
|
+
--k2b-tab-bar-color: var(--k2b-text);
|
|
557
|
+
--k2b-tab-bar-selected-background: var(--cloud-shell-selected);
|
|
558
|
+
--k2b-tab-bar-selected-color: var(--cloud-shell-selected-text);
|
|
332
559
|
}
|
|
333
560
|
|
|
334
561
|
/* Card: the outermost workspace is the app card, so it gets the card's radius
|
|
@@ -337,9 +564,7 @@ solid-island {
|
|
|
337
564
|
child fills `main` and scrolls inside itself, so `main` neither scrolls nor
|
|
338
565
|
clips: it keeps no scrollbar gutter beside the card, the card keeps the
|
|
339
566
|
shell spacing on every side, and its frame shadow shows in that spacing. A
|
|
340
|
-
workspace nested in other page content leaves `main` the page scroller.
|
|
341
|
-
signed-in people, the flush range below removes the frame again; it comes
|
|
342
|
-
later at equal specificity. */
|
|
567
|
+
workspace nested in other page content leaves `main` the page scroller. */
|
|
343
568
|
@media (min-width: 768px) {
|
|
344
569
|
.cloud-app-canvas .layout-content-main:has(> .k2b-app-workspace, > :is(solid-island, solid-client) > .k2b-app-workspace) {
|
|
345
570
|
overflow: visible;
|
|
@@ -354,42 +579,60 @@ solid-island {
|
|
|
354
579
|
}
|
|
355
580
|
}
|
|
356
581
|
|
|
357
|
-
/*
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
own surfaces fill the insets, and their content stays inside them. */
|
|
582
|
+
/* Tablet (I5): the rail sits in a rounded container filled with the app
|
|
583
|
+
color, and the app is a rounded card beside it, both 20 px round with 8 px
|
|
584
|
+
of neutral canvas on every side. The installed app's safe areas, such as
|
|
585
|
+
the status bar and the home indicator, add to that spacing, so nothing sits
|
|
586
|
+
under them. The outermost workspace is the card, as from 1024 px; a page
|
|
587
|
+
without a workspace shows its content on the canvas. On color the open app
|
|
588
|
+
is the surface color, and no separator divides the rail. */
|
|
365
589
|
@media (min-width: 768px) {
|
|
366
590
|
@media not all and (min-width: 1024px) {
|
|
367
591
|
.cloud-app-canvas[data-layout-authenticated] {
|
|
368
|
-
padding: 0
|
|
592
|
+
padding: calc(env(safe-area-inset-top, 0px) + 0.5rem) calc(env(safe-area-inset-right, 0px) + 0.5rem)
|
|
593
|
+
calc(env(safe-area-inset-bottom, 0px) + 0.5rem) calc(env(safe-area-inset-left, 0px) + 0.5rem);
|
|
594
|
+
background: var(--ui-canvas);
|
|
369
595
|
}
|
|
370
596
|
.cloud-app-canvas[data-layout-authenticated] > .layout-rail {
|
|
371
|
-
|
|
372
|
-
|
|
597
|
+
width: 3.75rem;
|
|
598
|
+
margin-inline-end: 0.5rem;
|
|
599
|
+
padding: 0 0 0.5rem;
|
|
600
|
+
border-radius: 1.25rem;
|
|
601
|
+
background-image: var(--cloud-shell-gradient) !important;
|
|
373
602
|
}
|
|
374
|
-
.cloud-app-canvas[data-layout-authenticated] > .layout-
|
|
375
|
-
|
|
376
|
-
padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) 0 0;
|
|
377
|
-
background: var(--k2b-surface);
|
|
603
|
+
.dark .cloud-app-canvas[data-layout-authenticated] > .layout-rail {
|
|
604
|
+
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--app-accent, var(--k2b-border)) 22%, var(--k2b-border));
|
|
378
605
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
.cloud-app-canvas[data-layout-authenticated] .layout-content-main:not(:has(.k2b-app-workspace)) {
|
|
382
|
-
padding-bottom: env(safe-area-inset-bottom, 0px);
|
|
606
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail .rail-item {
|
|
607
|
+
color: var(--k2b-text-secondary);
|
|
383
608
|
}
|
|
384
|
-
.cloud-app-canvas[data-layout-authenticated] .layout-
|
|
385
|
-
--k2b-
|
|
386
|
-
--k2b-workspace-inset-bottom: env(safe-area-inset-bottom, 0px);
|
|
387
|
-
border: 0;
|
|
388
|
-
box-shadow: none;
|
|
609
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail .rail-item:hover {
|
|
610
|
+
background: color-mix(in srgb, var(--k2b-surface) 45%, transparent);
|
|
389
611
|
}
|
|
390
|
-
.cloud-app-canvas[data-layout-authenticated] > .layout-
|
|
391
|
-
|
|
392
|
-
|
|
612
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail .rail-item-active {
|
|
613
|
+
box-shadow: 0 1px 2px rgb(9 9 11 / 0.06);
|
|
614
|
+
}
|
|
615
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail .rail-item-active,
|
|
616
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail .rail-item-active:hover {
|
|
617
|
+
border-color: transparent;
|
|
618
|
+
background: var(--cloud-shell-selected);
|
|
619
|
+
color: var(--cloud-shell-selected-text);
|
|
620
|
+
}
|
|
621
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail [role="separator"] {
|
|
622
|
+
display: none;
|
|
623
|
+
}
|
|
624
|
+
/* The apps scroll in their own area; room above and below the first and
|
|
625
|
+
last app keeps a focus ring whole, also WebKit's wider one, without
|
|
626
|
+
moving an app. */
|
|
627
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail [data-cloud-rail-apps] {
|
|
628
|
+
margin-block: -0.375rem;
|
|
629
|
+
padding-block: 0.375rem;
|
|
630
|
+
}
|
|
631
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-shell-content {
|
|
632
|
+
gap: 0.5rem;
|
|
633
|
+
}
|
|
634
|
+
.cloud-app-canvas[data-layout-authenticated] .layout-content-main .k2b-app-workspace:not(.k2b-app-workspace *) {
|
|
635
|
+
--k2b-workspace-radius: 1.25rem;
|
|
393
636
|
}
|
|
394
637
|
}
|
|
395
638
|
}
|
|
@@ -401,7 +644,7 @@ solid-island {
|
|
|
401
644
|
rail starts at the window's left edge and moves down with the card. In the
|
|
402
645
|
installed app the card and the rail stay below the status bar; the card keeps
|
|
403
646
|
its spacing at the bottom, and its surfaces keep their content above the
|
|
404
|
-
home indicator
|
|
647
|
+
home indicator. */
|
|
405
648
|
@media (min-width: 1024px) {
|
|
406
649
|
.cloud-app-canvas[data-layout-authenticated] {
|
|
407
650
|
--cloud-card-inset: round(clamp(0.25rem, calc(0.25rem + (100vw - 64rem) / 104), 0.5rem), 1px);
|
|
@@ -429,11 +672,12 @@ solid-island {
|
|
|
429
672
|
(Cmd/Ctrl+\ or the sidebar buttons). The canvas carries the state from the
|
|
430
673
|
`cloud_shell_focus` cookie, so the server renders the same first frame.
|
|
431
674
|
Phones ignore it. The app area takes the app bar's place and starts at the
|
|
432
|
-
card spacing
|
|
675
|
+
card spacing. The button that
|
|
433
676
|
shows them again floats at the app area's bottom start corner; on touch
|
|
434
|
-
screens a drag from the 18 px strip at the left edge does the same.
|
|
435
|
-
768 to 1023 px the
|
|
436
|
-
|
|
677
|
+
screens a drag from the 18 px strip at the left edge does the same. In an
|
|
678
|
+
app host below 64 rem (a window from 768 to 1023 px, or the app beside the
|
|
679
|
+
panel column) the navigation is already an overlay behind the workspace
|
|
680
|
+
head's button, so there only the app bar hides. */
|
|
437
681
|
.cloud-shell-show,
|
|
438
682
|
.cloud-shell-reveal {
|
|
439
683
|
display: none;
|
|
@@ -470,8 +714,9 @@ solid-island {
|
|
|
470
714
|
|
|
471
715
|
@media (min-width: 768px) {
|
|
472
716
|
@media not all and (min-width: 1024px) {
|
|
473
|
-
.cloud-app-canvas[data-layout-authenticated][data-shell-focus]
|
|
474
|
-
|
|
717
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] .cloud-shell-show {
|
|
718
|
+
left: calc(env(safe-area-inset-left, 0px) + 1.25rem);
|
|
719
|
+
bottom: calc(env(safe-area-inset-bottom, 0px) + 1.25rem);
|
|
475
720
|
}
|
|
476
721
|
}
|
|
477
722
|
}
|
|
@@ -484,12 +729,18 @@ solid-island {
|
|
|
484
729
|
left: calc(max(var(--cloud-card-inset), env(safe-area-inset-left, 0px)) + 0.75rem);
|
|
485
730
|
bottom: calc(var(--cloud-card-inset) + var(--cloud-card-inset-bottom) + 0.75rem);
|
|
486
731
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/* The navigation leaves like a hidden sidebar: its track, its resize handle,
|
|
735
|
+
and navigation panes go, and the work area rounds its start corners with
|
|
736
|
+
the card. An island may wrap the sidebar or Main, as in Grids. This follows
|
|
737
|
+
the app's host, as the sidebar column does: in a host below 64 rem, such as
|
|
738
|
+
the app beside the panel column, the navigation is an overlay behind the
|
|
739
|
+
workspace head's button and stays there. */
|
|
740
|
+
@container k2b-app-area (min-width: 64rem) {
|
|
491
741
|
.cloud-app-canvas[data-shell-focus] .k2b-app-workspace:not(.k2b-app-workspace *) {
|
|
492
742
|
--k2b-workspace-start-radius: var(--k2b-workspace-inner-radius);
|
|
743
|
+
--k2b-workspace-sidebar-space: 0px;
|
|
493
744
|
}
|
|
494
745
|
.cloud-app-canvas[data-shell-focus]
|
|
495
746
|
.k2b-app-workspace:not(.k2b-app-workspace *)
|
|
@@ -535,7 +786,7 @@ solid-island {
|
|
|
535
786
|
.cloud-mobile-menu .k2b-panel-dialog__actions { flex: 1; min-width: 0; }
|
|
536
787
|
.cloud-mobile-menu__switch { width: 100%; flex-wrap: nowrap; }
|
|
537
788
|
.cloud-mobile-menu__switch button { flex: 1; min-width: 0; min-height: 3rem; white-space: nowrap; }
|
|
538
|
-
.cloud-mobile-menu__switch button > span {
|
|
789
|
+
.cloud-mobile-menu__switch button > span { min-width: 0; overflow: hidden; }
|
|
539
790
|
.cloud-mobile-menu .k2b-dialog__close { width: 2.75rem; height: 2.75rem; flex-shrink: 0; }
|
|
540
791
|
|
|
541
792
|
.cloud-mobile-menu .k2b-panel-dialog__body { padding: .75rem 1rem 1rem; }
|