fix: open in app card style (#8667)

This commit is contained in:
Peng Xiao
2024-11-01 18:42:09 +08:00
committed by GitHub
parent 7e71395c8e
commit ecbf5a95fa
8 changed files with 149 additions and 92 deletions

View File

@@ -44,10 +44,7 @@ export const OpenInAppLinksMenu = () => {
align: 'end', align: 'end',
}} }}
> >
<MenuTrigger <MenuTrigger style={{ fontWeight: 600, width: '250px' }} block={true}>
style={{ textTransform: 'capitalize', fontWeight: 600, width: '250px' }}
block={true}
>
{options.find(option => option.value === currentOpenInAppMode)?.label} {options.find(option => option.value === currentOpenInAppMode)?.label}
</MenuTrigger> </MenuTrigger>
</Menu> </Menu>

View File

@@ -3,7 +3,10 @@ import {
pushGlobalLoadingEventAtom, pushGlobalLoadingEventAtom,
resolveGlobalLoadingEventAtom, resolveGlobalLoadingEventAtom,
} from '@affine/component/global-loading'; } from '@affine/component/global-loading';
import { SidebarSwitch } from '@affine/core/modules/app-sidebar/views'; import {
OpenInAppCard,
SidebarSwitch,
} from '@affine/core/modules/app-sidebar/views';
import { WorkspaceDesktopApiService } from '@affine/core/modules/desktop-api/service'; import { WorkspaceDesktopApiService } from '@affine/core/modules/desktop-api/service';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { type DocMode, ZipTransformer } from '@blocksuite/affine/blocks'; import { type DocMode, ZipTransformer } from '@blocksuite/affine/blocks';
@@ -205,6 +208,7 @@ const DesktopLayout = ({ children }: PropsWithChildren) => {
const BrowserLayout = ({ children }: PropsWithChildren) => { const BrowserLayout = ({ children }: PropsWithChildren) => {
return ( return (
<div className={styles.browserAppViewContainer}> <div className={styles.browserAppViewContainer}>
<OpenInAppCard />
<RootAppSidebar /> <RootAppSidebar />
<MainContainer>{children}</MainContainer> <MainContainer>{children}</MainContainer>
</div> </div>

View File

@@ -5,11 +5,11 @@ import {
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { import {
AddPageButton, AddPageButton,
AppDownloadButton,
AppSidebar, AppSidebar,
CategoryDivider, CategoryDivider,
MenuItem, MenuItem,
MenuLinkItem, MenuLinkItem,
OpenInAppCard,
QuickSearchInput, QuickSearchInput,
SidebarContainer, SidebarContainer,
SidebarScrollableContainer, SidebarScrollableContainer,
@@ -191,7 +191,7 @@ export const RootAppSidebar = (): ReactElement => {
</div> </div>
</SidebarScrollableContainer> </SidebarScrollableContainer>
<SidebarContainer> <SidebarContainer>
{BUILD_CONFIG.isElectron ? <UpdaterButton /> : <OpenInAppCard />} {BUILD_CONFIG.isElectron ? <UpdaterButton /> : <AppDownloadButton />}
</SidebarContainer> </SidebarContainer>
</AppSidebar> </AppSidebar>
); );

View File

@@ -57,9 +57,3 @@ export const linkText = style({
fontWeight: 700, fontWeight: 700,
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
}); });
export const shareCard = style({
position: 'fixed',
bottom: '16px',
left: '16px',
});

View File

@@ -167,7 +167,7 @@ const SharePageWebContainer = ({
{children} {children}
<SharePageFooter /> <SharePageFooter />
</div> </div>
<OpenInAppCard className={styles.shareCard} /> <OpenInAppCard />
</div> </div>
</MainContainer> </MainContainer>
); );

View File

@@ -2,12 +2,28 @@ import { cssVar } from '@toeverything/theme';
import { cssVarV2 } from '@toeverything/theme/v2'; import { cssVarV2 } from '@toeverything/theme/v2';
import { style } from '@vanilla-extract/css'; import { style } from '@vanilla-extract/css';
const width = 440;
export const root = style({ export const root = style({
background: cssVarV2('layer/background/primary'), background: cssVarV2('layer/background/primary'),
borderRadius: '8px', borderRadius: '8px',
border: `1px solid ${cssVarV2('layer/insideBorder/border')}`, border: `1px solid ${cssVarV2('layer/insideBorder/border')}`,
cursor: 'default', cursor: 'default',
userSelect: 'none', padding: '12px 10px',
boxShadow: cssVar('shadow1'),
display: 'flex',
gap: 8,
position: 'fixed',
bottom: 16,
left: `calc(50dvw - ${width / 2}px)`,
width,
zIndex: cssVar('zIndexPopover'),
transition: 'transform 0.2s ease-in-out',
selectors: {
'&[data-hidden="true"]': {
transform: 'translateY(200%)',
},
},
}); });
export const pane = style({ export const pane = style({
@@ -22,48 +38,86 @@ export const pane = style({
}, },
}); });
export const row = style({
fontSize: cssVar('fontSm'),
fontWeight: 400,
display: 'flex',
alignItems: 'center',
columnGap: 10,
color: cssVarV2('text/secondary'),
});
export const clickableRow = style([
row,
{
cursor: 'pointer',
},
]);
export const buttonGroup = style({ export const buttonGroup = style({
display: 'flex', display: 'flex',
gap: 4, gap: 4,
justifyContent: 'flex-end',
}); });
export const button = style({ export const button = style({
height: 26, height: 26,
borderRadius: 4, borderRadius: 8,
padding: '0 8px', padding: '0 12px',
fontSize: cssVar('fontXs'),
}); });
export const primaryRow = style([ export const titleRow = style({
row, display: 'inline-flex',
{ alignItems: 'center',
color: cssVarV2('text/primary'), fontSize: cssVar('fontSm'),
}, color: cssVarV2('text/primary'),
]); fontWeight: 500,
});
export const icon = style({ export const subtitleRow = style({
fontSize: cssVar('fontXs'),
color: cssVarV2('text/primary'),
marginTop: 4,
});
export const controlsRow = style({
display: 'flex',
alignItems: 'center',
marginTop: 8,
});
export const rememberLabel = style({
display: 'flex',
alignItems: 'center',
gap: 4,
fontWeight: 500,
fontSize: cssVar('fontXs'),
cursor: 'pointer',
});
export const rememberCheckbox = style({
width: 20, width: 20,
height: 20, height: 20,
flexShrink: 0, flexShrink: 0,
fontSize: 20, fontSize: 20,
selectors: { color: cssVarV2('icon/primary'),
[`${primaryRow} &`]: { });
color: cssVarV2('icon/activated'),
}, export const closeButton = style({
}, width: 24,
height: 24,
flexShrink: 0,
fontSize: 24,
});
export const contentCol = style({
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
flex: 1,
});
export const appIconCol = style({
display: 'flex',
justifyContent: 'flex-start',
});
export const appIcon = style({
width: 48,
height: 48,
flexShrink: 0,
});
export const spacer = style({
flex: 1,
});
export const link = style({
color: cssVarV2('text/link'),
textDecoration: 'underline',
}); });

View File

@@ -1,18 +1,17 @@
import { Button, Checkbox } from '@affine/component'; import { Button, Checkbox, IconButton } from '@affine/component';
import { import {
OpenInAppService, OpenInAppService,
OpenLinkMode, OpenLinkMode,
} from '@affine/core/modules/open-in-app'; } from '@affine/core/modules/open-in-app';
import { useI18n } from '@affine/i18n'; import { appIconMap } from '@affine/core/utils';
import { track } from '@affine/track'; import { Trans, useI18n } from '@affine/i18n';
import { DownloadIcon, LocalWorkspaceIcon } from '@blocksuite/icons/rc'; import { CloseIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import clsx from 'clsx';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import * as styles from './open-in-app-card.css'; import * as styles from './open-in-app-card.css';
export const OpenInAppCard = ({ className }: { className?: string }) => { export const OpenInAppCard = () => {
const openInAppService = useService(OpenInAppService); const openInAppService = useService(OpenInAppService);
const show = useLiveData(openInAppService.showOpenInAppBanner$); const show = useLiveData(openInAppService.showOpenInAppBanner$);
const t = useI18n(); const t = useI18n();
@@ -22,7 +21,7 @@ export const OpenInAppCard = ({ className }: { className?: string }) => {
const onOpen = useCallback(() => { const onOpen = useCallback(() => {
openInAppService.showOpenInAppPage(); openInAppService.showOpenInAppPage();
if (remember) { if (remember) {
openInAppService.setOpenLinkMode(OpenLinkMode.OPEN_IN_DESKTOP_APP); openInAppService.dismissBanner(OpenLinkMode.OPEN_IN_DESKTOP_APP);
} }
}, [openInAppService, remember]); }, [openInAppService, remember]);
@@ -36,34 +35,48 @@ export const OpenInAppCard = ({ className }: { className?: string }) => {
setRemember(v => !v); setRemember(v => !v);
}, []); }, []);
const handleDownload = useCallback(() => { const appIcon = appIconMap[BUILD_CONFIG.appBuildType];
track.$.navigationPanel.bottomButtons.downloadApp();
const url = `https://affine.pro/download?channel=stable`;
open(url, '_blank');
}, []);
if (!show) {
return null;
}
return ( return (
<div className={clsx(styles.root, className)}> <div className={styles.root} data-hidden={!show}>
<div className={styles.pane}> <div className={styles.appIconCol}>
<div className={styles.primaryRow}> <img src={appIcon} alt="app icon" width={48} height={48} />
<LocalWorkspaceIcon className={styles.icon} /> </div>
<div>{t.t('com.affine.open-in-app.card.title')}</div> <div className={styles.contentCol}>
<div className={styles.titleRow}>
{t.t('com.affine.open-in-app.card.title')}
<div className={styles.spacer} />
<IconButton
className={styles.closeButton}
icon={<CloseIcon />}
onClick={onDismiss}
/>
</div> </div>
<div className={styles.row}> <div className={styles.subtitleRow}>
<div className={styles.icon}>{/* placeholder */}</div> <Trans i18nKey="com.affine.open-in-app.card.subtitle">
<div className={styles.buttonGroup}> No desktop app?
<Button <a
variant="primary" href="https://affine.pro/download"
size="custom" target="_blank"
className={styles.button} rel="noreferrer"
onClick={onOpen} className={styles.link}
> >
{t.t('com.affine.open-in-app.card.button.open')} Click to download
</Button> </a>
.
</Trans>
</div>
<div className={styles.controlsRow}>
<label className={styles.rememberLabel}>
<Checkbox
className={styles.rememberCheckbox}
checked={remember}
onChange={onToggleRemember}
/>
{t.t('com.affine.open-in-app.card.remember')}
</label>
<div className={styles.spacer} />
<div className={styles.buttonGroup}>
<Button <Button
variant="secondary" variant="secondary"
size="custom" size="custom"
@@ -72,23 +85,17 @@ export const OpenInAppCard = ({ className }: { className?: string }) => {
> >
{t.t('com.affine.open-in-app.card.button.dismiss')} {t.t('com.affine.open-in-app.card.button.dismiss')}
</Button> </Button>
<Button
variant="primary"
size="custom"
className={styles.button}
onClick={onOpen}
>
{t.t('com.affine.open-in-app.card.button.open')}
</Button>
</div> </div>
</div> </div>
</div> </div>
<div className={styles.pane}>
<div className={styles.clickableRow} onClick={onToggleRemember}>
<Checkbox className={styles.icon} checked={remember} />
<div>{t.t('com.affine.open-in-app.card.remember')}</div>
</div>
</div>
<div className={styles.pane}>
<div className={styles.clickableRow} onClick={handleDownload}>
<DownloadIcon className={styles.icon} />
<div>{t.t('com.affine.open-in-app.card.download')}</div>
</div>
</div>
</div> </div>
); );
}; };

View File

@@ -1029,10 +1029,11 @@
"com.affine.setting.appearance.open-in-app.open-in-desktop-app": "Open links in desktop app", "com.affine.setting.appearance.open-in-app.open-in-desktop-app": "Open links in desktop app",
"com.affine.setting.appearance.open-in-app.open-in-web": "Open links in browser", "com.affine.setting.appearance.open-in-app.open-in-web": "Open links in browser",
"com.affine.setting.appearance.open-in-app.title": "Open AFFiNE links", "com.affine.setting.appearance.open-in-app.title": "Open AFFiNE links",
"com.affine.open-in-app.card.title": "Open this page in app?", "com.affine.open-in-app.card.title": "Open this page in AFFiNE app",
"com.affine.open-in-app.card.subtitle": "No desktop app? <1>Click to download</1>.",
"com.affine.open-in-app.card.button.open": "Open in app", "com.affine.open-in-app.card.button.open": "Open in app",
"com.affine.open-in-app.card.button.dismiss": "Dismiss", "com.affine.open-in-app.card.button.dismiss": "Dismiss",
"com.affine.open-in-app.card.remember": "Remember my choice", "com.affine.open-in-app.card.remember": "Remember choice",
"com.affine.open-in-app.card.download": "Download desktop app", "com.affine.open-in-app.card.download": "Download desktop app",
"com.affine.settings.auto-check-description": "If enabled, it will automatically check for new versions at regular intervals.", "com.affine.settings.auto-check-description": "If enabled, it will automatically check for new versions at regular intervals.",
"com.affine.settings.auto-download-description": "If enabled, new versions will be automatically downloaded to the current device.", "com.affine.settings.auto-download-description": "If enabled, new versions will be automatically downloaded to the current device.",