@k2b/cloud 0.35.0 → 0.37.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 +3 -3
- package/scripts/README.md +1 -0
- package/scripts/cli-pack.ts +123 -0
- package/src/_internal/shell-focus.ts +11 -0
- package/src/access/GroupCoverage.tsx +2 -1
- package/src/access/PermissionEditor.browser-harness.tsx +46 -0
- package/src/access/PermissionEditor.tsx +93 -35
- package/src/access/PrincipalPicker.tsx +2 -0
- package/src/access/messages.ts +2 -0
- package/src/access/ui.ts +1 -0
- package/src/ai/chat/answer-links.ts +8 -0
- package/src/ai/chat/messages.ts +2 -0
- package/src/ai/chat/primitives.tsx +2 -1
- package/src/ai/executor.ts +46 -3
- package/src/ai/types.ts +1 -0
- package/src/browser/reload.ts +32 -1
- package/src/browser/shell-focus.ts +67 -0
- package/src/cli/commands.ts +2 -0
- package/src/cli/plugin.ts +5 -5
- package/src/services/index.ts +9 -0
- package/src/services/network-security.ts +48 -4
- package/src/shared/network-address.ts +80 -0
- package/src/ssr/CloudShell.island.tsx +2 -0
- package/src/ssr/GlobalSearchTrigger.tsx +1 -1
- package/src/ssr/Layout.tsx +8 -0
- package/src/ssr/LayoutHelpTrigger.tsx +1 -1
- package/src/ssr/LayoutRail.tsx +1 -1
- package/src/ssr/ProfilePreferences.tsx +1 -1
- package/src/ssr/RailApps.tsx +1 -1
- package/src/ssr/ShellFocusToggle.tsx +43 -0
- package/src/ssr/ShellRuntime.island.tsx +36 -1
- package/src/ssr/app-launchpad.tsx +1 -1
- package/src/ssr/platform-messages.ts +10 -0
- package/src/ssr/shell-focus.browser-harness.tsx +83 -0
- package/src/styles/global.css +155 -26
- package/src/styles/utilities-navigation.css +11 -3
|
@@ -6,13 +6,14 @@ import {
|
|
|
6
6
|
serializeAppWorkspaceLayoutState,
|
|
7
7
|
useLocale,
|
|
8
8
|
} from "@k2b/ui";
|
|
9
|
-
import { createEffect, onCleanup, onMount } from "solid-js";
|
|
9
|
+
import { createEffect, createSignal, onCleanup, onMount } from "solid-js";
|
|
10
10
|
import { appWorkspaceCookieName, readAppWorkspaceLayoutCookie } from "../_internal/app-workspace-state";
|
|
11
11
|
import { registerContextAwareCommand } from "../browser/command-bridge";
|
|
12
12
|
import { attachCommandShortcuts } from "../browser/command-shortcuts";
|
|
13
13
|
import { navigationSearchItems } from "../browser/navigation-search";
|
|
14
14
|
import { importOnDemand } from "../browser/reload";
|
|
15
15
|
import { registerGlobalSearchHost } from "../browser/search-bridge";
|
|
16
|
+
import { attachShellFocusControls, readShellFocus, SHELL_FOCUS_CHANGE_EVENT, toggleShellFocus } from "../browser/shell-focus";
|
|
16
17
|
import {
|
|
17
18
|
ANNOUNCEMENTS_COOKIE,
|
|
18
19
|
ANNOUNCEMENTS_COOKIE_MAX_AGE_SECONDS,
|
|
@@ -37,6 +38,8 @@ export type ShellRuntimeProps = {
|
|
|
37
38
|
help?: { documents: readonly HelpDocumentManifest[]; pageBase: string };
|
|
38
39
|
/** Layout pages outside focus mode: the search host, Cmd/Ctrl+K, the Help command (Shift+/) and command shortcuts. */
|
|
39
40
|
commands?: { searchResources: boolean };
|
|
41
|
+
/** Signed-in Layout pages: the sidebar buttons, Cmd/Ctrl+\ and the left-edge drag hide and show the app bar and the app's navigation. */
|
|
42
|
+
focus?: boolean;
|
|
40
43
|
/** Signed-in pages: refresh this browser's push endpoint. */
|
|
41
44
|
push?: boolean;
|
|
42
45
|
/** Announcements the person has not seen yet; a dialog shows them once. */
|
|
@@ -95,6 +98,38 @@ export default function ShellRuntime(props: ShellRuntimeProps) {
|
|
|
95
98
|
});
|
|
96
99
|
});
|
|
97
100
|
}
|
|
101
|
+
if (props.focus) {
|
|
102
|
+
const [hidden, setHidden] = createSignal(false);
|
|
103
|
+
const [available, setAvailable] = createSignal(false);
|
|
104
|
+
onMount(() => {
|
|
105
|
+
setHidden(readShellFocus());
|
|
106
|
+
const media = window.matchMedia("(min-width: 768px)");
|
|
107
|
+
const resize = () => setAvailable(media.matches);
|
|
108
|
+
const change = (event: Event) => setHidden((event as CustomEvent<{ hidden: boolean }>).detail.hidden);
|
|
109
|
+
const dispose = attachShellFocusControls();
|
|
110
|
+
resize();
|
|
111
|
+
media.addEventListener("change", resize);
|
|
112
|
+
window.addEventListener(SHELL_FOCUS_CHANGE_EVENT, change);
|
|
113
|
+
onCleanup(() => {
|
|
114
|
+
dispose();
|
|
115
|
+
media.removeEventListener("change", resize);
|
|
116
|
+
window.removeEventListener(SHELL_FOCUS_CHANGE_EVENT, change);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
createEffect(() => {
|
|
120
|
+
if (!available()) return;
|
|
121
|
+
onCleanup(
|
|
122
|
+
registerContextAwareCommand({
|
|
123
|
+
id: "cloud.shell.focus",
|
|
124
|
+
title: hidden() ? t().showSidebar : t().hideSidebar,
|
|
125
|
+
description: t().sidebarCommandDescription,
|
|
126
|
+
icon: hidden() ? "ti ti-layout-sidebar-left-expand" : "ti ti-layout-sidebar-left-collapse",
|
|
127
|
+
shortcut: "mod+\\",
|
|
128
|
+
action: toggleShellFocus,
|
|
129
|
+
}),
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
98
133
|
if (props.commands) {
|
|
99
134
|
const host = createGlobalSearchHost(searchItems, props.commands.searchResources);
|
|
100
135
|
onMount(() => onCleanup(registerGlobalSearchHost(host.open, host.dispose)));
|
|
@@ -93,7 +93,7 @@ export function AppLaunchpadButton(props: AppLaunchpadContext & { variant: "rail
|
|
|
93
93
|
onClick={open}
|
|
94
94
|
aria-busy={action.busy() ? "true" : undefined}
|
|
95
95
|
>
|
|
96
|
-
<i class={`${action.busy() ? "ti ti-loader-2 animate-spin" : "ti ti-grid-dots"} text-
|
|
96
|
+
<i class={`${action.busy() ? "ti ti-loader-2 animate-spin" : "ti ti-grid-dots"} text-xl`} aria-hidden="true" />
|
|
97
97
|
</Tooltip.Trigger>
|
|
98
98
|
);
|
|
99
99
|
}
|
|
@@ -65,6 +65,11 @@ export const platformMessages = i18n.define({
|
|
|
65
65
|
pageUpDescription: "Go to the page above this one, as you left it in this tab.",
|
|
66
66
|
openHelp: "Open help",
|
|
67
67
|
helpShortcut: "Help (Shift+/)",
|
|
68
|
+
hideSidebar: "Hide sidebar",
|
|
69
|
+
showSidebar: "Show sidebar",
|
|
70
|
+
hideSidebarShortcut: "Hide sidebar (⌘/Ctrl+\\)",
|
|
71
|
+
showSidebarShortcut: "Show sidebar (⌘/Ctrl+\\)",
|
|
72
|
+
sidebarCommandDescription: "Hide or show the app bar and the app's navigation.",
|
|
68
73
|
signIn: "Sign in",
|
|
69
74
|
menu: "Menu",
|
|
70
75
|
search: "Search",
|
|
@@ -132,6 +137,11 @@ export const platformMessages = i18n.define({
|
|
|
132
137
|
pageUpDescription: "Zur Seite darüber, so wie du sie in diesem Tab verlassen hast.",
|
|
133
138
|
openHelp: "Hilfe öffnen",
|
|
134
139
|
helpShortcut: "Hilfe (Umschalt+/)",
|
|
140
|
+
hideSidebar: "Seitenleiste ausblenden",
|
|
141
|
+
showSidebar: "Seitenleiste zeigen",
|
|
142
|
+
hideSidebarShortcut: "Seitenleiste ausblenden (⌘/Strg+\\)",
|
|
143
|
+
showSidebarShortcut: "Seitenleiste zeigen (⌘/Strg+\\)",
|
|
144
|
+
sidebarCommandDescription: "App-Leiste und Navigation der App aus- oder einblenden.",
|
|
135
145
|
signIn: "Anmelden",
|
|
136
146
|
menu: "Menü",
|
|
137
147
|
search: "Suchen",
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { AppWorkspace } from "@k2b/ui";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { Dynamic } from "solid-js/web";
|
|
4
|
+
import { defineApp } from "../_internal/define-app";
|
|
5
|
+
import { person } from "../_internal/define-app.test-fixture";
|
|
6
|
+
import type { User } from "../contracts/shared";
|
|
7
|
+
import Layout from "./Layout";
|
|
8
|
+
import type { RuntimeContext } from "./runtime";
|
|
9
|
+
|
|
10
|
+
const probe = defineApp({
|
|
11
|
+
id: "shell-focus-probe",
|
|
12
|
+
name: "Focus probe",
|
|
13
|
+
icon: "ti ti-layout",
|
|
14
|
+
description: "Shell focus browser fixture",
|
|
15
|
+
baseUrl: "http://shell-focus-probe:3000",
|
|
16
|
+
routes: ["/app/focus"],
|
|
17
|
+
});
|
|
18
|
+
type Environment = { Variables: { runtime: RuntimeContext; user: User } };
|
|
19
|
+
export const server = new Hono<Environment>()
|
|
20
|
+
.use(async (c, next) => {
|
|
21
|
+
c.set("runtime", {
|
|
22
|
+
apps: [
|
|
23
|
+
{
|
|
24
|
+
id: "shell-focus-probe",
|
|
25
|
+
name: "Focus probe",
|
|
26
|
+
description: "Shell focus browser fixture",
|
|
27
|
+
icon: "ti ti-layout",
|
|
28
|
+
routes: ["/app/focus"],
|
|
29
|
+
nav: { href: "/app/focus", section: "primary" },
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
c.set("user", person);
|
|
34
|
+
await next();
|
|
35
|
+
})
|
|
36
|
+
.get(
|
|
37
|
+
"/app/focus",
|
|
38
|
+
...probe.ssr<Environment>((c) => () => (
|
|
39
|
+
<Layout c={c} fullWidth fullPage title={[{ title: "Focus probe", href: "/app/focus" }, { title: "Workspace" }]}>
|
|
40
|
+
<AppWorkspace mobileSurface="flush" class="min-h-0 flex-1">
|
|
41
|
+
<AppWorkspace.Sidebar id="focus-navigation" label="Navigation">
|
|
42
|
+
<AppWorkspace.SidebarDesktop>
|
|
43
|
+
<AppWorkspace.SidebarItem href="/app/focus" active>
|
|
44
|
+
Workspace
|
|
45
|
+
</AppWorkspace.SidebarItem>
|
|
46
|
+
</AppWorkspace.SidebarDesktop>
|
|
47
|
+
</AppWorkspace.Sidebar>
|
|
48
|
+
<AppWorkspace.Content>
|
|
49
|
+
<AppWorkspace.Main>
|
|
50
|
+
<textarea aria-label="Editor" />
|
|
51
|
+
</AppWorkspace.Main>
|
|
52
|
+
</AppWorkspace.Content>
|
|
53
|
+
</AppWorkspace>
|
|
54
|
+
</Layout>
|
|
55
|
+
)),
|
|
56
|
+
)
|
|
57
|
+
// Grids wraps Main in an island inside Content and gives it a navigation pane.
|
|
58
|
+
.get(
|
|
59
|
+
"/app/focus/panes",
|
|
60
|
+
...probe.ssr<Environment>((c) => () => (
|
|
61
|
+
<Layout c={c} fullWidth fullPage title={[{ title: "Focus probe", href: "/app/focus" }, { title: "Pages" }]}>
|
|
62
|
+
<AppWorkspace mobileSurface="flush" class="min-h-0 flex-1">
|
|
63
|
+
<AppWorkspace.Sidebar id="focus-navigation" label="Navigation">
|
|
64
|
+
<AppWorkspace.SidebarDesktop>
|
|
65
|
+
<AppWorkspace.SidebarItem href="/app/focus/panes" active>
|
|
66
|
+
Pages
|
|
67
|
+
</AppWorkspace.SidebarItem>
|
|
68
|
+
</AppWorkspace.SidebarDesktop>
|
|
69
|
+
</AppWorkspace.Sidebar>
|
|
70
|
+
<AppWorkspace.Content>
|
|
71
|
+
<Dynamic component="solid-island">
|
|
72
|
+
<AppWorkspace.Main mobilePane="main" scroll={false}>
|
|
73
|
+
<AppWorkspace.MainPane id="focus-pages" label="Pages" surface="navigation" defaultSize={280}>
|
|
74
|
+
Page list
|
|
75
|
+
</AppWorkspace.MainPane>
|
|
76
|
+
<div>Page</div>
|
|
77
|
+
</AppWorkspace.Main>
|
|
78
|
+
</Dynamic>
|
|
79
|
+
</AppWorkspace.Content>
|
|
80
|
+
</AppWorkspace>
|
|
81
|
+
</Layout>
|
|
82
|
+
)),
|
|
83
|
+
);
|
package/src/styles/global.css
CHANGED
|
@@ -79,8 +79,8 @@ html:has(.cloud-app-canvas[data-layout-full-page="true"]) {
|
|
|
79
79
|
/* The authenticated rail is part of the canvas. Keeping it transparent also
|
|
80
80
|
covers shell-only routes such as 404 pages that have no app workspace. */
|
|
81
81
|
.cloud-app-canvas > .layout-rail {
|
|
82
|
-
width: calc(
|
|
83
|
-
|
|
82
|
+
width: calc(3.5rem + env(safe-area-inset-left, 0px));
|
|
83
|
+
padding-left: env(safe-area-inset-left, 0px);
|
|
84
84
|
background-color: transparent !important;
|
|
85
85
|
background-image: none !important;
|
|
86
86
|
}
|
|
@@ -294,11 +294,13 @@ solid-island {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
/* Cloud has three shell modes. Phones, below md, get the header and no rail.
|
|
297
|
-
From md, signed-in people get the rail instead of the header: up to
|
|
298
|
-
app area meets the window's top, right and bottom edges, and
|
|
299
|
-
a card
|
|
300
|
-
from md.
|
|
301
|
-
|
|
297
|
+
From md, signed-in people get the 56 px rail instead of the header: up to
|
|
298
|
+
1023 px the app area meets the window's top, right and bottom edges, and
|
|
299
|
+
from 1024 px it is a card beside the rail. Anonymous pages keep the header
|
|
300
|
+
and the card from md. Each query is the exact opposite of the next one, so
|
|
301
|
+
every width, also a fractional one under browser zoom, falls into exactly
|
|
302
|
+
one mode. */
|
|
303
|
+
@media not all and (min-width: 768px) {
|
|
302
304
|
.cloud-app-canvas {
|
|
303
305
|
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);
|
|
304
306
|
}
|
|
@@ -360,35 +362,162 @@ solid-island {
|
|
|
360
362
|
The rail and the app area reach the window's edges also where the installed
|
|
361
363
|
app reports safe areas, such as the status bar and the home indicator. Their
|
|
362
364
|
own surfaces fill the insets, and their content stays inside them. */
|
|
363
|
-
@media (min-width: 768px)
|
|
365
|
+
@media (min-width: 768px) {
|
|
366
|
+
@media not all and (min-width: 1024px) {
|
|
367
|
+
.cloud-app-canvas[data-layout-authenticated] {
|
|
368
|
+
padding: 0;
|
|
369
|
+
}
|
|
370
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-rail {
|
|
371
|
+
padding-top: env(safe-area-inset-top, 0px);
|
|
372
|
+
padding-bottom: calc(var(--ui-space-shell) + env(safe-area-inset-bottom, 0px));
|
|
373
|
+
}
|
|
374
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-shell-content {
|
|
375
|
+
gap: 0;
|
|
376
|
+
padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) 0 0;
|
|
377
|
+
background: var(--k2b-surface);
|
|
378
|
+
}
|
|
379
|
+
/* A regular page scrolls `main`, so its end clears the home indicator. A
|
|
380
|
+
workspace reaches the bottom edge and clears it inside its own surfaces. */
|
|
381
|
+
.cloud-app-canvas[data-layout-authenticated] .layout-content-main:not(:has(.k2b-app-workspace)) {
|
|
382
|
+
padding-bottom: env(safe-area-inset-bottom, 0px);
|
|
383
|
+
}
|
|
384
|
+
.cloud-app-canvas[data-layout-authenticated] .layout-content-main .k2b-app-workspace:not(.k2b-app-workspace *) {
|
|
385
|
+
--k2b-workspace-radius: 0px;
|
|
386
|
+
--k2b-workspace-inset-bottom: env(safe-area-inset-bottom, 0px);
|
|
387
|
+
border: 0;
|
|
388
|
+
box-shadow: none;
|
|
389
|
+
}
|
|
390
|
+
.cloud-app-canvas[data-layout-authenticated] > .layout-shell-content > :not(.layout-content-main) .k2b-notice-card {
|
|
391
|
+
border: 0;
|
|
392
|
+
border-radius: 0;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/* Signed-in card: from 1024 px the app area is a card on the app canvas beside
|
|
398
|
+
the rail, as on laptops. Its spacing and radius grow with the window, from
|
|
399
|
+
4 to 8 px and from 10 to 14 px at 1440 px, the wide card from there on, in
|
|
400
|
+
whole pixels, so the card and its columns keep whole widths. The
|
|
401
|
+
rail starts at the window's left edge and moves down with the card. In the
|
|
402
|
+
installed app the card and the rail stay below the status bar; the card keeps
|
|
403
|
+
its spacing at the bottom, and its surfaces keep their content above the
|
|
404
|
+
home indicator, as in the flush range. */
|
|
405
|
+
@media (min-width: 1024px) {
|
|
364
406
|
.cloud-app-canvas[data-layout-authenticated] {
|
|
365
|
-
|
|
407
|
+
--cloud-card-inset: round(clamp(0.25rem, calc(0.25rem + (100vw - 64rem) / 104), 0.5rem), 1px);
|
|
408
|
+
--cloud-card-radius: round(clamp(0.625rem, calc(0.625rem + (100vw - 64rem) / 104), 0.875rem), 1px);
|
|
409
|
+
--cloud-card-inset-bottom: max(0px, env(safe-area-inset-bottom, 0px) - var(--cloud-card-inset));
|
|
410
|
+
padding: max(var(--cloud-card-inset), env(safe-area-inset-top, 0px)) max(var(--cloud-card-inset), env(safe-area-inset-right, 0px))
|
|
411
|
+
var(--cloud-card-inset) 0;
|
|
366
412
|
}
|
|
367
413
|
.cloud-app-canvas[data-layout-authenticated] > .layout-rail {
|
|
368
|
-
|
|
369
|
-
margin-inline-start: 0;
|
|
370
|
-
padding: env(safe-area-inset-top, 0px) 0 calc(var(--ui-space-shell) + env(safe-area-inset-bottom, 0px))
|
|
371
|
-
env(safe-area-inset-left, 0px);
|
|
414
|
+
padding-bottom: var(--cloud-card-inset-bottom);
|
|
372
415
|
}
|
|
373
416
|
.cloud-app-canvas[data-layout-authenticated] > .layout-shell-content {
|
|
374
|
-
gap:
|
|
375
|
-
padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) 0 0;
|
|
376
|
-
background: var(--k2b-surface);
|
|
417
|
+
gap: var(--cloud-card-inset);
|
|
377
418
|
}
|
|
378
|
-
/* A regular page scrolls `main`, so its end clears the home indicator. A
|
|
379
|
-
workspace reaches the bottom edge and clears it inside its own surfaces. */
|
|
380
419
|
.cloud-app-canvas[data-layout-authenticated] .layout-content-main:not(:has(.k2b-app-workspace)) {
|
|
381
|
-
padding-bottom:
|
|
420
|
+
padding-bottom: var(--cloud-card-inset-bottom);
|
|
382
421
|
}
|
|
383
422
|
.cloud-app-canvas[data-layout-authenticated] .layout-content-main .k2b-app-workspace:not(.k2b-app-workspace *) {
|
|
384
|
-
--k2b-workspace-radius:
|
|
385
|
-
--k2b-workspace-inset-bottom:
|
|
386
|
-
|
|
387
|
-
|
|
423
|
+
--k2b-workspace-radius: var(--cloud-card-radius);
|
|
424
|
+
--k2b-workspace-inset-bottom: var(--cloud-card-inset-bottom);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* Focus: the app bar and the outermost workspace's navigation hide together
|
|
429
|
+
(Cmd/Ctrl+\ or the sidebar buttons). The canvas carries the state from the
|
|
430
|
+
`cloud_shell_focus` cookie, so the server renders the same first frame.
|
|
431
|
+
Phones ignore it. The app area takes the app bar's place and starts at the
|
|
432
|
+
card spacing, or at the window's edge where it is flush. The button that
|
|
433
|
+
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. From
|
|
435
|
+
768 to 1023 px the navigation is already an overlay behind the
|
|
436
|
+
workspace head's button, so there only the app bar hides. */
|
|
437
|
+
.cloud-shell-show,
|
|
438
|
+
.cloud-shell-reveal {
|
|
439
|
+
display: none;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
@media (min-width: 768px) {
|
|
443
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] > .layout-rail {
|
|
444
|
+
display: none;
|
|
445
|
+
}
|
|
446
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] .cloud-shell-show {
|
|
447
|
+
position: absolute;
|
|
448
|
+
left: calc(env(safe-area-inset-left, 0px) + 0.75rem);
|
|
449
|
+
bottom: calc(env(safe-area-inset-bottom, 0px) + 0.75rem);
|
|
450
|
+
z-index: 15;
|
|
451
|
+
display: flex;
|
|
452
|
+
}
|
|
453
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] .cloud-shell-show .k2b-icon-button {
|
|
454
|
+
box-shadow: var(--k2b-shadow-float);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
@media (min-width: 768px) and (pointer: coarse) {
|
|
459
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] > .cloud-shell-reveal {
|
|
460
|
+
position: fixed;
|
|
461
|
+
top: 0;
|
|
462
|
+
bottom: 0;
|
|
463
|
+
left: 0;
|
|
464
|
+
z-index: 16;
|
|
465
|
+
display: block;
|
|
466
|
+
width: calc(1.125rem + env(safe-area-inset-left, 0px));
|
|
467
|
+
touch-action: pan-y;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
@media (min-width: 768px) {
|
|
472
|
+
@media not all and (min-width: 1024px) {
|
|
473
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] > .layout-shell-content {
|
|
474
|
+
padding-left: env(safe-area-inset-left, 0px);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
@media (min-width: 1024px) {
|
|
480
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] {
|
|
481
|
+
padding-left: max(var(--cloud-card-inset), env(safe-area-inset-left, 0px));
|
|
482
|
+
}
|
|
483
|
+
.cloud-app-canvas[data-layout-authenticated][data-shell-focus] .cloud-shell-show {
|
|
484
|
+
left: calc(max(var(--cloud-card-inset), env(safe-area-inset-left, 0px)) + 0.75rem);
|
|
485
|
+
bottom: calc(var(--cloud-card-inset) + var(--cloud-card-inset-bottom) + 0.75rem);
|
|
486
|
+
}
|
|
487
|
+
/* The navigation leaves like a hidden sidebar: its track, its resize
|
|
488
|
+
handle, and navigation panes go, and the work area rounds its start
|
|
489
|
+
corners with the card. An island may wrap the sidebar or Main, as in
|
|
490
|
+
Grids. */
|
|
491
|
+
.cloud-app-canvas[data-shell-focus] .k2b-app-workspace:not(.k2b-app-workspace *) {
|
|
492
|
+
--k2b-workspace-start-radius: var(--k2b-workspace-inner-radius);
|
|
388
493
|
}
|
|
389
|
-
.cloud-app-canvas[data-
|
|
390
|
-
|
|
391
|
-
|
|
494
|
+
.cloud-app-canvas[data-shell-focus]
|
|
495
|
+
.k2b-app-workspace:not(.k2b-app-workspace *)
|
|
496
|
+
> :is(.k2b-app-workspace__sidebar, .k2b-app-workspace__resize[data-app-workspace-resize="sidebar"]),
|
|
497
|
+
.cloud-app-canvas[data-shell-focus]
|
|
498
|
+
.k2b-app-workspace:not(.k2b-app-workspace *)
|
|
499
|
+
> :is(solid-island, solid-client)
|
|
500
|
+
> :is(.k2b-app-workspace__sidebar, .k2b-app-workspace__resize[data-app-workspace-resize="sidebar"]),
|
|
501
|
+
.cloud-app-canvas[data-shell-focus]
|
|
502
|
+
.k2b-app-workspace:not(.k2b-app-workspace *)
|
|
503
|
+
> .k2b-app-workspace__content
|
|
504
|
+
> .k2b-app-workspace__main
|
|
505
|
+
> :is(
|
|
506
|
+
.k2b-app-workspace__main-pane[data-surface="navigation"]:not(.is-primary),
|
|
507
|
+
.k2b-app-workspace__main-pane[data-surface="navigation"]:not(.is-primary) + .k2b-app-workspace__resize,
|
|
508
|
+
.k2b-app-workspace__resize:has(+ .k2b-app-workspace__main-pane[data-surface="navigation"]:not(.is-primary))
|
|
509
|
+
),
|
|
510
|
+
.cloud-app-canvas[data-shell-focus]
|
|
511
|
+
.k2b-app-workspace:not(.k2b-app-workspace *)
|
|
512
|
+
> .k2b-app-workspace__content
|
|
513
|
+
> :is(solid-island, solid-client)
|
|
514
|
+
> .k2b-app-workspace__main
|
|
515
|
+
> :is(
|
|
516
|
+
.k2b-app-workspace__main-pane[data-surface="navigation"]:not(.is-primary),
|
|
517
|
+
.k2b-app-workspace__main-pane[data-surface="navigation"]:not(.is-primary) + .k2b-app-workspace__resize,
|
|
518
|
+
.k2b-app-workspace__resize:has(+ .k2b-app-workspace__main-pane[data-surface="navigation"]:not(.is-primary))
|
|
519
|
+
) {
|
|
520
|
+
display: none;
|
|
392
521
|
}
|
|
393
522
|
}
|
|
394
523
|
|
|
@@ -750,10 +750,12 @@
|
|
|
750
750
|
@apply text-[0.6875rem] font-medium normal-case tracking-normal mb-5 text-dimmed select-none;
|
|
751
751
|
}
|
|
752
752
|
|
|
753
|
+
/* A rail control: a 44 px target in the 56 px rail. Its icon is 20 px
|
|
754
|
+
(`text-xl` on the icon). */
|
|
753
755
|
@utility rail-item {
|
|
754
756
|
border-right: 0;
|
|
755
757
|
border-radius: var(--ui-radius-surface);
|
|
756
|
-
@apply w-
|
|
758
|
+
@apply w-11 h-11;
|
|
757
759
|
@apply flex items-center justify-center text-dimmed;
|
|
758
760
|
@apply transition-[background-color,color] duration-150 ease-out;
|
|
759
761
|
|
|
@@ -795,6 +797,12 @@
|
|
|
795
797
|
pointer-events: none;
|
|
796
798
|
}
|
|
797
799
|
|
|
800
|
+
/* On the corner of the rail icon, not of its 44 px target. */
|
|
801
|
+
.rail-item > .cloud-app-badge {
|
|
802
|
+
top: 0.25rem;
|
|
803
|
+
right: 0.1875rem;
|
|
804
|
+
}
|
|
805
|
+
|
|
798
806
|
.app-icon > .cloud-app-badge {
|
|
799
807
|
top: -0.375rem;
|
|
800
808
|
right: -0.375rem;
|
|
@@ -841,8 +849,8 @@
|
|
|
841
849
|
.layout-profile-preferences__link,
|
|
842
850
|
.layout-profile-preferences__dropdown-trigger {
|
|
843
851
|
display: none;
|
|
844
|
-
width:
|
|
845
|
-
height:
|
|
852
|
+
width: 2.75rem;
|
|
853
|
+
height: 2.75rem;
|
|
846
854
|
align-items: center;
|
|
847
855
|
justify-content: center;
|
|
848
856
|
padding: 0;
|