diff --git a/src/main/menu.ts b/src/main/menu.ts index 0bd9cb1..7964a22 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -80,33 +80,31 @@ export function buildMenu( }, { type: "separator" }, { - label: "Export", + label: "Export Markdown…", + accelerator: "CmdOrCtrl+Shift+E", enabled: !!getState().bookPath, - submenu: [ - { - label: "Markdown…", - accelerator: "CmdOrCtrl+Shift+E", - click: () => getWindow()?.webContents.send("folio:export-markdown-requested"), - }, - { - label: "Bundle (ZIP)…", - click: () => getWindow()?.webContents.send("folio:export-zip-requested"), - }, - { type: "separator" }, - { - label: "Full Book (PDF)…", - accelerator: "CmdOrCtrl+Shift+P", - click: () => getWindow()?.webContents.send("folio:export-pdf-requested"), - }, - { - label: "Full Book (DOCX)…", - click: () => getWindow()?.webContents.send("folio:export-docx-requested"), - }, - { - label: "Full Book (ODT)…", - click: () => getWindow()?.webContents.send("folio:export-odt-requested"), - }, - ], + click: () => getWindow()?.webContents.send("folio:export-markdown-requested"), + }, + { + label: "Export Bundle (ZIP)…", + enabled: !!getState().bookPath, + click: () => getWindow()?.webContents.send("folio:export-zip-requested"), + }, + { + label: "Export Full Book (PDF)…", + accelerator: "CmdOrCtrl+Shift+P", + enabled: !!getState().bookPath, + click: () => getWindow()?.webContents.send("folio:export-pdf-requested"), + }, + { + label: "Export Full Book (DOCX)…", + enabled: !!getState().bookPath, + click: () => getWindow()?.webContents.send("folio:export-docx-requested"), + }, + { + label: "Export Full Book (ODT)…", + enabled: !!getState().bookPath, + click: () => getWindow()?.webContents.send("folio:export-odt-requested"), }, { type: "separator" }, { diff --git a/src/renderer/book/search.ts b/src/renderer/book/search.ts index e6295c5..c19c9da 100644 --- a/src/renderer/book/search.ts +++ b/src/renderer/book/search.ts @@ -95,40 +95,27 @@ export function createSearchFeature(ctx: BookCtx, editor: Editor): SearchFeature void (async () => { const list = await api.getChapterList(); const chapters = Array.isArray(list) ? list : []; - const byChapter: { id: string; title: string; plain: string; positions: number[]; titleHits: number }[] = []; + const byChapter: { id: string; title: string; plain: string; positions: number[] }[] = []; let total = 0; for (const ch of chapters) { if (total >= 200) break; - // Chapter titles count as matches too: a title hit links to the - // chapter itself (no in-body scroll position). - const title = ch.title || ch.id; - const titleHits = findMatches(title, term, matchCase).length; const res = await api.getChapterContent(ch.id); const md = typeof res === "string" ? res : ""; const plain = markdownToPlain(md); const positions = findMatches(plain, term, matchCase); - if (positions.length || titleHits) { - byChapter.push({ id: ch.id, title, plain, positions, titleHits }); - total += positions.length + titleHits; + if (positions.length) { + byChapter.push({ id: ch.id, title: ch.title || ch.id, plain, positions }); + total += positions.length; } } searchMeta.textContent = total ? `${total} match${total === 1 ? "" : "es"} in ${byChapter.length} chapter${byChapter.length === 1 ? "" : "s"}` : "No matches."; - for (const r of byChapter) { - const head = document.createElement("li"); - head.className = "search-chapter-head"; - const counts = [ - r.titleHits ? `title: ${r.titleHits}` : "", - r.positions.length ? `text: ${r.positions.length}` : "", - ].filter(Boolean).join(", "); - head.textContent = `${r.title} (${counts})`; - if (r.titleHits) { - head.classList.add("search-result"); - head.title = "Open chapter"; - head.addEventListener("click", () => void goToResult(r.id, 0, term, matchCase)); - } - searchResults.appendChild(head); + for (const r of byChapter) { + const head = document.createElement("li"); + head.className = "search-chapter-head"; + head.textContent = `${r.title} (${r.positions.length})`; + searchResults.appendChild(head); for (const pos of r.positions) { const li = document.createElement("li"); li.className = "search-result"; diff --git a/src/renderer/book/settings.ts b/src/renderer/book/settings.ts index c9adad1..0344849 100644 --- a/src/renderer/book/settings.ts +++ b/src/renderer/book/settings.ts @@ -164,8 +164,8 @@ export function createSettingsFeature(ctx: BookCtx): SettingsFeature { if (e.key === "Escape" && !modal.classList.contains("hidden")) closeSettings(); }); - // File-menu entry point (the redundant sidebar button was removed Sep 22). - $("settingCheckUpdate")?.addEventListener("click", () => hooks.checkForUpdates()); + // Sidebar + File-menu entry points. + $("settingsBtn")?.addEventListener("click", openSettings); api.onSettingsRequested(() => openSettings()); // Refresh the resolved-path line whenever a book opens (the default root diff --git a/src/renderer/index.css b/src/renderer/index.css index ad9509d..9495beb 100644 --- a/src/renderer/index.css +++ b/src/renderer/index.css @@ -188,13 +188,6 @@ html, body { margin-bottom: 10px; } -.update-control { - display: flex; - align-items: center; - gap: 6px; - margin-bottom: 10px; -} - .backup-label { font-size: 0.72rem; font-weight: 700; @@ -288,24 +281,11 @@ html, body { word-break: break-all; } -/* ---- sidebar nav row (Search / Full Book, under the Home bar) ---- */ -.sidebar-nav { - display: flex; - gap: 8px; - margin-bottom: var(--gap); -} - -.sidebar-nav .nav-btn { - flex: 1; - min-width: 0; - width: auto; -} - /* ---- full book nav ---- */ .full-book-nav { - display: flex; - flex: 1; - min-width: 0; + margin-top: var(--gap); + padding-top: var(--gap); + border-top: 1px solid var(--color-border); } .full-book-btn { @@ -321,8 +301,7 @@ html, body { padding: 6px 12px; cursor: pointer; transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease; - min-width: 0; - flex: 1; + min-width: 100px; } .full-book-btn:hover { @@ -609,47 +588,6 @@ html, body { color: var(--color-on-accent); } -.recent-list li.recent-item.selected { - background: var(--color-accent); - color: var(--color-on-accent); - outline: 1px solid var(--color-accent); -} - -.recent-list li.recent-item:focus-visible { - outline: 2px solid var(--color-accent); - outline-offset: -2px; -} - -/* Row actions appear only when the row is selected. */ -.recent-item .recent-actions { - flex: 0 0 auto; - display: none; - align-items: center; - gap: 4px; -} - -.recent-item.selected .recent-actions { - display: flex; -} - -.recent-item .recent-action { - height: 20px; - line-height: 1; - font-size: 0.72rem; - padding: 0 6px; - border: none; - background: transparent; - color: inherit; - cursor: pointer; - border-radius: var(--radius); - opacity: 0.85; -} - -.recent-item .recent-action:hover { - opacity: 1; - background: rgba(255, 255, 255, 0.18); -} - .recent-item .recent-title { flex: 1 1 auto; min-width: 0; @@ -659,9 +597,24 @@ html, body { user-select: none; } +.recent-item .recent-delete { + flex: 0 0 auto; + width: 20px; + height: 20px; + line-height: 1; + font-size: 1rem; + padding: 0; + border: none; + background: transparent; + color: inherit; + cursor: pointer; + border-radius: var(--radius); + opacity: 0.6; +} + .recent-item .recent-delete:hover { opacity: 1; - background: rgba(220, 53, 69, 0.35); + background: rgba(220, 53, 69, 0.18); color: #ff6b6b; } diff --git a/src/renderer/index.html b/src/renderer/index.html index d41d81b..f935365 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -24,14 +24,13 @@ -