feat(core): ai onboarding for edgeless mode (#6556)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const thumb = style({
|
||||
borderRadius: 'inherit',
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
width: '100%',
|
||||
height: 211,
|
||||
background: cssVar('backgroundOverlayPanelColor'),
|
||||
overflow: 'hidden',
|
||||
});
|
||||
@@ -1,9 +1,73 @@
|
||||
import { notify } from '@affine/component';
|
||||
import { CurrentWorkspaceService } from '@affine/core/modules/workspace';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { AiIcon } from '@blocksuite/icons';
|
||||
import { Doc, LiveData, useLiveData, useService } from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import Lottie from 'lottie-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import * as styles from './edgeless.dialog.css';
|
||||
import mouseDark from './lottie/edgeless/mouse-dark.json';
|
||||
import mouseLight from './lottie/edgeless/mouse-light.json';
|
||||
import trackPadDark from './lottie/edgeless/trackpad-dark.json';
|
||||
import trackPadLight from './lottie/edgeless/trackpad-light.json';
|
||||
import type { BaseAIOnboardingDialogProps } from './type';
|
||||
|
||||
export const AIOnboardingEdgeless = ({
|
||||
onDismiss: _,
|
||||
}: BaseAIOnboardingDialogProps) => {
|
||||
return (
|
||||
<div>{/* TODO: open edgeless in cloud workspace for the first time */}</div>
|
||||
);
|
||||
const EdgelessOnboardingAnimation = () => {
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const isTrackPad = false;
|
||||
|
||||
const data = useMemo(() => {
|
||||
if (isTrackPad) {
|
||||
return resolvedTheme === 'dark' ? trackPadDark : trackPadLight;
|
||||
}
|
||||
return resolvedTheme === 'dark' ? mouseDark : mouseLight;
|
||||
}, [isTrackPad, resolvedTheme]);
|
||||
|
||||
return <Lottie loop autoplay animationData={data} className={styles.thumb} />;
|
||||
};
|
||||
|
||||
// avoid notifying multiple times
|
||||
const notifyId$ = new LiveData<string | number | null>(null);
|
||||
|
||||
export const AIOnboardingEdgeless = ({
|
||||
onDismiss,
|
||||
}: BaseAIOnboardingDialogProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const notifyId = useLiveData(notifyId$);
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
const currentWorkspace = useLiveData(
|
||||
useService(CurrentWorkspaceService).currentWorkspace$
|
||||
);
|
||||
const isCloud = currentWorkspace?.flavour === WorkspaceFlavour.AFFINE_CLOUD;
|
||||
|
||||
const doc = useService(Doc);
|
||||
const mode = useLiveData(doc.mode$);
|
||||
|
||||
useEffect(() => {
|
||||
if (notifyId) return;
|
||||
if (isCloud && mode === 'edgeless') {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
const id = notify(
|
||||
{
|
||||
title: t['com.affine.ai-onboarding.edgeless.title'](),
|
||||
message: t['com.affine.ai-onboarding.edgeless.message'](),
|
||||
icon: <AiIcon color={cssVar('processingColor')} />,
|
||||
thumb: <EdgelessOnboardingAnimation />,
|
||||
alignMessage: 'icon',
|
||||
onDismiss,
|
||||
},
|
||||
{ duration: 1000 * 60 * 10 }
|
||||
);
|
||||
notifyId$.next(id);
|
||||
}, 1000);
|
||||
}
|
||||
}, [isCloud, mode, notifyId, onDismiss, t]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -16,13 +16,10 @@ const useDismiss = (key: AIOnboardingType) => {
|
||||
return [dismiss, onDismiss] as const;
|
||||
};
|
||||
|
||||
export const AIOnboarding = () => {
|
||||
export const WorkspaceAIOnboarding = () => {
|
||||
const [dismissGeneral, onDismissGeneral] = useDismiss(
|
||||
AIOnboardingType.GENERAL
|
||||
);
|
||||
const [dismissEdgeless, onDismissEdgeless] = useDismiss(
|
||||
AIOnboardingType.EDGELESS
|
||||
);
|
||||
const [dismissLocal, onDismissLocal] = useDismiss(AIOnboardingType.LOCAL);
|
||||
|
||||
return (
|
||||
@@ -30,10 +27,22 @@ export const AIOnboarding = () => {
|
||||
{dismissGeneral ? null : (
|
||||
<AIOnboardingGeneral onDismiss={onDismissGeneral} />
|
||||
)}
|
||||
{dismissEdgeless ? null : (
|
||||
<AIOnboardingEdgeless onDismiss={onDismissEdgeless} />
|
||||
)}
|
||||
|
||||
{dismissLocal ? null : <AIOnboardingLocal onDismiss={onDismissLocal} />}
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
export const PageAIOnboarding = () => {
|
||||
const [dismissEdgeless, onDismissEdgeless] = useDismiss(
|
||||
AIOnboardingType.EDGELESS
|
||||
);
|
||||
|
||||
return (
|
||||
<Suspense>
|
||||
{dismissEdgeless ? null : (
|
||||
<AIOnboardingEdgeless onDismiss={onDismissEdgeless} />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user