diff --git a/src/app/page.tsx b/src/app/page.tsx index 8e2129d..8318ac3 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,17 +1,21 @@ +/* eslint-disable @next/next/no-img-element */ 'use client' import { LiveImageShape, LiveImageShapeUtil } from '@/components/LiveImageShapeUtil' import { LockupLink } from '@/components/LockupLink' import * as fal from '@fal-ai/serverless-client' import { + AssetRecordType, DefaultSizeStyle, Editor, TLUiOverrides, Tldraw, toolbarItem, + track, useEditor, } from '@tldraw/tldraw' -import { useEffect } from 'react' +import { useEffect, useMemo, useState } from 'react' +import { createPortal } from 'react-dom' import { LiveImageTool, MakeLiveButton } from '../components/LiveImageTool' fal.config({ @@ -93,6 +97,7 @@ export default function Home() { > + @@ -106,7 +111,71 @@ function SneakySideEffects() { editor.sideEffects.registerAfterChangeHandler('shape', () => { editor.emit('update-drawings' as any) }) + editor.sideEffects.registerAfterCreateHandler('shape', () => { + editor.emit('update-drawings' as any) + }) + editor.sideEffects.registerAfterDeleteHandler('shape', () => { + editor.emit('update-drawings' as any) + }) }, [editor]) return null } + +const LiveImageAssets = track(function LiveImageAssets() { + const editor = useEditor() + + return ( + + {editor + .getCurrentPageShapes() + .filter((shape): shape is LiveImageShape => shape.type === 'live-image') + .map((shape) => ( + + ))} + + ) +}) + +const LiveImageAsset = track(function LiveImageAsset({ shape }: { shape: LiveImageShape }) { + const editor = useEditor() + + if (!shape.props.overlayResult) return null + + const transform = editor.getShapePageTransform(shape).toCssString() + const assetId = AssetRecordType.createId(shape.id.split(':')[1]) + const asset = editor.getAsset(assetId) + return ( + asset && ( + {shape.props.name} + ) + ) +}) + +function Inject({ children, selector }: { children: React.ReactNode; selector: string }) { + const [parent, setParent] = useState(null) + const target = useMemo(() => parent?.querySelector(selector) ?? null, [parent, selector]) + + return ( + <> +
setParent(el?.parentElement ?? null)} style={{ display: 'none' }} /> + {target && createPortal(children, target)} + + ) +} diff --git a/src/components/LiveImageShapeUtil.tsx b/src/components/LiveImageShapeUtil.tsx index 0d7e220..2af0711 100644 --- a/src/components/LiveImageShapeUtil.tsx +++ b/src/components/LiveImageShapeUtil.tsx @@ -2,6 +2,7 @@ /* eslint-disable react-hooks/rules-of-hooks */ import { AssetRecordType, + Button, Geometry2d, getDefaultColorTheme, Rectangle2d, @@ -51,13 +52,14 @@ export type LiveImageShape = TLBaseShape< w: number h: number name: string + overlayResult?: boolean } > export class LiveImageShapeUtil extends ShapeUtil { static type = 'live-image' as any - override canBind = () => true + override canBind = () => false override canUnmount = () => false override canEdit = () => true override isAspectRatioLocked = () => true @@ -107,7 +109,6 @@ export class LiveImageShapeUtil extends ShapeUtil { override onDragShapesOut = (_shape: LiveImageShape, shapes: TLShape[]): void => { const parent = this.editor.getShape(_shape.parentId) const isInGroup = parent && this.editor.isShapeOfType(parent, 'group') - if (isInGroup) { this.editor.reparentShapes(shapes, parent.id) } else { @@ -161,7 +162,6 @@ export class LiveImageShapeUtil extends ShapeUtil { const assetId = AssetRecordType.createId(shape.id.split(':')[1]) const asset = editor.getAsset(assetId) - // eslint-disable-next-line react-hooks/rules-of-hooks const theme = getDefaultColorTheme({ isDarkMode: useIsDarkMode() }) return ( @@ -181,7 +181,7 @@ export class LiveImageShapeUtil extends ShapeUtil { width={bounds.width} height={bounds.height} /> - {asset && ( + {!shape.props.overlayResult && asset && ( {shape.props.name} { }} /> )} +