@dxos/plugin-deck 0.6.14-staging.934c9de → 0.6.14-staging.9b873ce
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/dist/lib/browser/chunk-NIRHDTX4.mjs +17 -0
- package/dist/lib/browser/chunk-NIRHDTX4.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +387 -379
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types.mjs +11 -0
- package/dist/lib/browser/types.mjs.map +7 -0
- package/dist/types/src/DeckPlugin.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts +4 -3
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +3 -8
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +3 -4
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Plank.d.ts +4 -4
- package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/PlankControls.d.ts +19 -0
- package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +1 -0
- package/dist/types/src/components/DeckLayout/PlankError.d.ts +1 -2
- package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +7 -4
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +13 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/overscroll.d.ts +1 -2
- package/dist/types/src/util/overscroll.d.ts.map +1 -1
- package/package.json +34 -27
- package/src/DeckPlugin.tsx +18 -32
- package/src/components/DeckLayout/ComplementarySidebar.tsx +27 -45
- package/src/components/DeckLayout/DeckLayout.tsx +141 -137
- package/src/components/DeckLayout/NodePlankHeading.tsx +30 -17
- package/src/components/DeckLayout/Plank.tsx +62 -96
- package/src/components/DeckLayout/PlankControls.tsx +133 -0
- package/src/components/DeckLayout/PlankError.tsx +6 -8
- package/src/components/DeckLayout/PlankLoading.tsx +1 -1
- package/src/components/DeckLayout/Toast.tsx +1 -1
- package/src/components/LayoutSettings.tsx +13 -13
- package/src/translations.ts +11 -9
- package/src/types.ts +15 -0
- package/src/util/overscroll.ts +9 -30
package/src/DeckPlugin.tsx
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
openIds,
|
|
30
30
|
type LayoutMode,
|
|
31
31
|
type IntentData,
|
|
32
|
+
filterPlugins,
|
|
32
33
|
} from '@dxos/app-framework';
|
|
33
34
|
import { type UnsubscribeCallback } from '@dxos/async';
|
|
34
35
|
import { create, getTypename, isReactiveObject } from '@dxos/echo-schema';
|
|
@@ -36,21 +37,12 @@ import { scheduledEffect } from '@dxos/echo-signals/core';
|
|
|
36
37
|
import { LocalStorageStore } from '@dxos/local-storage';
|
|
37
38
|
import { log } from '@dxos/log';
|
|
38
39
|
import { parseAttentionPlugin, type AttentionPluginProvides } from '@dxos/plugin-attention';
|
|
39
|
-
import { parseClientPlugin, type ClientPluginProvides } from '@dxos/plugin-client';
|
|
40
40
|
import { createExtension, type Node } from '@dxos/plugin-graph';
|
|
41
41
|
import { ObservabilityAction } from '@dxos/plugin-observability/meta';
|
|
42
42
|
import { fullyQualifiedId } from '@dxos/react-client/echo';
|
|
43
|
-
import { translations as
|
|
43
|
+
import { translations as stackTranslations } from '@dxos/react-ui-stack';
|
|
44
44
|
|
|
45
|
-
import {
|
|
46
|
-
DeckLayout,
|
|
47
|
-
type DeckLayoutProps,
|
|
48
|
-
LayoutContext,
|
|
49
|
-
LayoutSettings,
|
|
50
|
-
NAV_ID,
|
|
51
|
-
DeckContext,
|
|
52
|
-
type DeckContextType,
|
|
53
|
-
} from './components';
|
|
45
|
+
import { DeckLayout, LayoutContext, LayoutSettings, NAV_ID, DeckContext, type DeckContextType } from './components';
|
|
54
46
|
import {
|
|
55
47
|
closeEntry,
|
|
56
48
|
incrementPlank,
|
|
@@ -62,7 +54,14 @@ import {
|
|
|
62
54
|
} from './layout';
|
|
63
55
|
import meta, { DECK_PLUGIN } from './meta';
|
|
64
56
|
import translations from './translations';
|
|
65
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
type NewPlankPositioning,
|
|
59
|
+
type DeckPluginProvides,
|
|
60
|
+
type DeckSettingsProps,
|
|
61
|
+
type Overscroll,
|
|
62
|
+
type Panel,
|
|
63
|
+
parsePanelPlugin,
|
|
64
|
+
} from './types';
|
|
66
65
|
import { checkAppScheme, getEffectivePart } from './util';
|
|
67
66
|
|
|
68
67
|
const isSocket = !!(globalThis as any).__args;
|
|
@@ -70,14 +69,6 @@ const isSocket = !!(globalThis as any).__args;
|
|
|
70
69
|
// TODO(mjamesderocher): Can we get this directly from Socket?
|
|
71
70
|
const appScheme = 'composer://';
|
|
72
71
|
|
|
73
|
-
// TODO(burdon): Evolve into customizable prefs.
|
|
74
|
-
const customSlots: DeckLayoutProps['slots'] = {
|
|
75
|
-
wallpaper: {
|
|
76
|
-
classNames:
|
|
77
|
-
'bg-cover bg-no-repeat dark:bg-[url(https://cdn.midjourney.com/3865ba61-f98a-4d94-b91a-1763ead01f4f/0_0.jpeg)]',
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
72
|
// NOTE(Zan): When producing values with immer, we shouldn't auto-freeze them because
|
|
82
73
|
// our signal implementation needs to add some hidden properties to the produced values.
|
|
83
74
|
// TODO(Zan): Move this to a more global location if we use immer more broadly.
|
|
@@ -105,10 +96,10 @@ export const DeckPlugin = ({
|
|
|
105
96
|
// TODO(burdon): GraphPlugin vs. IntentPluginProvides? (@wittjosiah).
|
|
106
97
|
let intentPlugin: Plugin<IntentPluginProvides> | undefined;
|
|
107
98
|
let attentionPlugin: Plugin<AttentionPluginProvides> | undefined;
|
|
108
|
-
let clientPlugin: Plugin<ClientPluginProvides> | undefined;
|
|
109
99
|
const unsubscriptionCallbacks = [] as (UnsubscribeCallback | undefined)[];
|
|
110
100
|
let currentUndoId: string | undefined;
|
|
111
101
|
let handleNavigation: () => Promise<void> | undefined;
|
|
102
|
+
const panels: Panel[] = [];
|
|
112
103
|
|
|
113
104
|
const settings = new LocalStorageStore<DeckSettingsProps>('dxos.org/settings/layout', {
|
|
114
105
|
showHints: false,
|
|
@@ -217,7 +208,6 @@ export const DeckPlugin = ({
|
|
|
217
208
|
intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
|
|
218
209
|
graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
|
|
219
210
|
attentionPlugin = resolvePlugin(plugins, parseAttentionPlugin);
|
|
220
|
-
clientPlugin = resolvePlugin(plugins, parseClientPlugin);
|
|
221
211
|
|
|
222
212
|
layout
|
|
223
213
|
.prop({ key: 'layoutMode', type: LocalStorageStore.enum<LayoutMode>() })
|
|
@@ -230,12 +220,8 @@ export const DeckPlugin = ({
|
|
|
230
220
|
.prop({ key: 'active', type: LocalStorageStore.json<LayoutParts>() })
|
|
231
221
|
.prop({ key: 'closed', type: LocalStorageStore.json<string[]>() });
|
|
232
222
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
layout.expunge();
|
|
236
|
-
location.expunge();
|
|
237
|
-
deck.expunge();
|
|
238
|
-
}),
|
|
223
|
+
panels.push(
|
|
224
|
+
...filterPlugins(plugins, parsePanelPlugin).flatMap((plugin) => plugin.provides.complementary.panels),
|
|
239
225
|
);
|
|
240
226
|
|
|
241
227
|
settings
|
|
@@ -261,12 +247,13 @@ export const DeckPlugin = ({
|
|
|
261
247
|
return;
|
|
262
248
|
}
|
|
263
249
|
|
|
250
|
+
const startingLayout = removePart(location.values.active, 'solo');
|
|
264
251
|
const layoutFromUri = uriToSoloPart(pathname);
|
|
265
252
|
if (!layoutFromUri) {
|
|
253
|
+
handleSetLocation(startingLayout);
|
|
266
254
|
return;
|
|
267
255
|
}
|
|
268
256
|
|
|
269
|
-
const startingLayout = removePart(location.values.active, 'solo');
|
|
270
257
|
handleSetLocation(mergeLayoutParts(layoutFromUri, startingLayout));
|
|
271
258
|
layout.values.layoutMode = 'solo';
|
|
272
259
|
};
|
|
@@ -296,7 +283,7 @@ export const DeckPlugin = ({
|
|
|
296
283
|
settings: settings.values,
|
|
297
284
|
layout: layout.values,
|
|
298
285
|
location: location.values,
|
|
299
|
-
translations: [...translations, ...
|
|
286
|
+
translations: [...translations, ...stackTranslations],
|
|
300
287
|
graph: {
|
|
301
288
|
builder: () => {
|
|
302
289
|
// TODO(burdon): Root menu isn't visible so nothing bound.
|
|
@@ -339,9 +326,8 @@ export const DeckPlugin = ({
|
|
|
339
326
|
layoutParts={location.values.active}
|
|
340
327
|
showHints={settings.values.showHints}
|
|
341
328
|
overscroll={settings.values.overscroll}
|
|
342
|
-
flatDeck={settings.values.flatDeck}
|
|
343
|
-
slots={settings.values.customSlots ? customSlots : undefined}
|
|
344
329
|
toasts={layout.values.toasts}
|
|
330
|
+
panels={panels}
|
|
345
331
|
onDismissToast={(id) => {
|
|
346
332
|
const index = layout.values.toasts.findIndex((toast) => toast.id === id);
|
|
347
333
|
if (index !== -1) {
|
|
@@ -14,41 +14,26 @@ import {
|
|
|
14
14
|
import { useGraph } from '@dxos/plugin-graph';
|
|
15
15
|
import { Main } from '@dxos/react-ui';
|
|
16
16
|
import { useAttended } from '@dxos/react-ui-attention';
|
|
17
|
-
import {
|
|
17
|
+
import { railGridHorizontal, StackContext } from '@dxos/react-ui-stack';
|
|
18
18
|
import { mx } from '@dxos/react-ui-theme';
|
|
19
19
|
|
|
20
20
|
import { NodePlankHeading } from './NodePlankHeading';
|
|
21
21
|
import { PlankContentError } from './PlankError';
|
|
22
22
|
import { PlankLoading } from './PlankLoading';
|
|
23
23
|
import { useNode, useNodeActionExpander } from '../../hooks';
|
|
24
|
-
import {
|
|
24
|
+
import { type Panel } from '../../types';
|
|
25
25
|
import { useLayout } from '../LayoutContext';
|
|
26
26
|
|
|
27
27
|
export type ComplementarySidebarProps = {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
panels: Panel[];
|
|
29
|
+
current?: string;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// TODO(burdon): Should be provided by plugins.
|
|
35
|
-
const panels: Panel[] = [
|
|
36
|
-
{ id: 'settings', icon: 'ph--gear--regular' },
|
|
37
|
-
{ id: 'comments', icon: 'ph--chat-text--regular' },
|
|
38
|
-
{ id: 'automation', icon: 'ph--atom--regular' },
|
|
39
|
-
{ id: 'debug', icon: 'ph--bug--regular' },
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
const getPanel = (id?: string): Panel['id'] => {
|
|
43
|
-
const panel = panels.find((p) => p.id === id) ?? panels[0];
|
|
44
|
-
return panel.id;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const ComplementarySidebar = ({ panel, flatDeck }: ComplementarySidebarProps) => {
|
|
32
|
+
export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarProps) => {
|
|
48
33
|
const { popoverAnchorId } = useLayout();
|
|
49
34
|
const attended = useAttended();
|
|
50
|
-
const
|
|
51
|
-
const id = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${
|
|
35
|
+
const panel = (panels.find((p) => p.id === current) ?? panels[0])?.id;
|
|
36
|
+
const id = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${panel}` : undefined;
|
|
52
37
|
const { graph } = useGraph();
|
|
53
38
|
const node = useNode(graph, id);
|
|
54
39
|
const dispatch = useIntentDispatcher();
|
|
@@ -56,19 +41,19 @@ export const ComplementarySidebar = ({ panel, flatDeck }: ComplementarySidebarPr
|
|
|
56
41
|
|
|
57
42
|
const actions = useMemo(
|
|
58
43
|
() =>
|
|
59
|
-
panels.map(({ id, icon }) => ({
|
|
44
|
+
panels.map(({ id, label, icon }) => ({
|
|
60
45
|
id: `complementary-${id}`,
|
|
61
46
|
data: () => {
|
|
62
47
|
void dispatch({ action: NavigationAction.OPEN, data: { activeParts: { complementary: id } } });
|
|
63
48
|
},
|
|
64
49
|
properties: {
|
|
65
|
-
label
|
|
50
|
+
label,
|
|
66
51
|
icon,
|
|
67
52
|
menuItemType: 'toggle',
|
|
68
|
-
isChecked:
|
|
53
|
+
isChecked: panel === id,
|
|
69
54
|
},
|
|
70
55
|
})),
|
|
71
|
-
[
|
|
56
|
+
[panel],
|
|
72
57
|
);
|
|
73
58
|
|
|
74
59
|
// TODO(wittjosiah): Ensure that id is always defined.
|
|
@@ -77,26 +62,23 @@ export const ComplementarySidebar = ({ panel, flatDeck }: ComplementarySidebarPr
|
|
|
77
62
|
// TODO(burdon): Debug panel doesn't change when switching even though id has chagned.
|
|
78
63
|
return (
|
|
79
64
|
<Main.ComplementarySidebar>
|
|
80
|
-
<
|
|
81
|
-
<
|
|
82
|
-
coordinate={coordinate}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
placeholder={<PlankLoading />}
|
|
96
|
-
/>
|
|
97
|
-
)}
|
|
65
|
+
<StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', separators: true, rail: true }}>
|
|
66
|
+
<div role='none' className={mx(railGridHorizontal, 'grid-cols-1 bs-full divide-y divide-separator')}>
|
|
67
|
+
<NodePlankHeading coordinate={coordinate} node={node} popoverAnchorId={popoverAnchorId} actions={actions} />
|
|
68
|
+
<div className='divide-y divide-separator overflow-x-hidden overflow-y-scroll'>
|
|
69
|
+
{node && (
|
|
70
|
+
<Surface
|
|
71
|
+
key={id}
|
|
72
|
+
role={`complementary--${panel}`}
|
|
73
|
+
limit={1}
|
|
74
|
+
data={{ id, subject: node.properties.object ?? node.properties.space, popoverAnchorId }}
|
|
75
|
+
fallback={PlankContentError}
|
|
76
|
+
placeholder={<PlankLoading />}
|
|
77
|
+
/>
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
98
80
|
</div>
|
|
99
|
-
</
|
|
81
|
+
</StackContext.Provider>
|
|
100
82
|
</Main.ComplementarySidebar>
|
|
101
83
|
);
|
|
102
84
|
};
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import { Sidebar as MenuIcon } from '@phosphor-icons/react';
|
|
6
6
|
import { untracked } from '@preact/signals-core';
|
|
7
|
-
import React, { useCallback, useEffect, useMemo, useRef, type UIEvent } from 'react';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment } from 'react';
|
|
8
8
|
|
|
9
9
|
import { type LayoutParts, Surface, type Toast as ToastSchema, firstIdInPart, usePlugin } from '@dxos/app-framework';
|
|
10
10
|
import { type AttentionPluginProvides } from '@dxos/plugin-attention';
|
|
11
|
-
import { Button, Dialog, Main, Popover, useOnTransition, useTranslation } from '@dxos/react-ui';
|
|
12
|
-
import {
|
|
11
|
+
import { Button, Dialog, Main, Popover, useOnTransition, useTranslation, type MainProps } from '@dxos/react-ui';
|
|
12
|
+
import { Stack, StackContext, DEFAULT_HORIZONTAL_SIZE } from '@dxos/react-ui-stack';
|
|
13
13
|
import { getSize, mainPaddingTransitions } from '@dxos/react-ui-theme';
|
|
14
14
|
|
|
15
15
|
import { ActiveNode } from './ActiveNode';
|
|
16
|
-
import { ComplementarySidebar } from './ComplementarySidebar';
|
|
16
|
+
import { ComplementarySidebar, type ComplementarySidebarProps } from './ComplementarySidebar';
|
|
17
17
|
import { ContentEmpty } from './ContentEmpty';
|
|
18
18
|
import { Fullscreen } from './Fullscreen';
|
|
19
19
|
import { Plank } from './Plank';
|
|
@@ -29,24 +29,15 @@ import { useLayout } from '../LayoutContext';
|
|
|
29
29
|
export type DeckLayoutProps = {
|
|
30
30
|
layoutParts: LayoutParts;
|
|
31
31
|
toasts: ToastSchema[];
|
|
32
|
-
flatDeck?: boolean;
|
|
33
32
|
overscroll: Overscroll;
|
|
34
33
|
showHints: boolean;
|
|
35
|
-
slots?: {
|
|
36
|
-
wallpaper?: { classNames?: string };
|
|
37
|
-
};
|
|
38
34
|
onDismissToast: (id: string) => void;
|
|
39
|
-
}
|
|
35
|
+
} & Pick<ComplementarySidebarProps, 'panels'>;
|
|
36
|
+
|
|
37
|
+
const PlankSeparator = ({ index }: { index: number }) =>
|
|
38
|
+
index > 0 ? <span role='separator' className='row-span-2 bg-deck is-4' style={{ gridColumn: index * 2 }} /> : null;
|
|
40
39
|
|
|
41
|
-
export const DeckLayout = ({
|
|
42
|
-
layoutParts,
|
|
43
|
-
toasts,
|
|
44
|
-
flatDeck,
|
|
45
|
-
overscroll,
|
|
46
|
-
showHints,
|
|
47
|
-
slots,
|
|
48
|
-
onDismissToast,
|
|
49
|
-
}: DeckLayoutProps) => {
|
|
40
|
+
export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels, onDismissToast }: DeckLayoutProps) => {
|
|
50
41
|
const context = useLayout();
|
|
51
42
|
const {
|
|
52
43
|
layoutMode,
|
|
@@ -63,16 +54,17 @@ export const DeckLayout = ({
|
|
|
63
54
|
const { plankSizing } = useDeckContext();
|
|
64
55
|
// NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
|
|
65
56
|
const attentionPlugin = usePlugin<AttentionPluginProvides>('dxos.org/plugin/attention');
|
|
66
|
-
const searchPlugin = usePlugin('dxos.org/plugin/search');
|
|
67
57
|
const fullScreenSlug = useMemo(() => firstIdInPart(layoutParts, 'fullScreen'), [layoutParts]);
|
|
68
58
|
|
|
69
59
|
const scrollLeftRef = useRef<number | null>();
|
|
70
60
|
const deckRef = useRef<HTMLDivElement>(null);
|
|
71
61
|
|
|
62
|
+
const isSoloModeLoaded = layoutMode === 'solo' && Boolean(layoutParts.solo?.[0]);
|
|
63
|
+
|
|
72
64
|
// Ensure the first plank is attended when the deck is first rendered.
|
|
73
65
|
useEffect(() => {
|
|
74
66
|
const attended = untracked(() => attentionPlugin?.provides.attention.attended ?? []);
|
|
75
|
-
const firstId =
|
|
67
|
+
const firstId = isSoloModeLoaded ? firstIdInPart(layoutParts, 'solo') : firstIdInPart(layoutParts, 'main');
|
|
76
68
|
if (attended.length === 0 && firstId) {
|
|
77
69
|
// TODO(wittjosiah): Focusing the type button is a workaround.
|
|
78
70
|
// If the plank is directly focused on first load the focus ring appears.
|
|
@@ -112,18 +104,14 @@ export const DeckLayout = ({
|
|
|
112
104
|
[layoutMode],
|
|
113
105
|
);
|
|
114
106
|
|
|
115
|
-
const isEmpty = layoutParts.main?.length === 0 && layoutParts.solo?.length === 0;
|
|
107
|
+
const isEmpty = (layoutParts.main?.length ?? 0) === 0 && (layoutParts.solo?.length ?? 0) === 0;
|
|
116
108
|
|
|
117
109
|
const padding = useMemo(() => {
|
|
118
110
|
if (layoutMode === 'deck' && overscroll === 'centering') {
|
|
119
|
-
return calculateOverscroll(layoutParts.main
|
|
111
|
+
return calculateOverscroll(layoutParts.main?.length ?? 0);
|
|
120
112
|
}
|
|
121
113
|
return {};
|
|
122
|
-
}, [layoutMode, overscroll, layoutParts.main
|
|
123
|
-
|
|
124
|
-
if (layoutMode === 'fullscreen') {
|
|
125
|
-
return <Fullscreen id={fullScreenSlug} />;
|
|
126
|
-
}
|
|
114
|
+
}, [layoutMode, overscroll, layoutParts.main]);
|
|
127
115
|
|
|
128
116
|
return (
|
|
129
117
|
<Popover.Root
|
|
@@ -140,127 +128,143 @@ export const DeckLayout = ({
|
|
|
140
128
|
>
|
|
141
129
|
<ActiveNode />
|
|
142
130
|
|
|
143
|
-
<
|
|
144
|
-
navigationSidebarOpen={context.sidebarOpen}
|
|
145
|
-
onNavigationSidebarOpenChange={(next) => (context.sidebarOpen = next)}
|
|
146
|
-
complementarySidebarOpen={context.complementarySidebarOpen}
|
|
147
|
-
onComplementarySidebarOpenChange={(next) => (context.complementarySidebarOpen = next)}
|
|
148
|
-
>
|
|
149
|
-
{/* Notch */}
|
|
150
|
-
<Main.Notch classNames='z-[21]'>
|
|
151
|
-
<Surface role='notch-start' />
|
|
152
|
-
<Button onClick={() => (context.sidebarOpen = !context.sidebarOpen)} variant='ghost' classNames='p-1'>
|
|
153
|
-
<span className='sr-only'>{t('open navigation sidebar label')}</span>
|
|
154
|
-
<MenuIcon weight='light' className={getSize(5)} />
|
|
155
|
-
</Button>
|
|
156
|
-
<Button
|
|
157
|
-
onClick={() => (context.complementarySidebarOpen = !context.complementarySidebarOpen)}
|
|
158
|
-
variant='ghost'
|
|
159
|
-
classNames='p-1'
|
|
160
|
-
>
|
|
161
|
-
<span className='sr-only'>{t('open complementary sidebar label')}</span>
|
|
162
|
-
<MenuIcon mirrored weight='light' className={getSize(5)} />
|
|
163
|
-
</Button>
|
|
164
|
-
<Surface role='notch-end' />
|
|
165
|
-
</Main.Notch>
|
|
131
|
+
{layoutMode === 'fullscreen' && <Fullscreen id={fullScreenSlug} />}
|
|
166
132
|
|
|
167
|
-
|
|
168
|
-
<
|
|
133
|
+
{layoutMode !== 'fullscreen' && (
|
|
134
|
+
<Main.Root
|
|
135
|
+
navigationSidebarOpen={context.sidebarOpen}
|
|
136
|
+
onNavigationSidebarOpenChange={(next) => (context.sidebarOpen = next)}
|
|
137
|
+
complementarySidebarOpen={context.complementarySidebarOpen}
|
|
138
|
+
onComplementarySidebarOpenChange={(next) => (context.complementarySidebarOpen = next)}
|
|
139
|
+
>
|
|
140
|
+
{/* Notch */}
|
|
141
|
+
<Main.Notch classNames='z-[21]'>
|
|
142
|
+
<Surface role='notch-start' />
|
|
143
|
+
<Button onClick={() => (context.sidebarOpen = !context.sidebarOpen)} variant='ghost' classNames='p-1'>
|
|
144
|
+
<span className='sr-only'>{t('open navigation sidebar label')}</span>
|
|
145
|
+
<MenuIcon weight='light' className={getSize(5)} />
|
|
146
|
+
</Button>
|
|
147
|
+
<Surface role='notch-end' />
|
|
148
|
+
</Main.Notch>
|
|
169
149
|
|
|
170
|
-
|
|
171
|
-
|
|
150
|
+
{/* Left sidebar. */}
|
|
151
|
+
<Sidebar layoutParts={layoutParts} />
|
|
172
152
|
|
|
173
|
-
|
|
174
|
-
|
|
153
|
+
{/* Right sidebar. */}
|
|
154
|
+
<ComplementarySidebar panels={panels} current={layoutParts.complementary?.[0].id} />
|
|
175
155
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<Main.Content handlesFocus>
|
|
179
|
-
<ContentEmpty />
|
|
180
|
-
</Main.Content>
|
|
181
|
-
)}
|
|
156
|
+
{/* Dialog overlay to dismiss dialogs. */}
|
|
157
|
+
<Main.Overlay />
|
|
182
158
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
159
|
+
{/* No content. */}
|
|
160
|
+
{isEmpty && (
|
|
161
|
+
<Main.Content handlesFocus>
|
|
162
|
+
<ContentEmpty />
|
|
163
|
+
</Main.Content>
|
|
164
|
+
)}
|
|
165
|
+
|
|
166
|
+
{/* Solo/deck mode. */}
|
|
167
|
+
{!isEmpty && (
|
|
168
|
+
<Main.Content
|
|
169
|
+
bounce
|
|
170
|
+
classNames='grid block-end-[--statusbar-size]'
|
|
171
|
+
handlesFocus
|
|
172
|
+
style={
|
|
173
|
+
{
|
|
174
|
+
'--dx-main-sidebarWidth': sidebarOpen ? 'var(--nav-sidebar-size)' : '0px',
|
|
175
|
+
'--dx-main-complementaryWidth': complementarySidebarOpen
|
|
176
|
+
? 'var(--complementary-sidebar-size)'
|
|
177
|
+
: '0px',
|
|
178
|
+
'--dx-main-contentFirstWidth': `${plankSizing[layoutParts.main?.[0]?.id ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
|
|
179
|
+
'--dx-main-contentLastWidth': `${plankSizing[layoutParts.main?.[(layoutParts.main?.length ?? 1) - 1]?.id ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
|
|
180
|
+
} as MainProps['style']
|
|
181
|
+
}
|
|
182
|
+
>
|
|
183
|
+
<div
|
|
184
|
+
role='none'
|
|
185
|
+
className={!isSoloModeLoaded ? 'relative bg-deck overflow-hidden' : 'sr-only'}
|
|
186
|
+
{...(isSoloModeLoaded && { inert: '' })}
|
|
198
187
|
>
|
|
199
|
-
<
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
key={layoutEntry.id}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
188
|
+
<Stack
|
|
189
|
+
orientation='horizontal'
|
|
190
|
+
size='contain'
|
|
191
|
+
classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
|
|
192
|
+
onScroll={handleScroll}
|
|
193
|
+
itemsCount={2 * (layoutParts.main?.length ?? 0) - 1}
|
|
194
|
+
style={padding}
|
|
195
|
+
ref={deckRef}
|
|
196
|
+
>
|
|
197
|
+
{layoutParts.main?.map((layoutEntry, index) => (
|
|
198
|
+
<Fragment key={layoutEntry.id}>
|
|
199
|
+
<PlankSeparator index={index} />
|
|
200
|
+
<Plank
|
|
201
|
+
entry={layoutEntry}
|
|
202
|
+
layoutParts={layoutParts}
|
|
203
|
+
part='main'
|
|
204
|
+
layoutMode={layoutMode}
|
|
205
|
+
order={index * 2 + 1}
|
|
206
|
+
last={index === layoutParts.main!.length - 1}
|
|
207
|
+
/>
|
|
208
|
+
</Fragment>
|
|
209
|
+
))}
|
|
210
|
+
</Stack>
|
|
211
|
+
</div>
|
|
212
|
+
<div
|
|
213
|
+
role='none'
|
|
214
|
+
className={isSoloModeLoaded ? 'relative bg-deck overflow-hidden' : 'sr-only'}
|
|
215
|
+
{...(!isSoloModeLoaded && { inert: '' })}
|
|
216
|
+
>
|
|
217
|
+
<StackContext.Provider
|
|
218
|
+
value={{ size: 'contain', orientation: 'horizontal', separators: true, rail: true }}
|
|
219
|
+
>
|
|
220
|
+
<Plank entry={layoutParts.solo?.[0]} layoutParts={layoutParts} part='solo' layoutMode={layoutMode} />
|
|
221
|
+
</StackContext.Provider>
|
|
222
|
+
</div>
|
|
223
|
+
</Main.Content>
|
|
224
|
+
)}
|
|
222
225
|
|
|
223
|
-
|
|
224
|
-
|
|
226
|
+
{/* Footer status. */}
|
|
227
|
+
<StatusBar showHints={showHints} />
|
|
228
|
+
</Main.Root>
|
|
229
|
+
)}
|
|
225
230
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
231
|
+
{/* Global popovers. */}
|
|
232
|
+
<Popover.Portal>
|
|
233
|
+
<Popover.Content
|
|
234
|
+
classNames='z-[60]'
|
|
235
|
+
onEscapeKeyDown={() => {
|
|
236
|
+
context.popoverOpen = false;
|
|
237
|
+
context.popoverAnchorId = undefined;
|
|
238
|
+
}}
|
|
239
|
+
>
|
|
240
|
+
<Popover.Viewport>
|
|
241
|
+
<Surface role='popover' data={popoverContent} />
|
|
242
|
+
</Popover.Viewport>
|
|
243
|
+
<Popover.Arrow />
|
|
244
|
+
</Popover.Content>
|
|
245
|
+
</Popover.Portal>
|
|
241
246
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
247
|
+
{/* Global dialog. */}
|
|
248
|
+
<Dialog.Root open={dialogOpen} onOpenChange={(nextOpen) => (context.dialogOpen = nextOpen)}>
|
|
249
|
+
<Dialog.Overlay blockAlign={dialogBlockAlign}>
|
|
250
|
+
<Surface role='dialog' data={dialogContent} />
|
|
251
|
+
</Dialog.Overlay>
|
|
252
|
+
</Dialog.Root>
|
|
248
253
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
{/* Global toasts. */}
|
|
255
|
+
{toasts?.map((toast) => (
|
|
256
|
+
<Toast
|
|
257
|
+
{...toast}
|
|
258
|
+
key={toast.id}
|
|
259
|
+
onOpenChange={(open) => {
|
|
260
|
+
if (!open) {
|
|
261
|
+
onDismissToast(toast.id);
|
|
262
|
+
}
|
|
258
263
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
</Main.Root>
|
|
264
|
+
return open;
|
|
265
|
+
}}
|
|
266
|
+
/>
|
|
267
|
+
))}
|
|
264
268
|
</Popover.Root>
|
|
265
269
|
);
|
|
266
270
|
};
|