| 1 |
#!/usr/bin/env bash
|
| 2 |
set -eu
|
| 3 |
|
| 4 |
TPL=template.html
|
| 5 |
OUT=public
|
| 6 |
YT="https://www.youtube.com/@tony-btw"
|
| 7 |
GH="https://github.com/tonybanters"
|
| 8 |
|
| 9 |
fm() { awk 'NR==1&&$0=="---"{f=1;next} f&&$0=="---"{exit} f' "$1"; }
|
| 10 |
field() { printf '%s\n' "$1" | sed -n "s/^$2: *//p" | head -1 | sed 's/^"//; s/"$//'; }
|
| 11 |
tagsof() { printf '%s\n' "$1" | sed -n 's/^tags: *//p' | head -1 | tr -d '[]"' | tr ',' ' '; }
|
| 12 |
esc() { printf '%s' "$1" | sed 's/&/\&/g; s/</\</g; s/>/\>/g'; }
|
| 13 |
fdate() { date -d "$1" +"%B %-d, %Y" 2>/dev/null || printf '%s' "$1"; }
|
| 14 |
tslug() { printf '%s' "$1" | tr 'A-Z' 'a-z' | sed 's/[^a-z0-9]\{1,\}/-/g; s/^-//; s/-$//'; }
|
| 15 |
|
| 16 |
render() { # out title section buffer showtitle(0|1) ; body on stdin
|
| 17 |
out=$1; title=$2; sec=$3; buf=$4; show=$5; extra=""
|
| 18 |
[ "$show" = 1 ] && extra="-M showtitle=true"
|
| 19 |
mkdir -p "$(dirname "$out")"
|
| 20 |
pandoc --template="$TPL" -s -M title="$title" -M section="$sec" -M buffer="$buf" $extra -o "$out"
|
| 21 |
}
|
| 22 |
|
| 23 |
tut_sorted() {
|
| 24 |
for f in content/tutorial/*/index.md; do
|
| 25 |
b=$(fm "$f"); printf '%s\t%s\n' "$(field "$b" date)" "$(basename "$(dirname "$f")")"
|
| 26 |
done | sort -r
|
| 27 |
}
|
| 28 |
comm_sorted() {
|
| 29 |
for f in content/community/*/index.md; do
|
| 30 |
b=$(fm "$f"); printf '%s\t%s\n' "$(field "$b" date)" "$(basename "$(dirname "$f")")"
|
| 31 |
done | sort -r
|
| 32 |
}
|
| 33 |
|
| 34 |
tut_card() {
|
| 35 |
f="content/tutorial/$1/index.md"; b=$(fm "$f")
|
| 36 |
img=$(field "$b" image); t=$(esc "$(field "$b" title)")
|
| 37 |
d=$(fdate "$(field "$b" date)"); desc=$(esc "$(field "$b" description)")
|
| 38 |
cat <<EOF
|
| 39 |
<div class="tutorial-card">
|
| 40 |
<a href="/tutorial/$1/"><img class="tutorial-card-image" src="$img" alt="$t" loading="lazy"></a>
|
| 41 |
<div class="tutorial-card-title"><a href="/tutorial/$1/">$t</a></div>
|
| 42 |
<div class="tutorial-card-date">$d</div>
|
| 43 |
<div class="tutorial-card-description">$desc</div>
|
| 44 |
</div>
|
| 45 |
EOF
|
| 46 |
}
|
| 47 |
|
| 48 |
comm_card() {
|
| 49 |
f="content/community/$1/index.md"; b=$(fm "$f")
|
| 50 |
t=$(esc "$(field "$b" title)"); d=$(fdate "$(field "$b" date)")
|
| 51 |
au=$(esc "$(field "$b" author)"); desc=$(esc "$(field "$b" description)")
|
| 52 |
tags=""
|
| 53 |
for tg in $(tagsof "$b"); do
|
| 54 |
tags="$tags<a class=\"ctag\" href=\"/tags/$(tslug "$tg")/\">$(esc "$tg")</a> "
|
| 55 |
done
|
| 56 |
cat <<EOF
|
| 57 |
<div class="tutorial-card">
|
| 58 |
<div class="tutorial-card-title"><a href="/community/$1/">$t</a></div>
|
| 59 |
<div class="tutorial-card-date">by $au · $d</div>
|
| 60 |
<div class="tutorial-card-description">$desc</div>
|
| 61 |
<div class="card-tags">$tags</div>
|
| 62 |
</div>
|
| 63 |
EOF
|
| 64 |
}
|
| 65 |
|
| 66 |
# ---------- home ----------
|
| 67 |
{
|
| 68 |
cat <<EOF
|
| 69 |
<section class="hero-section" style="padding:2rem 1rem;text-align:center;">
|
| 70 |
<h1 style="font-size:2.5rem;font-weight:800;margin-bottom:1rem;">Creating <span style="color:var(--cyn);">Quick and Painless</span> Linux Tutorials</h1>
|
| 71 |
<p style="font-size:1.2rem;max-width:700px;margin:0 auto 2rem auto;">My name is Tony, and I encourage you all to visit the command line and learn how to maneuver the CLI. Installing Linux distributions, window managers, text editors, and more will help you grow not only as a developer, but as a computer enthusiast.</p>
|
| 72 |
<div style="margin-top:1.5rem;">
|
| 73 |
<a href="$YT" class="btn-primary">YouTube Channel</a>
|
| 74 |
<a href="/support/" class="btn-outline" style="margin-left:1rem;">Support!</a>
|
| 75 |
<a href="$GH" class="btn-outline-secondary" style="margin-left:1rem;">Github</a>
|
| 76 |
</div>
|
| 77 |
</section>
|
| 78 |
<section style="margin-bottom:4rem;">
|
| 79 |
<h2 style="text-align:center;font-size:1.8rem;">Recent Tutorials</h2>
|
| 80 |
<p style="text-align:center;margin-bottom:2rem;">Stay tuned for new videos and writeups!</p>
|
| 81 |
<div class="recent-tutorials-grid">
|
| 82 |
EOF
|
| 83 |
tut_sorted | head -3 | while IFS="$(printf '\t')" read -r d s; do tut_card "$s"; done
|
| 84 |
cat <<EOF
|
| 85 |
</div>
|
| 86 |
<div style="text-align:center;margin-top:2rem;"><a href="/tutorial/" class="btn-primary">Explore All Tutorials</a></div>
|
| 87 |
</section>
|
| 88 |
EOF
|
| 89 |
} | render "$OUT/index.html" "Tony, btw." home index 0
|
| 90 |
|
| 91 |
# ---------- tutorial list ----------
|
| 92 |
{
|
| 93 |
echo '<div class="tutorial-grid">'
|
| 94 |
tut_sorted | while IFS="$(printf '\t')" read -r d s; do tut_card "$s"; done
|
| 95 |
echo '</div>'
|
| 96 |
} | render "$OUT/tutorial/index.html" "Tutorials" tutorial index 1
|
| 97 |
|
| 98 |
# ---------- community list ----------
|
| 99 |
{
|
| 100 |
echo '<div class="tutorial-grid">'
|
| 101 |
comm_sorted | while IFS="$(printf '\t')" read -r d s; do comm_card "$s"; done
|
| 102 |
echo '</div>'
|
| 103 |
} | render "$OUT/community/index.html" "Community" community index 1
|
| 104 |
|
| 105 |
# ---------- support ----------
|
| 106 |
{
|
| 107 |
cat <<EOF
|
| 108 |
<div class="recent-tutorials-grid" style="margin-top:2rem;">
|
| 109 |
<div class="tutorial-card"><div class="tutorial-card-title">Subscribe on YouTube</div>
|
| 110 |
<div class="tutorial-card-description">Support the channel by subscribing — it's free and helps spread the word.</div>
|
| 111 |
<p style="margin-top:1rem;"><a class="btn-primary" href="$YT">Go to YouTube</a></p></div>
|
| 112 |
<div class="tutorial-card"><div class="tutorial-card-title">Donate via Square</div>
|
| 113 |
<div class="tutorial-card-description">Help keep the content flowing. Every contribution makes a difference.</div>
|
| 114 |
<p style="margin-top:1rem;"><a class="btn-outline" href="https://square.link/u/tC3glUCo">Donate via Square</a></p></div>
|
| 115 |
<div class="tutorial-card"><div class="tutorial-card-title">Support on Ko-Fi</div>
|
| 116 |
<div class="tutorial-card-description">Prefer Ko-Fi? Buy me a coffee and support future videos directly.</div>
|
| 117 |
<p style="margin-top:1rem;"><a class="btn-outline-secondary" href="https://ko-fi.com/tonybtw">Go to Ko-Fi</a></p></div>
|
| 118 |
</div>
|
| 119 |
EOF
|
| 120 |
} | render "$OUT/support/index.html" "Support the Channel" support index 1
|
| 121 |
|
| 122 |
# ---------- tags ----------
|
| 123 |
tagdir=$(mktemp -d)
|
| 124 |
for f in content/tutorial/*/index.md; do
|
| 125 |
b=$(fm "$f"); s=$(basename "$(dirname "$f")")
|
| 126 |
for tg in $(tagsof "$b"); do ts=$(tslug "$tg"); echo "tutorial:$s" >> "$tagdir/$ts"; echo "$tg" > "$tagdir/$ts.name"; done
|
| 127 |
done
|
| 128 |
for f in content/community/*/index.md; do
|
| 129 |
b=$(fm "$f"); s=$(basename "$(dirname "$f")")
|
| 130 |
for tg in $(tagsof "$b"); do ts=$(tslug "$tg"); echo "community:$s" >> "$tagdir/$ts"; echo "$tg" > "$tagdir/$ts.name"; done
|
| 131 |
done
|
| 132 |
|
| 133 |
index_body=$(mktemp)
|
| 134 |
echo '<div class="card-tags" style="font-size:1rem;">' > "$index_body"
|
| 135 |
for tf in "$tagdir"/*; do
|
| 136 |
case "$tf" in *.name) continue;; esac
|
| 137 |
ts=$(basename "$tf"); name=$(cat "$tagdir/$ts.name"); n=$(wc -l < "$tf")
|
| 138 |
printf '<a class="ctag" href="/tags/%s/">%s (%s)</a>\n' "$ts" "$(esc "$name")" "$n" >> "$index_body"
|
| 139 |
{
|
| 140 |
echo '<div class="tutorial-grid">'
|
| 141 |
while IFS= read -r entry; do
|
| 142 |
type=${entry%%:*}; sl=${entry#*:}
|
| 143 |
[ "$type" = tutorial ] && tut_card "$sl" || comm_card "$sl"
|
| 144 |
done < "$tf"
|
| 145 |
echo '</div>'
|
| 146 |
} | render "$OUT/tags/$ts/index.html" "#$name" tags "$ts.org" 1
|
| 147 |
done
|
| 148 |
echo '</div>' >> "$index_body"
|
| 149 |
render "$OUT/tags/index.html" "Tags" tags index 1 < "$index_body"
|
| 150 |
rm -rf "$tagdir" "$index_body"
|
| 151 |
|
| 152 |
echo "generated home, lists, support, tags"
|