fix: open in app card style (#8667)
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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',
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ const SharePageWebContainer = ({
|
|||||||
{children}
|
{children}
|
||||||
<SharePageFooter />
|
<SharePageFooter />
|
||||||
</div>
|
</div>
|
||||||
<OpenInAppCard className={styles.shareCard} />
|
<OpenInAppCard />
|
||||||
</div>
|
</div>
|
||||||
</MainContainer>
|
</MainContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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.",
|
||||||
|
|||||||
Reference in New Issue
Block a user