diff --git a/packages/component/src/components/app-sidebar/index.css.ts b/packages/component/src/components/app-sidebar/index.css.ts
index f99576940f..50497c0c0f 100644
--- a/packages/component/src/components/app-sidebar/index.css.ts
+++ b/packages/component/src/components/app-sidebar/index.css.ts
@@ -79,6 +79,7 @@ export const sidebarButtonStyle = style({
width: 'auto',
height: '32px',
color: 'var(--affine-icon-color)',
+ zIndex: 1,
});
export const sidebarFloatMaskStyle = style({
diff --git a/packages/component/src/components/app-sidebar/sidebar-containers/index.tsx b/packages/component/src/components/app-sidebar/sidebar-containers/index.tsx
index f56198afac..60f3a963e6 100644
--- a/packages/component/src/components/app-sidebar/sidebar-containers/index.tsx
+++ b/packages/component/src/components/app-sidebar/sidebar-containers/index.tsx
@@ -1,41 +1,14 @@
import * as ScrollArea from '@radix-ui/react-scroll-area';
import clsx from 'clsx';
-import { type PropsWithChildren, useEffect, useRef, useState } from 'react';
+import { type PropsWithChildren } from 'react';
import * as styles from './index.css';
+import { useHasScrollTop } from './use-has-scroll-top';
export function SidebarContainer({ children }: PropsWithChildren) {
return
{children}
;
}
-function useHasScrollTop() {
- const ref = useRef(null);
- const [hasScrollTop, setHasScrollTop] = useState(false);
-
- useEffect(() => {
- if (!ref.current) {
- return;
- }
-
- const container = ref.current;
-
- function updateScrollTop() {
- if (container) {
- const hasScrollTop = container.scrollTop > 0;
- setHasScrollTop(hasScrollTop);
- }
- }
-
- container.addEventListener('scroll', updateScrollTop);
- updateScrollTop();
- return () => {
- container.removeEventListener('scroll', updateScrollTop);
- };
- }, []);
-
- return [hasScrollTop, ref] as const;
-}
-
export function SidebarScrollableContainer({ children }: PropsWithChildren) {
const [hasScrollTop, ref] = useHasScrollTop();
return (
diff --git a/packages/component/src/components/app-sidebar/sidebar-containers/use-has-scroll-top.tsx b/packages/component/src/components/app-sidebar/sidebar-containers/use-has-scroll-top.tsx
new file mode 100644
index 0000000000..34a661a45d
--- /dev/null
+++ b/packages/component/src/components/app-sidebar/sidebar-containers/use-has-scroll-top.tsx
@@ -0,0 +1,29 @@
+import { useEffect, useRef, useState } from 'react';
+
+export function useHasScrollTop() {
+ const ref = useRef(null);
+ const [hasScrollTop, setHasScrollTop] = useState(false);
+
+ useEffect(() => {
+ if (!ref.current) {
+ return;
+ }
+
+ const container = ref.current;
+
+ function updateScrollTop() {
+ if (container) {
+ const hasScrollTop = container.scrollTop > 0;
+ setHasScrollTop(hasScrollTop);
+ }
+ }
+
+ container.addEventListener('scroll', updateScrollTop);
+ updateScrollTop();
+ return () => {
+ container.removeEventListener('scroll', updateScrollTop);
+ };
+ }, []);
+
+ return [hasScrollTop, ref] as const;
+}
diff --git a/packages/component/src/components/page-list/all-page.tsx b/packages/component/src/components/page-list/all-page.tsx
index 8ca419d241..d239b43646 100644
--- a/packages/component/src/components/page-list/all-page.tsx
+++ b/packages/component/src/components/page-list/all-page.tsx
@@ -5,13 +5,15 @@ import { useMediaQuery, useTheme } from '@mui/material';
import type React from 'react';
import { type CSSProperties } from 'react';
-import { Table, TableBody, TableCell, TableHead, TableRow } from '../..';
+import { Table, TableBody, TableCell, TableHead, TableHeadRow } from '../..';
+import { TableBodyRow } from '../../ui/table';
+import { useHasScrollTop } from '../app-sidebar/sidebar-containers/use-has-scroll-top';
import { AllPagesBody } from './all-pages-body';
import { NewPageButton } from './components/new-page-buttton';
import { TitleCell } from './components/title-cell';
import { AllPageListMobileView, TrashListMobileView } from './mobile';
import { TrashOperationCell } from './operation-cell';
-import { StyledTableContainer, StyledTableRow } from './styles';
+import { StyledTableContainer } from './styles';
import type { ListData, PageListProps, TrashListData } from './type';
import { useSorter } from './use-sorter';
import { formatDate, useIsSmallDevices } from './utils';
@@ -66,7 +68,7 @@ const AllPagesHead = ({
return (
-
+
{titleList
.filter(({ showWhen = () => true }) => showWhen())
.map(({ key, content, proportion, sortable = true, styles }) => (
@@ -97,7 +99,7 @@ const AllPagesHead = ({
))}
-
+
);
};
@@ -115,7 +117,7 @@ export const PageList = ({
key: DEFAULT_SORT_KEY,
order: 'desc',
});
-
+ const [hasScrollTop, ref] = useHasScrollTop();
const isSmallDevices = useIsSmallDevices();
if (isSmallDevices) {
return (
@@ -138,8 +140,8 @@ export const PageList = ({
: undefined;
return (
-
-
+
+
{
const t = useAFFiNEI18N();
return (
-
+
{t['Title']()}
{t['Created']()}
{t['Moved to Trash']()}
-
+
);
};
@@ -179,6 +181,7 @@ export const PageListTrashView: React.FC<{
const t = useAFFiNEI18N();
const theme = useTheme();
+ const [hasScrollTop, ref] = useHasScrollTop();
const isSmallDevices = useMediaQuery(theme.breakpoints.down('sm'));
if (isSmallDevices) {
const mobileList = list.map(({ pageId, icon, title, onClickPage }) => ({
@@ -205,7 +208,7 @@ export const PageListTrashView: React.FC<{
index
) => {
return (
-
@@ -229,14 +232,14 @@ export const PageListTrashView: React.FC<{
onOpenPage={onClickPage}
/>
-
+
);
}
);
return (
-
-
+
+
diff --git a/packages/component/src/components/page-list/all-pages-body.tsx b/packages/component/src/components/page-list/all-pages-body.tsx
index 00c2337a19..54d6665d94 100644
--- a/packages/component/src/components/page-list/all-pages-body.tsx
+++ b/packages/component/src/components/page-list/all-pages-body.tsx
@@ -3,18 +3,19 @@ import { useDraggable } from '@dnd-kit/core';
import type { ReactNode } from 'react';
import { Fragment } from 'react';
-import { styled, TableBody, TableCell } from '../../..';
+import { styled } from '../../styles';
+import { TableBody, TableCell } from '../../ui/table';
import { FavoriteTag } from './components/favorite-tag';
import { TitleCell } from './components/title-cell';
import { OperationCell } from './operation-cell';
-import { StyledTableRow } from './styles';
+import { StyledTableBodyRow } from './styles';
import type { DateKey, DraggableTitleCellData, ListData } from './type';
import { useDateGroup } from './use-date-group';
import { formatDate, useIsSmallDevices } from './utils';
export const GroupRow = ({ children }: { children: ReactNode }) => {
return (
-
+
{
>
{children}
-
+
);
};
@@ -42,7 +43,7 @@ export const AllPagesBody = ({
const isSmallDevices = useIsSmallDevices();
const dataWithGroup = useDateGroup({ data, key: groupKey });
return (
-
+
{dataWithGroup.map(
(
{
@@ -71,7 +72,7 @@ export const AllPagesBody = ({
dataWithGroup[index - 1].groupName !== groupName) && (
{groupName}
)}
-
+
)}
-
+
);
}
diff --git a/packages/component/src/components/page-list/mobile.tsx b/packages/component/src/components/page-list/mobile.tsx
index 2c96d6c095..3e815e30df 100644
--- a/packages/component/src/components/page-list/mobile.tsx
+++ b/packages/component/src/components/page-list/mobile.tsx
@@ -6,13 +6,13 @@ import {
TableBody,
TableCell,
TableHead,
- TableRow,
+ TableHeadRow,
} from '../../..';
import { AllPagesBody } from './all-pages-body';
import { NewPageButton } from './components/new-page-buttton';
import {
+ StyledTableBodyRow,
StyledTableContainer,
- StyledTableRow,
StyledTitleLink,
} from './styles';
import type { ListData } from './type';
@@ -31,7 +31,7 @@ const MobileHead = ({
const t = useAFFiNEI18N();
return (
-
+
{t['Title']()}
{!isPublicWorkspace && (
@@ -50,7 +50,7 @@ const MobileHead = ({
)}
-
+
);
};
@@ -103,7 +103,7 @@ export const TrashListMobileView = ({
const ListItems = list.map(({ pageId, title, icon, onClickPage }, index) => {
return (
-
@@ -115,7 +115,7 @@ export const TrashListMobileView = ({
-
+
);
});
diff --git a/packages/component/src/components/page-list/styles.ts b/packages/component/src/components/page-list/styles.ts
index 0d111931af..40864fdb11 100644
--- a/packages/component/src/components/page-list/styles.ts
+++ b/packages/component/src/components/page-list/styles.ts
@@ -1,13 +1,13 @@
import { displayFlex, styled } from '../../styles';
import { Content } from '../../ui/layout/content';
-import { TableRow } from '../../ui/table/table-row';
+import { TableBodyRow } from '../../ui/table/table-row';
export const StyledTableContainer = styled('div')(({ theme }) => {
return {
- height: 'calc(100vh - 52px)',
- padding: '18px 32px 80px 32px',
+ height: '100%',
+ padding: '0 32px 180px 32px',
maxWidth: '100%',
- overflowY: 'auto',
+ overflowY: 'scroll',
[theme.breakpoints.down('sm')]: {
padding: '52px 0px',
'tr > td:first-of-type': {
@@ -69,7 +69,7 @@ export const StyledTitlePreview = styled(Content)(() => {
};
});
-export const StyledTableRow = styled(TableRow)(() => {
+export const StyledTableBodyRow = styled(TableBodyRow)(() => {
return {
cursor: 'pointer',
'.favorite-button': {
diff --git a/packages/component/src/stories/page-list.stories.tsx b/packages/component/src/stories/page-list.stories.tsx
index f57536669a..35897c067a 100644
--- a/packages/component/src/stories/page-list.stories.tsx
+++ b/packages/component/src/stories/page-list.stories.tsx
@@ -113,7 +113,7 @@ AffineAllPageList.args = {
removeToTrash: () => toast('Remove to trash'),
},
{
- pageId: '3',
+ pageId: '4',
favorite: false,
isPublicPage: false,
icon: ,
diff --git a/packages/component/src/ui/button/dropdown.tsx b/packages/component/src/ui/button/dropdown.tsx
index a9d103de91..6051d4f395 100644
--- a/packages/component/src/ui/button/dropdown.tsx
+++ b/packages/component/src/ui/button/dropdown.tsx
@@ -24,7 +24,11 @@ export const DropdownButton = forwardRef<
{children}
-
+
);
diff --git a/packages/component/src/ui/button/styles.css.ts b/packages/component/src/ui/button/styles.css.ts
index a21a7048dc..43c659b02b 100644
--- a/packages/component/src/ui/button/styles.css.ts
+++ b/packages/component/src/ui/button/styles.css.ts
@@ -44,10 +44,10 @@ export const dropdownWrapper = style({
paddingRight: '10px',
});
-export const icon = style({
+export const dropdownIcon = style({
borderRadius: '4px',
selectors: {
- '&:hover': {
+ [`${dropdownWrapper}:hover &`]: {
background: 'var(--affine-hover-color)',
},
},
diff --git a/packages/component/src/ui/button/styles.ts b/packages/component/src/ui/button/styles.ts
index f0d560973f..1df90306fb 100644
--- a/packages/component/src/ui/button/styles.ts
+++ b/packages/component/src/ui/button/styles.ts
@@ -1,6 +1,6 @@
import type { CSSProperties } from 'react';
-import { absoluteCenter, displayInlineFlex, styled } from '../../styles';
+import { displayInlineFlex, styled } from '../../styles';
import type { ButtonProps } from './interface';
import { getButtonColors, getSize } from './utils';
@@ -46,30 +46,13 @@ export const StyledIconButton = styled('button', {
WebkitAppRegion: 'no-drag',
color: 'var(--affine-icon-color)',
...displayInlineFlex('center', 'center'),
- position: 'relative',
...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}),
transition: 'background .15s',
-
- // TODO: we need to add @emotion/babel-plugin
- '::after': {
- content: '""',
- width,
- height,
- borderRadius,
- transition: 'background .15s',
- ...absoluteCenter({ horizontal: true, vertical: true }),
- },
-
- svg: {
- position: 'relative',
- zIndex: 1,
- },
+ borderRadius,
':hover': {
color: hoverColor ?? 'var(--affine-primary-color)',
- '::after': {
- background: hoverBackground || 'var(--affine-hover-color)',
- },
+ background: hoverBackground || 'var(--affine-hover-color)',
...(hoverStyle ?? {}),
},
};
diff --git a/packages/component/src/ui/empty/style.ts b/packages/component/src/ui/empty/style.ts
index 7f2727718a..c79a718a2b 100644
--- a/packages/component/src/ui/empty/style.ts
+++ b/packages/component/src/ui/empty/style.ts
@@ -8,6 +8,7 @@ export const StyledEmptyContainer = styled('div')<{ style?: CSSProperties }>(
height: '100%',
...displayFlex('center', 'center'),
flexDirection: 'column',
+ color: 'var(--affine-text-secondary-color)',
svg: {
color: 'transparent',
width: style?.width ?? '248px',
diff --git a/packages/component/src/ui/modal/modal-close-button.tsx b/packages/component/src/ui/modal/modal-close-button.tsx
index 03a0bb176a..625687943e 100644
--- a/packages/component/src/ui/modal/modal-close-button.tsx
+++ b/packages/component/src/ui/modal/modal-close-button.tsx
@@ -18,6 +18,7 @@ const StyledIconButton = styled(IconButton)<
position: 'absolute',
top: top ?? 24,
right: right ?? 40,
+ zIndex: 1,
};
});
diff --git a/packages/component/src/ui/table/styles.ts b/packages/component/src/ui/table/styles.ts
index cab5d79d56..cf29cdd41d 100644
--- a/packages/component/src/ui/table/styles.ts
+++ b/packages/component/src/ui/table/styles.ts
@@ -1,16 +1,36 @@
import { styled, textEllipsis } from '../../styles';
import type { TableCellProps } from './interface';
-export const StyledTable = styled('table')(() => {
- return {
- fontSize: 'var(--affine-font-base)',
- color: 'var(--affine-text-primary-color)',
- tableLayout: 'fixed',
- width: '100%',
- borderCollapse: 'separate',
- borderSpacing: '0',
- };
-});
+export const StyledTable = styled('table')<{ showBorder?: boolean }>(
+ ({ showBorder }) => {
+ return {
+ fontSize: 'var(--affine-font-base)',
+ color: 'var(--affine-text-primary-color)',
+ tableLayout: 'fixed',
+ width: '100%',
+ borderCollapse: 'collapse',
+ borderSpacing: '0',
+
+ ...(typeof showBorder === 'boolean'
+ ? {
+ thead: {
+ '::after': {
+ display: 'block',
+ position: 'absolute',
+ content: '""',
+ width: '100%',
+ height: '1px',
+ left: 0,
+ background: 'var(--affine-border-color)',
+ transition: 'opacity .15s',
+ opacity: showBorder ? 1 : 0,
+ },
+ },
+ }
+ : {}),
+ };
+ }
+);
export const StyledTableBody = styled('tbody')(() => {
return {
@@ -53,24 +73,29 @@ export const StyledTableHead = styled('thead')(() => {
return {
fontWeight: 500,
color: 'var(--affine-text-secondary-color)',
- tr: {
- td: {
- whiteSpace: 'nowrap',
- },
- ':hover': {
- td: {
- background: 'unset',
- },
- },
+ };
+});
+
+export const StyledTHeadRow = styled('tr')(() => {
+ return {
+ td: {
+ whiteSpace: 'nowrap',
+ // How to set tbody height with overflow scroll
+ // see https://stackoverflow.com/questions/23989463/how-to-set-tbody-height-with-overflow-scroll
+ position: 'sticky',
+ top: 0,
+ background: 'var(--affine-background-primary-color)',
},
};
});
-export const StyledTableRow = styled('tr')(() => {
+export const StyledTBodyRow = styled('tr')(() => {
return {
td: {
transition: 'background .15s',
},
+ // Add border radius to table row
+ // see https://stackoverflow.com/questions/4094126/how-to-add-border-radius-on-table-row
'td:first-of-type': {
borderTopLeftRadius: '10px',
borderBottomLeftRadius: '10px',
diff --git a/packages/component/src/ui/table/table-head.tsx b/packages/component/src/ui/table/table-head.tsx
index 552460d504..1c653dfce2 100644
--- a/packages/component/src/ui/table/table-head.tsx
+++ b/packages/component/src/ui/table/table-head.tsx
@@ -1,12 +1,5 @@
-import type { HTMLAttributes, PropsWithChildren } from 'react';
-
import { StyledTableHead } from './styles';
-export const TableHead = ({
- children,
- ...props
-}: PropsWithChildren>) => {
- return {children};
-};
+export const TableHead = StyledTableHead;
export default TableHead;
diff --git a/packages/component/src/ui/table/table-row.tsx b/packages/component/src/ui/table/table-row.tsx
index 740485e406..e3c4229610 100644
--- a/packages/component/src/ui/table/table-row.tsx
+++ b/packages/component/src/ui/table/table-row.tsx
@@ -1,4 +1,5 @@
-import { StyledTableRow } from './styles';
-export const TableRow = StyledTableRow;
+import { StyledTBodyRow, StyledTHeadRow } from './styles';
+export const TableHeadRow = StyledTHeadRow;
+export const TableBodyRow = StyledTBodyRow;
-export default TableRow;
+export default TableHeadRow;