From ca104870ab8b13a2ee0b835f756db901be46993a Mon Sep 17 00:00:00 2001 From: TC Date: Wed, 10 Jun 2026 23:01:35 +1000 Subject: [PATCH] =?UTF-8?q?=E2=99=BF=20separate=20chapter=20numbers=20and?= =?UTF-8?q?=20titles=20as=20export=20options?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/ipcHandlers.ts | 31 +++++++++---- .../components/Export/ExportDialog.tsx | 46 +++++++++++++++---- tsconfig.node.tsbuildinfo | 2 +- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/main/ipcHandlers.ts b/src/main/ipcHandlers.ts index 464f7f0..18479a2 100644 --- a/src/main/ipcHandlers.ts +++ b/src/main/ipcHandlers.ts @@ -370,6 +370,7 @@ export function registerIpcHandlers(): void { ipcMain.handle('export:projectPdf', async (event, opts: { romanNumerals: boolean + showChapterTitle: boolean includeCover: boolean includeFrontMatter: boolean pageFrom: number | null @@ -507,21 +508,35 @@ export function registerIpcHandlers(): void { }) } - let chapterTitle: string + const fileName = doc.relativePath.split('/').pop()?.replace(/\.md$/, '') ?? doc.relativePath let headerTitle: string - if (!isFrontMatter && opts.romanNumerals) { + let headingHtml: string + if (!isFrontMatter) { chapterIndex++ - chapterTitle = toRoman(chapterIndex) - headerTitle = toRoman(chapterIndex) + const numeral = opts.romanNumerals ? toRoman(chapterIndex) : null + const title = opts.showChapterTitle ? fileName : null + const safe = (s: string): string => s.replace(/&/g, '&').replace(/${safe(numeral)}

${safe(title)}

` + headerTitle = `${numeral} — ${title}` + } else if (numeral) { + headingHtml = `

${safe(numeral)}

` + headerTitle = numeral + } else if (title) { + headingHtml = `

${safe(title)}

` + headerTitle = title + } else { + headingHtml = '' + headerTitle = fileName + } } else { - chapterTitle = doc.relativePath.split('/').pop()?.replace(/\.md$/, '') ?? doc.relativePath - headerTitle = chapterTitle + headingHtml = `

${fileName.replace(/&/g, '&').replace(/` + headerTitle = fileName } - const safeChapterTitle = chapterTitle.replace(/&/g, '&').replace(/

${safeChapterTitle}

${contentHtml}` + bodyHtml: `
${headingHtml}${contentHtml}
` }) } diff --git a/src/renderer/components/Export/ExportDialog.tsx b/src/renderer/components/Export/ExportDialog.tsx index df5a04a..dcfaa91 100644 --- a/src/renderer/components/Export/ExportDialog.tsx +++ b/src/renderer/components/Export/ExportDialog.tsx @@ -3,21 +3,34 @@ import './Export.css' export interface ExportOptions { romanNumerals: boolean + showChapterTitle: boolean includeCover: boolean includeFrontMatter: boolean pageFrom: number | null pageTo: number | null } +const STORAGE_KEY = 'exportDialogPrefs' + +function loadPrefs(): Pick { + try { + const raw = localStorage.getItem(STORAGE_KEY) + if (raw) return JSON.parse(raw) + } catch { /* ignore */ } + return { romanNumerals: true, showChapterTitle: false, includeCover: true, includeFrontMatter: true } +} + interface Props { onClose: () => void onExport: (opts: ExportOptions) => void } export function ExportDialog({ onClose, onExport }: Props): JSX.Element { - const [romanNumerals, setRomanNumerals] = useState(true) - const [includeCover, setIncludeCover] = useState(true) - const [includeFrontMatter, setIncludeFrontMatter] = useState(true) + const prefs = loadPrefs() + const [romanNumerals, setRomanNumerals] = useState(prefs.romanNumerals) + const [showChapterTitle, setShowChapterTitle] = useState(prefs.showChapterTitle) + const [includeCover, setIncludeCover] = useState(prefs.includeCover) + const [includeFrontMatter, setIncludeFrontMatter] = useState(prefs.includeFrontMatter) const [pageFrom, setPageFrom] = useState('') const [pageTo, setPageTo] = useState('') const overlayRef = useRef(null) @@ -34,10 +47,15 @@ export function ExportDialog({ onClose, onExport }: Props): JSX.Element { if (e.target === overlayRef.current) onClose() } + const savePrefs = (patch: Partial): void => { + const next = { romanNumerals, showChapterTitle, includeCover, includeFrontMatter, ...patch } + localStorage.setItem(STORAGE_KEY, JSON.stringify(next)) + } + const handleExport = (): void => { const from = pageFrom.trim() ? parseInt(pageFrom, 10) : null const to = pageTo.trim() ? parseInt(pageTo, 10) : null - onExport({ romanNumerals, includeCover, includeFrontMatter, pageFrom: from, pageTo: to }) + onExport({ romanNumerals, showChapterTitle, includeCover, includeFrontMatter, pageFrom: from, pageTo: to }) } const pageRangeValid = (): boolean => { @@ -63,17 +81,27 @@ export function ExportDialog({ onClose, onExport }: Props): JSX.Element { setRomanNumerals(e.target.checked)} + onChange={e => { setRomanNumerals(e.target.checked); savePrefs({ romanNumerals: e.target.checked }) }} /> - Roman numeral chapter titles - I, II, III… instead of file names + Roman numeral chapter numbers + I, II, III… before the chapter heading + + +