From 1632dd22c4b0ea0838ae2d33bff54581d0d75d0b Mon Sep 17 00:00:00 2001 From: Sandro Date: Thu, 29 Oct 2026 23:47:38 +0100 Subject: [PATCH] fix(workspace): English slash commands, short texts, wider menu /image replaces /bild (aliases bild/foto keep working), shorter descriptions for /link, /image, /audio, /diktat; the menu is wider, the command never wraps and long descriptions are cut off. Co-Authored-By: Claude Opus 5.5 --- frontend/src/features/help/HelpView.tsx | 2 +- .../src/features/workspace/ImagePicker.tsx | 2 +- .../src/features/workspace/OutlinerBlock.tsx | 26 +++++++++++-------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/frontend/src/features/help/HelpView.tsx b/frontend/src/features/help/HelpView.tsx index 9132b94..2f7b43e 100644 --- a/frontend/src/features/help/HelpView.tsx +++ b/frontend/src/features/help/HelpView.tsx @@ -200,7 +200,7 @@ export const HelpView: React.FC = ({ onBack }) => {
🖼️ - /bild (Bild hochladen, fotografieren, einfügen oder per Link; nur im leeren Punkt) + /image oder /bild (Bild hochladen, fotografieren, einfügen oder per Link; nur im leeren Punkt)
🎙️ diff --git a/frontend/src/features/workspace/ImagePicker.tsx b/frontend/src/features/workspace/ImagePicker.tsx index a3dc88a..5526206 100644 --- a/frontend/src/features/workspace/ImagePicker.tsx +++ b/frontend/src/features/workspace/ImagePicker.tsx @@ -8,7 +8,7 @@ interface ImagePickerProps { onCancel: () => void; } -// Inline box an empty bullet turns into after /bild: pick a file (or the camera on phones), drop or +// Inline box an empty bullet turns into after /image: pick a file (or the camera on phones), drop or // paste an image, or give a link the server copies. Nothing is synced until the upload succeeded. export const ImagePicker: React.FC = ({ docId, onDone, onCancel }) => { const [busy, setBusy] = useState(false); diff --git a/frontend/src/features/workspace/OutlinerBlock.tsx b/frontend/src/features/workspace/OutlinerBlock.tsx index f4a1650..8a89d00 100644 --- a/frontend/src/features/workspace/OutlinerBlock.tsx +++ b/frontend/src/features/workspace/OutlinerBlock.tsx @@ -45,20 +45,22 @@ export interface SlashCommand { icon: React.ReactNode; /** Only offered in an empty bullet; the bullet turns into an inline picker first */ media?: boolean; + /** Further names that find the command (e.g. German ones) */ + aliases?: string[]; } const SLASH_COMMANDS: SlashCommand[] = [ { type: 'todo', label: '/todo', desc: 'Aufgabe mit Checkbox', icon: }, - { type: 'link', label: '/link', desc: 'Notiz verknüpfen oder Web-Link einfügen', icon: }, + { type: 'link', label: '/link', desc: 'Notiz oder Weblink', icon: }, { type: 'h1', label: '/h1', desc: 'Große Überschrift', icon: }, { type: 'h2', label: '/h2', desc: 'Abschnitts-Überschrift', icon: }, { type: 'h3', label: '/h3', desc: 'Unterabschnitt', icon: }, { type: 'code', label: '/code', desc: 'Code-Block mit Syntax', icon: }, { type: 'callout', label: '/callout', desc: 'Hinweisbox', icon: }, { type: 'divider', label: '/divider', desc: 'Trennlinie', icon: }, - { type: 'image', label: '/bild', desc: 'Bild hochladen, fotografieren oder verlinken (image)', icon: , media: true }, - { type: 'audio', label: '/audio', desc: 'Sprachnotiz aufnehmen oder Audiodatei hochladen', icon: , media: true }, - { type: 'dictation', label: '/diktat', desc: 'Sprechen statt tippen: Text direkt in den Punkt', icon: , media: true }, + { type: 'image', label: '/image', desc: 'Bilder hochladen oder verlinken', icon: , media: true, aliases: ['bild', 'foto'] }, + { type: 'audio', label: '/audio', desc: 'Sprachnotiz oder Audiodatei', icon: , media: true, aliases: ['sprachnotiz'] }, + { type: 'dictation', label: '/diktat', desc: 'Sprechen statt tippen', icon: , media: true, aliases: ['dictate'] }, ]; export interface OutlinerBlockProps { @@ -149,7 +151,7 @@ export const OutlinerBlock: React.FC = ({ // A block someone else is editing can still get the cursor (read-only), e.g. to press Enter at its end const canFocus = canEdit || (!!lockedBy && !!canAppendBelow); const [slashSearch, setSlashSearch] = useState(null); - // Inline picker an empty bullet turns into after /bild (local only, nothing synced until done) + // Inline picker an empty bullet turns into after /image (local only, nothing synced until done) const [mediaPicker, setMediaPicker] = useState<'image' | 'audio' | 'dictation' | null>(null); const [slashIndex, setSlashIndex] = useState(0); const [showLinkModal, setShowLinkModal] = useState(false); @@ -352,7 +354,9 @@ export const OutlinerBlock: React.FC = ({ (c) => (!c.media || emptyBullet) && (c.type !== 'dictation' || ['server', 'browser'].includes(currentVoiceConfig().mode)) && - (c.label.toLowerCase().includes(cmdQuery) || c.desc.toLowerCase().includes(cmdQuery)) + (c.label.toLowerCase().includes(cmdQuery) || + c.desc.toLowerCase().includes(cmdQuery) || + (c.aliases || []).some((a) => a.includes(cmdQuery))) ); }, [slashSearch, localContent]); @@ -366,7 +370,7 @@ export const OutlinerBlock: React.FC = ({ return; } if (cmd.media) { - // The typed "/bild" must not stay in the synced text; the block type changes only after the upload + // The typed "/image" must not stay in the synced text; the block type changes only after the upload setLocalContent(''); localContentRef.current = ''; flushDebounce(''); @@ -1208,7 +1212,7 @@ export const OutlinerBlock: React.FC = ({ {/* Floating Slash Commands Menu */} {slashSearch !== null && canEdit && ( -
+
Befehl auswählen
@@ -1227,11 +1231,11 @@ export const OutlinerBlock: React.FC = ({ : 'text-main hover:bg-panel-elevated' }`} > -
+
{cmd.icon} - {cmd.label} + {cmd.label}
- {cmd.desc} + {cmd.desc} ))} {filteredSlashCommands.length === 0 && (