coryd.dev/cli/lib/tasks/addPost.js
Cory Dransfeldt efe701f939
feat(*.liquid): apply prettier to liquid templates
- offer to create tag when none is found while adding a link from cli
- fix tag display in search
2025-06-16 14:41:29 -07:00

194 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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