mirror of
https://gitlab.com/ArkHost/HelixNotes.git
synced 2026-09-23 03:17:29 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f4f6f5f0e | ||
|
|
74f1c7f6b0 | ||
|
|
3b5cdf22eb | ||
|
|
31f4867e91 | ||
|
|
8baa976a02 |
@@ -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
@@ -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",
|
||||||
|
|||||||
Generated
+1
-1
@@ -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,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,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,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>
|
||||||
|
|
||||||
|
|||||||
@@ -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'] }),
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user