Merge pull request 'Cleanup in js' (#18) from cleanup_in_js into master

Reviewed-on: #18
This commit was merged in pull request #18.
This commit is contained in:
gru
2026-06-03 23:33:51 +02:00
10 changed files with 136 additions and 53 deletions
+2
View File
@@ -58,6 +58,7 @@ CREATE TABLE IF NOT EXISTS user_preferences (
keyboard_json TEXT,
mobile_mode INTEGER DEFAULT 0,
compact_torrent_list_enabled INTEGER DEFAULT 0,
torrent_list_font_size INTEGER DEFAULT 13,
footer_items_json TEXT,
title_speed_enabled INTEGER DEFAULT 0,
automation_toasts_enabled INTEGER DEFAULT 1,
@@ -529,6 +530,7 @@ MIGRATIONS = [
"ALTER TABLE users ADD COLUMN updated_at TEXT",
"ALTER TABLE user_preferences ADD COLUMN mobile_mode INTEGER DEFAULT 0",
"ALTER TABLE user_preferences ADD COLUMN compact_torrent_list_enabled INTEGER DEFAULT 0",
"ALTER TABLE user_preferences ADD COLUMN torrent_list_font_size INTEGER DEFAULT 13",
"ALTER TABLE user_preferences ADD COLUMN bootstrap_theme TEXT DEFAULT 'default'",
"ALTER TABLE user_preferences ADD COLUMN font_family TEXT DEFAULT 'default'",
"ALTER TABLE user_preferences ADD COLUMN footer_items_json TEXT",
+10
View File
@@ -472,6 +472,7 @@ def save_preferences(data: dict, user_id: int | None = None):
disk_monitor_stop_enabled = data.get("disk_monitor_stop_enabled")
disk_monitor_stop_threshold = data.get("disk_monitor_stop_threshold")
interface_scale = data.get("interface_scale")
torrent_list_font_size = data.get("torrent_list_font_size")
compact_torrent_list_enabled = data.get("compact_torrent_list_enabled")
detail_panel_height = data.get("detail_panel_height")
disk_payload = None
@@ -510,6 +511,15 @@ def save_preferences(data: dict, user_id: int | None = None):
if scale < 80: scale = 80
if scale > 140: scale = 140
conn.execute("UPDATE user_preferences SET interface_scale=?, updated_at=? WHERE user_id=?", (scale, now, user_id))
if torrent_list_font_size is not None:
# Note: Torrent list font size is clamped so dense rows cannot break the virtualized list layout.
try:
list_font_size = int(torrent_list_font_size or 13)
except (TypeError, ValueError):
list_font_size = 13
if list_font_size < 11: list_font_size = 11
if list_font_size > 16: list_font_size = 16
conn.execute("UPDATE user_preferences SET torrent_list_font_size=?, updated_at=? WHERE user_id=?", (list_font_size, now, user_id))
if compact_torrent_list_enabled is not None:
# Note: Compact torrent list is a visual-only preference for desktop and mobile list density.
conn.execute("UPDATE user_preferences SET compact_torrent_list_enabled=?, updated_at=? WHERE user_id=?", (1 if compact_torrent_list_enabled else 0, now, user_id))
+1 -1
View File
@@ -1 +1 @@
export const appearancePreferencesSource = " function bootstrapThemeUrl(theme){ /* Note: Themes use the URL map generated by the backend, so they also work offline. */ const key=theme||\"default\"; return window.PYTORRENT?.bootstrapThemeUrls?.[key] || window.PYTORRENT?.bootstrapThemeUrls?.default || \"\"; }\n function applyBootstrapTheme(theme){\n // Note: Custom Bootstrap 2-inspired themes are normal selectable themes and keep light/dark compatibility through data-bs-theme.\n bootstrapTheme = theme || \"default\";\n document.documentElement.dataset.bootstrapSkin = bootstrapTheme;\n const link=$(\"bootstrapThemeStylesheet\");\n if(link) link.href = bootstrapThemeUrl(bootstrapTheme);\n if($(\"bootstrapThemeSelect\")) $(\"bootstrapThemeSelect\").value = bootstrapTheme;\n }\n function applyFontFamily(font){ fontFamily = font || \"default\"; document.documentElement.dataset.appFont = fontFamily; if($(\"fontFamilySelect\")) $(\"fontFamilySelect\").value = fontFamily; }\n function clampInterfaceScale(value){ value = Number(value || 100); if(!Number.isFinite(value)) value = 100; return Math.max(80, Math.min(140, Math.round(value / 5) * 5)); }\n function applyInterfaceScale(value){ interfaceScale = clampInterfaceScale(value); document.documentElement.style.setProperty(\"--ui-scale\", String(interfaceScale / 100)); if($(\"interfaceScaleRange\")) $(\"interfaceScaleRange\").value = interfaceScale; if($(\"interfaceScaleValue\")) $(\"interfaceScaleValue\").textContent = `${interfaceScale}%`; scheduleRender(false); }\n function torrentRowHeight(){ return compactTorrentListEnabled ? COMPACT_ROW_HEIGHT : ROW_HEIGHT; }\n function applyCompactTorrentList(value){\n // Note: The compact switch changes density only; filtering, sorting and existing row actions stay unchanged.\n compactTorrentListEnabled = !!value;\n document.body.classList.toggle(\"compact-torrent-list\", compactTorrentListEnabled);\n if($(\"compactTorrentListEnabled\")) $(\"compactTorrentListEnabled\").checked = compactTorrentListEnabled;\n scheduleRender(true);\n }\n async function saveAppearancePreferences(){ applyBootstrapTheme($(\"bootstrapThemeSelect\")?.value || \"default\"); applyFontFamily($(\"fontFamilySelect\")?.value || \"default\"); applyInterfaceScale($(\"interfaceScaleRange\")?.value || interfaceScale); applyCompactTorrentList($(\"compactTorrentListEnabled\")?.checked); try{ await post(\"/api/preferences\",{bootstrap_theme:bootstrapTheme,font_family:fontFamily,interface_scale:interfaceScale,compact_torrent_list_enabled:compactTorrentListEnabled}); toast(\"Appearance preferences saved\",\"success\"); }catch(e){ toast(e.message,\"danger\"); } }\n if($(\"titleSpeedEnabled\")) $(\"titleSpeedEnabled\").checked=titleSpeedEnabled;\n applyBootstrapTheme(bootstrapTheme);\n applyCompactTorrentList(compactTorrentListEnabled);\n";
export const appearancePreferencesSource = " function bootstrapThemeUrl(theme){ /* Note: Themes use the URL map generated by the backend, so they also work offline. */ const key=theme||\"default\"; return window.PYTORRENT?.bootstrapThemeUrls?.[key] || window.PYTORRENT?.bootstrapThemeUrls?.default || \"\"; }\n function applyBootstrapTheme(theme){\n // Note: Custom Bootstrap 2-inspired themes are normal selectable themes and keep light/dark compatibility through data-bs-theme.\n bootstrapTheme = theme || \"default\";\n document.documentElement.dataset.bootstrapSkin = bootstrapTheme;\n const link=$(\"bootstrapThemeStylesheet\");\n if(link) link.href = bootstrapThemeUrl(bootstrapTheme);\n if($(\"bootstrapThemeSelect\")) $(\"bootstrapThemeSelect\").value = bootstrapTheme;\n }\n function applyFontFamily(font){ fontFamily = font || \"default\"; document.documentElement.dataset.appFont = fontFamily; if($(\"fontFamilySelect\")) $(\"fontFamilySelect\").value = fontFamily; }\n function clampInterfaceScale(value){ value = Number(value || 100); if(!Number.isFinite(value)) value = 100; return Math.max(80, Math.min(140, Math.round(value / 5) * 5)); }\n function applyInterfaceScale(value){ interfaceScale = clampInterfaceScale(value); document.documentElement.style.setProperty(\"--ui-scale\", String(interfaceScale / 100)); if($(\"interfaceScaleRange\")) $(\"interfaceScaleRange\").value = interfaceScale; if($(\"interfaceScaleValue\")) $(\"interfaceScaleValue\").textContent = `${interfaceScale}%`; scheduleRender(false); }\n function applyTorrentListFontSize(value){\n // Note: This controls torrent list text only; compact mode stays responsible for row density.\n torrentListFontSize = clampTorrentListFontSize(value);\n document.documentElement.style.setProperty(\"--torrent-list-font-size\", `${torrentListFontSize}px`);\n if($(\"torrentListFontSizeRange\")) $(\"torrentListFontSizeRange\").value = torrentListFontSize;\n if($(\"torrentListFontSizeValue\")) $(\"torrentListFontSizeValue\").textContent = `${torrentListFontSize}px`;\n scheduleRender(false);\n }\n function torrentRowHeight(){ return compactTorrentListEnabled ? COMPACT_ROW_HEIGHT : ROW_HEIGHT; }\n function applyCompactTorrentList(value){\n // Note: The compact switch changes density only; filtering, sorting and existing row actions stay unchanged.\n compactTorrentListEnabled = !!value;\n document.body.classList.toggle(\"compact-torrent-list\", compactTorrentListEnabled);\n if($(\"compactTorrentListEnabled\")) $(\"compactTorrentListEnabled\").checked = compactTorrentListEnabled;\n scheduleRender(true);\n }\n async function saveAppearancePreferences(){ applyBootstrapTheme($(\"bootstrapThemeSelect\")?.value || \"default\"); applyFontFamily($(\"fontFamilySelect\")?.value || \"default\"); applyInterfaceScale($(\"interfaceScaleRange\")?.value || interfaceScale); applyTorrentListFontSize($(\"torrentListFontSizeRange\")?.value || torrentListFontSize); applyCompactTorrentList($(\"compactTorrentListEnabled\")?.checked); try{ await post(\"/api/preferences\",{bootstrap_theme:bootstrapTheme,font_family:fontFamily,interface_scale:interfaceScale,torrent_list_font_size:torrentListFontSize,compact_torrent_list_enabled:compactTorrentListEnabled}); toast(\"Appearance preferences saved\",\"success\"); }catch(e){ toast(e.message,\"danger\"); } }\n if($(\"titleSpeedEnabled\")) $(\"titleSpeedEnabled\").checked=titleSpeedEnabled;\n applyBootstrapTheme(bootstrapTheme);\n applyTorrentListFontSize(torrentListFontSize);\n applyCompactTorrentList(compactTorrentListEnabled);\n";
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
export const preferenceEventsSource = "$('appStatusRefreshBtn')?.addEventListener('click',loadAppStatus); $('portCheckEnabled')?.addEventListener('change',savePortCheckPref); $('portCheckNowBtn')?.addEventListener('click',()=>loadPortCheck(true)); $('bootstrapThemeSelect')?.addEventListener('change',saveAppearancePreferences); $('fontFamilySelect')?.addEventListener('change',saveAppearancePreferences); $('interfaceScaleRange')?.addEventListener('input',e=>applyInterfaceScale(e.target.value)); $('interfaceScaleRange')?.addEventListener('change',saveAppearancePreferences); $('compactTorrentListEnabled')?.addEventListener('change',saveAppearancePreferences); $('resetViewPreferencesBtn')?.addEventListener('click',resetViewPreferences); $('titleSpeedEnabled')?.addEventListener('change',saveTitleSpeedPreference); $('trackerFaviconsEnabled')?.addEventListener('change',saveTrackerFaviconsPreference); $('reverseDnsEnabled')?.addEventListener('change',saveReverseDnsPreference); $('automationToastsEnabled')?.addEventListener('change',saveNotificationPrefs); $('smartQueueToastsEnabled')?.addEventListener('change',saveNotificationPrefs); $('saveEasterEggPrefsBtn')?.addEventListener('click',saveEasterEggPrefs); $('easterEggEnabled')?.addEventListener('change',saveEasterEggPrefs); document.querySelectorAll('.disk-monitor-mode').forEach(input=>input.addEventListener('change',async e=>{ diskMonitorMode=e.target.value||'default'; if(diskMonitorMode==='selected' && !diskMonitorSelectedPath && diskMonitorPaths.length) diskMonitorSelectedPath=diskMonitorPaths[0]; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); })); $('diskMonitorSelectedPath')?.addEventListener('change',async e=>{ diskMonitorSelectedPath=e.target.value||''; if(diskMonitorSelectedPath) diskMonitorMode='selected'; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); }); $('addDiskPathBtn')?.addEventListener('click',async()=>{ const p=($('diskMonitorPathInput')?.value||'').trim(); if(!p) return; if(!diskMonitorPaths.includes(p)) diskMonitorPaths.push(p); if(!diskMonitorSelectedPath) diskMonitorSelectedPath=p; if(diskMonitorMode==='default') diskMonitorMode='selected'; if($('diskMonitorPathInput')) $('diskMonitorPathInput').value=''; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); }); $('diskMonitorPaths')?.addEventListener('click',async e=>{ const use=e.target.closest('.disk-path-select'); if(use){ diskMonitorSelectedPath=use.dataset.path||''; diskMonitorMode='selected'; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); return; } const btn=e.target.closest('.disk-path-remove'); if(!btn) return; diskMonitorPaths=diskMonitorPaths.filter(p=>p!==btn.dataset.path); if(diskMonitorSelectedPath===btn.dataset.path) diskMonitorSelectedPath=diskMonitorPaths[0]||''; if(diskMonitorMode==='selected' && !diskMonitorSelectedPath) diskMonitorMode='default'; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); }); $('saveFooterPrefsBtn')?.addEventListener('click',saveFooterPreferences);\n ";
export const preferenceEventsSource = "$('appStatusRefreshBtn')?.addEventListener('click',loadAppStatus); $('portCheckEnabled')?.addEventListener('change',savePortCheckPref); $('portCheckNowBtn')?.addEventListener('click',()=>loadPortCheck(true)); $('bootstrapThemeSelect')?.addEventListener('change',saveAppearancePreferences); $('fontFamilySelect')?.addEventListener('change',saveAppearancePreferences); $('interfaceScaleRange')?.addEventListener('input',e=>applyInterfaceScale(e.target.value)); $('interfaceScaleRange')?.addEventListener('change',saveAppearancePreferences); $('torrentListFontSizeRange')?.addEventListener('input',e=>applyTorrentListFontSize(e.target.value)); $('torrentListFontSizeRange')?.addEventListener('change',saveAppearancePreferences); $('compactTorrentListEnabled')?.addEventListener('change',saveAppearancePreferences); $('resetViewPreferencesBtn')?.addEventListener('click',resetViewPreferences); $('titleSpeedEnabled')?.addEventListener('change',saveTitleSpeedPreference); $('trackerFaviconsEnabled')?.addEventListener('change',saveTrackerFaviconsPreference); $('reverseDnsEnabled')?.addEventListener('change',saveReverseDnsPreference); $('automationToastsEnabled')?.addEventListener('change',saveNotificationPrefs); $('smartQueueToastsEnabled')?.addEventListener('change',saveNotificationPrefs); $('saveEasterEggPrefsBtn')?.addEventListener('click',saveEasterEggPrefs); $('easterEggEnabled')?.addEventListener('change',saveEasterEggPrefs); document.querySelectorAll('.disk-monitor-mode').forEach(input=>input.addEventListener('change',async e=>{ diskMonitorMode=e.target.value||'default'; if(diskMonitorMode==='selected' && !diskMonitorSelectedPath && diskMonitorPaths.length) diskMonitorSelectedPath=diskMonitorPaths[0]; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); })); $('diskMonitorSelectedPath')?.addEventListener('change',async e=>{ diskMonitorSelectedPath=e.target.value||''; if(diskMonitorSelectedPath) diskMonitorMode='selected'; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); }); $('addDiskPathBtn')?.addEventListener('click',async()=>{ const p=($('diskMonitorPathInput')?.value||'').trim(); if(!p) return; if(!diskMonitorPaths.includes(p)) diskMonitorPaths.push(p); if(!diskMonitorSelectedPath) diskMonitorSelectedPath=p; if(diskMonitorMode==='default') diskMonitorMode='selected'; if($('diskMonitorPathInput')) $('diskMonitorPathInput').value=''; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); }); $('diskMonitorPaths')?.addEventListener('click',async e=>{ const use=e.target.closest('.disk-path-select'); if(use){ diskMonitorSelectedPath=use.dataset.path||''; diskMonitorMode='selected'; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); return; } const btn=e.target.closest('.disk-path-remove'); if(!btn) return; diskMonitorPaths=diskMonitorPaths.filter(p=>p!==btn.dataset.path); if(diskMonitorSelectedPath===btn.dataset.path) diskMonitorSelectedPath=diskMonitorPaths[0]||''; if(diskMonitorMode==='selected' && !diskMonitorSelectedPath) diskMonitorMode='default'; renderDiskMonitorPaths(); await saveDiskMonitorPrefs(); }); $('saveFooterPrefsBtn')?.addEventListener('click',saveFooterPreferences);\n ";
+1 -1
View File
@@ -1 +1 @@
export const preferencesToolsSource = " async function loadPreferences(){\n try{\n const j=await (await fetch(`/api/preferences?_=${Date.now()}`, {cache:'no-store'})).json();\n const prefs=j.preferences||{};\n portCheckEnabled=!!Number(prefs.port_check_enabled ?? portCheckEnabled);\n reverseDnsEnabled=!!Number(prefs.reverse_dns_enabled ?? (reverseDnsEnabled?1:0));\n if($('reverseDnsEnabled')) $('reverseDnsEnabled').checked=reverseDnsEnabled;\n automationToastsEnabled=Number(prefs.automation_toasts_enabled ?? (automationToastsEnabled?1:0))!==0;\n smartQueueToastsEnabled=Number(prefs.smart_queue_toasts_enabled ?? (smartQueueToastsEnabled?1:0))!==0;\n easterEggEnabled=Number(prefs.easter_egg_enabled ?? (easterEggEnabled?1:0))!==0;\n easterEggLoadingImageUrl=String(prefs.easter_egg_loading_image_url ?? easterEggLoadingImageUrl ?? '').trim();\n easterEggClickImageUrl=String(prefs.easter_egg_click_image_url ?? easterEggClickImageUrl ?? '').trim();\n diskMonitorMode=prefs.disk_monitor_mode||diskMonitorMode;\n diskMonitorSelectedPath=prefs.disk_monitor_selected_path||'';\n try{ diskMonitorPaths=JSON.parse(prefs.disk_monitor_paths_json||'[]'); }catch(_){ diskMonitorPaths=[]; }\n bootstrapTheme=prefs.bootstrap_theme||bootstrapTheme;\n fontFamily=prefs.font_family||fontFamily;\n interfaceScale=Number(prefs.interface_scale||interfaceScale||100);\n compactTorrentListEnabled=Number(prefs.compact_torrent_list_enabled ?? (compactTorrentListEnabled?1:0))!==0;\n try{ footerItems={...DEFAULT_FOOTER_ITEMS,...JSON.parse(prefs.footer_items_json||'{}')}; }catch(_){ footerItems={...DEFAULT_FOOTER_ITEMS}; }\n }catch(e){ console.warn('Preference load failed', e); }\n if($('portCheckEnabled')) $('portCheckEnabled').checked=portCheckEnabled; if($('automationToastsEnabled')) $('automationToastsEnabled').checked=automationToastsEnabled; if($('smartQueueToastsEnabled')) $('smartQueueToastsEnabled').checked=smartQueueToastsEnabled; if($('easterEggEnabled')) $('easterEggEnabled').checked=easterEggEnabled; if($('easterEggLoadingImageUrl')) $('easterEggLoadingImageUrl').value=easterEggLoadingImageUrl; if($('easterEggClickImageUrl')) $('easterEggClickImageUrl').value=easterEggClickImageUrl; if($('diskMonitorMode')) $('diskMonitorMode').value=diskMonitorMode; if($('diskMonitorSelectedPath')) $('diskMonitorSelectedPath').value=diskMonitorSelectedPath; renderDiskMonitorPaths(); applyInitialLoaderEasterEgg(); scheduleRender(true); applyBootstrapTheme(bootstrapTheme); applyFontFamily(fontFamily); applyInterfaceScale(interfaceScale); applyCompactTorrentList(compactTorrentListEnabled); renderFooterPreferences(); applyFooterPreferences(); await loadPortCheck(false); }";
export const preferencesToolsSource = " async function loadPreferences(){\n try{\n const j=await (await fetch(`/api/preferences?_=${Date.now()}`, {cache:'no-store'})).json();\n const prefs=j.preferences||{};\n portCheckEnabled=!!Number(prefs.port_check_enabled ?? portCheckEnabled);\n reverseDnsEnabled=!!Number(prefs.reverse_dns_enabled ?? (reverseDnsEnabled?1:0));\n if($('reverseDnsEnabled')) $('reverseDnsEnabled').checked=reverseDnsEnabled;\n automationToastsEnabled=Number(prefs.automation_toasts_enabled ?? (automationToastsEnabled?1:0))!==0;\n smartQueueToastsEnabled=Number(prefs.smart_queue_toasts_enabled ?? (smartQueueToastsEnabled?1:0))!==0;\n easterEggEnabled=Number(prefs.easter_egg_enabled ?? (easterEggEnabled?1:0))!==0;\n easterEggLoadingImageUrl=String(prefs.easter_egg_loading_image_url ?? easterEggLoadingImageUrl ?? '').trim();\n easterEggClickImageUrl=String(prefs.easter_egg_click_image_url ?? easterEggClickImageUrl ?? '').trim();\n diskMonitorMode=prefs.disk_monitor_mode||diskMonitorMode;\n diskMonitorSelectedPath=prefs.disk_monitor_selected_path||'';\n try{ diskMonitorPaths=JSON.parse(prefs.disk_monitor_paths_json||'[]'); }catch(_){ diskMonitorPaths=[]; }\n bootstrapTheme=prefs.bootstrap_theme||bootstrapTheme;\n fontFamily=prefs.font_family||fontFamily;\n interfaceScale=Number(prefs.interface_scale||interfaceScale||100);\n torrentListFontSize=clampTorrentListFontSize(prefs.torrent_list_font_size||torrentListFontSize||13);\n compactTorrentListEnabled=Number(prefs.compact_torrent_list_enabled ?? (compactTorrentListEnabled?1:0))!==0;\n try{ footerItems={...DEFAULT_FOOTER_ITEMS,...JSON.parse(prefs.footer_items_json||'{}')}; }catch(_){ footerItems={...DEFAULT_FOOTER_ITEMS}; }\n }catch(e){ console.warn('Preference load failed', e); }\n if($('portCheckEnabled')) $('portCheckEnabled').checked=portCheckEnabled; if($('automationToastsEnabled')) $('automationToastsEnabled').checked=automationToastsEnabled; if($('smartQueueToastsEnabled')) $('smartQueueToastsEnabled').checked=smartQueueToastsEnabled; if($('easterEggEnabled')) $('easterEggEnabled').checked=easterEggEnabled; if($('easterEggLoadingImageUrl')) $('easterEggLoadingImageUrl').value=easterEggLoadingImageUrl; if($('easterEggClickImageUrl')) $('easterEggClickImageUrl').value=easterEggClickImageUrl; if($('diskMonitorMode')) $('diskMonitorMode').value=diskMonitorMode; if($('diskMonitorSelectedPath')) $('diskMonitorSelectedPath').value=diskMonitorSelectedPath; renderDiskMonitorPaths(); applyInitialLoaderEasterEgg(); scheduleRender(true); applyBootstrapTheme(bootstrapTheme); applyFontFamily(fontFamily); applyInterfaceScale(interfaceScale); applyTorrentListFontSize(torrentListFontSize); applyCompactTorrentList(compactTorrentListEnabled); renderFooterPreferences(); applyFooterPreferences(); await loadPortCheck(false); }";
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+114 -43
View File
@@ -411,6 +411,7 @@ body {
position: relative;
}
.torrent-table {
font-size: var(--torrent-list-font-size, 13px);
margin: 0;
white-space: nowrap;
table-layout: fixed;
@@ -1024,6 +1025,7 @@ body.resizing-details {
background: var(--bs-body-bg);
}
.mobile-card {
font-size: var(--torrent-list-font-size, 13px);
border: 1px solid var(--bs-border-color);
background: rgba(var(--bs-secondary-bg-rgb), 0.72);
border-radius: 0.75rem;
@@ -4563,10 +4565,10 @@ body,
.operation-log-toolbar-main,
.operation-log-settings-grid,
.operation-log-view-settings {
align-items: flex-end;
display: flex;
flex-wrap: wrap;
gap: .5rem;
align-items: end;
gap: 0.5rem;
}
.operation-log-toolbar {
@@ -4578,10 +4580,21 @@ body,
}
.operation-log-toolbar-toggle {
align-items: center;
display: flex;
flex: 0 0 auto;
flex-wrap: wrap;
gap: 0.75rem;
margin-left: auto;
}
.operation-log-hide-jobs,
.operation-log-show-details {
align-items: center;
margin-bottom: 0;
min-height: 31px;
}
.operation-log-view-settings {
align-items: center;
}
@@ -4603,29 +4616,24 @@ body,
max-width: 260px;
}
.operation-log-hide-jobs {
align-items: center;
min-height: 31px;
}
.operation-log-settings-actions {
display: flex;
flex-wrap: wrap;
gap: .5rem;
gap: 0.5rem;
}
.operation-log-stats-grid {
display: grid;
gap: 0.75rem;
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
gap: .75rem;
}
.operation-log-stat,
.operation-log-panels section {
border: 1px solid var(--bs-border-color);
border-radius: .75rem;
padding: .75rem;
background: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
border-radius: 0.75rem;
padding: 0.75rem;
}
.operation-log-stat span {
@@ -4636,50 +4644,120 @@ body,
.operation-log-panels {
display: grid;
gap: 0.75rem;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: .75rem;
margin-top: .75rem;
margin-top: 0.75rem;
}
.operation-log-row {
display: flex;
justify-content: space-between;
gap: 1rem;
padding: .25rem 0;
border-bottom: 1px solid var(--bs-border-color-translucent);
display: flex;
gap: 1rem;
justify-content: space-between;
padding: 0.25rem 0;
}
.operation-log-row:last-child {
border-bottom: 0;
}
.operation-log-table {
min-width: 820px;
table-layout: fixed;
white-space: normal;
}
.operation-log-table th,
.operation-log-table td {
overflow-wrap: anywhere;
vertical-align: top;
}
.operation-log-details {
max-width: 24rem;
.operation-log-col-time {
width: 9.5rem;
}
.operation-log-details summary {
cursor: pointer;
.operation-log-col-type {
width: 8rem;
}
.operation-log-col-source,
.operation-log-col-action {
width: 5.5rem;
}
.operation-log-col-torrent {
width: 17rem;
}
.operation-log-col-message {
width: auto;
}
.operation-log-details-row > td {
background: color-mix(in srgb, var(--bs-tertiary-bg) 55%, transparent);
border-top: 0;
padding: 0.2rem 0.75rem 0.45rem;
}
.operation-log-details-inline {
align-items: flex-start;
display: flex;
gap: 0.7rem;
min-width: 0;
}
.operation-log-details-title {
color: var(--bs-secondary-color);
flex: 0 0 auto;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.02em;
line-height: 1.7;
text-transform: uppercase;
}
.operation-log-details-table {
border-collapse: collapse;
font-size: 0.78rem;
min-width: 0;
width: 100%;
}
.operation-log-details-table th,
.operation-log-details-table td {
border-bottom: 1px solid var(--bs-border-color-translucent);
line-height: 1.25;
padding: 0.12rem 0.4rem 0.12rem 0;
vertical-align: top;
}
.operation-log-details-table th {
color: var(--bs-secondary-color);
font-weight: 700;
white-space: nowrap;
width: 1%;
}
.operation-log-details-table td {
overflow-wrap: anywhere;
}
.operation-log-details pre {
background: var(--bs-tertiary-bg);
border: 1px solid var(--bs-border-color);
border-radius: .5rem;
color: var(--bs-body-color);
font-size: .75rem;
margin: .5rem 0 0;
max-height: 18rem;
overflow: auto;
padding: .65rem;
white-space: pre-wrap;
.operation-log-details-table tr:last-child th,
.operation-log-details-table tr:last-child td {
border-bottom: 0;
}
@media (max-width: 760px) {
.operation-log-details-inline {
display: block;
}
.operation-log-details-title {
display: block;
margin-bottom: 0.15rem;
}
.operation-log-type-filter,
.operation-log-search {
max-width: none;
@@ -4688,12 +4766,14 @@ body,
.operation-log-toolbar,
.operation-log-toolbar-main,
.operation-log-toolbar-toggle,
.operation-log-view-settings {
align-items: stretch;
flex-direction: column;
}
.operation-log-toolbar-toggle {
gap: 0.35rem;
margin-left: 0;
}
@@ -5385,11 +5465,7 @@ body,
}
}
/* Compact torrent list density */
body.compact-torrent-list .torrent-table {
font-size: 0.82rem;
}
/* Compact torrent list density. Font size is controlled only by the Torrent list font slider. */
body.compact-torrent-list .torrent-table tbody tr {
height: 24px;
}
@@ -5401,7 +5477,6 @@ body.compact-torrent-list .torrent-table > :not(caption) > * > * {
body.compact-torrent-list .torrent-table .badge,
body.compact-torrent-list .torrent-table .chip {
font-size: 0.68rem;
padding: 0.08rem 0.34rem;
}
@@ -5425,7 +5500,6 @@ body.compact-torrent-list .mobile-list {
body.compact-torrent-list .mobile-card {
border-radius: 0.55rem;
font-size: 0.82rem;
margin-bottom: 0.35rem;
padding: 0.42rem;
}
@@ -5435,12 +5509,10 @@ body.compact-torrent-list .mobile-card-header {
}
body.compact-torrent-list .mobile-card .name {
font-size: 0.88rem;
line-height: 1.16;
}
body.compact-torrent-list .mobile-card .small {
font-size: 0.72rem;
line-height: 1.18;
}
@@ -5453,7 +5525,6 @@ body.compact-torrent-list .mobile-actions .btn-xs,
body.compact-torrent-list .mobile-details-btn {
--bs-btn-padding-x: 0.28rem;
--bs-btn-padding-y: 0.08rem;
--bs-btn-font-size: 0.68rem;
}
body.compact-torrent-list .mobile-progress {
File diff suppressed because one or more lines are too long