gui: add sync settings panel in Svelte

This commit is contained in:
mirivlad 2026-06-01 22:58:12 +08:00
parent 1abe8c4fa0
commit a1a50863c5
1 changed files with 106 additions and 1 deletions

View File

@ -98,6 +98,14 @@
let renameValue = ''
let renameError = ''
// ===== Sync state =====
let showSettings = false
let syncStatus = null
let syncLoading = false
let syncServerUrl = ''
let syncApiKey = ''
let syncResult = ''
const tabs = [
{ id: 'overview', label: 'Обзор' },
{ id: 'notes', label: 'Заметки' },
@ -138,6 +146,7 @@
window.addEventListener('keydown', handleKeydown)
loading = false
loadSyncStatus()
})
onDestroy(() => {
@ -882,6 +891,53 @@
error = String(e)
}
}
// ===== Sync =====
async function loadSyncStatus() {
try {
syncStatus = await wailsCall('SyncStatus')
} catch (e) {
syncStatus = { configured: false, serverUrl: '', deviceId: '', unpushedOps: 0, lastSyncAt: '' }
}
}
function openSettings() {
showSettings = true
syncServerUrl = syncStatus?.serverUrl || ''
syncApiKey = ''
syncResult = ''
}
function closeSettings() {
showSettings = false
syncResult = ''
}
async function saveSyncConfig() {
syncLoading = true
syncResult = ''
try {
await wailsCall('SyncConfigure', syncServerUrl, syncApiKey)
syncResult = 'ok'
await loadSyncStatus()
} catch (e) {
syncResult = 'err: ' + String(e)
}
syncLoading = false
}
async function runSyncNow() {
syncLoading = true
syncResult = ''
try {
const r = await wailsCall('SyncNow')
syncResult = 'pushed ' + r.pushed + ', pulled ' + r.pulled + ' (rev ' + r.serverRevision + ')'
await loadSyncStatus()
} catch (e) {
syncResult = 'err: ' + String(e)
}
syncLoading = false
}
</script>
<div class="app">
@ -914,7 +970,12 @@
</div>
{/if}
</nav>
<div class="sidebar-footer"><span class="version">{version}</span></div>
<div class="sidebar-footer">
<span class="version">{version}</span>
<button class="settings-btn" on:click={openSettings} title="Настройки">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
</button>
</div>
</aside>
<!-- Main -->
@ -1425,6 +1486,39 @@
on:cancel={handleCancel}
/>
{/if}
{#if showSettings}
<div class="modal-overlay" on:click|self={closeSettings}>
<div class="modal modal-sync">
<h3>Настройки синхронизации</h3>
{#if syncStatus}
<div class="sync-status">
<div class="sync-row"><span class="sync-label">Статус</span><span class="sync-value">{syncStatus.configured ? 'Включена' : 'Отключена'}</span></div>
<div class="sync-row"><span class="sync-label">Сервер</span><span class="sync-value mono">{syncStatus.serverUrl || '—'}</span></div>
<div class="sync-row"><span class="sync-label">Устройство</span><span class="sync-value mono">{syncStatus.deviceId || '—'}</span></div>
<div class="sync-row"><span class="sync-label">Неотправлено</span><span class="sync-value">{syncStatus.unpushedOps}</span></div>
<div class="sync-row"><span class="sync-label">Последняя синх.</span><span class="sync-value">{syncStatus.lastSyncAt || '—'}</span></div>
</div>
{/if}
<div class="form-group">
<label>URL сервера</label>
<input type="text" placeholder="https://example.com:8443" bind:value={syncServerUrl} />
</div>
<div class="form-group">
<label>API-ключ</label>
<input type="password" placeholder="ключ из админ-панели" bind:value={syncApiKey} />
</div>
{#if syncResult}
<div class="sync-result">{syncResult}</div>
{/if}
<div class="modal-actions">
<button class="btn btn-primary" on:click={saveSyncConfig} disabled={syncLoading}>Сохранить</button>
<button class="btn" on:click={runSyncNow} disabled={syncLoading || !syncStatus?.configured}>Синхронизировать</button>
<button class="btn" on:click={closeSettings}>Закрыть</button>
</div>
</div>
</div>
{/if}
</main>
</div>
@ -1636,4 +1730,15 @@
.activity-feed-type { font-size: 11px; color: #666; }
.activity-feed-target { font-size: 10px; color: #555; background: #1e1e2e; padding: 1px 6px; border-radius: 8px; }
.activity-feed-time { font-size: 11px; color: #555; }
/* Sync */
.settings-btn { background: none; border: none; color: #555; cursor: pointer; padding: 4px; display: inline-flex; align-items: center; border-radius: 4px; margin-left: auto; }
.settings-btn:hover { color: #ccc; background: #222233; }
.modal-sync { width: 460px; }
.sync-status { background: #13131f; border-radius: 8px; padding: 12px; margin-bottom: 16px; }
.sync-row { display: flex; justify-content: space-between; padding: 4px 0; font-size: 13px; }
.sync-label { color: #666; }
.sync-value { color: #e4e4ef; }
.sync-value.mono { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 12px; }
.sync-result { font-size: 12px; color: #6366f1; padding: 4px 0; }
</style>