mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 20:46:38 +08:00
refactor: image preview component issues in center peek (#7313)
fix AF-948 - remove jotai - every editor got its own image block modal - image block uses center peek modal for animation and style
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const editor = style({
|
||||
@@ -7,3 +8,12 @@ export const editor = style({
|
||||
},
|
||||
minHeight: '100%',
|
||||
});
|
||||
|
||||
export const affineDocViewport = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
userSelect: 'none',
|
||||
containerName: 'viewport',
|
||||
containerType: 'inline-size',
|
||||
background: cssVar('backgroundPrimaryColor'),
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PageDetailSkeleton } from '@affine/component/page-detail-skeleton';
|
||||
import { AIProvider } from '@affine/core/blocksuite/presets/ai';
|
||||
import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error-boundary';
|
||||
import { BlockSuiteEditor } from '@affine/core/components/blocksuite/block-suite-editor';
|
||||
import { ImagePreviewModal } from '@affine/core/components/image-preview';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import { PageNotFound } from '@affine/core/pages/404';
|
||||
import { Bound, type EdgelessRootService } from '@blocksuite/blocks';
|
||||
@@ -10,6 +11,7 @@ import { DisposableGroup } from '@blocksuite/global/utils';
|
||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||
import type { DocMode } from '@toeverything/infra';
|
||||
import { DocsService, FrameworkScope, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { WorkbenchService } from '../../workbench';
|
||||
@@ -145,7 +147,9 @@ export function DocPeekPreview({
|
||||
return (
|
||||
<AffineErrorBoundary>
|
||||
<Scrollable.Root>
|
||||
<Scrollable.Viewport className="affine-page-viewport">
|
||||
<Scrollable.Viewport
|
||||
className={clsx('affine-page-viewport', styles.affineDocViewport)}
|
||||
>
|
||||
<FrameworkScope scope={doc.scope}>
|
||||
<BlockSuiteEditor
|
||||
ref={onRef}
|
||||
@@ -154,6 +158,13 @@ export function DocPeekPreview({
|
||||
defaultSelectedBlockId={blockId}
|
||||
page={doc.blockSuiteDoc}
|
||||
/>
|
||||
{editor?.host ? (
|
||||
<ImagePreviewModal
|
||||
pageId={doc.id}
|
||||
docCollection={doc.blockSuiteDoc.collection}
|
||||
host={editor.host}
|
||||
/>
|
||||
) : null}
|
||||
</FrameworkScope>
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar />
|
||||
|
||||
@@ -3,8 +3,9 @@ import { createVar, keyframes, style } from '@vanilla-extract/css';
|
||||
|
||||
export const animationTimeout = createVar();
|
||||
export const transformOrigin = createVar();
|
||||
export const animationType = createVar();
|
||||
|
||||
const contentShow = keyframes({
|
||||
const zoomIn = keyframes({
|
||||
from: {
|
||||
transform: 'scale(0.10)',
|
||||
},
|
||||
@@ -12,7 +13,7 @@ const contentShow = keyframes({
|
||||
transform: 'scale(1)',
|
||||
},
|
||||
});
|
||||
const contentHide = keyframes({
|
||||
const zoomOut = keyframes({
|
||||
to: {
|
||||
opacity: 0,
|
||||
transform: 'scale(0.10)',
|
||||
@@ -93,32 +94,57 @@ export const modalContentWrapper = style({
|
||||
export const modalContentContainer = style({
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
width: '90%',
|
||||
height: '90%',
|
||||
maxWidth: 1248,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
willChange: 'transform, opacity',
|
||||
transformOrigin: transformOrigin,
|
||||
selectors: {
|
||||
'&[data-state=entered], &[data-state=entering]': {
|
||||
animationFillMode: 'forwards',
|
||||
animationName: contentShow,
|
||||
animationDuration: animationTimeout,
|
||||
animationTimingFunction: 'cubic-bezier(0.42, 0, 0.58, 1)',
|
||||
},
|
||||
'&[data-state=exited], &[data-state=exiting]': {
|
||||
animationFillMode: 'forwards',
|
||||
animationName: contentHide,
|
||||
animationDuration: animationTimeout,
|
||||
animationTimingFunction: 'cubic-bezier(0.42, 0, 0.58, 1)',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const modalContentContainerWithZoom = style({
|
||||
selectors: {
|
||||
'&[data-state=entered], &[data-state=entering]': {
|
||||
animationName: zoomIn,
|
||||
},
|
||||
'&[data-state=exited], &[data-state=exiting]': {
|
||||
animationName: zoomOut,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const modalContentContainerWithFade = style({
|
||||
selectors: {
|
||||
'&[data-state=entered], &[data-state=entering]': {
|
||||
animationName: fadeIn,
|
||||
},
|
||||
'&[data-state=exited], &[data-state=exiting]': {
|
||||
animationName: fadeOut,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const containerPadding = style({
|
||||
width: '90%',
|
||||
height: '90%',
|
||||
maxWidth: 1248,
|
||||
});
|
||||
|
||||
export const modalContent = style({
|
||||
flex: 1,
|
||||
height: '100%',
|
||||
backgroundColor: cssVar('backgroundOverlayPanelColor'),
|
||||
boxShadow: '0px 0px 0px 2.23px rgba(0, 0, 0, 0.08)',
|
||||
backdropFilter: 'drop-shadow(0px 0px 2px rgba(0, 0, 0, 0.08))',
|
||||
borderRadius: '8px',
|
||||
minHeight: 300,
|
||||
// :focus-visible will set outline
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import {
|
||||
createContext,
|
||||
type PropsWithChildren,
|
||||
@@ -24,7 +24,7 @@ const contentOptions: Dialog.DialogContentProps = {
|
||||
},
|
||||
style: {
|
||||
padding: 0,
|
||||
backgroundColor: cssVar('backgroundPrimaryColor'),
|
||||
backgroundColor: 'transparent',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
};
|
||||
@@ -64,14 +64,22 @@ export const PeekViewModalContainer = ({
|
||||
controls,
|
||||
children,
|
||||
hideOnEntering,
|
||||
onAnimationStart,
|
||||
onAnimateEnd,
|
||||
animation = 'zoom',
|
||||
padding = true,
|
||||
testId,
|
||||
}: PropsWithChildren<{
|
||||
open: boolean;
|
||||
hideOnEntering?: boolean;
|
||||
target?: HTMLElement;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
controls: React.ReactNode;
|
||||
controls?: React.ReactNode;
|
||||
onAnimationStart?: () => void;
|
||||
onAnimateEnd?: () => void;
|
||||
padding?: boolean;
|
||||
animation?: 'fade' | 'zoom';
|
||||
testId?: string;
|
||||
}>) => {
|
||||
const [{ status }, toggle] = useTransition({
|
||||
timeout: animationTimeout,
|
||||
@@ -100,11 +108,11 @@ export const PeekViewModalContainer = ({
|
||||
[styles.transformOrigin]: transformOrigin,
|
||||
[styles.animationTimeout]: `${animationTimeout}ms`,
|
||||
})}
|
||||
onAnimationEnd={() => {
|
||||
onAnimateEnd?.();
|
||||
}}
|
||||
onAnimationStart={onAnimationStart}
|
||||
onAnimationEnd={onAnimateEnd}
|
||||
/>
|
||||
<div
|
||||
data-testid={testId}
|
||||
data-peek-view-wrapper
|
||||
className={styles.modalContentWrapper}
|
||||
style={assignInlineVars({
|
||||
@@ -113,7 +121,13 @@ export const PeekViewModalContainer = ({
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={styles.modalContentContainer}
|
||||
className={clsx(
|
||||
styles.modalContentContainer,
|
||||
padding && styles.containerPadding,
|
||||
animation === 'fade'
|
||||
? styles.modalContentContainerWithFade
|
||||
: styles.modalContentContainerWithZoom
|
||||
)}
|
||||
data-testid="peek-view-modal-animation-container"
|
||||
data-state={status}
|
||||
>
|
||||
@@ -123,9 +137,11 @@ export const PeekViewModalContainer = ({
|
||||
>
|
||||
{hideOnEntering && status === 'entering' ? null : children}
|
||||
</Dialog.Content>
|
||||
<div data-state={status} className={styles.modalControls}>
|
||||
{controls}
|
||||
</div>
|
||||
{controls ? (
|
||||
<div data-state={status} className={styles.modalControls}>
|
||||
{controls}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Portal>
|
||||
|
||||
Reference in New Issue
Block a user