@@ -0,0 +1,227 @@
1+#!/usr/bin/env bash
2+set -euo pipefail
3+
4+# Inputs (set by Nix derivation):
5+# $src - user's site source directory
6+# $out - Nix output path
7+# $layoutsDir - path to our default layouts
8+# $themeDir - path to our theme directory
9+
10+tmpdir=$(mktemp -d)
11+trap 'rm -rf "$tmpdir"' EXIT
12+
13+mkdir -p "$out"
14+
15+# --- Step 1: Generate manifest from site.dhall ---
16+echo "Generating site manifest..."
17+manifest="$tmpdir/manifest.json"
18+dhall-to-json --file "$src/site.dhall" > "$manifest"
19+
20+# --- Step 2: Extract site metadata ---
21+siteTitle=$(jq -r '.title' "$manifest")
22+baseUrl=$(jq -r '.baseUrl' "$manifest")
23+description=$(jq -r '.description' "$manifest")
24+
25+# --- Step 3: Render nav HTML ---
26+navHtmlFile="$tmpdir/nav.txt"
27+jq -r '.nav[] | "<a href=\"\(.url)\">\(.label)</a>"' "$manifest" \
28+ | tr '\n' ' ' > "$navHtmlFile"
29+
30+# --- Helper: render content ---
31+render_content() {
32+ local content_json="$1"
33+ local content_type content_value
34+ content_type=$(echo "$content_json" | jq -r '.tag')
35+ content_value=$(echo "$content_json" | jq -r '.value')
36+
37+ case "$content_type" in
38+ File)
39+ pandoc "$src/$content_value" -f markdown -t html --no-highlight
40+ ;;
41+ Inline)
42+ echo "$content_value" | pandoc -f markdown -t html --no-highlight
43+ ;;
44+ DhallHtml)
45+ dhall text --file "$src/$content_value"
46+ ;;
47+ *)
48+ echo "Unknown content type: $content_type" >&2
49+ exit 1
50+ ;;
51+ esac
52+}
53+
54+# --- Helper: format date ---
55+format_date() {
56+ local date_json="$1"
57+ local year month day
58+ year=$(echo "$date_json" | jq -r '.year')
59+ month=$(echo "$date_json" | jq -r '.month')
60+ day=$(echo "$date_json" | jq -r '.day')
61+ printf "%04d-%02d-%02d" "$year" "$month" "$day"
62+}
63+
64+# --- Helper: render tags HTML ---
65+render_tags() {
66+ local tags_json="$1"
67+ local count
68+ count=$(echo "$tags_json" | jq -r 'length')
69+ if [ "$count" -eq 0 ]; then
70+ echo ""
71+ return
72+ fi
73+ local result='<ul class="tags">'
74+ while IFS= read -r tag; do
75+ result+="<li>$tag</li>"
76+ done < <(echo "$tags_json" | jq -r '.[]')
77+ result+='</ul>'
78+ echo "$result"
79+}
80+
81+# --- Helper: apply a Dhall layout ---
82+apply_layout() {
83+ local layout_file="$1"
84+ local args_file="$2"
85+ dhall text <<DHALL
86+let layout = $layout_file
87+let args = $args_file
88+in layout args
89+DHALL
90+}
91+
92+# --- Step 4: Build pages ---
93+echo "Building pages..."
94+page_count=$(jq -r '.pages | length' "$manifest")
95+for ((i = 0; i < page_count; i++)); do
96+ page_json=$(jq -r ".pages[$i]" "$manifest")
97+ pageTitle=$(echo "$page_json" | jq -r '.title')
98+ pageSlug=$(echo "$page_json" | jq -r '.slug')
99+ content_json=$(echo "$page_json" | jq -r '.content')
100+
101+ echo " Page: $pageTitle ($pageSlug)"
102+
103+ contentFile="$tmpdir/content.txt"
104+ render_content "$content_json" > "$contentFile"
105+
106+ echo -n "$siteTitle" > "$tmpdir/siteTitle.txt"
107+ echo -n "$pageTitle" > "$tmpdir/pageTitle.txt"
108+
109+ argsFile="$tmpdir/args.dhall"
110+ cat > "$argsFile" <<DHALL
111+{ siteTitle = $tmpdir/siteTitle.txt as Text
112+, pageTitle = $tmpdir/pageTitle.txt as Text
113+, navHtml = $navHtmlFile as Text
114+, contentHtml = $contentFile as Text
115+}
116+DHALL
117+
118+ outDir="$out/$pageSlug"
119+ mkdir -p "$outDir"
120+ apply_layout "$layoutsDir/page.dhall" "$argsFile" > "$outDir/index.html"
121+done
122+
123+# --- Step 5: Build posts ---
124+echo "Building posts..."
125+post_count=$(jq -r '.posts | length' "$manifest")
126+postsHtmlFile="$tmpdir/posts_list.txt"
127+rssItemsFile="$tmpdir/rss_items.txt"
128+> "$postsHtmlFile"
129+> "$rssItemsFile"
130+
131+for ((i = 0; i < post_count; i++)); do
132+ post_json=$(jq -r ".posts[$i]" "$manifest")
133+ draft=$(echo "$post_json" | jq -r '.draft')
134+
135+ if [ "$draft" = "true" ]; then
136+ continue
137+ fi
138+
139+ postTitle=$(echo "$post_json" | jq -r '.title')
140+ postSlug=$(echo "$post_json" | jq -r '.slug')
141+ content_json=$(echo "$post_json" | jq -r '.content')
142+ date_json=$(echo "$post_json" | jq -r '.date')
143+ tags_json=$(echo "$post_json" | jq -r '.tags')
144+ dateStr=$(format_date "$date_json")
145+
146+ echo " Post: $postTitle ($postSlug)"
147+
148+ contentFile="$tmpdir/content.txt"
149+ render_content "$content_json" > "$contentFile"
150+
151+ tagsFile="$tmpdir/tags.txt"
152+ render_tags "$tags_json" > "$tagsFile"
153+
154+ echo -n "$siteTitle" > "$tmpdir/siteTitle.txt"
155+ echo -n "$postTitle" > "$tmpdir/postTitle.txt"
156+ echo -n "$dateStr" > "$tmpdir/dateStr.txt"
157+
158+ argsFile="$tmpdir/args.dhall"
159+ cat > "$argsFile" <<DHALL
160+{ siteTitle = $tmpdir/siteTitle.txt as Text
161+, postTitle = $tmpdir/postTitle.txt as Text
162+, dateStr = $tmpdir/dateStr.txt as Text
163+, tagsHtml = $tagsFile as Text
164+, navHtml = $navHtmlFile as Text
165+, contentHtml = $contentFile as Text
166+}
167+DHALL
168+
169+ outDir="$out/posts/$postSlug"
170+ mkdir -p "$outDir"
171+ apply_layout "$layoutsDir/post.dhall" "$argsFile" > "$outDir/index.html"
172+
173+ cat >> "$postsHtmlFile" <<HTML
174+<article class="post-summary">
175+ <h2><a href="/posts/$postSlug/">$postTitle</a></h2>
176+ <time>$dateStr</time>
177+</article>
178+HTML
179+
180+ contentForRss=$(cat "$contentFile")
181+ cat >> "$rssItemsFile" <<XML
182+<item>
183+ <title>$postTitle</title>
184+ <link>$baseUrl/posts/$postSlug/</link>
185+ <guid>$baseUrl/posts/$postSlug/</guid>
186+ <pubDate>$dateStr</pubDate>
187+ <description><![CDATA[$contentForRss]]></description>
188+</item>
189+XML
190+done
191+
192+# --- Step 6: Build index page ---
193+echo "Building index page..."
194+echo -n "$siteTitle" > "$tmpdir/siteTitle.txt"
195+echo -n "$description" > "$tmpdir/description.txt"
196+
197+argsFile="$tmpdir/args.dhall"
198+cat > "$argsFile" <<DHALL
199+{ siteTitle = $tmpdir/siteTitle.txt as Text
200+, description = $tmpdir/description.txt as Text
201+, navHtml = $navHtmlFile as Text
202+, postsHtml = $postsHtmlFile as Text
203+}
204+DHALL
205+
206+apply_layout "$layoutsDir/index.dhall" "$argsFile" > "$out/index.html"
207+
208+# --- Step 7: Build RSS feed ---
209+echo "Building RSS feed..."
210+echo -n "$baseUrl" > "$tmpdir/baseUrl.txt"
211+
212+argsFile="$tmpdir/args.dhall"
213+cat > "$argsFile" <<DHALL
214+{ siteTitle = $tmpdir/siteTitle.txt as Text
215+, baseUrl = $tmpdir/baseUrl.txt as Text
216+, description = $tmpdir/description.txt as Text
217+, itemsXml = $rssItemsFile as Text
218+}
219+DHALL
220+
221+apply_layout "$layoutsDir/rss.dhall" "$argsFile" > "$out/rss.xml"
222+
223+# --- Step 8: Copy theme ---
224+echo "Copying theme..."
225+cp "$themeDir/style.css" "$out/style.css"
226+
227+echo "Build complete!"