v1.0.7 - Virtual scroll, context menu fix, wiki-link cache fix

This commit is contained in:
Yuri Karamian
2026-02-11 15:08:28 +01:00
parent 070590bd2a
commit 6dfea864f3
6 changed files with 44 additions and 8 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "helixnotes", "name": "helixnotes",
"private": true, "private": true,
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"version": "1.0.6", "version": "1.0.7",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
+1 -1
View File
@@ -1778,7 +1778,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "helixnotes" name = "helixnotes"
version = "1.0.6" version = "1.0.7"
dependencies = [ dependencies = [
"chrono", "chrono",
"dirs", "dirs",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "helixnotes" name = "helixnotes"
version = "1.0.6" version = "1.0.7"
description = "Local-first markdown note-taking app" description = "Local-first markdown note-taking app"
authors = ["HelixNotes"] authors = ["HelixNotes"]
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "HelixNotes", "productName": "HelixNotes",
"version": "1.0.6", "version": "1.0.7",
"identifier": "com.helixnotes.app", "identifier": "com.helixnotes.app",
"build": { "build": {
"frontendDist": "../build", "frontendDist": "../build",
+3 -1
View File
@@ -723,6 +723,8 @@
closeWikiLinkMenu(); closeWikiLinkMenu();
return; return;
} }
// Refresh titles when the menu first opens so newly created notes are found
if (!wikiLinkMenu) refreshWikiLinkTitles();
const query = match[1]; const query = match[1];
const bracketOffset = textBefore.length - match[0].length; const bracketOffset = textBefore.length - match[0].length;
const from = resolvedFrom.start() + bracketOffset; const from = resolvedFrom.start() + bracketOffset;
@@ -1759,7 +1761,7 @@
let x = event.clientX; let x = event.clientX;
let y = event.clientY; let y = event.clientY;
const menuWidth = 220; const menuWidth = 220;
const menuHeight = 640; const menuHeight = 740;
if (x + menuWidth > window.innerWidth) x = window.innerWidth - menuWidth - 8; if (x + menuWidth > window.innerWidth) x = window.innerWidth - menuWidth - 8;
if (y + menuHeight > window.innerHeight) y = window.innerHeight - menuHeight - 8; if (y + menuHeight > window.innerHeight) y = window.innerHeight - menuHeight - 8;
if (x < 4) x = 4; if (x < 4) x = 4;
+37 -3
View File
@@ -54,16 +54,47 @@
let qaDragOver = $state<number | null>(null); let qaDragOver = $state<number | null>(null);
let qaDragHalf = $state<'top' | 'bottom'>('bottom'); let qaDragHalf = $state<'top' | 'bottom'>('bottom');
// Virtual scroll
let listContainer = $state<HTMLDivElement>(null!);
let scrollTop = $state(0);
let containerHeight = $state(600);
let itemHeight = $derived(compact ? 33 : 62);
const BUFFER = 10;
let totalHeight = $derived($sortedNotes.length * itemHeight);
let startIndex = $derived(Math.max(0, Math.floor(scrollTop / itemHeight) - BUFFER));
let endIndex = $derived(Math.min($sortedNotes.length, Math.ceil((scrollTop + containerHeight) / itemHeight) + BUFFER));
let visibleNotes = $derived($sortedNotes.slice(startIndex, endIndex));
let topPad = $derived(startIndex * itemHeight);
let bottomPad = $derived(Math.max(0, ($sortedNotes.length - endIndex) * itemHeight));
function onListScroll(e: Event) {
const el = e.currentTarget as HTMLDivElement;
scrollTop = el.scrollTop;
}
function clearSelection() { function clearSelection() {
selectedPaths = new Set(); selectedPaths = new Set();
lastClickedPath = null; lastClickedPath = null;
batchMovePicker = false; batchMovePicker = false;
} }
// Clear selection when view/notebook changes // Clear selection and reset scroll when view/notebook changes
$effect(() => { $effect(() => {
const _ = [$viewMode, $activeNotebook, $activeTag]; const _ = [$viewMode, $activeNotebook, $activeTag];
clearSelection(); clearSelection();
scrollTop = 0;
if (listContainer) listContainer.scrollTop = 0;
});
// Track container height via ResizeObserver
$effect(() => {
if (!listContainer) return;
const ro = new ResizeObserver((entries) => {
containerHeight = entries[0].contentRect.height;
});
ro.observe(listContainer);
return () => ro.disconnect();
}); });
interface FlatNotebook { name: string; path: string; depth: number; } interface FlatNotebook { name: string; path: string; depth: number; }
@@ -506,7 +537,7 @@
</div> </div>
{/if} {/if}
<div class="list-content"> <div class="list-content" bind:this={listContainer} onscroll={onListScroll}>
{#if $sortedNotes.length === 0} {#if $sortedNotes.length === 0}
<div class="empty-state"> <div class="empty-state">
{#if $viewMode === 'trash'} {#if $viewMode === 'trash'}
@@ -518,7 +549,9 @@
</div> </div>
{/if} {/if}
{#each $sortedNotes as note, noteIndex (note.path)} <div style="height: {topPad}px"></div>
{#each visibleNotes as note, i (note.path)}
{@const noteIndex = startIndex + i}
{#if editingNote === note.path} {#if editingNote === note.path}
<div class="note-item active"> <div class="note-item active">
<input <input
@@ -626,6 +659,7 @@
</button> </button>
{/if} {/if}
{/each} {/each}
<div style="height: {bottomPad}px"></div>
</div> </div>
</div> </div>