mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-09 21:25:45 +08:00
feat(electron): electron shell skeleton (#8127)
fix AF-1331
<div class='graphite__hidden'>
<div>🎥 Video uploaded on Graphite:</div>
<a href="https://app.graphite.dev/media/video/T2klNLEk0wxLh4NRDzhk/e09203aa-f143-42f8-bd39-e5078d07ada2.mp4">
<img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/T2klNLEk0wxLh4NRDzhk/e09203aa-f143-42f8-bd39-e5078d07ada2.mp4">
</a>
</div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/T2klNLEk0wxLh4NRDzhk/e09203aa-f143-42f8-bd39-e5078d07ada2.mp4">1.mp4</video>
missing
- per split view skeleton
- per route skeleton
This commit is contained in:
@@ -29,6 +29,7 @@ const waveKeyframes = keyframes({
|
|||||||
export const root = style({
|
export const root = style({
|
||||||
display: 'block',
|
display: 'block',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
maxWidth: '100%',
|
||||||
height: defaultHeight,
|
height: defaultHeight,
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
/**
|
/**
|
||||||
@@ -51,7 +52,7 @@ export const variant = {
|
|||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
}),
|
}),
|
||||||
rectangular: style({
|
rectangular: style({
|
||||||
borderRadius: '0px',
|
borderRadius: '4px',
|
||||||
}),
|
}),
|
||||||
rounded: style({
|
rounded: style({
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export const Skeleton = ({
|
|||||||
variant = 'text',
|
variant = 'text',
|
||||||
children,
|
children,
|
||||||
|
|
||||||
|
flex,
|
||||||
width: _width,
|
width: _width,
|
||||||
height: _height,
|
height: _height,
|
||||||
style: _style,
|
style: _style,
|
||||||
@@ -29,6 +30,7 @@ export const Skeleton = ({
|
|||||||
const style = {
|
const style = {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
flex,
|
||||||
..._style,
|
..._style,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ export interface SkeletonProps
|
|||||||
* Number values are treated as pixels.
|
* Number values are treated as pixels.
|
||||||
*/
|
*/
|
||||||
height?: number | string;
|
height?: number | string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flex of the skeleton.
|
||||||
|
*/
|
||||||
|
flex?: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PickStringFromUnion<T> = T extends string ? T : never;
|
export type PickStringFromUnion<T> = T extends string ? T : never;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { ReactElement } from 'react';
|
import type { PropsWithChildren, ReactElement } from 'react';
|
||||||
|
|
||||||
import { useAppSettingHelper } from '../../hooks/affine/use-app-setting-helper';
|
import { useAppSettingHelper } from '../../hooks/affine/use-app-setting-helper';
|
||||||
import { AppSidebarFallback } from '../app-sidebar';
|
import { AppSidebarFallback } from '../app-sidebar';
|
||||||
import type { WorkspaceRootProps } from '../workspace';
|
import type { WorkspaceRootProps } from '../workspace';
|
||||||
import {
|
import {
|
||||||
AppContainer as AppContainerWithoutSettings,
|
AppContainer as AppContainerWithoutSettings,
|
||||||
MainContainer,
|
MainContainerFallback,
|
||||||
} from '../workspace';
|
} from '../workspace';
|
||||||
|
|
||||||
export const AppContainer = (props: WorkspaceRootProps) => {
|
export const AppContainer = (props: WorkspaceRootProps) => {
|
||||||
@@ -24,11 +24,16 @@ export const AppContainer = (props: WorkspaceRootProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AppFallback = (): ReactElement => {
|
export const AppFallback = ({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
}: PropsWithChildren<{
|
||||||
|
className?: string;
|
||||||
|
}>): ReactElement => {
|
||||||
return (
|
return (
|
||||||
<AppContainer>
|
<AppContainer className={className}>
|
||||||
<AppSidebarFallback />
|
<AppSidebarFallback />
|
||||||
<MainContainer />
|
<MainContainerFallback>{children}</MainContainerFallback>
|
||||||
</AppContainer>
|
</AppContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,38 @@
|
|||||||
import { style } from '@vanilla-extract/css';
|
import { style } from '@vanilla-extract/css';
|
||||||
export const fallbackStyle = style({
|
|
||||||
margin: '4px 16px',
|
export const fallback = style({
|
||||||
|
padding: '4px 20px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
overflow: 'clip',
|
||||||
});
|
});
|
||||||
export const fallbackHeaderStyle = style({
|
|
||||||
|
export const fallbackHeader = style({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
gap: '8px',
|
gap: '8px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
height: '52px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const spacer = style({
|
||||||
|
flex: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fallbackBody = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '42px',
|
||||||
|
marginTop: '42px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fallbackGroupItems = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '16px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fallbackItemHeader = style({
|
||||||
|
transform: 'translateX(-10px)',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { Skeleton } from '@affine/component';
|
import { Skeleton } from '@affine/component';
|
||||||
import { ResizePanel } from '@affine/component/resize-panel';
|
import { ResizePanel } from '@affine/component/resize-panel';
|
||||||
|
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||||
|
import { NavigateContext } from '@affine/core/hooks/use-navigate-helper';
|
||||||
import { useServiceOptional, WorkspaceService } from '@toeverything/infra';
|
import { useServiceOptional, WorkspaceService } from '@toeverything/infra';
|
||||||
import { useAtom, useAtomValue } from 'jotai';
|
import { useAtom, useAtomValue } from 'jotai';
|
||||||
import { debounce } from 'lodash-es';
|
import { debounce } from 'lodash-es';
|
||||||
import type { PropsWithChildren, ReactElement } from 'react';
|
import type { PropsWithChildren, ReactElement } from 'react';
|
||||||
import { useEffect } from 'react';
|
import { useContext, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import { WorkspaceNavigator } from '../workspace-selector';
|
import { WorkspaceNavigator } from '../workspace-selector';
|
||||||
import { fallbackHeaderStyle, fallbackStyle } from './fallback.css';
|
import * as styles from './fallback.css';
|
||||||
import {
|
import {
|
||||||
floatingMaxWidth,
|
floatingMaxWidth,
|
||||||
navBodyStyle,
|
navBodyStyle,
|
||||||
@@ -25,11 +27,6 @@ import {
|
|||||||
} from './index.jotai';
|
} from './index.jotai';
|
||||||
import { SidebarHeader } from './sidebar-header';
|
import { SidebarHeader } from './sidebar-header';
|
||||||
|
|
||||||
export type AppSidebarProps = PropsWithChildren<{
|
|
||||||
clientBorder?: boolean;
|
|
||||||
translucentUI?: boolean;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type History = {
|
export type History = {
|
||||||
stack: string[];
|
stack: string[];
|
||||||
current: number;
|
current: number;
|
||||||
@@ -38,10 +35,11 @@ export type History = {
|
|||||||
const MAX_WIDTH = 480;
|
const MAX_WIDTH = 480;
|
||||||
const MIN_WIDTH = 248;
|
const MIN_WIDTH = 248;
|
||||||
|
|
||||||
export function AppSidebar({
|
export function AppSidebar({ children }: PropsWithChildren) {
|
||||||
children,
|
const { appSettings } = useAppSettingHelper();
|
||||||
clientBorder,
|
|
||||||
}: AppSidebarProps): ReactElement {
|
const clientBorder = appSettings.clientBorder;
|
||||||
|
|
||||||
const [open, setOpen] = useAtom(appSidebarOpenAtom);
|
const [open, setOpen] = useAtom(appSidebarOpenAtom);
|
||||||
const [width, setWidth] = useAtom(appSidebarWidthAtom);
|
const [width, setWidth] = useAtom(appSidebarWidthAtom);
|
||||||
const [floating, setFloating] = useAtom(appSidebarFloatingAtom);
|
const [floating, setFloating] = useAtom(appSidebarFloatingAtom);
|
||||||
@@ -122,35 +120,96 @@ export function AppSidebar({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppSidebarFallback = (): ReactElement | null => {
|
const FallbackHeader = () => {
|
||||||
const width = useAtomValue(appSidebarWidthAtom);
|
// if navigate is not defined, it is rendered outside of router
|
||||||
|
// WorkspaceNavigator requires navigate context
|
||||||
|
// todo: refactor
|
||||||
|
const navigate = useContext(NavigateContext);
|
||||||
|
|
||||||
const currentWorkspace = useServiceOptional(WorkspaceService);
|
const currentWorkspace = useServiceOptional(WorkspaceService);
|
||||||
|
return (
|
||||||
|
<div className={styles.fallbackHeader}>
|
||||||
|
{!currentWorkspace && navigate ? (
|
||||||
|
<WorkspaceNavigator
|
||||||
|
showSettingsButton
|
||||||
|
showSyncStatus
|
||||||
|
showEnableCloudButton
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Skeleton variant="rectangular" width={32} height={32} />
|
||||||
|
<Skeleton variant="rectangular" width={150} height={32} flex={1} />
|
||||||
|
<Skeleton variant="circular" width={25} height={25} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const randomWidth = () => {
|
||||||
|
return Math.floor(Math.random() * 200) + 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
const RandomBar = ({ className }: { className?: string }) => {
|
||||||
|
const width = useMemo(() => randomWidth(), []);
|
||||||
|
return (
|
||||||
|
<Skeleton
|
||||||
|
variant="rectangular"
|
||||||
|
width={width}
|
||||||
|
height={16}
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RandomBars = ({ count, header }: { count: number; header?: boolean }) => {
|
||||||
|
return (
|
||||||
|
<div className={styles.fallbackGroupItems}>
|
||||||
|
{header ? (
|
||||||
|
<Skeleton
|
||||||
|
className={styles.fallbackItemHeader}
|
||||||
|
variant="rectangular"
|
||||||
|
width={50}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{Array.from({ length: count }).map((_, index) => (
|
||||||
|
<RandomBar key={index} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FallbackBody = () => {
|
||||||
|
return (
|
||||||
|
<div className={styles.fallbackBody}>
|
||||||
|
<RandomBars count={3} />
|
||||||
|
<RandomBars count={4} header />
|
||||||
|
<RandomBars count={4} header />
|
||||||
|
<RandomBars count={3} header />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AppSidebarFallback = (): ReactElement | null => {
|
||||||
|
const width = useAtomValue(appSidebarWidthAtom);
|
||||||
|
const { appSettings } = useAppSettingHelper();
|
||||||
|
const clientBorder = appSettings.clientBorder;
|
||||||
|
const hasRightBorder = !environment.isElectron && !clientBorder;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ width }}
|
style={{ width }}
|
||||||
className={navWrapperStyle}
|
className={navWrapperStyle}
|
||||||
data-has-border
|
data-has-border={hasRightBorder}
|
||||||
data-open="true"
|
data-open="true"
|
||||||
>
|
>
|
||||||
<nav className={navStyle}>
|
<nav className={navStyle}>
|
||||||
<div className={navHeaderStyle} data-open="true" />
|
{!environment.isElectron ? <div className={navHeaderStyle} /> : null}
|
||||||
<div className={navBodyStyle}>
|
<div className={navBodyStyle}>
|
||||||
<div className={fallbackStyle}>
|
<div className={styles.fallback}>
|
||||||
<div className={fallbackHeaderStyle}>
|
<FallbackHeader />
|
||||||
{currentWorkspace ? (
|
<FallbackBody />
|
||||||
<WorkspaceNavigator
|
|
||||||
showSettingsButton
|
|
||||||
showSyncStatus
|
|
||||||
showEnableCloudButton
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Skeleton variant="circular" width={40} height={40} />
|
|
||||||
<Skeleton variant="rectangular" width={150} height={40} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import { useSetAtom } from 'jotai';
|
|||||||
import type { MouseEvent, ReactElement } from 'react';
|
import type { MouseEvent, ReactElement } from 'react';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
import { useAppSettingHelper } from '../../hooks/affine/use-app-setting-helper';
|
|
||||||
import { WorkbenchService } from '../../modules/workbench';
|
import { WorkbenchService } from '../../modules/workbench';
|
||||||
import {
|
import {
|
||||||
AddPageButton,
|
AddPageButton,
|
||||||
@@ -84,7 +83,6 @@ export const RootAppSidebar = (): ReactElement => {
|
|||||||
CMDKQuickSearchService,
|
CMDKQuickSearchService,
|
||||||
});
|
});
|
||||||
const currentWorkspace = workspaceService.workspace;
|
const currentWorkspace = workspaceService.workspace;
|
||||||
const { appSettings } = useAppSettingHelper();
|
|
||||||
const docCollection = currentWorkspace.docCollection;
|
const docCollection = currentWorkspace.docCollection;
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const workbench = workbenchService.workbench;
|
const workbench = workbenchService.workbench;
|
||||||
@@ -141,10 +139,7 @@ export const RootAppSidebar = (): ReactElement => {
|
|||||||
}, [setOpenSettingModalAtom]);
|
}, [setOpenSettingModalAtom]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppSidebar
|
<AppSidebar>
|
||||||
clientBorder={appSettings.clientBorder}
|
|
||||||
translucentUI={appSettings.enableBlurBackground}
|
|
||||||
>
|
|
||||||
<SidebarContainer>
|
<SidebarContainer>
|
||||||
<div className={workspaceAndUserWrapper}>
|
<div className={workspaceAndUserWrapper}>
|
||||||
<div className={workspaceWrapper}>
|
<div className={workspaceWrapper}>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { cssVar, lightCssVariables } from '@toeverything/theme';
|
import { cssVar, lightCssVariables } from '@toeverything/theme';
|
||||||
import { globalStyle, style } from '@vanilla-extract/css';
|
import { globalStyle, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
export const appStyle = style({
|
export const appStyle = style({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@@ -98,3 +99,11 @@ export const toolStyle = style({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const fallbackRootStyle = style({
|
||||||
|
paddingTop: 52,
|
||||||
|
display: 'flex',
|
||||||
|
flex: 1,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
});
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { appStyle, mainContainerStyle, toolStyle } from './index.css';
|
|||||||
|
|
||||||
export type WorkspaceRootProps = PropsWithChildren<{
|
export type WorkspaceRootProps = PropsWithChildren<{
|
||||||
resizing?: boolean;
|
resizing?: boolean;
|
||||||
|
className?: string;
|
||||||
useNoisyBackground?: boolean;
|
useNoisyBackground?: boolean;
|
||||||
useBlurBackground?: boolean;
|
useBlurBackground?: boolean;
|
||||||
}>;
|
}>;
|
||||||
@@ -24,6 +25,7 @@ export const AppContainer = ({
|
|||||||
useNoisyBackground,
|
useNoisyBackground,
|
||||||
useBlurBackground,
|
useBlurBackground,
|
||||||
children,
|
children,
|
||||||
|
className,
|
||||||
...rest
|
...rest
|
||||||
}: WorkspaceRootProps) => {
|
}: WorkspaceRootProps) => {
|
||||||
const noisyBackground = useNoisyBackground && environment.isElectron;
|
const noisyBackground = useNoisyBackground && environment.isElectron;
|
||||||
@@ -31,7 +33,7 @@ export const AppContainer = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...rest}
|
{...rest}
|
||||||
className={clsx(appStyle, {
|
className={clsx(appStyle, className, {
|
||||||
'noisy-background': noisyBackground,
|
'noisy-background': noisyBackground,
|
||||||
'blur-background': blurBackground,
|
'blur-background': blurBackground,
|
||||||
})}
|
})}
|
||||||
@@ -71,6 +73,11 @@ export const MainContainer = forwardRef<
|
|||||||
|
|
||||||
MainContainer.displayName = 'MainContainer';
|
MainContainer.displayName = 'MainContainer';
|
||||||
|
|
||||||
|
export const MainContainerFallback = ({ children }: PropsWithChildren) => {
|
||||||
|
// todo: default app fallback?
|
||||||
|
return <MainContainer>{children}</MainContainer>;
|
||||||
|
};
|
||||||
|
|
||||||
export const ToolContainer = (
|
export const ToolContainer = (
|
||||||
props: PropsWithChildren<{ className?: string }>
|
props: PropsWithChildren<{ className?: string }>
|
||||||
): ReactElement => {
|
): ReactElement => {
|
||||||
|
|||||||
@@ -39,6 +39,17 @@ export interface SplitViewPanelProps
|
|||||||
>;
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const SplitViewPanelContainer = ({
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: HTMLAttributes<HTMLDivElement>) => {
|
||||||
|
return (
|
||||||
|
<div className={styles.splitViewPanel} {...props}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const SplitViewPanel = memo(function SplitViewPanel({
|
export const SplitViewPanel = memo(function SplitViewPanel({
|
||||||
children,
|
children,
|
||||||
view,
|
view,
|
||||||
@@ -85,9 +96,8 @@ export const SplitViewPanel = memo(function SplitViewPanel({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<SplitViewPanelContainer
|
||||||
style={style}
|
style={style}
|
||||||
className={styles.splitViewPanel}
|
|
||||||
data-is-dragging={isDragging}
|
data-is-dragging={isDragging}
|
||||||
data-is-active={isActive && views.length > 1}
|
data-is-active={isActive && views.length > 1}
|
||||||
data-is-last={isLast}
|
data-is-last={isLast}
|
||||||
@@ -110,7 +120,7 @@ export const SplitViewPanel = memo(function SplitViewPanel({
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</SplitViewPanelContainer>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ import {
|
|||||||
} from '@dnd-kit/sortable';
|
} from '@dnd-kit/sortable';
|
||||||
import { useService } from '@toeverything/infra';
|
import { useService } from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import type { HTMLAttributes, RefObject } from 'react';
|
import type { HTMLAttributes, PropsWithChildren, RefObject } from 'react';
|
||||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
import type { View } from '../../entities/view';
|
import type { View } from '../../entities/view';
|
||||||
import { WorkbenchService } from '../../services/workbench';
|
import { WorkbenchService } from '../../services/workbench';
|
||||||
import { SplitViewPanel } from './panel';
|
import { SplitViewPanel, SplitViewPanelContainer } from './panel';
|
||||||
import { ResizeHandle } from './resize-handle';
|
import { ResizeHandle } from './resize-handle';
|
||||||
import * as styles from './split-view.css';
|
import * as styles from './split-view.css';
|
||||||
|
|
||||||
@@ -141,3 +141,20 @@ export const SplitView = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SplitViewFallback = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}: PropsWithChildren<{ className?: string }>) => {
|
||||||
|
const { appSettings } = useAppSettingHelper();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(styles.splitViewRoot, className)}
|
||||||
|
data-client-border={appSettings.clientBorder}
|
||||||
|
>
|
||||||
|
{/* todo: support multiple split views */}
|
||||||
|
<SplitViewPanelContainer>{children}</SplitViewPanelContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export const Component = (): ReactElement => {
|
|||||||
return <PageNotFound noPermission />;
|
return <PageNotFound noPermission />;
|
||||||
}
|
}
|
||||||
if (!meta) {
|
if (!meta) {
|
||||||
return <AppFallback key="workspaceLoading" />;
|
return <AppFallback />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <WorkspacePage meta={meta} />;
|
return <WorkspacePage meta={meta} />;
|
||||||
@@ -204,7 +204,7 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
|
|||||||
if (!isRootDocReady) {
|
if (!isRootDocReady) {
|
||||||
return (
|
return (
|
||||||
<FrameworkScope scope={workspace.scope}>
|
<FrameworkScope scope={workspace.scope}>
|
||||||
<AppFallback key="workspaceLoading" />
|
<AppFallback />
|
||||||
</FrameworkScope>
|
</FrameworkScope>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export function App() {
|
|||||||
<DebugProvider>
|
<DebugProvider>
|
||||||
<GlobalLoading />
|
<GlobalLoading />
|
||||||
<RouterProvider
|
<RouterProvider
|
||||||
fallbackElement={<AppFallback key="RouterFallback" />}
|
fallbackElement={<AppFallback />}
|
||||||
router={router}
|
router={router}
|
||||||
future={future}
|
future={future}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
import { createVar, style } from '@vanilla-extract/css';
|
import { createVar, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
export const sidebarOffsetVar = createVar();
|
export const sidebarOffsetVar = createVar();
|
||||||
@@ -7,10 +7,33 @@ export const root = style({
|
|||||||
width: '100vw',
|
width: '100vw',
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
background: cssVar('backgroundPrimaryColor'),
|
flexDirection: 'column',
|
||||||
|
background: cssVarV2('layer/background/primary'),
|
||||||
selectors: {
|
selectors: {
|
||||||
'&[data-translucent="true"]': {
|
'&[data-translucent="true"]': {
|
||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const appTabsHeader = style({
|
||||||
|
zIndex: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fallbackRoot = style({
|
||||||
|
position: 'absolute',
|
||||||
|
paddingTop: 52,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
zIndex: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const splitViewFallback = style({
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
zIndex: 0,
|
||||||
|
background: cssVarV2('layer/background/primary'),
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||||
import { AppTabsHeader } from '@affine/core/modules/app-tabs-header';
|
import { AppTabsHeader } from '@affine/core/modules/app-tabs-header';
|
||||||
|
import { SplitViewFallback } from '@affine/core/modules/workbench/view/split-view/split-view';
|
||||||
|
|
||||||
import * as styles from './shell.css';
|
import * as styles from './shell.css';
|
||||||
|
|
||||||
@@ -11,7 +13,10 @@ export function ShellRoot() {
|
|||||||
appSettings.enableBlurBackground;
|
appSettings.enableBlurBackground;
|
||||||
return (
|
return (
|
||||||
<div className={styles.root} data-translucent={translucent}>
|
<div className={styles.root} data-translucent={translucent}>
|
||||||
<AppTabsHeader mode="shell" />
|
<AppTabsHeader mode="shell" className={styles.appTabsHeader} />
|
||||||
|
<AppFallback className={styles.fallbackRoot}>
|
||||||
|
<SplitViewFallback className={styles.splitViewFallback} />
|
||||||
|
</AppFallback>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export function App() {
|
|||||||
<AffineContext store={getCurrentStore()}>
|
<AffineContext store={getCurrentStore()}>
|
||||||
<Telemetry />
|
<Telemetry />
|
||||||
<RouterProvider
|
<RouterProvider
|
||||||
fallbackElement={<AppFallback key="RouterFallback" />}
|
fallbackElement={<AppFallback />}
|
||||||
router={router}
|
router={router}
|
||||||
future={future}
|
future={future}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export const WorkspaceLayout = ({
|
|||||||
if (!isRootDocReady) {
|
if (!isRootDocReady) {
|
||||||
return (
|
return (
|
||||||
<FrameworkScope scope={workspace.scope}>
|
<FrameworkScope scope={workspace.scope}>
|
||||||
<AppFallback key="workspaceLoading" />
|
<AppFallback />
|
||||||
</FrameworkScope>
|
</FrameworkScope>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user