import inquirer from 'inquirer'; import { loadConfig } from '../config.js'; import { initDirectusClient, createItem, searchItems } from '../directus/client.js'; import { promptForMultipleRelations } from '../directus/relationHelpers.js'; const ASSOCIATED_MEDIA_TYPES = ['artists', 'books', 'movies', 'shows', 'genres']; const BLOCK_COLLECTIONS = [ 'youtube_player', 'github_banner', 'npm_banner', 'rss_banner', 'calendar_banner', 'forgejo_banner' ]; export const addPost = async () => { const config = await loadConfig(); initDirectusClient(config); const { title, description, content, featured } = await inquirer.prompt([ { name: 'title', message: '📝 Title:', validate: (input) => !!input || 'Title is required' }, { name: 'description', message: '🗒 Description:', default: '' }, { name: 'content', message: '📄 Content:', default: '' }, { type: 'confirm', name: 'featured', message: '⭐ Featured?', default: false } ]); let tagIds = []; while (true) { const { query } = await inquirer.prompt({ name: 'query', message: '🏷 Search for tags (or leave blank to finish):' }); const trimmedQuery = query.trim(); if (!trimmedQuery) break; const tags = await searchItems('tags', trimmedQuery); if (!tags.length) { console.warn(`⚠️ No tags found matching "${trimmedQuery}"`); continue; } const { selected } = await inquirer.prompt({ type: 'checkbox', name: 'selected', message: '✔ Select tags to add:', choices: tags.map((tag) => ({ name: tag.name, value: tag.id })) }); tagIds.push(...selected); const { again } = await inquirer.prompt({ type: 'confirm', name: 'again', message: 'Search and select more tags?', default: false }); if (!again) break; } const selectedBlocks = []; const { includeBlocks } = await inquirer.prompt({ type: 'confirm', name: 'includeBlocks', message: '➕ Add blocks?', default: false }); if (includeBlocks) { while (true) { const { collection } = await inquirer.prompt({ type: 'list', name: 'collection', message: '🧱 Choose a block collection (or Cancel to finish):', choices: [...BLOCK_COLLECTIONS, new inquirer.Separator(), 'Cancel'] }); if (collection === 'Cancel') break; const { query } = await inquirer.prompt({ name: 'query', message: `🔍 Search ${collection}:` }); const results = await searchItems(collection, query); if (!results.length) { console.warn(`⚠️ No items found in "${collection}" matching "${query}"`); continue; } const { itemId } = await inquirer.prompt({ type: 'list', name: 'itemId', message: `Select an item from ${collection}:`, choices: results.map((item) => ({ name: item.title || item.name || item.id, value: item.id })) }); selectedBlocks.push({ collection, item: itemId }); const { again } = await inquirer.prompt({ type: 'confirm', name: 'again', message: '➕ Add another block?', default: false }); if (!again) break; } } const associatedMediaPayload = {}; const { includeMedia } = await inquirer.prompt({ type: 'confirm', name: 'includeMedia', message: '➕ Add associated media?', default: false }); if (includeMedia) { for (const mediaType of ASSOCIATED_MEDIA_TYPES) { const { query } = await inquirer.prompt({ name: 'query', message: `🔎 Search for ${mediaType} to associate (or leave blank to skip):` }); if (!query.trim()) continue; const matches = await searchItems(mediaType, query.trim()); if (!matches.length) { console.warn(`⚠️ No ${mediaType} found matching "${query.trim()}"`); continue; } const { selected } = await inquirer.prompt({ type: 'checkbox', name: 'selected', message: `✔ Select ${mediaType} to associate:`, choices: matches.map((m) => ({ name: m.name_string || m.title || m.name || m.label || m.id, value: m.id })) }); if (selected.length) associatedMediaPayload[`${mediaType}`] = selected.map((id) => ({ [`${mediaType}_id`]: id })); } } const media = await promptForMultipleRelations('media', 'Associated media'); const payload = { title, description, content, featured, date: new Date().toISOString(), post_tags: tagIds.map((tagId) => ({ tags_id: tagId })), blocks: selectedBlocks, ...associatedMediaPayload }; await createItem('posts', payload); console.log('✅ Post created successfully.'); };