feat(notes): billeder og bilag følger med ind — og ud
Release / Build and publish image (push) Failing after 9m58s

Du spurgte, hvad der sker med bilag og indsatte billeder. Svaret var: de forsvandt
stille. Scriptet konverterede til ren tekst, og en note fra Apple Noter, der kommer
over som ord alene, er ikke den note — den er et referat af den.

En note kan nu bære filer, i samme tabel som opgaver og grupper allerede bruger.
Filerne er indholdsadresserede og deduplikeres på disken, upload-vejen er skrevet
og afprøvet, og oprydningen af forældreløse filer går allerede den tabel igennem.
En tabel mere ville være et alt-sammen mere.

Importen læser arkivet i to omgange. Alt, der ikke er Markdown, gemmes først, så
en note, der bliver læst, allerede har adresser at få sine links rettet til —
noter og billeder ligger i den rækkefølge, arkivet nu har dem, og ét gennemløb
ville efterlade halvdelen af henvisningerne pegende på ingenting.

Kun de filer, noten faktisk nævner. Et arkiv er én mappe til mange noter, og at
hænge hvert billede på hver note ville gøre hundrede noter til ti tusind bilag.

Hentningen af en note-fil gav 404, fordi adgangskontrollen ikke kendte noter som
forælder. Et billede midt i den tekst, der navngav det, svarede altså "findes
ikke". Den følger nu noten, som følger sit projekt — samme kæde som alt andet.

AppleScriptet gemmer nu hver vedhæftning og skriver en henvisning til den i noten.
Vedhæftninger uden fil bag sig — links til websider, kort — springes over frem for
at vælte kørslen.

Migration 0021.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kristian Wind
2026-08-19 19:12:54 +02:00
co-authored by Claude Opus 5
parent 11fdbefe1b
commit 414a35eaba
12 changed files with 615 additions and 8 deletions
@@ -1,4 +1,5 @@
<script>
/** Import, export and project templates. */
import { api, humanMessage } from '$lib/api.js';
import { app } from '$lib/stores.svelte.js';
@@ -57,6 +58,34 @@
// --- Todoist import ------------------------------------------------------------
let importing = $state(false);
let importingNotes = $state(false);
/**
* A zip of Markdown files becomes notes.
*
* The whole archive in one request rather than a file at a time: the pictures
* have to be in the same request as the notes that name them, or the links
* cannot be rewritten.
*/
async function importNotes(event) {
const file = event.currentTarget.files?.[0];
if (!file) return;
importingNotes = true;
try {
const result = await api.importNotes(file);
app.toast(
t('data.notesImported', {
n: result.created ?? 0,
files: result.files ?? 0
})
);
} catch (e) {
app.toast(humanMessage(e));
} finally {
importingNotes = false;
event.target.value = '';
}
}
let result = $state(null);
async function importTodoist(event) {
@@ -344,6 +373,21 @@
<a class="link" href={api.exportNotesURL()} download>{t('data.exportNotes')}</a>
</div>
<!-- The way back in, and from anywhere else: a folder of Markdown is what
Obsidian, Bear and iA Writer all produce, and what the Apple Notes script in
tools/ writes. Pictures beside the files come with them. -->
<div class="field">
<label for="import-notes">{t('data.importNotes')}</label>
<input
id="import-notes"
type="file"
accept=".zip,application/zip"
onchange={importNotes}
disabled={importingNotes}
/>
<p class="hint">{t('data.importNotesHint')}</p>
</div>
<div class="field">
<label for="export-project">{t('data.exportOne')}</label>
<select id="export-project" bind:value={exportProject}>