style: add scrollbar (#2826)

This commit is contained in:
JimmFly
2023-06-26 15:12:44 +08:00
committed by GitHub
parent 773d92760e
commit 002e64c819
11 changed files with 199 additions and 45 deletions

View File

@@ -48,8 +48,7 @@ export const StyleWorkspaceTitle = styled('div')(() => {
}); });
export const StyledFooter = styled('div')({ export const StyledFooter = styled('div')({
height: '84px', padding: '20px 40px',
padding: '0 40px',
flexShrink: 0, flexShrink: 0,
...displayFlex('space-between', 'center'), ...displayFlex('space-between', 'center'),
}); });

View File

@@ -6,6 +6,7 @@ import {
ModalWrapper, ModalWrapper,
Tooltip, Tooltip,
} from '@affine/component'; } from '@affine/component';
import { ScrollableContainer } from '@affine/component';
import { WorkspaceList } from '@affine/component/workspace-list'; import { WorkspaceList } from '@affine/component/workspace-list';
import type { import type {
AffineLegacyCloudWorkspace, AffineLegacyCloudWorkspace,
@@ -105,7 +106,7 @@ export const WorkspaceListModal = ({
/> />
</StyledOperationWrapper> </StyledOperationWrapper>
</StyledModalHeader> </StyledModalHeader>
<ScrollableContainer>
<StyledModalContent> <StyledModalContent>
<WorkspaceList <WorkspaceList
disabled={disabled} disabled={disabled}
@@ -128,6 +129,7 @@ export const WorkspaceListModal = ({
)} )}
/> />
{!environment.isDesktop && ( {!environment.isDesktop && (
<div>
<StyledCreateWorkspaceCard <StyledCreateWorkspaceCard
onClick={onNewWorkspace} onClick={onNewWorkspace}
data-testid="new-workspace" data-testid="new-workspace"
@@ -143,6 +145,7 @@ export const WorkspaceListModal = ({
<p>{t['Create Or Import']()}</p> <p>{t['Create Or Import']()}</p>
</StyleWorkspaceInfo> </StyleWorkspaceInfo>
</StyledCreateWorkspaceCard> </StyledCreateWorkspaceCard>
</div>
)} )}
{environment.isDesktop && ( {environment.isDesktop && (
@@ -218,7 +221,7 @@ export const WorkspaceListModal = ({
</Menu> </Menu>
)} )}
</StyledModalContent> </StyledModalContent>
</ScrollableContainer>
<Footer user={user} onLogin={onClickLogin} onLogout={onClickLogout} /> <Footer user={user} onLogin={onClickLogin} onLogout={onClickLogout} />
</ModalWrapper> </ModalWrapper>
</Modal> </Modal>

View File

@@ -45,6 +45,7 @@ export const StyledCreateWorkspaceCard = styled('div')(() => {
return { return {
width: '310px', width: '310px',
height: '124px', height: '124px',
marginBottom: '24px',
cursor: 'pointer', cursor: 'pointer',
padding: '16px', padding: '16px',
boxShadow: 'var(--affine-shadow-1)', boxShadow: 'var(--affine-shadow-1)',
@@ -133,10 +134,8 @@ export const StyledHelperContainer = styled('div')(() => {
}); });
export const StyledModalContent = styled('div')({ export const StyledModalContent = styled('div')({
height: '534px', height: '540px',
padding: '8px 40px', padding: '8px 40px',
marginTop: '72px',
overflow: 'auto',
...displayFlex('space-between', 'flex-start', 'flex-start'), ...displayFlex('space-between', 'flex-start', 'flex-start'),
flexWrap: 'wrap', flexWrap: 'wrap',
}); });
@@ -163,12 +162,11 @@ export const StyleWorkspaceAdd = styled('div')(() => {
export const StyledModalHeader = styled('div')(() => { export const StyledModalHeader = styled('div')(() => {
return { return {
width: '100%', width: '100%',
height: '72px', marginTop: '10px',
position: 'absolute',
left: 0, left: 0,
top: 0, top: 0,
borderRadius: '24px 24px 0 0', borderRadius: '24px 24px 0 0',
padding: '0 40px', padding: '10px 40px',
...displayFlex('space-between', 'center'), ...displayFlex('space-between', 'center'),
}; };
}); });

View File

@@ -5,7 +5,7 @@ import { useMediaQuery, useTheme } from '@mui/material';
import type React from 'react'; import type React from 'react';
import { type CSSProperties } from 'react'; import { type CSSProperties } from 'react';
import { Table, TableBody, TableCell, TableHead, TableHeadRow } from '../..'; import { ScrollableContainer, Table, TableBody, TableCell, TableHead, TableHeadRow } from '../..';
import { TableBodyRow } from '../../ui/table'; import { TableBodyRow } from '../../ui/table';
import { useHasScrollTop } from '../app-sidebar/sidebar-containers/use-has-scroll-top'; import { useHasScrollTop } from '../app-sidebar/sidebar-containers/use-has-scroll-top';
import { AllPagesBody } from './all-pages-body'; import { AllPagesBody } from './all-pages-body';
@@ -121,13 +121,15 @@ export const PageList = ({
const isSmallDevices = useIsSmallDevices(); const isSmallDevices = useIsSmallDevices();
if (isSmallDevices) { if (isSmallDevices) {
return ( return (
<AllPageListMobileView <ScrollableContainer inTableView>
isPublicWorkspace={isPublicWorkspace} <AllPageListMobileView
createNewPage={onCreateNewPage} isPublicWorkspace={isPublicWorkspace}
createNewEdgeless={onCreateNewEdgeless} createNewPage={onCreateNewPage}
importFile={onImportFile} createNewEdgeless={onCreateNewEdgeless}
list={sorter.data} importFile={onImportFile}
/> list={sorter.data}
/>
</ScrollableContainer>
); );
} }
@@ -140,23 +142,30 @@ export const PageList = ({
: undefined; : undefined;
return ( return (
<StyledTableContainer ref={ref}> sorter.data.length === 0 && fallback ?
<Table showBorder={hasScrollTop} style={{ maxHeight: '100%' }}> <StyledTableContainer>
<AllPagesHead {fallback}
isPublicWorkspace={isPublicWorkspace}
sorter={sorter}
createNewPage={onCreateNewPage}
createNewEdgeless={onCreateNewEdgeless}
importFile={onImportFile}
/>
<AllPagesBody
isPublicWorkspace={isPublicWorkspace}
groupKey={groupKey}
data={sorter.data}
/>
</Table>
{sorter.data.length === 0 && fallback ? fallback : null}
</StyledTableContainer> </StyledTableContainer>
:
<ScrollableContainer inTableView>
<StyledTableContainer ref={ref}>
<Table showBorder={hasScrollTop} style={{ maxHeight: '100%' }}>
<AllPagesHead
isPublicWorkspace={isPublicWorkspace}
sorter={sorter}
createNewPage={onCreateNewPage}
createNewEdgeless={onCreateNewEdgeless}
importFile={onImportFile}
/>
<AllPagesBody
isPublicWorkspace={isPublicWorkspace}
groupKey={groupKey}
data={sorter.data}
/>
</Table>
</StyledTableContainer>
</ScrollableContainer>
); );
}; };
@@ -238,12 +247,18 @@ export const PageListTrashView: React.FC<{
); );
return ( return (
<StyledTableContainer ref={ref}> list.length === 0 && fallback ?
<Table showBorder={hasScrollTop}> <StyledTableContainer>
<TrashListHead /> {fallback}
<TableBody>{ListItems}</TableBody>
</Table>
{list.length === 0 && fallback ? fallback : null}
</StyledTableContainer> </StyledTableContainer>
:
<ScrollableContainer inTableView>
<StyledTableContainer ref={ref}>
<Table showBorder={hasScrollTop}>
<TrashListHead />
<TableBody>{ListItems}</TableBody>
</Table>
</StyledTableContainer>
</ScrollableContainer>
); );
}; };

View File

@@ -7,7 +7,6 @@ export const StyledTableContainer = styled('div')(({ theme }) => {
height: '100%', height: '100%',
padding: '0 32px 180px 32px', padding: '0 32px 180px 32px',
maxWidth: '100%', maxWidth: '100%',
overflowY: 'scroll',
[theme.breakpoints.down('sm')]: { [theme.breakpoints.down('sm')]: {
padding: '52px 0px', padding: '52px 0px',
'tr > td:first-of-type': { 'tr > td:first-of-type': {

View File

@@ -10,6 +10,7 @@ export * from './ui/menu';
export * from './ui/modal'; export * from './ui/modal';
export * from './ui/mui'; export * from './ui/mui';
export * from './ui/popper'; export * from './ui/popper';
export * from './ui/scrollbar';
export * from './ui/shared/container'; export * from './ui/shared/container';
export * from './ui/switch'; export * from './ui/switch';
export * from './ui/table'; export * from './ui/table';

View File

@@ -187,14 +187,24 @@ input[type='number']::-webkit-outer-spin-button {
-ms-overflow-style: none; /* IE 10+ */ -ms-overflow-style: none; /* IE 10+ */
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
display: none; /* Chrome Safari */ width: 0; /* Chrome Safari */
height: 0;
} }
.affine-default-viewport::-webkit-scrollbar {
width: 8px; /* Chrome Safari */
}
.affine-default-viewport::-webkit-scrollbar-thumb {
border-radius: 4px;
}
.affine-default-viewport:hover::-webkit-scrollbar-thumb {
background-color: var(--affine-black-30);
}
.editor-wrapper { .editor-wrapper {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 0 2rem; padding: 0 1rem;
padding-right: 8px;
} }
/* issue: https://github.com/toeverything/AFFiNE/issues/2004 */ /* issue: https://github.com/toeverything/AFFiNE/issues/2004 */

View File

@@ -28,7 +28,7 @@ export const dropdownBtn = style({
export const divider = style({ export const divider = style({
width: '0.5px', width: '0.5px',
height: '16px', height: '16px',
background: 'var(--affine-border-color)', background: 'var(--affine-divider-color)',
// fix dropdown button click area // fix dropdown button click area
margin: '0 4px', margin: '0 4px',
marginRight: 0, marginRight: 0,

View File

@@ -0,0 +1,85 @@
import { globalStyle, style } from '@vanilla-extract/css';
export const scrollableContainerRoot = style({
width: '100%',
vars: {
'--scrollbar-width': '10px',
},
height: '100%',
});
export const scrollTopBorder = style({
position: 'absolute',
top: 0,
left: '16px',
right: '16px',
height: '1px',
transition: 'opacity .3s .2s',
opacity: 0,
background: 'var(--affine-border-color)',
selectors: {
'&[data-has-scroll-top="true"]': {
opacity: 1,
},
},
});
export const scrollableViewport = style({
height: '100%',
width: '100%',
});
globalStyle(`${scrollableViewport} > div`, {
maxWidth: '100%',
display: 'block !important',
});
export const scrollableContainer = style({
height: '100%',
marginBottom: '4px',
});
export const scrollbar = style({
display: 'flex',
flexDirection: 'column',
userSelect: 'none',
touchAction: 'none',
padding: '0 2px',
marginRight: '4px',
width: 'var(--scrollbar-width)',
height: '100%',
opacity: 1,
transition: 'opacity .15s',
selectors: {
'&[data-state="hidden"]': {
opacity: 0,
},
},
});
export const TableScrollbar = style({
paddingTop: '60px',
paddingBottom: '60px',
});
export const scrollbarThumb = style({
position: 'relative',
background: 'var(--affine-black-30)',
borderRadius: '4px',
selectors: {
'&::before': {
content: '""',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '100%',
height: '100%',
minWidth: '44px',
minHeight: '44px',
},
},
});

View File

@@ -0,0 +1 @@
export * from './scrollbar';

View File

@@ -0,0 +1,43 @@
import * as ScrollArea from '@radix-ui/react-scroll-area';
import clsx from 'clsx';
import { type PropsWithChildren } from 'react';
import { useHasScrollTop } from '../../components/app-sidebar/sidebar-containers/use-has-scroll-top';
import * as styles from './index.css';
export type ScrollableContainerProps = {
showScrollTopBorder?: boolean;
inTableView?: boolean;
};
export const ScrollableContainer = ({
children,
showScrollTopBorder = false,
inTableView = false,
}: PropsWithChildren<ScrollableContainerProps>) => {
const [hasScrollTop, ref] = useHasScrollTop();
return (
<ScrollArea.Root className={styles.scrollableContainerRoot}>
<div
data-has-scroll-top={hasScrollTop}
className={clsx({[styles.scrollTopBorder]:showScrollTopBorder})}
/>
<ScrollArea.Viewport
className={clsx([styles.scrollableViewport])}
ref={ref}
>
<div className={styles.scrollableContainer}>
{children}
</div>
</ScrollArea.Viewport>
<ScrollArea.Scrollbar
orientation="vertical"
className={clsx(styles.scrollbar,{[styles.TableScrollbar]:inTableView})}
>
<ScrollArea.Thumb className={styles.scrollbarThumb} />
</ScrollArea.Scrollbar>
</ScrollArea.Root>
);
}