refactor(component): adapt the questionnaire component to the desktop client (#5514)

close TOV-240

Windows desktop:
<img width="1145" alt="image" src="https://github.com/toeverything/AFFiNE/assets/102217452/6b12a6bd-c020-4d02-a366-e97e1afd1e10">

MacOS desktop:
<img width="1187" alt="image" src="https://github.com/toeverything/AFFiNE/assets/102217452/9a3c909c-b283-4ddc-a187-3db12b26a7f5">

Web:
<img width="1438" alt="image" src="https://github.com/toeverything/AFFiNE/assets/102217452/e8e04258-9275-470d-a3f8-5d18f5b29eb3">
This commit is contained in:
JimmFly
2024-01-19 10:07:18 +00:00
parent fa8655e43e
commit 353b27d796
3 changed files with 136 additions and 42 deletions
@@ -1,28 +1,65 @@
import { globalStyle, style } from '@vanilla-extract/css'; import { globalStyle, style } from '@vanilla-extract/css';
export const layout = style({
backgroundColor: 'var(--affine-background-primary-color)',
height: '100vh',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
selectors: {
'&[data-is-macos-electron="true"]': {
margin: '8px',
borderRadius: '8px',
height: 'calc(100vh - 16px)',
},
},
});
export const header = style({
paddingTop: '24px',
paddingRight: '24px',
position: 'sticky',
top: 0,
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
['WebkitAppRegion' as string]: 'drag',
selectors: {
'&[data-is-windows-electron="true"]': {
paddingTop: '0',
paddingRight: '0',
gap: '16px',
},
},
});
export const footer = style({
padding: '20px',
position: 'sticky',
bottom: 0,
backgroundColor: 'var(--affine-background-primary-color)',
});
export const scrollableContainer = style({ export const scrollableContainer = style({
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
height: '100vh', padding: '80px 200px 160px',
padding: '0 200px',
backgroundColor: 'var(--affine-background-primary-color)',
'@media': { '@media': {
'screen and (max-width: 1024px)': { 'screen and (max-width: 1024px)': {
padding: '80px 36px', padding: '0px 36px 80px',
alignItems: 'center',
}, },
}, },
}); });
export const onboardingContainer = style({ export const onboardingContainer = style({
maxWidth: '600px', maxWidth: '600px',
padding: '160px 0',
'@media': { '@media': {
'screen and (max-width: 1024px)': { 'screen and (max-width: 1024px)': {
padding: '40px 0', padding: '40px 0',
width: '100%', maxWidth: '100%',
}, },
}, },
}); });
@@ -49,7 +86,6 @@ export const optionsWrapper = style({
flexDirection: 'column', flexDirection: 'column',
alignItems: 'flex-start', alignItems: 'flex-start',
gap: '16px', gap: '16px',
// flexShrink: 0,
flexGrow: 1, flexGrow: 1,
}); });
@@ -95,10 +131,13 @@ export const openAFFiNEButton = style({
alignSelf: 'flex-start', alignSelf: 'flex-start',
}); });
export const rightCornerButton = style({ export const disableButton = style({
position: 'absolute', position: 'absolute',
top: '24px', display: 'none',
right: '24px', pointerEvents: 'none',
});
export const windowsAppButton = style({
marginRight: '24px',
}); });
export const thankContainer = style({ export const thankContainer = style({
@@ -122,9 +161,6 @@ export const thankText = style({
export const linkGroup = style({ export const linkGroup = style({
display: 'flex', display: 'flex',
position: 'absolute',
bottom: '24px',
right: '24px',
fontSize: 'var(--affine-font-xs)', fontSize: 'var(--affine-font-xs)',
height: '16px', height: '16px',
gap: '6px', gap: '6px',
@@ -1,7 +1,8 @@
import { apis } from '@affine/electron-api';
import { fetchWithTraceReport } from '@affine/graphql'; import { fetchWithTraceReport } from '@affine/graphql';
import { ArrowRightSmallIcon } from '@blocksuite/icons'; import { ArrowRightSmallIcon } from '@blocksuite/icons';
import clsx from 'clsx'; import clsx from 'clsx';
import { useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports // eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { type Location, useLocation, useNavigate } from 'react-router-dom'; import { type Location, useLocation, useNavigate } from 'react-router-dom';
import useSWR from 'swr'; import useSWR from 'swr';
@@ -50,43 +51,60 @@ function getCallbackUrl(location: Location) {
} }
export const ScrollableLayout = ({ export const ScrollableLayout = ({
headerItems,
children, children,
isMacosDesktop,
isWindowsDesktop,
}: { }: {
isMacosDesktop?: boolean;
isWindowsDesktop?: boolean;
headerItems?: React.ReactNode;
children: React.ReactNode; children: React.ReactNode;
}) => { }) => {
return ( return (
<ScrollableContainer className={styles.scrollableContainer}> <div className={styles.layout} data-is-macos-electron={isMacosDesktop}>
<div className={styles.onboardingContainer}>{children}</div> <header
className={styles.header}
<div className={styles.linkGroup}> data-is-windows-electron={isWindowsDesktop}
<a >
className={styles.link} {headerItems}
href="https://affine.pro/terms" </header>
target="_blank" <ScrollableContainer className={styles.scrollableContainer}>
rel="noreferrer" <div className={styles.onboardingContainer}>{children}</div>
> </ScrollableContainer>
Terms of Conditions <footer className={styles.footer}>
</a> <div className={styles.linkGroup}>
<Divider orientation="vertical" /> <a
<a className={styles.link}
className={styles.link} href="https://affine.pro/terms"
href="https://affine.pro/privacy" target="_blank"
target="_blank" rel="noreferrer"
rel="noreferrer" >
> Terms of Conditions
Privacy Policy </a>
</a> <Divider orientation="vertical" />
</div> <a
</ScrollableContainer> className={styles.link}
href="https://affine.pro/privacy"
target="_blank"
rel="noreferrer"
>
Privacy Policy
</a>
</div>
</footer>
</div>
); );
}; };
export const OnboardingPage = ({ export const OnboardingPage = ({
user, user,
onOpenAffine, onOpenAffine,
windowControl,
}: { }: {
user: User; user: User;
onOpenAffine: () => void; onOpenAffine: () => void;
windowControl?: React.ReactNode;
}) => { }) => {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -104,6 +122,17 @@ export const OnboardingPage = ({
() => questions?.[questionIdx], () => questions?.[questionIdx],
[questionIdx, questions] [questionIdx, questions]
); );
const isMacosDesktop = environment.isDesktop && environment.isMacOs;
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
useEffect(() => {
if (environment.isDesktop) {
// to hide macOS window control buttons
apis?.ui.handleSidebarVisibilityChange(false).catch(err => {
console.error(err);
});
}
}, []);
if (!questions) { if (!questions) {
return null; return null;
@@ -119,7 +148,25 @@ export const OnboardingPage = ({
if (question) { if (question) {
return ( return (
<ScrollableLayout> <ScrollableLayout
headerItems={
<>
{isWindowsDesktop ? windowControl : null}
<Button
className={clsx(styles.button, {
[styles.disableButton]: questionIdx === 0,
[styles.windowsAppButton]: isWindowsDesktop,
})}
size="extraLarge"
onClick={() => setQuestionIdx(questions.length)}
>
Skip
</Button>
</>
}
isMacosDesktop={isMacosDesktop}
isWindowsDesktop={isWindowsDesktop}
>
<div className={styles.content}> <div className={styles.content}>
<h1 className={styles.question}>{question.question}</h1> <h1 className={styles.question}>{question.question}</h1>
<div className={styles.optionsWrapper}> <div className={styles.optionsWrapper}>
@@ -168,7 +215,7 @@ export const OnboardingPage = ({
<div className={styles.buttonWrapper}> <div className={styles.buttonWrapper}>
<Button <Button
className={clsx(styles.button, { className={clsx(styles.button, {
[styles.rightCornerButton]: questionIdx !== 0, [styles.disableButton]: questionIdx !== 0,
})} })}
size="extraLarge" size="extraLarge"
onClick={() => setQuestionIdx(questions.length)} onClick={() => setQuestionIdx(questions.length)}
@@ -217,7 +264,11 @@ export const OnboardingPage = ({
); );
} }
return ( return (
<ScrollableLayout> <ScrollableLayout
headerItems={isWindowsDesktop ? windowControl : null}
isMacosDesktop={isMacosDesktop}
isWindowsDesktop={isWindowsDesktop}
>
<div className={styles.thankContainer}> <div className={styles.thankContainer}>
<h1 className={styles.thankTitle}>Thank you!</h1> <h1 className={styles.thankTitle}>Thank you!</h1>
<p className={styles.thankText}> <p className={styles.thankText}>
+8 -1
View File
@@ -27,6 +27,7 @@ import {
import { z } from 'zod'; import { z } from 'zod';
import { SubscriptionRedirect } from '../components/affine/auth/subscription-redirect'; import { SubscriptionRedirect } from '../components/affine/auth/subscription-redirect';
import { WindowsAppControls } from '../components/pure/header/windows-app-controls';
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status'; import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
import { useCurrentUser } from '../hooks/affine/use-current-user'; import { useCurrentUser } from '../hooks/affine/use-current-user';
import { useMutation } from '../hooks/use-mutation'; import { useMutation } from '../hooks/use-mutation';
@@ -97,7 +98,13 @@ export const AuthPage = (): ReactElement | null => {
switch (authType) { switch (authType) {
case 'onboarding': case 'onboarding':
return <OnboardingPage user={user} onOpenAffine={onOpenAffine} />; return (
<OnboardingPage
user={user}
onOpenAffine={onOpenAffine}
windowControl={<WindowsAppControls />}
/>
);
case 'signUp': { case 'signUp': {
return ( return (
<SignUpPage <SignUpPage