WIP: Wrap posts in an article tag

This commit is contained in:
Catalin Constantin Mititiuc 2025-06-16 20:18:04 -07:00
parent 48d3f807c9
commit 462a08d9dc
12 changed files with 192 additions and 122 deletions

43
command.moon Normal file
View File

@ -0,0 +1,43 @@
-- =========================================================================
-- capture output of a system command
-- =========================================================================
handle = io.popen "ls"
result = handle\read("*a")
print result
handle\close!
-- =========================================================================
-- how changing the config in the Site class works
-- =========================================================================
-- f = class Site, config: { "one" } -- simulate `f = require "sitegen.site"`
-- f.config = { "two" }
-- simulate `n = require "sitegen.site"`
-- n = f -- because it has already been required, it returns the existing `f`
-- n!
-- { v } = n.config
-- print v
-- =========================================================================
-- markdown link pseudo-protocols
-- =========================================================================
-- [what-is-this](class:asdf)
--
-- [reference link][blah]
--
-- [blah]: <https://example.com> "titlehere"
--
-- [App Platform](id:doesthiswork><https://example.com>)
--
-- > %class-one%
-- >
-- > Lorem ipsum...
--
-- [postoffice](class:caps "asdf")
--
-- [postoffice][caps]
--
-- [caps]: class:caps 'ALL UPPER CASE, ALL THE TIME'

View File

@ -1,7 +1,3 @@
{
id: "recursively-list-all-files-in-a-directory-with-elixir"
}
## Introduction ## Introduction
We wish to print a list of all the files in a directory, ignoring files beginning with certain characters, sorted alphabetically, with the directories last. We wish to print a list of all the files in a directory, ignoring files beginning with certain characters, sorted alphabetically, with the directories last.
@ -43,7 +39,6 @@ end
The data structure holding the results of the file search. The data structure holding the results of the file search.
```
iex(1)> directory_tree = Files.find("hello") iex(1)> directory_tree = Files.find("hello")
{"hello", {"hello",
[ [
@ -73,7 +68,6 @@ iex(1)> directory_tree = Files.find("hello")
["config.exs", "dev.exs", "test.exs", "prod.exs", "runtime.exs"]}, ["config.exs", "dev.exs", "test.exs", "prod.exs", "runtime.exs"]},
"mix.exs" "mix.exs"
]} ]}
```
## Sorting and printing ## Sorting and printing
@ -107,7 +101,6 @@ end
Print all the files sorted. Print all the files sorted.
```
iex(2)> Paths.puts(directory_tree) iex(2)> Paths.puts(directory_tree)
hello/mix.exs hello/mix.exs
hello/README.md hello/README.md
@ -129,7 +122,6 @@ hello/test/test_helper.exs
hello/test/hello_web/controllers/error_json_test.exs hello/test/hello_web/controllers/error_json_test.exs
hello/test/support/conn_case.ex hello/test/support/conn_case.ex
:ok :ok
```
## Conclusion ## Conclusion

View File

@ -1,14 +1,8 @@
{ {
id: "open-an-iex-shell-from-an-elixir-script"
title: "Open An IEx Shell From An Elixir Script" title: "Open An IEx Shell From An Elixir Script"
blurb: "We can run an Elixir script with either the <code>elixir</code> or the <code>iex</code> command. Both will execute the code, but the second command opens an interactive IEx shell afterward. What if, we won't know until runtime whether we want a shell or not? How can we start an IEx session even when we use <code>elixir</code>, instead of <code>iex</code>, to run our script?" blurb: "We can run an Elixir script with either the <code>elixir</code> or the <code>iex</code> command. Both will execute the code, but the second command opens an interactive IEx shell afterward. What if, we won't know until runtime whether we want a shell or not? How can we start an IEx session even when we use <code>elixir</code>, instead of <code>iex</code>, to run our script?"
} }
---
title: "Open An IEx Shell From An Elixir Script"
blurb: "We can run an Elixir script with either the <code>elixir</code> or the <code>iex</code> command. Both will execute the code, but the second command opens an interactive IEx shell afterward. What if, we won't know until runtime whether we want a shell or not? How can we start an IEx session even when we use <code>elixir</code>, instead of <code>iex</code>, to run our script?"
...
## Method 1 ## Method 1
Here's a quick test script: Here's a quick test script:

View File

@ -1,14 +1,8 @@
{ {
id: "start-erlangs-dialyzer-with-gui-from-a-docker-container"
title: "Start Erlang's Dialyzer With GUI From A Docker Container" title: "Start Erlang's Dialyzer With GUI From A Docker Container"
blurb: "Everything in OTP is command-line driven, so using containers during development has been without issue. But, Dialyzer, Erlang's static analysis tool, actually has a Graphical User Interface. How can we still use Dialyzer and its GUI even though Elixir is running inside a container?" blurb: "Everything in OTP is command-line driven, so using containers during development has been without issue. But, Dialyzer, Erlang's static analysis tool, actually has a Graphical User Interface. How can we still use Dialyzer and its GUI even though Elixir is running inside a container?"
} }
---
title: "Start Erlang's Dialyzer With GUI From A Docker Container"
blurb: "Everything in OTP is command-line driven, so using containers during development has been without issue. But, Dialyzer, Erlang's static analysis tool, actually has a Graphical User Interface. How can we still use Dialyzer and its GUI even though Elixir is running inside a container?"
...
I use Docker mostly when working on software projects and I figured out how to get Erlang's Dialyzer GUI working in a Docker container. I use Docker mostly when working on software projects and I figured out how to get Erlang's Dialyzer GUI working in a Docker container.
1. Start a container with X11 forwarding: 1. Start a container with X11 forwarding:

View File

@ -1,12 +1,7 @@
{ {
id: "fix-distortion-introduced-when-transforming-multiview-projections-to-isometric"
blurb: "One thing we learned from a week of trying to make isometric vector drawings." blurb: "One thing we learned from a week of trying to make isometric vector drawings."
} }
---
blurb: "One thing we learned from a week of trying to make isometric vector drawings."
...
## Objective ## Objective
Construct an isometric vector image of an object from top, front, and side view projections (like [this](https://workforce.libretexts.org/Bookshelves/Drafting_and_Design_Technology/Introduction_to_Drafting_and_AutoCAD_3D_(Baumback)/02%3A_Part_2/2.01%3A_Module_7-_Visualizing_Multiview_Drawings), but using Inkscape instead of AutoCAD). Construct an isometric vector image of an object from top, front, and side view projections (like [this](https://workforce.libretexts.org/Bookshelves/Drafting_and_Design_Technology/Introduction_to_Drafting_and_AutoCAD_3D_(Baumback)/02%3A_Part_2/2.01%3A_Module_7-_Visualizing_Multiview_Drawings), but using Inkscape instead of AutoCAD).

View File

@ -1,14 +1,8 @@
{ {
id: "deploy-elixir-generated-html-with-docker-on-digitalocean"
title: "Deploy Elixir-Generated HTML With Docker On DigitalOcean" title: "Deploy Elixir-Generated HTML With Docker On DigitalOcean"
blurb: "This is a simple proof of concept where we create a boilerplate HTML file with Elixir, containerize our build process with Docker, and deploy our markup live with DigitalOcean's hosting service." blurb: "This is a simple proof of concept where we create a boilerplate HTML file with Elixir, containerize our build process with Docker, and deploy our markup live with DigitalOcean's hosting service."
} }
---
title: "Deploy Elixir-Generated HTML With Docker On DigitalOcean"
blurb: "This is a simple proof of concept where we create a boilerplate HTML file with Elixir, containerize our build process with Docker, and deploy our markup live with DigitalOcean's hosting service."
...
## Introduction ## Introduction
DigitalOcean has this [App Platform](https://www.digitalocean.com/products/app-platform) service that can host a static website, as well as build it from a Docker image, if provided a `Dockerfile`. We thought a static website built by an Elixir app could be an instructive project. To explore if the idea is viable, we wrote a small Elixir application that generates a simple `index.html` file and deployed it live on DigitalOcean's service. DigitalOcean has this [App Platform](https://www.digitalocean.com/products/app-platform) service that can host a static website, as well as build it from a Docker image, if provided a `Dockerfile`. We thought a static website built by an Elixir app could be an instructive project. To explore if the idea is viable, we wrote a small Elixir application that generates a simple `index.html` file and deployed it live on DigitalOcean's service.

View File

@ -1,14 +1,8 @@
{ {
id: "test-mix-task-file-modify"
title: "Temporary Directories For Testing Mix Tasks That Modify Files" title: "Temporary Directories For Testing Mix Tasks That Modify Files"
blurb: "Writing a test for a simple Mix task gets surprisingly complex. Application environment variables, temporary test directories, and IO capture are all involved." blurb: "Writing a test for a simple Mix task gets surprisingly complex. Application environment variables, temporary test directories, and IO capture are all involved."
} }
---
title: "Temporary Directories For Testing Mix Tasks That Modify Files"
blurb: "Writing a test for a simple Mix task gets surprisingly complex. Application environment variables, temporary test directories, and IO capture are all involved."
...
## Intro ## Intro
Last time, we added a Mix task to our project that writes an HTML file to a directory `/public` in the container's filesystem. Today, we will write a test for that task. Last time, we added a Mix task to our project that writes an HTML file to a directory `/public` in the container's filesystem. Today, we will write a test for that task.

View File

@ -1,15 +1,9 @@
{ {
id: "build-static-website-generator-part-1"
title: "Build A Static-Website Generator With Elixir, Part 1" title: "Build A Static-Website Generator With Elixir, Part 1"
blurb: "We take the first steps in designing and implementing the \"world's simplest static-website generator\". Building on tools and knowledge we acquired previously, and utilizing an incremental and iterative development process, we go through the entire software life-cycle from creating the initial project files to deploying to production. We spare nothing, from spelling out every command, to ensuring application integrity with tests, and even updating the README file. Grab a drink and some snacks, and dive right in!" blurb: "We take the first steps in designing and implementing the \"world's simplest static-website generator\". Building on tools and knowledge we acquired previously, and utilizing an incremental and iterative development process, we go through the entire software life-cycle from creating the initial project files to deploying to production. We spare nothing, from spelling out every command, to ensuring application integrity with tests, and even updating the README file. Grab a drink and some snacks, and dive right in!"
} }
--- <div class="info">$markdown{[[
title: "Build A Static-Website Generator With Elixir, Part 1"
blurb: "We take the first steps in designing and implementing the \"world's simplest static-website generator\". Building on tools and knowledge we acquired previously, and utilizing an incremental and iterative development process, we go through the entire software life-cycle from creating the initial project files to deploying to production. We spare nothing, from spelling out every command, to ensuring application integrity with tests, and even updating the README file. Grab a drink and some snacks, and dive right in!"
...
::: info
This post was originally intended to be the first in a multi-part series. This post was originally intended to be the first in a multi-part series.
However, the deeper we got into this project, the more we realized we were However, the deeper we got into this project, the more we realized we were
basically implementing our own version of a web framework. Rather than basically implementing our own version of a web framework. Rather than
@ -18,7 +12,7 @@ framework, [Phoenix](https://www.phoenixframework.org/), and simply added a
Markdown-to-HTML conversion feature. As a consequence, there are no other parts Markdown-to-HTML conversion feature. As a consequence, there are no other parts
to this post, but a description of the solution we chose instead can be found to this post, but a description of the solution we chose instead can be found
[here](/posts/publish-markdown-documents-as-static-web-pages-with-pandoc-and-phoenix). [here](/posts/publish-markdown-documents-as-static-web-pages-with-pandoc-and-phoenix).
::: ]]}</div>
This is one of our longer posts, so we've included a table of contents. This is one of our longer posts, so we've included a table of contents.

View File

@ -1,27 +1,35 @@
date = require "date" date = require "date"
path = require "sitegen.path" path = require "sitegen.path"
moon = require("moon") -- import slugify from "sitegen.common"
common = require("sitegen.common") common = require "sitegen.common"
rootname = (str) ->
result = string.gsub str, "%..+", ""
result
extract_id = (source) -> string.match path.filename(source), "%a[%w%-]+"
extract_date = (source) -> string.match path.filename(source), "%d+%-%d%d%-%d%d" extract_date = (source) -> string.match path.filename(source), "%d+%-%d%d%-%d%d"
format_date = (str) -> date(str)\fmt "%b %d, %Y" format_date = (str) -> date(str)\fmt "%b %d, %Y"
publish_date = (path) -> format_date extract_date path publish_date = (path) -> format_date extract_date path
posts = [{ pages = site\query_pages { is_a: "post" }
id: p.meta.id table.sort pages, (a, b) -> a.source > b.source
tgt: p.meta.target
src: p.source
title: p.meta.title or p.meta.id
blurb: p.meta.blurb
} for _, p in pairs site.pages when p.meta.template == "blog"]
table.sort posts, (a, b) -> a.src > b.src
html -> html ->
[tag["section"] { [tag["section"] {
tag["h3"] { tag["a"] { href: p.tgt .. ".html", p.title }} tag["h3"] {
tag["time"] { publish_date p.src } tag["a"] {
{"—", if p.blurb then text(p.blurb)} href: p.meta.target .. ".html",
tag["a"] { class: "read-post-link", href: p.tgt .. ".html", "Read post →"} p.meta.title or p.meta.id
} for _, p in ipairs posts] }
}
tag["time"] { publish_date p.source }
{ "—", if p.meta.blurb then text p.meta.blurb }
tag["a"] {
class: "read-post-link",
href: p.meta.target .. ".html",
"Read post →"
}
} for _, p in ipairs pages]

View File

@ -3,6 +3,11 @@ tools = require "sitegen.tools"
site = require "sitegen.site" site = require "sitegen.site"
lfs = require "lfs" lfs = require "lfs"
date = require "date"
path = require "sitegen.path"
-- import slugify from "sitegen.common"
common = require "sitegen.common"
rootname = (str) -> rootname = (str) ->
result = string.gsub str, "%..+", "" result = string.gsub str, "%..+", ""
result result
@ -22,7 +27,7 @@ posts = (path=".") ->
-- site = site! -- site = site!
site.config.out_dir = "html/" site.config.out_dir = "html/"
css = tools.system_command "cat < %s > %s", "css" css = tools.system_command "cp %s %s", "css"
ps = posts("docs") ps = posts("docs")
@ -49,8 +54,27 @@ one = () ->
tag.a { href: "momo", "yayaya" } tag.a { href: "momo", "yayaya" }
tag.a { href: "momo", "yayaya" } tag.a { href: "momo", "yayaya" }
require("sitegen.renderers.markdown").render = (page, md_source) =>
discount = require "discount"
md_source = page\pipe "renderer.markdown.pre_render", md_source
md_source, escapes = escape_cosmo md_source
html_source = assert discount md_source
html_source = unescape_cosmo html_source, escapes
print("DDDDDDDDDDDDDD")
super page, html_source
-- require("moon").p require("sitegen.renderers.markdown")
extract_id = (source) -> string.match path.filename(source), "%a[%w%-]+"
extract_date = (source) -> string.match path.filename(source), "%d+%-%d%d%-%d%d"
format_date = (str) -> date(str)\fmt "%b %d, %Y"
publish_date = (path) -> format_date extract_date path
sitegen.create => sitegen.create =>
@title = "WebDevCat.me · Catalin Mititiuc" @site_title = "WebDevCat.me · Catalin Mititiuc"
@app_name = "stasis" @app_name = "stasis"
@version = "0.2.12" @version = "0.2.12"
@val = "yes" @val = "yes"
@ -82,21 +106,44 @@ sitegen.create =>
-- require("moon").p get_site -- require("moon").p get_site
@test = (page) -> {{"b": 1, "c": 2}, {"d": 3, "e": 4}} @test = (page) -> {{"b": 1, "c": 2}, {"d": 3, "e": 4}}
@what = (page) -> @what = (page) ->
page
-- require("moon").p [{ln, lv} for ln, lv in pairs debug.getlocal(2, idx)] -- require("moon").p [{ln, lv} for ln, lv in pairs debug.getlocal(2, idx)]
-- require("moon").p -- require("moon").p
"what?"
-- require("moon").p @ -- require("moon").p @
-- require("moon").p @site -- @what = (page) =>
-- require("moon").p @
-- require("moon").p site.pages
-- @what!
add "index.html", o: one add "index.html", o: one
add path, target: out, template: "blog" for path, out in pairs posts "docs" add path, target: out, template: "blog", is_a: "post", post: {
-- add "test.html", id: "test" publish_date: publish_date(path)
}, id: extract_id(path) for path, out in pairs posts "docs"
add "test.html", id: "test"
-- feed "posts.moon", "feed.xml" -- feed "posts.moon", "feed.xml"
-- require("moon").p site -- require("moon").p site
build css, "app.css" -- build css, "app.css"
copy "app.css"
-- require("moon").p site -- filter "docs", (body) =>
-- require("moon").p body
-- require("moon").p search "start", "docs"
-- filter "2023%-08%-03", (body) =>
-- table.concat { body, "<p>hey there</p>" }
-- require("moon").p body
-- body\gsub "<h1>.-</h1>", (header) ->
-- table.concat { body, "yoyoasdf" }
-- body .. "yoyo"
-- body\gsub "{.-}", (header) ->
-- require("moon").p header
-- table.concat { '</div>', header, '<div class="main">' }

View File

@ -1,4 +1,6 @@
$render{"templates/root"} <h2><code>templates/blog.html</code></h2>
$wrap{"root"}
<section> <section>
<h2><a href="$root/posts/">Web Log</a></h2> <h2><a href="$root/posts/">Web Log</a></h2>
@ -8,4 +10,17 @@ $render{"templates/root"}
</p> </p>
</section> </section>
<article>
<header>
<div>
<h2>$(title or id)</h2>
<time>$(post.publish_date)</time>
</div>
</header>
$body $body
<div class="mt-16">
<a href="/posts">Back to posts</a>
</div>
</article>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>$title</title> <title>$site_title</title>
<link <link
rel="stylesheet" rel="stylesheet"
id="font-bitter-css" id="font-bitter-css"