Files
AFFiNE/packages/component/src/components/page-list/view/create-collection.tsx
T
2023-07-04 07:32:11 +00:00

301 lines
7.2 KiB
TypeScript

import type { Collection } from '@affine/env/filter';
import type { PropertiesMeta } from '@affine/env/filter';
import type { GetPageInfoById } from '@affine/env/page-info';
import {
EdgelessIcon,
PageIcon,
RemoveIcon,
SaveIcon,
} from '@blocksuite/icons';
import { useCallback, useState } from 'react';
import {
Button,
Input,
Modal,
ModalCloseButton,
ModalWrapper,
ScrollableContainer,
} from '../../..';
import { FilterList } from '../filter';
import * as styles from './collection-list.css';
type CreateCollectionProps = {
title?: string;
init: Collection;
onConfirm: (collection: Collection) => void;
onConfirmText?: string;
getPageInfo: GetPageInfoById;
propertiesMeta: PropertiesMeta;
};
export const EditCollectionModel = ({
init,
onConfirm,
open,
onClose,
getPageInfo,
propertiesMeta,
}: {
init?: Collection;
onConfirm: (view: Collection) => void;
open: boolean;
onClose: () => void;
getPageInfo: GetPageInfoById;
propertiesMeta: PropertiesMeta;
}) => {
return (
<Modal open={open} onClose={onClose}>
<ModalWrapper
width={600}
style={{
padding: '40px',
background: 'var(--affine-background-primary-color)',
}}
>
<ModalCloseButton
top={12}
right={12}
onClick={onClose}
hoverColor="var(--affine-icon-color)"
/>
{init ? (
<EditCollection
propertiesMeta={propertiesMeta}
title="Update Collection"
onConfirmText="Save"
init={init}
getPageInfo={getPageInfo}
onCancel={onClose}
onConfirm={view => {
onConfirm(view);
onClose();
}}
/>
) : null}
</ModalWrapper>
</Modal>
);
};
const Page = ({
id,
onClick,
getPageInfo,
}: {
id: string;
onClick: (id: string) => void;
getPageInfo: GetPageInfoById;
}) => {
const page = getPageInfo(id);
if (!page) {
return null;
}
const icon = page.isEdgeless ? (
<EdgelessIcon
style={{
width: 17.5,
height: 17.5,
}}
/>
) : (
<PageIcon
style={{
width: 17.5,
height: 17.5,
}}
/>
);
const click = () => {
onClick(id);
};
return (
<div className={styles.pageContainer}>
<div className={styles.pageIcon}>{icon}</div>
<div className={styles.pageTitle}>{page.title}</div>
<div onClick={click} className={styles.deleteIcon}>
<RemoveIcon />
</div>
</div>
);
};
export const EditCollection = ({
title,
init,
onConfirm,
onCancel,
onConfirmText,
getPageInfo,
propertiesMeta,
}: CreateCollectionProps & {
onCancel: () => void;
}) => {
const [value, onChange] = useState<Collection>(init);
const removeFromExcludeList = useCallback(
(id: string) => {
onChange({
...value,
excludeList: value.excludeList?.filter(v => v !== id),
});
},
[value]
);
const removeFromAllowList = useCallback(
(id: string) => {
onChange({
...value,
allowList: value.allowList?.filter(v => v !== id),
});
},
[value]
);
return (
<div
style={{
maxHeight: '90vh',
display: 'flex',
flexDirection: 'column',
}}
>
<div className={styles.saveTitle}>
{title ?? 'Save As New Collection'}
</div>
<ScrollableContainer
className={styles.scrollContainer}
viewPortClassName={styles.container}
>
{value.excludeList?.length ? (
<div className={styles.excludeList}>
<div className={styles.excludeTitle}>
Exclude from this collection
</div>
<div className={styles.excludeListContent}>
{value.excludeList.map(id => {
return (
<Page
id={id}
getPageInfo={getPageInfo}
key={id}
onClick={removeFromExcludeList}
/>
);
})}
</div>
<div className={styles.excludeTip}>
These pages will never appear in the current collection
</div>
</div>
) : null}
<div
style={{
backgroundColor: 'var(--affine-hover-color)',
borderRadius: 8,
padding: 18,
marginTop: 20,
}}
>
<div className={styles.filterTitle}>Filters</div>
<FilterList
propertiesMeta={propertiesMeta}
value={value.filterList}
onChange={list =>
onChange({
...value,
filterList: list,
})
}
></FilterList>
{value.allowList ? (
<div className={styles.allowList}>
<div className={styles.allowTitle}>With follow pages:</div>
<div className={styles.allowListContent}>
{value.allowList.map(id => {
return (
<Page
key={id}
id={id}
getPageInfo={getPageInfo}
onClick={removeFromAllowList}
/>
);
})}
</div>
</div>
) : null}
</div>
<div style={{ marginTop: 20 }}>
<Input
data-testid="input-collection-title"
placeholder="Untitled Collection"
defaultValue={value.name}
onChange={text =>
onChange({
...value,
name: text,
})
}
/>
</div>
</ScrollableContainer>
<div
style={{
display: 'flex',
justifyContent: 'flex-end',
marginTop: 40,
}}
>
<Button className={styles.cancelButton} onClick={onCancel}>
Cancel
</Button>
<Button
style={{
marginLeft: 20,
borderRadius: '8px',
}}
data-testid="save-collection"
type="primary"
onClick={() => {
if (value.name.trim().length > 0) {
onConfirm(value);
}
}}
>
{onConfirmText ?? 'Create'}
</Button>
</div>
</div>
);
};
export const SaveCollectionButton = ({
init,
onConfirm,
getPageInfo,
propertiesMeta,
}: CreateCollectionProps) => {
const [show, changeShow] = useState(false);
return (
<>
<Button
className={styles.saveButton}
onClick={() => changeShow(true)}
size="middle"
data-testid="save-as-collection"
>
<div className={styles.saveButtonContainer}>
<div className={styles.saveIcon}>
<SaveIcon />
</div>
<div className={styles.saveText}>Save As Collection</div>
</div>
</Button>
<EditCollectionModel
propertiesMeta={propertiesMeta}
init={init}
onConfirm={onConfirm}
open={show}
getPageInfo={getPageInfo}
onClose={() => changeShow(false)}
/>
</>
);
};