Auto blog post addition.
This commit is contained in:
@@ -13,15 +13,76 @@
|
|||||||
"<nav>
|
"<nav>
|
||||||
<a href=\"/\">Home</a>
|
<a href=\"/\">Home</a>
|
||||||
<a href=\"/about.html\">About</a>
|
<a href=\"/about.html\">About</a>
|
||||||
|
<a href=\"/blog.html\">Blog</a>
|
||||||
</nav>")
|
</nav>")
|
||||||
|
|
||||||
|
(defun blog-extract-title (file)
|
||||||
|
"Extract #+TITLE: value from FILE."
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents file)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(if (re-search-forward "^#\\+TITLE:[ \t]*\\(.+\\)$" nil t)
|
||||||
|
(string-trim (match-string 1))
|
||||||
|
(file-name-base file))))
|
||||||
|
|
||||||
|
(defun blog-extract-excerpt (file &optional max-chars)
|
||||||
|
"Extract first body paragraph from FILE, up to MAX-CHARS characters."
|
||||||
|
(let ((max (or max-chars 250)))
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents file)
|
||||||
|
(goto-char (point-min))
|
||||||
|
;; Skip metadata lines and headings
|
||||||
|
(while (and (not (eobp))
|
||||||
|
(looking-at "^\\(#\\+\\|\\*\\|[ \t]*$\\)"))
|
||||||
|
(forward-line 1))
|
||||||
|
(let ((start (point)))
|
||||||
|
;; Collect lines until blank line or heading
|
||||||
|
(while (and (not (eobp))
|
||||||
|
(not (looking-at "^\\(\\*\\|[ \t]*$\\)")))
|
||||||
|
(forward-line 1))
|
||||||
|
(let ((text (string-trim (buffer-substring-no-properties start (point)))))
|
||||||
|
;; Collapse whitespace
|
||||||
|
(setq text (replace-regexp-in-string "[ \t\n]+" " " text))
|
||||||
|
(if (> (length text) max)
|
||||||
|
(concat (substring text 0 max) "...")
|
||||||
|
text))))))
|
||||||
|
|
||||||
|
(defun blog-generate-listings (_project)
|
||||||
|
"Scan content/blog/ and generate recent-posts.org and all-posts.org."
|
||||||
|
(let* ((blog-dir "./content/blog")
|
||||||
|
(gen-dir "./content/generated")
|
||||||
|
(pattern (concat blog-dir "/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-*.org"))
|
||||||
|
(files (sort (file-expand-wildcards pattern t)
|
||||||
|
(lambda (a b) (string> (file-name-base a)
|
||||||
|
(file-name-base b)))))
|
||||||
|
(make-entry
|
||||||
|
(lambda (file)
|
||||||
|
(let* ((base (file-name-base file))
|
||||||
|
(date (substring base 0 10))
|
||||||
|
(title (blog-extract-title file))
|
||||||
|
(excerpt (blog-extract-excerpt file))
|
||||||
|
(link (concat "file:../blog/" base ".org")))
|
||||||
|
(concat
|
||||||
|
"*[[" link "][" title "]]* — " date "\n\n"
|
||||||
|
excerpt "\n\n"
|
||||||
|
"[[" link "][Read more →]]\n\n"
|
||||||
|
"-----\n\n")))))
|
||||||
|
(make-directory gen-dir t)
|
||||||
|
(with-temp-file (concat gen-dir "/recent-posts.org")
|
||||||
|
(dolist (file (seq-take files 3))
|
||||||
|
(insert (funcall make-entry file))))
|
||||||
|
(with-temp-file (concat gen-dir "/all-posts.org")
|
||||||
|
(dolist (file files)
|
||||||
|
(insert (funcall make-entry file))))))
|
||||||
(setq org-publish-project-alist
|
(setq org-publish-project-alist
|
||||||
`(("site-pages"
|
`(("site-pages"
|
||||||
:base-directory "./content"
|
:base-directory "./content"
|
||||||
:base-extension "org"
|
:base-extension "org"
|
||||||
:publishing-directory "./public"
|
:publishing-directory "./public"
|
||||||
:recursive t
|
:recursive t
|
||||||
|
:exclude "generated/"
|
||||||
:publishing-function org-html-publish-to-html
|
:publishing-function org-html-publish-to-html
|
||||||
|
:preparation-function blog-generate-listings
|
||||||
:html-head-include-default-style nil
|
:html-head-include-default-style nil
|
||||||
:html-head-include-scripts nil
|
:html-head-include-scripts nil
|
||||||
:html-head "<link rel=\"stylesheet\" href=\"/style.css\"><script src=\"/animation.js\" defer></script>"
|
:html-head "<link rel=\"stylesheet\" href=\"/style.css\"><script src=\"/animation.js\" defer></script>"
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#+TITLE: Blog
|
||||||
|
#+DESCRIPTION: All blog posts
|
||||||
|
|
||||||
|
* All Posts
|
||||||
|
|
||||||
|
#+INCLUDE: generated/all-posts.org
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
* Recent Blog Posts
|
* Recent Blog Posts
|
||||||
|
|
||||||
- [[file:blog/post001.org][Nix Selfhosting in the Age of LLMs]]
|
#+INCLUDE: generated/recent-posts.org
|
||||||
|
|
||||||
* Contact me
|
* Contact me
|
||||||
|
|
||||||
|
|||||||
@@ -95,9 +95,37 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
new-post = pkgs.writeShellApplication {
|
||||||
|
name = "new-post";
|
||||||
|
runtimeInputs = [ pkgs.coreutils pkgs.gnused ];
|
||||||
|
text = ''
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Usage: new-post \"Post Title\""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
title="$*"
|
||||||
|
slug=$(echo "$title" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//;s/-$//')
|
||||||
|
date=$(date +%Y-%m-%d)
|
||||||
|
filename="content/blog/''${date}-''${slug}.org"
|
||||||
|
mkdir -p content/blog
|
||||||
|
cat > "$filename" <<EOF
|
||||||
|
#+TITLE: $title
|
||||||
|
#+DATE: $date
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
EOF
|
||||||
|
echo "Created: $filename"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
packages.default = site;
|
packages.default = site;
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
packages = [ new-post ];
|
||||||
|
};
|
||||||
|
|
||||||
apps = {
|
apps = {
|
||||||
default = {
|
default = {
|
||||||
type = "app";
|
type = "app";
|
||||||
|
|||||||
Reference in New Issue
Block a user