Add dark mode and compact chapter links
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "libre-study",
|
"name": "libre-study",
|
||||||
"version": "0.1.17",
|
"version": "0.1.18",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "libre-study",
|
"name": "libre-study",
|
||||||
"version": "0.1.17",
|
"version": "0.1.18",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.11.1",
|
"@tauri-apps/api": "^2.11.1",
|
||||||
"react": "^19.2.7",
|
"react": "^19.2.7",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "libre-study",
|
"name": "libre-study",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.17",
|
"version": "0.1.18",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 127.0.0.1",
|
"dev": "vite --host 127.0.0.1",
|
||||||
|
|||||||
Generated
+1
-1
@@ -77,7 +77,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "app"
|
name = "app"
|
||||||
version = "0.1.17"
|
version = "0.1.18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "app"
|
name = "app"
|
||||||
version = "0.1.17"
|
version = "0.1.18"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
license = ""
|
license = ""
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"productName": "Libre Study",
|
"productName": "Libre Study",
|
||||||
"version": "0.1.17",
|
"version": "0.1.18",
|
||||||
"identifier": "org.librestudy.desktop",
|
"identifier": "org.librestudy.desktop",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../dist",
|
"frontendDist": "../dist",
|
||||||
|
|||||||
+209
-11
@@ -386,29 +386,37 @@ textarea:focus-visible {
|
|||||||
|
|
||||||
.chapter-tabs {
|
.chapter-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: nowrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 3px;
|
gap: 0;
|
||||||
max-height: 38px;
|
max-width: 100%;
|
||||||
|
max-height: 18px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chapter-tabs button {
|
.chapter-tabs button {
|
||||||
min-width: 22px;
|
min-width: 0;
|
||||||
min-height: 20px;
|
min-height: 0;
|
||||||
padding: 2px 5px;
|
padding: 0 3px;
|
||||||
border-color: #cfc4ad;
|
border: 0;
|
||||||
background: #f2ead8;
|
border-radius: 0;
|
||||||
color: #4c422f;
|
background: transparent;
|
||||||
|
color: #6f5a24;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
line-height: 1;
|
line-height: 1.1;
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chapter-tabs button.active,
|
.chapter-tabs button.active,
|
||||||
.chapter-tabs button:hover,
|
.chapter-tabs button:hover,
|
||||||
.chapter-tabs button:focus-visible {
|
.chapter-tabs button:focus-visible {
|
||||||
background: #d6a84f;
|
background: transparent;
|
||||||
color: #151510;
|
color: #151510;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: #d6a84f;
|
||||||
|
text-underline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-columns {
|
.page-columns {
|
||||||
@@ -1291,6 +1299,196 @@ textarea:focus-visible {
|
|||||||
width: auto;
|
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 {
|
.about-modal p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #3f443d;
|
color: #3f443d;
|
||||||
|
|||||||
+33
@@ -19,6 +19,7 @@ const timelineLimit = 200
|
|||||||
type ViewMode = 'page' | 'study' | 'notes' | 'compare'
|
type ViewMode = 'page' | 'study' | 'notes' | 'compare'
|
||||||
type StrongDisplayMode = 'off' | 'highlight' | 'numbers'
|
type StrongDisplayMode = 'off' | 'highlight' | 'numbers'
|
||||||
type PageMotion = 'idle' | 'turn-forward' | 'turn-back'
|
type PageMotion = 'idle' | 'turn-forward' | 'turn-back'
|
||||||
|
type ThemeMode = 'light' | 'dark'
|
||||||
type TimelineEntryType = 'verse' | 'strong' | 'footnote' | 'search' | 'navigation' | 'view' | 'setting'
|
type TimelineEntryType = 'verse' | 'strong' | 'footnote' | 'search' | 'navigation' | 'view' | 'setting'
|
||||||
|
|
||||||
type TimelineEntry = {
|
type TimelineEntry = {
|
||||||
@@ -223,6 +224,7 @@ function App() {
|
|||||||
const [pageMotion, setPageMotion] = useState<PageMotion>('idle')
|
const [pageMotion, setPageMotion] = useState<PageMotion>('idle')
|
||||||
const [viewMode, setViewMode] = useState<ViewMode>('notes')
|
const [viewMode, setViewMode] = useState<ViewMode>('notes')
|
||||||
const [query, setQuery] = useState('')
|
const [query, setQuery] = useState('')
|
||||||
|
const [themeMode, setThemeMode] = useState<ThemeMode>('light')
|
||||||
const [libraryVerses, setLibraryVerses] = useState<Verse[]>([])
|
const [libraryVerses, setLibraryVerses] = useState<Verse[]>([])
|
||||||
const [verses, setVerses] = useState<Verse[]>([])
|
const [verses, setVerses] = useState<Verse[]>([])
|
||||||
const [selectedId, setSelectedId] = useState<number | null>(null)
|
const [selectedId, setSelectedId] = useState<number | null>(null)
|
||||||
@@ -407,6 +409,7 @@ function App() {
|
|||||||
showDictionaryPanel: boolean
|
showDictionaryPanel: boolean
|
||||||
splitPercent: number
|
splitPercent: number
|
||||||
notesPinned: boolean
|
notesPinned: boolean
|
||||||
|
themeMode: ThemeMode
|
||||||
}>
|
}>
|
||||||
setLemmaFontSize(parsed.lemmaFontSize ?? 17)
|
setLemmaFontSize(parsed.lemmaFontSize ?? 17)
|
||||||
setLinkedFontSize(parsed.linkedFontSize ?? 15)
|
setLinkedFontSize(parsed.linkedFontSize ?? 15)
|
||||||
@@ -422,6 +425,7 @@ function App() {
|
|||||||
setShowDictionaryPanel(parsed.showDictionaryPanel ?? true)
|
setShowDictionaryPanel(parsed.showDictionaryPanel ?? true)
|
||||||
setSplitPercent(parsed.splitPercent ?? 50)
|
setSplitPercent(parsed.splitPercent ?? 50)
|
||||||
setNotesPinned(parsed.notesPinned ?? false)
|
setNotesPinned(parsed.notesPinned ?? false)
|
||||||
|
setThemeMode(parsed.themeMode ?? 'light')
|
||||||
} catch {
|
} catch {
|
||||||
localStorage.removeItem(studySettingsStorageKey)
|
localStorage.removeItem(studySettingsStorageKey)
|
||||||
}
|
}
|
||||||
@@ -493,6 +497,7 @@ function App() {
|
|||||||
showDictionaryPanel,
|
showDictionaryPanel,
|
||||||
splitPercent,
|
splitPercent,
|
||||||
notesPinned,
|
notesPinned,
|
||||||
|
themeMode,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}, [
|
}, [
|
||||||
@@ -510,6 +515,7 @@ function App() {
|
|||||||
showLinkedLine,
|
showLinkedLine,
|
||||||
showOriginalLine,
|
showOriginalLine,
|
||||||
splitPercent,
|
splitPercent,
|
||||||
|
themeMode,
|
||||||
])
|
])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -782,6 +788,11 @@ function App() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeThemeMode(nextThemeMode: ThemeMode) {
|
||||||
|
setThemeMode(nextThemeMode)
|
||||||
|
recordDisplaySetting(`Theme: ${nextThemeMode}`)
|
||||||
|
}
|
||||||
|
|
||||||
function beginSplitResize(event: ReactMouseEvent<HTMLDivElement>) {
|
function beginSplitResize(event: ReactMouseEvent<HTMLDivElement>) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const reader = readerRef.current
|
const reader = readerRef.current
|
||||||
@@ -1278,6 +1289,7 @@ function App() {
|
|||||||
key={chapter}
|
key={chapter}
|
||||||
type="button"
|
type="button"
|
||||||
className={chapter === selectedVerse?.chapter ? 'active' : ''}
|
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)}
|
onClick={() => selectedVerse && jumpTo(selectedVerse.book, chapter, 1)}
|
||||||
>
|
>
|
||||||
{chapter}
|
{chapter}
|
||||||
@@ -1733,6 +1745,26 @@ function App() {
|
|||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
<div className="settings-grid">
|
<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">
|
<section className="modal-section">
|
||||||
<h3>Original Language Line</h3>
|
<h3>Original Language Line</h3>
|
||||||
<label>
|
<label>
|
||||||
@@ -1964,6 +1996,7 @@ function App() {
|
|||||||
'app-shell',
|
'app-shell',
|
||||||
railOpen ? 'menu-open' : '',
|
railOpen ? 'menu-open' : '',
|
||||||
notesPinned ? 'notes-pinned' : '',
|
notesPinned ? 'notes-pinned' : '',
|
||||||
|
themeMode === 'dark' ? 'theme-dark' : 'theme-light',
|
||||||
].filter(Boolean).join(' ')}
|
].filter(Boolean).join(' ')}
|
||||||
>
|
>
|
||||||
<aside
|
<aside
|
||||||
|
|||||||
Reference in New Issue
Block a user