Add dark mode and compact chapter links
This commit is contained in:
Generated
+2
-2
@@ -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
@@ -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",
|
||||
|
||||
Generated
+1
-1
@@ -77,7 +77,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
||||
|
||||
[[package]]
|
||||
name = "app"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rusqlite",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user