@dxos/plugin-deck 0.6.13-main.ed424a1 → 0.6.13
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-GVOGPULO.mjs → chunk-YVHGFQQR.mjs} +1 -1
- package/dist/lib/browser/chunk-YVHGFQQR.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +184 -239
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/types/src/DeckPlugin.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts +2 -2
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +4 -3
- 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/Sidebar.d.ts +3 -2
- package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts +1 -3
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
- package/dist/types/src/components/LayoutSettings.d.ts.map +1 -1
- package/dist/types/src/hooks/useNode.d.ts.map +1 -1
- package/dist/types/src/layout.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +1 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/overscroll.d.ts +1 -1
- package/dist/types/src/util/overscroll.d.ts.map +1 -1
- package/package.json +29 -30
- package/src/DeckPlugin.tsx +71 -93
- package/src/components/DeckLayout/ComplementarySidebar.tsx +27 -72
- package/src/components/DeckLayout/DeckLayout.tsx +84 -63
- package/src/components/DeckLayout/NodePlankHeading.tsx +15 -15
- package/src/components/DeckLayout/Plank.tsx +3 -3
- package/src/components/DeckLayout/Sidebar.tsx +5 -6
- package/src/components/DeckLayout/StatusBar.tsx +3 -12
- package/src/components/LayoutSettings.tsx +8 -5
- package/src/hooks/useNode.ts +1 -5
- package/src/layout.ts +0 -1
- package/src/meta.ts +1 -3
- package/src/translations.ts +1 -3
- package/src/types.ts +1 -1
- package/src/util/overscroll.ts +5 -5
- package/dist/lib/browser/chunk-GVOGPULO.mjs.map +0 -7
|
@@ -3,13 +3,21 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Sidebar as MenuIcon } from '@phosphor-icons/react';
|
|
6
|
-
import React, { useCallback, useEffect, useMemo, useRef, type UIEvent } from 'react';
|
|
6
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState, useLayoutEffect, type UIEvent } from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import {
|
|
9
|
+
SLUG_PATH_SEPARATOR,
|
|
10
|
+
type Attention,
|
|
11
|
+
type LayoutEntry,
|
|
12
|
+
type LayoutParts,
|
|
13
|
+
Surface,
|
|
14
|
+
type Toast as ToastSchema,
|
|
15
|
+
firstIdInPart,
|
|
16
|
+
usePlugin,
|
|
17
|
+
} from '@dxos/app-framework';
|
|
18
|
+
import { Button, Dialog, Main, Popover, useTranslation } from '@dxos/react-ui';
|
|
11
19
|
import { Deck } from '@dxos/react-ui-deck';
|
|
12
|
-
import { getSize
|
|
20
|
+
import { getSize } from '@dxos/react-ui-theme';
|
|
13
21
|
|
|
14
22
|
import { ActiveNode } from './ActiveNode';
|
|
15
23
|
import { ComplementarySidebar } from './ComplementarySidebar';
|
|
@@ -27,10 +35,11 @@ import { useLayout } from '../LayoutContext';
|
|
|
27
35
|
|
|
28
36
|
export type DeckLayoutProps = {
|
|
29
37
|
layoutParts: LayoutParts;
|
|
38
|
+
attention: Attention;
|
|
30
39
|
toasts: ToastSchema[];
|
|
31
40
|
flatDeck?: boolean;
|
|
32
41
|
overscroll: Overscroll;
|
|
33
|
-
|
|
42
|
+
showHintsFooter: boolean;
|
|
34
43
|
slots?: {
|
|
35
44
|
wallpaper?: { classNames?: string };
|
|
36
45
|
};
|
|
@@ -39,10 +48,11 @@ export type DeckLayoutProps = {
|
|
|
39
48
|
|
|
40
49
|
export const DeckLayout = ({
|
|
41
50
|
layoutParts,
|
|
51
|
+
attention,
|
|
42
52
|
toasts,
|
|
43
53
|
flatDeck,
|
|
44
54
|
overscroll,
|
|
45
|
-
|
|
55
|
+
showHintsFooter,
|
|
46
56
|
slots,
|
|
47
57
|
onDismissToast,
|
|
48
58
|
}: DeckLayoutProps) => {
|
|
@@ -60,42 +70,36 @@ export const DeckLayout = ({
|
|
|
60
70
|
} = context;
|
|
61
71
|
const { t } = useTranslation(DECK_PLUGIN);
|
|
62
72
|
const { plankSizing } = useDeckContext();
|
|
63
|
-
const attended = useAttended();
|
|
64
73
|
const searchPlugin = usePlugin('dxos.org/plugin/search');
|
|
65
74
|
const fullScreenSlug = useMemo(() => firstIdInPart(layoutParts, 'fullScreen'), [layoutParts]);
|
|
66
75
|
|
|
67
|
-
const
|
|
68
|
-
const deckRef = useRef<HTMLDivElement>(null);
|
|
69
|
-
|
|
70
|
-
// Ensure the first plank is attended when the deck is first rendered.
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
const firstId = layoutMode === 'solo' ? firstIdInPart(layoutParts, 'solo') : firstIdInPart(layoutParts, 'main');
|
|
73
|
-
if (attended.length === 0 && firstId) {
|
|
74
|
-
// TODO(wittjosiah): Focusing the type button is a workaround.
|
|
75
|
-
// If the plank is directly focused on first load the focus ring appears.
|
|
76
|
-
document.querySelector<HTMLElement>(`article[data-attendable-id="${firstId}"] button`)?.focus();
|
|
77
|
-
}
|
|
78
|
-
}, []);
|
|
76
|
+
const [scrollLeft, setScrollLeft] = useState<number | null>(null);
|
|
77
|
+
const deckRef = useRef<HTMLDivElement | null>(null);
|
|
78
|
+
const restoreScrollRef = useRef<boolean>(false);
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
81
|
* Clear scroll restoration state if the window is resized
|
|
82
82
|
*/
|
|
83
83
|
const handleResize = useCallback(() => {
|
|
84
|
-
|
|
84
|
+
setScrollLeft(null);
|
|
85
85
|
}, []);
|
|
86
|
-
|
|
87
86
|
useEffect(() => {
|
|
88
87
|
window.addEventListener('resize', handleResize);
|
|
89
88
|
return () => window.removeEventListener('resize', handleResize);
|
|
90
89
|
}, [handleResize]);
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Restore scroll when returning to deck mode
|
|
93
|
+
*/
|
|
94
|
+
useLayoutEffect(() => {
|
|
95
|
+
if (layoutMode !== 'deck') {
|
|
96
|
+
restoreScrollRef.current = true;
|
|
97
|
+
} else if (restoreScrollRef.current && deckRef.current && scrollLeft) {
|
|
98
|
+
// console.log('[restoring scrollLeft]', scrollLeft);
|
|
99
|
+
deckRef.current.scrollLeft = scrollLeft;
|
|
100
|
+
restoreScrollRef.current = false;
|
|
95
101
|
}
|
|
96
|
-
}, []);
|
|
97
|
-
|
|
98
|
-
useOnTransition(layoutMode, (mode) => mode !== 'deck', 'deck', restoreScroll);
|
|
102
|
+
}, [layoutMode, deckRef.current, scrollLeft]);
|
|
99
103
|
|
|
100
104
|
/**
|
|
101
105
|
* Save scroll position as the user scrolls
|
|
@@ -103,13 +107,22 @@ export const DeckLayout = ({
|
|
|
103
107
|
const handleScroll = useCallback(
|
|
104
108
|
(event: UIEvent) => {
|
|
105
109
|
if (layoutMode === 'deck' && event.currentTarget === event.target) {
|
|
106
|
-
|
|
110
|
+
// console.log('[save scroll left]', (event.target as HTMLDivElement).scrollLeft);
|
|
111
|
+
setScrollLeft((event.target as HTMLDivElement).scrollLeft);
|
|
107
112
|
}
|
|
108
113
|
},
|
|
109
114
|
[layoutMode],
|
|
110
115
|
);
|
|
111
116
|
|
|
112
|
-
const
|
|
117
|
+
const complementarySlug = useMemo(() => {
|
|
118
|
+
const entry = layoutParts.complementary?.at(0);
|
|
119
|
+
if (entry) {
|
|
120
|
+
return entry.path ? `${entry.id}${SLUG_PATH_SEPARATOR}${entry.path}` : entry.id;
|
|
121
|
+
}
|
|
122
|
+
}, [layoutParts]);
|
|
123
|
+
|
|
124
|
+
const firstAttendedId = useMemo(() => Array.from(attention.attended ?? [])[0], [attention.attended]);
|
|
125
|
+
|
|
113
126
|
useEffect(() => {
|
|
114
127
|
// TODO(burdon): Can we prevent the need to re-scroll since the planks are preserved?
|
|
115
128
|
// E.g., hide the deck and just move the solo article?
|
|
@@ -121,14 +134,21 @@ export const DeckLayout = ({
|
|
|
121
134
|
}
|
|
122
135
|
}, [layoutMode, firstAttendedId]);
|
|
123
136
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
// TODO(burdon): Needs cleaning up.
|
|
138
|
+
const parts: LayoutEntry[] = useMemo(() => {
|
|
139
|
+
const parts = [...(layoutParts.main ?? [])];
|
|
140
|
+
for (const part of layoutParts.solo ?? []) {
|
|
141
|
+
if (!parts.find((entry) => entry.id === part.id)) {
|
|
142
|
+
parts.push(part);
|
|
143
|
+
}
|
|
129
144
|
}
|
|
130
|
-
return
|
|
131
|
-
}, [
|
|
145
|
+
return parts;
|
|
146
|
+
}, [layoutParts.main, layoutParts.solo]);
|
|
147
|
+
|
|
148
|
+
const padding =
|
|
149
|
+
layoutMode === 'deck' && overscroll === 'centering'
|
|
150
|
+
? calculateOverscroll(layoutParts.main, plankSizing, sidebarOpen, complementarySidebarOpen)
|
|
151
|
+
: {};
|
|
132
152
|
|
|
133
153
|
if (layoutMode === 'fullscreen') {
|
|
134
154
|
return <Fullscreen id={fullScreenSlug} />;
|
|
@@ -153,17 +173,25 @@ export const DeckLayout = ({
|
|
|
153
173
|
<Main.Root
|
|
154
174
|
navigationSidebarOpen={context.sidebarOpen}
|
|
155
175
|
onNavigationSidebarOpenChange={(next) => (context.sidebarOpen = next)}
|
|
156
|
-
complementarySidebarOpen
|
|
157
|
-
|
|
176
|
+
{...(complementarySidebarOpen !== null && {
|
|
177
|
+
complementarySidebarOpen: /* complementaryAvailable && */ context.complementarySidebarOpen as boolean,
|
|
178
|
+
onComplementarySidebarOpenChange: (next) => (context.complementarySidebarOpen = next),
|
|
179
|
+
})}
|
|
158
180
|
>
|
|
159
181
|
{/* Notch */}
|
|
160
182
|
<Main.Notch classNames='z-[21]'>
|
|
161
183
|
<Surface role='notch-start' />
|
|
162
|
-
<Button
|
|
184
|
+
<Button
|
|
185
|
+
// disabled={!sidebarAvailable}
|
|
186
|
+
onClick={() => (context.sidebarOpen = !context.sidebarOpen)}
|
|
187
|
+
variant='ghost'
|
|
188
|
+
classNames='p-1'
|
|
189
|
+
>
|
|
163
190
|
<span className='sr-only'>{t('open navigation sidebar label')}</span>
|
|
164
191
|
<MenuIcon weight='light' className={getSize(5)} />
|
|
165
192
|
</Button>
|
|
166
193
|
<Button
|
|
194
|
+
// disabled={!complementaryAvailable}
|
|
167
195
|
onClick={() => (context.complementarySidebarOpen = !context.complementarySidebarOpen)}
|
|
168
196
|
variant='ghost'
|
|
169
197
|
classNames='p-1'
|
|
@@ -175,52 +203,38 @@ export const DeckLayout = ({
|
|
|
175
203
|
</Main.Notch>
|
|
176
204
|
|
|
177
205
|
{/* Left sidebar. */}
|
|
178
|
-
<Sidebar layoutParts={layoutParts} />
|
|
206
|
+
<Sidebar attention={attention} layoutParts={layoutParts} />
|
|
179
207
|
|
|
180
208
|
{/* Right sidebar. */}
|
|
181
|
-
{
|
|
182
|
-
<ComplementarySidebar context='comments' layoutParts={layoutParts} flatDeck={flatDeck} />
|
|
209
|
+
<ComplementarySidebar id={complementarySlug} layoutParts={layoutParts} flatDeck={flatDeck} />
|
|
183
210
|
|
|
184
211
|
{/* Dialog overlay to dismiss dialogs. */}
|
|
185
212
|
<Main.Overlay />
|
|
186
213
|
|
|
187
214
|
{/* No content. */}
|
|
188
|
-
{
|
|
215
|
+
{parts.length === 0 && (
|
|
189
216
|
<Main.Content handlesFocus>
|
|
190
217
|
<ContentEmpty />
|
|
191
218
|
</Main.Content>
|
|
192
219
|
)}
|
|
193
220
|
|
|
194
221
|
{/* Solo/deck mode. */}
|
|
195
|
-
{
|
|
222
|
+
{parts.length !== 0 && (
|
|
196
223
|
<Main.Content bounce classNames='grid block-end-[--statusbar-size]' handlesFocus>
|
|
197
224
|
<div role='none' className='relative'>
|
|
198
225
|
<Deck.Root
|
|
199
226
|
style={padding}
|
|
200
|
-
classNames={[
|
|
201
|
-
!flatDeck && 'bg-deck',
|
|
202
|
-
mainPaddingTransitions,
|
|
203
|
-
'absolute inset-0',
|
|
204
|
-
slots?.wallpaper?.classNames,
|
|
205
|
-
]}
|
|
227
|
+
classNames={[!flatDeck && 'bg-deck', 'absolute inset-0', slots?.wallpaper?.classNames]}
|
|
206
228
|
solo={layoutMode === 'solo'}
|
|
207
229
|
onScroll={handleScroll}
|
|
208
230
|
ref={deckRef}
|
|
209
231
|
>
|
|
210
|
-
|
|
211
|
-
entry={layoutParts.solo?.[0] ?? { id: 'unknown-solo' }}
|
|
212
|
-
layoutParts={layoutParts}
|
|
213
|
-
part='solo'
|
|
214
|
-
layoutMode={layoutMode}
|
|
215
|
-
flatDeck={flatDeck}
|
|
216
|
-
searchEnabled={!!searchPlugin}
|
|
217
|
-
/>
|
|
218
|
-
{layoutParts.main?.map((layoutEntry) => (
|
|
232
|
+
{parts.map((layoutEntry) => (
|
|
219
233
|
<Plank
|
|
220
234
|
key={layoutEntry.id}
|
|
221
235
|
entry={layoutEntry}
|
|
222
236
|
layoutParts={layoutParts}
|
|
223
|
-
part='main'
|
|
237
|
+
part={layoutMode === 'solo' && layoutEntry.id === layoutParts.solo?.[0]?.id ? 'solo' : 'main'}
|
|
224
238
|
layoutMode={layoutMode}
|
|
225
239
|
flatDeck={flatDeck}
|
|
226
240
|
searchEnabled={!!searchPlugin}
|
|
@@ -231,8 +245,15 @@ export const DeckLayout = ({
|
|
|
231
245
|
</Main.Content>
|
|
232
246
|
)}
|
|
233
247
|
|
|
234
|
-
|
|
235
|
-
|
|
248
|
+
<StatusBar />
|
|
249
|
+
|
|
250
|
+
{/* Help hints. */}
|
|
251
|
+
{/* TODO(burdon): Need to make room for this in status bar. */}
|
|
252
|
+
{showHintsFooter && (
|
|
253
|
+
<div className='fixed bottom-0 left-0 right-0 h-[32px] z-[1] flex justify-center'>
|
|
254
|
+
<Surface role='hints' limit={1} />
|
|
255
|
+
</div>
|
|
256
|
+
)}
|
|
236
257
|
|
|
237
258
|
{/* Global popovers. */}
|
|
238
259
|
<Popover.Portal>
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Placeholder } from '@phosphor-icons/react';
|
|
5
6
|
import React, { Fragment, useEffect } from 'react';
|
|
6
7
|
|
|
7
8
|
import {
|
|
8
9
|
LayoutAction,
|
|
9
10
|
NavigationAction,
|
|
11
|
+
SLUG_COLLECTION_INDICATOR,
|
|
10
12
|
SLUG_PATH_SEPARATOR,
|
|
11
13
|
Surface,
|
|
12
14
|
useIntentDispatcher,
|
|
@@ -14,10 +16,11 @@ import {
|
|
|
14
16
|
partLength,
|
|
15
17
|
type LayoutParts,
|
|
16
18
|
type LayoutPart,
|
|
19
|
+
type LayoutEntry,
|
|
17
20
|
} from '@dxos/app-framework';
|
|
18
21
|
import { type Node, useGraph } from '@dxos/plugin-graph';
|
|
19
|
-
import {
|
|
20
|
-
import { PlankHeading,
|
|
22
|
+
import { Popover, toLocalizedString, useMediaQuery, useTranslation } from '@dxos/react-ui';
|
|
23
|
+
import { PlankHeading, plankHeadingIconProps } from '@dxos/react-ui-deck';
|
|
21
24
|
import { TextTooltip } from '@dxos/react-ui-text-tooltip';
|
|
22
25
|
|
|
23
26
|
import { DECK_PLUGIN } from '../../meta';
|
|
@@ -27,23 +30,24 @@ export const NodePlankHeading = ({
|
|
|
27
30
|
id,
|
|
28
31
|
layoutParts,
|
|
29
32
|
layoutPart,
|
|
33
|
+
// TODO(wittjosiah): Unused?
|
|
34
|
+
layoutEntry,
|
|
30
35
|
popoverAnchorId,
|
|
31
36
|
pending,
|
|
32
37
|
flatDeck,
|
|
33
|
-
actions = [],
|
|
34
38
|
}: {
|
|
35
39
|
node?: Node;
|
|
36
40
|
id?: string;
|
|
37
41
|
layoutParts?: LayoutParts;
|
|
38
42
|
layoutPart?: LayoutPart;
|
|
43
|
+
layoutEntry?: LayoutEntry;
|
|
39
44
|
popoverAnchorId?: string;
|
|
40
45
|
pending?: boolean;
|
|
41
46
|
flatDeck?: boolean;
|
|
42
|
-
actions?: PlankHeadingAction[];
|
|
43
47
|
}) => {
|
|
44
48
|
const { t } = useTranslation(DECK_PLUGIN);
|
|
45
49
|
const { graph } = useGraph();
|
|
46
|
-
const
|
|
50
|
+
const Icon = node?.properties?.icon ?? Placeholder;
|
|
47
51
|
const label = pending
|
|
48
52
|
? t('pending heading')
|
|
49
53
|
: toLocalizedString(node?.properties?.label ?? ['plank heading fallback label', { ns: DECK_PLUGIN }], t);
|
|
@@ -76,11 +80,10 @@ export const NodePlankHeading = ({
|
|
|
76
80
|
<ActionRoot>
|
|
77
81
|
{node ? (
|
|
78
82
|
<PlankHeading.ActionsMenu
|
|
79
|
-
|
|
80
|
-
related={layoutPart === 'complementary'}
|
|
83
|
+
Icon={Icon}
|
|
81
84
|
attendableId={attendableId}
|
|
82
85
|
triggerLabel={t('actions menu label')}
|
|
83
|
-
actions={
|
|
86
|
+
actions={graph.actions(node)}
|
|
84
87
|
onAction={(action) =>
|
|
85
88
|
typeof action.data === 'function' && action.data?.({ node: action as Node, caller: DECK_PLUGIN })
|
|
86
89
|
}
|
|
@@ -90,16 +93,12 @@ export const NodePlankHeading = ({
|
|
|
90
93
|
) : (
|
|
91
94
|
<PlankHeading.Button>
|
|
92
95
|
<span className='sr-only'>{label}</span>
|
|
93
|
-
<Icon
|
|
96
|
+
<Icon {...plankHeadingIconProps} />
|
|
94
97
|
</PlankHeading.Button>
|
|
95
98
|
)}
|
|
96
99
|
</ActionRoot>
|
|
97
100
|
<TextTooltip text={label} onlyWhenTruncating>
|
|
98
|
-
<PlankHeading.Label
|
|
99
|
-
attendableId={attendableId}
|
|
100
|
-
related={layoutPart === 'complementary'}
|
|
101
|
-
{...(pending && { classNames: 'text-description' })}
|
|
102
|
-
>
|
|
101
|
+
<PlankHeading.Label attendableId={node?.id} {...(pending && { classNames: 'text-description' })}>
|
|
103
102
|
{label}
|
|
104
103
|
</PlankHeading.Label>
|
|
105
104
|
</TextTooltip>
|
|
@@ -144,6 +143,7 @@ export const NodePlankHeading = ({
|
|
|
144
143
|
action: NavigationAction.CLOSE,
|
|
145
144
|
data: {
|
|
146
145
|
activeParts: {
|
|
146
|
+
complementary: [`${id}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`],
|
|
147
147
|
[layoutPart]: [id],
|
|
148
148
|
},
|
|
149
149
|
},
|
|
@@ -151,7 +151,7 @@ export const NodePlankHeading = ({
|
|
|
151
151
|
: { action: NavigationAction.ADJUST, data: { type: eventType, layoutCoordinate } },
|
|
152
152
|
);
|
|
153
153
|
}}
|
|
154
|
-
close={
|
|
154
|
+
close={layoutCoordinate?.part === 'complementary' ? 'minify-end' : true}
|
|
155
155
|
/>
|
|
156
156
|
</PlankHeading.Root>
|
|
157
157
|
);
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import { debounce } from '@dxos/async';
|
|
20
20
|
import { useGraph } from '@dxos/plugin-graph';
|
|
21
21
|
import { Button, Tooltip, useTranslation } from '@dxos/react-ui';
|
|
22
|
-
import {
|
|
22
|
+
import { createAttendableAttributes } from '@dxos/react-ui-attention';
|
|
23
23
|
import { Plank as NaturalPlank } from '@dxos/react-ui-deck';
|
|
24
24
|
import { mainIntrinsicSize } from '@dxos/react-ui-theme';
|
|
25
25
|
|
|
@@ -52,7 +52,7 @@ export const Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layou
|
|
|
52
52
|
const rootElement = useRef<HTMLDivElement | null>(null);
|
|
53
53
|
const resizeable = layoutMode === 'deck';
|
|
54
54
|
|
|
55
|
-
const attendableAttrs =
|
|
55
|
+
const attendableAttrs = createAttendableAttributes(entry.id);
|
|
56
56
|
const coordinate: LayoutCoordinate = { part, entryId: entry.id };
|
|
57
57
|
|
|
58
58
|
const size = plankSizing?.[entry.id] as number | undefined;
|
|
@@ -78,7 +78,7 @@ export const Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layou
|
|
|
78
78
|
}, [scrollIntoView, layoutMode]);
|
|
79
79
|
|
|
80
80
|
const isSolo = layoutMode === 'solo' && part === 'solo';
|
|
81
|
-
const isSuppressed =
|
|
81
|
+
const isSuppressed = layoutMode === 'solo' && part !== 'solo';
|
|
82
82
|
|
|
83
83
|
const sizeAttrs = useMainSize();
|
|
84
84
|
|
|
@@ -4,19 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { useMemo } from 'react';
|
|
6
6
|
|
|
7
|
-
import { type LayoutParts, openIds, Surface } from '@dxos/app-framework';
|
|
7
|
+
import { type Attention, type LayoutParts, openIds, Surface } from '@dxos/app-framework';
|
|
8
8
|
import { Main } from '@dxos/react-ui';
|
|
9
|
-
import { useAttended } from '@dxos/react-ui-attention';
|
|
10
9
|
|
|
11
10
|
import { useLayout } from '../LayoutContext';
|
|
12
11
|
|
|
13
12
|
export type SidebarProps = {
|
|
13
|
+
attention: Attention;
|
|
14
14
|
layoutParts: LayoutParts;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export const Sidebar = ({ layoutParts }: SidebarProps) => {
|
|
17
|
+
export const Sidebar = ({ attention, layoutParts }: SidebarProps) => {
|
|
18
18
|
const { layoutMode, popoverAnchorId } = useLayout();
|
|
19
|
-
const attended = useAttended();
|
|
20
19
|
|
|
21
20
|
const activeIds = useMemo(() => {
|
|
22
21
|
if (layoutMode === 'solo') {
|
|
@@ -32,9 +31,9 @@ export const Sidebar = ({ layoutParts }: SidebarProps) => {
|
|
|
32
31
|
() => ({
|
|
33
32
|
popoverAnchorId,
|
|
34
33
|
activeIds,
|
|
35
|
-
attended,
|
|
34
|
+
attended: attention.attended,
|
|
36
35
|
}),
|
|
37
|
-
[popoverAnchorId, activeIds, attended],
|
|
36
|
+
[popoverAnchorId, activeIds, attention.attended],
|
|
38
37
|
);
|
|
39
38
|
return (
|
|
40
39
|
<Main.NavigationSidebar>
|
|
@@ -5,23 +5,14 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
7
|
import { Surface } from '@dxos/app-framework';
|
|
8
|
-
import { mainPadding,
|
|
8
|
+
import { mainPadding, mx } from '@dxos/react-ui-theme';
|
|
9
9
|
|
|
10
10
|
import { useMainSize } from '../../hooks';
|
|
11
11
|
|
|
12
|
-
export const StatusBar = (
|
|
12
|
+
export const StatusBar = () => {
|
|
13
13
|
const sizeAttrs = useMainSize();
|
|
14
14
|
return (
|
|
15
|
-
<div
|
|
16
|
-
role='none'
|
|
17
|
-
{...sizeAttrs}
|
|
18
|
-
className={mx(
|
|
19
|
-
'fixed flex justify-between block-end-0 inset-inline-0 items-center border-bs border-separator z-[2]',
|
|
20
|
-
mainPadding,
|
|
21
|
-
mainPaddingTransitions,
|
|
22
|
-
)}
|
|
23
|
-
>
|
|
24
|
-
<div role='none'>{showHints && <Surface role='hints' limit={1} />}</div>
|
|
15
|
+
<div role='none' {...sizeAttrs} className={mx('fixed block-end-0 inset-inline-0 z-[2]', mainPadding)}>
|
|
25
16
|
<Surface role='status-bar' limit={1} />
|
|
26
17
|
</div>
|
|
27
18
|
);
|
|
@@ -61,22 +61,25 @@ export const LayoutSettings = ({ settings }: { settings: DeckSettingsProps }) =>
|
|
|
61
61
|
</Select.Portal>
|
|
62
62
|
</Select.Root>
|
|
63
63
|
</SettingsValue>
|
|
64
|
-
<SettingsValue label={t('settings show
|
|
65
|
-
<Input.Switch checked={settings.
|
|
64
|
+
<SettingsValue label={t('settings show footer label')}>
|
|
65
|
+
<Input.Switch checked={settings.showFooter} onCheckedChange={(checked) => (settings.showFooter = !!checked)} />
|
|
66
66
|
</SettingsValue>
|
|
67
67
|
{!isSocket && (
|
|
68
68
|
<SettingsValue label={t('settings native redirect label')}>
|
|
69
69
|
<Input.Switch
|
|
70
70
|
checked={settings.enableNativeRedirect}
|
|
71
|
-
onCheckedChange={(checked) => (settings.enableNativeRedirect = checked)}
|
|
71
|
+
onCheckedChange={(checked) => (settings.enableNativeRedirect = !!checked)}
|
|
72
72
|
/>
|
|
73
73
|
</SettingsValue>
|
|
74
74
|
)}
|
|
75
75
|
<SettingsValue label={t('settings custom slots')}>
|
|
76
|
-
<Input.Switch
|
|
76
|
+
<Input.Switch
|
|
77
|
+
checked={settings.customSlots}
|
|
78
|
+
onCheckedChange={(checked) => (settings.customSlots = !!checked)}
|
|
79
|
+
/>
|
|
77
80
|
</SettingsValue>
|
|
78
81
|
<SettingsValue label={t('settings flat deck')}>
|
|
79
|
-
<Input.Switch checked={settings.flatDeck} onCheckedChange={(checked) => (settings.flatDeck = checked)} />
|
|
82
|
+
<Input.Switch checked={settings.flatDeck} onCheckedChange={(checked) => (settings.flatDeck = !!checked)} />
|
|
80
83
|
</SettingsValue>
|
|
81
84
|
</>
|
|
82
85
|
);
|
package/src/hooks/useNode.ts
CHANGED
|
@@ -16,13 +16,9 @@ import { type Graph, type Node } from '@dxos/plugin-graph';
|
|
|
16
16
|
*/
|
|
17
17
|
// TODO(wittjosiah): Factor out.
|
|
18
18
|
export const useNode = <T = any>(graph: Graph, id?: string, timeout?: number): Node<T> | undefined => {
|
|
19
|
-
const [nodeState, setNodeState] = useState<Node<T> | undefined>(id ? graph.findNode(id
|
|
19
|
+
const [nodeState, setNodeState] = useState<Node<T> | undefined>(id ? graph.findNode(id) : undefined);
|
|
20
20
|
|
|
21
21
|
useEffect(() => {
|
|
22
|
-
if (!id && nodeState) {
|
|
23
|
-
setNodeState(undefined);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
22
|
if (nodeState?.id === id || !id) {
|
|
27
23
|
return;
|
|
28
24
|
}
|
package/src/layout.ts
CHANGED
package/src/meta.ts
CHANGED
package/src/translations.ts
CHANGED
|
@@ -16,7 +16,7 @@ export default [
|
|
|
16
16
|
'content fallback description':
|
|
17
17
|
'No plugin had a response for the address you navigated to. Double-check the URL, and ensure you’ve enabled a plugin that supports the object.',
|
|
18
18
|
'toggle fullscreen label': 'Toggle fullscreen',
|
|
19
|
-
'settings show
|
|
19
|
+
'settings show footer label': 'Show footer (experimental)',
|
|
20
20
|
'settings native redirect label': 'Enable native url redirect (experimental)',
|
|
21
21
|
'settings custom slots': 'Theme option (experimental)',
|
|
22
22
|
'settings new plank position start label': 'Start',
|
|
@@ -41,8 +41,6 @@ export default [
|
|
|
41
41
|
'settings overscroll centering label': 'Centering',
|
|
42
42
|
'settings overscroll none label': 'None',
|
|
43
43
|
'settings flat deck': 'Flatten deck appearance',
|
|
44
|
-
'comments label': 'Show Comments',
|
|
45
|
-
'settings label': 'Show Settings',
|
|
46
44
|
},
|
|
47
45
|
},
|
|
48
46
|
},
|
package/src/types.ts
CHANGED
|
@@ -20,7 +20,7 @@ export const OverscrollOptions = ['none', 'centering'] as const;
|
|
|
20
20
|
export type Overscroll = (typeof OverscrollOptions)[number];
|
|
21
21
|
|
|
22
22
|
export type DeckSettingsProps = {
|
|
23
|
-
|
|
23
|
+
showFooter: boolean;
|
|
24
24
|
customSlots: boolean;
|
|
25
25
|
flatDeck: boolean;
|
|
26
26
|
enableNativeRedirect: boolean;
|
package/src/util/overscroll.ts
CHANGED
|
@@ -56,9 +56,9 @@ export const calculateOverscroll = (
|
|
|
56
56
|
plankSizing: Record<string, number>,
|
|
57
57
|
sidebarOpen: boolean,
|
|
58
58
|
complementarySidebarOpen: boolean,
|
|
59
|
-
): Pick<CSSProperties, '
|
|
59
|
+
): Pick<CSSProperties, 'paddingLeft' | 'paddingRight'> | undefined => {
|
|
60
60
|
if (!planks?.length) {
|
|
61
|
-
return
|
|
61
|
+
return;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// TODO(Zan): Move complementary sidebar size (360px), sidebar size (270px), plank resize handle size (20px) to CSS variables.
|
|
@@ -73,7 +73,7 @@ export const calculateOverscroll = (
|
|
|
73
73
|
const plankSize = getPlankSize(plank.id);
|
|
74
74
|
const overscrollPadding = `max(0px, calc(((100dvw - ${sidebarWidth} - ${complementarySidebarWidth} - (${plankSize} + 20px)) / 2)))`;
|
|
75
75
|
|
|
76
|
-
return {
|
|
76
|
+
return { paddingLeft: overscrollPadding, paddingRight: overscrollPadding };
|
|
77
77
|
} else {
|
|
78
78
|
// Center the plank on the screen.
|
|
79
79
|
const first = planks[0];
|
|
@@ -83,8 +83,8 @@ export const calculateOverscroll = (
|
|
|
83
83
|
const lastSize = getPlankSize(last.id);
|
|
84
84
|
|
|
85
85
|
return {
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
paddingLeft: `max(0px, calc(((100dvw - (${firstSize} + 20px)) / 2) - ${sidebarWidth}))`,
|
|
87
|
+
paddingRight: `max(0px, calc(((100dvw - (${lastSize} + 20px)) / 2) - ${complementarySidebarWidth}))`,
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/meta.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type PluginMeta } from '@dxos/app-framework';\n\nexport const DECK_PLUGIN = 'dxos.org/plugin/deck';\n\nexport default {\n id: DECK_PLUGIN,\n name: 'Deck',\n} satisfies PluginMeta;\n"],
|
|
5
|
-
"mappings": ";AAMO,IAAMA,cAAc;AAE3B,IAAA,eAAe;EACbC,IAAID;EACJE,MAAM;AACR;",
|
|
6
|
-
"names": ["DECK_PLUGIN", "id", "name"]
|
|
7
|
-
}
|