diff --git a/src/main/globalConfig.ts b/src/main/globalConfig.ts index 32dcbb4..307c52c 100644 --- a/src/main/globalConfig.ts +++ b/src/main/globalConfig.ts @@ -1,10 +1,11 @@ -import { join } from 'path' +import { join, basename } from 'path' import { homedir } from 'os' import { readFileSync, writeFileSync, mkdirSync } from 'fs' export interface GlobalConfig { apiKey?: string projectPath?: string + projectTitle?: string fontSize?: number theme?: 'dark' | 'light' } @@ -28,6 +29,9 @@ export const getDraftRoot = (): string => export const getApiKey = (): string | undefined => _config.apiKey ?? process.env.ANTHROPIC_API_KEY +export const getProjectTitle = (): string => + _config.projectTitle?.trim() || basename(getDraftRoot()) + export function readGlobalConfig(): GlobalConfig { return { ..._config } } diff --git a/src/main/ipcHandlers.ts b/src/main/ipcHandlers.ts index cca6a96..3a6ed3d 100644 --- a/src/main/ipcHandlers.ts +++ b/src/main/ipcHandlers.ts @@ -6,7 +6,7 @@ import { listDraftFiles, readMarkdownFile, writeMarkdownFile, getProjectWordCoun import type { SearchOptions } from './fileSystem' import { streamMessage, resetClient } from './aiService' import type { AIPayload, Attachment } from '../renderer/types/editor' -import { readGlobalConfig, writeGlobalConfig, getDraftRoot } from './globalConfig' +import { readGlobalConfig, writeGlobalConfig, getProjectTitle } from './globalConfig' import type { GlobalConfig } from './globalConfig' export function registerIpcHandlers(): void { @@ -278,7 +278,7 @@ export function registerIpcHandlers(): void { ipcMain.handle('export:projectPdf', async (event): Promise => { const win = BrowserWindow.fromWebContents(event.sender) - const projectName = basename(getDraftRoot()) + const projectName = getProjectTitle() const result = await dialog.showSaveDialog(win!, { defaultPath: `${projectName}.pdf`, diff --git a/src/renderer/components/Settings/SettingsDialog.tsx b/src/renderer/components/Settings/SettingsDialog.tsx index 8a69a2a..aac7200 100644 --- a/src/renderer/components/Settings/SettingsDialog.tsx +++ b/src/renderer/components/Settings/SettingsDialog.tsx @@ -10,6 +10,7 @@ interface Props { export function SettingsDialog({ onClose, onProjectChanged, isSetup }: Props): JSX.Element { const [apiKey, setApiKey] = useState('') const [projectPath, setProjectPath] = useState('') + const [projectTitle, setProjectTitle] = useState('') const [originalPath, setOriginalPath] = useState('') const [saved, setSaved] = useState(false) const overlayRef = useRef(null) @@ -18,6 +19,7 @@ export function SettingsDialog({ onClose, onProjectChanged, isSetup }: Props): J window.api.readConfig().then((cfg) => { setApiKey(cfg.apiKey ?? '') setProjectPath(cfg.projectPath ?? '') + setProjectTitle(cfg.projectTitle ?? '') setOriginalPath(cfg.projectPath ?? '') }) }, []) @@ -41,7 +43,7 @@ export function SettingsDialog({ onClose, onProjectChanged, isSetup }: Props): J } const handleSave = async (): Promise => { - await window.api.writeConfig({ apiKey: apiKey || undefined, projectPath: projectPath || undefined }) + await window.api.writeConfig({ apiKey: apiKey || undefined, projectPath: projectPath || undefined, projectTitle: projectTitle.trim() || undefined }) if (projectPath !== originalPath) onProjectChanged?.() setOriginalPath(projectPath) setSaved(true) @@ -79,6 +81,20 @@ export function SettingsDialog({ onClose, onProjectChanged, isSetup }: Props): J +
+ + setProjectTitle(e.target.value)} + placeholder="My Novel" + spellCheck={false} + /> +

Used as the title in PDF exports. Defaults to the project folder name if left blank.

+
+