mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-24 21:43:40 +03:00
feat: support gif toast (#3389)
This commit is contained in:
parent
fa8086d525
commit
bc27412425
@ -12,6 +12,12 @@ export default {
|
|||||||
} satisfies Meta<typeof NotificationCenter>;
|
} satisfies Meta<typeof NotificationCenter>;
|
||||||
|
|
||||||
let id = 0;
|
let id = 0;
|
||||||
|
const image = (
|
||||||
|
<video autoPlay muted loop>
|
||||||
|
<source src="/editingVideo.mp4" type="video/mp4" />
|
||||||
|
<source src="/editingVideo.webm" type="video/webm" />
|
||||||
|
</video>
|
||||||
|
);
|
||||||
export const Basic = () => {
|
export const Basic = () => {
|
||||||
const push = useSetAtom(pushNotificationAtom);
|
const push = useSetAtom(pushNotificationAtom);
|
||||||
const expand = useAtomValue(expandNotificationCenterAtom);
|
const expand = useAtomValue(expandNotificationCenterAtom);
|
||||||
@ -196,6 +202,27 @@ export const Basic = () => {
|
|||||||
dark error
|
dark error
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
const key = id++;
|
||||||
|
push({
|
||||||
|
key: `${key}`,
|
||||||
|
title: `${key} title`,
|
||||||
|
message: `gif test`,
|
||||||
|
type: 'info',
|
||||||
|
multimedia: image,
|
||||||
|
timeout: 3000,
|
||||||
|
undo: async () => {
|
||||||
|
console.log('undo');
|
||||||
|
},
|
||||||
|
progressingBar: true,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
gif
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<NotificationCenter />
|
<NotificationCenter />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,12 @@
|
|||||||
// License on the MIT
|
// License on the MIT
|
||||||
// https://github.com/emilkowalski/sonner/blob/5cb703edc108a23fd74979235c2f3c4005edd2a7/src/styles.css
|
// https://github.com/emilkowalski/sonner/blob/5cb703edc108a23fd74979235c2f3c4005edd2a7/src/styles.css
|
||||||
|
|
||||||
import { keyframes, style, styleVariants } from '@vanilla-extract/css';
|
import {
|
||||||
|
globalStyle,
|
||||||
|
keyframes,
|
||||||
|
style,
|
||||||
|
styleVariants,
|
||||||
|
} from '@vanilla-extract/css';
|
||||||
|
|
||||||
const swipeOut = keyframes({
|
const swipeOut = keyframes({
|
||||||
'0%': {
|
'0%': {
|
||||||
@ -19,12 +24,28 @@ const swipeOut = keyframes({
|
|||||||
|
|
||||||
export const notificationCenterViewportStyle = style({
|
export const notificationCenterViewportStyle = style({
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
bottom: '200px',
|
height: '500px',
|
||||||
right: '60px',
|
bottom: '20px',
|
||||||
|
right: '20px',
|
||||||
width: '380px',
|
width: '380px',
|
||||||
margin: 0,
|
|
||||||
zIndex: 2147483647,
|
zIndex: 2147483647,
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
});
|
||||||
|
export const notificationMultimediaStyle = style({
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
|
height: '230px',
|
||||||
|
borderRadius: '8px 8px 0 0',
|
||||||
|
overflow: 'hidden',
|
||||||
|
marginBottom: '16px',
|
||||||
|
});
|
||||||
|
globalStyle(`${notificationMultimediaStyle} > *`, {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
objectFit: 'cover',
|
||||||
|
cursor: 'unset',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const notificationStyle = style({
|
export const notificationStyle = style({
|
||||||
@ -128,18 +149,32 @@ export const notificationStyle = style({
|
|||||||
export const notificationIconStyle = style({
|
export const notificationIconStyle = style({
|
||||||
fontSize: '24px',
|
fontSize: '24px',
|
||||||
marginLeft: '18px',
|
marginLeft: '18px',
|
||||||
marginRight: '12px',
|
marginRight: '8px',
|
||||||
color: 'var(--affine-processing-color)',
|
color: 'var(--affine-processing-color)',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
});
|
});
|
||||||
|
export const hasMediaStyle = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
paddingTop: '0',
|
||||||
|
paddingBottom: '16px',
|
||||||
|
width: '380px',
|
||||||
|
borderRadius: '8px',
|
||||||
|
boxShadow: 'var(--affine-shadow-1)',
|
||||||
|
border: '1px solid var(--affine-border-color)',
|
||||||
|
background: 'var(--affine-white)',
|
||||||
|
transition: 'all 0.3s',
|
||||||
|
});
|
||||||
export const notificationContentStyle = style({
|
export const notificationContentStyle = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
padding: '16px 0',
|
paddingTop: '16px',
|
||||||
width: '100%',
|
paddingBottom: '16px',
|
||||||
|
width: '380px',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
boxShadow: 'var(--affine-shadow-1)',
|
boxShadow: 'var(--affine-shadow-1)',
|
||||||
border: '1px solid var(--affine-border-color)',
|
border: '1px solid var(--affine-border-color)',
|
||||||
@ -181,6 +216,26 @@ export const closeButtonStyle = style({
|
|||||||
export const closeButtonWithoutUndoStyle = style({
|
export const closeButtonWithoutUndoStyle = style({
|
||||||
marginLeft: '92px',
|
marginLeft: '92px',
|
||||||
});
|
});
|
||||||
|
export const closeButtonWithMediaStyle = style({
|
||||||
|
position: 'absolute',
|
||||||
|
width: '22px',
|
||||||
|
height: '22px',
|
||||||
|
fontSize: '16px',
|
||||||
|
top: '6px',
|
||||||
|
right: '6px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
cursor: 'pointer',
|
||||||
|
borderRadius: '4px',
|
||||||
|
color: 'var(--affine-pure-black)',
|
||||||
|
':hover': {
|
||||||
|
background: 'var(--affine-hover-color)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export const closeButtonColorStyle = style({
|
||||||
|
color: 'var(--affine-white)',
|
||||||
|
});
|
||||||
export const undoButtonStyle = style({
|
export const undoButtonStyle = style({
|
||||||
fontSize: 'var(--affine-font-sm)',
|
fontSize: 'var(--affine-font-sm)',
|
||||||
background: 'var(--affine-hover-color)',
|
background: 'var(--affine-hover-color)',
|
||||||
@ -189,6 +244,10 @@ export const undoButtonStyle = style({
|
|||||||
color: 'var(--affine-processing-color)',
|
color: 'var(--affine-processing-color)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
});
|
});
|
||||||
|
export const undoButtonWithMediaStyle = style({
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: '16px',
|
||||||
|
});
|
||||||
export const messageStyle = style({
|
export const messageStyle = style({
|
||||||
fontSize: 'var(--affine-font-sm)',
|
fontSize: 'var(--affine-font-sm)',
|
||||||
width: '200px',
|
width: '200px',
|
||||||
|
@ -8,6 +8,7 @@ export type Notification = {
|
|||||||
theme?: 'light' | 'dark';
|
theme?: 'light' | 'dark';
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
progressingBar?: boolean;
|
progressingBar?: boolean;
|
||||||
|
multimedia?: React.ReactNode | JSX.Element | HTMLElement;
|
||||||
// actions
|
// actions
|
||||||
undo?: () => Promise<void>;
|
undo?: () => Promise<void>;
|
||||||
};
|
};
|
||||||
|
@ -288,10 +288,20 @@ function NotificationCard(props: NotificationCardProps): ReactElement {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={clsx(styles.notificationContentStyle, {
|
className={clsx({
|
||||||
[typeStyle]: notification.theme,
|
[typeStyle]: notification.theme,
|
||||||
|
[styles.hasMediaStyle]: notification.multimedia,
|
||||||
|
[styles.notificationContentStyle]: !notification.multimedia,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
{notification.multimedia ? (
|
||||||
|
<div className={styles.notificationMultimediaStyle}>
|
||||||
|
<>{notification.multimedia}</>
|
||||||
|
<IconButton className={styles.closeButtonWithMediaStyle}>
|
||||||
|
<CloseIcon onClick={onClickRemove} />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<Toast.Title
|
<Toast.Title
|
||||||
className={clsx(styles.notificationTitleStyle, {
|
className={clsx(styles.notificationTitleStyle, {
|
||||||
[styles.darkColorStyle]: notification.theme === 'dark',
|
[styles.darkColorStyle]: notification.theme === 'dark',
|
||||||
@ -312,25 +322,28 @@ function NotificationCard(props: NotificationCardProps): ReactElement {
|
|||||||
<div
|
<div
|
||||||
className={clsx(styles.undoButtonStyle, {
|
className={clsx(styles.undoButtonStyle, {
|
||||||
[styles.darkColorStyle]: notification.theme === 'dark',
|
[styles.darkColorStyle]: notification.theme === 'dark',
|
||||||
|
[styles.undoButtonWithMediaStyle]: notification.multimedia,
|
||||||
})}
|
})}
|
||||||
onClick={onClickUndo}
|
onClick={onClickUndo}
|
||||||
>
|
>
|
||||||
UNDO
|
UNDO
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<IconButton
|
{notification.multimedia ? null : (
|
||||||
className={clsx(styles.closeButtonStyle, {
|
<IconButton
|
||||||
[styles.closeButtonWithoutUndoStyle]: !notification.undo,
|
className={clsx(styles.closeButtonStyle, {
|
||||||
})}
|
[styles.closeButtonWithoutUndoStyle]: !notification.undo,
|
||||||
style={{
|
})}
|
||||||
color:
|
style={{
|
||||||
notification.theme === 'dark'
|
color:
|
||||||
? 'var(--affine-white)'
|
notification.theme === 'dark'
|
||||||
: 'var(--affine-icon-color)',
|
? 'var(--affine-white)'
|
||||||
}}
|
: 'var(--affine-icon-color)',
|
||||||
>
|
}}
|
||||||
<CloseIcon onClick={onClickRemove} />
|
>
|
||||||
</IconButton>
|
<CloseIcon onClick={onClickRemove} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
</Toast.Title>
|
</Toast.Title>
|
||||||
<Toast.Description
|
<Toast.Description
|
||||||
className={clsx(styles.messageStyle, {
|
className={clsx(styles.messageStyle, {
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
ExportToPdfIcon,
|
ExportToPdfIcon,
|
||||||
ExportToPngIcon,
|
ExportToPngIcon,
|
||||||
} from '@blocksuite/icons';
|
} from '@blocksuite/icons';
|
||||||
|
import { uuidv4 } from '@blocksuite/store';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ export const ExportToPdfMenuItem = ({
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
onSelect?.({ type: 'pdf' });
|
onSelect?.({ type: 'pdf' });
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-pdf',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.success.title'](),
|
title: t['com.affine.export.success.title'](),
|
||||||
message: t['com.affine.export.success.message'](),
|
message: t['com.affine.export.success.message'](),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@ -45,7 +46,7 @@ export const ExportToPdfMenuItem = ({
|
|||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-pdf',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.error.title'](),
|
title: t['com.affine.export.error.title'](),
|
||||||
message: t['com.affine.export.error.message'](),
|
message: t['com.affine.export.error.message'](),
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@ -59,7 +60,7 @@ export const ExportToPdfMenuItem = ({
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
onSelect?.({ type: 'pdf' });
|
onSelect?.({ type: 'pdf' });
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-pdf',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.success.title'](),
|
title: t['com.affine.export.success.title'](),
|
||||||
message: t['com.affine.export.success.message'](),
|
message: t['com.affine.export.success.message'](),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@ -68,7 +69,7 @@ export const ExportToPdfMenuItem = ({
|
|||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-pdf',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.error.title'](),
|
title: t['com.affine.export.error.title'](),
|
||||||
message: t['com.affine.export.error.message'](),
|
message: t['com.affine.export.error.message'](),
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@ -104,7 +105,7 @@ export const ExportToHtmlMenuItem = ({
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
onSelect?.({ type: 'html' });
|
onSelect?.({ type: 'html' });
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-html',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.success.title'](),
|
title: t['com.affine.export.success.title'](),
|
||||||
message: t['com.affine.export.success.message'](),
|
message: t['com.affine.export.success.message'](),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@ -112,6 +113,12 @@ export const ExportToHtmlMenuItem = ({
|
|||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
setPushNotification({
|
||||||
|
key: uuidv4(),
|
||||||
|
title: t['com.affine.export.error.title'](),
|
||||||
|
message: t['com.affine.export.error.message'](),
|
||||||
|
type: 'error',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
onSelect?.({ type: 'html' });
|
onSelect?.({ type: 'html' });
|
||||||
}, [currentEditor, onSelect, setPushNotification, t]);
|
}, [currentEditor, onSelect, setPushNotification, t]);
|
||||||
@ -146,7 +153,7 @@ export const ExportToPngMenuItem = ({
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
onSelect?.({ type: 'png' });
|
onSelect?.({ type: 'png' });
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-png',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.success.title'](),
|
title: t['com.affine.export.success.title'](),
|
||||||
message: t['com.affine.export.success.message'](),
|
message: t['com.affine.export.success.message'](),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@ -155,7 +162,7 @@ export const ExportToPngMenuItem = ({
|
|||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-png',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.error.title'](),
|
title: t['com.affine.export.error.title'](),
|
||||||
message: t['com.affine.export.error.message'](),
|
message: t['com.affine.export.error.message'](),
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@ -192,7 +199,7 @@ export const ExportToMarkdownMenuItem = ({
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
onSelect?.({ type: 'markdown' });
|
onSelect?.({ type: 'markdown' });
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-markdown',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.success.title'](),
|
title: t['com.affine.export.success.title'](),
|
||||||
message: t['com.affine.export.success.message'](),
|
message: t['com.affine.export.success.message'](),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@ -201,7 +208,7 @@ export const ExportToMarkdownMenuItem = ({
|
|||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setPushNotification({
|
setPushNotification({
|
||||||
key: 'export-to-markdown',
|
key: uuidv4(),
|
||||||
title: t['com.affine.export.error.title'](),
|
title: t['com.affine.export.error.title'](),
|
||||||
message: t['com.affine.export.error.message'](),
|
message: t['com.affine.export.error.message'](),
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
Loading…
Reference in New Issue
Block a user