mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-26 02:35:58 +08:00
chore: add changeLog to storybook (#2118)
Co-authored-by: himself65 <himself65@outlook.com>
This commit is contained in:
@@ -1,21 +1,15 @@
|
|||||||
import { IconButton } from '@affine/component';
|
import ChangeLogComponent from '@affine/component/changeLog';
|
||||||
import { useTranslation } from '@affine/i18n';
|
import { useCallback } from 'react';
|
||||||
import { CloseIcon, NewIcon } from '@blocksuite/icons';
|
|
||||||
import { useCallback, useState } from 'react';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useGuideHidden,
|
useGuideHidden,
|
||||||
useGuideHiddenUntilNextUpdate,
|
useGuideHiddenUntilNextUpdate,
|
||||||
} from '../../../../hooks/use-is-first-load';
|
} from '../../../../hooks/use-is-first-load';
|
||||||
import { StyledChangeLog, StyledChangeLogWrapper } from '../shared-styles';
|
|
||||||
import { StyledLink } from '../style';
|
|
||||||
|
|
||||||
export const ChangeLog = () => {
|
export const ChangeLog = () => {
|
||||||
const [guideHidden, setGuideHidden] = useGuideHidden();
|
const [guideHidden, setGuideHidden] = useGuideHidden();
|
||||||
const [guideHiddenUntilNextUpdate, setGuideHiddenUntilNextUpdate] =
|
const [guideHiddenUntilNextUpdate, setGuideHiddenUntilNextUpdate] =
|
||||||
useGuideHiddenUntilNextUpdate();
|
useGuideHiddenUntilNextUpdate();
|
||||||
const [isClose, setIsClose] = useState(false);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const onCloseWhatsNew = useCallback(() => {
|
const onCloseWhatsNew = useCallback(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setGuideHiddenUntilNextUpdate({
|
setGuideHiddenUntilNextUpdate({
|
||||||
@@ -33,28 +27,7 @@ export const ChangeLog = () => {
|
|||||||
if (guideHiddenUntilNextUpdate.changeLog) {
|
if (guideHiddenUntilNextUpdate.changeLog) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
return (
|
return <ChangeLogComponent onCloseWhatsNew={onCloseWhatsNew} />;
|
||||||
<StyledChangeLogWrapper isClose={isClose}>
|
|
||||||
<StyledChangeLog data-testid="change-log" isClose={isClose}>
|
|
||||||
<StyledLink
|
|
||||||
href="https://github.com/toeverything/AFFiNE/releases"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<NewIcon />
|
|
||||||
{t("Discover what's new!")}
|
|
||||||
</StyledLink>
|
|
||||||
<IconButton
|
|
||||||
onClick={() => {
|
|
||||||
setIsClose(true);
|
|
||||||
onCloseWhatsNew();
|
|
||||||
}}
|
|
||||||
data-testid="change-log-close-button"
|
|
||||||
>
|
|
||||||
<CloseIcon />
|
|
||||||
</IconButton>
|
|
||||||
</StyledChangeLog>
|
|
||||||
</StyledChangeLogWrapper>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ChangeLog;
|
export default ChangeLog;
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
import {
|
import { alpha, displayFlex, styled, textEllipsis } from '@affine/component';
|
||||||
alpha,
|
|
||||||
displayFlex,
|
|
||||||
keyframes,
|
|
||||||
styled,
|
|
||||||
textEllipsis,
|
|
||||||
} from '@affine/component';
|
|
||||||
|
|
||||||
export const StyledListItem = styled('div')<{
|
export const StyledListItem = styled('div')<{
|
||||||
active?: boolean;
|
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')({
|
export const StyledRouteNavigationWrapper = styled('div')({
|
||||||
height: '32px',
|
height: '32px',
|
||||||
width: '80px',
|
width: '80px',
|
||||||
|
|||||||
108
packages/component/src/components/changeLog/index.css.ts
Normal file
108
packages/component/src/components/changeLog/index.css.ts
Normal file
@@ -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)',
|
||||||
|
});
|
||||||
66
packages/component/src/components/changeLog/index.tsx
Normal file
66
packages/component/src/components/changeLog/index.tsx
Normal file
@@ -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 (
|
||||||
|
<div
|
||||||
|
className={clsx(changeLogWrapperSlideInStyle, {
|
||||||
|
[changeLogWrapperSlideOutStyle]: isClose,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-testid="change-log"
|
||||||
|
className={clsx(changeLogSlideInStyle, {
|
||||||
|
[changeLogSlideOutStyle]: isClose,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={linkStyle}
|
||||||
|
onClick={() => {
|
||||||
|
window.open(
|
||||||
|
'https://github.com/toeverything/AFFiNE/releases',
|
||||||
|
'_blank'
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<NewIcon className={iconStyle} />
|
||||||
|
{t("Discover what's new!")}
|
||||||
|
</div>
|
||||||
|
<IconButton
|
||||||
|
className={iconButtonStyle}
|
||||||
|
onClick={() => {
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
data-testid="change-log-close-button"
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChangeLog;
|
||||||
48
packages/component/src/stories/ChangeLog.stories.tsx
Normal file
48
packages/component/src/stories/ChangeLog.stories.tsx
Normal file
@@ -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 = () => (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '256px',
|
||||||
|
height: '100vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ChangeLog onCloseWhatsNew={() => {}} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Close: StoryFn = () => {
|
||||||
|
const [closed, setIsClosed] = useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>Closed: {closed ? 'true' : 'false'}</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '256px',
|
||||||
|
height: '100vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ChangeLog
|
||||||
|
onCloseWhatsNew={() => {
|
||||||
|
setIsClosed(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Close.play = async ({ canvasElement }) => {
|
||||||
|
const element = within(canvasElement);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
await element.getByTestId('change-log-close-button').click();
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user