From b9addbe417ad1491b747199303ff368980c52c45 Mon Sep 17 00:00:00 2001 From: Jeff-Emmett Date: Sat, 15 Mar 2025 14:57:57 -0700 Subject: [PATCH] Markdown tool working, console log cleanup --- src/shapes/ChatBoxShapeUtil.tsx | 2 +- src/shapes/MarkdownShapeUtil.tsx | 314 ++++++++++------------ src/shapes/MycrozineTemplateShapeUtil.tsx | 2 +- src/ui/cameraUtils.ts | 13 +- src/utils/llmUtils.ts | 2 +- 5 files changed, 154 insertions(+), 179 deletions(-) diff --git a/src/shapes/ChatBoxShapeUtil.tsx b/src/shapes/ChatBoxShapeUtil.tsx index 8aabec5..a3cf623 100644 --- a/src/shapes/ChatBoxShapeUtil.tsx +++ b/src/shapes/ChatBoxShapeUtil.tsx @@ -184,7 +184,7 @@ async function sendMessageToChat( }) const result = await response.text() - console.log("Message sent successfully:", result) + //console.log("Message sent successfully:", result) } catch (error) { console.error("Error sending message:", error) } diff --git a/src/shapes/MarkdownShapeUtil.tsx b/src/shapes/MarkdownShapeUtil.tsx index 36df750..5b6db44 100644 --- a/src/shapes/MarkdownShapeUtil.tsx +++ b/src/shapes/MarkdownShapeUtil.tsx @@ -1,188 +1,170 @@ -/** TODO: build this */ - -import { BaseBoxShapeUtil, TLBaseBoxShape, TLBaseShape, StyleProp, T, DefaultSizeStyle, DefaultFontStyle, DefaultColorStyle } from "tldraw" -import { useEffect, useRef, useState } from "react" -import { marked } from "marked" - -// Uncomment and use these style definitions -const MarkdownColor = StyleProp.defineEnum('markdown:color', { - defaultValue: 'black', - values: ['black', 'blue', 'green', 'grey', 'light-blue', 'light-green', 'light-red', 'light-violet', 'orange', 'red', 'violet', 'yellow'], -}) - -const MarkdownSize = StyleProp.defineEnum('markdown:size', { - defaultValue: 'medium', - values: ['small', 'medium', 'large'], -}) - -const MarkdownFont = StyleProp.defineEnum('markdown:font', { - defaultValue: 'draw', - values: ['draw', 'sans', 'serif', 'mono'], -}) - -//const MarkdownHorizontalAlign = StyleProp.define('markdown:horizontalalign', { defaultValue: 'start' }) -//const MarkdownVerticalAlign = StyleProp.define('markdown:verticalalign', { defaultValue: 'start' }) +import React from 'react' +import MDEditor from '@uiw/react-md-editor' +import { BaseBoxShapeUtil, TLBaseShape } from '@tldraw/tldraw' export type IMarkdownShape = TLBaseShape< - "MarkdownTool", + 'Markdown', { - content: string - isPreview: boolean w: number h: number - color: string - size: string - font: string + text: string } > -export class MarkdownShape extends BaseBoxShapeUtil< - IMarkdownShape & TLBaseBoxShape -> { - static override type = "MarkdownTool" +export class MarkdownShape extends BaseBoxShapeUtil { + static type = 'Markdown' as const - styles = { - color: MarkdownColor, - size: MarkdownSize, - font: MarkdownFont, - } - - getDefaultProps(): IMarkdownShape["props"] & { w: number; h: number } { - console.log('getDefaultProps called'); - const props = { - content: "", - isPreview: false, - w: 400, - h: 300, - color: 'black', - size: 'medium', - font: 'draw' - }; - console.log('Default props:', props); - return props; - } - - indicator(shape: IMarkdownShape) { - return ( - - - - ) + getDefaultProps(): IMarkdownShape['props'] { + return { + w: 300, + h: 200, + text: '', + } } component(shape: IMarkdownShape) { - console.log('Component rendering with shape:', shape); - console.log('Available styles:', this.styles); - const editor = this.editor - return - } -} - -function MarkdownEditor({ shape, editor }: { shape: IMarkdownShape; editor: any }) { - console.log('MarkdownEditor mounted with shape:', shape); - console.log('Editor instance:', editor); - - const textareaRef = useRef(null) - const [isPreview, setIsPreview] = useState(shape.props.isPreview) - const [renderedContent, setRenderedContent] = useState("") - - useEffect(() => { - if (textareaRef.current && textareaRef.current.value !== shape.props.content) { - textareaRef.current.value = shape.props.content - } - }, [shape.props.content]) - - useEffect(() => { - const html = marked.parse(shape.props.content, { breaks: true }) as string - setRenderedContent(html) - }, [shape.props.content]) - - const togglePreview = () => { - const newPreviewState = !isPreview - setIsPreview(newPreviewState) - editor.updateShape(shape.id, { - props: { - ...shape.props, - isPreview: newPreviewState + // Hooks must be at the top level + const isSelected = this.editor.getSelectedShapeIds().includes(shape.id) + const markdownRef = React.useRef(null) + + // Single useEffect hook that handles checkbox interactivity + React.useEffect(() => { + if (!isSelected && markdownRef.current) { + const checkboxes = markdownRef.current.querySelectorAll('input[type="checkbox"]') + checkboxes.forEach((checkbox) => { + checkbox.removeAttribute('disabled') + checkbox.addEventListener('click', handleCheckboxClick) + }) + + // Cleanup function + return () => { + if (markdownRef.current) { + const checkboxes = markdownRef.current.querySelectorAll('input[type="checkbox"]') + checkboxes.forEach((checkbox) => { + checkbox.removeEventListener('click', handleCheckboxClick) + }) + } + } } - }) - } + }, [isSelected, shape.props.text]) - return ( -
{ + event.stopPropagation() + const target = event.target as HTMLInputElement + const checked = target.checked + + const text = shape.props.text + const lines = text.split('\n') + const checkboxRegex = /^\s*[-*+]\s+\[([ x])\]/ + + const newText = lines.map(line => { + if (line.includes(target.parentElement?.textContent || '')) { + return line.replace(checkboxRegex, `- [${checked ? 'x' : ' '}]`) + } + return line + }).join('\n') + + this.editor.updateShape({ + id: shape.id, + type: 'Markdown', + props: { + ...shape.props, + text: newText, + }, + }) + } + + const wrapperStyle: React.CSSProperties = { width: '100%', height: '100%', - display: 'flex', - flexDirection: 'column', backgroundColor: 'white', - border: '1px solid #e0e0e0', + border: '1px solid #ddd', borderRadius: '4px', - overflow: 'hidden' - }}> - {/* Toolbar */} -
- -
+ overflow: 'hidden', + } - {/* Editor/Preview Area */} -
- {isPreview ? ( -
- ) : ( -