diff --git a/apps/web/src/components/pure/workspace-slider-bar/changeLog/index.tsx b/apps/web/src/components/pure/workspace-slider-bar/changeLog/index.tsx
index 87c1cf1098..2ecabaeb4e 100644
--- a/apps/web/src/components/pure/workspace-slider-bar/changeLog/index.tsx
+++ b/apps/web/src/components/pure/workspace-slider-bar/changeLog/index.tsx
@@ -1,21 +1,15 @@
-import { IconButton } from '@affine/component';
-import { useTranslation } from '@affine/i18n';
-import { CloseIcon, NewIcon } from '@blocksuite/icons';
-import { useCallback, useState } from 'react';
+import ChangeLogComponent from '@affine/component/changeLog';
+import { useCallback } from 'react';
import {
useGuideHidden,
useGuideHiddenUntilNextUpdate,
} from '../../../../hooks/use-is-first-load';
-import { StyledChangeLog, StyledChangeLogWrapper } from '../shared-styles';
-import { StyledLink } from '../style';
export const ChangeLog = () => {
const [guideHidden, setGuideHidden] = useGuideHidden();
const [guideHiddenUntilNextUpdate, setGuideHiddenUntilNextUpdate] =
useGuideHiddenUntilNextUpdate();
- const [isClose, setIsClose] = useState(false);
- const { t } = useTranslation();
const onCloseWhatsNew = useCallback(() => {
setTimeout(() => {
setGuideHiddenUntilNextUpdate({
@@ -33,28 +27,7 @@ export const ChangeLog = () => {
if (guideHiddenUntilNextUpdate.changeLog) {
return <>>;
}
- return (
-
-
-
-
- {t("Discover what's new!")}
-
- {
- setIsClose(true);
- onCloseWhatsNew();
- }}
- data-testid="change-log-close-button"
- >
-
-
-
-
- );
+ return ;
};
export default ChangeLog;
diff --git a/apps/web/src/components/pure/workspace-slider-bar/shared-styles.ts b/apps/web/src/components/pure/workspace-slider-bar/shared-styles.ts
index afaa6695e8..e79f4df47a 100644
--- a/apps/web/src/components/pure/workspace-slider-bar/shared-styles.ts
+++ b/apps/web/src/components/pure/workspace-slider-bar/shared-styles.ts
@@ -1,10 +1,4 @@
-import {
- alpha,
- displayFlex,
- keyframes,
- styled,
- textEllipsis,
-} from '@affine/component';
+import { alpha, displayFlex, styled, textEllipsis } from '@affine/component';
export const StyledListItem = styled('div')<{
active?: boolean;
@@ -123,105 +117,6 @@ export const StyledCollapseItem = styled('div')<{
};
});
-const slideIn = keyframes({
- '0%': {
- height: '0px',
- },
- '50%': {
- height: '36px',
- },
- '100%': {
- height: '32px',
- },
-});
-const slideIn2 = keyframes({
- '0%': {
- transform: 'translateX(100%)',
- },
- '50%': {
- transform: 'translateX(100%)',
- },
- '80%': {
- transform: 'translateX(-10%)',
- },
- '100%': {
- transform: 'translateX(0%)',
- },
-});
-
-const slideOut = keyframes({
- '0%': {
- height: '32px',
- },
- '60%': {
- height: '32px',
- },
- '80%': {
- height: '32px',
- },
- '100%': {
- height: '0px',
- },
-});
-const slideOut2 = keyframes({
- '0%': {
- transform: 'translateX(0%)',
- },
- '100%': {
- transform: 'translateX(100%)',
- },
-});
-
-export const StyledChangeLog = styled('div')<{
- isClose?: boolean;
-}>(({ isClose }) => {
- return {
- width: '110%',
- height: '32px',
- ...displayFlex('flex-start', 'center'),
- color: 'var(--affine-primary-color)',
- backgroundColor: 'var(--affine-hover-color)',
- border: '1px solid var(--affine-primary-color)',
- borderRight: 'none',
- marginLeft: '8px',
- paddingLeft: '8px',
- borderRadius: '16px 0 0 16px',
- cursor: 'pointer',
- zIndex: 1001,
- position: 'absolute',
- userSelect: 'none',
- transition: 'all 0.3s',
- animation: isClose
- ? `${slideOut2} .3s ease-in-out forwards`
- : `${slideIn2} 1s ease-in-out forwards`,
- '> svg, a > svg': {
- fontSize: '20px',
- marginRight: '12px',
- color: 'var(--affine-primary-color)',
- },
- button: {
- marginRight: '12%',
- },
- };
-});
-export const StyledChangeLogWrapper = styled('div')<{
- isClose?: boolean;
-}>(({ isClose }) => {
- return {
- width: 'calc(100% + 4px)',
- height: '0px',
- animation: isClose
- ? `${slideOut} .3s ease-in-out forwards`
- : `${slideIn} 1s ease-in-out forwards`,
- ...displayFlex('flex-start', 'center'),
- marginBottom: '4px',
- position: 'relative',
- userSelect: 'none',
- transition: 'all 0.3s',
- overflow: 'hidden',
- };
-});
-
export const StyledRouteNavigationWrapper = styled('div')({
height: '32px',
width: '80px',
diff --git a/packages/component/src/components/changeLog/index.css.ts b/packages/component/src/components/changeLog/index.css.ts
new file mode 100644
index 0000000000..05e1012308
--- /dev/null
+++ b/packages/component/src/components/changeLog/index.css.ts
@@ -0,0 +1,108 @@
+import { keyframes, style } from '@vanilla-extract/css';
+
+const slideIn = keyframes({
+ '0%': {
+ height: '0px',
+ },
+ '50%': {
+ height: '36px',
+ },
+ '100%': {
+ height: '32px',
+ },
+});
+const slideIn2 = keyframes({
+ '0%': {
+ transform: 'translateX(100%)',
+ },
+ '50%': {
+ transform: 'translateX(100%)',
+ },
+ '80%': {
+ transform: 'translateX(-10%)',
+ },
+ '100%': {
+ transform: 'translateX(0%)',
+ },
+});
+
+const slideOut = keyframes({
+ '0%': {
+ height: '32px',
+ },
+ '60%': {
+ height: '32px',
+ },
+ '80%': {
+ height: '32px',
+ },
+ '100%': {
+ height: '0px',
+ },
+});
+const slideOut2 = keyframes({
+ '0%': {
+ transform: 'translateX(0%)',
+ },
+ '100%': {
+ transform: 'translateX(100%)',
+ },
+});
+
+export const changeLogWrapperSlideInStyle = style({
+ width: 'calc(100% + 4px)',
+ height: '0px',
+ animation: `${slideIn} 1s ease-in-out forwards`,
+ display: 'flex',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ marginBottom: '4px',
+ position: 'relative',
+ userSelect: 'none',
+ transition: 'all 0.3s',
+ overflow: 'hidden',
+});
+export const changeLogWrapperSlideOutStyle = style({
+ animation: `${slideOut} .3s ease-in-out forwards`,
+});
+export const changeLogSlideInStyle = style({
+ width: '110%',
+ height: '32px',
+ display: 'flex',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ color: 'var(--affine-primary-color)',
+ backgroundColor: 'var(--affine-tertiary-color)',
+ border: '1px solid var(--affine-primary-color)',
+ borderRight: 'none',
+ marginLeft: '8px',
+ paddingLeft: '8px',
+ borderRadius: '16px 0 0 16px',
+ cursor: 'pointer',
+ zIndex: 1001,
+ position: 'absolute',
+ userSelect: 'none',
+ transition: 'all 0.3s',
+ animation: `${slideIn2} 1s ease-in-out forwards`,
+});
+export const changeLogSlideOutStyle = style({
+ animation: `${slideOut2} .3s ease-in-out forwards`,
+});
+export const linkStyle = style({
+ flexGrow: 1,
+ textAlign: 'left',
+ color: 'inherit',
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+});
+export const iconStyle = style({
+ fontSize: '20px',
+ marginRight: '12px',
+});
+export const iconButtonStyle = style({
+ fontSize: '20px',
+ marginRight: '12%',
+ color: 'var(--affine-icon-color)',
+});
diff --git a/packages/component/src/components/changeLog/index.tsx b/packages/component/src/components/changeLog/index.tsx
new file mode 100644
index 0000000000..f55f9577d7
--- /dev/null
+++ b/packages/component/src/components/changeLog/index.tsx
@@ -0,0 +1,66 @@
+import { useTranslation } from '@affine/i18n';
+import { CloseIcon, NewIcon } from '@blocksuite/icons';
+import clsx from 'clsx';
+import { useState } from 'react';
+
+import { IconButton } from '../..';
+import {
+ changeLogSlideInStyle,
+ changeLogSlideOutStyle,
+ changeLogWrapperSlideInStyle,
+ changeLogWrapperSlideOutStyle,
+ iconButtonStyle,
+ iconStyle,
+ linkStyle,
+} from './index.css';
+
+type ChangeLogProps = {
+ onCloseWhatsNew: () => void;
+};
+export const ChangeLog = (props: ChangeLogProps) => {
+ const { onCloseWhatsNew } = props;
+ const [isClose, setIsClose] = useState(false);
+ const { t } = useTranslation();
+ const handleClose = () => {
+ setIsClose(true);
+ onCloseWhatsNew();
+ };
+ return (
+
+
+
{
+ window.open(
+ 'https://github.com/toeverything/AFFiNE/releases',
+ '_blank'
+ );
+ }}
+ >
+
+ {t("Discover what's new!")}
+
+
{
+ handleClose();
+ }}
+ data-testid="change-log-close-button"
+ >
+
+
+
+
+ );
+};
+
+export default ChangeLog;
diff --git a/packages/component/src/stories/ChangeLog.stories.tsx b/packages/component/src/stories/ChangeLog.stories.tsx
new file mode 100644
index 0000000000..2234e1ea5d
--- /dev/null
+++ b/packages/component/src/stories/ChangeLog.stories.tsx
@@ -0,0 +1,48 @@
+import type { StoryFn } from '@storybook/react';
+import { within } from '@storybook/testing-library';
+import { useState } from 'react';
+
+import { ChangeLog } from '../components/changeLog';
+
+export default {
+ title: 'AFFiNE/ChangeLog',
+ component: ChangeLog,
+};
+
+export const Default: StoryFn = () => (
+
+ {}} />
+
+);
+
+export const Close: StoryFn = () => {
+ const [closed, setIsClosed] = useState(false);
+ return (
+ <>
+ Closed: {closed ? 'true' : 'false'}
+
+ {
+ setIsClosed(true);
+ }}
+ />
+
+ >
+ );
+};
+
+Close.play = async ({ canvasElement }) => {
+ const element = within(canvasElement);
+ await new Promise(resolve => setTimeout(resolve, 2000));
+ await element.getByTestId('change-log-close-button').click();
+};