#!/usr/bin/env bash
set -euo pipefail
###############################################################################
# DEDIT — dmenu metadata editor for krisyotam.com
#
# Maintainer: Kris Yotam <krisyotam@pm.me>
# License: MIT
# Created: 2026-02-15
# Description: Edit content metadata via dmenu. Select type, entry, field,
# and new value through dmenu prompts.
###############################################################################
DB="/home/krisyotam/dev/krisyotam.com/public/data/content.db"
declare -A TYPE_ICONS=(
[blog]="" [diary]="" [essays]="" [fiction]=""
[news]="" [notes]="" [ocs]="" [papers]=""
[progymnasmata]="" [reviews]="" [verse]=""
)
CONTENT_TYPES=(blog diary essays fiction news notes ocs papers progymnasmata reviews verse)
sql() { sqlite3 "$DB" "$1"; }
notify() { notify-send "dedit" "$1" 2>/dev/null || true; }
# Select content type
select_type() {
local entries=""
for t in "${CONTENT_TYPES[@]}"; do
entries+="${TYPE_ICONS[$t]:-} $t"$'\n'
done
echo "$entries" | dmenu -i -l 11 -p "edit:" | awk '{print $2}'
}
# Select entry from type
select_entry() {
local type="$1"
sql "SELECT title || ' [' || slug || ']' FROM $type ORDER BY title" |
dmenu -i -l 20 -p "$type:" |
sed 's/.*\[\(.*\)\]/\1/'
}
# Select field to edit
select_field() {
local type="$1"
local fields="title
preview
category_slug
tags
state"
if [[ "$type" != "diary" ]]; then
fields+="
status
confidence
importance"
fi
echo "$fields" | dmenu -i -l 10 -p "field:"
}
# Edit a field
edit_field() {
local type="$1" slug="$2" field="$3"
local current new_value
case "$field" in
title|preview)
current="$(sql "SELECT $field FROM $type WHERE slug='$slug'")"
new_value="$(echo "$current" | dmenu -p "$field:")"
[[ -z "$new_value" ]] && return
new_value="${new_value//\'/\'\'}"
sql "UPDATE $type SET $field='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
notify "Updated $field"
;;
category_slug)
new_value="$(sql "SELECT slug FROM categories ORDER BY slug" | dmenu -i -l 15 -p "category:")"
[[ -z "$new_value" ]] && return
sql "UPDATE $type SET category_slug='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
notify "Category: $new_value"
;;
tags)
local id
id="$(sql "SELECT id FROM $type WHERE slug='$slug'")"
local action
action="$(printf "add\nremove" | dmenu -i -p "tags:")"
[[ -z "$action" ]] && return
if [[ "$action" == "add" ]]; then
local tag
tag="$(sql "SELECT slug FROM tags ORDER BY slug" | dmenu -i -l 20 -p "add tag:")"
[[ -z "$tag" ]] && return
local tag_id
tag_id="$(sql "SELECT id FROM tags WHERE slug='$tag'")"
[[ -z "$tag_id" ]] && return
sql "INSERT OR IGNORE INTO content_tags (content_type, content_id, tag_id) VALUES ('$type', $id, $tag_id)"
notify "Added tag: $tag"
else
local tag
tag="$(sql "SELECT t.slug FROM tags t JOIN content_tags ct ON ct.tag_id=t.id WHERE ct.content_type='$type' AND ct.content_id=$id ORDER BY t.slug" | dmenu -i -l 10 -p "remove:")"
[[ -z "$tag" ]] && return
sql "DELETE FROM content_tags WHERE content_type='$type' AND content_id=$id AND tag_id=(SELECT id FROM tags WHERE slug='$tag')"
notify "Removed tag: $tag"
fi
;;
status)
new_value="$(printf "Notes\nDraft\nIn Progress\nFinished\nAbandoned" | dmenu -i -l 5 -p "status:")"
[[ -z "$new_value" ]] && return
sql "UPDATE $type SET status='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
notify "Status: $new_value"
;;
confidence)
new_value="$(printf "certain\nhighly likely\nlikely\npossible\nunlikely\nhighly unlikely\nremote\nimpossible" | dmenu -i -l 8 -p "confidence:")"
[[ -z "$new_value" ]] && return
sql "UPDATE $type SET confidence='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
notify "Confidence: $new_value"
;;
importance)
new_value="$(seq 1 10 | dmenu -i -l 10 -p "importance:")"
[[ -z "$new_value" ]] && return
sql "UPDATE $type SET importance=$new_value, updated_at=datetime('now') WHERE slug='$slug'"
notify "Importance: $new_value"
;;
state)
new_value="$(printf "active\nhidden" | dmenu -i -l 2 -p "state:")"
[[ -z "$new_value" ]] && return
sql "UPDATE $type SET state='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
notify "State: $new_value"
;;
esac
}
# Main loop — keep editing until user cancels
type="$(select_type)"
[[ -z "$type" ]] && exit 0
slug="$(select_entry "$type")"
[[ -z "$slug" ]] && exit 0
while true; do
field="$(select_field "$type")"
[[ -z "$field" ]] && break
edit_field "$type" "$slug" "$field"
done