Clean up tool names
This commit is contained in:
parent
8664e847cc
commit
c2abfcd3e3
|
|
@ -25,7 +25,7 @@ import {
|
|||
ClickPropagator,
|
||||
} from "@/propagators/ScopedPropagators"
|
||||
import { SlideShapeTool } from "@/tools/SlideShapeTool"
|
||||
import { SlideShapeUtil } from "@/shapes/SlideShapeUtil"
|
||||
import { SlideShape } from "@/shapes/SlideShapeUtil"
|
||||
import { makeRealSettings, applySettingsMigrations } from "@/lib/settings"
|
||||
import { PromptShapeTool } from "@/tools/PromptShapeTool"
|
||||
import { PromptShape } from "@/shapes/PromptShapeUtil"
|
||||
|
|
@ -38,7 +38,7 @@ const customShapeUtils = [
|
|||
ChatBoxShape,
|
||||
VideoChatShape,
|
||||
EmbedShape,
|
||||
SlideShapeUtil,
|
||||
SlideShape,
|
||||
MycrozineTemplateShape,
|
||||
MarkdownShape,
|
||||
PromptShape,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { llm } from "@/utils/llm"
|
|||
import { isShapeOfType } from "@/propagators/utils"
|
||||
|
||||
type IPrompt = TLBaseShape<
|
||||
"prompt",
|
||||
"Prompt",
|
||||
{
|
||||
w: number
|
||||
h: number
|
||||
|
|
@ -21,7 +21,7 @@ type IPrompt = TLBaseShape<
|
|||
>
|
||||
|
||||
export class PromptShape extends BaseBoxShapeUtil<IPrompt> {
|
||||
static override type = "prompt" as const
|
||||
static override type = "Prompt" as const
|
||||
|
||||
FIXED_HEIGHT = 50 as const
|
||||
MIN_WIDTH = 150 as const
|
||||
|
|
@ -59,27 +59,28 @@ export class PromptShape extends BaseBoxShapeUtil<IPrompt> {
|
|||
shape.id,
|
||||
"arrow",
|
||||
)
|
||||
const arrows = arrowBindings
|
||||
.map((binding) => this.editor.getShape(binding.fromId))
|
||||
const arrows = arrowBindings.map((binding) =>
|
||||
this.editor.getShape(binding.fromId),
|
||||
)
|
||||
|
||||
const inputMap = arrows.reduce((acc, arrow) => {
|
||||
const edge = getEdge(arrow, this.editor);
|
||||
const edge = getEdge(arrow, this.editor)
|
||||
if (edge) {
|
||||
const sourceShape = this.editor.getShape(edge.from);
|
||||
const sourceShape = this.editor.getShape(edge.from)
|
||||
if (sourceShape && edge.text) {
|
||||
acc[edge.text] = sourceShape;
|
||||
acc[edge.text] = sourceShape
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, TLShape>);
|
||||
return acc
|
||||
}, {} as Record<string, TLShape>)
|
||||
|
||||
const generateText = async (prompt: string) => {
|
||||
await llm('', prompt, (partial: string, done: boolean) => {
|
||||
await llm("", prompt, (partial: string, done: boolean) => {
|
||||
console.log("DONE??", done)
|
||||
this.editor.updateShape<IPrompt>({
|
||||
id: shape.id,
|
||||
type: "prompt",
|
||||
props: { value: partial, agentBinding: done ? null : 'someone' },
|
||||
type: "Prompt",
|
||||
props: { value: partial, agentBinding: done ? null : "someone" },
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -88,18 +89,21 @@ export class PromptShape extends BaseBoxShapeUtil<IPrompt> {
|
|||
if (shape.props.agentBinding) {
|
||||
return
|
||||
}
|
||||
let processedPrompt = shape.props.prompt;
|
||||
let processedPrompt = shape.props.prompt
|
||||
for (const [key, sourceShape] of Object.entries(inputMap)) {
|
||||
const pattern = `{${key}}`;
|
||||
const pattern = `{${key}}`
|
||||
if (processedPrompt.includes(pattern)) {
|
||||
if (isShapeOfType<TLGeoShape>(sourceShape, 'geo')) {
|
||||
processedPrompt = processedPrompt.replace(pattern, sourceShape.props.text);
|
||||
if (isShapeOfType<TLGeoShape>(sourceShape, "geo")) {
|
||||
processedPrompt = processedPrompt.replace(
|
||||
pattern,
|
||||
sourceShape.props.text,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(processedPrompt);
|
||||
//console.log(processedPrompt)
|
||||
generateText(processedPrompt)
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<HTMLContainer
|
||||
|
|
@ -134,7 +138,7 @@ export class PromptShape extends BaseBoxShapeUtil<IPrompt> {
|
|||
onChange={(text) => {
|
||||
this.editor.updateShape<IPrompt>({
|
||||
id: shape.id,
|
||||
type: "prompt",
|
||||
type: "Prompt",
|
||||
props: { prompt: text.target.value },
|
||||
})
|
||||
}}
|
||||
|
|
@ -158,7 +162,6 @@ export class PromptShape extends BaseBoxShapeUtil<IPrompt> {
|
|||
)
|
||||
}
|
||||
|
||||
// [5]
|
||||
indicator(shape: IPrompt) {
|
||||
return <rect width={shape.props.w} height={shape.props.h} rx={5} />
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback } from 'react'
|
||||
import { useCallback } from "react"
|
||||
import {
|
||||
BaseBoxShapeUtil,
|
||||
Geometry2d,
|
||||
|
|
@ -11,18 +11,18 @@ import {
|
|||
getPerfectDashProps,
|
||||
resizeBox,
|
||||
useValue,
|
||||
} from 'tldraw'
|
||||
import { moveToSlide, useSlides } from '@/slides/useSlides'
|
||||
} from "tldraw"
|
||||
import { moveToSlide, useSlides } from "@/slides/useSlides"
|
||||
|
||||
export type ISlideShape = TLBaseShape<
|
||||
'Slide',
|
||||
"Slide",
|
||||
{
|
||||
w: number
|
||||
h: number
|
||||
}
|
||||
>
|
||||
|
||||
export class SlideShapeUtil extends BaseBoxShapeUtil<ISlideShape> {
|
||||
export class SlideShape extends BaseBoxShapeUtil<ISlideShape> {
|
||||
static override type = "Slide"
|
||||
|
||||
// static override props = {
|
||||
|
|
@ -67,27 +67,35 @@ export class SlideShapeUtil extends BaseBoxShapeUtil<ISlideShape> {
|
|||
const bounds = this.editor.getShapeGeometry(shape).bounds
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const zoomLevel = useValue('zoom level', () => this.editor.getZoomLevel(), [this.editor])
|
||||
const zoomLevel = useValue("zoom level", () => this.editor.getZoomLevel(), [
|
||||
this.editor,
|
||||
])
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const slides = useSlides()
|
||||
const index = slides.findIndex((s) => s.id === shape.id)
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const handleLabelPointerDown = useCallback(() => this.editor.select(shape.id), [shape.id])
|
||||
const handleLabelPointerDown = useCallback(
|
||||
() => this.editor.select(shape.id),
|
||||
[shape.id],
|
||||
)
|
||||
|
||||
if (!bounds) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<div onPointerDown={handleLabelPointerDown} className="slide-shape-label">
|
||||
<div
|
||||
onPointerDown={handleLabelPointerDown}
|
||||
className="slide-shape-label"
|
||||
>
|
||||
{`Slide ${index + 1}`}
|
||||
</div>
|
||||
<SVGContainer>
|
||||
<g
|
||||
style={{
|
||||
stroke: 'var(--color-text)',
|
||||
strokeWidth: 'calc(1px * var(--tl-scale))',
|
||||
stroke: "var(--color-text)",
|
||||
strokeWidth: "calc(1px * var(--tl-scale))",
|
||||
opacity: 0.25,
|
||||
}}
|
||||
pointerEvents="none"
|
||||
|
|
@ -99,9 +107,9 @@ export class SlideShapeUtil extends BaseBoxShapeUtil<ISlideShape> {
|
|||
side[0].dist(side[1]),
|
||||
1 / zoomLevel,
|
||||
{
|
||||
style: 'dashed',
|
||||
style: "dashed",
|
||||
lengthRatio: 6,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { BaseBoxShapeTool } from 'tldraw'
|
||||
|
||||
export class PromptShapeTool extends BaseBoxShapeTool {
|
||||
static override id = 'prompt'
|
||||
static override id = 'Prompt'
|
||||
static override initial = 'idle'
|
||||
override shapeType = 'prompt'
|
||||
override shapeType = 'Prompt'
|
||||
|
||||
}
|
||||
|
|
@ -7,6 +7,6 @@ export class SlideShapeTool extends BaseBoxShapeTool {
|
|||
|
||||
constructor(editor: any) {
|
||||
super(editor)
|
||||
console.log('SlideShapeTool constructed', { id: this.id, shapeType: this.shapeType })
|
||||
//console.log('SlideShapeTool constructed', { id: this.id, shapeType: this.shapeType })
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ export function CustomContextMenu(props: TLUiContextMenuProps) {
|
|||
}}
|
||||
/>
|
||||
<TldrawUiMenuItem
|
||||
id="mycrozine-template"
|
||||
id="MycrozineTemplate"
|
||||
label="Create Mycrozine Template"
|
||||
icon="rectangle"
|
||||
kbd="m"
|
||||
|
|
@ -152,7 +152,7 @@ export function CustomContextMenu(props: TLUiContextMenuProps) {
|
|||
}}
|
||||
/>
|
||||
<TldrawUiMenuItem
|
||||
id="markdown"
|
||||
id="Markdown"
|
||||
label="Create Markdown"
|
||||
icon="markdown"
|
||||
kbd="alt+m"
|
||||
|
|
@ -161,6 +161,16 @@ export function CustomContextMenu(props: TLUiContextMenuProps) {
|
|||
editor.setCurrentTool("Markdown")
|
||||
}}
|
||||
/>
|
||||
<TldrawUiMenuItem
|
||||
id="Prompt"
|
||||
label="Create Prompt"
|
||||
icon="prompt"
|
||||
kbd="alt+p"
|
||||
disabled={hasSelection}
|
||||
onSelect={() => {
|
||||
editor.setCurrentTool("Prompt")
|
||||
}}
|
||||
/>
|
||||
</TldrawUiMenuGroup>
|
||||
|
||||
{/* Frame Controls */}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@ import { DefaultToolbar, DefaultToolbarContent } from "tldraw"
|
|||
import { useTools } from "tldraw"
|
||||
import { useEditor } from "tldraw"
|
||||
import { useState, useEffect } from "react"
|
||||
import { useDialogs } from "tldraw"
|
||||
import { SettingsDialog } from "./SettingsDialog"
|
||||
|
||||
export function CustomToolbar() {
|
||||
const editor = useEditor()
|
||||
const tools = useTools()
|
||||
const [isReady, setIsReady] = useState(false)
|
||||
const [hasApiKey, setHasApiKey] = useState(false)
|
||||
const { addDialog, removeDialog } = useDialogs()
|
||||
|
||||
useEffect(() => {
|
||||
if (editor && tools) {
|
||||
|
|
@ -15,9 +19,71 @@ export function CustomToolbar() {
|
|||
}
|
||||
}, [editor, tools])
|
||||
|
||||
useEffect(() => {
|
||||
const settings = localStorage.getItem("jeff_keys")
|
||||
if (settings) {
|
||||
const { keys } = JSON.parse(settings)
|
||||
setHasApiKey(Object.values(keys).some((key) => key))
|
||||
}
|
||||
}, [])
|
||||
|
||||
if (!isReady) return null
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: "40px",
|
||||
right: "12px",
|
||||
zIndex: 99999,
|
||||
pointerEvents: "auto",
|
||||
display: "flex",
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
addDialog({
|
||||
id: "api-keys",
|
||||
component: ({ onClose }: { onClose: () => void }) => (
|
||||
<SettingsDialog
|
||||
onClose={() => {
|
||||
onClose()
|
||||
removeDialog("api-keys")
|
||||
const settings = localStorage.getItem("jeff_keys")
|
||||
if (settings) {
|
||||
const { keys } = JSON.parse(settings)
|
||||
setHasApiKey(Object.values(keys).some((key) => key))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
})
|
||||
}}
|
||||
style={{
|
||||
padding: "8px 16px",
|
||||
borderRadius: "4px",
|
||||
background: "#2F80ED",
|
||||
color: "white",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
fontWeight: 500,
|
||||
transition: "background 0.2s ease",
|
||||
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
|
||||
whiteSpace: "nowrap",
|
||||
userSelect: "none",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = "#1366D6"
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = "#2F80ED"
|
||||
}}
|
||||
>
|
||||
Keys {hasApiKey ? "✅" : "❌"}
|
||||
</button>
|
||||
</div>
|
||||
<DefaultToolbar>
|
||||
<DefaultToolbarContent />
|
||||
{tools["VideoChat"] && (
|
||||
|
|
@ -52,7 +118,6 @@ export function CustomToolbar() {
|
|||
isSelected={tools["SlideShape"].id === editor.getCurrentToolId()}
|
||||
/>
|
||||
)}
|
||||
{/*
|
||||
{tools["Markdown"] && (
|
||||
<TldrawUiMenuItem
|
||||
{...tools["Markdown"]}
|
||||
|
|
@ -61,7 +126,25 @@ export function CustomToolbar() {
|
|||
isSelected={tools["Markdown"].id === editor.getCurrentToolId()}
|
||||
/>
|
||||
)}
|
||||
*/}
|
||||
{tools["MycrozineTemplate"] && (
|
||||
<TldrawUiMenuItem
|
||||
{...tools["MycrozineTemplate"]}
|
||||
icon="mycrozinetemplate"
|
||||
label="MycrozineTemplate"
|
||||
isSelected={
|
||||
tools["MycrozineTemplate"].id === editor.getCurrentToolId()
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{tools["Prompt"] && (
|
||||
<TldrawUiMenuItem
|
||||
{...tools["Prompt"]}
|
||||
icon="prompt"
|
||||
label="Prompt"
|
||||
isSelected={tools["Prompt"].id === editor.getCurrentToolId()}
|
||||
/>
|
||||
)}
|
||||
</DefaultToolbar>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,102 +4,17 @@ import { CustomContextMenu } from "./CustomContextMenu"
|
|||
import {
|
||||
DefaultKeyboardShortcutsDialog,
|
||||
DefaultKeyboardShortcutsDialogContent,
|
||||
DefaultToolbar,
|
||||
DefaultToolbarContent,
|
||||
TLComponents,
|
||||
TldrawUiMenuItem,
|
||||
useDialogs,
|
||||
useIsToolSelected,
|
||||
useTools,
|
||||
} from "tldraw"
|
||||
import { SettingsDialog } from "./SettingsDialog"
|
||||
import { useEffect } from "react"
|
||||
import { SlidesPanel } from "@/slides/SlidesPanel"
|
||||
import { useState } from "react"
|
||||
|
||||
export const components: TLComponents = {
|
||||
// Toolbar: CustomToolbar,
|
||||
Toolbar: CustomToolbar,
|
||||
MainMenu: CustomMainMenu,
|
||||
ContextMenu: CustomContextMenu,
|
||||
HelperButtons: SlidesPanel,
|
||||
Toolbar: (props: any) => {
|
||||
const tools = useTools()
|
||||
const slideTool = tools["Slide"]
|
||||
const isSlideSelected = slideTool ? useIsToolSelected(slideTool) : false
|
||||
const { addDialog, removeDialog } = useDialogs()
|
||||
const [hasApiKey, setHasApiKey] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const key = localStorage.getItem("openai_api_key")
|
||||
setHasApiKey(!!key)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative", width: "100%", height: "100%" }}>
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: "40px",
|
||||
right: "12px",
|
||||
zIndex: 99999,
|
||||
pointerEvents: "auto",
|
||||
display: "flex",
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
(
|
||||
<button
|
||||
onClick={() => {
|
||||
addDialog({
|
||||
id: "api-keys",
|
||||
component: ({ onClose }: { onClose: () => void }) => (
|
||||
<SettingsDialog
|
||||
onClose={() => {
|
||||
onClose()
|
||||
removeDialog("api-keys")
|
||||
const settings = localStorage.getItem("jeff_keys")
|
||||
if (settings) {
|
||||
const { keys } = JSON.parse(settings)
|
||||
setHasApiKey(Object.values(keys).some((key) => key))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
})
|
||||
}}
|
||||
style={{
|
||||
padding: "8px 16px",
|
||||
borderRadius: "4px",
|
||||
background: "#2F80ED",
|
||||
color: "white",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
fontWeight: 500,
|
||||
transition: "background 0.2s ease",
|
||||
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
|
||||
whiteSpace: "nowrap",
|
||||
userSelect: "none",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = "#1366D6"
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = "#2F80ED"
|
||||
}}
|
||||
>
|
||||
Keys {hasApiKey ? "✅" : "❌"}
|
||||
</button>
|
||||
)
|
||||
</div>
|
||||
<DefaultToolbar {...props}>
|
||||
{slideTool && (
|
||||
<TldrawUiMenuItem {...slideTool} isSelected={isSlideSelected} />
|
||||
)}
|
||||
<DefaultToolbarContent />
|
||||
</DefaultToolbar>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
KeyboardShortcutsDialog: (props: any) => {
|
||||
const tools = useTools()
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -106,10 +106,7 @@ export const overrides: TLUiOverrides = {
|
|||
type: "Slide",
|
||||
readonlyOk: true,
|
||||
onSelect: () => {
|
||||
console.log("SlideShape tool selected from menu")
|
||||
console.log("Current tool before:", editor.getCurrentToolId())
|
||||
editor.setCurrentTool("Slide")
|
||||
console.log("Current tool after:", editor.getCurrentToolId())
|
||||
},
|
||||
},
|
||||
Markdown: {
|
||||
|
|
@ -130,6 +127,15 @@ export const overrides: TLUiOverrides = {
|
|||
readonlyOk: true,
|
||||
onSelect: () => editor.setCurrentTool("MycrozineTemplate"),
|
||||
},
|
||||
Prompt: {
|
||||
id: "Prompt",
|
||||
icon: "prompt",
|
||||
label: "Prompt",
|
||||
type: "Prompt",
|
||||
kdb: "p",
|
||||
readonlyOk: true,
|
||||
onSelect: () => editor.setCurrentTool("Prompt"),
|
||||
},
|
||||
hand: {
|
||||
...tools.hand,
|
||||
onDoubleClick: (info: any) => {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ import { VideoChatShape } from "@/shapes/VideoChatShapeUtil"
|
|||
import { EmbedShape } from "@/shapes/EmbedShapeUtil"
|
||||
import { MarkdownShape } from "@/shapes/MarkdownShapeUtil"
|
||||
import { MycrozineTemplateShape } from "@/shapes/MycrozineTemplateShapeUtil"
|
||||
import { T } from "@tldraw/tldraw"
|
||||
import { SlideShapeUtil } from "@/shapes/SlideShapeUtil"
|
||||
import { SlideShape } from "@/shapes/SlideShapeUtil"
|
||||
|
||||
// add custom shapes and bindings here if needed:
|
||||
export const customSchema = createTLSchema({
|
||||
|
|
@ -45,8 +44,8 @@ export const customSchema = createTLSchema({
|
|||
migrations: MycrozineTemplateShape.migrations,
|
||||
},
|
||||
Slide: {
|
||||
props: SlideShapeUtil.props,
|
||||
migrations: SlideShapeUtil.migrations,
|
||||
props: SlideShape.props,
|
||||
migrations: SlideShape.migrations,
|
||||
},
|
||||
},
|
||||
bindings: defaultBindingSchemas,
|
||||
|
|
@ -225,6 +224,7 @@ export class TldrawDurableObject {
|
|||
onDataChange: () => {
|
||||
// and persist whenever the data in the room changes
|
||||
this.schedulePersistToR2()
|
||||
console.log("Persisting", this.roomId, "to R2")
|
||||
},
|
||||
})
|
||||
})()
|
||||
|
|
|
|||
Loading…
Reference in New Issue