diff --git a/awk/definition_lists.awk b/awk/definition_lists.awk new file mode 100644 index 0000000..13ed75d --- /dev/null +++ b/awk/definition_lists.awk @@ -0,0 +1,62 @@ +BEGIN { + in_dl = 0 + has_prev = 0 + prev_line = "" + in_pre = 0 +} +{ + if ($0 ~ /^
/) {
+ if (!in_pre) in_pre = 1
+ }
+
+ if (!in_pre && $0 ~ /^:[ \t]+[^ \t]/) {
+ if (!in_dl) {
+ in_dl = 1
+ print "/) in_pre = 1
+ if (!in_pre) {
+ code_count = 0
+ line = $0
+ out = ""
+ while (match(line, /[^<]*<\/code>/)) {
+ code_count++
+ code_store[code_count] = substr(line, RSTART, RLENGTH)
+ out = out substr(line, 1, RSTART - 1) "\034EC" code_count "\034"
+ line = substr(line, RSTART + RLENGTH)
+ }
+ out = out line
+
+ for (sc in map) {
+ if (index(out, sc)) {
+ gsub(sc, map[sc], out)
+ }
+ }
+
+ for (i = 1; i <= code_count; i++) {
+ gsub("\034EC" i "\034", code_store[i], out)
+ }
+ $0 = out
+ }
+ if ($0 ~ /<\/pre>/) in_pre = 0
+ print
+}
diff --git a/awk/footnotes.awk b/awk/footnotes.awk
new file mode 100644
index 0000000..79bd712
--- /dev/null
+++ b/awk/footnotes.awk
@@ -0,0 +1,51 @@
+BEGIN { fn_count = 0 }
+
+# Match [^id]: text
+/^\[\^[a-zA-Z0-9_-]+\]:/ {
+ id_start = index($0, "[^") + 2
+ id_end = index($0, "]:")
+ id = substr($0, id_start, id_end - id_start)
+ text = substr($0, id_end + 2)
+ # Trim leading space
+ sub(/^[ \t]+/, "", text)
+
+ fn_ids[++fn_count] = id
+ fn_texts[id] = text
+ next
+}
+
+{
+ lines[++line_count] = $0
+}
+
+END {
+ for (i = 1; i <= line_count; i++) {
+ line = lines[i]
+
+ for (j = 1; j <= fn_count; j++) {
+ id = fn_ids[j]
+ marker = "[^" id "]"
+ repl = "" id ""
+
+ while ((pos = index(line, marker)) > 0) {
+ line = substr(line, 1, pos - 1) repl substr(line, pos + length(marker))
+ }
+ }
+ print line
+ }
+
+ if (fn_count > 0) {
+ print "
"
+ print ""
+ print ""
+ for (j = 1; j <= fn_count; j++) {
+ id = fn_ids[j]
+ text = fn_texts[id]
+ print "- "
+ print "
" text " ↩
"
+ print " "
+ }
+ print "
"
+ print " "
+ }
+}
diff --git a/awk/markdown_inline.awk b/awk/markdown_inline.awk
index 66e7ee7..9b05a7a 100644
--- a/awk/markdown_inline.awk
+++ b/awk/markdown_inline.awk
@@ -230,5 +230,7 @@ function restore_html_tags(s, i, val) {
}
}
+ gsub(/"
in_p = 0
diff --git a/awk/toc.awk b/awk/toc.awk
new file mode 100644
index 0000000..c35e2e1
--- /dev/null
+++ b/awk/toc.awk
@@ -0,0 +1,50 @@
+BEGIN {
+ toc_str = "\n"
+ has_toc = 0
+}
+{
+ lines[++n] = $0
+ if ($0 ~ //) in_pre = 1
+ if (!in_pre && $0 ~ /\{\{TOC\}\}/) {
+ has_toc = 1
+ toc_lines[n] = 1
+ }
+ if ($0 ~ /<\/pre>/) in_pre = 0
+ if (match($0, /]*>/)) {
+ tag_len = RLENGTH
+ title_start = RSTART + tag_len
+ title_str = substr($0, title_start)
+ title_end = index(title_str, " 0) {
+ title = substr(title_str, 1, title_end - 1)
+ gsub(/<[^>]+>/, "", title)
+
+ # extract id
+ id_start = match($0, /id="[^"]*"/)
+ if (id_start > 0) {
+ id_str = substr($0, id_start + 4)
+ id_end = index(id_str, "\"")
+ id = substr(id_str, 1, id_end - 1)
+
+ # what tag? level
+ level = substr($0, match($0, /" title "\n"
+ } else if (level == "3") {
+ toc_str = toc_str "- " title "
\n"
+ }
+ }
+ }
+ }
+}
+END {
+ toc_str = toc_str "
"
+ for (i = 1; i <= n; i++) {
+ if (has_toc && toc_lines[i] && lines[i] ~ /^[[:space:]]*\{\{TOC\}\}[[:space:]]*$/) {
+ toc_lines[i] = 0 # Mark as processed if we want, but not strictly needed
+ sub(/\{\{TOC\}\}/, toc_str, lines[i])
+ }
+ print lines[i]
+ }
+}
diff --git a/kewt.sh b/kewt.sh
index 6928c6c..3633ab1 100755
--- a/kewt.sh
+++ b/kewt.sh
@@ -26,6 +26,8 @@ Options:
--version Show version information.
--from Source directory (default: site)
--to Output directory (default: out)
+ --watch, -w Watch for file changes and rebuild automatically.
+ --serve, -s [port] Start a local HTTP server after building (default port: 8000).
EOF
}
@@ -33,7 +35,8 @@ script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd)
awk_dir="$script_dir/awk"
KEWT_TMPDIR=$(mktemp -d "/tmp/kewt_run.XXXXXX")
-trap 'rm -rf "$KEWT_TMPDIR"' EXIT HUP INT TERM
+trap 'rm -rf "$KEWT_TMPDIR"' EXIT
+trap 'exit 0' HUP INT TERM
DEFAULT_CONF='title = "kewt"
style = "kewt"
@@ -59,6 +62,7 @@ base_url = ""
generate_feed = false
feed_file = "rss.xml"
posts_dir = ""
+posts_per_page = 12
custom_admonitions = ""'
DEFAULT_TMPL='
@@ -73,8 +77,10 @@ DEFAULT_TMPL='
+
{{HEADER_BRAND}}
+
@@ -201,8 +207,6 @@ update_site() {
exit 0
}
-
-
src=""
out=""
new_mode="false"
@@ -210,6 +214,8 @@ new_title=""
post_mode="false"
post_title=""
positional_count=0
+watch_mode="false"
+serve_mode="false"
while [ $# -gt 0 ]; do
case "$1" in
@@ -261,6 +267,16 @@ while [ $# -gt 0 ]; do
out="$2"
shift
;;
+ --watch|-w)
+ watch_mode="true"
+ ;;
+ --serve|-s)
+ serve_mode="true"
+ if [ $# -ge 2 ] && echo "$2" | grep -qE '^[0-9]+$'; then
+ serve_port="$2"
+ shift
+ fi
+ ;;
--*)
die "Unknown option: $1"
;;
@@ -427,6 +443,7 @@ base_url=""
generate_feed="false"
feed_file="rss.xml"
posts_dir=""
+posts_per_page="12"
custom_admonitions=""
load_config() {
@@ -479,6 +496,7 @@ load_config() {
generate_feed) generate_feed="$val" ;;
feed_file) feed_file="${val#/}" ;;
posts_dir) posts_dir="${val#/}" ;;
+ posts_per_page) posts_per_page="$val" ;;
custom_admonitions) custom_admonitions="$val" ;;
esac
done < "$1"
@@ -521,11 +539,13 @@ parse_frontmatter() {
fm_title=""
fm_date=""
fm_draft=""
+ fm_description=""
while IFS='=' read -r _fk _fv; do
case "$_fk" in
title) fm_title="$_fv" ;;
date) fm_date="$_fv" ;;
draft) fm_draft="$_fv" ;;
+ description) fm_description="$_fv" ;;
esac
done < "$_fm_out"
rm -f "$_fm_out"
@@ -721,6 +741,22 @@ render_markdown() {
fi
fi
+ head_extra_og=""
+ if [ -n "$fm_description" ]; then
+ head_extra_og="$head_extra_og
+ "
+ fi
+ og_url="${base_url%/}${current_url}"
+ head_extra_og="$head_extra_og
+ "
+
+ if [ -n "$head_extra" ]; then
+ head_extra="$head_extra
+ $head_extra_og"
+ else
+ head_extra="$head_extra_og"
+ fi
+
ENABLE_HEADER_LINKS="$enable_header_links" CUSTOM_ADMONITIONS="$custom_admonitions" MARKDOWN_SITE_ROOT="$src" MARKDOWN_FALLBACK_FILE="$script_dir/styles/$style.css" sh "$script_dir/markdown.sh" "$content_file" | AWK_CURRENT_URL="$current_url" AWK_TITLE="$page_title" AWK_NAV="$nav" AWK_FOOTER="$footer" AWK_STYLE_PATH="${style_path}${asset_version}" AWK_HEADER_BRAND="$header_brand" AWK_HEAD_EXTRA="$head_extra" awk -f "$awk_dir/render_template.awk" "$local_template"
}
@@ -736,6 +772,7 @@ needs_rebuild() {
return 1
}
+build_site() {
echo "Building site from '$src' to '$out'..."
eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while read -r dir; do
@@ -883,29 +920,94 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
fi
done
- if [ "$has_custom_index" = "true" ]; then
- awk '
- /^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ {
- while((getline line < "'"$temp_list"'") > 0) print line
- close("'"$temp_list"'")
- next
- }
- { print }
- ' "$dir/index.md" > "$temp_index"
- else
- cat "$temp_list" >> "$temp_index"
- fi
-
is_home="false"; [ "$dir" = "$src" ] && is_home="true"
target_url="/$rel_dir/index.html"
[ "$rel_dir" = "." ] && target_url="/index.html"
- do_rebuild="false"
- needs_rebuild "$dir" "$out_dir/index.html" && do_rebuild="true"
- [ "$has_custom_index" = "true" ] && needs_rebuild "$dir/index.md" "$out_dir/index.html" && do_rebuild="true"
+ num_items=$(wc -l < "$temp_list")
+ if [ "$is_posts_dir" = "true" ] && [ -n "$posts_per_page" ] && [ "$posts_per_page" -gt 0 ] && [ "$num_items" -gt "$posts_per_page" ]; then
+ num_pages=$(( (num_items + posts_per_page - 1) / posts_per_page ))
+ for p in $(seq 1 $num_pages); do
+ chunk_list="$KEWT_TMPDIR/chunk.md"
+ start_line=$(( (p - 1) * posts_per_page + 1 ))
+ tail -n +$start_line "$temp_list" | head -n "$posts_per_page" > "$chunk_list"
- if [ "$do_rebuild" = "true" ]; then
- render_markdown "$temp_index" "$is_home" "$target_url" > "$out_dir/index.html"
+ base_url_dir="$(dirname "$target_url")"
+ [ "$base_url_dir" = "/" ] && base_url_dir=""
+
+ nav_html=""
+ if [ "$p" -gt 1 ]; then
+ if [ "$p" -eq 2 ]; then
+ nav_html="$nav_html « Prev "
+ else
+ nav_html="$nav_html « Prev "
+ fi
+ fi
+ nav_html="$nav_html Page $p of $num_pages "
+ if [ "$p" -lt "$num_pages" ]; then
+ nav_html="$nav_html Next » "
+ fi
+ nav_html="$nav_html"
+
+ echo "" >> "$chunk_list"
+ echo "$nav_html" >> "$chunk_list"
+
+ temp_index_p="$KEWT_TMPDIR/index_p$p.md"
+ if [ "$has_custom_index" = "false" ]; then
+ display_dir="${rel_dir#.}"
+ [ -z "$display_dir" ] && display_dir="/"
+ echo "# Index of $display_dir" > "$temp_index_p"
+ echo "" >> "$temp_index_p"
+ else
+ : > "$temp_index_p"
+ fi
+
+ if [ "$has_custom_index" = "true" ]; then
+ awk '
+ /^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ {
+ while((getline line < "'"$chunk_list"'") > 0) print line
+ close("'"$chunk_list"'")
+ next
+ }
+ { print }
+ ' "$dir/index.md" >> "$temp_index_p"
+ else
+ cat "$chunk_list" >> "$temp_index_p"
+ fi
+
+ if [ "$p" -eq 1 ]; then
+ out_file="$out_dir/index.html"
+ target_url_p="$target_url"
+ else
+ out_file="$out_dir/page/$p/index.html"
+ target_url_p="$base_url_dir/page/$p/index.html"
+ mkdir -p "$(dirname "$out_file")"
+ fi
+
+ render_markdown "$temp_index_p" "$is_home" "$target_url_p" > "$out_file"
+ rm -f "$temp_index_p" "$chunk_list"
+ done
+ else
+ if [ "$has_custom_index" = "true" ]; then
+ awk '
+ /^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ {
+ while((getline line < "'"$temp_list"'") > 0) print line
+ close("'"$temp_list"'")
+ next
+ }
+ { print }
+ ' "$dir/index.md" > "$temp_index"
+ else
+ cat "$temp_list" >> "$temp_index"
+ fi
+
+ do_rebuild="false"
+ needs_rebuild "$dir" "$out_dir/index.html" && do_rebuild="true"
+ [ "$has_custom_index" = "true" ] && needs_rebuild "$dir/index.md" "$out_dir/index.html" && do_rebuild="true"
+
+ if [ "$do_rebuild" = "true" ]; then
+ render_markdown "$temp_index" "$is_home" "$target_url" > "$out_dir/index.html"
+ fi
fi
rm -f "$temp_index" "$temp_list"
fi
@@ -1053,18 +1155,22 @@ if [ "$generate_feed" = "true" ] && [ -n "$base_url" ]; then
rel_path="${rel_path#/}"
post_url="$base_url_feed/${rel_path%.md}.html"
- pub_year=$(echo "$post_date" | cut -d- -f1)
- pub_month=$(echo "$post_date" | cut -d- -f2)
- pub_day=$(echo "$post_date" | cut -d- -f3)
- # zero-padded
- pub_day=$(printf '%02d' "${pub_day#0}")
- case "$pub_month" in
- 01) pub_mon="Jan" ;; 02) pub_mon="Feb" ;; 03) pub_mon="Mar" ;;
- 04) pub_mon="Apr" ;; 05) pub_mon="May" ;; 06) pub_mon="Jun" ;;
- 07) pub_mon="Jul" ;; 08) pub_mon="Aug" ;; 09) pub_mon="Sep" ;;
- 10) pub_mon="Oct" ;; 11) pub_mon="Nov" ;; 12) pub_mon="Dec" ;;
- esac
- pub_date="${pub_day} ${pub_mon} ${pub_year} ${post_time}:00 +0000"
+ if date -u -d "$post_date $post_time" '+%a, %d %b %Y %H:%M:%S +0000' >/dev/null 2>&1; then
+ pub_date=$(date -u -d "$post_date $post_time" '+%a, %d %b %Y %H:%M:%S +0000')
+ else
+ pub_year=$(echo "$post_date" | cut -d- -f1)
+ pub_month=$(echo "$post_date" | cut -d- -f2)
+ pub_day=$(echo "$post_date" | cut -d- -f3)
+ # zero-padded
+ pub_day=$(printf '%02d' "${pub_day#0}")
+ case "$pub_month" in
+ 01) pub_mon="Jan" ;; 02) pub_mon="Feb" ;; 03) pub_mon="Mar" ;;
+ 04) pub_mon="Apr" ;; 05) pub_mon="May" ;; 06) pub_mon="Jun" ;;
+ 07) pub_mon="Jul" ;; 08) pub_mon="Aug" ;; 09) pub_mon="Sep" ;;
+ 10) pub_mon="Oct" ;; 11) pub_mon="Nov" ;; 12) pub_mon="Dec" ;;
+ esac
+ pub_date="Mon, ${pub_day} ${pub_mon} ${pub_year} ${post_time}:00 +0000"
+ fi
{
printf ' - \n'
@@ -1081,3 +1187,46 @@ if [ "$generate_feed" = "true" ] && [ -n "$base_url" ]; then
fi
echo "Build complete."
+}
+
+build_site
+
+if [ "$serve_mode" = "true" ]; then
+ port="${serve_port:-8000}"
+ if command -v python3 >/dev/null 2>&1; then
+ python3 -m http.server "$port" -d "$out" >/dev/null 2>&1 &
+ server_pid=$!
+ echo "Serving '$out' on http://localhost:$port (python3)"
+ elif command -v busybox >/dev/null 2>&1; then
+ busybox httpd -f -p "$port" -h "$out" >/dev/null 2>&1 &
+ server_pid=$!
+ echo "Serving '$out' on http://localhost:$port (busybox)"
+ else
+ die "Neither python3 nor busybox httpd is available to serve."
+ fi
+
+ trap 'kill $server_pid 2>/dev/null; rm -rf "$KEWT_TMPDIR"' EXIT
+ trap 'kill $server_pid 2>/dev/null; exit 0' HUP INT TERM
+fi
+
+if [ "$watch_mode" = "true" ]; then
+ echo "Watching for changes in '$src'..."
+ touch "$KEWT_TMPDIR/watch_mark"
+ while true; do
+ sleep 1
+ changed="$(find "$src" -type f -newer "$KEWT_TMPDIR/watch_mark" 2>/dev/null | head -n 1)"
+ [ -z "$changed" ] && [ -f "site.conf" ] && [ "site.conf" -nt "$KEWT_TMPDIR/watch_mark" ] && changed="site.conf"
+ [ -z "$changed" ] && [ -f "$src/site.conf" ] && [ "$src/site.conf" -nt "$KEWT_TMPDIR/watch_mark" ] && changed="$src/site.conf"
+ [ -z "$changed" ] && [ -f "$template" ] && [ "$template" -nt "$KEWT_TMPDIR/watch_mark" ] && changed="$template"
+ [ -z "$changed" ] && [ -d "$script_dir/styles" ] && changed="$(find "$script_dir/styles" -type f -newer "$KEWT_TMPDIR/watch_mark" 2>/dev/null | head -n 1)"
+
+ if [ -n "$changed" ]; then
+ echo ""
+ echo "Change detected, rebuilding..."
+ build_site
+ touch "$KEWT_TMPDIR/watch_mark"
+ fi
+ done
+elif [ "$serve_mode" = "true" ]; then
+ wait "$server_pid"
+fi
diff --git a/markdown.sh b/markdown.sh
index 9dac41e..9848105 100755
--- a/markdown.sh
+++ b/markdown.sh
@@ -62,13 +62,20 @@ awk -f "$awk_dir/fenced_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_f
awk -f "$awk_dir/indented_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
awk -f "$awk_dir/pipe_tables.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
awk -v enable_header_links="$ENABLE_HEADER_LINKS" -f "$awk_dir/headers.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
+awk -f "$awk_dir/definition_lists.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
awk -f "$awk_dir/lists.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
+# TOC
+awk -f "$awk_dir/toc.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
+# Footnotes
+awk -f "$awk_dir/footnotes.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
+
# Spacing
awk -f "$awk_dir/breaks.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
awk -f "$awk_dir/paragraphs.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
# Inline styles
+awk -f "$awk_dir/emoji.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
awk -f "$awk_dir/markdown_inline.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
awk -v input_file="$1" -v site_root="$MARKDOWN_SITE_ROOT" -v fallback_file="$MARKDOWN_FALLBACK_FILE" -f "$awk_dir/markdown_embed.awk" "$temp_file"
rm "$temp_file"
diff --git a/site/Docs/configuration.md b/site/Docs/configuration.md
index d437ac3..ed96703 100644
--- a/site/Docs/configuration.md
+++ b/site/Docs/configuration.md
@@ -15,11 +15,13 @@ You can set metadata for a page using a `site.conf`-style frontmatter block at t
title = "Custom Page Title"
date = "2026-03-23 11:32"
draft = false
+description = "A short page summary"
---
```
- `title` - overrides the page title, post name in index links, and RSS `
`.
- `date` - overrides the post date and time. Supports `YYYY-MM-DD` and `YYYY-MM-DD HH:MM` (or `HH-MM`).
- `draft` - if `true`, the file is excluded from HTML generation.
+- `description` - page description, used for Open Graph `og:description` meta tag.
## Directory Index Customisation
@@ -34,4 +36,26 @@ This is my blog. The posts are below. The top-most one is the most recent.
{{LIST}}
```
-The `{{LIST}}` tag will be replaced with the generated list of links to child pages and files, exactly as in case the custom index didn't exist.
\ No newline at end of file
+The `{{LIST}}` tag will be replaced with the generated list of links to child pages and files, exactly as in case the custom index didn't exist.
+
+## Table of Contents
+
+You can auto-generate a Table of Contents by placing `{{TOC}}` anywhere in your markdown file. It collects all `h2` and `h3` headings and generates an ordered list with anchor links.
+
+## Footnotes
+
+Footnotes use the `[^id]` syntax inline and `[^id]: text` for definitions at the bottom of the file. They are rendered as a numbered `` at the end of the page.
+
+## Definition Lists
+
+Definition lists use the standard syntax:
+
+```md
+Term
+: Definition
+```
+This renders as `- Term
- Definition
`. Multiple definitions per term are supported.
+
+## Emoji Shortcodes
+
+Standard GitHub/MkDocs emoji shortcodes like `:smile:`, `:fire:`, `:rocket:` are automatically replaced with their Unicode emoji equivalents. Shortcodes inside code blocks are left as-is.
\ No newline at end of file
diff --git a/site/Docs/usage.md b/site/Docs/usage.md
index 55dc5b6..5424bb3 100644
--- a/site/Docs/usage.md
+++ b/site/Docs/usage.md
@@ -9,11 +9,15 @@ kewt --generate-template [path]
kewt --update [dir]
kewt --from --to
kewt [src] [out]
+kewt --watch
+kewt --serve [port]
```
- `--new [title]` creates a new site directory with a default `site.conf`, `template.html`, and `index.md`.
- `--post [title]` creates a new markdown file in the configured `posts_dir` with the current date/time as the filename and default frontmatter.
- `--generate-template [path]` writes the default `template.html` to the given path (defaults to `template.html` in the current directory).
- `--update [dir]` adds any missing keys to `site.conf` and checks `template.html` against the latest default.
+- `--watch` (`-w`) watches for file changes in the source directory and rebuilds automatically.
+- `--serve` (`-s`) starts a local HTTP server (python3 or busybox) in the output directory after building. Use with the port number to specify the port. Composable with `--watch`.
## site.conf
@@ -42,6 +46,7 @@ base_url = ""
generate_feed = false
feed_file = "rss.xml"
posts_dir = ""
+posts_per_page = 12
custom_admonitions = ""
```
- `title` - site title
@@ -67,5 +72,6 @@ custom_admonitions = ""
- `generate_feed` - enable RSS feed generation (requires `base_url`)
- `feed_file` - filename for the generated RSS feed (default: "rss.xml")
- `posts_dir` - directory name containing posts (e.g., "posts"). Enables reverse-chronological sorting, title headings in indexes, and automatic backlinks.
+- `posts_per_page` - number of posts per page in paginated post indexes (default: 12). Set to 0 to disable pagination.
- `enable_header_links` - turns markdown section headings into clickable anchor links (default: true)
- `custom_admonitions` - comma separated list of custom admonitions
diff --git a/site/index.md b/site/index.md
index 6700ac3..c0bab4b 100644
--- a/site/index.md
+++ b/site/index.md
@@ -14,7 +14,7 @@ It's meant to be a static site generator, like _[kew](https://github.com/uint23/
## Features
- No dependencies
-- Frontmatter support (title, date, draft)
+- Frontmatter support (title, date, draft, description)
- Supports many embed types
- Automatic css variable replacement for older browsers
- Automatic inlining and embedding of many filetypes with `\![link]` or `\`
@@ -31,6 +31,13 @@ It's meant to be a static site generator, like _[kew](https://github.com/uint23/
- Clickable markdown header anchors
- Mobile responsive layout
- Customisable directory index pages with `{{LIST}}`
+- Open Graph meta tags from frontmatter
+- Auto-generated Table of Contents via `{{TOC}}`
+- Footnotes (`[^id]`)
+- Definition lists
+- Emoji shortcodes (`:smile:`, `:fire:`, etc.)
+- Post pagination
+- `--watch` and `--serve` modes for development
***
diff --git a/styles/kewt.css b/styles/kewt.css
index fadedad..2f0aaad 100644
--- a/styles/kewt.css
+++ b/styles/kewt.css
@@ -252,8 +252,27 @@ hr {
border-top: 1px solid var(--code-border);
}
+.nav-toggle, .nav-toggle-label {
+ display: none;
+}
+
@media screen and (max-width: 600px) {
+ header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .nav-toggle-label {
+ display: block;
+ font-size: 30px;
+ cursor: pointer;
+ color: var(--fg-heading);
+ user-select: none;
+ }
+
#side-bar {
+ display: none;
position: relative;
top: auto;
left: auto;
@@ -264,6 +283,10 @@ hr {
margin: 0 20px 20px 20px;
}
+ .nav-toggle:checked ~ #side-bar {
+ display: block;
+ }
+
article {
margin: 0 20px 0 20px;
}