diff --git a/package-lock.json b/package-lock.json index 83918c8..164d097 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "libre-study", - "version": "0.1.15", + "version": "0.1.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "libre-study", - "version": "0.1.15", + "version": "0.1.16", "dependencies": { "@tauri-apps/api": "^2.11.1", "react": "^19.2.7", diff --git a/package.json b/package.json index c8f97c6..45c22ed 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "libre-study", "private": true, - "version": "0.1.15", + "version": "0.1.16", "type": "module", "scripts": { "dev": "vite --host 127.0.0.1", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 131c688..87f072d 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -77,7 +77,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "app" -version = "0.1.15" +version = "0.1.16" dependencies = [ "log", "rusqlite", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 99b03dd..c96cbf4 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "app" -version = "0.1.15" +version = "0.1.16" description = "A Tauri App" authors = ["you"] license = "" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 11bef3a..1c8cc76 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "productName": "Libre Study", - "version": "0.1.15", + "version": "0.1.16", "identifier": "org.librestudy.desktop", "build": { "frontendDist": "../dist", diff --git a/src/App.css b/src/App.css index 812e712..ebae107 100644 --- a/src/App.css +++ b/src/App.css @@ -2,6 +2,7 @@ display: grid; grid-template-columns: 58px minmax(0, 1fr); min-height: 100vh; + overflow: hidden; background: #ece9df; color: #202124; } @@ -151,19 +152,40 @@ .reader { display: grid; grid-template-rows: auto minmax(0, 1fr); - gap: 16px; + gap: 10px; min-width: 0; height: 100vh; - padding: 18px; + padding: 18px 42px 18px 18px; box-sizing: border-box; transition: filter 160ms ease; } .top-bar { display: grid; - grid-template-columns: minmax(760px, 1.42fr) minmax(320px, 0.58fr); + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px; + align-items: stretch; + min-width: 0; +} + +.bible-top-tools { + display: grid; + gap: 8px; + min-width: 0; +} + +.study-top-tools { + display: flex; align-items: end; + min-width: 0; + padding: 0 12px 3px; + border: 1px solid #d4cdbd; + border-radius: 8px; + background: #fbf8ef; + color: #657061; + font-size: 12px; + font-weight: 800; + text-transform: uppercase; } .study-margin h2, @@ -230,10 +252,10 @@ textarea:focus-visible { .page-controls { display: grid; - grid-template-columns: minmax(130px, 1.1fr) minmax(130px, 1.3fr) minmax(86px, 0.7fr) minmax(78px, 0.6fr) minmax(120px, 0.9fr); + grid-template-columns: minmax(92px, 1fr) minmax(118px, 1.24fr) minmax(72px, 0.74fr) minmax(68px, 0.66fr) minmax(96px, 0.9fr); gap: 8px; align-items: end; - max-width: 960px; + max-width: none; } .page-controls label { @@ -248,20 +270,16 @@ textarea:focus-visible { .study-desk { display: grid; - grid-template-columns: minmax(720px, 1fr); + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px; min-height: 0; } .study-desk.page, .study-desk.study, +.study-desk.notes, .study-desk.compare { - grid-template-columns: minmax(680px, 1160px); - justify-content: center; -} - -.study-desk.notes { - grid-template-columns: minmax(760px, 1.42fr) minmax(320px, 0.58fr); + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } .page-system, @@ -282,13 +300,9 @@ textarea:focus-visible { perspective: 1400px; } -.page-system.study, -.page-system.notes { - grid-template-columns: minmax(0, 1fr) minmax(250px, 330px); -} - .page-system.compare-system { display: block; + grid-column: 1 / -1; } .bible-page { @@ -409,11 +423,11 @@ textarea:focus-visible { } .study-margin { - grid-column: 2; - grid-row: 1 / -1; min-width: 0; - border-left: 1px solid #e4dece; + border: 1px solid #d4cdbd; + border-radius: 8px; background: #fbf8ef; + box-shadow: 0 12px 30px rgba(44, 48, 42, 0.08); } .panel-header { @@ -693,6 +707,49 @@ textarea:focus-visible { gap: 14px; } +.notes-drawer { + position: fixed; + top: 0; + right: 0; + z-index: 28; + display: grid; + grid-template-columns: 30px minmax(360px, 30vw); + width: min(540px, calc(100vw - 92px)); + height: 100vh; + transform: translateX(calc(100% - 30px)); + transition: transform 190ms ease, box-shadow 190ms ease; +} + +.notes-drawer.open, +.notes-drawer:hover, +.notes-drawer:focus-within { + transform: translateX(0); + box-shadow: -18px 0 42px rgba(17, 20, 17, 0.24); +} + +.notes-drawer-grip { + display: grid; + align-content: center; + justify-items: center; + gap: 5px; + border-left: 1px solid #d1cab9; + border-right: 1px solid #3c4239; + background: #1f231f; + color: #f6f3eb; + font-size: 10px; + font-weight: 900; + letter-spacing: 0; + cursor: pointer; +} + +.notes-drawer .notes-workspace { + border: 1px solid #d4cdbd; + border-right: 0; + border-radius: 8px 0 0 8px; + background: #fffef8; + box-shadow: none; +} + .session-manager { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) auto; diff --git a/src/App.tsx b/src/App.tsx index 53f5502..de2caf1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,7 +6,7 @@ import { getLibraryState, searchVerses, } from './studyClient' -import type { ReactNode } from 'react' +import type { DragEvent, ReactNode } from 'react' import type { CommentaryEntry, DictionaryEntry, Verse } from './types' import './App.css' @@ -218,6 +218,7 @@ function App() { const [aboutModalOpen, setAboutModalOpen] = useState(false) const [timelineModalOpen, setTimelineModalOpen] = useState(false) const [settingsModalOpen, setSettingsModalOpen] = useState(false) + const [notesDrawerOpen, setNotesDrawerOpen] = useState(false) const [pageMotion, setPageMotion] = useState('idle') const [viewMode, setViewMode] = useState('notes') const [query, setQuery] = useState('') @@ -728,6 +729,19 @@ function App() { patchActiveSession({ noteDraft: value }) } + function appendNoteClip(value: string) { + const clip = value.trim() + if (!clip) return + const nextValue = noteDraft.trim() ? `${noteDraft.trim()}\n\n${clip}` : clip + updateNoteDraft(nextValue) + } + + function startTextDrag(event: DragEvent, value: string) { + event.dataTransfer.setData('text/plain', value) + event.dataTransfer.effectAllowed = 'copy' + setNotesDrawerOpen(true) + } + function renameActiveSession(title: string) { patchActiveSession({ title }) } @@ -1022,7 +1036,13 @@ function App() { commentaryEntries.length ? (
{commentaryEntries.map((entry) => ( -
+
+ startTextDrag(event, `${entry.reference}\n${entry.text}\n- ${entry.source}`) + } + >

{entry.reference}

{entry.text}

{entry.source} @@ -1073,7 +1093,18 @@ function App() { dictionaryEntries.length ? (
{dictionaryEntries.slice(0, 6).map((entry) => ( -
+
+ startTextDrag( + event, + `${entry.term}\n${entry.definitions + .map((definition) => `${definition.sourceName}: ${definition.text}`) + .join('\n\n')}`, + ) + } + >

{entry.term}

{entry.definitions.slice(0, 2).map((definition) => (

@@ -1108,6 +1139,8 @@ function App() {

startTextDrag(event, `${reference(verse)} ${verse.text}`)} onClick={() => selectVerse(verse)} > {verse.verse} @@ -1220,6 +1253,8 @@ function App() { role="button" tabIndex={0} onClick={() => recordFootnote(note.reference, note.text)} + draggable + onDragStart={(event) => startTextDrag(event, `${note.reference} ${note.text}`)} onKeyDown={(event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault() @@ -1629,6 +1664,93 @@ function App() { ) } + function renderNotesDrawer() { + if (!selectedVerse) return null + + return ( +