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 7ec4e0306..0109f5280 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 78cf73654..19157829c 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 009cfd649..8eadeb34e 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 8e5780fbc..9c84a1af0 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 5158a83d4..967e1a2a4 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 657137a0e..3c002faf4 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 000000000..9c27aa117 --- /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 f1e9ae5e4..d10e28e55 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 000000000..3d3c2f277 --- /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 79a079bdb..1c48e0af8 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 68287b5b2..bf6d40068 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 ec4068a35..bec41cecd 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 98dee41b8..477eb6190 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 72d653199..4b3e3597a 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 aefeb25f0..cb3ab184f 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 f6ae03ae6..67c8dfbb1 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 93c1aa234..d564a6df8 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 d01bccc2a..7337e95ab 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 eb749c858..bff4f5316 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;