mirror of
https://gitlab.com/ArkHost/HelixNotes.git
synced 2026-07-23 23:35:57 +02:00
Add Note Width setting to cap editor content width (#137)
This commit is contained in:
@@ -122,6 +122,14 @@ pub fn set_ui_scale(state: State<'_, AppState>, scale: f64) -> Result<(), String
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn set_content_width(state: State<'_, AppState>, width: Option<u32>) -> Result<(), String> {
|
||||
let mut config = state.config.lock().map_err(|e| e.to_string())?;
|
||||
config.content_width = width;
|
||||
save_app_config(&config)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ── Notebooks ──
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@@ -106,6 +106,7 @@ pub fn run() {
|
||||
commands::set_font_family,
|
||||
commands::set_line_height,
|
||||
commands::set_ui_scale,
|
||||
commands::set_content_width,
|
||||
commands::get_notebooks,
|
||||
commands::count_root_notes,
|
||||
commands::create_notebook,
|
||||
|
||||
@@ -72,6 +72,8 @@ pub struct AppConfig {
|
||||
#[serde(default)]
|
||||
pub ui_scale: Option<f64>,
|
||||
#[serde(default)]
|
||||
pub content_width: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub compact_notes: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub show_note_dates: bool,
|
||||
@@ -205,6 +207,7 @@ impl Default for AppConfig {
|
||||
font_family: None,
|
||||
line_height: None,
|
||||
ui_scale: None,
|
||||
content_width: None,
|
||||
compact_notes: false,
|
||||
show_note_dates: true,
|
||||
time_format: "relative".to_string(),
|
||||
|
||||
@@ -52,6 +52,10 @@ export async function setUiScale(scale: number): Promise<void> {
|
||||
return invoke("set_ui_scale", { scale });
|
||||
}
|
||||
|
||||
export async function setContentWidth(width: number | null): Promise<void> {
|
||||
return invoke("set_content_width", { width });
|
||||
}
|
||||
|
||||
export async function getNotebooks(): Promise<NotebookEntry[]> {
|
||||
return invoke("get_notebooks");
|
||||
}
|
||||
|
||||
@@ -7433,7 +7433,8 @@
|
||||
resize: none;
|
||||
outline: none;
|
||||
padding: 0 0 var(--editor-scroll-past-end, 65vh);
|
||||
margin: 0;
|
||||
margin: 0 auto;
|
||||
max-width: var(--editor-content-width, none);
|
||||
user-select: text;
|
||||
/* Wrap long lines instead of horizontal-scrolling (matches mobile). (issue #100) */
|
||||
white-space: pre-wrap;
|
||||
@@ -7447,6 +7448,9 @@
|
||||
Keep no-wrap (horizontal scroll) whenever line numbers are on. (issue #100) */
|
||||
white-space: pre;
|
||||
overflow-x: auto;
|
||||
/* The line-number gutter is pinned to the left edge, so don't center/cap here. (#137) */
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.line-numbers-clip {
|
||||
@@ -7479,6 +7483,12 @@
|
||||
.tiptap-wrapper {
|
||||
height: 100%;
|
||||
user-select: text;
|
||||
/* Optional reading-width cap (Settings > Styling > Note Width). Default `none` = full
|
||||
width; when set, the text column is capped and centered. Scrollbar stays at the
|
||||
panel edge because only the inner content is constrained, not .editor-body. (#137) */
|
||||
max-width: var(--editor-content-width, none);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
:global(.tiptap-wrapper .tiptap) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { showSettings, theme, appConfig, updateAvailable as globalUpdateAvailable, updateObj as globalUpdateObj, installType, settingsTab, vaultReady, androidApkUrl, checkForUpdateMobile, notebookSortMode, isManagedInstall } from '$lib/stores/app';
|
||||
import { setTheme, setAccentColor, setFontSize, setFontFamily, setLineHeight, setUiScale, setGeneralSettings, importObsidian, createBackup, listBackups, restoreBackup, deleteBackup, setBackupSettings, setAiSettings, testAiConnection, setSyncSettings, testSyncConnection, syncNow } from '$lib/api';
|
||||
import { setTheme, setAccentColor, setFontSize, setFontFamily, setLineHeight, setUiScale, setContentWidth, setGeneralSettings, importObsidian, createBackup, listBackups, restoreBackup, deleteBackup, setBackupSettings, setAiSettings, testAiConnection, setSyncSettings, testSyncConnection, syncNow } from '$lib/api';
|
||||
import { darkThemes } from '$lib/platform';
|
||||
import { open as openDialog } from '@tauri-apps/plugin-dialog';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
@@ -477,12 +477,20 @@
|
||||
{ label: '200%', value: 2 },
|
||||
];
|
||||
|
||||
const contentWidthPresets: { label: string; value: number | null }[] = [
|
||||
{ label: 'Narrow', value: 600 },
|
||||
{ label: 'Medium', value: 760 },
|
||||
{ label: 'Wide', value: 960 },
|
||||
{ label: 'Full', value: null },
|
||||
];
|
||||
|
||||
let activeAccent = $state($appConfig?.accent_color ?? 'Indigo');
|
||||
let customAccentColor = $state(($appConfig?.accent_color?.startsWith('#') ? $appConfig.accent_color : null) ?? '#5b6abf');
|
||||
let activeFontSize = $state($appConfig?.font_size ?? 14);
|
||||
let activeFontFamily = $state($appConfig?.font_family ?? 'system');
|
||||
let activeLineHeight = $state($appConfig?.line_height ?? 1.6);
|
||||
let activeUiScale = $state($appConfig?.ui_scale ?? 1);
|
||||
let activeContentWidth = $state<number | null>($appConfig?.content_width ?? null);
|
||||
let themeDropdownOpen = $state(false);
|
||||
let accentDropdownOpen = $state(false);
|
||||
let activeThemePreset = $derived(themePresets.find(p => p.id === $theme) ?? themePresets[0]);
|
||||
@@ -681,6 +689,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
function selectContentWidth(value: number | null) {
|
||||
activeContentWidth = value;
|
||||
applyContentWidth(value);
|
||||
if ($appConfig) $appConfig.content_width = value;
|
||||
setContentWidth(value).catch((e) => console.error('Failed to save content width:', e));
|
||||
}
|
||||
|
||||
function applyContentWidth(value: number | null) {
|
||||
document.documentElement.style.setProperty('--editor-content-width', value ? `${value}px` : 'none');
|
||||
}
|
||||
|
||||
function clickOutside(node: HTMLElement, callback: () => void) {
|
||||
function handle(e: MouseEvent) {
|
||||
if (!node.contains(e.target as Node)) callback();
|
||||
@@ -732,6 +751,11 @@
|
||||
activeLineHeight = savedLineHeight;
|
||||
applyLineHeight(savedLineHeight);
|
||||
}
|
||||
const savedContentWidth = $appConfig?.content_width;
|
||||
if (savedContentWidth) {
|
||||
activeContentWidth = savedContentWidth;
|
||||
applyContentWidth(savedContentWidth);
|
||||
}
|
||||
// Sync general settings
|
||||
if ($appConfig) {
|
||||
compactNotes = $appConfig.compact_notes ?? false;
|
||||
@@ -1185,6 +1209,24 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !isMobile}
|
||||
<div class="settings-section">
|
||||
<h3>Note Width</h3>
|
||||
<div class="font-size-options">
|
||||
{#each contentWidthPresets as preset}
|
||||
<button
|
||||
class="font-size-btn"
|
||||
class:active={activeContentWidth === preset.value}
|
||||
onclick={() => selectContentWidth(preset.value)}
|
||||
>
|
||||
<span class="font-size-label">{preset.label}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<p class="setting-hint">Caps the width of the note text for easier reading on wide screens; the column stays centered. Most noticeable in Focus Mode. "Full" uses the entire width.</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="settings-section">
|
||||
<h3>Line Height</h3>
|
||||
<div class="font-size-options">
|
||||
|
||||
@@ -55,6 +55,7 @@ export interface AppConfig {
|
||||
font_family: string | null;
|
||||
line_height: number | null;
|
||||
ui_scale: number | null;
|
||||
content_width: number | null;
|
||||
compact_notes: boolean;
|
||||
show_note_dates: boolean;
|
||||
time_format: string;
|
||||
|
||||
@@ -138,6 +138,9 @@
|
||||
if (config.line_height) {
|
||||
document.documentElement.style.setProperty('--editor-line-height', String(config.line_height));
|
||||
}
|
||||
if (config.content_width) {
|
||||
document.documentElement.style.setProperty('--editor-content-width', `${config.content_width}px`);
|
||||
}
|
||||
if (config.font_family) {
|
||||
const fontStacks: Record<string, string> = {
|
||||
system: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
|
||||
Reference in New Issue
Block a user