feat(reader): implement full appearance customization panel with themes, fonts, margins, line-height, and localStorage persistence
This commit is contained in:
+281
-9
@@ -2822,6 +2822,22 @@ body {
|
||||
animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
||||
}
|
||||
|
||||
.reader-settings-panel {
|
||||
position: fixed !important;
|
||||
top: auto !important;
|
||||
bottom: calc(58px + env(safe-area-inset-bottom, 0px)) !important;
|
||||
left: 8px !important;
|
||||
right: 8px !important;
|
||||
width: auto !important;
|
||||
max-height: calc(85dvh - 60px) !important;
|
||||
overflow-y: auto !important;
|
||||
-webkit-overflow-scrolling: touch !important;
|
||||
border-radius: 20px !important;
|
||||
box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.55) !important;
|
||||
z-index: 10006 !important;
|
||||
animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
||||
}
|
||||
|
||||
@keyframes slideUpSheet {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
@@ -3127,22 +3143,278 @@ body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.reader-scroll-area {
|
||||
padding: 36px 24px 60px;
|
||||
max-width: 780px;
|
||||
margin: 0 auto;
|
||||
--reader-font-size: 18px;
|
||||
--reader-line-height: 1.65;
|
||||
--reader-font-family: 'Literata', 'Merriweather', 'Georgia', 'Cambria', serif;
|
||||
--reader-max-width: 760px;
|
||||
--reader-padding-h: 24px;
|
||||
--reader-text-align: left;
|
||||
--reader-bg: var(--bg-surface);
|
||||
--reader-text: var(--text-main);
|
||||
|
||||
background-color: var(--reader-bg);
|
||||
min-height: 60vh;
|
||||
padding: 0;
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.reader-content-body {
|
||||
font-family: Georgia, 'Times New Roman', serif;
|
||||
font-size: 19px;
|
||||
line-height: 1.85;
|
||||
color: var(--text-main);
|
||||
max-width: var(--reader-max-width);
|
||||
margin: 0 auto;
|
||||
padding: 32px var(--reader-padding-h) 80px;
|
||||
font-family: var(--reader-font-family);
|
||||
font-size: var(--reader-font-size);
|
||||
line-height: var(--reader-line-height);
|
||||
text-align: var(--reader-text-align);
|
||||
color: var(--reader-text);
|
||||
word-break: break-word;
|
||||
user-select: text;
|
||||
transition: font-size 0.15s ease, line-height 0.15s ease, max-width 0.2s ease, padding 0.2s ease;
|
||||
}
|
||||
|
||||
/* Reader Appearance Themes */
|
||||
.reader-scroll-area.reader-theme-sepia {
|
||||
--reader-bg: #fbf0d9;
|
||||
--reader-text: #433422;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-sepia .reader-word:hover {
|
||||
background-color: rgba(217, 119, 6, 0.25);
|
||||
color: #92400e;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-sepia blockquote {
|
||||
background-color: #f4e4c1;
|
||||
border-color: #d6bc97;
|
||||
color: #5f4b32;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-sepia .reader-inline-code,
|
||||
.reader-scroll-area.reader-theme-sepia .reader-code-wrap pre {
|
||||
background-color: #efe0bc;
|
||||
color: #433422;
|
||||
border-color: #dec89f;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-sepia .reader-table th,
|
||||
.reader-scroll-area.reader-theme-sepia .reader-table td {
|
||||
border-color: #dec89f;
|
||||
}
|
||||
|
||||
.reader-scroll-area.reader-theme-light {
|
||||
--reader-bg: #ffffff;
|
||||
--reader-text: #1e293b;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-light blockquote {
|
||||
background-color: #f8fafc;
|
||||
border-color: #cbd5e1;
|
||||
color: #334155;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-light .reader-inline-code,
|
||||
.reader-scroll-area.reader-theme-light .reader-code-wrap pre {
|
||||
background-color: #f1f5f9;
|
||||
color: #0f172a;
|
||||
border-color: #e2e8f0;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-light .reader-word:hover {
|
||||
background-color: rgba(2, 132, 199, 0.15);
|
||||
color: #0284c7;
|
||||
}
|
||||
|
||||
.reader-scroll-area.reader-theme-oled {
|
||||
--reader-bg: #000000;
|
||||
--reader-text: #d8e2ec;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-oled blockquote {
|
||||
background-color: #0a0e17;
|
||||
border-color: #1e293b;
|
||||
}
|
||||
.reader-scroll-area.reader-theme-oled .reader-inline-code,
|
||||
.reader-scroll-area.reader-theme-oled .reader-code-wrap pre {
|
||||
background-color: #0a0e17;
|
||||
border-color: #1e293b;
|
||||
}
|
||||
|
||||
.reader-scroll-area.reader-theme-dark {
|
||||
--reader-bg: var(--bg-surface);
|
||||
--reader-text: var(--text-main);
|
||||
}
|
||||
|
||||
/* Reader Font Families */
|
||||
.reader-scroll-area.reader-font-sans {
|
||||
--reader-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
.reader-scroll-area.reader-font-serif {
|
||||
--reader-font-family: 'Literata', 'Merriweather', 'Georgia', 'Cambria', 'Times New Roman', serif;
|
||||
}
|
||||
.reader-scroll-area.reader-font-mono {
|
||||
--reader-font-family: 'JetBrains Mono', 'Fira Code', 'Menlo', 'Consolas', monospace;
|
||||
}
|
||||
|
||||
/* Reader Margin & Width Variants */
|
||||
.reader-scroll-area.reader-margins-narrow {
|
||||
--reader-max-width: 940px;
|
||||
--reader-padding-h: 12px;
|
||||
}
|
||||
.reader-scroll-area.reader-margins-normal {
|
||||
--reader-max-width: 760px;
|
||||
--reader-padding-h: 24px;
|
||||
}
|
||||
.reader-scroll-area.reader-margins-wide {
|
||||
--reader-max-width: 600px;
|
||||
--reader-padding-h: 36px;
|
||||
}
|
||||
|
||||
/* Reader Text Alignment */
|
||||
.reader-scroll-area.reader-align-left {
|
||||
--reader-text-align: left;
|
||||
}
|
||||
.reader-scroll-area.reader-align-justify {
|
||||
--reader-text-align: justify;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
/* Reader Appearance Settings Panel / Sheet */
|
||||
.reader-settings-panel {
|
||||
position: fixed;
|
||||
top: 64px;
|
||||
right: 28px;
|
||||
width: 320px;
|
||||
background-color: var(--bg-surface);
|
||||
border: 1px solid var(--border-focus);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: 0 16px 36px rgba(0, 0, 0, 0.45);
|
||||
z-index: 10002;
|
||||
padding: 16px;
|
||||
animation: fadeIn 0.15s ease-out;
|
||||
}
|
||||
|
||||
.reader-settings-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.reader-settings-header h4 {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.reader-settings-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.setting-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.setting-segmented-control {
|
||||
display: flex;
|
||||
background-color: var(--bg-input);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.seg-btn {
|
||||
flex: 1;
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
transition: var(--transition);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.seg-btn:hover {
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.seg-btn.active {
|
||||
background-color: var(--primary);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.setting-stepper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: var(--bg-input);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
.step-btn {
|
||||
background: var(--bg-surface-hover);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
color: var(--text-main);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
width: 38px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.step-val {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.theme-palette {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.theme-chip {
|
||||
padding: 7px 10px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.theme-chip-dark { background: #1e293b; color: #f8fafc; border-color: #334155; }
|
||||
.theme-chip-sepia { background: #fbf0d9; color: #433422; border-color: #d6bc97; }
|
||||
.theme-chip-light { background: #ffffff; color: #0f172a; border-color: #cbd5e1; }
|
||||
.theme-chip-oled { background: #000000; color: #e2e8f0; border-color: #334155; }
|
||||
|
||||
.theme-chip.active {
|
||||
border-color: var(--primary) !important;
|
||||
box-shadow: 0 0 0 2px var(--primary-dim);
|
||||
}
|
||||
|
||||
.reader-settings-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.reader-content-body h1,
|
||||
|
||||
Reference in New Issue
Block a user