coryd.dev/cli/lib/tasks/addLinkToShare.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

161 lines
4.2 KiB
JavaScript

import inquirer from "inquirer";
import { loadConfig } from "../config.js";
import { initDirectusClient, searchItems, createItem } from "../directus/client.js";
import { removeUrlProtocol } from "../sanitize.js";
export const addLinkToShare = async () => {
const config = await loadConfig();
initDirectusClient(config);
const { title, link, description, authorQuery } = await inquirer.prompt([
{
name: "title",
message: "📝 Title for the link:",
validate: (input) => !!input || "Title is required"
},
{
name: "link",
message: "🔗 URL to share:",
validate: (input) => input.startsWith("http") || "Must be a valid URL"
},
{
name: "description",
message: "🗒 Description (optional):",
default: ""
},
{
name: "authorQuery",
message: "👤 Search for an author:"
}
]);
const authorMatches = await searchItems("authors", authorQuery);
let author;
if (!authorMatches.length) {
const { shouldCreate } = await inquirer.prompt({
type: "confirm",
name: "shouldCreate",
message: "❌ No authors found. Do you want to create a new one?",
default: true
});
if (!shouldCreate) return;
const { name, url, mastodon, rss, json, newsletter, blogroll } = await inquirer.prompt([
{
name: "name",
message: "👤 Author name:",
validate: (input) => !!input || "Name is required"
},
{ name: "url", message: "🔗 URL (optional):", default: "" },
{ name: "mastodon", message: "🐘 Mastodon handle (optional):", default: "" },
{ name: "rss", message: "📡 RSS feed (optional):", default: "" },
{ name: "json", message: "🧾 JSON feed (optional):", default: "" },
{ name: "newsletter", message: "📰 Newsletter URL (optional):", default: "" },
{ type: "confirm", name: "blogroll", message: "📌 Add to blogroll?", default: false }
]);
const created = await createItem("authors", {
name,
url,
mastodon,
rss,
json,
newsletter,
blogroll
});
author = created.data?.id || created.id;
} else {
const response = await inquirer.prompt({
type: "list",
name: "author",
message: "Select an author:",
choices: authorMatches.map((a) => {
const cleanUrl = removeUrlProtocol(a.url);
const display = cleanUrl ? `${a.name} (${cleanUrl})` : a.name;
return {
name: display,
value: a.id
};
})
});
author = response.author;
}
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}"`);
const { shouldCreateTag } = await inquirer.prompt({
type: "confirm",
name: "shouldCreateTag",
message: `Do you want to create a new tag named "${trimmedQuery}"?`,
default: true
});
if (shouldCreateTag) {
const createdTag = await createItem("tags", { name: trimmedQuery });
const newTagId = createdTag.data?.id || createdTag.id;
tagIds.push(newTagId);
}
const { again } = await inquirer.prompt({
type: "confirm",
name: "again",
message: "Search and select more tags?",
default: false
});
if (!again) break;
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;
}
await createItem("links", {
title,
link,
description,
author,
link_tags: tagIds.map((tagId) => ({ tags_id: tagId })),
date: new Date().toISOString()
});
console.log("✅ Link created successfully.");
};