Same class of bug as cd982f2: 9878ab4 (extract FilesTab) also
removed 'let' declarations for capture/drag-drop state that's still
used by the inbox capture flow and CaptureDropOverlay:
captureDropActive, captureDropLabel, captureDragDepth,
lastCaptureDragOverAt, captureDragResetTimer,
dropRootValid, inboxDropValid
Without them, Svelte runtime throws ReferenceError on first render
('captureDropActive is not defined'), leaving the WebView empty.
Verified with headless render smoke: .app + .sidebar mount,
sidebar shows system views + workspace, welcome screen renders.
Rebuild embedded frontend bundle.
After 9878ab4 moved file-preview state into FilesTab, App.svelte still
references previewItem/previewContent/previewLoading/previewError in
two places that were not migrated:
- openTrashPreview() (trash file preview flow, ~line 1334)
- {#if previewItem} <FilePreviewModal ...> block (~line 3563)
Without these 'let' bindings, vite-plugin-svelte warned
'previewError is not defined' and the Svelte runtime threw a
ReferenceError on first render, leaving the WebView empty.
Restore the four 'let' declarations in App.svelte (kept here because
trash lives outside FilesTab) and rebuild the embedded frontend bundle.
Problem: MarkdownPreview dispatched DOM CustomEvent via link.dispatchEvent()
which doesn't propagate through Svelte's event system. The on:verstak-link
handler on <MarkdownPreview> in NoteEditorPanel only catches Svelte dispatch()
events, not DOM CustomEvents from {@html} content.
Fix: Replaced DOM CustomEvent dispatch with Svelte createEventDispatcher.
Now handleClick() in MarkdownPreview calls dispatch('verstak-link', {...})
which properly propagates through NoteEditorPanel → App.svelte chain.
Also: removed unused importInternalLink import (was unused after
InternalLinkPicker replaced the manual modal).
Root cause: DOMPurify afterSanitizeAttributes hook was treating verstak://
links as blocked because hash-based href didnt match ALLOWED_SCHEMES regex.
Fix:
1. afterSanitizeAttributes hook now checks data-verstak-href first and
returns early for internal links - they never get blocked
2. Changed href from hash-based to about:blank (safe value that
DOMPurify wont strip, unlike javascript:void(0))
3. Click handler already uses data-verstak-href, not href
Added unit test: markdown.test.js (27 tests for renderer.link output)
Unified search normalization across InternalLinkPicker and GlobalSearch:
1. GlobalSearch.svelte: multi-variant search (same as InternalLinkPicker)
- expandKeyboardVariants() for RU/EN layout swap
- Parallel Search queries with dedup by type+nodeId+targetId+title
- 180ms debounce preserved
2. Backend: fix LOWER() in SQL for links/actions
- Replace LOWER(column) LIKE with lowercased columns (title_lower, url_lower, etc.)
- Migration 020: add lowercased columns + indexes for links and actions
- BackfillLinksLower() + BackfillActionsLower() in storage.go
- Update INSERT in bindings_links.go and action.go to populate lowercased columns
3. FTS5 search: Unicode case-insensitive
- Index lowercased title/content/tags in search_index
- sanitizeFTS() now lowercases query before MATCH
- RebuildFTS() called after migrations
4. Case-insensitive search for nodes (already done in previous commit, verified):
- title_lower column with Go strings.ToLower
- Search() queries title_lower with lowercased query
All test suites PASS, full build OK.
Replace broken ObjectPickerModal and manual modal with proper
InternalLinkPicker component:
- Search field with debounced SearchNodes API calls
- Type tabs: Дело, Заметка, Файл, Секрет (disabled)
- Results list showing title + path, keyboard navigation
- Inserts [Title](verstak://type/id) at cursor position
- No layout breakage — picker is a normal modal via position:fixed
- Escape/Cancel close picker cleanly
- bind:this on NoteEditorPanel → MarkdownEditor.insertText()
Also:
- MarkdownEditor: added public insertText() method + bind:this
- NoteEditorPanel: added bind:this on MarkdownEditor + public insertText()
- Removed manual modal, insertInternalLinkMarkdown(), document.querySelector
Root cause: CallFunctionJSON used .String() on Lua return values, which
for tables produces 'table: 0x...' — not valid JSON. Frontend does
JSON.parse() on the result and silently caught the parse error.
Fix:
- runtime.go: convert Lua return value to JSON via luaValueToGo +
json.Marshal so tables become proper JSON arrays/objects
- main.lua: add backward compat in get_events() and update_event()
to accept both positional args (start, end) and table params
- CalendarPluginPage.svelte: show errors in UI instead of silent catch;
restructure template to always show iframe + error overlay
PluginPage.svelte использовал несуществующий Wails binding CallPluginAction.
Заменён на CallPluginFunction с правильным dotted path (calendar.get_events и т.д.),
что соответствует сигнатуре bindings_plugins.go.
Frontend пересобран, go build + go test ./... — всё зелёное.
- Новый экран 'Сегодня' разбит на 4 вкладки: Лента, Предложения,
В работе, Захвачено
- Лента отображает события за сегодня с кликабельными сущностями
- Предложения вынесены в отдельную вкладку (только предложения)
- В работе: изменённые файлы/заметки/действия за сегодня с сортировками
- Захвачено: захваченные элементы за сегодня с сортировками
- Неразобранное: сортировка по дате/имени/типу с направлением
- Неразобранное: переключатель 'Группировать по месту захвата'
- TodayScreen.svelte: новый компонент с 4 вкладками
- Новые i18n ключи для вкладок и сортировок
- Backend: ListTodayInProgress, ListTodayCaptures bindings
- Все переходы из вкладок ведут в соответствующее место программы