From b978bb171aef50040a1a5e464a519803e12b63ad Mon Sep 17 00:00:00 2001 From: JimmFly Date: Wed, 10 May 2023 00:07:34 +0800 Subject: [PATCH] feat: add download tips banner (#2151) --- apps/web/src/atoms/guide.ts | 18 ++++ .../workspace-header/download-tips.tsx | 22 +++++ .../blocksuite/workspace-header/header.tsx | 49 +++++------ .../affine-banner/browser-warning.tsx | 32 +++++++ .../affine-banner/download-client.tsx | 44 ++++++++++ .../src/components/affine-banner/index.css.ts | 87 +++++++++++++++++++ .../src/components/affine-banner/index.tsx | 2 + .../src/stories/affine-banner.stories.tsx | 37 ++++++++ tests/parallels/open-affine.spec.ts | 18 ++++ 9 files changed, 282 insertions(+), 27 deletions(-) create mode 100644 apps/web/src/components/blocksuite/workspace-header/download-tips.tsx create mode 100644 packages/component/src/components/affine-banner/browser-warning.tsx create mode 100644 packages/component/src/components/affine-banner/download-client.tsx create mode 100644 packages/component/src/components/affine-banner/index.css.ts create mode 100644 packages/component/src/components/affine-banner/index.tsx create mode 100644 packages/component/src/stories/affine-banner.stories.tsx diff --git a/apps/web/src/atoms/guide.ts b/apps/web/src/atoms/guide.ts index 305438b8ef..06535ac875 100644 --- a/apps/web/src/atoms/guide.ts +++ b/apps/web/src/atoms/guide.ts @@ -10,12 +10,15 @@ export type Guide = { changeLog: boolean; // should show recording tips onBoarding: boolean; + // should show download client tips + downloadClientTip: boolean; }; const guidePrimitiveAtom = atomWithStorage('helper-guide', { quickSearchTips: true, changeLog: true, onBoarding: true, + downloadClientTip: true, }); export const guideQuickSearchTipsAtom = atom< @@ -67,3 +70,18 @@ export const guideOnboardingAtom = atom< })); } ); +export const guideDownloadClientTipAtom = atom< + Guide['downloadClientTip'], + [open: boolean], + void +>( + get => { + return get(guidePrimitiveAtom).downloadClientTip; + }, + (_, set, open) => { + set(guidePrimitiveAtom, tips => ({ + ...tips, + downloadClientTip: open, + })); + } +); diff --git a/apps/web/src/components/blocksuite/workspace-header/download-tips.tsx b/apps/web/src/components/blocksuite/workspace-header/download-tips.tsx new file mode 100644 index 0000000000..1e56f270cd --- /dev/null +++ b/apps/web/src/components/blocksuite/workspace-header/download-tips.tsx @@ -0,0 +1,22 @@ +import { DownloadTips } from '@affine/component/affine-banner'; +import { getEnvironment } from '@affine/env'; +import { useAtom } from 'jotai'; +import { useCallback } from 'react'; + +import { guideDownloadClientTipAtom } from '../../../atoms/guide'; + +export const DownloadClientTip = () => { + const env = getEnvironment(); + const [showDownloadClientTips, setShowDownloadClientTips] = useAtom( + guideDownloadClientTipAtom + ); + const onCloseDownloadClient = useCallback(() => { + setShowDownloadClientTips(false); + }, [setShowDownloadClientTips]); + + if (!showDownloadClientTips || env.isDesktop) { + return <>; + } + return ; +}; +export default DownloadClientTip; diff --git a/apps/web/src/components/blocksuite/workspace-header/header.tsx b/apps/web/src/components/blocksuite/workspace-header/header.tsx index 4e9b6a2acc..cda6e601ca 100644 --- a/apps/web/src/components/blocksuite/workspace-header/header.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/header.tsx @@ -1,7 +1,7 @@ +import { BrowserWarning } from '@affine/component/affine-banner'; import { appSidebarOpenAtom } from '@affine/component/app-sidebar'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { WorkspaceFlavour } from '@affine/workspace/type'; -import { CloseIcon } from '@blocksuite/icons'; import type { Page } from '@blocksuite/store'; import { useAtom } from 'jotai'; import type { FC, HTMLAttributes, PropsWithChildren } from 'react'; @@ -14,8 +14,10 @@ import { useState, } from 'react'; +import { guideDownloadClientTipAtom } from '../../../atoms/guide'; import { useCurrentMode } from '../../../hooks/current/use-current-mode'; import type { AffineOfficialWorkspace } from '../../../shared'; +import { DownloadClientTip } from './download-tips'; import EditPage from './header-right-items/edit-page'; import { EditorOptionMenu } from './header-right-items/editor-option-menu'; import { HeaderShareMenu } from './header-right-items/share-menu'; @@ -23,8 +25,6 @@ import SyncUser from './header-right-items/sync-user'; import TrashButtonGroup from './header-right-items/trash-button-group'; import UserAvatar from './header-right-items/user-avatar'; import { - StyledBrowserWarning, - StyledCloseButton, StyledHeader, StyledHeaderContainer, StyledHeaderRightSide, @@ -37,23 +37,6 @@ const SidebarSwitch = lazy(() => })) ); -const BrowserWarning = ({ - show, - onClose, -}: { - show: boolean; - onClose: () => void; -}) => { - return ( - - - - - - - ); -}; - export type BaseHeaderProps< Workspace extends AffineOfficialWorkspace = AffineOfficialWorkspace > = { @@ -130,9 +113,15 @@ export const Header = forwardRef< PropsWithChildren & HTMLAttributes >((props, ref) => { const [showWarning, setShowWarning] = useState(false); + const [showGuideDownloadClientTip, setShowGuideDownloadClientTip] = + useState(false); + const [shouldShowGuideDownloadClientTip] = useAtom( + guideDownloadClientTipAtom + ); useEffect(() => { setShowWarning(shouldShowWarning()); - }, []); + setShowGuideDownloadClientTip(shouldShowGuideDownloadClientTip); + }, [shouldShowGuideDownloadClientTip]); const [open] = useAtom(appSidebarOpenAtom); const t = useAFFiNEI18N(); @@ -144,12 +133,18 @@ export const Header = forwardRef< data-open={open} {...props} > - { - setShowWarning(false); - }} - /> + {showGuideDownloadClientTip ? ( + + ) : ( + } + onClose={() => { + setShowWarning(false); + }} + /> + )} + void; + message: React.ReactNode; +}) => { + if (!show) { + return null; + } + return ( +
+ {message} +
+ +
+
+ ); +}; + +export default BrowserWarning; diff --git a/packages/component/src/components/affine-banner/download-client.tsx b/packages/component/src/components/affine-banner/download-client.tsx new file mode 100644 index 0000000000..59affec0f9 --- /dev/null +++ b/packages/component/src/components/affine-banner/download-client.tsx @@ -0,0 +1,44 @@ +import { AffineLogoSimSBlue1_1Icon, CloseIcon } from '@blocksuite/icons'; + +import { + downloadCloseButtonStyle, + downloadMessageStyle, + downloadTipContainerStyle, + downloadTipIconStyle, + downloadTipStyle, + linkStyle, +} from './index.css'; + +export const DownloadTips = ({ onClose }: { onClose: () => void }) => { + return ( +
+
+ +
+ Enjoying the demo?   + + Download the AFFiNE Client + +  for the full experience. +
+
+
+ +
+
+ ); +}; + +export default DownloadTips; diff --git a/packages/component/src/components/affine-banner/index.css.ts b/packages/component/src/components/affine-banner/index.css.ts new file mode 100644 index 0000000000..515f15c760 --- /dev/null +++ b/packages/component/src/components/affine-banner/index.css.ts @@ -0,0 +1,87 @@ +import { keyframes, style } from '@vanilla-extract/css'; + +const slideDown = keyframes({ + '0%': { + height: '0px', + }, + '100%': { + height: '44px', + }, +}); + +export const browserWarningStyle = style({ + backgroundColor: 'var(--affine-background-warning-color)', + color: 'var(--affine-warning-color)', + height: '36px', + fontSize: 'var(--affine-font-sm)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + position: 'relative', +}); +export const closeButtonStyle = style({ + width: '36px', + height: '36px', + color: 'var(--affine-icon-color)', + cursor: 'pointer', + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + position: 'absolute', + right: '16px', +}); +export const closeIconStyle = style({ + width: '15px', + height: '15px', + position: 'relative', + zIndex: 1, +}); +export const downloadTipContainerStyle = style({ + backgroundColor: 'var(--affine-primary-color)', + color: 'var(--affine-white)', + width: '100%', + height: '44px', + fontSize: 'var(--affine-font-base)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + position: 'relative', + animation: `${slideDown} .3s ease-in-out forwards`, +}); +export const downloadTipStyle = style({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); +export const downloadTipIconStyle = style({ + color: 'var(--affine-white)', + width: '24px', + height: '24px', + fontSize: '24px', + position: 'relative', + zIndex: 1, +}); +export const downloadCloseButtonStyle = style({ + color: 'var(--affine-white)', + cursor: 'pointer', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + position: 'absolute', + right: '24px', +}); +export const downloadMessageStyle = style({ + color: 'var(--affine-white)', + marginLeft: '8px', +}); +export const linkStyle = style({ + color: 'var(--affine-white)', + textDecoration: 'underline', + ':hover': { + textDecoration: 'underline', + }, + ':visited': { + color: 'var(--affine-white)', + textDecoration: 'underline', + }, +}); diff --git a/packages/component/src/components/affine-banner/index.tsx b/packages/component/src/components/affine-banner/index.tsx new file mode 100644 index 0000000000..24c34dfbfb --- /dev/null +++ b/packages/component/src/components/affine-banner/index.tsx @@ -0,0 +1,2 @@ +export * from './browser-warning'; +export * from './download-client'; diff --git a/packages/component/src/stories/affine-banner.stories.tsx b/packages/component/src/stories/affine-banner.stories.tsx new file mode 100644 index 0000000000..8a7577d707 --- /dev/null +++ b/packages/component/src/stories/affine-banner.stories.tsx @@ -0,0 +1,37 @@ +import type { StoryFn } from '@storybook/react'; +import { useState } from 'react'; + +import { BrowserWarning, DownloadTips } from '../components/affine-banner'; + +export default { + title: 'AFFiNE/Banner', + component: BrowserWarning, +}; + +export const Default: StoryFn = () => { + const [closed, setIsClosed] = useState(true); + return ( +
+ test} + show={closed} + onClose={() => { + setIsClosed(false); + }} + /> +
+ ); +}; + +export const Download: StoryFn = () => { + const [, setIsClosed] = useState(true); + return ( +
+ { + setIsClosed(false); + }} + /> +
+ ); +}; diff --git a/tests/parallels/open-affine.spec.ts b/tests/parallels/open-affine.spec.ts index 11bb1bd451..d286fb98c5 100644 --- a/tests/parallels/open-affine.spec.ts +++ b/tests/parallels/open-affine.spec.ts @@ -54,3 +54,21 @@ test('Click right-bottom corner change log icon', async ({ page }) => { ); expect(await normalRightBottomChangeLog.isVisible()).toEqual(true); }); + +test('Download client tip', async ({ page }) => { + await openHomePage(page); + const downloadClientTipItem = page.locator( + '[data-testid=download-client-tip]' + ); + await expect(downloadClientTipItem).toBeVisible(); + const closeButton = page.locator( + '[data-testid=download-client-tip-close-button]' + ); + await closeButton.click(); + await expect(downloadClientTipItem).not.toBeVisible(); + await page.goto('http://localhost:8080'); + const currentDownloadClientTipItem = page.locator( + '[data-testid=download-client-tip]' + ); + await expect(currentDownloadClientTipItem).not.toBeVisible(); +});