Refine rail and book tab layout

This commit is contained in:
2026-07-12 09:45:33 -05:00
parent ea22ffd2b9
commit 984db5b4dd
7 changed files with 91 additions and 55 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "libre-study", "name": "libre-study",
"version": "0.1.9", "version": "0.1.10",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "libre-study", "name": "libre-study",
"version": "0.1.9", "version": "0.1.10",
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.11.1", "@tauri-apps/api": "^2.11.1",
"react": "^19.2.7", "react": "^19.2.7",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "libre-study", "name": "libre-study",
"private": true, "private": true,
"version": "0.1.9", "version": "0.1.10",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 127.0.0.1", "dev": "vite --host 127.0.0.1",
+1 -1
View File
@@ -77,7 +77,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
[[package]] [[package]]
name = "app" name = "app"
version = "0.1.9" version = "0.1.10"
dependencies = [ dependencies = [
"log", "log",
"rusqlite", "rusqlite",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "app" name = "app"
version = "0.1.9" version = "0.1.10"
description = "A Tauri App" description = "A Tauri App"
authors = ["you"] authors = ["you"]
license = "" license = ""
+1 -1
View File
@@ -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.9", "version": "0.1.10",
"identifier": "org.librestudy.desktop", "identifier": "org.librestudy.desktop",
"build": { "build": {
"frontendDist": "../dist", "frontendDist": "../dist",
+49 -11
View File
@@ -7,7 +7,7 @@
} }
.app-shell.menu-open .reader { .app-shell.menu-open .reader {
filter: brightness(0.72); filter: blur(1.5px) brightness(0.62) saturate(0.72);
} }
.tool-rail { .tool-rail {
@@ -35,6 +35,7 @@
.brand-mark { .brand-mark {
display: grid; display: grid;
flex: 0 0 auto;
place-items: center; place-items: center;
width: 42px; width: 42px;
height: 42px; height: 42px;
@@ -67,6 +68,7 @@
.menu-button { .menu-button {
flex: 0 0 auto; flex: 0 0 auto;
justify-content: center; justify-content: center;
align-self: center;
} }
.menu-button span { .menu-button span {
@@ -82,6 +84,19 @@
gap: 4px; gap: 4px;
} }
.tool-rail:hover .menu-button,
.tool-rail:focus-within .menu-button {
width: 42px;
padding: 0;
}
.app-identity {
display: flex;
gap: 12px;
align-items: center;
min-height: 42px;
}
.rail-icon { .rail-icon {
display: grid; display: grid;
flex: 0 0 18px; flex: 0 0 18px;
@@ -116,6 +131,23 @@
margin-top: auto; margin-top: auto;
} }
.rail-description {
display: none;
margin: 0;
padding: 12px;
border: 1px solid #3c4239;
border-radius: 6px;
background: #252b25;
color: #d9ddd4;
font-size: 13px;
line-height: 1.45;
}
.tool-rail:hover .rail-description,
.tool-rail:focus-within .rail-description {
display: block;
}
.reader { .reader {
display: grid; display: grid;
grid-template-rows: auto minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr);
@@ -266,13 +298,13 @@ textarea:focus-visible {
.bible-page { .bible-page {
display: grid; display: grid;
grid-template-rows: auto minmax(0, 1fr) auto; grid-template-rows: auto minmax(0, 1fr);
min-height: 0; min-height: 0;
padding: 26px 30px; padding: 26px 30px;
} }
.bible-page header, .bible-page header,
.bible-page footer { .page-turner {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 16px; gap: 16px;
@@ -283,13 +315,15 @@ textarea:focus-visible {
text-transform: uppercase; text-transform: uppercase;
} }
.bible-page footer { .page-turner {
padding-top: 16px; grid-column: 1 / -1;
padding: 14px 30px;
border-top: 1px solid #e8e2d4; border-top: 1px solid #e8e2d4;
background: #fffef8;
text-transform: none; text-transform: none;
} }
.bible-page footer span { .page-turner span {
color: #6b675d; color: #6b675d;
font-size: 13px; font-size: 13px;
font-weight: 700; font-weight: 700;
@@ -687,26 +721,30 @@ textarea:focus-visible {
} }
.book-tabs { .book-tabs {
display: flex; display: grid;
grid-column: 1 / -1; grid-column: 1 / -1;
grid-template-columns: repeat(24, minmax(0, 1fr));
gap: 3px; gap: 3px;
align-items: flex-start; align-items: flex-start;
padding: 0 16px 10px; padding: 0 16px 10px;
overflow-x: auto; overflow: hidden;
background: #ece9df; background: #ece9df;
} }
.book-tabs button { .book-tabs button {
min-width: 44px; min-width: 0;
height: 30px; height: 30px;
padding: 4px 7px; padding: 4px 3px;
border-color: #c8bea9; border-color: #c8bea9;
border-top: 0; border-top: 0;
border-radius: 0 0 7px 7px; border-radius: 0 0 7px 7px;
background: #efe4c9; background: #efe4c9;
color: #4c422f; color: #4c422f;
font-size: 11px; font-size: 10px;
font-weight: 800; font-weight: 800;
line-height: 1.05;
white-space: normal;
overflow-wrap: anywhere;
box-shadow: 0 5px 10px rgba(44, 48, 42, 0.08); box-shadow: 0 5px 10px rgba(44, 48, 42, 0.08);
} }
+36 -38
View File
@@ -387,6 +387,16 @@ function App() {
() => Array.from(new Set(libraryVerses.map((verse) => verse.book))), () => Array.from(new Set(libraryVerses.map((verse) => verse.book))),
[libraryVerses], [libraryVerses],
) )
const visibleBookTabs = useMemo(() => {
if (!selectedVerse || !books.length) return []
const visibleCount = 24
const selectedIndex = Math.max(0, books.indexOf(selectedVerse.book))
const halfWindow = Math.floor(visibleCount / 2)
const maxStart = Math.max(0, books.length - visibleCount)
const start = Math.min(Math.max(0, selectedIndex - halfWindow), maxStart)
return books.slice(start, start + visibleCount)
}, [books, selectedVerse])
const chapters = useMemo(() => { const chapters = useMemo(() => {
if (!selectedVerse) return [] if (!selectedVerse) return []
return Array.from( return Array.from(
@@ -512,17 +522,6 @@ function App() {
) )
} }
function setWorkspaceView(nextViewMode: ViewMode) {
setViewMode(nextViewMode)
recordTimeline(
{
type: 'view',
label: `View: ${nextViewMode}`,
},
{ viewMode: nextViewMode },
)
}
function setStrongDisplayMode(nextStrongDisplay: StrongDisplayMode) { function setStrongDisplayMode(nextStrongDisplay: StrongDisplayMode) {
setStrongDisplay(nextStrongDisplay) setStrongDisplay(nextStrongDisplay)
recordTimeline( recordTimeline(
@@ -707,19 +706,24 @@ function App() {
</p> </p>
))} ))}
</div> </div>
<footer>
<button type="button" onClick={() => shiftPage(-1)}>
Previous page
</button>
<span>{pageRange}</span>
<button type="button" onClick={() => shiftPage(1)}>
Next page
</button>
</footer>
</article> </article>
) )
} }
function renderPageTurner() {
return (
<nav className="page-turner" aria-label="Page navigation">
<button type="button" onClick={() => shiftPage(-1)}>
Previous page
</button>
<span>{pageRange}</span>
<button type="button" onClick={() => shiftPage(1)}>
Next page
</button>
</nav>
)
}
function renderStudyMargin() { function renderStudyMargin() {
if (!selectedVerse) return null if (!selectedVerse) return null
return ( return (
@@ -814,7 +818,7 @@ function App() {
return ( return (
<nav className="book-tabs" aria-label="Bible book tabs"> <nav className="book-tabs" aria-label="Bible book tabs">
{books.map((book) => ( {visibleBookTabs.map((book) => (
<button <button
key={book} key={book}
type="button" type="button"
@@ -1039,23 +1043,16 @@ function App() {
<span /> <span />
<span /> <span />
</button> </button>
<span className="brand-mark">LS</span> <div className="app-identity" aria-label="Libre Study">
<button type="button" title="Bible page" onClick={() => setWorkspaceView('page')}> <span className="brand-mark">LS</span>
<span className="rail-icon">B</span> <span className="rail-copy">
<span className="rail-copy"><strong>Bible</strong><small>Page-only reading</small></span> <strong>Libre Study</strong>
</button> <small>Free Bible study by Christ IT</small>
<button type="button" title="Study margin" onClick={() => setWorkspaceView('study')}> </span>
<span className="rail-icon">M</span> </div>
<span className="rail-copy"><strong>Margin</strong><small>References and linked words</small></span> <p className="rail-description">
</button> A readable Bible page, study margin, notes workspace, and linked public Bible data.
<button type="button" title="Notes workspace" onClick={() => setWorkspaceView('notes')}> </p>
<span className="rail-icon">N</span>
<span className="rail-copy"><strong>Notes</strong><small>Study notes and timeline</small></span>
</button>
<button type="button" title="Compare translations" onClick={() => setWorkspaceView('compare')}>
<span className="rail-icon">C</span>
<span className="rail-copy"><strong>Compare</strong><small>Translation comparison</small></span>
</button>
<button type="button" title="Session management" onClick={() => setSessionModalOpen(true)}> <button type="button" title="Session management" onClick={() => setSessionModalOpen(true)}>
<span className="rail-icon">S</span> <span className="rail-icon">S</span>
<span className="rail-copy"><strong>Sessions</strong><small>Save, export, and configure</small></span> <span className="rail-copy"><strong>Sessions</strong><small>Save, export, and configure</small></span>
@@ -1188,6 +1185,7 @@ function App() {
{renderBiblePage('KJV')} {renderBiblePage('KJV')}
{viewMode !== 'page' ? renderStudyMargin() : null} {viewMode !== 'page' ? renderStudyMargin() : null}
{renderFootnoteStrip()} {renderFootnoteStrip()}
{renderPageTurner()}
{renderBookTabs()} {renderBookTabs()}
</div> </div>
)} )}