diff --git a/packages/frontend/core/src/components/affine/onboarding/animate-in-tooltip.css.tsx b/packages/frontend/core/src/components/affine/onboarding/animate-in-tooltip.css.tsx index 7ec4e0306b..0109f52805 100644 --- a/packages/frontend/core/src/components/affine/onboarding/animate-in-tooltip.css.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/animate-in-tooltip.css.tsx @@ -14,11 +14,16 @@ export const tooltip = style({ fontSize: '20px', lineHeight: '28px', fontWeight: 600, - textShadow: '0px 0px 4px rgba(66, 65, 73, 0.14)', - color: 'white', opacity: 0, animation: `${fadeIn} 1s ease forwards`, animationDelay: onboardingVars.animateIn.tooltipShowUpDelay, + color: '#121212', + selectors: { + '[data-is-desktop="true"] &': { + color: 'white', + textShadow: '0px 0px 4px rgba(66, 65, 73, 0.14)', + }, + }, }); export const next = style({ diff --git a/packages/frontend/core/src/components/affine/onboarding/articles/article-0.tsx b/packages/frontend/core/src/components/affine/onboarding/articles/article-0.tsx index 78cf736549..19157829cd 100644 --- a/packages/frontend/core/src/components/affine/onboarding/articles/article-0.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/articles/article-0.tsx @@ -3,6 +3,7 @@ import type { OnboardingBlockOption } from '../types'; import bookmark1png from './assets/article-0-bookmark-1.png'; import bookmark2png from './assets/article-0-bookmark-2.png'; import embed1png from './assets/article-0-embed-1.png'; +import { BlogLink } from './blog-link'; export const article0: Array = [ { @@ -245,6 +246,7 @@ export const article0: Array = [ work. Obviously if you attend one of these, you should stop. But what else can you do?

+ ), offset: { x: 1200, y: -1600 }, diff --git a/packages/frontend/core/src/components/affine/onboarding/articles/article-1.tsx b/packages/frontend/core/src/components/affine/onboarding/articles/article-1.tsx index 009cfd649f..8eadeb34e4 100644 --- a/packages/frontend/core/src/components/affine/onboarding/articles/article-1.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/articles/article-1.tsx @@ -7,6 +7,7 @@ import bookmark1png from './assets/article-1-bookmark-1.png'; import illustration1png from './assets/article-1-illustration-1.png'; import Article1Illustration2 from './assets/article-1-illustration-2'; import { hr, link, quote } from './blocks.css'; +import { BlogLink } from './blog-link'; export const article1: Array = [ { @@ -256,6 +257,7 @@ export const article1: Array = [ intricate algorithm, designing a user interface, or figuring out how to lead a team towards some goal are also creative efforts.)

+ ), offset: { x: 900, y: -950 }, diff --git a/packages/frontend/core/src/components/affine/onboarding/articles/article-2.tsx b/packages/frontend/core/src/components/affine/onboarding/articles/article-2.tsx index 8e5780fbc7..9c84a1af01 100644 --- a/packages/frontend/core/src/components/affine/onboarding/articles/article-2.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/articles/article-2.tsx @@ -4,6 +4,7 @@ import illustration1png from './assets/article-2-illustration-1.jpg'; import illustration2png from './assets/article-2-illustration-2.jpg'; import note1png from './assets/article-2-note-1.png'; import note2png from './assets/article-2-note-2.png'; +import { BlogLink } from './blog-link'; export const article2: Array = [ { @@ -140,6 +141,7 @@ export const article2: Array = [ media can also be an echo chamber that can push us to unwittingly become more extreme in our beliefs.

+ ), offset: { x: 150, y: -680 }, diff --git a/packages/frontend/core/src/components/affine/onboarding/articles/article-3.tsx b/packages/frontend/core/src/components/affine/onboarding/articles/article-3.tsx index 5158a83d41..967e1a2a4f 100644 --- a/packages/frontend/core/src/components/affine/onboarding/articles/article-3.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/articles/article-3.tsx @@ -5,6 +5,7 @@ import illustration2jpg from './assets/article-3-illustration-2.jpg'; import illustration3jpg from './assets/article-3-illustration-3.jpg'; import illustration4jpg from './assets/article-3-illustration-4.jpg'; import illustration5jpg from './assets/article-3-illustration-5.jpg'; +import { BlogLink } from './blog-link'; export const article3: Array = [ { @@ -191,6 +192,7 @@ export const article3: Array = [ game world in creative and flexible ways, leading to fresh and unexpected discoveries.

+ ), offset: { x: 450, y: -1400 }, diff --git a/packages/frontend/core/src/components/affine/onboarding/articles/article-4.tsx b/packages/frontend/core/src/components/affine/onboarding/articles/article-4.tsx index 657137a0e5..3c002faf48 100644 --- a/packages/frontend/core/src/components/affine/onboarding/articles/article-4.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/articles/article-4.tsx @@ -4,6 +4,7 @@ import bookmark1png from './assets/article-4-bookmark-1.png'; import bookmark2png from './assets/article-4-bookmark-2.png'; import illustration1jpg from './assets/article-4-illustration-1.jpg'; import illustration2jpg from './assets/article-4-illustration-2.jpg'; +import { BlogLink } from './blog-link'; export const article4: Array = [ { @@ -180,6 +181,7 @@ export const article4: Array = [ degree as in the previous one. Psychology is not applied biology, nor is biology applied chemistry.

+ ), diff --git a/packages/frontend/core/src/components/affine/onboarding/articles/blog-link.tsx b/packages/frontend/core/src/components/affine/onboarding/articles/blog-link.tsx new file mode 100644 index 0000000000..9c27aa1178 --- /dev/null +++ b/packages/frontend/core/src/components/affine/onboarding/articles/blog-link.tsx @@ -0,0 +1,9 @@ +import { link } from './blocks.css'; + +export const BlogLink = () => { + return ( + + Check other articles + + ); +}; diff --git a/packages/frontend/core/src/components/affine/onboarding/articles/index.tsx b/packages/frontend/core/src/components/affine/onboarding/articles/index.tsx index f1e9ae5e43..d10e28e559 100644 --- a/packages/frontend/core/src/components/affine/onboarding/articles/index.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/articles/index.tsx @@ -36,7 +36,7 @@ const paperLocations = { /** paper enter animation config */ const paperEnterAnimationOriginal = { '0': { - curveCenter: 4, + curveCenter: 3, curve: 292, delay: 800, fromZ: 1230, @@ -54,7 +54,7 @@ const paperEnterAnimationOriginal = { }, '1': { curveCenter: 4, - curve: 280, + curve: 390, delay: 0, fromZ: 3697, fromX: 25, @@ -71,9 +71,9 @@ const paperEnterAnimationOriginal = { }, '2': { curveCenter: 3, - curve: 660, + curve: 1240, delay: 1700, - fromZ: 57379, + fromZ: 27379, fromX: 2, fromY: -77, fromRotateX: 0, @@ -87,8 +87,8 @@ const paperEnterAnimationOriginal = { easing: 'ease', }, '3': { - curveCenter: 4, - curve: 260, + curveCenter: 1, + curve: 300, delay: 1500, fromZ: 4303, fromX: -37, @@ -104,8 +104,8 @@ const paperEnterAnimationOriginal = { easing: 'ease', }, '4': { - curveCenter: 3, - curve: 270, + curveCenter: 4, + curve: 470, delay: 1571, fromZ: 1876, fromX: 65, diff --git a/packages/frontend/core/src/components/affine/onboarding/assets/logo.tsx b/packages/frontend/core/src/components/affine/onboarding/assets/logo.tsx new file mode 100644 index 0000000000..3d3c2f277c --- /dev/null +++ b/packages/frontend/core/src/components/affine/onboarding/assets/logo.tsx @@ -0,0 +1,101 @@ +import { memo } from 'react'; + +export default memo(function Logo() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}); diff --git a/packages/frontend/core/src/components/affine/onboarding/onboarding.tsx b/packages/frontend/core/src/components/affine/onboarding/onboarding.tsx index 79a079bdb7..1c48e0af86 100644 --- a/packages/frontend/core/src/components/affine/onboarding/onboarding.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/onboarding.tsx @@ -35,7 +35,11 @@ export const Onboarding = ({ onOpenApp }: OnboardingProps) => { }, []); return ( -
+
{(Object.entries(articles) as Array<[ArticleId, ArticleOption]>).map( ([id, article]) => { diff --git a/packages/frontend/core/src/components/affine/onboarding/paper-steps.tsx b/packages/frontend/core/src/components/affine/onboarding/paper-steps.tsx index 68287b5b24..bf6d400687 100644 --- a/packages/frontend/core/src/components/affine/onboarding/paper-steps.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/paper-steps.tsx @@ -55,7 +55,6 @@ export const PaperSteps = ({ useEffect(() => { if (stage === 'unfold' && status.unfoldingId === article.id) { - console.log('unfold', article.id); setFold(false); } }, [article.id, stage, status.unfoldingId]); diff --git a/packages/frontend/core/src/components/affine/onboarding/steps/animate-in.tsx b/packages/frontend/core/src/components/affine/onboarding/steps/animate-in.tsx index ec4068a35f..bec41cecdc 100644 --- a/packages/frontend/core/src/components/affine/onboarding/steps/animate-in.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/steps/animate-in.tsx @@ -12,8 +12,8 @@ interface AnimateInProps { onFinished?: () => void; } -const easing = 'spring(5, 100, 10, 0)'; -const segments = 4; +const easing = 'spring(3.2, 100, 10, 0)'; +const segments = 6; const animeSync = (params: Parameters[0]) => { return new Promise(resolve => { diff --git a/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.css.ts b/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.css.ts index 98dee41b8c..477eb61904 100644 --- a/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.css.ts +++ b/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.css.ts @@ -1,4 +1,4 @@ -import { globalStyle, style } from '@vanilla-extract/css'; +import { globalStyle, keyframes, style } from '@vanilla-extract/css'; import { onboardingVars } from '../style.css'; @@ -7,9 +7,9 @@ export const edgelessSwitchWindow = style({ borderRadius: onboardingVars.paper.r, backgroundColor: onboardingVars.paper.bg, position: 'relative', - transition: `width ${onboardingVars.window.transition.size}, height ${onboardingVars.window.transition.size}`, + transition: `width ${onboardingVars.window.transition.size}, height ${onboardingVars.window.transition.size}, border-radius ${onboardingVars.window.transition.size}`, overflow: 'hidden', - boxShadow: 'var(--affine-shadow-2)', + boxShadow: onboardingVars.web.windowShadow, fontFamily: 'var(--affine-font-family)', color: onboardingVars.paper.textColor, @@ -18,11 +18,43 @@ export const edgelessSwitchWindow = style({ '&[data-mode="edgeless"]': { width: onboardingVars.edgeless.w, height: onboardingVars.edgeless.h, + borderRadius: onboardingVars.edgeless.r, }, '&[data-mode="page"]': { width: onboardingVars.article.w, height: onboardingVars.article.h, + borderRadius: onboardingVars.article.r, }, + '&[data-mode="well-done"]': { + width: onboardingVars.wellDone.w, + height: onboardingVars.wellDone.h, + borderRadius: onboardingVars.wellDone.r, + }, + }, +}); + +export const orbit = style({ + width: '200%', + height: '100%', + display: 'flex', + transition: 'transform 0.4s ease', + willChange: 'transform', + selectors: { + '[data-mode="well-done"] &': { + transform: 'translateX(-50%)', + }, + }, +}); +export const orbitItem = style({ + width: '50%', + height: '100%', + flexShrink: 0, + flexGrow: 0, + overflow: 'hidden', +}); + +export const doc = style({ + selectors: { // grid background '&::before': { content: '""', @@ -39,12 +71,56 @@ export const edgelessSwitchWindow = style({ pointerEvents: 'none', transition: 'opacity 0.3s ease', }, - '&[data-mode="edgeless"]::before': { + '[data-mode="edgeless"] &::before': { opacity: 1, }, }, }); +export const wellDone = style({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + gap: 8, + textAlign: 'center', + userSelect: 'none', +}); + +const wellDoneSlideIn = keyframes({ + from: { + transform: 'translateX(100px)', + opacity: 0, + }, + to: { + transform: 'translateX(0)', + opacity: 1, + }, +}); +export const wellDoneEnterAnim = style({ + opacity: 0, + selectors: { + '[data-mode="well-done"] &': { + animation: `${wellDoneSlideIn} 0.25s cubic-bezier(0.25, 0.1, 0.25, 1) forwards`, + }, + '&:nth-child(1)': { animationDelay: '0.1s' }, + '&:nth-child(2)': { animationDelay: '0.15s' }, + '&:nth-child(3)': { animationDelay: '0.2s' }, + '&:nth-child(4)': { animationDelay: '0.25s' }, + }, +}); + +export const wellDoneTitle = style({ + fontSize: 28, + lineHeight: '36px', + fontWeight: '600', +}); +export const wellDoneContent = style({ + fontSize: 15, + lineHeight: '24px', + fontWeight: '400', +}); + export const toolbar = style({ position: 'absolute', bottom: '20px', @@ -77,11 +153,11 @@ export const canvas = style({ '[data-mode="edgeless"] &': { cursor: 'grab', }, - '.grabbing[data-mode="edgeless"] &': { + '[data-mode="edgeless"] .grabbing &': { cursor: 'grabbing', transition: 'none', }, - '.scaling[data-mode="edgeless"] &': { + '[data-mode="edgeless"] .scaling &': { transition: 'none', }, }, diff --git a/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.tsx b/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.tsx index 72d6531990..4b3e3597a3 100644 --- a/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/steps/edgeless-switch.tsx @@ -1,4 +1,5 @@ import { Button } from '@affine/component'; +import clsx from 'clsx'; import { debounce } from 'lodash-es'; import { type CSSProperties, @@ -8,6 +9,7 @@ import { useState, } from 'react'; +import Logo from '../assets/logo'; import { OnboardingBlock } from '../switch-widgets/block'; import { EdgelessSwitchButtons } from '../switch-widgets/switch'; import { ToolbarSVG } from '../switch-widgets/toolbar'; @@ -39,7 +41,8 @@ export const EdgelessSwitch = ({ onBack, onNext, }: EdgelessSwitchProps) => { - const windowRef = useRef(null); + // const windowRef = useRef(null); + const docRef = useRef(null); const canvasRef = useRef(null); const mouseDownRef = useRef(false); const prevStateRef = useRef( @@ -59,12 +62,12 @@ export const EdgelessSwitch = ({ const onSwitchToPageMode = useCallback(() => setMode('page'), []); const onSwitchToEdgelessMode = useCallback(() => setMode('edgeless'), []); const toggleGrabbing = useCallback((v: boolean) => { - if (!windowRef.current) return; - windowRef.current.classList.toggle('grabbing', v); + if (!docRef.current) return; + docRef.current.classList.toggle('grabbing', v); }, []); const turnOnScaling = useCallback(() => { - if (!windowRef.current) return; - windowRef.current.classList.add('scaling'); + if (!docRef.current) return; + docRef.current.classList.add('scaling'); }, []); const enableScrollWithDelay = useCallback(() => { @@ -86,20 +89,21 @@ export const EdgelessSwitch = ({ }, []); const onNextClick = useCallback(() => { if (mode === 'page') setMode('edgeless'); + else if (mode === 'edgeless') setMode('well-done'); else onNext?.(); }, [mode, onNext]); useEffect(() => { turnOffScalingRef.current = debounce(() => { - if (!windowRef.current) return; - windowRef.current.classList.remove('scaling'); + if (!docRef.current) return; + docRef.current.classList.remove('scaling'); }, 100); }, []); useEffect(() => { if (mode === 'page') return; const canvas = canvasRef.current; - const win = windowRef.current; + const win = docRef.current; if (!win || !canvas) return; const onWheel = (e: WheelEvent) => { @@ -197,40 +201,71 @@ export const EdgelessSwitch = ({ return (
-
-
- { - /* render blocks */ - article.blocks.map((block, key) => { - return ; - }) - } +
+
+
+
+ { + /* render blocks */ + article.blocks.map((block, key) => { + return ; + }) + } +
+
+ +
+
+ + + +
+ +
+ +
+
-
-
-
- - - -
- -
-
diff --git a/packages/frontend/core/src/components/affine/onboarding/steps/unfolding.css.ts b/packages/frontend/core/src/components/affine/onboarding/steps/unfolding.css.ts index aefeb25f08..cb3ab184f0 100644 --- a/packages/frontend/core/src/components/affine/onboarding/steps/unfolding.css.ts +++ b/packages/frontend/core/src/components/affine/onboarding/steps/unfolding.css.ts @@ -20,11 +20,16 @@ const fadeOut = keyframes({ export const unfoldingWrapper = style([ paperLocation, { + vars: { + '--hover-offset-y': '0px', + '--hover-scale': '1', + }, display: 'flex', alignItems: 'center', justifyContent: 'center', - transform: 'rotate(var(--toRotateZ))', + transform: + 'rotate(var(--toRotateZ)) translateY(var(--hover-offset-y)) scale(var(--hover-scale))', cursor: 'pointer', backgroundColor: onboardingVars.paper.bg, @@ -38,6 +43,13 @@ export const unfoldingWrapper = style([ transition: `all 0.23s ease, width ${unfolding.sizeTransition}, height ${unfolding.sizeTransition}, transform ${unfolding.transformTransition}`, + ':hover': { + vars: { + '--hover-offset-y': '-10px', + '--hover-scale': '1.03', + }, + }, + '::before': { // hack border content: '""', @@ -53,6 +65,9 @@ export const unfoldingWrapper = style([ '&[data-fold="false"]': { vars: { '--toRotateZ': '0deg', + // reset hover to avoid flickering + '--hover-offset-y': '0px', + '--hover-scale': '1', }, width: onboardingVars.article.w, height: onboardingVars.article.h, diff --git a/packages/frontend/core/src/components/affine/onboarding/style.css.ts b/packages/frontend/core/src/components/affine/onboarding/style.css.ts index f6ae03ae60..67c8dfbb17 100644 --- a/packages/frontend/core/src/components/affine/onboarding/style.css.ts +++ b/packages/frontend/core/src/components/affine/onboarding/style.css.ts @@ -1,4 +1,4 @@ -import { globalStyle, style } from '@vanilla-extract/css'; +import { globalStyle, keyframes, style } from '@vanilla-extract/css'; // in case that we need to support dark mode later export const onboardingVars = { @@ -23,16 +23,25 @@ export const onboardingVars = { transformTransition: '0.3s ease', }, web: { - bg: '#fafafa', + bg: '#F4F4F5', + windowShadow: + '1px 18px 39px 0px rgba(0, 0, 0, 0.15), 5px 71px 71px 0px rgba(0, 0, 0, 0.09), 12px 160px 96px 0px rgba(0, 0, 0, 0.05), 20px 284px 114px 0px rgba(0, 0, 0, 0.01), 32px 443px 124px 0px rgba(0, 0, 0, 0.00)', }, article: { w: '1200px', h: '800px', + r: '8px', }, edgeless: { w: '1200px', h: '800px', + r: '8px', + }, + wellDone: { + w: '800px', + h: '600px', + r: '12px', }, canvas: { @@ -62,6 +71,11 @@ export const perspective = style({ transformStyle: 'preserve-3d', }); +export const fadeIn = keyframes({ + from: { opacity: 0 }, + to: { opacity: 1 }, +}); + export const onboarding = style([ perspective, { @@ -80,9 +94,17 @@ export const onboarding = style([ inset: 0, background: onboardingVars.web.bg, transform: 'translateZ(-1000px) scale(2)', + transition: 'opacity 0.3s ease', }, '&[data-is-desktop="true"]::after': { - content: 'unset', + animation: `${fadeIn} 0.8s linear`, + // content: 'unset', + background: + // 'linear-gradient(180deg, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 99.58%)', + 'linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0) 80%)', + }, + '&[data-is-window="true"][data-is-desktop="true"]::after': { + opacity: 0, }, }, }, diff --git a/packages/frontend/core/src/components/affine/onboarding/switch-widgets/block.tsx b/packages/frontend/core/src/components/affine/onboarding/switch-widgets/block.tsx index 93c1aa234d..d564a6df8b 100644 --- a/packages/frontend/core/src/components/affine/onboarding/switch-widgets/block.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/switch-widgets/block.tsx @@ -47,7 +47,7 @@ export const OnboardingBlock = ({ const blockStyles = { ...baseStyles, ...style, - ...customStyle?.[mode], + ...customStyle?.[mode === 'page' ? 'page' : 'edgeless'], } as CSSProperties; return ( @@ -58,7 +58,7 @@ export const OnboardingBlock = ({ }} className={onboardingBlock} data-mode={mode} - data-bg-mode={bg && mode === 'edgeless'} + data-bg-mode={bg && mode !== 'page'} data-invisible={mode === 'page' && edgelessOnly} > {children} diff --git a/packages/frontend/core/src/components/affine/onboarding/switch-widgets/style.css.tsx b/packages/frontend/core/src/components/affine/onboarding/switch-widgets/style.css.tsx index d01bccc2ae..7337e95ab0 100644 --- a/packages/frontend/core/src/components/affine/onboarding/switch-widgets/style.css.tsx +++ b/packages/frontend/core/src/components/affine/onboarding/switch-widgets/style.css.tsx @@ -109,7 +109,7 @@ export const onboardingBlock = style([ '&:last-child': { marginBottom: 0, }, - '&[data-mode="edgeless"]': { + '&[data-mode="edgeless"], &[data-mode="well-done"]': { transition: `all ${onboardingVars.block.transition} var(--enter-delay)`, }, '&[data-mode="page"]': { diff --git a/packages/frontend/core/src/components/affine/onboarding/types.ts b/packages/frontend/core/src/components/affine/onboarding/types.ts index eb749c858c..bff4f53169 100644 --- a/packages/frontend/core/src/components/affine/onboarding/types.ts +++ b/packages/frontend/core/src/components/affine/onboarding/types.ts @@ -3,7 +3,7 @@ import type { PropsWithChildren, ReactNode } from 'react'; export type OnboardingStep = 'enter' | 'unfold' | 'edgeless-switch'; export type ArticleId = '0' | '1' | '2' | '3' | '4'; -export type EdgelessSwitchMode = 'edgeless' | 'page'; +export type EdgelessSwitchMode = 'edgeless' | 'page' | 'well-done'; /** * Paper enter animation options @@ -77,10 +77,7 @@ export interface OnboardingBlockOption extends PropsWithChildren { style?: CSSProperties; /** customize style for different mode */ - customStyle?: { - page?: CSSProperties; - edgeless?: CSSProperties; - }; + customStyle?: Partial>; /** attach a sub block to current block */ sub?: OnboardingBlockOption;