mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-25 14:28:51 +08:00
feat(mobile): mobile index page UI (#7959)
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# mobile views
|
||||
|
||||
Maintain complex views that used for `../pages`, view can contain mobile-components in `../components`
|
||||
@@ -0,0 +1,51 @@
|
||||
import { IconButton } from '@affine/component';
|
||||
import { SettingsIcon } from '@blocksuite/icons/rc';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { SearchButton, WorkspaceSelector } from '../../components';
|
||||
import { useGlobalEvent } from '../../hooks/use-global-events';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
/**
|
||||
* Contains `Setting`, `Workspace Selector`, `Search`
|
||||
* When scrolled:
|
||||
* - combine Setting and Workspace Selector
|
||||
* - hide Search
|
||||
*/
|
||||
export const HomeHeader = () => {
|
||||
const [dense, setDense] = useState(false);
|
||||
|
||||
useGlobalEvent(
|
||||
'scroll',
|
||||
useCallback(() => {
|
||||
setDense(window.scrollY > 114);
|
||||
}, [])
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={clsx(styles.root, { dense })}>
|
||||
<div className={styles.float}>
|
||||
<div className={styles.headerAndWsSelector}>
|
||||
<div className={styles.wsSelectorWrapper}>
|
||||
<WorkspaceSelector />
|
||||
</div>
|
||||
<div className={styles.settingWrapper}>
|
||||
<Link to="/settings">
|
||||
<IconButton
|
||||
size="24"
|
||||
style={{ padding: 10 }}
|
||||
icon={<SettingsIcon />}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.searchWrapper}>
|
||||
<SearchButton />
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.space} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { createVar, style } from '@vanilla-extract/css';
|
||||
|
||||
const headerHeight = createVar('headerHeight');
|
||||
const wsSelectorHeight = createVar('wsSelectorHeight');
|
||||
const searchHeight = createVar('searchHeight');
|
||||
|
||||
const searchPadding = [10, 16, 15, 16];
|
||||
|
||||
export const root = style({
|
||||
vars: {
|
||||
[headerHeight]: '44px',
|
||||
[wsSelectorHeight]: '48px',
|
||||
[searchHeight]: '44px',
|
||||
},
|
||||
width: '100vw',
|
||||
});
|
||||
export const float = style({
|
||||
// why not 'sticky'?
|
||||
// when height change, will affect scroll behavior, causing shaking
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
width: '100%',
|
||||
background: cssVarV2('layer/background/secondary'),
|
||||
paddingTop: 12,
|
||||
zIndex: 1,
|
||||
});
|
||||
export const space = style({
|
||||
height: `calc(${headerHeight} + ${wsSelectorHeight} + ${searchHeight} + ${searchPadding[0] + searchPadding[2]}px + 12px)`,
|
||||
});
|
||||
|
||||
export const headerAndWsSelector = style({
|
||||
display: 'flex',
|
||||
gap: 10,
|
||||
alignItems: 'end',
|
||||
transition: 'height 0.2s',
|
||||
height: `calc(${headerHeight} + ${wsSelectorHeight})`,
|
||||
|
||||
selectors: {
|
||||
[`${root}.dense &`]: {
|
||||
height: wsSelectorHeight,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const wsSelectorWrapper = style({
|
||||
width: 0,
|
||||
flex: 1,
|
||||
height: wsSelectorHeight,
|
||||
padding: '0 10px 0 16px',
|
||||
});
|
||||
|
||||
export const settingWrapper = style({
|
||||
width: '44px',
|
||||
height: headerHeight,
|
||||
transition: 'height 0.2s',
|
||||
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
alignSelf: 'start',
|
||||
|
||||
selectors: {
|
||||
[`${root}.dense &`]: {
|
||||
height: wsSelectorHeight,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const searchWrapper = style({
|
||||
padding: searchPadding.map(v => `${v}px`).join(' '),
|
||||
width: '100%',
|
||||
height: 44 + searchPadding[0] + searchPadding[2],
|
||||
transition: 'all 0.2s',
|
||||
overflow: 'hidden',
|
||||
selectors: {
|
||||
[`${root}.dense &`]: {
|
||||
height: 0,
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './home-header';
|
||||
export * from './recent-docs';
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { CollapsibleSection } from '@affine/core/modules/explorer';
|
||||
import { useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { DocCard } from '../../components/doc-card';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
export const RecentDocs = ({ max = 5 }: { max?: number }) => {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const allPageMetas = useBlockSuiteDocMeta(workspace.docCollection);
|
||||
|
||||
const cardMetas = useMemo(() => {
|
||||
return [...allPageMetas]
|
||||
.sort((a, b) => (b.updatedDate ?? 0) - (a.updatedDate ?? 0))
|
||||
.slice(0, max);
|
||||
}, [allPageMetas, max]);
|
||||
|
||||
return (
|
||||
<CollapsibleSection
|
||||
name="recent"
|
||||
title="Recent"
|
||||
headerClassName={styles.header}
|
||||
>
|
||||
<div className={styles.scroll}>
|
||||
<ul className={styles.list}>
|
||||
{cardMetas.map((doc, index) => (
|
||||
<li key={index} className={styles.cardWrapper}>
|
||||
<DocCard meta={doc} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</CollapsibleSection>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
|
||||
export const scroll = style({
|
||||
width: '100%',
|
||||
paddingTop: 8,
|
||||
paddingBottom: 32,
|
||||
overflowX: 'auto',
|
||||
});
|
||||
|
||||
export const list = style({
|
||||
paddingLeft: 16,
|
||||
paddingRight: 16,
|
||||
display: 'flex',
|
||||
gap: 10,
|
||||
width: 'fit-content',
|
||||
});
|
||||
|
||||
export const cardWrapper = style({
|
||||
width: 172,
|
||||
height: 210,
|
||||
flexShrink: 0,
|
||||
});
|
||||
|
||||
export const header = style({
|
||||
margin: '0 8px',
|
||||
});
|
||||
|
||||
globalStyle(`${cardWrapper} > *`, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
});
|
||||
Reference in New Issue
Block a user