Add Interface Scale setting to zoom the whole app (80-200%)

This commit is contained in:
Yuri Karamian
2026-06-04 19:27:00 +02:00
parent 4b82d51f6c
commit 139ecc8176
8 changed files with 75 additions and 2 deletions
+2 -1
View File
@@ -6,6 +6,7 @@
"windows": ["main"], "windows": ["main"],
"permissions": [ "permissions": [
"updater:default", "updater:default",
"window-state:default" "window-state:default",
"core:webview:allow-set-webview-zoom"
] ]
} }
+8
View File
@@ -103,6 +103,14 @@ pub fn set_line_height(state: State<'_, AppState>, height: f64) -> Result<(), St
Ok(()) Ok(())
} }
#[tauri::command]
pub fn set_ui_scale(state: State<'_, AppState>, scale: f64) -> Result<(), String> {
let mut config = state.config.lock().map_err(|e| e.to_string())?;
config.ui_scale = Some(scale);
save_app_config(&config)?;
Ok(())
}
// ── Notebooks ── // ── Notebooks ──
#[tauri::command] #[tauri::command]
+1
View File
@@ -103,6 +103,7 @@ pub fn run() {
commands::set_font_size, commands::set_font_size,
commands::set_font_family, commands::set_font_family,
commands::set_line_height, commands::set_line_height,
commands::set_ui_scale,
commands::get_notebooks, commands::get_notebooks,
commands::count_root_notes, commands::count_root_notes,
commands::create_notebook, commands::create_notebook,
+3
View File
@@ -70,6 +70,8 @@ pub struct AppConfig {
#[serde(default)] #[serde(default)]
pub line_height: Option<f64>, pub line_height: Option<f64>,
#[serde(default)] #[serde(default)]
pub ui_scale: Option<f64>,
#[serde(default)]
pub compact_notes: bool, pub compact_notes: bool,
#[serde(default)] #[serde(default)]
pub time_format: String, pub time_format: String,
@@ -167,6 +169,7 @@ impl Default for AppConfig {
font_size: None, font_size: None,
font_family: None, font_family: None,
line_height: None, line_height: None,
ui_scale: None,
compact_notes: false, compact_notes: false,
time_format: "relative".to_string(), time_format: "relative".to_string(),
gpu_acceleration: true, gpu_acceleration: true,
+4
View File
@@ -43,6 +43,10 @@ export async function setLineHeight(height: number): Promise<void> {
return invoke("set_line_height", { height }); return invoke("set_line_height", { height });
} }
export async function setUiScale(scale: number): Promise<void> {
return invoke("set_ui_scale", { scale });
}
export async function getNotebooks(): Promise<NotebookEntry[]> { export async function getNotebooks(): Promise<NotebookEntry[]> {
return invoke("get_notebooks"); return invoke("get_notebooks");
} }
+46 -1
View File
@@ -1,9 +1,10 @@
<script lang="ts"> <script lang="ts">
import { showSettings, theme, appConfig, updateAvailable as globalUpdateAvailable, updateObj as globalUpdateObj, installType, settingsTab, vaultReady, androidApkUrl, checkForUpdateMobile, notebookSortMode } from '$lib/stores/app'; import { showSettings, theme, appConfig, updateAvailable as globalUpdateAvailable, updateObj as globalUpdateObj, installType, settingsTab, vaultReady, androidApkUrl, checkForUpdateMobile, notebookSortMode } from '$lib/stores/app';
import { setTheme, setAccentColor, setFontSize, setFontFamily, setLineHeight, setGeneralSettings, importObsidian, createBackup, listBackups, restoreBackup, deleteBackup, setBackupSettings, setAiSettings, testAiConnection } from '$lib/api'; import { setTheme, setAccentColor, setFontSize, setFontFamily, setLineHeight, setUiScale, setGeneralSettings, importObsidian, createBackup, listBackups, restoreBackup, deleteBackup, setBackupSettings, setAiSettings, testAiConnection } from '$lib/api';
import { open as openDialog } from '@tauri-apps/plugin-dialog'; import { open as openDialog } from '@tauri-apps/plugin-dialog';
import { listen } from '@tauri-apps/api/event'; import { listen } from '@tauri-apps/api/event';
import { getVersion } from '@tauri-apps/api/app'; import { getVersion } from '@tauri-apps/api/app';
import { getCurrentWebview } from '@tauri-apps/api/webview';
import { openUrl } from '$lib/api'; import { openUrl } from '$lib/api';
import type { ImportResult, BackupEntry } from '$lib/types'; import type { ImportResult, BackupEntry } from '$lib/types';
@@ -336,10 +337,21 @@
{ label: 'Loose', value: 2.0 }, { label: 'Loose', value: 2.0 },
]; ];
const uiScalePresets = [
{ label: '80%', value: 0.8 },
{ label: '90%', value: 0.9 },
{ label: '100%', value: 1 },
{ label: '125%', value: 1.25 },
{ label: '150%', value: 1.5 },
{ label: '175%', value: 1.75 },
{ label: '200%', value: 2 },
];
let activeAccent = $state($appConfig?.accent_color ?? 'Indigo'); let activeAccent = $state($appConfig?.accent_color ?? 'Indigo');
let activeFontSize = $state($appConfig?.font_size ?? 14); let activeFontSize = $state($appConfig?.font_size ?? 14);
let activeFontFamily = $state($appConfig?.font_family ?? 'system'); let activeFontFamily = $state($appConfig?.font_family ?? 'system');
let activeLineHeight = $state($appConfig?.line_height ?? 1.6); let activeLineHeight = $state($appConfig?.line_height ?? 1.6);
let activeUiScale = $state($appConfig?.ui_scale ?? 1);
// General settings // General settings
let compactNotes = $state($appConfig?.compact_notes ?? false); let compactNotes = $state($appConfig?.compact_notes ?? false);
@@ -477,6 +489,21 @@
document.documentElement.style.setProperty('--editor-line-height', String(value)); document.documentElement.style.setProperty('--editor-line-height', String(value));
} }
function selectUiScale(value: number) {
activeUiScale = value;
applyUiScale(value);
if ($appConfig) $appConfig.ui_scale = value;
setUiScale(value).catch((e) => console.error('Failed to save interface scale:', e));
}
async function applyUiScale(value: number) {
try {
await getCurrentWebview().setZoom(value);
} catch (e) {
console.error('Failed to apply interface scale:', e);
}
}
function close() { function close() {
// Ensure AI settings are saved when closing (in case input wasn't blurred) // Ensure AI settings are saved when closing (in case input wasn't blurred)
// Only save if the key differs from what's already stored // Only save if the key differs from what's already stored
@@ -846,6 +873,24 @@
</div> </div>
</div> </div>
{#if !isMobile}
<div class="settings-section">
<h3>Interface Scale</h3>
<div class="font-size-options">
{#each uiScalePresets as preset}
<button
class="font-size-btn"
class:active={activeUiScale === preset.value}
onclick={() => selectUiScale(preset.value)}
>
<span class="font-size-label">{preset.label}</span>
</button>
{/each}
</div>
<p class="setting-hint">Zooms the whole app: every panel, menu, and the editor. Use Default (100%) to reset.</p>
</div>
{/if}
<div class="settings-section"> <div class="settings-section">
<h3>Line Height</h3> <h3>Line Height</h3>
<div class="font-size-options"> <div class="font-size-options">
+1
View File
@@ -54,6 +54,7 @@ export interface AppConfig {
font_size: number | null; font_size: number | null;
font_family: string | null; font_family: string | null;
line_height: number | null; line_height: number | null;
ui_scale: number | null;
compact_notes: boolean; compact_notes: boolean;
time_format: string; time_format: string;
gpu_acceleration: boolean; gpu_acceleration: boolean;
+10
View File
@@ -2,6 +2,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { appConfig, vaultReady, theme } from '$lib/stores/app'; import { appConfig, vaultReady, theme } from '$lib/stores/app';
import { getAppConfig, openVault } from '$lib/api'; import { getAppConfig, openVault } from '$lib/api';
import { getCurrentWebview } from '@tauri-apps/api/webview';
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';
@@ -78,6 +79,15 @@
} }
} }
// Apply saved interface scale (desktop main window only; no-ops gracefully elsewhere)
if (!noteWindowPath && config.ui_scale && config.ui_scale !== 1) {
try {
await getCurrentWebview().setZoom(config.ui_scale);
} catch (e) {
console.error('Failed to apply interface scale:', e);
}
}
// Auto-open last vault if available // Auto-open last vault if available
if (config.active_vault) { if (config.active_vault) {
try { try {