diff --git a/libs/components/editor-blocks/src/components/source-view/SourceView.tsx b/libs/components/editor-blocks/src/components/source-view/SourceView.tsx index 3835199d3f..2c117e97fe 100644 --- a/libs/components/editor-blocks/src/components/source-view/SourceView.tsx +++ b/libs/components/editor-blocks/src/components/source-view/SourceView.tsx @@ -1,6 +1,11 @@ -import type { AsyncBlock } from '@toeverything/components/editor-core'; +import { + AsyncBlock, + useCurrentView, + useLazyIframe, +} from '@toeverything/components/editor-core'; import { styled } from '@toeverything/components/ui'; -import type { FC } from 'react'; +import { FC, useRef } from 'react'; +import { SCENE_CONFIG } from '../../blocks/group/config'; import { BlockPreview } from './BlockView'; import { formatUrl } from './format-url'; @@ -15,7 +20,18 @@ export interface Props { } const getHost = (url: string) => new URL(url).host; - +const MouseMaskContainer = styled('div')({ + position: 'absolute', + zIndex: 1, + top: '0px', + left: '0px', + right: '0px', + bottom: '0px', + backgroundColor: 'transparent', + '&:hover': { + pointerEvents: 'none', + }, +}); const LinkContainer = styled('div')<{ isSelected: boolean; }>(({ theme, isSelected }) => { @@ -38,12 +54,28 @@ const LinkContainer = styled('div')<{ }, }; }); - +const _getLinkStyle = (scene: string) => { + switch (scene) { + case SCENE_CONFIG.PAGE: + return { + width: '420px', + height: '198px', + }; + default: + return { + width: '252px', + height: '126px', + }; + } +}; const SourceViewContainer = styled('div')<{ isSelected: boolean; -}>(({ theme, isSelected }) => { + scene: string; +}>(({ theme, isSelected, scene }) => { return { + ..._getLinkStyle(scene), overflow: 'hidden', + position: 'relative', borderRadius: theme.affine.shape.borderRadius, background: isSelected ? 'rgba(152, 172, 189, 0.1)' : 'transparent', padding: '8px', @@ -52,32 +84,46 @@ const SourceViewContainer = styled('div')<{ height: '100%', border: '1px solid #EAEEF2', borderRadius: theme.affine.shape.borderRadius, + userSelect: 'none', }, }; }); - +const IframeContainer = styled('div')<{ show: boolean }>(({ show }) => { + return { + height: '100%', + display: show ? 'block' : 'none', + }; +}); export const SourceView: FC = props => { const { link, isSelected, block, editorElement } = props; const src = formatUrl(link); - const openTabOnBrowser = () => { - window.open(link, '_blank'); - }; + + const iframeContainer = useRef(null); + let iframeShow = useLazyIframe(src, 3000, iframeContainer); + const [currentView] = useCurrentView(); + const { type } = currentView; if (src?.startsWith('http')) { return ( - e.preventDefault()} - onClick={openTabOnBrowser} - > -

{getHost(src)}

-

{src}

-
+
+ + + { + e.preventDefault(); + e.stopPropagation(); + }} + show={iframeShow} + ref={iframeContainer} + > + +
); } else if (src?.startsWith('affine')) { return ( { ); return [currentView, setCurrentView] as const; }; +export const useLazyIframe = ( + link: string, + timers: number, + container: MutableRefObject +) => { + const [iframeShow, setIframeShow] = useState(false); + useEffect(() => { + const iframe = document.createElement('iframe'); + iframe.src = link; + iframe.onload = () => { + setTimeout(() => { + setIframeShow(true); + }, timers); + }; + container.current.appendChild(iframe); + return () => { + iframe.remove(); + }; + }, [link, container]); + return iframeShow; +}; export const useRecastView = () => { const recastBlock = useRecastBlock(); const recastViews =