Add 6 selectable layout themes to Settings (Appearance)
This commit is contained in:
@@ -248,6 +248,7 @@ const DEFAULT_SETTINGS = {
|
||||
density: 'comfortable', // 'comfortable' | 'compact'
|
||||
perfMode: false, // disable heavy visual effects for speed
|
||||
reduceMotion: false, // disable animations
|
||||
layout: 'classic', // 'classic'|'sanctuary-stage'|'liturgical'|'living-hymnal'|'broadcaster'|'contemplative'|'bento-hub'
|
||||
autoBackupEnabled: false,
|
||||
autoBackupIntervalDays: 7,
|
||||
};
|
||||
@@ -832,6 +833,7 @@ function applyAppearance() {
|
||||
root.dataset.density = s.density || 'comfortable';
|
||||
root.dataset.perf = s.perfMode ? 'on' : 'off';
|
||||
root.dataset.motion = s.reduceMotion ? 'reduced' : 'full';
|
||||
root.dataset.layout = s.layout || 'classic';
|
||||
}
|
||||
function fmtBytes(n) {
|
||||
if (!n) return '0 B';
|
||||
@@ -2853,6 +2855,10 @@ async function renderSettings() {
|
||||
<span>Theme</span>
|
||||
${sel('setTheme', data.settings.theme, [['dark', 'Dark'], ['light', 'Light'], ['contrast', 'High contrast']])}
|
||||
</label>
|
||||
<label class="set-row">
|
||||
<span>Layout theme</span>
|
||||
${sel('setLayout', data.settings.layout || 'classic', [['classic', 'Classic (default)'], ['sanctuary-stage', 'Sanctuary Stage'], ['liturgical', 'Liturgical Chronicle'], ['living-hymnal', 'Living Hymnal'], ['broadcaster', 'Sunday Broadcaster'], ['contemplative', 'Contemplative'], ['bento-hub', 'Bento Hub']])}
|
||||
</label>
|
||||
<label class="set-row">
|
||||
<span>Font size</span>
|
||||
${sel('setFont', data.settings.fontScale, [['small', 'Small'], ['normal', 'Normal'], ['large', 'Large'], ['xl', 'Extra large']])}
|
||||
@@ -3041,6 +3047,7 @@ async function renderSettings() {
|
||||
|
||||
// ---- Wire appearance / accessibility ----
|
||||
$('setTheme').addEventListener('change', (e) => { data.settings.theme = e.target.value; applyAppearance(); persist(); });
|
||||
$('setLayout').addEventListener('change', (e) => { data.settings.layout = e.target.value; applyAppearance(); persist(); });
|
||||
$('setFont').addEventListener('change', (e) => { data.settings.fontScale = e.target.value; applyAppearance(); persist(); });
|
||||
$('setDensity').addEventListener('change', (e) => { data.settings.density = e.target.value; applyAppearance(); persist(); });
|
||||
$('setPerf').addEventListener('change', (e) => { data.settings.perfMode = e.target.checked; applyAppearance(); persist(); });
|
||||
|
||||
@@ -2805,3 +2805,224 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* LAYOUT THEMES — scoped to html[data-layout="..."]
|
||||
* All themes preserve the existing DOM; only colors, fonts, and structural
|
||||
* CSS properties are overridden. The mini-bar, service-mode overlay, and
|
||||
* video element remain fully functional in every theme.
|
||||
* ========================================================================== */
|
||||
|
||||
/* --- Sanctuary Stage -------------------------------------------------------
|
||||
* Dark near-black with warm amber/gold accent. Sidebar collapses; bottom-nav
|
||||
* takes over navigation so all views remain accessible.
|
||||
* ------------------------------------------------------------------------- */
|
||||
html[data-layout="sanctuary-stage"] {
|
||||
--bg: #090b10;
|
||||
--bg-1: #0d1018;
|
||||
--bg-2: #121620;
|
||||
--bg-3: #181c28;
|
||||
--line: #1e2232;
|
||||
--line-soft: #171b2a;
|
||||
--accent: #f59e0b;
|
||||
--accent-bright: #fbbf24;
|
||||
--accent-deep: #d97706;
|
||||
--accent-glow: rgba(245, 158, 11, 0.4);
|
||||
}
|
||||
html[data-layout="sanctuary-stage"] body::before {
|
||||
background:
|
||||
radial-gradient(900px 600px at 50% -10%, rgba(245, 158, 11, 0.10), transparent 60%),
|
||||
radial-gradient(700px 500px at 50% 110%, rgba(245, 158, 11, 0.04), transparent 55%);
|
||||
}
|
||||
html[data-layout="sanctuary-stage"] .app {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
html[data-layout="sanctuary-stage"] .sidebar {
|
||||
display: none;
|
||||
}
|
||||
html[data-layout="sanctuary-stage"] .bottom-nav {
|
||||
display: flex;
|
||||
}
|
||||
/* Pad main content above mini-bar + bottom-nav */
|
||||
html[data-layout="sanctuary-stage"] .main > *:last-child {
|
||||
padding-bottom: calc(56px + 52px + env(safe-area-inset-bottom));
|
||||
}
|
||||
html[data-layout="sanctuary-stage"] .mini-bar {
|
||||
bottom: calc(56px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* --- Liturgical Chronicle --------------------------------------------------
|
||||
* Light parchment palette with burgundy accent and serif typography.
|
||||
* Sidebar kept wider for the editorial column feel.
|
||||
* ------------------------------------------------------------------------- */
|
||||
html[data-layout="liturgical"] {
|
||||
--bg: #faf8f5;
|
||||
--bg-1: #f2ede6;
|
||||
--bg-2: #e8e0d5;
|
||||
--bg-3: #ddd5c8;
|
||||
--line: #d5ccbc;
|
||||
--line-soft: #e0d8cc;
|
||||
--text: #1a1208;
|
||||
--text-2: #3d3027;
|
||||
--text-dim: #8b7060;
|
||||
--accent: #8b261d;
|
||||
--accent-bright: #a83028;
|
||||
--accent-deep: #6b1c14;
|
||||
--accent-glow: rgba(139, 38, 29, 0.35);
|
||||
--display: Georgia, 'Times New Roman', serif;
|
||||
--ui: Georgia, 'Times New Roman', serif;
|
||||
--shadow: 0 18px 50px -12px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
html[data-layout="liturgical"] body::before {
|
||||
background: radial-gradient(900px 600px at 0% 0%, rgba(139, 38, 29, 0.04), transparent 60%);
|
||||
}
|
||||
html[data-layout="liturgical"] body::after { opacity: 0.008; }
|
||||
html[data-layout="liturgical"] .app { grid-template-columns: 300px 1fr; }
|
||||
/* Keep video player dark */
|
||||
html[data-layout="liturgical"] #video,
|
||||
html[data-layout="liturgical"] .video-wrap,
|
||||
html[data-layout="liturgical"] #videoOverlay { background: #000; }
|
||||
/* Scrollbar for light theme */
|
||||
html[data-layout="liturgical"] ::-webkit-scrollbar-thumb { background: var(--bg-2); }
|
||||
html[data-layout="liturgical"] ::-webkit-scrollbar-thumb:hover { background: var(--bg-3); }
|
||||
/* Topbar tint */
|
||||
html[data-layout="liturgical"] .topbar {
|
||||
background: linear-gradient(180deg, var(--bg-1), rgba(250,248,245,0.92));
|
||||
border-bottom-color: var(--line);
|
||||
}
|
||||
/* Mini-bar on light */
|
||||
html[data-layout="liturgical"] .mini-bar-inner {
|
||||
background: linear-gradient(180deg, var(--bg-2), var(--bg-1));
|
||||
border-top-color: var(--line);
|
||||
}
|
||||
/* Input / select elements */
|
||||
html[data-layout="liturgical"] select,
|
||||
html[data-layout="liturgical"] input[type="text"],
|
||||
html[data-layout="liturgical"] input[type="search"],
|
||||
html[data-layout="liturgical"] input[type="number"] {
|
||||
color: var(--text);
|
||||
background: var(--bg-2);
|
||||
border-color: var(--line);
|
||||
}
|
||||
|
||||
/* --- Living Hymnal ---------------------------------------------------------
|
||||
* Dark zinc with indigo accent. Clean, technical feel; slightly narrower
|
||||
* sidebar gives the main content area more room.
|
||||
* ------------------------------------------------------------------------- */
|
||||
html[data-layout="living-hymnal"] {
|
||||
--bg: #09090b;
|
||||
--bg-1: #0d0d10;
|
||||
--bg-2: #18181b;
|
||||
--bg-3: #27272a;
|
||||
--line: #3f3f46;
|
||||
--line-soft: #27272a;
|
||||
--text: #e4e4e7;
|
||||
--text-2: #a1a1aa;
|
||||
--text-dim: #71717a;
|
||||
--accent: #6366f1;
|
||||
--accent-bright: #818cf8;
|
||||
--accent-deep: #4f46e5;
|
||||
--accent-glow: rgba(99, 102, 241, 0.4);
|
||||
}
|
||||
html[data-layout="living-hymnal"] body::before {
|
||||
background:
|
||||
radial-gradient(900px 600px at 18% -10%, rgba(99, 102, 241, 0.08), transparent 60%),
|
||||
radial-gradient(700px 500px at 100% 110%, rgba(99, 102, 241, 0.04), transparent 55%);
|
||||
}
|
||||
html[data-layout="living-hymnal"] .app { grid-template-columns: 220px 1fr; }
|
||||
|
||||
/* --- Sunday Broadcaster ----------------------------------------------------
|
||||
* Near-black with crimson/rose accent for a live-broadcast feel.
|
||||
* Prominent top bar with an accent underline.
|
||||
* ------------------------------------------------------------------------- */
|
||||
html[data-layout="broadcaster"] {
|
||||
--bg: #050507;
|
||||
--bg-1: #0a0a0e;
|
||||
--bg-2: #141418;
|
||||
--bg-3: #1e1e24;
|
||||
--line: #2a2a32;
|
||||
--line-soft: #1e1e26;
|
||||
--accent: #f43f5e;
|
||||
--accent-bright: #fb7185;
|
||||
--accent-deep: #e11d48;
|
||||
--accent-glow: rgba(244, 63, 94, 0.45);
|
||||
}
|
||||
html[data-layout="broadcaster"] body::before {
|
||||
background:
|
||||
radial-gradient(900px 600px at 18% -10%, rgba(244, 63, 94, 0.09), transparent 60%),
|
||||
radial-gradient(700px 500px at 100% 110%, rgba(244, 63, 94, 0.04), transparent 55%);
|
||||
}
|
||||
html[data-layout="broadcaster"] .topbar {
|
||||
border-bottom: 2px solid rgba(244, 63, 94, 0.25);
|
||||
}
|
||||
html[data-layout="broadcaster"] .brand-mark {
|
||||
background: linear-gradient(145deg, #fb7185, #e11d48);
|
||||
box-shadow: 0 6px 18px -4px rgba(244, 63, 94, 0.5), inset 0 1px 0 rgba(255,255,255,0.25);
|
||||
}
|
||||
|
||||
/* --- Contemplative Sanctuary ------------------------------------------------
|
||||
* Deep blue-black with teal accent and serif typography. Sidebar collapses
|
||||
* and bottom-nav keeps all views accessible.
|
||||
* ------------------------------------------------------------------------- */
|
||||
html[data-layout="contemplative"] {
|
||||
--bg: #0a0e14;
|
||||
--bg-1: #0d1218;
|
||||
--bg-2: #131820;
|
||||
--bg-3: #1a2030;
|
||||
--line: #1e2840;
|
||||
--line-soft: #161e30;
|
||||
--accent: #2dd4bf;
|
||||
--accent-bright: #5eead4;
|
||||
--accent-deep: #0d9488;
|
||||
--accent-glow: rgba(45, 212, 191, 0.35);
|
||||
--display: Georgia, 'Times New Roman', serif;
|
||||
}
|
||||
html[data-layout="contemplative"] body::before {
|
||||
background:
|
||||
radial-gradient(900px 600px at 50% -20%, rgba(45, 212, 191, 0.07), transparent 60%),
|
||||
radial-gradient(700px 500px at 50% 120%, rgba(45, 212, 191, 0.04), transparent 55%);
|
||||
}
|
||||
html[data-layout="contemplative"] .app { grid-template-columns: 1fr; }
|
||||
html[data-layout="contemplative"] .sidebar { display: none; }
|
||||
html[data-layout="contemplative"] .bottom-nav { display: flex; }
|
||||
html[data-layout="contemplative"] .mini-bar {
|
||||
bottom: calc(56px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* --- Bento Hub -------------------------------------------------------------
|
||||
* GitHub-dark-ish with honey-gold accent. Tighter borders give a
|
||||
* "dashboard card" feel throughout.
|
||||
* ------------------------------------------------------------------------- */
|
||||
html[data-layout="bento-hub"] {
|
||||
--bg: #0d1117;
|
||||
--bg-1: #13181f;
|
||||
--bg-2: #1c2333;
|
||||
--bg-3: #252d3d;
|
||||
--line: #30363d;
|
||||
--line-soft: #21262d;
|
||||
--text: #e6edf3;
|
||||
--text-2: #8b949e;
|
||||
--text-dim: #484f58;
|
||||
--accent: #eab308;
|
||||
--accent-bright: #fbbf24;
|
||||
--accent-deep: #ca8a04;
|
||||
--accent-glow: rgba(234, 179, 8, 0.4);
|
||||
--radius: 10px;
|
||||
--radius-sm: 6px;
|
||||
}
|
||||
html[data-layout="bento-hub"] body::before {
|
||||
background:
|
||||
radial-gradient(900px 600px at 18% -10%, rgba(234, 179, 8, 0.06), transparent 60%),
|
||||
radial-gradient(700px 500px at 100% 110%, rgba(234, 179, 8, 0.03), transparent 55%);
|
||||
}
|
||||
html[data-layout="bento-hub"] .brand-mark {
|
||||
background: linear-gradient(145deg, #fbbf24, #ca8a04);
|
||||
box-shadow: 0 6px 18px -4px rgba(234, 179, 8, 0.45), inset 0 1px 0 rgba(255,255,255,0.25);
|
||||
}
|
||||
html[data-layout="bento-hub"] .sidebar {
|
||||
border-right-color: var(--line);
|
||||
}
|
||||
html[data-layout="bento-hub"] .topbar {
|
||||
border-bottom-color: var(--line);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user