Add WebDAV sync provider (manual + auto-sync, title-bar button)

This commit is contained in:
Yuri Karamian
2026-06-07 23:25:47 +02:00
parent aeafd55491
commit eafd2b0a24
3 changed files with 23 additions and 16 deletions
+2 -15
View File
@@ -38,8 +38,8 @@
import { readFile } from '@tauri-apps/plugin-fs';
import { openFile, openUrl, copyFileTo, copyImageToClipboard as copyImageToClipboardCmd, writeBytesTo, copyPngToClipboard } from '$lib/api';
import { save as saveDialog } from '@tauri-apps/plugin-dialog';
import { activeNote, activeNotePath, appConfig, editorDirty, sourceMode, focusMode, readOnly, quickAccessPaths, notes, navHistory, canGoBack, canGoForward, viewerNote, notebooks, syncState } from '$lib/stores/app';
import { saveNote, saveImage, saveAttachment, readClipboardImage, addQuickAccess, removeQuickAccess, getQuickAccess, getNoteVersions, getNoteVersionContent, createVersion, aiAsk, getAllNoteTitles, readNote, renameNote, syncNow } from '$lib/api';
import { activeNote, activeNotePath, appConfig, editorDirty, sourceMode, focusMode, readOnly, quickAccessPaths, notes, navHistory, canGoBack, canGoForward, viewerNote, notebooks } from '$lib/stores/app';
import { saveNote, saveImage, saveAttachment, readClipboardImage, addQuickAccess, removeQuickAccess, getQuickAccess, getNoteVersions, getNoteVersionContent, createVersion, aiAsk, getAllNoteTitles, readNote, renameNote } from '$lib/api';
import type { VersionEntry, AiStreamEvent, NoteTitleEntry } from '$lib/types';
import { listen } from '@tauri-apps/api/event';
import { debounce } from '$lib/utils/debounce';
@@ -4287,19 +4287,6 @@
</svg>
</button>
{/if}
{#if $appConfig?.sync_provider === 'webdav'}
<button
class="icon-btn"
class:active={$syncState.running}
onclick={() => { if (!$syncState.running) syncNow().catch(() => {}); }}
disabled={$syncState.running}
title={$syncState.error ? `Sync error: ${$syncState.error}` : ($syncState.running ? 'Syncing...' : 'Sync now')}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:sync-spin={$syncState.running}>
<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0115-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 01-15 6.7L3 16"/>
</svg>
</button>
{/if}
<button
class="icon-btn"
class:active={$sourceMode}
+12
View File
@@ -316,6 +316,18 @@
async function saveSyncSettings() {
await setSyncSettings(syncProvider, syncUrl || null, syncUsername || null, syncPassword || null, syncOnOpen, syncOnChange, syncIntervalMinutes);
// Reflect into the global store so the top-bar button visibility and the auto-sync
// triggers update live, without needing an app restart.
if ($appConfig) $appConfig = {
...$appConfig,
sync_provider: syncProvider,
webdav_url: syncUrl || null,
webdav_username: syncUsername || null,
webdav_password: syncPassword || null,
sync_on_open: syncOnOpen,
sync_on_change: syncOnChange,
sync_interval_minutes: syncIntervalMinutes,
};
}
async function handleTestSync() {
+9 -1
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import { getCurrentWindow } from '@tauri-apps/api/window';
import { vaultReady, focusMode, readOnly, updateAvailable, showSettings, settingsTab } from '$lib/stores/app';
import { vaultReady, focusMode, readOnly, updateAvailable, showSettings, settingsTab, appConfig, syncState } from '$lib/stores/app';
import { syncNow } from '$lib/api';
let { onNewNote = () => {}, onDailyNote = () => {} }: {
onNewNote?: () => void;
@@ -111,6 +112,13 @@
<line x1="3" y1="10" x2="21" y2="10" />
</svg>
</button>
{#if $appConfig?.sync_provider === 'webdav'}
<button class="switch-vault-btn" class:active={$syncState.running} onclick={() => { if (!$syncState.running) syncNow().catch(() => {}); }} disabled={$syncState.running} title={$syncState.error ? `Sync error: ${$syncState.error}` : ($syncState.running ? 'Syncing vault...' : 'Sync vault now')}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:sync-spin={$syncState.running}>
<path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0115-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 01-15 6.7L3 16"/>
</svg>
</button>
{/if}
<button class="new-note-btn" onclick={onNewNote} title={`New Note (${modKey}+N)`}>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
<path d="M7 1v12M1 7h12" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" />