diff --git a/src/lib/components/Editor.svelte b/src/lib/components/Editor.svelte
index dd0b886..94690f5 100644
--- a/src/lib/components/Editor.svelte
+++ b/src/lib/components/Editor.svelte
@@ -48,6 +48,7 @@
import { WrapSelectedText } from '$lib/editor/extensions/wrapSelectedText';
import { calloutGroup, calloutIcon, calloutLabel, CALLOUT_MENU, transformCalloutBlockquotes, serializeCallout } from '$lib/editor/callouts';
import { wrapTextareaSelection } from '$lib/editor/source/selectionPairs';
+ import { relativePath } from '$lib/utils/paths';
import GraphView from './GraphView.svelte';
import TagSuggestInput from './TagSuggestInput.svelte';
import { isMobile, isAndroid } from '$lib/platform';
@@ -3697,7 +3698,7 @@
}
}
// Convert asset:// URLs back to relative paths for saving
- if (!src.startsWith('asset:') && !src.startsWith('http://asset.localhost')) return src;
+ if (!src.startsWith('asset:') && !src.startsWith('http://asset.localhost') && !src.startsWith('https://asset.localhost')) return src;
let absPath = '';
try {
const url = new URL(src);
@@ -3707,18 +3708,20 @@
}
// Clean up any leading double/triple slashes (URL parsing artifact)
absPath = absPath.replace(/^\/{2,}/, '/');
- // Make relative to note directory (matches how resolveImageSrc works)
+ absPath = absPath.replace(/^\/([A-Za-z]:\/)/, '$1').replace(/\\/g, '/');
+ // Preserve note-relative paths, including parent-directory segments.
const notePath = $activeNotePath;
- if (notePath) {
- const noteDir = notePath.substring(0, notePath.lastIndexOf('/'));
- if (absPath.startsWith(noteDir + '/')) {
- return absPath.substring(noteDir.length + 1);
- }
- }
- // Fallback: make relative to vault root
- const vaultRoot = $appConfig?.active_vault;
+ const vaultRoot = $appConfig?.active_vault?.replace(/\\/g, '/').replace(/\/$/, '');
if (vaultRoot && absPath.startsWith(vaultRoot + '/')) {
- return absPath.substring(vaultRoot.length + 1);
+ const vaultRelative = absPath.substring(vaultRoot.length + 1);
+ // HelixNotes-managed attachments have explicit vault-root semantics.
+ if (vaultRelative.startsWith('.helixnotes/')) return vaultRelative;
+ if (notePath) {
+ const normalizedNotePath = notePath.replace(/\\/g, '/');
+ const noteDir = normalizedNotePath.substring(0, normalizedNotePath.lastIndexOf('/'));
+ return relativePath(noteDir, absPath);
+ }
+ return vaultRelative;
}
return absPath;
}
diff --git a/src/lib/components/NoteList.svelte b/src/lib/components/NoteList.svelte
index 204c135..5430edd 100644
--- a/src/lib/components/NoteList.svelte
+++ b/src/lib/components/NoteList.svelte
@@ -787,6 +787,19 @@
}
}
+ function isFiled(note: NoteEntry): boolean {
+ const vaultRoot = $appConfig?.active_vault?.replace(/\\/g, '/').replace(/\/$/, '');
+ if (!vaultRoot) return false;
+ const normalizedPath = note.path.replace(/\\/g, '/');
+ const noteDir = normalizedPath.substring(0, normalizedPath.lastIndexOf('/'));
+ return noteDir !== vaultRoot;
+ }
+
+ function unfileNote(note: NoteEntry) {
+ const vaultRoot = $appConfig?.active_vault;
+ if (vaultRoot) handleMoveNote(note, vaultRoot);
+ }
+
function clampMenu(x: number, y: number, menuWidth = 220, menuHeight = 400): { x: number; y: number } {
if (x + menuWidth > window.innerWidth) x = window.innerWidth - menuWidth - 8;
if (y + menuHeight > window.innerHeight) y = window.innerHeight - menuHeight - 8;
@@ -1535,6 +1548,14 @@
Move to...
+ {#if isFiled(contextMenu.note)}
+
+ {/if}
{#if !isMobile}