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."); };