Generieren: Bild wie Annotieren-Seite groß, Prompt als eingeklappte Leiste
- Canvas-Struktur identisch zu DrawIt (canvas-area > canvas-frame > DrawCanvas) → kein Schrumpfen beim Bild-Wechsel mehr - Prompt-Editor als absolute Leiste am unteren Rand des Canvas-Bereichs - Eingeklappt: zeigt Titel + Layout-Name + Aktionen - Ausgeklappt: Textarea + Speichern-Dialog Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -139,6 +139,7 @@ export default function GenerateIt() {
|
||||
const [promptText, setPromptText] = useState(() => loadLayouts()[0]?.prompt ?? DEFAULT_PROMPT)
|
||||
const [showSaveDialog, setShowSaveDialog] = useState(false)
|
||||
const [newLayoutName, setNewLayoutName] = useState('')
|
||||
const [promptOpen, setPromptOpen] = useState(false)
|
||||
|
||||
const currentPicture: DirectusPicture | null =
|
||||
currentIndex >= 0 && currentIndex < pictureList.length ? pictureList[currentIndex] : null
|
||||
@@ -288,78 +289,81 @@ export default function GenerateIt() {
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{/* Center: Canvas + Prompt Editor */}
|
||||
<main className="canvas-area" style={{ alignItems: 'flex-start', justifyContent: 'flex-start', flexDirection: 'column', gap: 12, padding: 16 }}>
|
||||
<div style={{ width: '100%', maxHeight: 320, overflow: 'hidden' }}>
|
||||
<div className="canvas-frame" style={{ display: 'inline-flex', maxWidth: '100%' }}>
|
||||
<DrawCanvas
|
||||
ref={canvasRef}
|
||||
imageSrc={currentPicture && token ? directusAssetUrl(currentPicture.media, token) : null}
|
||||
objects={canvasObjects}
|
||||
selectedObjectId={selectedObjId}
|
||||
mode="rect"
|
||||
onHasSelection={() => {}}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
{/* Center: Canvas + Prompt Bar */}
|
||||
<main className="canvas-area canvas-area--relative">
|
||||
<div className="canvas-frame">
|
||||
<DrawCanvas
|
||||
ref={canvasRef}
|
||||
imageSrc={currentPicture && token ? directusAssetUrl(currentPicture.media, token) : null}
|
||||
objects={canvasObjects}
|
||||
selectedObjectId={selectedObjId}
|
||||
mode="rect"
|
||||
onHasSelection={() => {}}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Prompt Editor */}
|
||||
<div className="prompt-editor">
|
||||
<div className="prompt-editor-toolbar">
|
||||
<select
|
||||
className="prompt-layout-select"
|
||||
value={selectedLayoutName}
|
||||
onChange={e => handleSelectLayout(e.target.value)}
|
||||
>
|
||||
{layouts.map(l => (
|
||||
<option key={l.name} value={l.name}>{l.name}</option>
|
||||
))}
|
||||
</select>
|
||||
{selectedLayoutName !== 'Standard' && (
|
||||
<button
|
||||
className="btn-ghost btn-sm btn-danger"
|
||||
onClick={() => handleDeleteLayout(selectedLayoutName)}
|
||||
title="Layout löschen"
|
||||
{/* Collapsible Prompt Bar */}
|
||||
<div className={`prompt-bar${promptOpen ? ' prompt-bar--open' : ''}`}>
|
||||
<div className="prompt-bar-header" onClick={() => setPromptOpen(o => !o)}>
|
||||
<span className="prompt-bar-chevron">{promptOpen ? '▾' : '▸'}</span>
|
||||
<span className="prompt-bar-title">Prompt</span>
|
||||
<span className="prompt-bar-layout-name">{selectedLayoutName}</span>
|
||||
<div className="prompt-bar-actions" onClick={e => e.stopPropagation()}>
|
||||
<select
|
||||
className="prompt-layout-select"
|
||||
value={selectedLayoutName}
|
||||
onChange={e => handleSelectLayout(e.target.value)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="btn-ghost btn-sm"
|
||||
style={{ marginLeft: 'auto' }}
|
||||
onClick={() => { setNewLayoutName(''); setShowSaveDialog(s => !s) }}
|
||||
>
|
||||
<SaveIcon />
|
||||
Als Layout speichern
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{showSaveDialog && (
|
||||
<div className="prompt-save-dialog">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Layout-Name"
|
||||
value={newLayoutName}
|
||||
onChange={e => setNewLayoutName(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') handleSaveLayout(); if (e.key === 'Escape') setShowSaveDialog(false) }}
|
||||
autoFocus
|
||||
/>
|
||||
<button className="btn-ghost btn-sm" onClick={handleSaveLayout} disabled={!newLayoutName.trim()}>
|
||||
{layouts.map(l => (
|
||||
<option key={l.name} value={l.name}>{l.name}</option>
|
||||
))}
|
||||
</select>
|
||||
{selectedLayoutName !== 'Standard' && (
|
||||
<button
|
||||
className="btn-ghost btn-sm btn-danger"
|
||||
onClick={() => handleDeleteLayout(selectedLayoutName)}
|
||||
title="Layout löschen"
|
||||
>✕</button>
|
||||
)}
|
||||
<button
|
||||
className="btn-ghost btn-sm"
|
||||
onClick={() => { setNewLayoutName(''); setShowSaveDialog(s => !s) }}
|
||||
>
|
||||
<SaveIcon />
|
||||
Speichern
|
||||
</button>
|
||||
<button className="btn-ghost btn-sm" onClick={() => setShowSaveDialog(false)}>
|
||||
Abbrechen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{promptOpen && (
|
||||
<div className="prompt-bar-body">
|
||||
{showSaveDialog && (
|
||||
<div className="prompt-save-dialog">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Layout-Name"
|
||||
value={newLayoutName}
|
||||
onChange={e => setNewLayoutName(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') handleSaveLayout(); if (e.key === 'Escape') setShowSaveDialog(false) }}
|
||||
autoFocus
|
||||
/>
|
||||
<button className="btn-ghost btn-sm" onClick={handleSaveLayout} disabled={!newLayoutName.trim()}>
|
||||
Speichern
|
||||
</button>
|
||||
<button className="btn-ghost btn-sm" onClick={() => setShowSaveDialog(false)}>
|
||||
Abbrechen
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<textarea
|
||||
className="prompt-textarea"
|
||||
value={promptText}
|
||||
onChange={e => setPromptText(e.target.value)}
|
||||
placeholder="Prompt eingeben…"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<textarea
|
||||
className="prompt-textarea"
|
||||
value={promptText}
|
||||
onChange={e => setPromptText(e.target.value)}
|
||||
placeholder="Prompt eingeben…"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user