mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-24 09:52:49 +08:00
feat: add history back & forward for desktop app (#1926)
This commit is contained in:
@@ -14,7 +14,7 @@ async function createWindow() {
|
|||||||
|
|
||||||
const browserWindow = new BrowserWindow({
|
const browserWindow = new BrowserWindow({
|
||||||
titleBarStyle: isMacOS() ? 'hiddenInset' : 'default',
|
titleBarStyle: isMacOS() ? 'hiddenInset' : 'default',
|
||||||
trafficLightPosition: { x: 20, y: 18 },
|
trafficLightPosition: { x: 24, y: 18 },
|
||||||
x: mainWindowState.x,
|
x: mainWindowState.x,
|
||||||
y: mainWindowState.y,
|
y: mainWindowState.y,
|
||||||
width: mainWindowState.width,
|
width: mainWindowState.width,
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export const StyledCollapsedButton = styled('button')<{
|
|||||||
}>(({ collapse, show = true, theme }) => {
|
}>(({ collapse, show = true, theme }) => {
|
||||||
return {
|
return {
|
||||||
width: '16px',
|
width: '16px',
|
||||||
height: '16px',
|
height: '100%',
|
||||||
|
...displayFlex('center', 'center'),
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: '0',
|
left: '0',
|
||||||
@@ -21,9 +22,13 @@ export const StyledCollapsedButton = styled('button')<{
|
|||||||
margin: 'auto',
|
margin: 'auto',
|
||||||
color: theme.colors.iconColor,
|
color: theme.colors.iconColor,
|
||||||
opacity: '.6',
|
opacity: '.6',
|
||||||
|
transition: 'opacity .15s ease-in-out',
|
||||||
display: show ? 'flex' : 'none',
|
display: show ? 'flex' : 'none',
|
||||||
svg: {
|
svg: {
|
||||||
transform: `rotate(${collapse ? '0' : '-90'}deg)`,
|
transform: `rotate(${collapse ? '-90' : '0'}deg)`,
|
||||||
|
},
|
||||||
|
':hover': {
|
||||||
|
opacity: '1',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export const NavigationPath = ({
|
|||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
data-testid="navigation-path-expand-btn"
|
data-testid="navigation-path-expand-btn"
|
||||||
size="middle"
|
size="small"
|
||||||
className="collapse-btn"
|
className="collapse-btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpenExtend(!openExtend);
|
setOpenExtend(!openExtend);
|
||||||
@@ -158,9 +158,7 @@ const NavigationPathExtendPanel = ({
|
|||||||
show={open}
|
show={open}
|
||||||
data-testid="navigation-path-expand-panel"
|
data-testid="navigation-path-expand-panel"
|
||||||
>
|
>
|
||||||
<div className="tree-container">
|
<TreeView data={data} indent={10} disableCollapse={true} />
|
||||||
<TreeView data={data} indent={10} disableCollapse={true} />
|
|
||||||
</div>
|
|
||||||
</StyledNavPathExtendContainer>
|
</StyledNavPathExtendContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,12 +55,7 @@ export const StyledNavPathExtendContainer = styled('div')<{ show: boolean }>(
|
|||||||
transition: 'top .15s',
|
transition: 'top .15s',
|
||||||
fontSize: theme.font.sm,
|
fontSize: theme.font.sm,
|
||||||
color: theme.colors.secondaryTextColor,
|
color: theme.colors.secondaryTextColor,
|
||||||
paddingTop: '46px',
|
padding: '46px 12px 0 15px',
|
||||||
paddingRight: '12px',
|
|
||||||
|
|
||||||
'.tree-container': {
|
|
||||||
padding: '0 12px 0 15px',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { PageMeta } from '@blocksuite/store';
|
|||||||
export function findPath(metas: PageMeta[], meta: PageMeta): PageMeta[] {
|
export function findPath(metas: PageMeta[], meta: PageMeta): PageMeta[] {
|
||||||
function helper(group: PageMeta[]): PageMeta[] {
|
function helper(group: PageMeta[]): PageMeta[] {
|
||||||
const last = group[group.length - 1];
|
const last = group[group.length - 1];
|
||||||
const parent = metas.find(m => m.subpageIds.includes(last.id));
|
const parent = metas.find(m => (m.subpageIds ?? []).includes(last.id));
|
||||||
if (parent) {
|
if (parent) {
|
||||||
return helper([...group, parent]);
|
return helper([...group, parent]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { IconButton } from '@affine/component';
|
||||||
|
import { ArrowLeftSmallIcon, ArrowRightSmallIcon } from '@blocksuite/icons';
|
||||||
|
|
||||||
|
import { StyledRouteNavigationWrapper } from './shared-styles';
|
||||||
|
|
||||||
|
export const RouteNavigation = () => {
|
||||||
|
if (!environment.isDesktop) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<StyledRouteNavigationWrapper>
|
||||||
|
<IconButton
|
||||||
|
size="middle"
|
||||||
|
onClick={() => {
|
||||||
|
window.history.back();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ArrowLeftSmallIcon />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
size="middle"
|
||||||
|
onClick={() => {
|
||||||
|
window.history.forward();
|
||||||
|
}}
|
||||||
|
style={{ marginLeft: '32px' }}
|
||||||
|
>
|
||||||
|
<ArrowRightSmallIcon />
|
||||||
|
</IconButton>
|
||||||
|
</StyledRouteNavigationWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -26,12 +26,13 @@ import { SidebarSwitch } from '../../affine/sidebar-switch';
|
|||||||
import { ChangeLog } from './changeLog';
|
import { ChangeLog } from './changeLog';
|
||||||
import Favorite from './favorite';
|
import Favorite from './favorite';
|
||||||
import { Pinboard } from './Pinboard';
|
import { Pinboard } from './Pinboard';
|
||||||
|
import { RouteNavigation } from './RouteNavigation';
|
||||||
import { StyledListItem } from './shared-styles';
|
import { StyledListItem } from './shared-styles';
|
||||||
import {
|
import {
|
||||||
StyledLink,
|
StyledLink,
|
||||||
StyledNewPageButton,
|
StyledNewPageButton,
|
||||||
StyledScrollWrapper,
|
StyledScrollWrapper,
|
||||||
StyledSidebarSwitchWrapper,
|
StyledSidebarHeader,
|
||||||
StyledSliderBar,
|
StyledSliderBar,
|
||||||
StyledSliderBarInnerWrapper,
|
StyledSliderBarInnerWrapper,
|
||||||
StyledSliderBarWrapper,
|
StyledSliderBarWrapper,
|
||||||
@@ -115,13 +116,14 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
data-testid="sliderBar-root"
|
data-testid="sliderBar-root"
|
||||||
>
|
>
|
||||||
<StyledSliderBar>
|
<StyledSliderBar>
|
||||||
<StyledSidebarSwitchWrapper>
|
<StyledSidebarHeader>
|
||||||
|
<RouteNavigation />
|
||||||
<SidebarSwitch
|
<SidebarSwitch
|
||||||
visible={sidebarOpen}
|
visible={sidebarOpen}
|
||||||
tooltipContent={t('Collapse sidebar')}
|
tooltipContent={t('Collapse sidebar')}
|
||||||
testid="sliderBar-arrowButton-collapse"
|
testid="sliderBar-arrowButton-collapse"
|
||||||
/>
|
/>
|
||||||
</StyledSidebarSwitchWrapper>
|
</StyledSidebarHeader>
|
||||||
|
|
||||||
<StyledSliderBarInnerWrapper data-testid="sliderBar-inner">
|
<StyledSliderBarInnerWrapper data-testid="sliderBar-inner">
|
||||||
<WorkspaceSelector
|
<WorkspaceSelector
|
||||||
@@ -138,7 +140,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
{t('Quick search')}
|
{t('Quick search')}
|
||||||
</StyledListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
<StyledListItem
|
<StyledListItem
|
||||||
active={
|
active={
|
||||||
currentPath ===
|
currentPath ===
|
||||||
@@ -159,7 +160,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
{t('Workspace Settings')}
|
{t('Workspace Settings')}
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
</StyledListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
<StyledListItem
|
<StyledListItem
|
||||||
active={
|
active={
|
||||||
currentPath ===
|
currentPath ===
|
||||||
@@ -175,7 +175,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
<span data-testid="all-pages">{t('All pages')}</span>
|
<span data-testid="all-pages">{t('All pages')}</span>
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
</StyledListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
<StyledScrollWrapper
|
<StyledScrollWrapper
|
||||||
showTopBorder={!isScrollAtTop}
|
showTopBorder={!isScrollAtTop}
|
||||||
onScroll={(e: UIEvent<HTMLDivElement>) => {
|
onScroll={(e: UIEvent<HTMLDivElement>) => {
|
||||||
@@ -199,7 +198,7 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledScrollWrapper>
|
</StyledScrollWrapper>
|
||||||
|
<div style={{ height: 16 }}></div>
|
||||||
{currentWorkspace?.flavour === WorkspaceFlavour.AFFINE &&
|
{currentWorkspace?.flavour === WorkspaceFlavour.AFFINE &&
|
||||||
currentWorkspace.public ? (
|
currentWorkspace.public ? (
|
||||||
<StyledListItem>
|
<StyledListItem>
|
||||||
@@ -236,9 +235,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
currentPath ===
|
currentPath ===
|
||||||
(currentWorkspaceId && paths.trash(currentWorkspaceId))
|
(currentWorkspaceId && paths.trash(currentWorkspaceId))
|
||||||
}
|
}
|
||||||
style={{
|
|
||||||
marginTop: '16px',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<StyledLink
|
<StyledLink
|
||||||
href={{
|
href={{
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export const StyledListItem = styled('div')<{
|
|||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
marginBottom: '4px',
|
marginBottom: '4px',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
flexShrink: 0,
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
...displayFlex('flex-start', 'center'),
|
...displayFlex('flex-start', 'center'),
|
||||||
...(disabled
|
...(disabled
|
||||||
@@ -44,7 +45,8 @@ export const StyledCollapseButton = styled('button')<{
|
|||||||
}>(({ collapse, show = true, theme }) => {
|
}>(({ collapse, show = true, theme }) => {
|
||||||
return {
|
return {
|
||||||
width: '16px',
|
width: '16px',
|
||||||
height: '16px',
|
height: '100%',
|
||||||
|
...displayFlex('center', 'center'),
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: '0',
|
left: '0',
|
||||||
@@ -53,10 +55,14 @@ export const StyledCollapseButton = styled('button')<{
|
|||||||
margin: 'auto',
|
margin: 'auto',
|
||||||
color: theme.colors.iconColor,
|
color: theme.colors.iconColor,
|
||||||
opacity: '.6',
|
opacity: '.6',
|
||||||
|
transition: 'opacity .15s ease-in-out',
|
||||||
display: show ? 'flex' : 'none',
|
display: show ? 'flex' : 'none',
|
||||||
svg: {
|
svg: {
|
||||||
transform: `rotate(${collapse ? '0' : '-90'}deg)`,
|
transform: `rotate(${collapse ? '0' : '-90'}deg)`,
|
||||||
},
|
},
|
||||||
|
':hover': {
|
||||||
|
opacity: '1',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -205,3 +211,10 @@ export const StyledChangeLogWrapper = styled('div')<{
|
|||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const StyledRouteNavigationWrapper = styled('div')({
|
||||||
|
height: '32px',
|
||||||
|
width: '80px',
|
||||||
|
marginRight: '16px',
|
||||||
|
...displayFlex('space-between', 'center'),
|
||||||
|
});
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const StyledSliderBarWrapper = styled('div')<{
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const StyledSliderBar = styled('div')(({ theme }) => {
|
export const StyledSliderBar = styled('div')(() => {
|
||||||
return {
|
return {
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@@ -34,19 +34,18 @@ export const StyledSliderBar = styled('div')(({ theme }) => {
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
// overflow: 'hidden',
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
export const StyledSidebarSwitchWrapper = styled('div')(() => {
|
export const StyledSidebarHeader = styled('div')(() => {
|
||||||
return {
|
return {
|
||||||
height: '52px',
|
height: '52px',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
padding: '0 16px',
|
padding: '0 16px 0 10px',
|
||||||
WebkitAppRegion: 'drag',
|
WebkitAppRegion: 'drag',
|
||||||
button: {
|
button: {
|
||||||
WebkitAppRegion: 'no-drag',
|
WebkitAppRegion: 'no-drag',
|
||||||
},
|
},
|
||||||
...displayFlex(macosElectron ? 'flex-end' : 'flex-start', 'center'),
|
...displayFlex(macosElectron ? 'flex-end' : 'space-between', 'center'),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
export const StyledSliderBarInnerWrapper = styled('div')(() => {
|
export const StyledSliderBarInnerWrapper = styled('div')(() => {
|
||||||
@@ -55,6 +54,9 @@ export const StyledSliderBarInnerWrapper = styled('div')(() => {
|
|||||||
// overflowX: 'hidden',
|
// overflowX: 'hidden',
|
||||||
// overflowY: 'auto',
|
// overflowY: 'auto',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
height: 'calc(100% - 52px * 2)',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,7 +77,7 @@ export const StyledNewPageButton = styled('button')(({ theme }) => {
|
|||||||
...displayFlex('flex-start', 'center'),
|
...displayFlex('flex-start', 'center'),
|
||||||
borderTop: '1px solid',
|
borderTop: '1px solid',
|
||||||
borderColor: theme.colors.borderColor,
|
borderColor: theme.colors.borderColor,
|
||||||
padding: '0 8px',
|
padding: '0 8px 0 16px',
|
||||||
svg: {
|
svg: {
|
||||||
fontSize: '20px',
|
fontSize: '20px',
|
||||||
color: theme.colors.iconColor,
|
color: theme.colors.iconColor,
|
||||||
@@ -105,44 +107,11 @@ export const StyledSliderModalBackground = styled('div')<{ active: boolean }>(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
export const StyledSliderResizer = styled('div')<{ isResizing: boolean }>(
|
|
||||||
() => {
|
|
||||||
return {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
width: '12px',
|
|
||||||
transform: 'translateX(50%)',
|
|
||||||
cursor: 'col-resize',
|
|
||||||
zIndex: 1,
|
|
||||||
userSelect: 'none',
|
|
||||||
':hover > *': {
|
|
||||||
background: 'rgba(0, 0, 0, 0.1)',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
export const StyledSliderResizerInner = styled('div')<{ isResizing: boolean }>(
|
|
||||||
({ isResizing }) => {
|
|
||||||
return {
|
|
||||||
transition: 'background .15s .1s',
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
right: '50%',
|
|
||||||
bottom: 0,
|
|
||||||
transform: 'translateX(0.5px)',
|
|
||||||
width: '2px',
|
|
||||||
background: isResizing ? 'rgba(0, 0, 0, 0.1)' : 'transparent',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const StyledScrollWrapper = styled('div')<{
|
export const StyledScrollWrapper = styled('div')<{
|
||||||
showTopBorder: boolean;
|
showTopBorder: boolean;
|
||||||
}>(({ showTopBorder, theme }) => {
|
}>(({ showTopBorder, theme }) => {
|
||||||
return {
|
return {
|
||||||
maxHeight: '360px',
|
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
borderTop: '1px solid',
|
borderTop: '1px solid',
|
||||||
borderColor: showTopBorder ? theme.colors.borderColor : 'transparent',
|
borderColor: showTopBorder ? theme.colors.borderColor : 'transparent',
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const SIZE_CONFIG = {
|
|||||||
areaSize: 20,
|
areaSize: 20,
|
||||||
},
|
},
|
||||||
[SIZE_MIDDLE]: {
|
[SIZE_MIDDLE]: {
|
||||||
iconSize: 16,
|
iconSize: 20,
|
||||||
areaSize: 24,
|
areaSize: 24,
|
||||||
},
|
},
|
||||||
[SIZE_NORMAL]: {
|
[SIZE_NORMAL]: {
|
||||||
|
|||||||
Reference in New Issue
Block a user