Compare commits
2 Commits
feat/aw-po
...
claude/iss
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad41d3eef7 | ||
| cbcad273ef |
55
404.html
Normal file
55
404.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Lost in the Tower</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #0a0a0f;
|
||||
color: #e0d8c8;
|
||||
font-family: Georgia, 'Times New Roman', serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
font-weight: normal;
|
||||
letter-spacing: 0.15em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 1.5rem;
|
||||
color: #8a7f6a;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.9rem;
|
||||
color: #6a6050;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #8a7f6a;
|
||||
text-decoration: none;
|
||||
padding: 0.8rem 2rem;
|
||||
border: 1px solid #2a2520;
|
||||
transition: border-color 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
border-color: #8a7f6a;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Lost in the Tower</h1>
|
||||
<p>This room doesn't exist.</p>
|
||||
<a href="/">Return to the Entry Hall</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,7 +4,7 @@
|
||||
<link href="https://alexanderwhitestone.com/blog/"/>
|
||||
<link rel="self" href="https://alexanderwhitestone.com/blog/feed.xml"/>
|
||||
<id>https://alexanderwhitestone.com/blog/</id>
|
||||
<updated>2026-03-19T01:42:22Z</updated>
|
||||
<updated>2026-03-19T01:45:33Z</updated>
|
||||
<author>
|
||||
<name>Alexander Whitestone</name>
|
||||
</author>
|
||||
|
||||
115
scripts/aw-post
115
scripts/aw-post
@@ -2,51 +2,104 @@
|
||||
# aw-post — Quick-post a scroll from the command line
|
||||
#
|
||||
# Usage:
|
||||
# aw-post "Title of the Post"
|
||||
# aw-post "Title" < body.md
|
||||
# echo "Post body here" | aw-post "Title"
|
||||
# aw-post "Title" # Create empty post, open for editing
|
||||
# aw-post "Title" < body.md # Pipe body from stdin
|
||||
# echo "Post body" | aw-post "Title" # Pipe body from stdin
|
||||
# aw-post --file thoughts.md # Post from a file (title from first line)
|
||||
# aw-post --from-x "Tweet text here" # Port an X/Twitter post
|
||||
#
|
||||
# Creates a new markdown file in blog/posts/ with frontmatter,
|
||||
# then rebuilds the blog index, post pages, and RSS feed.
|
||||
# Creates a markdown file in blog/posts/, rebuilds the blog.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BLOG_DIR="${REPO_DIR}/blog/posts"
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: aw-post \"Title of the Post\""
|
||||
echo " Pipe or redirect body content via stdin."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TITLE="$1"
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
SLUG=$(echo "$TITLE" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-')
|
||||
FILENAME="${DATE}-${SLUG}.md"
|
||||
FILEPATH="${BLOG_DIR}/${FILENAME}"
|
||||
|
||||
if [ -f "$FILEPATH" ]; then
|
||||
echo "Error: $FILEPATH already exists"
|
||||
exit 1
|
||||
fi
|
||||
slugify() {
|
||||
echo "$1" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-' | head -c 60
|
||||
}
|
||||
|
||||
# Read body from stdin if available
|
||||
BODY=""
|
||||
if [ ! -t 0 ]; then
|
||||
BODY=$(cat)
|
||||
fi
|
||||
create_post() {
|
||||
local title="$1"
|
||||
local body="$2"
|
||||
local slug
|
||||
slug=$(slugify "$title")
|
||||
local filename="${DATE}-${slug}.md"
|
||||
local filepath="${BLOG_DIR}/${filename}"
|
||||
|
||||
cat > "$FILEPATH" << EOF
|
||||
if [ -f "$filepath" ]; then
|
||||
echo "Error: $filepath already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat > "$filepath" << EOF
|
||||
---
|
||||
title: "${TITLE}"
|
||||
title: "${title}"
|
||||
date: ${DATE}
|
||||
---
|
||||
|
||||
${BODY}
|
||||
${body}
|
||||
EOF
|
||||
|
||||
echo "Created: ${FILEPATH}"
|
||||
echo "Created: ${filepath}"
|
||||
python3 "${REPO_DIR}/scripts/build.py"
|
||||
}
|
||||
|
||||
# Rebuild the blog
|
||||
python3 "${REPO_DIR}/scripts/build.py"
|
||||
# Parse arguments
|
||||
case "${1:-}" in
|
||||
--file)
|
||||
# Post from a file — title from first non-empty line
|
||||
if [ -z "${2:-}" ] || [ ! -f "${2:-}" ]; then
|
||||
echo "Usage: aw-post --file <path-to-markdown>"
|
||||
exit 1
|
||||
fi
|
||||
BODY=$(cat "$2")
|
||||
# Extract title: first line starting with # or first non-empty line
|
||||
TITLE=$(echo "$BODY" | grep -m1 '^#' | sed 's/^#* *//' || echo "$BODY" | grep -m1 '.' || echo "Untitled")
|
||||
if [ -z "$TITLE" ]; then
|
||||
TITLE="Untitled"
|
||||
fi
|
||||
# Strip the title line from body if it was a markdown header
|
||||
BODY=$(echo "$BODY" | sed '1{/^#/d;}')
|
||||
create_post "$TITLE" "$BODY"
|
||||
;;
|
||||
|
||||
--from-x)
|
||||
# Port an X/Twitter post — the text becomes both title and body
|
||||
if [ -z "${2:-}" ]; then
|
||||
echo "Usage: aw-post --from-x \"Tweet text here\""
|
||||
exit 1
|
||||
fi
|
||||
TEXT="$2"
|
||||
# Title: first 60 chars, cleaned up
|
||||
TITLE=$(echo "$TEXT" | head -1 | cut -c1-60 | sed 's/[[:space:]]*$//')
|
||||
create_post "$TITLE" "$TEXT"
|
||||
;;
|
||||
|
||||
--help|-h)
|
||||
echo "aw-post — Quick-post a scroll to The Scrolls"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " aw-post \"Title\" Create a post (body from stdin)"
|
||||
echo " aw-post --file thoughts.md Post from a markdown file"
|
||||
echo " aw-post --from-x \"Tweet text\" Port an X/Twitter post"
|
||||
echo " aw-post --help Show this help"
|
||||
;;
|
||||
|
||||
"")
|
||||
echo "Usage: aw-post \"Title of the Post\""
|
||||
echo " See: aw-post --help"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
# Standard mode: title as arg, body from stdin
|
||||
TITLE="$1"
|
||||
BODY=""
|
||||
if [ ! -t 0 ]; then
|
||||
BODY=$(cat)
|
||||
fi
|
||||
create_post "$TITLE" "$BODY"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
<p><a href="/">← Back to the Tower</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Reject unknown sub-paths: only /world/ is valid -->
|
||||
<script>
|
||||
(function() {
|
||||
var path = window.location.pathname.replace(/\/+$/, '') || '/';
|
||||
if (path !== '/world') {
|
||||
window.location.replace('/404.html');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<!-- Three.js scene will mount to #scene -->
|
||||
<!-- <script type="module" src="main.js"></script> -->
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user