Add dark mode and compact chapter links

This commit is contained in:
2026-07-12 10:48:31 -05:00
parent 123cb8dd98
commit 735e247477
7 changed files with 248 additions and 17 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "libre-study",
"version": "0.1.17",
"version": "0.1.18",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "libre-study",
"version": "0.1.17",
"version": "0.1.18",
"dependencies": {
"@tauri-apps/api": "^2.11.1",
"react": "^19.2.7",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "libre-study",
"private": true,
"version": "0.1.17",
"version": "0.1.18",
"type": "module",
"scripts": {
"dev": "vite --host 127.0.0.1",
+1 -1
View File
@@ -77,7 +77,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
[[package]]
name = "app"
version = "0.1.17"
version = "0.1.18"
dependencies = [
"log",
"rusqlite",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "app"
version = "0.1.17"
version = "0.1.18"
description = "A Tauri App"
authors = ["you"]
license = ""
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "Libre Study",
"version": "0.1.17",
"version": "0.1.18",
"identifier": "org.librestudy.desktop",
"build": {
"frontendDist": "../dist",
+209 -11
View File
@@ -386,29 +386,37 @@ textarea:focus-visible {
.chapter-tabs {
display: flex;
flex-wrap: wrap;
flex-wrap: nowrap;
justify-content: center;
gap: 3px;
max-height: 38px;
gap: 0;
max-width: 100%;
max-height: 18px;
overflow: hidden;
white-space: nowrap;
}
.chapter-tabs button {
min-width: 22px;
min-height: 20px;
padding: 2px 5px;
border-color: #cfc4ad;
background: #f2ead8;
color: #4c422f;
min-width: 0;
min-height: 0;
padding: 0 3px;
border: 0;
border-radius: 0;
background: transparent;
color: #6f5a24;
font-size: 10px;
line-height: 1;
line-height: 1.1;
text-decoration: none;
box-shadow: none;
}
.chapter-tabs button.active,
.chapter-tabs button:hover,
.chapter-tabs button:focus-visible {
background: #d6a84f;
background: transparent;
color: #151510;
text-decoration: underline;
text-decoration-color: #d6a84f;
text-underline-offset: 2px;
}
.page-columns {
@@ -1291,6 +1299,196 @@ textarea:focus-visible {
width: auto;
}
.segmented-control {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 4px;
padding: 3px;
border: 1px solid #d8cfbf;
border-radius: 7px;
background: #fffef8;
}
.segmented-control button {
background: transparent;
color: #3f443d;
}
.segmented-control button.active {
background: #2f6f5e;
color: #fffef8;
}
.theme-dark {
background: #161a18;
color: #eee8d8;
}
.theme-dark .reader {
background: #161a18;
}
.theme-dark .page-system,
.theme-dark .notes-workspace,
.theme-dark .status-panel,
.theme-dark .bible-page,
.theme-dark .page-turner,
.theme-dark .footnote-strip,
.theme-dark .modal-panel,
.theme-dark .study-margin,
.theme-dark .study-top-tools,
.theme-dark .modal-section,
.theme-dark .note-helper,
.theme-dark .note-placeholder,
.theme-dark .segmented-control,
.theme-dark input,
.theme-dark select,
.theme-dark textarea {
border-color: #3f493f;
background: #222820;
color: #eee8d8;
}
.theme-dark .bible-page,
.theme-dark .page-turner,
.theme-dark .footnote-strip {
background: #1d221c;
}
.theme-dark .page-columns {
column-rule-color: #333b32;
}
.theme-dark .page-verse {
color: #f2eadb;
}
.theme-dark .page-verse.selected {
background: #3a3322;
}
.theme-dark .page-verse sup,
.theme-dark .chapter-tabs button,
.theme-dark .footnote-list p span {
color: #ddb763;
}
.theme-dark .chapter-tabs button.active,
.theme-dark .chapter-tabs button:hover,
.theme-dark .chapter-tabs button:focus-visible {
color: #fff7df;
}
.theme-dark .original-language-verse,
.theme-dark .english-strong-line,
.theme-dark .resource-card {
border-color: #3f493f;
background: #20251f;
}
.theme-dark .margin-section-header {
background: #2b332a;
}
.theme-dark .margin-section-header:hover,
.theme-dark .margin-section-header:focus-visible {
background: #344031;
}
.theme-dark .strong-focus {
border-color: #3b5a50;
background: #1f302b;
}
.theme-dark .panel-header {
border-bottom-color: #3f493f;
}
.theme-dark .panel-header span,
.theme-dark .margin-reference,
.theme-dark .translit,
.theme-dark .eyebrow,
.theme-dark .collapse-button,
.theme-dark .mini-settings,
.theme-dark .resource-disabled,
.theme-dark .commentary-list small,
.theme-dark .dictionary-list p strong,
.theme-dark .page-turner span,
.theme-dark .footnote-strip span,
.theme-dark .timeline-canvas time,
.theme-dark .timeline-canvas span,
.theme-dark .timeline-canvas small,
.theme-dark .note-helper small,
.theme-dark .note-placeholder small,
.theme-dark .session-facts dt,
.theme-dark .about-list dt,
.theme-dark .modal-section label,
.theme-dark .page-controls label {
color: #aaa996;
}
.theme-dark .strong-focus h4,
.theme-dark .strong-focus p,
.theme-dark .commentary-list h3,
.theme-dark .dictionary-list h3,
.theme-dark .commentary-list p,
.theme-dark .dictionary-list p,
.theme-dark .linked-line-text,
.theme-dark .lemma-line-text,
.theme-dark .session-facts dd,
.theme-dark .about-list dd,
.theme-dark .about-modal p,
.theme-dark .resource-toggles label,
.theme-dark .checkbox-row,
.theme-dark .segmented-control button {
color: #eee8d8 !important;
}
.theme-dark .segmented-control button.active,
.theme-dark .study-top-tools button,
.theme-dark .pin-notes,
.theme-dark .strong-focus button,
.theme-dark .about-links a {
background: #3a7a69;
color: #fffdf6 !important;
}
.theme-dark .modal-backdrop {
background: rgba(5, 7, 5, 0.68);
}
.theme-dark .close-button,
.theme-dark .tool-rail,
.theme-dark .notes-drawer-grip {
background: #111511;
}
.theme-dark .book-tabs {
background: #161a18;
}
.theme-dark .book-tabs button {
border-color: #4b422f;
background: #312c20;
color: #ddc17f;
}
.theme-dark .book-tabs button:hover,
.theme-dark .book-tabs button:focus-visible,
.theme-dark .book-tabs button.active {
background: #c7963f;
color: #141510;
}
.theme-dark .split-resizer {
background: linear-gradient(90deg, transparent, #4b5448 45%, #4b5448 55%, transparent);
}
.theme-dark .split-resizer:hover,
.theme-dark .split-resizer:focus-visible {
background: #c7963f;
}
.about-modal p {
margin: 0;
color: #3f443d;
+33
View File
@@ -19,6 +19,7 @@ const timelineLimit = 200
type ViewMode = 'page' | 'study' | 'notes' | 'compare'
type StrongDisplayMode = 'off' | 'highlight' | 'numbers'
type PageMotion = 'idle' | 'turn-forward' | 'turn-back'
type ThemeMode = 'light' | 'dark'
type TimelineEntryType = 'verse' | 'strong' | 'footnote' | 'search' | 'navigation' | 'view' | 'setting'
type TimelineEntry = {
@@ -223,6 +224,7 @@ function App() {
const [pageMotion, setPageMotion] = useState<PageMotion>('idle')
const [viewMode, setViewMode] = useState<ViewMode>('notes')
const [query, setQuery] = useState('')
const [themeMode, setThemeMode] = useState<ThemeMode>('light')
const [libraryVerses, setLibraryVerses] = useState<Verse[]>([])
const [verses, setVerses] = useState<Verse[]>([])
const [selectedId, setSelectedId] = useState<number | null>(null)
@@ -407,6 +409,7 @@ function App() {
showDictionaryPanel: boolean
splitPercent: number
notesPinned: boolean
themeMode: ThemeMode
}>
setLemmaFontSize(parsed.lemmaFontSize ?? 17)
setLinkedFontSize(parsed.linkedFontSize ?? 15)
@@ -422,6 +425,7 @@ function App() {
setShowDictionaryPanel(parsed.showDictionaryPanel ?? true)
setSplitPercent(parsed.splitPercent ?? 50)
setNotesPinned(parsed.notesPinned ?? false)
setThemeMode(parsed.themeMode ?? 'light')
} catch {
localStorage.removeItem(studySettingsStorageKey)
}
@@ -493,6 +497,7 @@ function App() {
showDictionaryPanel,
splitPercent,
notesPinned,
themeMode,
}),
)
}, [
@@ -510,6 +515,7 @@ function App() {
showLinkedLine,
showOriginalLine,
splitPercent,
themeMode,
])
useEffect(() => {
@@ -782,6 +788,11 @@ function App() {
})
}
function changeThemeMode(nextThemeMode: ThemeMode) {
setThemeMode(nextThemeMode)
recordDisplaySetting(`Theme: ${nextThemeMode}`)
}
function beginSplitResize(event: ReactMouseEvent<HTMLDivElement>) {
event.preventDefault()
const reader = readerRef.current
@@ -1278,6 +1289,7 @@ function App() {
key={chapter}
type="button"
className={chapter === selectedVerse?.chapter ? 'active' : ''}
style={{ fontSize: `${Math.max(8, Math.min(11, 13 - chapters.length / 20))}px` }}
onClick={() => selectedVerse && jumpTo(selectedVerse.book, chapter, 1)}
>
{chapter}
@@ -1733,6 +1745,26 @@ function App() {
</button>
</header>
<div className="settings-grid">
<section className="modal-section">
<h3>Theme</h3>
<div className="segmented-control" aria-label="Theme mode">
<button
type="button"
className={themeMode === 'light' ? 'active' : ''}
onClick={() => changeThemeMode('light')}
>
Light
</button>
<button
type="button"
className={themeMode === 'dark' ? 'active' : ''}
onClick={() => changeThemeMode('dark')}
>
Dark
</button>
</div>
</section>
<section className="modal-section">
<h3>Original Language Line</h3>
<label>
@@ -1964,6 +1996,7 @@ function App() {
'app-shell',
railOpen ? 'menu-open' : '',
notesPinned ? 'notes-pinned' : '',
themeMode === 'dark' ? 'theme-dark' : 'theme-light',
].filter(Boolean).join(' ')}
>
<aside