make real integration attempt, settingsdialog errors

This commit is contained in:
Jeff-Emmett 2025-01-21 22:35:00 +07:00
parent bfbe7b8325
commit 5c24bb64da
6 changed files with 245 additions and 0 deletions

View File

@ -0,0 +1,52 @@
import { TldrawUiButton, useDialogs } from 'tldraw'
import { useMakeReal } from '../hooks/useMakeReal'
import { SettingsDialog } from './SettingsDialog'
export function MakeRealButton() {
const { addDialog } = useDialogs()
const makeReal = useMakeReal()
return (
<div style={{ display: 'flex' }}>
{/* Settings Button */}
<TldrawUiButton
type="icon"
style={{ height: 52, width: 52, padding: 'var(--space-2)' }}
onClick={() => {
addDialog({
id: 'api keys',
component: SettingsDialog,
})
}}
>
<svg
width="20"
height="20"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{ backgroundColor: 'var(--color-background)', borderRadius: '100%' }}
>
{/* Settings icon path */}
<path
d="M7.07095 0.650238C6.67391 0.650238 6.32977 0.925096 6.24198 1.31231L6.0039 2.36247C5.6249 2.47269 5.26335 2.62363 4.92436 2.81013L4.01335 2.23585C3.67748 2.02413 3.23978 2.07312 2.95903 2.35386L2.35294 2.95996C2.0722 3.2407 2.0232 3.6784 2.23493 4.01427L2.80942 4.92561C2.62307 5.2645 2.47227 5.62594 2.36216 6.00481L1.31209 6.24287C0.924883 6.33065 0.650024 6.6748 0.650024 7.07183V7.92897C0.650024 8.32601 0.924883 8.67015 1.31209 8.75794L2.36228 8.99603C2.47246 9.375 2.62335 9.73652 2.80979 10.0755L2.2354 10.9867C2.02367 11.3225 2.07267 11.7602 2.35341 12.041L2.95951 12.6471C3.24025 12.9278 3.67795 12.9768 4.01382 12.7651L4.92506 12.1907C5.26384 12.377 5.62516 12.5278 6.0039 12.6379L6.24198 13.6881C6.32977 14.0753 6.67391 14.3502 7.07095 14.3502H7.92809C8.32512 14.3502 8.66927 14.0753 8.75705 13.6881L8.99505 12.6383C9.37411 12.5282 9.73573 12.3773 10.0748 12.1909L10.986 12.7653C11.3218 12.977 11.7595 12.928 12.0403 12.6473L12.6464 12.0412C12.9271 11.7604 12.9761 11.3227 12.7644 10.9869L12.1902 10.076C12.3768 9.73688 12.5278 9.37515 12.638 8.99596L13.6879 8.75794C14.0751 8.67015 14.35 8.32601 14.35 7.92897V7.07183C14.35 6.6748 14.0751 6.33065 13.6879 6.24287L12.6381 6.00488C12.528 5.62578 12.3771 5.26414 12.1906 4.92507L12.7648 4.01407C12.9766 3.6782 12.9276 3.2405 12.6468 2.95975L12.0407 2.35366C11.76 2.07292 11.3223 2.02392 10.9864 2.23565L10.0755 2.80989C9.73622 2.62328 9.37437 2.47229 8.99505 2.36209L8.75705 1.31231C8.66927 0.925096 8.32512 0.650238 7.92809 0.650238H7.07095Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
/>
</svg>
</TldrawUiButton>
{/* Make Real Button */}
<button
onClick={makeReal}
className="pt-2 pb-2 pr-2"
style={{ cursor: 'pointer', zIndex: 100000, pointerEvents: 'all' }}
>
<div className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Add AI API
</div>
</button>
</div>
)
}

View File

@ -0,0 +1,132 @@
import {
TLUiDialogProps,
TldrawUiButton,
TldrawUiButtonLabel,
TldrawUiDialogBody,
TldrawUiDialogCloseButton,
TldrawUiDialogFooter,
TldrawUiDialogHeader,
TldrawUiDialogTitle,
TldrawUiIcon,
TldrawUiInput,
useReactor,
useValue,
} from 'tldraw'
import { Provider, makeRealSettings } from '../makeRealSettings'
export function SettingsDialog({ onClose }: TLUiDialogProps) {
// Get settings and set up local storage sync
const settings = useValue('settings', () => makeRealSettings.get(), [])
useReactor(
'update settings local storage',
() => {
localStorage.setItem('makereal_settings_2', JSON.stringify(makeRealSettings.get()))
},
[]
)
return (
<>
<TldrawUiDialogHeader>
<TldrawUiDialogTitle>Settings</TldrawUiDialogTitle>
<TldrawUiDialogCloseButton />
</TldrawUiDialogHeader>
<TldrawUiDialogBody
style={{ maxWidth: 350, display: 'flex', flexDirection: 'column', gap: 8 }}
>
{/* Provider Selection */}
<div style={{ display: 'flex', flexDirection: 'column', gap: 4, marginTop: 8 }}>
<div style={{ display: 'flex', flexDirection: 'row', gap: 4 }}>
<label style={{ flexGrow: 2 }}>Provider</label>
</div>
<select
className="apikey_select"
value={settings.provider}
onChange={(e) => {
makeRealSettings.set({
...settings,
provider: e.target.value as any
})
}}
>
<option value="anthropic">Anthropic</option>
<option value="openai">OpenAI</option>
</select>
</div>
{/* API Keys Section */}
<hr style={{ margin: '12px 0px' }} />
{Provider.map((provider: any) => {
if (provider.id === 'google') return null
const value = settings.keys[provider.id]
return (
<ApiKeyInput
key={provider.name + 'key'}
provider={provider}
value={value}
warning={
value === '' &&
(settings.provider === provider.id || settings.provider === 'any')
}
/>
)
})}
{/* Save Button */}
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
<TldrawUiButton
type="primary"
onClick={async () => {
onClose()
}}
>
<TldrawUiButtonLabel>Save</TldrawUiButtonLabel>
</TldrawUiButton>
</TldrawUiDialogFooter>
</TldrawUiDialogBody>
</>
)
}
// Helper component for API key inputs
function ApiKeyInput({
provider,
value,
warning,
}: {
provider: (typeof Provider)[number]
value: string
warning: boolean
}) {
const isValid = value.length === 0 || provider.validate(value)
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
<div style={{ display: 'flex', flexDirection: 'row', gap: 4, alignItems: 'center' }}>
<label style={{ flexGrow: 2, color: warning ? 'red' : 'var(--color-text)' }}>
{provider.name} API key
</label>
<a style={{ cursor: 'pointer', pointerEvents: 'all' }} target="_blank" href={provider.help}>
<TldrawUiIcon
className="apikey_help_icon"
small
icon={provider.validate(value) ? 'check' : 'question-mark-circle'}
/>
</a>
</div>
<TldrawUiInput
className={`apikey_input ${isValid ? '' : 'apikey_input__invalid'}`}
value={value}
placeholder="Enter API key"
onValueChange={(value) => {
makeRealSettings.update((s) => ({
...s,
keys: { ...s.keys, [provider.id]: value }
}))
}}
/>
</div>
)
}

35
hooks/useMakeReal.ts Normal file
View File

@ -0,0 +1,35 @@
import { useCallback } from 'react'
import { useEditor } from 'tldraw'
import { makeRealSettings } from '../makeRealSettings'
export function useMakeReal() {
const editor = useEditor()
return useCallback(async () => {
const settings = makeRealSettings.get()
// Get the current selection from the canvas
const shapes = editor.getSelectedShapes()
try {
// Make API request with the selected shapes
const response = await fetch('/api/make-real', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
shapes,
apiKey: settings.apiKey,
provider: settings.provider,
}),
})
const result = await response.json()
// Handle the result
} catch (error) {
console.error('Error making real:', error)
}
}, [editor])
}

23
makeRealSettings.ts Normal file
View File

@ -0,0 +1,23 @@
type Settings = {
apiKey: string
provider: 'anthropic' | 'openai'
}
class MakeRealSettings {
private settings: Settings = {
apiKey: '',
provider: 'anthropic',
}
get() {
return this.settings
}
set(settings: Partial<Settings>) {
this.settings = { ...this.settings, ...settings }
localStorage.setItem('makereal_settings_2', JSON.stringify(this.settings))
}
}
export const makeRealSettings = new MakeRealSettings()
export const Provider = makeRealSettings.get().provider

1
pages/index.tsx Normal file
View File

@ -0,0 +1 @@

View File

@ -2,9 +2,11 @@ import { CustomMainMenu } from "./CustomMainMenu"
import { CustomToolbar } from "./CustomToolbar"
import { CustomContextMenu } from "./CustomContextMenu"
import { TLComponents } from "tldraw"
import { MakeRealButton } from "../../components/MakeRealButton"
export const components: TLComponents = {
Toolbar: CustomToolbar,
MainMenu: CustomMainMenu,
ContextMenu: CustomContextMenu,
SharePanel: MakeRealButton,
}