#!/usr/bin/env bash
set -euo pipefail
###############################################################################
# DCREATE — dmenu content creator for krisyotam.com
#
# Maintainer: Kris Yotam <krisyotam@pm.me>
# License: MIT
# Created: 2026-02-15
# Updated: 2026-02-26
# Description: Create new content entries via dmenu. Collects title + preview,
# auto-generates slug, validates uniqueness against ~/content/,
# then spawns Claude in st terminal to determine metadata and
# write a YAML-frontmatter .mdx file.
###############################################################################
CONTENT_DIR="$HOME/content"
declare -A TYPE_ICONS=(
[papers]="" [blog]="" [essays]="" [notes]=""
[diary]="" [progymnasmata]="" [reviews]=""
[fiction]="" [verse]="" [news]="" [ocs]=""
)
ALL_TYPES=(blog diary essays fiction news notes ocs papers progymnasmata reviews verse)
notify() { notify-send "dcreate" "$1" 2>/dev/null || true; }
slugify() {
echo "$1" |
tr '[:upper:]' '[:lower:]' |
sed 's/[^a-z0-9 -]//g' |
sed 's/ */ /g; s/ /-/g; s/--*/-/g; s/^-//; s/-$//'
}
# Check if slug.mdx already exists in any content subdirectory
check_slug_globally() {
local slug="$1"
for dir in "$CONTENT_DIR"/*/; do
[ -d "$dir" ] || continue
if [ -f "$dir/${slug}.mdx" ]; then
echo "$(basename "$dir"):${slug}.mdx"
return
fi
done
}
# Select type
type_menu() {
local entries=""
for t in "${ALL_TYPES[@]}"; do
entries+="${TYPE_ICONS[$t]:-} $t"$'\n'
done
echo "$entries" | dmenu -i -l 12 -p "create:" | awk '{print $2}'
}
# Main
type="$(type_menu)"
[[ -z "$type" ]] && exit 0
# Get title
title="$(echo "" | dmenu -p "title:")"
[[ -z "$title" ]] && exit 0
# Generate and validate slug
slug="$(slugify "$title")"
collision="$(check_slug_globally "$slug")"
if [[ -n "$collision" ]]; then
notify "Slug collision: $slug ($collision)"
slug="$(echo "$slug" | dmenu -p "collision! alt slug:")"
[[ -z "$slug" ]] && exit 0
slug="$(slugify "$slug")"
collision="$(check_slug_globally "$slug")"
if [[ -n "$collision" ]]; then
notify "Still colliding: $slug. Aborting."
exit 1
fi
fi
# Get preview
preview="$(echo "" | dmenu -p "preview:")"
# Type-specific extra fields
extra_prompt=""
if [[ "$type" == "verse" ]]; then
verse_type="$(printf 'haiku\nsonnet\nfree-verse\node\nlimerick\nvillanelle\nother' | dmenu -i -l 7 -p "verse type:")"
[[ -n "$verse_type" ]] && extra_prompt="verse_type: $verse_type"
fi
# Ensure target directory exists
target_dir="$CONTENT_DIR/$type"
mkdir -p "$target_dir"
date="$(date +%Y-%m-%d)"
target_file="$target_dir/${slug}.mdx"
# Build Claude instruction
instruction="You are creating a new $type entry as a YAML-frontmatter .mdx file.
=== USER INPUT ===
Type: $type
Title: $title
Preview: ${preview:-"(none)"}
Slug: $slug
Date: $date
${extra_prompt:+Extra: $extra_prompt}
=== TARGET FILE ===
$target_file
=== YAML FORMAT ===
The file MUST use this exact YAML frontmatter structure:
---
title: $title
slug: $slug
type: $type
category: <choose-appropriate-category>
start_date: '$date'
end_date: ''
state: active
preview: ${preview:-"<write-a-one-line-preview>"}
status: Draft
confidence: <certain|likely|possible|unlikely>
importance: <1-10>
tags:
- <tag1>
- <tag2>
- <tag3>
---
Content goes here...
=== YOUR TASK ===
1. ANALYZE the title and preview to determine: category, tags, confidence, importance.
2. WRITE the .mdx file to: $target_file
3. Use the Write tool to create the file with proper YAML frontmatter.
4. VERIFY the file was created.
Execute this now without asking for confirmation."
# Spawn Claude in st terminal
notify "Creating: $title ($slug)"
st -e bash -c "claude -p '$(echo "$instruction" | sed "s/'/'\\\\''/g")'; echo; echo 'Press Enter to close...'; read" &
disown