Skip to content

Commit d089470

Browse files
committed
1 parent 16bb00e commit d089470

File tree

17 files changed

+222
-58
lines changed

17 files changed

+222
-58
lines changed

packages/frontend/component/src/ui/skeleton/index.css.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const waveKeyframes = keyframes({
2929
export const root = style({
3030
display: 'block',
3131
width: '100%',
32+
maxWidth: '100%',
3233
height: defaultHeight,
3334
flexShrink: 0,
3435
/**
@@ -51,7 +52,7 @@ export const variant = {
5152
borderRadius: '50%',
5253
}),
5354
rectangular: style({
54-
borderRadius: '0px',
55+
borderRadius: '4px',
5556
}),
5657
rounded: style({
5758
borderRadius: '8px',

packages/frontend/component/src/ui/skeleton/skeleton.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const Skeleton = ({
1616
variant = 'text',
1717
children,
1818

19+
flex,
1920
width: _width,
2021
height: _height,
2122
style: _style,
@@ -29,6 +30,7 @@ export const Skeleton = ({
2930
const style = {
3031
width,
3132
height,
33+
flex,
3234
..._style,
3335
};
3436

packages/frontend/component/src/ui/skeleton/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ export interface SkeletonProps
2828
* Number values are treated as pixels.
2929
*/
3030
height?: number | string;
31+
32+
/**
33+
* Flex of the skeleton.
34+
*/
35+
flex?: number | string;
3136
}
3237

3338
export type PickStringFromUnion<T> = T extends string ? T : never;

packages/frontend/core/src/components/affine/app-container.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import type { ReactElement } from 'react';
1+
import type { PropsWithChildren, ReactElement } from 'react';
22

33
import { useAppSettingHelper } from '../../hooks/affine/use-app-setting-helper';
44
import { AppSidebarFallback } from '../app-sidebar';
55
import type { WorkspaceRootProps } from '../workspace';
66
import {
77
AppContainer as AppContainerWithoutSettings,
8-
MainContainer,
8+
MainContainerFallback,
99
} from '../workspace';
1010

1111
export const AppContainer = (props: WorkspaceRootProps) => {
@@ -24,11 +24,16 @@ export const AppContainer = (props: WorkspaceRootProps) => {
2424
);
2525
};
2626

27-
export const AppFallback = (): ReactElement => {
27+
export const AppFallback = ({
28+
className,
29+
children,
30+
}: PropsWithChildren<{
31+
className?: string;
32+
}>): ReactElement => {
2833
return (
29-
<AppContainer>
34+
<AppContainer className={className}>
3035
<AppSidebarFallback />
31-
<MainContainer />
36+
<MainContainerFallback>{children}</MainContainerFallback>
3237
</AppContainer>
3338
);
3439
};
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
11
import { style } from '@vanilla-extract/css';
2-
export const fallbackStyle = style({
3-
margin: '4px 16px',
2+
3+
export const fallback = style({
4+
padding: '4px 20px',
45
height: '100%',
6+
overflow: 'clip',
57
});
6-
export const fallbackHeaderStyle = style({
8+
9+
export const fallbackHeader = style({
710
width: '100%',
811
display: 'flex',
912
alignItems: 'center',
1013
flexDirection: 'row',
1114
gap: '8px',
15+
overflow: 'hidden',
16+
height: '52px',
17+
});
18+
19+
export const spacer = style({
20+
flex: 1,
21+
});
22+
23+
export const fallbackBody = style({
24+
display: 'flex',
25+
flexDirection: 'column',
26+
gap: '42px',
27+
marginTop: '42px',
28+
});
29+
30+
export const fallbackGroupItems = style({
31+
display: 'flex',
32+
flexDirection: 'column',
33+
gap: '16px',
34+
});
35+
36+
export const fallbackItemHeader = style({
37+
transform: 'translateX(-10px)',
1238
});

packages/frontend/core/src/components/app-sidebar/index.tsx

Lines changed: 88 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Skeleton } from '@affine/component';
22
import { ResizePanel } from '@affine/component/resize-panel';
3+
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
4+
import { NavigateContext } from '@affine/core/hooks/use-navigate-helper';
35
import { useServiceOptional, WorkspaceService } from '@toeverything/infra';
46
import { useAtom, useAtomValue } from 'jotai';
57
import { debounce } from 'lodash-es';
68
import type { PropsWithChildren, ReactElement } from 'react';
7-
import { useEffect } from 'react';
9+
import { useContext, useEffect, useMemo } from 'react';
810

911
import { WorkspaceNavigator } from '../workspace-selector';
10-
import { fallbackHeaderStyle, fallbackStyle } from './fallback.css';
12+
import * as styles from './fallback.css';
1113
import {
1214
floatingMaxWidth,
1315
navBodyStyle,
@@ -25,11 +27,6 @@ import {
2527
} from './index.jotai';
2628
import { SidebarHeader } from './sidebar-header';
2729

28-
export type AppSidebarProps = PropsWithChildren<{
29-
clientBorder?: boolean;
30-
translucentUI?: boolean;
31-
}>;
32-
3330
export type History = {
3431
stack: string[];
3532
current: number;
@@ -38,10 +35,11 @@ export type History = {
3835
const MAX_WIDTH = 480;
3936
const MIN_WIDTH = 248;
4037

41-
export function AppSidebar({
42-
children,
43-
clientBorder,
44-
}: AppSidebarProps): ReactElement {
38+
export function AppSidebar({ children }: PropsWithChildren) {
39+
const { appSettings } = useAppSettingHelper();
40+
41+
const clientBorder = appSettings.clientBorder;
42+
4543
const [open, setOpen] = useAtom(appSidebarOpenAtom);
4644
const [width, setWidth] = useAtom(appSidebarWidthAtom);
4745
const [floating, setFloating] = useAtom(appSidebarFloatingAtom);
@@ -122,35 +120,96 @@ export function AppSidebar({
122120
);
123121
}
124122

123+
const FallbackHeader = () => {
124+
// if navigate is not defined, it is rendered outside of router
125+
// WorkspaceNavigator requires navigate context
126+
// todo: refactor
127+
const navigate = useContext(NavigateContext);
128+
129+
const currentWorkspace = useServiceOptional(WorkspaceService);
130+
return (
131+
<div className={styles.fallbackHeader}>
132+
{!currentWorkspace && navigate ? (
133+
<WorkspaceNavigator
134+
showSettingsButton
135+
showSyncStatus
136+
showEnableCloudButton
137+
/>
138+
) : (
139+
<>
140+
<Skeleton variant="rectangular" width={32} height={32} />
141+
<Skeleton variant="rectangular" width={150} height={32} flex={1} />
142+
<Skeleton variant="circular" width={25} height={25} />
143+
</>
144+
)}
145+
</div>
146+
);
147+
};
148+
149+
const randomWidth = () => {
150+
return Math.floor(Math.random() * 200) + 100;
151+
};
152+
153+
const RandomBar = ({ className }: { className?: string }) => {
154+
const width = useMemo(() => randomWidth(), []);
155+
return (
156+
<Skeleton
157+
variant="rectangular"
158+
width={width}
159+
height={16}
160+
className={className}
161+
/>
162+
);
163+
};
164+
165+
const RandomBars = ({ count, header }: { count: number; header?: boolean }) => {
166+
return (
167+
<div className={styles.fallbackGroupItems}>
168+
{header ? (
169+
<Skeleton
170+
className={styles.fallbackItemHeader}
171+
variant="rectangular"
172+
width={50}
173+
height={16}
174+
/>
175+
) : null}
176+
{Array.from({ length: count }).map((_, index) => (
177+
<RandomBar key={index} />
178+
))}
179+
</div>
180+
);
181+
};
182+
183+
const FallbackBody = () => {
184+
return (
185+
<div className={styles.fallbackBody}>
186+
<RandomBars count={3} />
187+
<RandomBars count={4} header />
188+
<RandomBars count={4} header />
189+
<RandomBars count={3} header />
190+
</div>
191+
);
192+
};
193+
125194
export const AppSidebarFallback = (): ReactElement | null => {
126195
const width = useAtomValue(appSidebarWidthAtom);
196+
const { appSettings } = useAppSettingHelper();
197+
const clientBorder = appSettings.clientBorder;
198+
const hasRightBorder = !environment.isElectron && !clientBorder;
127199

128-
const currentWorkspace = useServiceOptional(WorkspaceService);
129200
return (
130201
<div
131202
style={{ width }}
132203
className={navWrapperStyle}
133-
data-has-border
204+
data-has-border={hasRightBorder}
134205
data-open="true"
135206
>
136207
<nav className={navStyle}>
137-
<div className={navHeaderStyle} data-open="true" />
208+
{!environment.isElectron ? <div className={navHeaderStyle} /> : null}
138209
<div className={navBodyStyle}>
139-
<div className={fallbackStyle}>
140-
<div className={fallbackHeaderStyle}>
141-
{currentWorkspace ? (
142-
<WorkspaceNavigator
143-
showSettingsButton
144-
showSyncStatus
145-
showEnableCloudButton
146-
/>
147-
) : (
148-
<>
149-
<Skeleton variant="circular" width={40} height={40} />
150-
<Skeleton variant="rectangular" width={150} height={40} />
151-
</>
152-
)}
153-
</div>
210+
<div className={styles.fallback}>
211+
<FallbackHeader />
212+
<FallbackBody />
154213
</div>
155214
</div>
156215
</nav>

packages/frontend/core/src/components/root-app-sidebar/index.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import { useSetAtom } from 'jotai';
2929
import type { MouseEvent, ReactElement } from 'react';
3030
import { useCallback, useEffect } from 'react';
3131

32-
import { useAppSettingHelper } from '../../hooks/affine/use-app-setting-helper';
3332
import { WorkbenchService } from '../../modules/workbench';
3433
import {
3534
AddPageButton,
@@ -84,7 +83,6 @@ export const RootAppSidebar = (): ReactElement => {
8483
CMDKQuickSearchService,
8584
});
8685
const currentWorkspace = workspaceService.workspace;
87-
const { appSettings } = useAppSettingHelper();
8886
const docCollection = currentWorkspace.docCollection;
8987
const t = useI18n();
9088
const workbench = workbenchService.workbench;
@@ -141,10 +139,7 @@ export const RootAppSidebar = (): ReactElement => {
141139
}, [setOpenSettingModalAtom]);
142140

143141
return (
144-
<AppSidebar
145-
clientBorder={appSettings.clientBorder}
146-
translucentUI={appSettings.enableBlurBackground}
147-
>
142+
<AppSidebar>
148143
<SidebarContainer>
149144
<div className={workspaceAndUserWrapper}>
150145
<div className={workspaceWrapper}>

packages/frontend/core/src/components/workspace/index.css.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { cssVar, lightCssVariables } from '@toeverything/theme';
22
import { globalStyle, style } from '@vanilla-extract/css';
3+
34
export const appStyle = style({
45
width: '100%',
56
position: 'relative',
@@ -98,3 +99,11 @@ export const toolStyle = style({
9899
},
99100
},
100101
});
102+
103+
export const fallbackRootStyle = style({
104+
paddingTop: 52,
105+
display: 'flex',
106+
flex: 1,
107+
width: '100%',
108+
height: '100%',
109+
});

packages/frontend/core/src/components/workspace/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { appStyle, mainContainerStyle, toolStyle } from './index.css';
1515

1616
export type WorkspaceRootProps = PropsWithChildren<{
1717
resizing?: boolean;
18+
className?: string;
1819
useNoisyBackground?: boolean;
1920
useBlurBackground?: boolean;
2021
}>;
@@ -24,14 +25,15 @@ export const AppContainer = ({
2425
useNoisyBackground,
2526
useBlurBackground,
2627
children,
28+
className,
2729
...rest
2830
}: WorkspaceRootProps) => {
2931
const noisyBackground = useNoisyBackground && environment.isElectron;
3032
const blurBackground = environment.isElectron && useBlurBackground;
3133
return (
3234
<div
3335
{...rest}
34-
className={clsx(appStyle, {
36+
className={clsx(appStyle, className, {
3537
'noisy-background': noisyBackground,
3638
'blur-background': blurBackground,
3739
})}
@@ -71,6 +73,11 @@ export const MainContainer = forwardRef<
7173

7274
MainContainer.displayName = 'MainContainer';
7375

76+
export const MainContainerFallback = ({ children }: PropsWithChildren) => {
77+
// todo: default app fallback?
78+
return <MainContainer>{children}</MainContainer>;
79+
};
80+
7481
export const ToolContainer = (
7582
props: PropsWithChildren<{ className?: string }>
7683
): ReactElement => {

0 commit comments

Comments
 (0)