Compare commits

...
5 Commits
9 changed files with 51 additions and 20 deletions
+4 -4
View File
@@ -23,19 +23,19 @@ curl -fsSL https://repo.arkhost.com/gpg.key | sudo gpg --dearmor -o /usr/share/k
#### AppImage (Arch, Fedora, openSUSE) #### AppImage (Arch, Fedora, openSUSE)
[Download AppImage](https://download.helixnotes.com/releases/v1.1.3/HelixNotes_1.1.3_amd64.AppImage) [Download AppImage](https://download.helixnotes.com/releases/v1.1.4/HelixNotes_1.1.4_amd64.AppImage)
#### .deb (manual) #### .deb (manual)
[Download .deb](https://codeberg.org/ArkHost/HelixNotes/releases/download/v1.1.3/HelixNotes_1.1.3_amd64.deb) — Ubuntu 22.04+ [Download .deb](https://codeberg.org/ArkHost/HelixNotes/releases/download/v1.1.4/HelixNotes_1.1.4_amd64.deb) — Ubuntu 22.04+
### Windows ### Windows
[Download Installer](https://codeberg.org/ArkHost/HelixNotes/releases/download/v1.1.3/HelixNotes_1.1.3_x64-setup.exe) — Windows 10/11 [Download Installer](https://codeberg.org/ArkHost/HelixNotes/releases/download/v1.1.4/HelixNotes_1.1.4_x64-setup.exe) — Windows 10/11
### macOS ### macOS
[Download .dmg](https://codeberg.org/ArkHost/HelixNotes/releases/download/v1.1.3/HelixNotes_1.1.3_x64.dmg) — macOS 12+ (Intel, runs on Apple Silicon via Rosetta) [Download .dmg](https://codeberg.org/ArkHost/HelixNotes/releases/download/v1.1.4/HelixNotes_1.1.4_x64.dmg) — macOS 12+ (Intel, runs on Apple Silicon via Rosetta)
--- ---
+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.1.4", "version": "1.1.5",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
+1 -1
View File
@@ -1750,7 +1750,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "helixnotes" name = "helixnotes"
version = "1.1.4" version = "1.1.5"
dependencies = [ dependencies = [
"chrono", "chrono",
"dirs", "dirs",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "helixnotes" name = "helixnotes"
version = "1.1.4" version = "1.1.5"
description = "Local markdown note-taking app" description = "Local 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.1.4", "version": "1.1.5",
"identifier": "com.helixnotes.app", "identifier": "com.helixnotes.app",
"build": { "build": {
"frontendDist": "../build", "frontendDist": "../build",
+34 -1
View File
@@ -34,18 +34,46 @@
const appWindow = getCurrentWindow(); const appWindow = getCurrentWindow();
const isMac = navigator.platform.startsWith('Mac'); const isMac = navigator.platform.startsWith('Mac');
const isMobile = /android|ios/i.test(navigator.userAgent); const isMobile = /android|ios/i.test(navigator.userAgent);
import { loadVaultState, saveVaultState, readNote, createDailyNote } from '$lib/api'; import { loadVaultState, saveVaultState, readNote, createDailyNote, createBackup } from '$lib/api';
import { debounce } from '$lib/utils/debounce'; import { debounce } from '$lib/utils/debounce';
import { get } from 'svelte/store';
import type { VaultState, FileEvent } from '$lib/types'; import type { VaultState, FileEvent } from '$lib/types';
let sidebar: Sidebar; let sidebar: Sidebar;
let noteList: NoteList; let noteList: NoteList;
let editor: Editor; let editor: Editor;
let unlistenFileChange: (() => void) | null = null; let unlistenFileChange: (() => void) | null = null;
let backupInterval: ReturnType<typeof setInterval> | null = null;
let navigatingFromHistory = false; let navigatingFromHistory = false;
let noteHistory: string[] = []; let noteHistory: string[] = [];
let noteHistoryIndex = -1; let noteHistoryIndex = -1;
function parseFrequencyMs(freq: string): number {
switch (freq) {
case '6h': return 6 * 60 * 60 * 1000;
case '12h': return 12 * 60 * 60 * 1000;
case '7d': return 7 * 24 * 60 * 60 * 1000;
case '24h': default: return 24 * 60 * 60 * 1000;
}
}
async function checkScheduledBackup() {
const config = get(appConfig);
if (!config?.backup_enabled) return;
const interval = parseFrequencyMs(config.backup_frequency);
const last = config.last_backup_time ? new Date(config.last_backup_time).getTime() : 0;
if (Date.now() - last >= interval) {
const unlisten = await listen('backup-done', (event: any) => {
if (event.payload?.success) {
const cur = get(appConfig);
if (cur) appConfig.set({ ...cur, last_backup_time: new Date().toISOString() });
}
unlisten();
});
try { await createBackup(); } catch (_) { unlisten(); }
}
}
// Track note navigation in history stack // Track note navigation in history stack
$effect(() => { $effect(() => {
const path = $activeNotePath; const path = $activeNotePath;
@@ -239,10 +267,15 @@
await sidebar?.refresh(); await sidebar?.refresh();
await noteList?.refresh(true); await noteList?.refresh(true);
}); });
// Scheduled backup: check on startup and every 5 minutes
checkScheduledBackup();
backupInterval = setInterval(checkScheduledBackup, 5 * 60 * 1000);
}); });
onDestroy(() => { onDestroy(() => {
unlistenFileChange?.(); unlistenFileChange?.();
if (backupInterval) clearInterval(backupInterval);
}); });
</script> </script>
+1 -1
View File
@@ -2043,7 +2043,7 @@
PdfEmbed, PdfEmbed,
MathBlock, MathBlock,
MathInline, MathInline,
Details.configure({ persist: true, HTMLAttributes: { class: 'editor-details' } }), Details.configure({ persist: false, HTMLAttributes: { class: 'editor-details' } }),
DetailsSummary, DetailsSummary,
DetailsContent, DetailsContent,
TextAlign.configure({ types: ['heading', 'paragraph'] }), TextAlign.configure({ types: ['heading', 'paragraph'] }),
+5 -2
View File
@@ -126,6 +126,7 @@
<div class="shortcut-row"><span class="shortcut-desc">Redo</span><span class="shortcut-keys"><kbd>{modKey}</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd></span></div> <div class="shortcut-row"><span class="shortcut-desc">Redo</span><span class="shortcut-keys"><kbd>{modKey}</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd></span></div>
<div class="shortcut-row"><span class="shortcut-desc">Go back</span><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd></kbd></span></div> <div class="shortcut-row"><span class="shortcut-desc">Go back</span><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd></kbd></span></div>
<div class="shortcut-row"><span class="shortcut-desc">Go forward</span><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd></kbd></span></div> <div class="shortcut-row"><span class="shortcut-desc">Go forward</span><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd></kbd></span></div>
<div class="shortcut-row"><span class="shortcut-desc">Toggle source mode</span><span class="shortcut-keys"><kbd>{modKey}</kbd>+<kbd>Shift</kbd>+<kbd>M</kbd></span></div>
<div class="shortcut-row"><span class="shortcut-desc">Exit focus mode</span><span class="shortcut-keys"><kbd>Esc</kbd></span></div> <div class="shortcut-row"><span class="shortcut-desc">Exit focus mode</span><span class="shortcut-keys"><kbd>Esc</kbd></span></div>
<h4 class="shortcuts-group-title">Editor Commands</h4> <h4 class="shortcuts-group-title">Editor Commands</h4>
@@ -164,7 +165,8 @@
border-radius: 16px; border-radius: 16px;
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
width: 500px; width: 500px;
max-height: 80vh; height: 80vh;
max-height: 600px;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -201,7 +203,7 @@
} }
.info-body { .info-body {
padding: 0 24px 32px; padding: 0 24px 16px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@@ -244,6 +246,7 @@
} }
.info-logo { .info-logo {
margin-top: 12px;
margin-bottom: 8px; margin-bottom: 8px;
} }
+3 -8
View File
@@ -612,13 +612,7 @@
<div class="tab-content"> <div class="tab-content">
<div class="settings-section"> <div class="settings-section">
<h3>Title</h3> <h3>Title</h3>
<div class="setting-options"> <label class="setting-toggle">
<button class="option-btn" class:active={titleMode === 'input'} onclick={() => { titleMode = 'input'; saveGeneralSettings(); }}>Input</button>
<button class="option-btn" class:active={titleMode === 'heading'} onclick={() => { titleMode = 'heading'; saveGeneralSettings(); }}>Heading</button>
<button class="option-btn" class:active={titleMode === 'hidden'} onclick={() => { titleMode = 'hidden'; saveGeneralSettings(); }}>Hidden</button>
</div>
<span class="setting-hint">How the note title is displayed in the editor</span>
<label class="setting-toggle" style="margin-top: 12px;">
<span class="setting-label"> <span class="setting-label">
<span class="setting-name">Hide title in note body</span> <span class="setting-name">Hide title in note body</span>
<span class="setting-desc">Hide the first heading when it matches the note title</span> <span class="setting-desc">Hide the first heading when it matches the note title</span>
@@ -1147,7 +1141,8 @@
border-radius: 16px; border-radius: 16px;
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
width: 620px; width: 620px;
max-height: 80vh; height: 80vh;
max-height: 700px;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;