fix(workspace): keep the cursor in a block that turns into a code block
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m58s

Converting via /code or ``` swapped the text field for the code editor's
and left the focus nowhere, so further typing triggered app shortcuts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 22:48:35 +01:00
1 parent 9124809f54
commit cc68d3f334
2 files changed
+19

No files matched your search

+2
View File
@@ -9,8 +9,10 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V
### Added
- Eigene Spracherkennung (optional): Mit `STT_URL` schickt MindSift Aufnahmen an einen selbst betriebenen Whisper-Server (OpenAI-kompatibel, z. B. speaches) statt an Google oder Microsoft. Einstellung nur per Umgebungsvariablen (`STT_*`) inklusive Grenzwerten; `docker-compose.yml` bringt den Dienst `whisper` als Profil mit, das Modell lädt MindSift beim ersten Start selbst. Administration → Server & Isolation zeigt den aktiven Modus und bietet eine Testaufnahme. In der Demo bleibt es bei der Browser-Erkennung.
- API: `POST /voice/transcribe`, `GET /admin/voice`; `/auth/status` meldet `voice.mode`.
- Code-Blöcke in Notizen: Sprachauswahl (rund 50 Sprachen, bei Bedarf nachgeladen), Farben beim Tippen im Stil von VS Code Dark+/Light+ für alle Themes, „Kopieren“, Tab/Shift+Tab rückt ein und aus. `/code yaml` oder ```` ```yaml ```` legt die Sprache direkt fest.
### Changed
- Workspace-Seitenleiste wie ein Datei-Explorer: angeheftete Notizen oben, darunter Ordner und Notizen ohne Zwischenüberschriften.
- Spracheingabe in Quick Dump, im mobilen Erfassen-Sheet und beim Halten des +-Knopfs folgt der Server-Einstellung: mit eigenem Whisper-Server funktioniert sie in allen Browsern (auch Firefox), mit Live-Wellen während der Aufnahme und „Wird erkannt…“ danach. Ohne Unterstützung im Browser oder mit `STT_DISABLED=true` ist das Mikrofon ausgeblendet statt einer Fehlermeldung.
## [0.6.1] - 2026-10-29
@@ -289,6 +289,20 @@ export const OutlinerBlock: React.FC<OutlinerBlockProps> = ({
adjustHeight();
}, [localContent, block.type, block.level, activeFocus, adjustHeight]);
// Turning the block into another type (slash menu, ``` or markdown shortcut) can swap the text field
// for a new one (e.g. the code editor); the cursor must stay in the block so typing goes on there
const refocusAfterTypeChangeRef = useRef(false);
useLayoutEffect(() => {
if (!refocusAfterTypeChangeRef.current) return;
refocusAfterTypeChangeRef.current = false;
const ta = textareaRef.current;
if (ta && document.activeElement !== ta) {
ta.focus();
const end = ta.value.length;
ta.setSelectionRange(end, end);
}
}, [block.type]);
useEffect(() => {
window.addEventListener('resize', adjustHeight);
// The field can be measured while hidden (phone layout shows the editor only after selecting a note);
@@ -335,6 +349,7 @@ export const OutlinerBlock: React.FC<OutlinerBlockProps> = ({
: undefined;
setLocalContent(clean);
localContentRef.current = clean;
if (cmd.type !== block.type) refocusAfterTypeChangeRef.current = true;
flushDebounce(clean, {
type: cmd.type,
...(langOverride !== undefined ? { lang: langOverride } : {}),
@@ -423,6 +438,7 @@ export const OutlinerBlock: React.FC<OutlinerBlockProps> = ({
}
if (typeOverride) {
refocusAfterTypeChangeRef.current = true;
flushDebounce(val, {
type: typeOverride,
...(langOverride !== undefined ? { lang: langOverride } : {}),
@@ -578,6 +594,7 @@ export const OutlinerBlock: React.FC<OutlinerBlockProps> = ({
const resolvedLang = rawLang ? resolveLanguageId(rawLang) || rawLang.toLowerCase() : '';
setLocalContent('');
localContentRef.current = '';
refocusAfterTypeChangeRef.current = true;
flushDebounce('', {
type: 'code',
lang: resolvedLang,