Merge pull request #157 from gamosoft/features/readable-line-length

readable line length toggle
This commit is contained in:
Guillermo Villar 2026-01-26 16:48:50 +01:00 committed by GitHub
commit 7df04bf985
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 120 additions and 94 deletions

View File

@ -11,6 +11,22 @@ const CONFIG = {
DEFAULT_SIDEBAR_WIDTH: 256, // px - Default sidebar width (w-64 in Tailwind)
};
// localStorage settings configuration - centralized definition of all persisted settings
const LOCAL_SETTINGS = {
// Boolean settings
syntaxHighlightEnabled: { key: 'syntaxHighlightEnabled', type: 'boolean', default: false },
readableLineLength: { key: 'readableLineLength', type: 'boolean', default: true },
favoritesExpanded: { key: 'favoritesExpanded', type: 'boolean', default: true },
tagsExpanded: { key: 'tagsExpanded', type: 'boolean', default: false },
// Number settings with validation
sidebarWidth: { key: 'sidebarWidth', type: 'number', default: CONFIG.DEFAULT_SIDEBAR_WIDTH, min: 200, max: 600 },
editorWidth: { key: 'editorWidth', type: 'number', default: 50, min: 20, max: 80 },
// String settings with validation
viewMode: { key: 'viewMode', type: 'string', default: 'split', valid: ['edit', 'split', 'preview'] },
// JSON settings
favorites: { key: 'noteFavorites', type: 'json', default: [] },
};
// Centralized error handling
const ErrorHandler = {
/**
@ -190,6 +206,9 @@ function noteApp() {
syntaxHighlightEnabled: false,
syntaxHighlightTimeout: null,
// Readable line length (preview max-width)
readableLineLength: true,
// Icon rail / panel state
activePanel: 'files', // 'files', 'search', 'tags', 'settings'
@ -458,13 +477,7 @@ function noteApp() {
await this.loadSharedNotePaths();
await this.loadTemplates();
await this.checkStatsPlugin();
this.loadSidebarWidth();
this.loadEditorWidth();
this.loadViewMode();
this.loadTagsExpanded();
this.loadFavorites();
this.loadFavoritesExpanded();
this.loadSyntaxHighlightSetting();
this.loadLocalSettings();
// Parse URL and load specific note if provided
this.loadItemFromURL();
@ -745,13 +758,51 @@ function noteApp() {
}
},
loadSyntaxHighlightSetting() {
try {
const saved = localStorage.getItem('syntaxHighlightEnabled');
this.syntaxHighlightEnabled = saved === 'true';
} catch (error) {
console.error('Error loading syntax highlight setting:', error);
// Load all localStorage settings at once using centralized config
loadLocalSettings() {
for (const [prop, config] of Object.entries(LOCAL_SETTINGS)) {
try {
const saved = localStorage.getItem(config.key);
if (saved === null) {
// Use default value if not set
this[prop] = config.default;
} else if (config.type === 'boolean') {
this[prop] = saved === 'true';
} else if (config.type === 'number') {
const num = parseFloat(saved);
// Validate range if specified
if (!isNaN(num) &&
(config.min === undefined || num >= config.min) &&
(config.max === undefined || num <= config.max)) {
this[prop] = num;
} else {
this[prop] = config.default;
}
} else if (config.type === 'string') {
// Validate against allowed values if specified
if (!config.valid || config.valid.includes(saved)) {
this[prop] = saved;
} else {
this[prop] = config.default;
}
} else if (config.type === 'json') {
this[prop] = JSON.parse(saved);
}
} catch (error) {
console.error(`Error loading setting ${prop}:`, error);
this[prop] = config.default;
}
}
// Special case: favorites also needs to update the Set for O(1) lookups
this.favoritesSet = new Set(this.favorites);
},
// Readable line length toggle (for preview max-width)
toggleReadableLineLength() {
this.readableLineLength = !this.readableLineLength;
localStorage.setItem('readableLineLength', this.readableLineLength);
},
// Update syntax highlight overlay (debounced, called on input)
@ -1439,20 +1490,6 @@ function noteApp() {
// ==================== FAVORITES ====================
// Load favorites from localStorage
loadFavorites() {
try {
const stored = localStorage.getItem('noteFavorites');
if (stored) {
this.favorites = JSON.parse(stored);
this.favoritesSet = new Set(this.favorites);
}
} catch (e) {
this.favorites = [];
this.favoritesSet = new Set();
}
},
// Save favorites to localStorage
saveFavorites() {
try {
@ -1503,17 +1540,6 @@ function noteApp() {
.filter(Boolean); // Remove nulls (deleted notes)
},
loadFavoritesExpanded() {
try {
const saved = localStorage.getItem('favoritesExpanded');
if (saved !== null) {
this.favoritesExpanded = saved === 'true';
}
} catch (e) {
console.error('Error loading favorites expanded state:', e);
}
},
saveFavoritesExpanded() {
try {
localStorage.setItem('favoritesExpanded', this.favoritesExpanded.toString());
@ -4770,34 +4796,11 @@ function noteApp() {
return Array.isArray(this.noteMetadata.tags) ? this.noteMetadata.tags : [this.noteMetadata.tags];
},
// Load sidebar width from localStorage
loadSidebarWidth() {
const saved = localStorage.getItem('sidebarWidth');
if (saved) {
const width = parseInt(saved, 10);
if (width >= 200 && width <= 600) {
this.sidebarWidth = width;
}
}
},
// Save sidebar width to localStorage
saveSidebarWidth() {
localStorage.setItem('sidebarWidth', this.sidebarWidth.toString());
},
// Load view mode from localStorage
loadViewMode() {
try {
const saved = localStorage.getItem('viewMode');
if (saved && ['edit', 'split', 'preview'].includes(saved)) {
this.viewMode = saved;
}
} catch (error) {
console.error('Error loading view mode:', error);
}
},
// Save view mode to localStorage
saveViewMode() {
try {
@ -4807,17 +4810,6 @@ function noteApp() {
}
},
loadTagsExpanded() {
try {
const saved = localStorage.getItem('tagsExpanded');
if (saved !== null) {
this.tagsExpanded = saved === 'true';
}
} catch (error) {
console.error('Error loading tags expanded state:', error);
}
},
saveTagsExpanded() {
try {
localStorage.setItem('tagsExpanded', this.tagsExpanded.toString());
@ -4916,17 +4908,6 @@ function noteApp() {
}
},
// Load editor width from localStorage
loadEditorWidth() {
const saved = localStorage.getItem('editorWidth');
if (saved) {
const width = parseFloat(saved);
if (width >= 20 && width <= 80) {
this.editorWidth = width;
}
}
},
// Save editor width to localStorage
saveEditorWidth() {
localStorage.setItem('editorWidth', this.editorWidth.toString());

View File

@ -170,6 +170,13 @@
font-size: 16px;
}
/* Readable line length - constrain text width for better readability */
.markdown-preview.readable-width {
max-width: 750px;
margin-left: auto;
margin-right: auto;
}
/* Remove top margin from first element */
.markdown-preview > *:first-child {
margin-top: 0 !important;
@ -1829,6 +1836,24 @@
<p class="text-xs mt-1" style="color: var(--text-tertiary);" x-text="t('syntax_highlight.description')"></p>
</div>
<!-- Readable Line Length Toggle -->
<div class="mb-4">
<label class="flex items-center justify-between cursor-pointer">
<span class="text-xs font-medium" style="color: var(--text-secondary);" x-text="t('settings.readable_line_length')"></span>
<div
@click="toggleReadableLineLength()"
class="relative w-10 h-5 rounded-full transition-colors cursor-pointer"
:style="readableLineLength ? 'background-color: var(--accent-primary)' : 'background-color: var(--bg-tertiary)'"
>
<div
class="absolute top-0.5 left-0.5 w-4 h-4 rounded-full transition-transform"
:style="'background-color: var(--bg-primary);' + (readableLineLength ? ' transform: translateX(20px);' : '')"
></div>
</div>
</label>
<p class="text-xs mt-1" style="color: var(--text-tertiary);" x-text="t('settings.readable_line_length_desc')"></p>
</div>
<!-- Logout (if auth enabled) - uses authEnabled from main app state -->
<div x-show="authEnabled" class="mb-4">
<label class="block text-xs font-medium mb-2" style="color: var(--text-secondary);" x-text="t('settings.account')"></label>
@ -2576,7 +2601,7 @@
<div
class="p-6 markdown-preview"
:class="{ 'pt-2': getHasMetadata() && currentNote }"
:class="{ 'pt-2': getHasMetadata() && currentNote, 'readable-width': readableLineLength }"
x-html="renderedMarkdown"
@click="handleInternalLink($event)"
></div>

View File

@ -235,7 +235,9 @@
"settings": {
"account": "Konto",
"logout": "Abmelden"
"logout": "Abmelden",
"readable_line_length": "Lesbare Zeilenlänge",
"readable_line_length_desc": "Vorschaubreite für bessere Lesbarkeit begrenzen"
},
"homepage": {

View File

@ -234,7 +234,9 @@
"settings": {
"account": "Account",
"logout": "Logout"
"logout": "Logout",
"readable_line_length": "Readable line length",
"readable_line_length_desc": "Limit preview width for easier reading"
},
"homepage": {

View File

@ -235,7 +235,9 @@
"settings": {
"account": "Account",
"logout": "Logout"
"logout": "Logout",
"readable_line_length": "Readable line length",
"readable_line_length_desc": "Limit preview width for easier reading"
},
"homepage": {

View File

@ -235,7 +235,9 @@
"settings": {
"account": "Cuenta",
"logout": "Cerrar sesión"
"logout": "Cerrar sesión",
"readable_line_length": "Longitud de línea legible",
"readable_line_length_desc": "Limitar el ancho de vista previa para facilitar la lectura"
},
"homepage": {

View File

@ -235,7 +235,9 @@
"settings": {
"account": "Compte",
"logout": "Déconnexion"
"logout": "Déconnexion",
"readable_line_length": "Longueur de ligne lisible",
"readable_line_length_desc": "Limiter la largeur de l'aperçu pour une lecture plus facile"
},
"homepage": {

View File

@ -234,7 +234,9 @@
"settings": {
"account": "Account",
"logout": "Esci"
"logout": "Esci",
"readable_line_length": "Larghezza riga leggibile",
"readable_line_length_desc": "Limita la larghezza dell'anteprima per una lettura più facile"
},
"homepage": {

View File

@ -234,7 +234,9 @@
"settings": {
"account": "アカウント",
"logout": "ログアウト"
"logout": "ログアウト",
"readable_line_length": "読みやすい行幅",
"readable_line_length_desc": "プレビューの幅を制限して読みやすくする"
},
"homepage": {

View File

@ -234,7 +234,9 @@
"settings": {
"account": "Аккаунт",
"logout": "Выйти"
"logout": "Выйти",
"readable_line_length": "Удобная длина строки",
"readable_line_length_desc": "Ограничить ширину предпросмотра для удобства чтения"
},
"homepage": {

View File

@ -234,7 +234,9 @@
"settings": {
"account": "Račun",
"logout": "Odjava"
"logout": "Odjava",
"readable_line_length": "Berljiva dolžina vrstice",
"readable_line_length_desc": "Omejite širino predogleda za lažje branje"
},
"homepage": {

View File

@ -234,7 +234,9 @@
"settings": {
"account": "账户",
"logout": "登出"
"logout": "登出",
"readable_line_length": "可读行宽",
"readable_line_length_desc": "限制预览宽度以便于阅读"
},
"homepage": {