Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e5b380f8c | ||
|
|
e76919ab5c | ||
|
|
84ab90fd3f | ||
|
|
87b191eb63 | ||
|
|
0def9d6d6d | ||
|
|
e708d8ee63 | ||
|
|
461001442a | ||
|
|
6b5e923e8e | ||
|
|
289606a746 |
@@ -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.3.3",
|
"version": "1.3.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
|
|||||||
@@ -1850,7 +1850,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "helixnotes"
|
name = "helixnotes"
|
||||||
version = "1.3.3"
|
version = "1.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arboard",
|
"arboard",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -1860,6 +1860,7 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
"notify",
|
"notify",
|
||||||
|
"objc2-app-kit",
|
||||||
"png 0.17.16",
|
"png 0.17.16",
|
||||||
"quick-xml 0.36.2",
|
"quick-xml 0.36.2",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "helixnotes"
|
name = "helixnotes"
|
||||||
version = "1.3.3"
|
version = "1.3.4"
|
||||||
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"
|
||||||
@@ -42,6 +42,9 @@ quick-xml = "0.36"
|
|||||||
urlencoding = "2"
|
urlencoding = "2"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
rustls = { version = "0.23", default-features = false, features = ["ring", "logging", "std", "tls12"] }
|
rustls = { version = "0.23", default-features = false, features = ["ring", "logging", "std", "tls12"] }
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
objc2-app-kit = "0.3.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "ios")'.dependencies]
|
[target.'cfg(target_os = "ios")'.dependencies]
|
||||||
tauri-plugin-ios-vault-access = { path = "plugins/ios-vault-access" }
|
tauri-plugin-ios-vault-access = { path = "plugins/ios-vault-access" }
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 5.2 KiB |
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="ic_launcher_background">#fff</color>
|
<color name="ic_launcher_background">#626ED4</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="translate(85.333 85.333) scale(0.666667)">
|
||||||
|
<line x1="178.45584" y1="178.45584" x2="333.54416" y2="333.54416" stroke="#ffffff" stroke-width="25" stroke-opacity="0.5" stroke-linecap="round"/>
|
||||||
|
<line x1="337.53708" y1="174.46292" x2="174.46294" y2="337.53708" stroke="#ffffff" stroke-width="25" stroke-opacity="0.5" stroke-linecap="round"/>
|
||||||
|
<circle cx="153" cy="153" r="36" fill="#ffffff"/>
|
||||||
|
<circle cx="359" cy="153" r="36" fill="#ffffff"/>
|
||||||
|
<circle cx="153" cy="359" r="36" fill="#ffffff"/>
|
||||||
|
<circle cx="359" cy="359" r="36" fill="#ffffff"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 706 B |
@@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, PluginApi, PluginHandle, TauriPlugin},
|
plugin::{Builder, PluginHandle, TauriPlugin},
|
||||||
AppHandle, Manager, Runtime,
|
Manager, Runtime,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
@@ -73,19 +73,11 @@ impl<R: Runtime, T: Manager<R>> IosVaultAccessExt<R> for T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize<R: Runtime>(
|
|
||||||
_app: &AppHandle<R>,
|
|
||||||
api: PluginApi<R, ()>,
|
|
||||||
) -> tauri::Result<IosVaultAccess<R>> {
|
|
||||||
let handle = api.register_ios_plugin(init_plugin_ios_vault_access)?;
|
|
||||||
Ok(IosVaultAccess(handle))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||||
Builder::new("ios-vault-access")
|
Builder::new("ios-vault-access")
|
||||||
.setup(|app, api| {
|
.setup(|app, api| {
|
||||||
let access = initialize(app, api)?;
|
let handle = api.register_ios_plugin(init_plugin_ios_vault_access)?;
|
||||||
app.manage(access);
|
app.manage(IosVaultAccess(handle));
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@@ -392,11 +392,15 @@ pub fn import_custom_themes(state: State<'_, AppState>, path: String) -> Result<
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn set_font_size(state: State<'_, AppState>, size: u32) -> Result<(), String> {
|
pub fn set_font_size(app: AppHandle, state: State<'_, AppState>, size: u32) -> Result<(), String> {
|
||||||
let mut config = state.config.lock().map_err(|e| e.to_string())?;
|
let mut config = state.config.lock().map_err(|e| e.to_string())?;
|
||||||
config.font_size = Some(size);
|
config.font_size = Some(size);
|
||||||
save_app_config(&config)?;
|
save_app_config(&config)?;
|
||||||
Ok(())
|
drop(config);
|
||||||
|
|
||||||
|
use tauri::Emitter;
|
||||||
|
app.emit("editor-font-size-changed", size)
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
|||||||
@@ -56,6 +56,23 @@ pub fn run() {
|
|||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.plugin(tauri_plugin_fs::init())
|
.plugin(tauri_plugin_fs::init())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
|
.on_page_load(|webview, payload| {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
if webview.label() == "main"
|
||||||
|
&& matches!(
|
||||||
|
payload.event(),
|
||||||
|
tauri::webview::PageLoadEvent::Finished
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let window = webview.window();
|
||||||
|
let window_on_main = window.clone();
|
||||||
|
let _ = window.run_on_main_thread(move || {
|
||||||
|
fix_macos_traffic_lights(&window_on_main);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let _ = (webview, payload);
|
||||||
|
})
|
||||||
.setup(move |app| {
|
.setup(move |app| {
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
app.handle().plugin(tauri_plugin_ios_vault_access::init())?;
|
app.handle().plugin(tauri_plugin_ios_vault_access::init())?;
|
||||||
@@ -88,13 +105,6 @@ pub fn run() {
|
|||||||
setup_tray(app)?;
|
setup_tray(app)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
if let Some(window) = app.get_webview_window("main") {
|
|
||||||
fix_macos_traffic_lights(&window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check CLI args for a .md file path on initial launch
|
// Check CLI args for a .md file path on initial launch
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
{
|
{
|
||||||
@@ -401,44 +411,49 @@ fn percent_decode(input: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
fn fix_macos_traffic_lights(window: &tauri::WebviewWindow) {
|
fn fix_macos_traffic_lights(window: &tauri::Window) {
|
||||||
use objc2_app_kit::{NSView, NSWindow, NSWindowButton};
|
use objc2_app_kit::{NSView, NSWindow, NSWindowButton};
|
||||||
|
|
||||||
|
const TITLEBAR_HEIGHT: f64 = 34.0;
|
||||||
|
const LEFT_INSET: f64 = 12.0;
|
||||||
|
|
||||||
let ns_window_ptr = match window.ns_window() {
|
let ns_window_ptr = match window.ns_window() {
|
||||||
Ok(ptr) => ptr,
|
Ok(ptr) => ptr,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ns_window: &NSWindow = unsafe { &*(ns_window_ptr as *const NSWindow) };
|
let ns_window: &NSWindow = unsafe { &*(ns_window_ptr as *const NSWindow) };
|
||||||
|
|
||||||
let close = match ns_window.standardWindowButton(NSWindowButton::CloseButton) {
|
let close = match ns_window.standardWindowButton(NSWindowButton::CloseButton) {
|
||||||
Some(btn) => btn,
|
Some(button) => button,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let miniaturize = match ns_window.standardWindowButton(NSWindowButton::MiniaturizeButton) {
|
let miniaturize = match ns_window.standardWindowButton(NSWindowButton::MiniaturizeButton) {
|
||||||
Some(btn) => btn,
|
Some(button) => button,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let zoom = match ns_window.standardWindowButton(NSWindowButton::ZoomButton) {
|
let zoom = match ns_window.standardWindowButton(NSWindowButton::ZoomButton) {
|
||||||
Some(btn) => btn,
|
Some(button) => button,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let superview = match close.superview() {
|
let window_height = ns_window.frame().size.height;
|
||||||
Some(sv) => sv,
|
if window_height <= 0.0 {
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
let sv_height = NSView::frame(&superview).size.height;
|
|
||||||
let btn_height = NSView::frame(&close).size.height;
|
|
||||||
if sv_height <= 0.0 || btn_height <= 0.0 {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let centered_y = (sv_height - btn_height) / 2.0;
|
|
||||||
|
|
||||||
for btn in [&close, &miniaturize, &zoom] {
|
let close_frame = NSView::frame(&close);
|
||||||
let mut frame = NSView::frame(btn);
|
let button_spacing = NSView::frame(&miniaturize).origin.x - close_frame.origin.x;
|
||||||
frame.origin.y = centered_y;
|
for (index, button) in [&close, &miniaturize, &zoom].into_iter().enumerate() {
|
||||||
btn.setFrameOrigin(frame.origin);
|
let button_superview = match unsafe { button.superview() } {
|
||||||
|
Some(view) => view,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
let mut frame = NSView::frame(button);
|
||||||
|
let top_inset = ((TITLEBAR_HEIGHT - frame.size.height) / 2.0).max(0.0);
|
||||||
|
let mut target = frame.origin;
|
||||||
|
target.y = window_height - top_inset - frame.size.height;
|
||||||
|
frame.origin.y = button_superview.convertPoint_fromView(target, None).y;
|
||||||
|
frame.origin.x = LEFT_INSET + index as f64 * button_spacing;
|
||||||
|
button.setFrameOrigin(frame.origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.3.3",
|
"version": "1.3.4",
|
||||||
"identifier": "com.helixnotes.app",
|
"identifier": "com.helixnotes.app",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../build",
|
"frontendDist": "../build",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"hiddenTitle": true,
|
"hiddenTitle": true,
|
||||||
"trafficLightPosition": {
|
"trafficLightPosition": {
|
||||||
"x": 12,
|
"x": 12,
|
||||||
"y": 12
|
"y": 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -614,25 +614,28 @@
|
|||||||
// Run sidebar and note list refresh in parallel
|
// Run sidebar and note list refresh in parallel
|
||||||
await Promise.all([sidebar?.refresh(), noteList?.refresh()]);
|
await Promise.all([sidebar?.refresh(), noteList?.refresh()]);
|
||||||
|
|
||||||
// Auto-cleanup orphaned attachments in the background
|
// Full-vault attachment scans cause navigation stalls on mobile storage.
|
||||||
setTimeout(async () => {
|
// Mobile users can run the same cleanup explicitly from the Info panel.
|
||||||
if (get(editorDirty)) return; // skip if user is actively editing
|
if (!isMobile) {
|
||||||
try {
|
setTimeout(async () => {
|
||||||
const orphans = await findOrphanedAttachments();
|
if (get(editorDirty)) return; // skip if user is actively editing
|
||||||
if (orphans.length > 0) {
|
try {
|
||||||
if (get(editorDirty)) return; // re-check after async scan
|
const orphans = await findOrphanedAttachments();
|
||||||
const moved = await trashOrphanedAttachments(orphans.map((o) => o.name));
|
if (orphans.length > 0) {
|
||||||
if (moved > 0) {
|
if (get(editorDirty)) return; // re-check after async scan
|
||||||
const toast = document.createElement('div');
|
const moved = await trashOrphanedAttachments(orphans.map((o) => o.name));
|
||||||
toast.style.cssText = 'position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--bg-secondary);color:var(--text-primary);padding:10px 18px;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15);border:1px solid var(--border-color);font-size:13px;z-index:10000;opacity:0;transition:opacity .3s;pointer-events:none';
|
if (moved > 0) {
|
||||||
toast.textContent = `Moved ${moved} orphaned attachment${moved > 1 ? 's' : ''} to trash`;
|
const toast = document.createElement('div');
|
||||||
document.body.appendChild(toast);
|
toast.style.cssText = 'position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--bg-secondary);color:var(--text-primary);padding:10px 18px;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15);border:1px solid var(--border-color);font-size:13px;z-index:10000;opacity:0;transition:opacity .3s;pointer-events:none';
|
||||||
requestAnimationFrame(() => (toast.style.opacity = '1'));
|
toast.textContent = `Moved ${moved} orphaned attachment${moved > 1 ? 's' : ''} to trash`;
|
||||||
setTimeout(() => { toast.style.opacity = '0'; setTimeout(() => toast.remove(), 300); }, 4000);
|
document.body.appendChild(toast);
|
||||||
|
requestAnimationFrame(() => (toast.style.opacity = '1'));
|
||||||
|
setTimeout(() => { toast.style.opacity = '0'; setTimeout(() => toast.remove(), 300); }, 4000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (_) {}
|
||||||
} catch (_) {}
|
}, 3000);
|
||||||
}, 3000);
|
}
|
||||||
|
|
||||||
// Restore the last session (view + open note) if enabled.
|
// Restore the last session (view + open note) if enabled.
|
||||||
if ($appConfig?.restore_last_session) {
|
if ($appConfig?.restore_last_session) {
|
||||||
|
|||||||
@@ -1112,7 +1112,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="list-content" bind:this={listContainer} onscroll={onListScroll} ondblclick={handleListDoubleClick}>
|
<div class="list-content" class:tasks-mode={$viewMode === 'tasks'} bind:this={listContainer} onscroll={onListScroll} ondblclick={handleListDoubleClick}>
|
||||||
{#if $viewMode === 'tasks'}
|
{#if $viewMode === 'tasks'}
|
||||||
<TasksView onOpenTask={openTask} onToggleTask={onToggleTask} onSetTaskPriority={onSetTaskPriority} onSetTaskDue={onSetTaskDue} />
|
<TasksView onOpenTask={openTask} onToggleTask={onToggleTask} onSetTaskPriority={onSetTaskPriority} onSetTaskDue={onSetTaskDue} />
|
||||||
{/if}
|
{/if}
|
||||||
@@ -2213,6 +2213,11 @@
|
|||||||
padding: 4px 8px 180px;
|
padding: 4px 8px 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note-list.mobile .list-content.tasks-mode {
|
||||||
|
padding-bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.note-list.mobile .note-item {
|
.note-list.mobile .note-item {
|
||||||
padding: 14px 16px;
|
padding: 14px 16px;
|
||||||
min-height: 56px;
|
min-height: 56px;
|
||||||
|
|||||||
@@ -807,6 +807,7 @@
|
|||||||
class="notebook-item"
|
class="notebook-item"
|
||||||
class:active={$viewMode === 'notebook' && $activeNotebook?.relative_path === ''}
|
class:active={$viewMode === 'notebook' && $activeNotebook?.relative_path === ''}
|
||||||
onclick={selectUnfiled}
|
onclick={selectUnfiled}
|
||||||
|
style="padding-left: 4px"
|
||||||
>
|
>
|
||||||
<span style="width:14px;flex-shrink:0"></span>
|
<span style="width:14px;flex-shrink:0"></span>
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0;opacity:0.6">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0;opacity:0.6">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import { getAppConfig, openVault, restoreExternalVault, setFontSize } from '$lib/api';
|
import { getAppConfig, openVault, restoreExternalVault, setFontSize } from '$lib/api';
|
||||||
import { darkThemes, isIOS } from '$lib/platform';
|
import { darkThemes, isIOS } from '$lib/platform';
|
||||||
import { getCurrentWebview } from '@tauri-apps/api/webview';
|
import { getCurrentWebview } from '@tauri-apps/api/webview';
|
||||||
|
import { listen } from '@tauri-apps/api/event';
|
||||||
import VaultPicker from '$lib/components/VaultPicker.svelte';
|
import VaultPicker from '$lib/components/VaultPicker.svelte';
|
||||||
import AppLayout from '$lib/components/AppLayout.svelte';
|
import AppLayout from '$lib/components/AppLayout.svelte';
|
||||||
import NoteWindow from '$lib/components/NoteWindow.svelte';
|
import NoteWindow from '$lib/components/NoteWindow.svelte';
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
let startupVaultError = $state('');
|
let startupVaultError = $state('');
|
||||||
let fontSizeSaveTimer: ReturnType<typeof setTimeout> | null = null;
|
let fontSizeSaveTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
let removeEditorZoomShortcuts: (() => void) | null = null;
|
let removeEditorZoomShortcuts: (() => void) | null = null;
|
||||||
|
let removeFontSizeListener: (() => void) | null = null;
|
||||||
|
|
||||||
const defaultEditorFontSize = 14;
|
const defaultEditorFontSize = 14;
|
||||||
const minEditorFontSize = 10;
|
const minEditorFontSize = 10;
|
||||||
@@ -56,12 +58,17 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setEditorFontSize(value: number) {
|
function applyEditorFontSize(value: number) {
|
||||||
const nextSize = Math.max(minEditorFontSize, Math.min(maxEditorFontSize, Math.round(value)));
|
const nextSize = Math.max(minEditorFontSize, Math.min(maxEditorFontSize, Math.round(value)));
|
||||||
const restoreEditorViewport = preserveEditorViewportAfterLayout(getEditorScrollSurface());
|
const restoreEditorViewport = preserveEditorViewportAfterLayout(getEditorScrollSurface());
|
||||||
if ($appConfig) $appConfig.font_size = nextSize;
|
if ($appConfig) $appConfig.font_size = nextSize;
|
||||||
document.documentElement.style.setProperty('--editor-font-size', `${nextSize}px`);
|
document.documentElement.style.setProperty('--editor-font-size', `${nextSize}px`);
|
||||||
restoreEditorViewport();
|
restoreEditorViewport();
|
||||||
|
return nextSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setEditorFontSize(value: number) {
|
||||||
|
const nextSize = applyEditorFontSize(value);
|
||||||
if (fontSizeSaveTimer) clearTimeout(fontSizeSaveTimer);
|
if (fontSizeSaveTimer) clearTimeout(fontSizeSaveTimer);
|
||||||
fontSizeSaveTimer = setTimeout(() => {
|
fontSizeSaveTimer = setTimeout(() => {
|
||||||
setFontSize(nextSize).catch((e) => console.error('Failed to save font size:', e));
|
setFontSize(nextSize).catch((e) => console.error('Failed to save font size:', e));
|
||||||
@@ -117,6 +124,9 @@
|
|||||||
try {
|
try {
|
||||||
const config = await getAppConfig();
|
const config = await getAppConfig();
|
||||||
$appConfig = config;
|
$appConfig = config;
|
||||||
|
removeFontSizeListener = await listen<number>('editor-font-size-changed', (event) => {
|
||||||
|
if ($appConfig?.font_size !== event.payload) applyEditorFontSize(event.payload);
|
||||||
|
});
|
||||||
$theme = config.theme || 'system';
|
$theme = config.theme || 'system';
|
||||||
|
|
||||||
// Apply theme immediately to prevent flash
|
// Apply theme immediately to prevent flash
|
||||||
@@ -133,9 +143,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply saved font settings
|
// Apply saved font settings
|
||||||
if (config.font_size) {
|
if (config.font_size) applyEditorFontSize(config.font_size);
|
||||||
document.documentElement.style.setProperty('--editor-font-size', `${config.font_size}px`);
|
|
||||||
}
|
|
||||||
if (config.line_height) {
|
if (config.line_height) {
|
||||||
document.documentElement.style.setProperty('--editor-line-height', String(config.line_height));
|
document.documentElement.style.setProperty('--editor-line-height', String(config.line_height));
|
||||||
}
|
}
|
||||||
@@ -193,15 +201,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply saved interface scale (desktop main window only; no-ops gracefully elsewhere)
|
// Apply saved interface scale to every desktop window; no-ops gracefully elsewhere.
|
||||||
if (!noteWindowPath && config.ui_scale && config.ui_scale !== 1) {
|
if (config.ui_scale && config.ui_scale !== 1) {
|
||||||
try {
|
try {
|
||||||
await getCurrentWebview().setZoom(config.ui_scale);
|
await getCurrentWebview().setZoom(config.ui_scale);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to apply interface scale:', e);
|
console.error('Failed to apply interface scale:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!noteWindowPath) removeEditorZoomShortcuts = installEditorZoomShortcuts();
|
removeEditorZoomShortcuts = installEditorZoomShortcuts();
|
||||||
|
|
||||||
// Auto-open last vault if available
|
// Auto-open last vault if available
|
||||||
if (config.active_vault) {
|
if (config.active_vault) {
|
||||||
@@ -240,6 +248,7 @@
|
|||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
removeEditorZoomShortcuts?.();
|
removeEditorZoomShortcuts?.();
|
||||||
|
removeFontSizeListener?.();
|
||||||
if (fontSizeSaveTimer) clearTimeout(fontSizeSaveTimer);
|
if (fontSizeSaveTimer) clearTimeout(fontSizeSaveTimer);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||