diff --git a/drizzle/0003_foamy_whiplash.sql b/drizzle/0003_foamy_whiplash.sql new file mode 100644 index 0000000..78d848c --- /dev/null +++ b/drizzle/0003_foamy_whiplash.sql @@ -0,0 +1 @@ +ALTER TABLE `media` ADD `author` text; \ No newline at end of file diff --git a/drizzle/meta/0003_snapshot.json b/drizzle/meta/0003_snapshot.json new file mode 100644 index 0000000..262144e --- /dev/null +++ b/drizzle/meta/0003_snapshot.json @@ -0,0 +1,766 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "602674b9-0b1e-4d1b-aed3-125bac4d1dda", + "prevId": "26aa5345-b6d8-4426-a144-0199140a896a", + "tables": { + "chat_conversations": { + "name": "chat_conversations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "copilot_session_id": { + "name": "copilot_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "chat_messages": { + "name": "chat_messages", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tool_call_id": { + "name": "tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tool_calls": { + "name": "tool_calls", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "import_definitions": { + "name": "import_definitions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "wxr_file_path": { + "name": "wxr_file_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "uploads_folder_path": { + "name": "uploads_folder_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_analysis_result": { + "name": "last_analysis_result", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "media": { + "name": "media", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "alt": { + "name": "alt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "caption": { + "name": "caption", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sidecar_path": { + "name": "sidecar_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "post_links": { + "name": "post_links", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source_post_id": { + "name": "source_post_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_post_id": { + "name": "target_post_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link_text": { + "name": "link_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "post_media": { + "name": "post_media", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "media_id": { + "name": "media_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "post_media_post_media_idx": { + "name": "post_media_post_media_idx", + "columns": [ + "post_id", + "media_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "posts": { + "name": "posts", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "excerpt": { + "name": "excerpt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "categories": { + "name": "categories", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_title": { + "name": "published_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_content": { + "name": "published_content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_tags": { + "name": "published_tags", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_categories": { + "name": "published_categories", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_excerpt": { + "name": "published_excerpt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "posts_project_slug_idx": { + "name": "posts_project_slug_idx", + "columns": [ + "project_id", + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "data_path": { + "name": "data_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_active": { + "name": "is_active", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": { + "projects_slug_unique": { + "name": "projects_slug_unique", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "settings": { + "name": "settings", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tags": { + "name": "tags", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "tags_project_name_idx": { + "name": "tags_project_name_idx", + "columns": [ + "project_id", + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 26566d8..a05b0f6 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1771141922712, "tag": "0002_rainy_luckman", "breakpoints": true + }, + { + "idx": 3, + "version": "6", + "when": 1771168311850, + "tag": "0003_foamy_whiplash", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/main/database/schema.ts b/src/main/database/schema.ts index a877cae..efa2c27 100644 --- a/src/main/database/schema.ts +++ b/src/main/database/schema.ts @@ -57,6 +57,7 @@ export const media = sqliteTable('media', { title: text('title'), alt: text('alt'), caption: text('caption'), + author: text('author'), filePath: text('file_path').notNull(), sidecarPath: text('sidecar_path').notNull(), createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), diff --git a/src/main/engine/ImportExecutionEngine.ts b/src/main/engine/ImportExecutionEngine.ts index 2b72cfb..e1af5e1 100644 --- a/src/main/engine/ImportExecutionEngine.ts +++ b/src/main/engine/ImportExecutionEngine.ts @@ -36,6 +36,8 @@ import type { WxrPost, WxrMedia } from './WxrParser'; export interface ImportExecutionOptions { /** Path to the WordPress uploads folder for media files */ uploadsFolder?: string; + /** Default author to use when WXR post/media has no author */ + defaultAuthor?: string; /** Progress callback */ onProgress?: (phase: string, current: number, total: number, detail?: string) => void; } @@ -461,7 +463,7 @@ export class ImportExecutionEngine extends EventEmitter { excerpt: wxrPost.excerpt || undefined, content: transformedContent, status, - author: wxrPost.creator || undefined, + author: wxrPost.creator || options.defaultAuthor || undefined, createdAt, updatedAt, publishedAt, @@ -634,6 +636,7 @@ export class ImportExecutionEngine extends EventEmitter { title: wxrMedia.title || undefined, alt: wxrMedia.description || undefined, mimeType: wxrMedia.mimeType, + author: options.defaultAuthor, tags: [], linkedPostIds, createdAt, diff --git a/src/main/engine/MediaEngine.ts b/src/main/engine/MediaEngine.ts index 9718b8a..c709d06 100644 --- a/src/main/engine/MediaEngine.ts +++ b/src/main/engine/MediaEngine.ts @@ -30,6 +30,7 @@ export interface MediaData { title?: string; alt?: string; caption?: string; + author?: string; createdAt: Date; updatedAt: Date; tags: string[]; @@ -46,6 +47,7 @@ export interface MediaMetadata { title?: string; alt?: string; caption?: string; + author?: string; createdAt: string; updatedAt: string; tags: string[]; @@ -317,6 +319,7 @@ export class MediaEngine extends EventEmitter { title: mediaData.title, alt: mediaData.alt, caption: mediaData.caption, + author: mediaData.author, createdAt: mediaData.createdAt.toISOString(), updatedAt: mediaData.updatedAt.toISOString(), tags: mediaData.tags, @@ -337,6 +340,7 @@ export class MediaEngine extends EventEmitter { if (metadata.title) lines.push(`title: "${metadata.title}"`); if (metadata.alt) lines.push(`alt: "${metadata.alt}"`); if (metadata.caption) lines.push(`caption: "${metadata.caption}"`); + if (metadata.author) lines.push(`author: "${metadata.author}"`); lines.push(`createdAt: ${metadata.createdAt}`); lines.push(`updatedAt: ${metadata.updatedAt}`); @@ -410,6 +414,9 @@ export class MediaEngine extends EventEmitter { case 'caption': metadata.caption = value; break; + case 'author': + metadata.author = value; + break; case 'createdAt': metadata.createdAt = value; break; @@ -514,6 +521,7 @@ export class MediaEngine extends EventEmitter { title: metadata?.title, alt: metadata?.alt, caption: metadata?.caption, + author: metadata?.author, createdAt, updatedAt, tags: metadata?.tags || [], @@ -541,6 +549,7 @@ export class MediaEngine extends EventEmitter { title: mediaData.title, alt: mediaData.alt, caption: mediaData.caption, + author: mediaData.author, filePath: destPath, sidecarPath, createdAt: mediaData.createdAt, @@ -591,6 +600,7 @@ export class MediaEngine extends EventEmitter { title: updated.title, alt: updated.alt, caption: updated.caption, + author: updated.author, updatedAt: updated.updatedAt, tags: JSON.stringify(updated.tags), }) @@ -740,6 +750,7 @@ export class MediaEngine extends EventEmitter { title: dbMedia.title || undefined, alt: dbMedia.alt || undefined, caption: dbMedia.caption || undefined, + author: dbMedia.author || undefined, createdAt: dbMedia.createdAt, updatedAt: dbMedia.updatedAt, tags: JSON.parse(dbMedia.tags || '[]'), @@ -766,6 +777,7 @@ export class MediaEngine extends EventEmitter { title: dbMedia.title || undefined, alt: dbMedia.alt || undefined, caption: dbMedia.caption || undefined, + author: dbMedia.author || undefined, createdAt: dbMedia.createdAt, updatedAt: dbMedia.updatedAt, tags: JSON.parse(dbMedia.tags || '[]'), @@ -827,6 +839,7 @@ export class MediaEngine extends EventEmitter { title: dbMedia.title || undefined, alt: dbMedia.alt || undefined, caption: dbMedia.caption || undefined, + author: dbMedia.author || undefined, createdAt: dbMedia.createdAt, updatedAt: dbMedia.updatedAt, tags: JSON.parse(dbMedia.tags || '[]'), diff --git a/src/main/engine/MetaEngine.ts b/src/main/engine/MetaEngine.ts index bc77c51..0db2ce7 100644 --- a/src/main/engine/MetaEngine.ts +++ b/src/main/engine/MetaEngine.ts @@ -14,6 +14,7 @@ export interface ProjectMetadata { description?: string; dataPath?: string; // Custom path for project data mainLanguage?: string; // Main language for AI-generated content (ISO code, e.g., 'en', 'de', 'es') + defaultAuthor?: string; // Default author for new posts and media } /** diff --git a/src/main/ipc/handlers.ts b/src/main/ipc/handlers.ts index a94ee4f..66bf2cd 100644 --- a/src/main/ipc/handlers.ts +++ b/src/main/ipc/handlers.ts @@ -138,6 +138,16 @@ export function registerIpcHandlers(): void { safeHandle('posts:create', async (_, data: Partial) => { const engine = getPostEngine(); + + // If no author provided, use default author from project settings + if (!data.author) { + const metaEngine = getMetaEngine(); + const metadata = await metaEngine.getProjectMetadata(); + if (metadata?.defaultAuthor) { + data.author = metadata.defaultAuthor; + } + } + return engine.createPost(data); }); @@ -279,6 +289,17 @@ export function registerIpcHandlers(): void { safeHandle('media:import', async (_, sourcePath: string, metadata?: Partial) => { const engine = getMediaEngine(); + + // If no author provided, use default author from project settings + if (!metadata?.author) { + const metaEngine = getMetaEngine(); + const projectMetadata = await metaEngine.getProjectMetadata(); + if (projectMetadata?.defaultAuthor) { + metadata = metadata || {}; + metadata.author = projectMetadata.defaultAuthor; + } + } + return engine.importMedia(sourcePath, metadata); }); @@ -309,9 +330,14 @@ export function registerIpcHandlers(): void { const imported: MediaData[] = []; + // Get default author from project settings + const metaEngine = getMetaEngine(); + const projectMetadata = await metaEngine.getProjectMetadata(); + const defaultAuthor = projectMetadata?.defaultAuthor; + for (const filePath of result.filePaths) { try { - const media = await engine.importMedia(filePath); + const media = await engine.importMedia(filePath, defaultAuthor ? { author: defaultAuthor } : undefined); imported.push(media); } catch (error) { console.error(`Failed to import ${filePath}:`, error); @@ -881,8 +907,14 @@ export function registerIpcHandlers(): void { executionEngine.setProjectContext(activeProject.id, activeProject.dataPath); } + // Get default author from project settings + const metaEngine = getMetaEngine(); + const projectMetadata = await metaEngine.getProjectMetadata(); + const defaultAuthor = projectMetadata?.defaultAuthor; + const result = await executionEngine.executeImport(report, { uploadsFolder, + defaultAuthor, onProgress: (phase, current, total, detail) => { // Update processed items count based on phase progress processedItems++; diff --git a/src/renderer/components/Editor/Editor.tsx b/src/renderer/components/Editor/Editor.tsx index f97c30c..35a4134 100644 --- a/src/renderer/components/Editor/Editor.tsx +++ b/src/renderer/components/Editor/Editor.tsx @@ -884,7 +884,7 @@ const PostEditor: React.FC = ({ postId }) => { title, content, tags, - categories: category ? [category] : ['article'], + categories: selectedCategories.length > 0 ? selectedCategories : ['article'], }); if (updated) { @@ -903,7 +903,7 @@ const PostEditor: React.FC = ({ postId }) => { } finally { setIsSaving(false); } - }, [postId, title, content, tags, category, isDirty, isSaving, updatePost, markClean, showErrorModal]); + }, [postId, title, content, tags, selectedCategories, isDirty, isSaving, updatePost, markClean, showErrorModal]); const handlePublish = async () => { await handleSave(); diff --git a/src/renderer/components/SettingsView/SettingsView.tsx b/src/renderer/components/SettingsView/SettingsView.tsx index 9cda8af..4902d7a 100644 --- a/src/renderer/components/SettingsView/SettingsView.tsx +++ b/src/renderer/components/SettingsView/SettingsView.tsx @@ -102,6 +102,7 @@ export const SettingsView: React.FC = () => { const [projectDataPath, setProjectDataPath] = useState(''); const [defaultProjectPath, setDefaultProjectPath] = useState(''); const [projectMainLanguage, setProjectMainLanguage] = useState('en'); + const [projectDefaultAuthor, setProjectDefaultAuthor] = useState(''); // Post categories management const [postCategories, setPostCategories] = useState(DEFAULT_POST_CATEGORIES); @@ -136,11 +137,16 @@ export const SettingsView: React.FC = () => { setDefaultProjectPath(path); }); - // Load project metadata (includes mainLanguage) + // Load project metadata (includes mainLanguage and defaultAuthor) window.electronAPI?.meta.getProjectMetadata().then(metadata => { if (metadata?.mainLanguage) { setProjectMainLanguage(metadata.mainLanguage); } + if (metadata?.defaultAuthor) { + setProjectDefaultAuthor(metadata.defaultAuthor); + } else { + setProjectDefaultAuthor(''); + } }); } }, [activeProject]); @@ -233,12 +239,13 @@ export const SettingsView: React.FC = () => { setActiveProject(updated as any); useAppStore.getState().updateProject(activeProject.id, updated as any); - // Also update project.json to keep dataPath and mainLanguage in sync + // Also update project.json to keep dataPath, mainLanguage, and defaultAuthor in sync await window.electronAPI?.meta.updateProjectMetadata({ name: projectName.trim() || activeProject.name, description: projectDescription.trim(), dataPath: projectDataPath.trim() || undefined, mainLanguage: projectMainLanguage, + defaultAuthor: projectDefaultAuthor.trim() || undefined, }); } showToast.success('Project settings saved'); @@ -260,7 +267,7 @@ export const SettingsView: React.FC = () => { }; // Keywords for each section for search filtering - const projectKeywords = ['project', 'name', 'description', 'blog', 'site', 'path', 'folder', 'location', 'data', 'language']; + const projectKeywords = ['project', 'name', 'description', 'blog', 'site', 'path', 'folder', 'location', 'data', 'language', 'author', 'default']; const editorKeywords = ['editor', 'mode', 'wysiwyg', 'markdown', 'preview', 'visual']; const contentKeywords = ['content', 'categories', 'post', 'article', 'picture', 'aside', 'page']; const aiKeywords = ['ai', 'assistant', 'chat', 'model', 'prompt', 'system', 'api', 'key', 'claude', 'gpt', 'opencode']; @@ -359,6 +366,20 @@ export const SettingsView: React.FC = () => { + + setProjectDefaultAuthor(e.target.value)} + /> + +