Compare commits

..

No commits in common. "647965668015b3bde4019e8137c55f4a2912f182" and "76222fc1b2079ed95976aa193d53f2ebdf5b554f" have entirely different histories.

5 changed files with 59 additions and 124 deletions

View file

@ -80,34 +80,32 @@ export function buildMenu(
}, },
{ type: "separator" }, { type: "separator" },
{ {
label: "Export", label: "Export Markdown…",
enabled: !!getState().bookPath,
submenu: [
{
label: "Markdown…",
accelerator: "CmdOrCtrl+Shift+E", accelerator: "CmdOrCtrl+Shift+E",
enabled: !!getState().bookPath,
click: () => getWindow()?.webContents.send("folio:export-markdown-requested"), click: () => getWindow()?.webContents.send("folio:export-markdown-requested"),
}, },
{ {
label: "Bundle (ZIP)…", label: "Export Bundle (ZIP)…",
enabled: !!getState().bookPath,
click: () => getWindow()?.webContents.send("folio:export-zip-requested"), click: () => getWindow()?.webContents.send("folio:export-zip-requested"),
}, },
{ type: "separator" },
{ {
label: "Full Book (PDF)…", label: "Export Full Book (PDF)…",
accelerator: "CmdOrCtrl+Shift+P", accelerator: "CmdOrCtrl+Shift+P",
enabled: !!getState().bookPath,
click: () => getWindow()?.webContents.send("folio:export-pdf-requested"), click: () => getWindow()?.webContents.send("folio:export-pdf-requested"),
}, },
{ {
label: "Full Book (DOCX)…", label: "Export Full Book (DOCX)…",
enabled: !!getState().bookPath,
click: () => getWindow()?.webContents.send("folio:export-docx-requested"), click: () => getWindow()?.webContents.send("folio:export-docx-requested"),
}, },
{ {
label: "Full Book (ODT)…", label: "Export Full Book (ODT)…",
enabled: !!getState().bookPath,
click: () => getWindow()?.webContents.send("folio:export-odt-requested"), click: () => getWindow()?.webContents.send("folio:export-odt-requested"),
}, },
],
},
{ type: "separator" }, { type: "separator" },
{ {
label: "Check for Updates…", label: "Check for Updates…",

View file

@ -95,21 +95,17 @@ export function createSearchFeature(ctx: BookCtx, editor: Editor): SearchFeature
void (async () => { void (async () => {
const list = await api.getChapterList(); const list = await api.getChapterList();
const chapters = Array.isArray(list) ? list : []; 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; let total = 0;
for (const ch of chapters) { for (const ch of chapters) {
if (total >= 200) break; 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 res = await api.getChapterContent(ch.id);
const md = typeof res === "string" ? res : ""; const md = typeof res === "string" ? res : "";
const plain = markdownToPlain(md); const plain = markdownToPlain(md);
const positions = findMatches(plain, term, matchCase); const positions = findMatches(plain, term, matchCase);
if (positions.length || titleHits) { if (positions.length) {
byChapter.push({ id: ch.id, title, plain, positions, titleHits }); byChapter.push({ id: ch.id, title: ch.title || ch.id, plain, positions });
total += positions.length + titleHits; total += positions.length;
} }
} }
searchMeta.textContent = total searchMeta.textContent = total
@ -118,16 +114,7 @@ export function createSearchFeature(ctx: BookCtx, editor: Editor): SearchFeature
for (const r of byChapter) { for (const r of byChapter) {
const head = document.createElement("li"); const head = document.createElement("li");
head.className = "search-chapter-head"; head.className = "search-chapter-head";
const counts = [ head.textContent = `${r.title} (${r.positions.length})`;
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); searchResults.appendChild(head);
for (const pos of r.positions) { for (const pos of r.positions) {
const li = document.createElement("li"); const li = document.createElement("li");

View file

@ -164,8 +164,8 @@ export function createSettingsFeature(ctx: BookCtx): SettingsFeature {
if (e.key === "Escape" && !modal.classList.contains("hidden")) closeSettings(); if (e.key === "Escape" && !modal.classList.contains("hidden")) closeSettings();
}); });
// File-menu entry point (the redundant sidebar button was removed Sep 22). // Sidebar + File-menu entry points.
$("settingCheckUpdate")?.addEventListener("click", () => hooks.checkForUpdates()); $("settingsBtn")?.addEventListener("click", openSettings);
api.onSettingsRequested(() => openSettings()); api.onSettingsRequested(() => openSettings());
// Refresh the resolved-path line whenever a book opens (the default root // Refresh the resolved-path line whenever a book opens (the default root

View file

@ -188,13 +188,6 @@ html, body {
margin-bottom: 10px; margin-bottom: 10px;
} }
.update-control {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 10px;
}
.backup-label { .backup-label {
font-size: 0.72rem; font-size: 0.72rem;
font-weight: 700; font-weight: 700;
@ -288,24 +281,11 @@ html, body {
word-break: break-all; 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 ---- */
.full-book-nav { .full-book-nav {
display: flex; margin-top: var(--gap);
flex: 1; padding-top: var(--gap);
min-width: 0; border-top: 1px solid var(--color-border);
} }
.full-book-btn { .full-book-btn {
@ -321,8 +301,7 @@ html, body {
padding: 6px 12px; padding: 6px 12px;
cursor: pointer; cursor: pointer;
transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease; transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
min-width: 0; min-width: 100px;
flex: 1;
} }
.full-book-btn:hover { .full-book-btn:hover {
@ -609,47 +588,6 @@ html, body {
color: var(--color-on-accent); 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 { .recent-item .recent-title {
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0; min-width: 0;
@ -659,9 +597,24 @@ html, body {
user-select: none; 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 { .recent-item .recent-delete:hover {
opacity: 1; opacity: 1;
background: rgba(220, 53, 69, 0.35); background: rgba(220, 53, 69, 0.18);
color: #ff6b6b; color: #ff6b6b;
} }

View file

@ -24,14 +24,13 @@
<span class="book-title" id="bookTitle"></span> <span class="book-title" id="bookTitle"></span>
<span class="book-path" id="bookPath" title=""></span> <span class="book-path" id="bookPath" title=""></span>
</div> </div>
<div class="sidebar-nav">
<button class="button button-ghost nav-btn" id="searchBtn" title="Search chapter titles and text (Ctrl+F)">Search</button>
<div class="full-book-nav hidden" id="fullBookNav">
<button class="full-book-btn nav-btn" id="fullBookBtn" title="View the entire book as one continuous manuscript">Full Book</button>
</div>
</div>
<ul class="chapter-list" id="chapterList"></ul> <ul class="chapter-list" id="chapterList"></ul>
<div class="full-book-nav hidden" id="fullBookNav">
<button class="full-book-btn" id="fullBookBtn" title="View the entire book as one continuous manuscript">Full Book</button>
</div>
<div class="sidebar-footer"> <div class="sidebar-footer">
<button class="button button-ghost" id="searchBtn" title="Search all chapters (Ctrl+F)">Search</button>
<button class="button button-ghost" id="settingsBtn" title="Settings (autosave, backups)">Settings</button>
<div class="theme-control"> <div class="theme-control">
<label class="theme-label" for="themeSelect">Theme</label> <label class="theme-label" for="themeSelect">Theme</label>
<select id="themeSelect" class="theme-select" title="Interface theme"> <select id="themeSelect" class="theme-select" title="Interface theme">
@ -58,6 +57,8 @@
<div class="welcome-actions"> <div class="welcome-actions">
<button class="button" id="welcomeNewBook">New</button> <button class="button" id="welcomeNewBook">New</button>
<button class="button button-ghost" id="welcomeOpenBook">Open</button> <button class="button button-ghost" id="welcomeOpenBook">Open</button>
<button class="button button-ghost" id="welcomeOpenMd" title="Open a Markdown or text file as a new book">Open file</button>
<button class="button button-ghost" id="welcomeUpdate" title="Check for a new version of Folio">Update</button>
</div> </div>
<div class="recents-block"> <div class="recents-block">
<div class="recents-title">Recent</div> <div class="recents-title">Recent</div>
@ -350,10 +351,6 @@
</div> </div>
<p class="setting-meta" id="settingResolved"></p> <p class="setting-meta" id="settingResolved"></p>
<p class="setting-meta" id="settingLastSnap"></p> <p class="setting-meta" id="settingLastSnap"></p>
<div class="update-control">
<span class="backup-label">Updates</span>
<button type="button" class="button button-ghost" id="settingCheckUpdate" title="Check for a new version of Folio">Check now</button>
</div>
<div class="modal-actions"> <div class="modal-actions">
<button class="button button-ghost" id="settingSnapNow" title="Take a snapshot right now">Snapshot now</button> <button class="button button-ghost" id="settingSnapNow" title="Take a snapshot right now">Snapshot now</button>
<button class="button" id="settingsClose">Close</button> <button class="button" id="settingsClose">Close</button>