Compare commits
59 Commits
b1f69673d1
...
v1.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 35eac48dcd | |||
| ef16ed4c88 | |||
| 30b7681234 | |||
| 13b6106efd | |||
| 831b081fc7 | |||
| fde423a32b | |||
| 55a82f75a9 | |||
| f85abd43c4 | |||
| 0f66ebf52a | |||
| 55a515ccd5 | |||
| de8cbefb8e | |||
| cc7fee573f | |||
| 137be9579a | |||
| 5afd0170e5 | |||
| 5a2053cfb4 | |||
| 2fc3d6fc6f | |||
| c5a9355871 | |||
| b8cd129c47 | |||
| 5e033a65e7 | |||
| 5bf2e2abe5 | |||
| 3a2056ff8f | |||
| fd829a3f22 | |||
| bad02decba | |||
| 2aef6ec4a1 | |||
| 78eac182dc | |||
| b7382a20ab | |||
| d8cf07ee2a | |||
| 76e2ae0117 | |||
| 2e331b5d9a | |||
| 9f5d1089a2 | |||
| 9ccba8fd4e | |||
| 95679abd85 | |||
| 8b1e793510 | |||
| 19f96553d9 | |||
| 1a7525a857 | |||
| e7d90d18e8 | |||
| 4019d2721d | |||
| b58604a4cf | |||
| 99e805b180 | |||
| 62075dea4a | |||
| 7afd041e53 | |||
| 64d08a0de3 | |||
| dd18bc3367 | |||
| f89661c1a5 | |||
| e0a3b66fa9 | |||
| 4e6c9dbeb5 | |||
| af453ca2ec | |||
| cea84de242 | |||
| ad1ec9c2e3 | |||
| fa3b5592da | |||
| 722d687afe | |||
| 77c0b29b4c | |||
| 9ae965662c | |||
| 9ced2af562 | |||
| f407b1c4af | |||
| bee12ce8c1 | |||
| 696dc1c142 | |||
| c2416e731b | |||
| 01fd55001a |
16
.gitea/workflows/lint.yml
Normal file
16
.gitea/workflows/lint.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
name: Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
shellcheck:
|
||||||
|
runs-on: local
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Shellcheck
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y shellcheck
|
||||||
|
- name: Run Shellcheck
|
||||||
|
run: shellcheck -s sh kewt.sh markdown.sh tools/build-standalone.sh || true
|
||||||
38
.gitea/workflows/publish-aur-git.yml
Normal file
38
.gitea/workflows/publish-aur-git.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: Publish kewt-git to AUR
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'packaging/AUR/PKGBUILD.git'
|
||||||
|
- 'packaging/AUR/.SRCINFO.git'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish-aur-git:
|
||||||
|
runs-on: local
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Arch Linux environment
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y pacman-package-manager curl jq || true
|
||||||
|
|
||||||
|
- name: Prepare AUR files
|
||||||
|
run: |
|
||||||
|
mkdir -p aur-work
|
||||||
|
cp packaging/AUR/PKGBUILD.git aur-work/PKGBUILD
|
||||||
|
cp packaging/AUR/.SRCINFO.git aur-work/.SRCINFO
|
||||||
|
|
||||||
|
- name: Publish to AUR
|
||||||
|
uses: KSXGitHub/github-actions-deploy-aur@v3.0.1
|
||||||
|
with:
|
||||||
|
pkgname: kewt-git
|
||||||
|
pkgbuild: ./aur-work/PKGBUILD
|
||||||
|
commit_username: ${{ github.actor }}
|
||||||
|
commit_email: ${{ github.actor }}@users.noreply.github.com
|
||||||
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
|
commit_message: "Update kewt-git to ${{ github.sha }}"
|
||||||
137
.gitea/workflows/release.yml
Normal file
137
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
name: Release Standalone Builder
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: local
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build standalone executable
|
||||||
|
run: |
|
||||||
|
chmod +x tools/build-standalone.sh
|
||||||
|
./tools/build-standalone.sh
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.21'
|
||||||
|
|
||||||
|
- name: Upload Release Asset
|
||||||
|
uses: https://gitea.com/actions/release-action@main
|
||||||
|
with:
|
||||||
|
files: |-
|
||||||
|
kewt
|
||||||
|
api_key: '${{secrets.GITEA_TOKEN}}'
|
||||||
|
|
||||||
|
- name: Push to GitHub Release
|
||||||
|
run: |
|
||||||
|
TAG="${GITHUB_REF#refs/tags/}"
|
||||||
|
|
||||||
|
# Fetch release body from Gitea
|
||||||
|
RELEASE_BODY=$(curl -sL \
|
||||||
|
"https://git.krzak.org/api/v1/repos/N0VA/kewt/releases/tags/${TAG}" \
|
||||||
|
| jq -r '.body // ""')
|
||||||
|
|
||||||
|
# Build JSON payload
|
||||||
|
PAYLOAD=$(jq -n \
|
||||||
|
--arg tag "$TAG" \
|
||||||
|
--arg name "Release $TAG" \
|
||||||
|
--arg body "$RELEASE_BODY" \
|
||||||
|
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
|
||||||
|
|
||||||
|
# Create the release on GitHub
|
||||||
|
curl -sL -X POST \
|
||||||
|
-H "Authorization: token ${{ secrets.GH_RELEASE_TOKEN }}" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
"https://api.github.com/repos/n0va-bot/kewt/releases" \
|
||||||
|
-d "$PAYLOAD" || true
|
||||||
|
|
||||||
|
# Get the release ID
|
||||||
|
RELEASE_ID=$(curl -sL \
|
||||||
|
-H "Authorization: token ${{ secrets.GH_RELEASE_TOKEN }}" \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
"https://api.github.com/repos/n0va-bot/kewt/releases/tags/${TAG}" | jq -r '.id')
|
||||||
|
|
||||||
|
# Upload the asset
|
||||||
|
curl -sL -X POST \
|
||||||
|
-H "Authorization: token ${{ secrets.GH_RELEASE_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
"https://uploads.github.com/repos/n0va-bot/kewt/releases/${RELEASE_ID}/assets?name=kewt" \
|
||||||
|
--data-binary @kewt
|
||||||
|
|
||||||
|
publish-aur:
|
||||||
|
runs-on: local
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Arch Linux environment
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y pacman-package-manager curl jq || true
|
||||||
|
|
||||||
|
- name: Render PKGBUILD and SRCINFO
|
||||||
|
run: |
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/v}
|
||||||
|
VERSION=${VERSION#refs/tags/}
|
||||||
|
|
||||||
|
curl -sL -o kewt https://git.krzak.org/N0VA/kewt/releases/download/v${VERSION}/kewt
|
||||||
|
|
||||||
|
CHECKSUM=$(sha256sum kewt | awk '{print $1}')
|
||||||
|
|
||||||
|
mkdir -p aur-work
|
||||||
|
sed -e "s/VERSION_PLACEHOLDER/${VERSION}/g" \
|
||||||
|
-e "s/SHA256SUM_PLACEHOLDER/${CHECKSUM}/g" \
|
||||||
|
packaging/AUR/PKGBUILD.template > aur-work/PKGBUILD
|
||||||
|
|
||||||
|
sed -e "s/VERSION_PLACEHOLDER/${VERSION}/g" \
|
||||||
|
-e "s/SHA256SUM_PLACEHOLDER/${CHECKSUM}/g" \
|
||||||
|
packaging/AUR/.SRCINFO.template > aur-work/.SRCINFO
|
||||||
|
|
||||||
|
- name: Publish to AUR
|
||||||
|
uses: KSXGitHub/github-actions-deploy-aur@v3.0.1
|
||||||
|
with:
|
||||||
|
pkgname: kewt-bin
|
||||||
|
pkgbuild: ./aur-work/PKGBUILD
|
||||||
|
commit_username: ${{ github.actor }}
|
||||||
|
commit_email: ${{ github.actor }}@users.noreply.github.com
|
||||||
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
|
commit_message: "Update kewt-bin to ${{ github.ref_name }}"
|
||||||
|
|
||||||
|
publish-homebrew:
|
||||||
|
runs-on: local
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Render Formula and push to GitHub
|
||||||
|
run: |
|
||||||
|
TAG="${GITHUB_REF#refs/tags/}"
|
||||||
|
VERSION="${TAG#v}"
|
||||||
|
|
||||||
|
curl -sL -o kewt-binary \
|
||||||
|
"https://git.krzak.org/N0VA/kewt/releases/download/${TAG}/kewt"
|
||||||
|
CHECKSUM=$(sha256sum kewt-binary | awk '{print $1}')
|
||||||
|
rm -f kewt-binary
|
||||||
|
|
||||||
|
git clone https://x-access-token:${{ secrets.GH_RELEASE_TOKEN }}@github.com/n0va-bot/homebrew-tap.git brew-work || true
|
||||||
|
mkdir -p brew-work/Formula
|
||||||
|
sed -e "s/VERSION_PLACEHOLDER/${VERSION}/g" \
|
||||||
|
-e "s/SHA256SUM_PLACEHOLDER/${CHECKSUM}/g" \
|
||||||
|
packaging/homebrew/kewt.rb.template > brew-work/Formula/kewt.rb
|
||||||
|
|
||||||
|
cd brew-work
|
||||||
|
[ -d .git ] || { git init && git checkout --orphan main && git remote add origin https://x-access-token:${{ secrets.GH_RELEASE_TOKEN }}@github.com/n0va-bot/homebrew-tap.git; }
|
||||||
|
git add Formula/kewt.rb
|
||||||
|
git config user.name "${{ github.actor }}"
|
||||||
|
git config user.email "${{ github.actor }}@users.noreply.github.com"
|
||||||
|
git commit -m "Update kewt to ${TAG}" || echo "No changes to commit"
|
||||||
|
git push -u origin main
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
|||||||
out/
|
out/
|
||||||
|
kewt
|
||||||
|
site.conf
|
||||||
|
template.html
|
||||||
|
|||||||
34
LICENSE
Normal file
34
LICENSE
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright 2026 N0\A
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This project incorporates code (CSS style) from the 'kew' project,
|
||||||
|
which is also licensed under the ISC License: Copyright (c) 2026 uint23
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
19
Makefile
Normal file
19
Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
PREFIX ?= /usr/local
|
||||||
|
BINDIR = $(PREFIX)/bin
|
||||||
|
|
||||||
|
all: kewt
|
||||||
|
|
||||||
|
kewt:
|
||||||
|
./tools/build-standalone.sh
|
||||||
|
|
||||||
|
install: kewt
|
||||||
|
install -d $(DESTDIR)$(BINDIR)
|
||||||
|
install -m 755 kewt $(DESTDIR)$(BINDIR)/kewt
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(DESTDIR)$(BINDIR)/kewt
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f kewt
|
||||||
|
|
||||||
|
.PHONY: all install uninstall clean
|
||||||
88
README.md
88
README.md
@@ -1,89 +1,21 @@
|
|||||||
# _kewt_
|
# 
|
||||||
### Pronounced "cute"
|
### Pronounced "cute"
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
# [Go to the website](https://kewt.krzak.org)
|
# [Go to the website](https://kewt.krzak.org)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
_kewt_ is a minimalist ssg inspired by _[werc](http://werc.cat-v.org/)_ and _[kew](https://github.com/uint23/kew)_
|
_kewt_ is a minimalist ssg inspired by _[werc](http://werc.cat-v.org/)_ and _[kew](https://github.com/uint23/kew)_
|
||||||
|
|
||||||
It's meant to be a static site generator, like _[kew](https://github.com/uint23/kew)_ but use only default (POSIX) tooling, like _[werc](http://werc.cat-v.org/)_ (and definitely unlike _[kew](https://github.com/uint23/kew)_)
|
|
||||||
|
|
||||||
## Features
|
## [Installation](https://kewt.krzak.org/#Installation)
|
||||||
|
|
||||||
- No dependencies
|
## Contributing
|
||||||
- Supports many embed types
|
|
||||||
- Automatic css variable replacement for older browsers
|
|
||||||
- Automatic inlining and embedding of many filetypes with `\![link]` or `\`
|
|
||||||
- Inline html support
|
|
||||||
- MFM `$font` and `\<plain>` tags
|
|
||||||
- Admonition support (that's what the blocks like the warning block below are called)
|
|
||||||
|
|
||||||
If you want to **force** a file to be inlined, use `\!![]` instead of `\![]`
|
Either open an issue or pull request on the **home** repository ([N0VA/kewt](https://git.krzak.org/N0VA/kewt)) or message me on my email address ([n0va@krzak.org](mailto:n0va@krzak.org?subject=%5Bkewt%5D%20something)) with the subjectline being `[kewt] something`.
|
||||||
|
|
||||||
## Usage
|
## License
|
||||||
|
|
||||||
```sh
|
ISC
|
||||||
./kewt.sh --help
|
|
||||||
./kewt.sh --new [title]
|
|
||||||
./kewt.sh --from <src> --to <out>
|
|
||||||
./kewt.sh [src] [out]
|
|
||||||
```
|
|
||||||
|
|
||||||
`--new [title]` creates a new site directory with a copied `site.conf` and a default `index.md`.
|
|
||||||
|
|
||||||
## site.conf
|
|
||||||
|
|
||||||
```conf
|
|
||||||
title = "kewt"
|
|
||||||
style = "kewt"
|
|
||||||
dir_indexes = true
|
|
||||||
single_file_index = true
|
|
||||||
flatten = false
|
|
||||||
order = ""
|
|
||||||
home_name = "Home"
|
|
||||||
show_home_in_nav = true
|
|
||||||
footer = "made with <a href="https://kewt.krzak.org">kewt</a>"
|
|
||||||
logo = ""
|
|
||||||
display_logo = false
|
|
||||||
display_title = true
|
|
||||||
logo_as_favicon = true
|
|
||||||
favicon = ""
|
|
||||||
```
|
|
||||||
|
|
||||||
- `title` site title
|
|
||||||
- `style` style file name from `./styles` (without `.css`)
|
|
||||||
- `dir_indexes` generate directory index pages when missing `index.md`
|
|
||||||
- `single_file_index` if a directory has one markdown file and no `index.md`, use that file as `index.html`
|
|
||||||
- `flatten` flatten sidebar directory levels
|
|
||||||
- `order` comma separated file/directory name list to order the sidebar (alphabetical by default)
|
|
||||||
- `home_name` text for the home link in navigation (default: "Home")
|
|
||||||
- `show_home_in_nav` show home link in navigation (default: true)
|
|
||||||
- `footer` footer html/text shown at the bottom of pages
|
|
||||||
- `logo` logo image path (used in header if enabled)
|
|
||||||
- `display_logo` show logo in header
|
|
||||||
- `display_title` show title text in header
|
|
||||||
- `logo_as_favicon` use `logo` as favicon
|
|
||||||
- `favicon` explicit favicon path (used when `logo_as_favicon` is false or no logo is set)
|
|
||||||
|
|
||||||
## Ignores
|
|
||||||
|
|
||||||
- `.kewtignore`: Files/directories to ignore. If empty, the whole directory gets ignored
|
|
||||||
- `.kewthide`: Files/directories to hide from navigation but still process. Same empty rules as with ignore
|
|
||||||
- `.kewtpreserve`: Files/directories to copy but not convert markdown to html. Same empty rules again
|
|
||||||
|
|
||||||
## Embeds
|
|
||||||
|
|
||||||
- `\![link]`:
|
|
||||||
- local image/audio/video files are embedded as media tags
|
|
||||||
- local text/code files are inlined directly
|
|
||||||
- global image/audio/video links are embedded as media tags
|
|
||||||
- other global links are embedded as `<iframe>`
|
|
||||||
- `\` works the same, with `alt` used for images
|
|
||||||
- `\!![]` and `\!` force inline local file contents
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
- Markdown to html conversion based on [markdown.bash](https://github.com/chadbraunduin/markdown.bash) by [chadbraunduin](https://github.com/chadbraunduin)
|
|
||||||
- Default css style and html template based on _[kew](https://github.com/uint23/kew)_ by [uint23](https://github.com/uint23)
|
|
||||||
|
|
||||||
>[!WARNING]
|
|
||||||
>Most of this was coded at night, while sleepy and a bit sick, and after walking for about 4 hours around a forest, so...
|
|
||||||
|
|||||||
@@ -22,7 +22,19 @@ END {
|
|||||||
sub(/^\[!/, "", kind)
|
sub(/^\[!/, "", kind)
|
||||||
sub(/\]$/, "", kind)
|
sub(/\]$/, "", kind)
|
||||||
lkind = tolower(kind)
|
lkind = tolower(kind)
|
||||||
if (lkind == "note" || lkind == "tip" || lkind == "important" || lkind == "warning" || lkind == "caution") {
|
is_valid = 0
|
||||||
|
if (custom_admonitions != "") {
|
||||||
|
n = split(tolower(custom_admonitions), adms, ",")
|
||||||
|
for (idx = 1; idx <= n; idx++) {
|
||||||
|
adm = adms[idx]
|
||||||
|
sub(/^[ \t]+/, "", adm)
|
||||||
|
sub(/[ \t]+$/, "", adm)
|
||||||
|
if (lkind == adm) { is_valid = 1; break }
|
||||||
|
}
|
||||||
|
} else if (lkind == "note" || lkind == "tip" || lkind == "important" || lkind == "warning" || lkind == "caution") {
|
||||||
|
is_valid = 1
|
||||||
|
}
|
||||||
|
if (is_valid) {
|
||||||
print "<div class=\"admonition admonition-" lkind "\">"
|
print "<div class=\"admonition admonition-" lkind "\">"
|
||||||
print "<p class=\"admonition-title\">" cap(lkind) "</p>"
|
print "<p class=\"admonition-title\">" cap(lkind) "</p>"
|
||||||
has_body = 0
|
has_body = 0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
BEGIN {
|
BEGIN {
|
||||||
|
src = ENVIRON["AWK_SRC"]
|
||||||
slen = length(src)
|
slen = length(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
BEGIN { in_fence = 0; first_line = 0 }
|
BEGIN { in_fence = 0; first_line = 0; code_tag = "<code>" }
|
||||||
{
|
{
|
||||||
if (!in_fence && $0 ~ /^```/) {
|
if (!in_fence && $0 ~ /^```/) {
|
||||||
in_fence = 1
|
in_fence = 1
|
||||||
first_line = 1
|
first_line = 1
|
||||||
|
lang = $0
|
||||||
|
sub(/^```[[:space:]]*/, "", lang)
|
||||||
|
sub(/[[:space:]]*$/, "", lang)
|
||||||
|
if (lang != "") {
|
||||||
|
code_tag = "<code class=\"language-" lang "\">"
|
||||||
|
} else {
|
||||||
|
code_tag = "<code>"
|
||||||
|
}
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
if (in_fence && $0 ~ /^```[[:space:]]*$/) {
|
if (in_fence && $0 ~ /^```[[:space:]]*$/) {
|
||||||
|
if (first_line) printf "%s", "<pre>" code_tag
|
||||||
print "</code></pre>"
|
print "</code></pre>"
|
||||||
in_fence = 0
|
in_fence = 0
|
||||||
next
|
next
|
||||||
@@ -14,8 +23,12 @@ BEGIN { in_fence = 0; first_line = 0 }
|
|||||||
gsub(/&/, "\\&"); gsub(/</, "\\<"); gsub(/>/, "\\>")
|
gsub(/&/, "\\&"); gsub(/</, "\\<"); gsub(/>/, "\\>")
|
||||||
if (first_line) {
|
if (first_line) {
|
||||||
first_line = 0
|
first_line = 0
|
||||||
if ($0 == "") next
|
printf "%s", "<pre>" code_tag
|
||||||
print "<pre><code>" $0
|
if ($0 == "") {
|
||||||
|
print ""
|
||||||
|
next
|
||||||
|
}
|
||||||
|
print $0
|
||||||
} else {
|
} else {
|
||||||
print
|
print
|
||||||
}
|
}
|
||||||
@@ -24,5 +37,8 @@ BEGIN { in_fence = 0; first_line = 0 }
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
END {
|
END {
|
||||||
if (in_fence) print "</code></pre>"
|
if (in_fence) {
|
||||||
|
if (first_line) printf "%s", "<pre>" code_tag
|
||||||
|
print "</code></pre>"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
awk/frontmatter.awk
Normal file
46
awk/frontmatter.awk
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
BEGIN {
|
||||||
|
state = "start"
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (state == "start") {
|
||||||
|
if ($0 == "---") {
|
||||||
|
state = "in_fm"
|
||||||
|
next
|
||||||
|
} else {
|
||||||
|
state = "body"
|
||||||
|
print
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state == "in_fm") {
|
||||||
|
if ($0 == "---") {
|
||||||
|
state = "body"
|
||||||
|
next
|
||||||
|
}
|
||||||
|
line = $0
|
||||||
|
if (line ~ /^[[:space:]]*$/ || line ~ /^[[:space:]]*#/) next
|
||||||
|
if (line !~ /=/) next
|
||||||
|
|
||||||
|
key = line
|
||||||
|
val = line
|
||||||
|
sub(/=.*/, "", key)
|
||||||
|
sub(/[^=]*=/, "", val)
|
||||||
|
|
||||||
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", key)
|
||||||
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", val)
|
||||||
|
|
||||||
|
if (val ~ /^".*"$/) {
|
||||||
|
val = substr(val, 2, length(val) - 2)
|
||||||
|
gsub(/\\"/, "\"", val)
|
||||||
|
} else if (val ~ /^'.*'$/) {
|
||||||
|
val = substr(val, 2, length(val) - 2)
|
||||||
|
gsub(/\\'/, "'", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fm_out != "") {
|
||||||
|
print key "=" val >> fm_out
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
print
|
||||||
|
}
|
||||||
@@ -33,6 +33,13 @@ function compare_paths(p1, p2, parts1, parts2, n1, n2, i, name1, name2, lname
|
|||||||
}
|
}
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
|
src = ENVIRON["AWK_SRC"]
|
||||||
|
single_file_index = ENVIRON["AWK_SINGLE_FILE_INDEX"]
|
||||||
|
flatten = ENVIRON["AWK_FLATTEN"]
|
||||||
|
order = ENVIRON["AWK_ORDER"]
|
||||||
|
home_name = ENVIRON["AWK_HOME_NAME"]
|
||||||
|
show_home_in_nav = ENVIRON["AWK_SHOW_HOME_IN_NAV"]
|
||||||
|
dinfo = ENVIRON["AWK_DINFO"]
|
||||||
n_dlines = split(dinfo, dlines, "\n")
|
n_dlines = split(dinfo, dlines, "\n")
|
||||||
for (i = 1; i <= n_dlines; i++) {
|
for (i = 1; i <= n_dlines; i++) {
|
||||||
if (split(dlines[i], dparts, "|") == 3) {
|
if (split(dlines[i], dparts, "|") == 3) {
|
||||||
|
|||||||
@@ -3,23 +3,32 @@ function strip_markdown(s) {
|
|||||||
gsub(/[*_`~]/, "", s)
|
gsub(/[*_`~]/, "", s)
|
||||||
gsub(/[\[\]]/, "", s)
|
gsub(/[\[\]]/, "", s)
|
||||||
gsub(/\([^\)]*\)/, "", s)
|
gsub(/\([^\)]*\)/, "", s)
|
||||||
|
s = tolower(s)
|
||||||
|
gsub(/[^a-z0-9 -]/, "", s)
|
||||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", s)
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", s)
|
||||||
gsub(/[[:space:]]+/, "-", s)
|
gsub(/[[:space:]]+/, "-", s)
|
||||||
|
gsub(/-{2,}/, "-", s)
|
||||||
|
gsub(/^-+|-+$/, "", s)
|
||||||
|
if (length(s) > 80) s = substr(s, 1, 80)
|
||||||
|
gsub(/-+$/, "", s)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
function print_header(line) {
|
function print_header(line) {
|
||||||
if (line ~ /^# /) {
|
tag = ""
|
||||||
sub(/^# /, "", line); print "<h1 id=\"" strip_markdown(line) "\">" line "</h1>"
|
if (line ~ /^# /) { tag = "h1"; sub(/^# /, "", line) }
|
||||||
} else if (line ~ /^## /) {
|
else if (line ~ /^## /) { tag = "h2"; sub(/^## /, "", line) }
|
||||||
sub(/^## /, "", line); print "<h2 id=\"" strip_markdown(line) "\">" line "</h2>"
|
else if (line ~ /^### /) { tag = "h3"; sub(/^### /, "", line) }
|
||||||
} else if (line ~ /^### /) {
|
else if (line ~ /^#### /) { tag = "h4"; sub(/^#### /, "", line) }
|
||||||
sub(/^### /, "", line); print "<h3 id=\"" strip_markdown(line) "\">" line "</h3>"
|
else if (line ~ /^##### /) { tag = "h5"; sub(/^##### /, "", line) }
|
||||||
} else if (line ~ /^#### /) {
|
else if (line ~ /^###### /) { tag = "h6"; sub(/^###### /, "", line) }
|
||||||
sub(/^#### /, "", line); print "<h4 id=\"" strip_markdown(line) "\">" line "</h4>"
|
|
||||||
} else if (line ~ /^##### /) {
|
if (tag != "") {
|
||||||
sub(/^##### /, "", line); print "<h5 id=\"" strip_markdown(line) "\">" line "</h5>"
|
id = strip_markdown(line)
|
||||||
} else if (line ~ /^###### /) {
|
if (enable_header_links == "true") {
|
||||||
sub(/^###### /, "", line); print "<h6 id=\"" strip_markdown(line) "\">" line "</h6>"
|
print "<" tag " id=\"" id "\"><a href=\"#" id "\" class=\"header-anchor\">" line "</a></" tag ">"
|
||||||
|
} else {
|
||||||
|
print "<" tag " id=\"" id "\">" line "</" tag ">"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
print line
|
print line
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
BEGIN { in_code = 0 }
|
BEGIN { in_code = 0; in_html_pre = 0 }
|
||||||
/^ | / {
|
{
|
||||||
if (!in_code) { print "<pre><code>"; in_code = 1 }
|
if ($0 ~ /<pre>/) in_html_pre = 1
|
||||||
sub(/^ | /, "", $0)
|
if ($0 ~ /<\/pre>/) { in_html_pre = 0; if (in_code) { print "</code></pre>"; in_code = 0 }; print; next }
|
||||||
gsub(/&/, "\\&"); gsub(/</, "\\<"); gsub(/>/, "\\>")
|
|
||||||
print; next
|
if (!in_html_pre && $0 ~ /^(\t| )/) {
|
||||||
|
if (!in_code) { printf "%s", "<pre><code>"; in_code = 1 }
|
||||||
|
sub(/^(\t| )/, "", $0)
|
||||||
|
gsub(/&/, "\\&"); gsub(/</, "\\<"); gsub(/>/, "\\>")
|
||||||
|
print
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_code) {
|
||||||
|
print "</code></pre>"
|
||||||
|
in_code = 0
|
||||||
|
}
|
||||||
|
print
|
||||||
}
|
}
|
||||||
{ if (in_code) { print "</code></pre>"; in_code = 0 } print }
|
|
||||||
END { if (in_code) print "</code></pre>" }
|
END { if (in_code) print "</code></pre>" }
|
||||||
|
|||||||
@@ -48,7 +48,26 @@ BEGIN {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print "<li>" content "</li>"
|
has_checkbox = 0
|
||||||
|
if (content ~ /^\[[ \t]\] /) {
|
||||||
|
has_checkbox = 1
|
||||||
|
is_checked = 0
|
||||||
|
sub(/^\[[ \t]\] /, "", content)
|
||||||
|
} else if (content ~ /^\[[xX]\] /) {
|
||||||
|
has_checkbox = 1
|
||||||
|
is_checked = 1
|
||||||
|
sub(/^\[[xX]\] /, "", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_checkbox) {
|
||||||
|
if (is_checked) {
|
||||||
|
print "<li class=\"task-list-item\"><input type=\"checkbox\" class=\"task-list-item-checkbox\" checked disabled> " content "</li>"
|
||||||
|
} else {
|
||||||
|
print "<li class=\"task-list-item\"><input type=\"checkbox\" class=\"task-list-item-checkbox\" disabled> " content "</li>"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print "<li>" content "</li>"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
while (depth > 0) {
|
while (depth > 0) {
|
||||||
print "</" cur_type[depth] ">"
|
print "</" cur_type[depth] ">"
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ function render_embed(src, alt, has_alt, force_inline, ext, local_path, conte
|
|||||||
}
|
}
|
||||||
if (is_audio_ext(ext)) return "<audio controls src=\"" src "\"></audio>"
|
if (is_audio_ext(ext)) return "<audio controls src=\"" src "\"></audio>"
|
||||||
if (is_video_ext(ext)) return "<video controls src=\"" src "\"></video>"
|
if (is_video_ext(ext)) return "<video controls src=\"" src "\"></video>"
|
||||||
return "<iframe src=\"" src "\"></iframe>"
|
return "<iframe src=\"" src "\" allowfullscreen></iframe>"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_image_ext(ext)) {
|
if (is_image_ext(ext)) {
|
||||||
@@ -223,7 +223,29 @@ function render_embed(src, alt, has_alt, force_inline, ext, local_path, conte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "<iframe src=\"" src "\"></iframe>"
|
return "<iframe src=\"" src "\" allowfullscreen></iframe>"
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_typed_embed(etype, src, alt, has_alt, local_path, content) {
|
||||||
|
if (etype == "i") {
|
||||||
|
if (has_alt) return "<img alt=\"" alt "\" src=\"" src "\" />"
|
||||||
|
return "<img src=\"" src "\" />"
|
||||||
|
}
|
||||||
|
if (etype == "v") return "<video controls src=\"" src "\"></video>"
|
||||||
|
if (etype == "a") return "<audio controls src=\"" src "\"></audio>"
|
||||||
|
if (etype == "f") return "<iframe src=\"" src "\" allowfullscreen></iframe>"
|
||||||
|
if (etype == "e") {
|
||||||
|
if (!is_global_url(src)) {
|
||||||
|
local_path = resolve_local_path(src)
|
||||||
|
if (local_path != "") {
|
||||||
|
content = read_file(local_path)
|
||||||
|
if (content ~ /\n$/) sub(/\n$/, "", content)
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return render_embed(src, alt, has_alt, 1)
|
||||||
|
}
|
||||||
|
return render_embed(src, alt, has_alt, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_attr(tag, attr, pat, m, token) {
|
function extract_attr(tag, attr, pat, m, token) {
|
||||||
@@ -319,7 +341,7 @@ function apply_td_vertical_align(line, out, rest, seg, td_tag, img_tag, after
|
|||||||
return out rest
|
return out rest
|
||||||
}
|
}
|
||||||
|
|
||||||
function rewrite_img_tags(line, out, rest, tag, src, alt, force_inline_tag, pre, post, repl) {
|
function rewrite_img_tags(line, out, rest, tag, src, alt, force_inline_tag, embed_type, pre, post, repl) {
|
||||||
out = ""
|
out = ""
|
||||||
rest = line
|
rest = line
|
||||||
while (match(rest, /<img[^>]*\/?>/)) {
|
while (match(rest, /<img[^>]*\/?>/)) {
|
||||||
@@ -329,7 +351,10 @@ function rewrite_img_tags(line, out, rest, tag, src, alt, force_inline_tag, p
|
|||||||
src = extract_attr(tag, "src")
|
src = extract_attr(tag, "src")
|
||||||
alt = extract_attr(tag, "alt")
|
alt = extract_attr(tag, "alt")
|
||||||
force_inline_tag = extract_attr(tag, "data-force-inline")
|
force_inline_tag = extract_attr(tag, "data-force-inline")
|
||||||
if (is_image_ext(ext_of(src)) && force_inline_tag == "") {
|
embed_type = extract_attr(tag, "data-embed-type")
|
||||||
|
if (embed_type != "") {
|
||||||
|
repl = render_typed_embed(embed_type, src, alt, (alt != ""))
|
||||||
|
} else if (is_image_ext(ext_of(src)) && force_inline_tag == "") {
|
||||||
# Preserve hand-written <img> attributes (style/class/etc) for normal images.
|
# Preserve hand-written <img> attributes (style/class/etc) for normal images.
|
||||||
repl = tag
|
repl = tag
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,6 +2,33 @@ BEGIN {
|
|||||||
in_pre = 0
|
in_pre = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mask_html_tags(s, out, rest, start, len, tag, token) {
|
||||||
|
out = ""
|
||||||
|
rest = s
|
||||||
|
html_tag_count = 0
|
||||||
|
while (match(rest, /<[^>]+>/)) {
|
||||||
|
out = out substr(rest, 1, RSTART - 1)
|
||||||
|
start = RSTART
|
||||||
|
len = RLENGTH
|
||||||
|
tag = substr(rest, start, len)
|
||||||
|
html_tag_count++
|
||||||
|
html_tag_token[html_tag_count] = "\034HT" html_tag_count "\034"
|
||||||
|
html_tag_value[html_tag_count] = tag
|
||||||
|
out = out html_tag_token[html_tag_count]
|
||||||
|
rest = substr(rest, start + len)
|
||||||
|
}
|
||||||
|
return out rest
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore_html_tags(s, i, val) {
|
||||||
|
for (i = 1; i <= html_tag_count; i++) {
|
||||||
|
val = html_tag_value[i]
|
||||||
|
gsub(/&/, "\\\\&", val)
|
||||||
|
gsub(html_tag_token[i], val, s)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
if ($0 ~ /<pre>/) {
|
if ($0 ~ /<pre>/) {
|
||||||
in_pre = 1
|
in_pre = 1
|
||||||
@@ -33,6 +60,36 @@ BEGIN {
|
|||||||
line = substr(line, 1, start - 1) repl substr(line, start + len)
|
line = substr(line, 1, start - 1) repl substr(line, start + len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# typed embeds: !i, !v, !a, !f, !e
|
||||||
|
while (match(line, /![ivafe]\[[^\]]*\]\([^\)]+ "[^"]*"\)/)) {
|
||||||
|
start = RSTART; len = RLENGTH
|
||||||
|
token = substr(line, start, len)
|
||||||
|
etype = substr(token, 2, 1)
|
||||||
|
match(token, /\[[^\]]*\]/); alt = substr(token, RSTART + 1, RLENGTH - 2)
|
||||||
|
match(token, /"[^"]*"/); etitle = substr(token, RSTART + 1, RLENGTH - 2)
|
||||||
|
match(token, /\([^\)]+/); inner = substr(token, RSTART + 1, RLENGTH - 1)
|
||||||
|
sub(/[[:space:]]*"[^"]*"/, "", inner); src = inner
|
||||||
|
repl = "<img data-embed-type=\"" etype "\" alt=\"" alt "\" src=\"" src "\" title=\"" etitle "\" />"
|
||||||
|
line = substr(line, 1, start - 1) repl substr(line, start + len)
|
||||||
|
}
|
||||||
|
while (match(line, /![ivafe]\[[^\]]*\]\([^\)]+\)/)) {
|
||||||
|
start = RSTART; len = RLENGTH
|
||||||
|
token = substr(line, start, len)
|
||||||
|
etype = substr(token, 2, 1)
|
||||||
|
match(token, /\[[^\]]*\]/); alt = substr(token, RSTART + 1, RLENGTH - 2)
|
||||||
|
match(token, /\([^\)]+/); src = substr(token, RSTART + 1, RLENGTH - 1)
|
||||||
|
repl = "<img data-embed-type=\"" etype "\" alt=\"" alt "\" src=\"" src "\" />"
|
||||||
|
line = substr(line, 1, start - 1) repl substr(line, start + len)
|
||||||
|
}
|
||||||
|
while (match(line, /![ivafe]\[[^\]]+\]/)) {
|
||||||
|
start = RSTART; len = RLENGTH
|
||||||
|
token = substr(line, start, len)
|
||||||
|
etype = substr(token, 2, 1)
|
||||||
|
src = substr(token, 4, len - 4)
|
||||||
|
repl = "<img data-embed-type=\"" etype "\" src=\"" src "\" />"
|
||||||
|
line = substr(line, 1, start - 1) repl substr(line, start + len)
|
||||||
|
}
|
||||||
|
|
||||||
# force-inline image syntax (double bang)
|
# force-inline image syntax (double bang)
|
||||||
while (match(line, /!!\[[^\]]*\]\([^\)]+ "[^"]*"\)/)) {
|
while (match(line, /!!\[[^\]]*\]\([^\)]+ "[^"]*"\)/)) {
|
||||||
start = RSTART; len = RLENGTH
|
start = RSTART; len = RLENGTH
|
||||||
@@ -114,6 +171,8 @@ BEGIN {
|
|||||||
line = substr(line, 1, start - 1) "<span style=\"font-family: sans-serif;\">" content "</span>" substr(line, start + len)
|
line = substr(line, 1, start - 1) "<span style=\"font-family: sans-serif;\">" content "</span>" substr(line, start + len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line = mask_html_tags(line)
|
||||||
|
|
||||||
# Bold, Italic, Strikethrough (BRE-like logic in AWK)
|
# Bold, Italic, Strikethrough (BRE-like logic in AWK)
|
||||||
# Strong Bold **
|
# Strong Bold **
|
||||||
while (match(line, /\*\*[^*]+\*\*/)) {
|
while (match(line, /\*\*[^*]+\*\*/)) {
|
||||||
@@ -152,6 +211,8 @@ BEGIN {
|
|||||||
line = substr(line, 1, start - 1) repl substr(line, start + len)
|
line = substr(line, 1, start - 1) repl substr(line, start + len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line = restore_html_tags(line)
|
||||||
|
|
||||||
# special characters
|
# special characters
|
||||||
if (line !~ /&[A-Za-z0-9#]+;/) {
|
if (line !~ /&[A-Za-z0-9#]+;/) {
|
||||||
gsub(/&/, "&", line)
|
gsub(/&/, "&", line)
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
function replace_all(text, token, value, pos, token_len) {
|
function replace_all(text, token, value, pos, token_len, res) {
|
||||||
token_len = length(token)
|
token_len = length(token)
|
||||||
|
res = ""
|
||||||
while ((pos = index(text, token)) > 0) {
|
while ((pos = index(text, token)) > 0) {
|
||||||
text = substr(text, 1, pos - 1) value substr(text, pos + token_len)
|
res = res substr(text, 1, pos - 1) value
|
||||||
|
text = substr(text, pos + token_len)
|
||||||
|
}
|
||||||
|
return res text
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
current_url = ENVIRON["AWK_CURRENT_URL"]
|
||||||
|
nav = ENVIRON["AWK_NAV"]
|
||||||
|
title = ENVIRON["AWK_TITLE"]
|
||||||
|
footer = ENVIRON["AWK_FOOTER"]
|
||||||
|
style_path = ENVIRON["AWK_STYLE_PATH"]
|
||||||
|
head_extra = ENVIRON["AWK_HEAD_EXTRA"]
|
||||||
|
header_brand = ENVIRON["AWK_HEADER_BRAND"]
|
||||||
|
if (current_url != "") {
|
||||||
|
nav = replace_all(nav, "href=\"" current_url "\"", "href=\"" current_url "\" class=\"current-page\"")
|
||||||
}
|
}
|
||||||
return text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
BEGIN { done = 0 }
|
BEGIN {
|
||||||
|
new_title = ENVIRON["AWK_NEW_TITLE"]
|
||||||
|
done = 0
|
||||||
|
}
|
||||||
/^title[[:space:]]*=/ {
|
/^title[[:space:]]*=/ {
|
||||||
print "title = \"" new_title "\""
|
print "title = \"" new_title "\""
|
||||||
done = 1
|
done = 1
|
||||||
|
|||||||
21
icon.svg
Normal file
21
icon.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg-grad" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0%" stop-color="#4a3b69"/>
|
||||||
|
<stop offset="100%" stop-color="#352654"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="512" height="512" rx="80" ry="80" fill="url(#bg-grad)"/>
|
||||||
|
<text
|
||||||
|
x="256"
|
||||||
|
y="296"
|
||||||
|
text-anchor="middle"
|
||||||
|
dominant-baseline="central"
|
||||||
|
font-family="Georgia, 'Times New Roman', Times, serif"
|
||||||
|
font-size="220"
|
||||||
|
font-weight="bold"
|
||||||
|
font-style="italic"
|
||||||
|
fill="#debfff"
|
||||||
|
letter-spacing="-8"
|
||||||
|
>kewt</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 639 B |
30
markdown.sh
30
markdown.sh
@@ -1,22 +1,29 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd)
|
||||||
awk_dir="$script_dir/awk"
|
awk_dir="$script_dir/awk"
|
||||||
|
|
||||||
sed_inplace() {
|
sed_inplace() {
|
||||||
script="$1"
|
script="$1"
|
||||||
file="$2"
|
file="$2"
|
||||||
tmp="${file}.tmp.$$"
|
tmp="${file}.tmp.$$"
|
||||||
sed "$script" "$file" > "$tmp" && mv "$tmp" "$file" || {
|
if sed "$script" "$file" > "$tmp" && mv "$tmp" "$file"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
return 1
|
return 1
|
||||||
}
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
temp_file="/tmp/markdown.$$.md"
|
temp_file="${KEWT_TMPDIR:-/tmp}/markdown.$$.md"
|
||||||
cat "$@" > "$temp_file"
|
cat "$@" > "$temp_file"
|
||||||
|
|
||||||
trap 'rm -f "$temp_file" "$temp_file.tmp"' EXIT INT TERM
|
trap 'rm -f "$temp_file" "$temp_file.tmp" "$temp_file.fm"' EXIT INT TERM
|
||||||
|
|
||||||
|
# Frontmatter
|
||||||
|
fm_file="$temp_file.fm"
|
||||||
|
: > "$fm_file"
|
||||||
|
awk -v fm_out="$fm_file" -f "$awk_dir/frontmatter.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
|
|
||||||
# Mask
|
# Mask
|
||||||
awk -f "$awk_dir/mask_inline_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
awk -f "$awk_dir/mask_inline_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
@@ -38,18 +45,23 @@ done
|
|||||||
sed_inplace "/^\[[^\]]*\]: */d" "$temp_file"
|
sed_inplace "/^\[[^\]]*\]: */d" "$temp_file"
|
||||||
|
|
||||||
# Blocks
|
# Blocks
|
||||||
sed_inplace "s/^>!\[/> [!/g" "$temp_file"
|
|
||||||
sed_inplace "s/^>\[!/> [!/g" "$temp_file"
|
|
||||||
|
|
||||||
|
loop_count=0
|
||||||
|
max_iterations=100
|
||||||
while grep '^>' "$temp_file" >/dev/null; do
|
while grep '^>' "$temp_file" >/dev/null; do
|
||||||
awk -f "$awk_dir/blockquote.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
awk -f "$awk_dir/blockquote.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
|
loop_count=$((loop_count + 1))
|
||||||
|
if [ "$loop_count" -gt "$max_iterations" ]; then
|
||||||
|
echo "Warning: Blockquote processing exceeded $max_iterations iterations on $1. Breaking to prevent infinite loop." >&2
|
||||||
|
break
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
awk -f "$awk_dir/blockquote_to_admonition.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
awk -v custom_admonitions="$CUSTOM_ADMONITIONS" -f "$awk_dir/blockquote_to_admonition.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
awk -f "$awk_dir/fenced_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
awk -f "$awk_dir/fenced_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
awk -f "$awk_dir/indented_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
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 -f "$awk_dir/pipe_tables.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
awk -f "$awk_dir/headers.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/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"
|
||||||
|
|
||||||
# Spacing
|
# Spacing
|
||||||
|
|||||||
7
package.json
Normal file
7
package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "kewt",
|
||||||
|
"description": "A minimalist static site generator inspired by werc",
|
||||||
|
"global": "true",
|
||||||
|
"install": "make install",
|
||||||
|
"scripts": ["kewt"]
|
||||||
|
}
|
||||||
16
packaging/AUR/.SRCINFO.git
Normal file
16
packaging/AUR/.SRCINFO.git
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
pkgbase = kewt-git
|
||||||
|
pkgdesc = A minimalist, 100% POSIX, static site generator inspired by werc and kew
|
||||||
|
pkgver = r0.0000000
|
||||||
|
pkgrel = 3
|
||||||
|
url = https://kewt.krzak.org
|
||||||
|
arch = any
|
||||||
|
license = ISC
|
||||||
|
makedepends = git
|
||||||
|
depends = sh
|
||||||
|
provides = kewt
|
||||||
|
conflicts = kewt
|
||||||
|
conflicts = kewt-bin
|
||||||
|
source = kewt-git::git+https://git.krzak.org/N0VA/kewt.git
|
||||||
|
sha256sums = SKIP
|
||||||
|
|
||||||
|
pkgname = kewt-git
|
||||||
15
packaging/AUR/.SRCINFO.template
Normal file
15
packaging/AUR/.SRCINFO.template
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
pkgbase = kewt-bin
|
||||||
|
pkgdesc = A minimalist, 100% POSIX, static site generator inspired by werc and kew
|
||||||
|
pkgver = VERSION_PLACEHOLDER
|
||||||
|
pkgrel = 2
|
||||||
|
url = https://kewt.krzak.org
|
||||||
|
arch = any
|
||||||
|
license = ISC
|
||||||
|
depends = sh
|
||||||
|
provides = kewt
|
||||||
|
conflicts = kewt
|
||||||
|
conflicts = kewt-git
|
||||||
|
source = kewt-bin-VERSION_PLACEHOLDER.sh::https://git.krzak.org/N0VA/kewt/releases/download/vVERSION_PLACEHOLDER/kewt
|
||||||
|
sha256sums = SHA256SUM_PLACEHOLDER
|
||||||
|
|
||||||
|
pkgname = kewt-bin
|
||||||
29
packaging/AUR/PKGBUILD.git
Normal file
29
packaging/AUR/PKGBUILD.git
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Maintainer: n0va <n0va@krzak.org>
|
||||||
|
pkgname=kewt-git
|
||||||
|
pkgver=r0.0000000
|
||||||
|
pkgrel=2
|
||||||
|
pkgdesc="A minimalist, 100% POSIX, static site generator inspired by werc and kew"
|
||||||
|
arch=('any')
|
||||||
|
url="https://kewt.krzak.org"
|
||||||
|
license=('ISC')
|
||||||
|
makedepends=('git')
|
||||||
|
depends=('sh')
|
||||||
|
provides=('kewt')
|
||||||
|
conflicts=('kewt' 'kewt-bin')
|
||||||
|
source=("${pkgname}::git+https://git.krzak.org/N0VA/kewt.git")
|
||||||
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
|
pkgver() {
|
||||||
|
cd "${pkgname}"
|
||||||
|
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "${pkgname}"
|
||||||
|
sh tools/build-standalone.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "${pkgname}"
|
||||||
|
install -Dm755 kewt "${pkgdir}/usr/bin/kewt"
|
||||||
|
}
|
||||||
21
packaging/AUR/PKGBUILD.template
Normal file
21
packaging/AUR/PKGBUILD.template
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Maintainer: n0va <n0va@krzak.org>
|
||||||
|
pkgname=kewt-bin
|
||||||
|
pkgver=VERSION_PLACEHOLDER
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="A minimalist, 100% POSIX, static site generator inspired by werc and kew"
|
||||||
|
arch=('any')
|
||||||
|
url="https://kewt.krzak.org"
|
||||||
|
license=('ISC')
|
||||||
|
depends=('sh')
|
||||||
|
provides=('kewt')
|
||||||
|
conflicts=('kewt' 'kewt-git')
|
||||||
|
source=("${pkgname}-${pkgver}.sh::https://git.krzak.org/N0VA/kewt/releases/download/v${pkgver}/kewt")
|
||||||
|
sha256sums=('SHA256SUM_PLACEHOLDER')
|
||||||
|
|
||||||
|
build() {
|
||||||
|
chmod +x "${srcdir}/${pkgname}-${pkgver}.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
install -Dm755 "${srcdir}/${pkgname}-${pkgver}.sh" "${pkgdir}/usr/bin/kewt"
|
||||||
|
}
|
||||||
16
packaging/homebrew/kewt.rb.template
Normal file
16
packaging/homebrew/kewt.rb.template
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
class Kewt < Formula
|
||||||
|
desc "Minimalist static site generator inspired by werc"
|
||||||
|
homepage "https://kewt.krzak.org"
|
||||||
|
url "https://github.com/n0va-bot/kewt/releases/download/vVERSION_PLACEHOLDER/kewt"
|
||||||
|
sha256 "SHA256SUM_PLACEHOLDER"
|
||||||
|
license "ISC"
|
||||||
|
version "VERSION_PLACEHOLDER"
|
||||||
|
|
||||||
|
def install
|
||||||
|
bin.install "kewt"
|
||||||
|
end
|
||||||
|
|
||||||
|
test do
|
||||||
|
system "#{bin}/kewt", "--version"
|
||||||
|
end
|
||||||
|
end
|
||||||
12
site.conf
12
site.conf
@@ -1,12 +0,0 @@
|
|||||||
title = "kewt"
|
|
||||||
style = "kewt"
|
|
||||||
dir_indexes = true
|
|
||||||
single_file_index = true
|
|
||||||
flatten = false
|
|
||||||
footer = "made with <a href="https://kewt.krzak.org">kewt</a>"
|
|
||||||
logo = ""
|
|
||||||
display_logo = false
|
|
||||||
display_title = true
|
|
||||||
logo_as_favicon = true
|
|
||||||
favicon = ""
|
|
||||||
order = ""
|
|
||||||
@@ -15,3 +15,5 @@ Sed dictum tortor at interdum dignissim. Nunc hendrerit sollicitudin elementum.
|
|||||||
Cras vitae sapien egestas, blandit libero et, volutpat augue. Ut augue quam, sollicitudin quis libero laoreet, bibendum imperdiet massa. Duis sed venenatis risus. Praesent a est mollis, viverra erat quis, faucibus elit. Donec at sagittis est, non posuere nisi. Integer posuere pharetra dui in aliquam. Morbi vehicula eros in hendrerit aliquam. Duis in turpis vel mauris mattis convallis in id tortor. Cras et aliquam augue.
|
Cras vitae sapien egestas, blandit libero et, volutpat augue. Ut augue quam, sollicitudin quis libero laoreet, bibendum imperdiet massa. Duis sed venenatis risus. Praesent a est mollis, viverra erat quis, faucibus elit. Donec at sagittis est, non posuere nisi. Integer posuere pharetra dui in aliquam. Morbi vehicula eros in hendrerit aliquam. Duis in turpis vel mauris mattis convallis in id tortor. Cras et aliquam augue.
|
||||||
|
|
||||||
Cras quis consectetur dolor, a sodales tortor. Vestibulum aliquam lacinia metus, sed viverra erat egestas in. Morbi interdum sapien sed bibendum maximus. Aenean accumsan pharetra libero dapibus aliquam. Etiam sodales purus posuere gravida ullamcorper. Vestibulum tincidunt, nibh a pulvinar aliquet, leo tortor pulvinar diam, ut viverra nunc elit bibendum nulla. Praesent vel pulvinar erat, eu efficitur magna. Mauris at consequat purus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in dui quis nisi elementum aliquam. Proin eget justo sed est commodo accumsan. Suspendisse a feugiat tellus, eget gravida tellus.
|
Cras quis consectetur dolor, a sodales tortor. Vestibulum aliquam lacinia metus, sed viverra erat egestas in. Morbi interdum sapien sed bibendum maximus. Aenean accumsan pharetra libero dapibus aliquam. Etiam sodales purus posuere gravida ullamcorper. Vestibulum tincidunt, nibh a pulvinar aliquet, leo tortor pulvinar diam, ut viverra nunc elit bibendum nulla. Praesent vel pulvinar erat, eu efficitur magna. Mauris at consequat purus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in dui quis nisi elementum aliquam. Proin eget justo sed est commodo accumsan. Suspendisse a feugiat tellus, eget gravida tellus.
|
||||||
|
|
||||||
|
![https://www.youtube.com/embed/NvQD9E5Cq8A]
|
||||||
|
|||||||
BIN
site/favicon.ico
Normal file
BIN
site/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 361 KiB |
131
site/index.md
131
site/index.md
@@ -1,8 +1,12 @@
|
|||||||
# _kewt_
|
# _kewt_
|
||||||
### Pronounced "cute"
|
### Pronounced "cute"
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
# [Go to the repo](https://git.krzak.org/N0VA/kewt)
|
# [Go to the repo](https://git.krzak.org/N0VA/kewt)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
_kewt_ is a minimalist ssg inspired by _[werc](http://werc.cat-v.org/)_ and _[kew](https://github.com/uint23/kew)_
|
_kewt_ is a minimalist ssg inspired by _[werc](http://werc.cat-v.org/)_ and _[kew](https://github.com/uint23/kew)_
|
||||||
|
|
||||||
It's meant to be a static site generator, like _[kew](https://github.com/uint23/kew)_ but use only default (POSIX) tooling, like _[werc](http://werc.cat-v.org/)_ (and definitely unlike _[kew](https://github.com/uint23/kew)_)
|
It's meant to be a static site generator, like _[kew](https://github.com/uint23/kew)_ but use only default (POSIX) tooling, like _[werc](http://werc.cat-v.org/)_ (and definitely unlike _[kew](https://github.com/uint23/kew)_)
|
||||||
@@ -10,27 +14,93 @@ It's meant to be a static site generator, like _[kew](https://github.com/uint23/
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- No dependencies
|
- No dependencies
|
||||||
|
- Frontmatter support (title, date, draft)
|
||||||
- Supports many embed types
|
- Supports many embed types
|
||||||
- Automatic css variable replacement for older browsers
|
- Automatic css variable replacement for older browsers
|
||||||
- Automatic inlining and embedding of many filetypes with `\![link]` or `\`
|
- Automatic inlining and embedding of many filetypes with `\![link]` or `\`
|
||||||
|
- Typed embeds: `\!i`, `\!v`, `\!a`, `\!f`, `\!e`
|
||||||
- Inline html support
|
- Inline html support
|
||||||
- MFM `$font` and `\<plain>` tags
|
- MFM `$font` and `\<plain>` tags
|
||||||
- Admonition support (that's what the blocks like the warning block below are called)
|
- GFM Admonition support (that's what the blocks like the warning block below are called)
|
||||||
|
- Task list support (`- [ ]`, `- [x]`)
|
||||||
|
- RSS/Feed generation and Sitemap support
|
||||||
|
- Post creation via `--post`
|
||||||
|
- Automatic 404 page generation
|
||||||
|
- `?v=n` support for cache busting
|
||||||
|
- Code block classes for use with external libraries like highlight.js or prism.js (both tested)
|
||||||
|
- Clickable markdown header anchors
|
||||||
|
- Mobile responsive layout
|
||||||
|
|
||||||
If you want to **force** a file to be inlined, use `\!![]` instead of `\![]`
|
If you want to **force** a file to be inlined, use `\!![]` instead of `\![]`
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Standalone
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -L -o kewt https://git.krzak.org/N0VA/kewt/releases/download/latest/kewt
|
||||||
|
chmod +x kewt
|
||||||
|
```
|
||||||
|
|
||||||
|
### From source
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://git.krzak.org/N0VA/kewt.git
|
||||||
|
cd kewt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Building
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Installing
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Package Managers
|
||||||
|
|
||||||
|
#### AUR
|
||||||
|
|
||||||
|
- [kewt-bin](https://aur.archlinux.org/packages/kewt-bin) — prebuilt standalone binary from the latest release
|
||||||
|
- [kewt-git](https://aur.archlinux.org/packages/kewt-git) — built from the latest git source
|
||||||
|
|
||||||
|
#### Homebrew
|
||||||
|
|
||||||
|
```sh
|
||||||
|
brew tap n0va-bot/tap
|
||||||
|
brew install kewt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### bpkg
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bpkg install n0va-bot/kewt
|
||||||
|
```
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./kewt.sh --help
|
./kewt.sh --help
|
||||||
|
./kewt.sh --version
|
||||||
./kewt.sh --new [title]
|
./kewt.sh --new [title]
|
||||||
|
./kewt.sh --post
|
||||||
./kewt.sh --from <src> --to <out>
|
./kewt.sh --from <src> --to <out>
|
||||||
./kewt.sh [src] [out]
|
./kewt.sh [src] [out]
|
||||||
```
|
```
|
||||||
|
|
||||||
`--new [title]` creates a new site directory with a copied `site.conf` and a default `index.md`.
|
`--new [title]` creates a new site directory with a copied `site.conf` and a default `index.md`.
|
||||||
|
|
||||||
## site.conf
|
`--post [title]` creates a new markdown file in the configured `posts_dir` with the current date/time as the name and creates the default frontmatter.
|
||||||
|
|
||||||
|
### site.conf
|
||||||
|
|
||||||
```conf
|
```conf
|
||||||
title = "kewt"
|
title = "kewt"
|
||||||
@@ -41,12 +111,23 @@ flatten = false
|
|||||||
order = ""
|
order = ""
|
||||||
home_name = "Home"
|
home_name = "Home"
|
||||||
show_home_in_nav = true
|
show_home_in_nav = true
|
||||||
footer = "made with <a href="https://kewt.krzak.org">kewt</a>"
|
nav_links = ""
|
||||||
|
nav_extra = ""
|
||||||
|
footer = "made with <a href=\"https://kewt.krzak.org\">kewt</a>"
|
||||||
logo = ""
|
logo = ""
|
||||||
display_logo = false
|
display_logo = false
|
||||||
display_title = true
|
display_title = true
|
||||||
logo_as_favicon = true
|
logo_as_favicon = true
|
||||||
favicon = ""
|
favicon = ""
|
||||||
|
generate_page_title = true
|
||||||
|
error_page = "not_found.html"
|
||||||
|
versioning = false
|
||||||
|
base_url = ""
|
||||||
|
generate_feed = false
|
||||||
|
feed_file = "rss.xml"
|
||||||
|
posts_dir = ""
|
||||||
|
enable_header_links = true
|
||||||
|
custom_admonitions = ""
|
||||||
```
|
```
|
||||||
|
|
||||||
- `title` site title
|
- `title` site title
|
||||||
@@ -57,20 +138,31 @@ favicon = ""
|
|||||||
- `order` comma separated file/directory name list to order the sidebar (alphabetical by default)
|
- `order` comma separated file/directory name list to order the sidebar (alphabetical by default)
|
||||||
- `home_name` text for the home link in navigation (default: "Home")
|
- `home_name` text for the home link in navigation (default: "Home")
|
||||||
- `show_home_in_nav` show home link in navigation (default: true)
|
- `show_home_in_nav` show home link in navigation (default: true)
|
||||||
|
- `nav_links` comma separated extra nav links, as bare URLs or Markdown links like `[Label](https://example.com)`
|
||||||
|
- `nav_extra` raw HTML appended inside the `<nav>` after the generated link list
|
||||||
- `footer` footer html/text shown at the bottom of pages
|
- `footer` footer html/text shown at the bottom of pages
|
||||||
- `logo` logo image path (used in header if enabled)
|
- `logo` logo image path (used in header if enabled)
|
||||||
- `display_logo` show logo in header
|
- `display_logo` show logo in header
|
||||||
- `display_title` show title text in header
|
- `display_title` show title text in header
|
||||||
- `logo_as_favicon` use `logo` as favicon
|
- `logo_as_favicon` use `logo` as favicon
|
||||||
- `favicon` explicit favicon path (used when `logo_as_favicon` is false or no logo is set)
|
- `favicon` explicit favicon path (used when `logo_as_favicon` is false or no logo is set)
|
||||||
|
- `generate_page_title` automatically generate title text from the first markdown heading or filename (default: true)
|
||||||
|
- `error_page` filename for the generated 404 error page (default: "not_found.html", empty to disable)
|
||||||
|
- `versioning` append a version query parameter (`?v=timestamp`) to css asset urls to bypass cache (default: false)
|
||||||
|
- `base_url` absolute URL of the site, used for sitemap and RSS feed generation
|
||||||
|
- `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.
|
||||||
|
- `enable_header_links` turns markdown section headings into clickable anchor links (default: true)
|
||||||
|
- `custom_admonitions` comma separated list of custom admonitions
|
||||||
|
|
||||||
## Ignores
|
### Ignores
|
||||||
|
|
||||||
- `.kewtignore`: Files/directories to ignore. If empty, the whole directory gets ignored
|
- `.kewtignore`: Files/directories to ignore. If empty, the whole directory gets ignored
|
||||||
- `.kewthide`: Files/directories to hide from navigation but still process. Same empty rules as with ignore
|
- `.kewthide`: Files/directories to hide from navigation but still process. Same empty rules as with ignore
|
||||||
- `.kewtpreserve`: Files/directories to copy but not convert markdown to html. Same empty rules again
|
- `.kewtpreserve`: Files/directories to copy but not convert markdown to html. Same empty rules again
|
||||||
|
|
||||||
## Embeds
|
### Embeds
|
||||||
|
|
||||||
- `\![link]`:
|
- `\![link]`:
|
||||||
- local image/audio/video files are embedded as media tags
|
- local image/audio/video files are embedded as media tags
|
||||||
@@ -79,11 +171,30 @@ favicon = ""
|
|||||||
- other global links are embedded as `<iframe>`
|
- other global links are embedded as `<iframe>`
|
||||||
- `\` works the same, with `alt` used for images
|
- `\` works the same, with `alt` used for images
|
||||||
- `\!![]` and `\!` force inline local file contents
|
- `\!![]` and `\!` force inline local file contents
|
||||||
|
- **Typed Embeds**: Force specific output regardless of extension:
|
||||||
|
- `\!i[link]` or `\!i[alt](link)`: **I**mage
|
||||||
|
- `\!v[link]`: **V**ideo
|
||||||
|
- `\!a[link]`: **A**udio
|
||||||
|
- `\!f[link]`: I**f**rame
|
||||||
|
- `\!e[link]`: Inline/**e**mbed text/code file directly
|
||||||
|
|
||||||
## Credits
|
### Frontmatter
|
||||||
|
|
||||||
- Markdown to html conversion based on [markdown.bash](https://github.com/chadbraunduin/markdown.bash) by [chadbraunduin](https://github.com/chadbraunduin)
|
You can set metadata for a page using a `site.conf`-style frontmatter block at the very top of `.md` files:
|
||||||
- Default css style and html template based on _[kew](https://github.com/uint23/kew)_ by [uint23](https://github.com/uint23)
|
|
||||||
|
|
||||||
>![WARNING]
|
```conf
|
||||||
>Most of this was coded at night, while sleepy and a bit sick, and after walking for about 4 hours around a forest, so...
|
---
|
||||||
|
title = "Custom Page Title"
|
||||||
|
date = "2026-03-23 11:32"
|
||||||
|
draft = false
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
- `title`: Overrides the page title, post name in index links, and RSS `<title>`.
|
||||||
|
- `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
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
>[!WARNING]
|
||||||
|
>The base that all of this is built upon was coded at night, while sleepy and a bit sick, and after walking for about 4 hours around a forest, so...
|
||||||
|
|||||||
@@ -3,10 +3,20 @@ style = "kewt"
|
|||||||
dir_indexes = true
|
dir_indexes = true
|
||||||
single_file_index = true
|
single_file_index = true
|
||||||
flatten = false
|
flatten = false
|
||||||
footer = "<a href="https://kewt.krzak.org"><img src="/button.gif" /></a>"
|
footer = "<a href=\"https://kewt.krzak.org\"><img src=\"/button.gif\" /></a>"
|
||||||
logo = ""
|
logo = ""
|
||||||
display_logo = false
|
display_logo = false
|
||||||
display_title = true
|
display_title = true
|
||||||
logo_as_favicon = true
|
logo_as_favicon = false
|
||||||
favicon = ""
|
favicon = "favicon.ico"
|
||||||
order = ""
|
order = ""
|
||||||
|
home_name = "Home"
|
||||||
|
show_home_in_nav = true
|
||||||
|
nav_links = ""
|
||||||
|
nav_extra = ""
|
||||||
|
generate_page_title = true
|
||||||
|
error_page = "not_found.html"
|
||||||
|
versioning = true
|
||||||
|
enable_header_links = true
|
||||||
|
base_url = "https://kewt.krzak.org"
|
||||||
|
custom_admonitions = ""
|
||||||
|
|||||||
127
styles/kewt.css
127
styles/kewt.css
@@ -1,25 +1,28 @@
|
|||||||
:root {
|
:root {
|
||||||
--bg: #646c7f;
|
--bg: #4a3b69;
|
||||||
--fg: #fffde0;
|
--bg-deep: #352654;
|
||||||
--fg-link: #fff18f;
|
--fg: #fbf5ff;
|
||||||
--code-bg: #32394a;
|
--fg-muted: #c8b9df;
|
||||||
--code-border: #8f95a4;
|
--fg-link: #dfaeff;
|
||||||
--code-fg: #fffde0;
|
--fg-heading: #debfff;
|
||||||
--code-sel: #fff18f;
|
--code-bg: #31234c;
|
||||||
--code-prop: #ffd27f;
|
--code-border: #8060af;
|
||||||
--code-val: #cde7ff;
|
--code-fg: #fbf5ff;
|
||||||
--code-var: #b9ffbe;
|
--code-sel: #ffef99;
|
||||||
--code-com: #d0d0d0;
|
--code-prop: #ffdfba;
|
||||||
--adm-note-bg: #3f5666;
|
--code-val: #cae2ff;
|
||||||
--adm-note-border: #a8d8ff;
|
--code-var: #caffc2;
|
||||||
--adm-tip-bg: #3f664c;
|
--code-com: #b8aac8;
|
||||||
--adm-tip-border: #b9ffbe;
|
--adm-note-bg: #353866;
|
||||||
--adm-important-bg: #5a4a6c;
|
--adm-note-border: #b8c5ff;
|
||||||
--adm-important-border: #e4c7ff;
|
--adm-tip-bg: #295246;
|
||||||
--adm-warning-bg: #6b5539;
|
--adm-tip-border: #aeffda;
|
||||||
--adm-warning-border: #ffe0a8;
|
--adm-important-bg: #533076;
|
||||||
--adm-caution-bg: #6f3f3f;
|
--adm-important-border: #f4d9ff;
|
||||||
--adm-caution-border: #ffb4b4;
|
--adm-warning-bg: #634631;
|
||||||
|
--adm-warning-border: #ffe2bd;
|
||||||
|
--adm-caution-bg: #662d43;
|
||||||
|
--adm-caution-border: #ffc4d5;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -29,18 +32,22 @@ body {
|
|||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
font-family: serif;
|
font-family: serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.2;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: 1px solid var(--code-border);
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header h1 {
|
header h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 35px;
|
font-size: 35px;
|
||||||
font-weight: normal;
|
font-weight: bold;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
color: var(--fg-heading);
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-logo {
|
.site-logo {
|
||||||
@@ -57,18 +64,26 @@ header a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header a:hover {
|
||||||
|
color: var(--bg-deep);
|
||||||
|
background: var(--fg);
|
||||||
|
}
|
||||||
|
|
||||||
#side-bar {
|
#side-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 80px;
|
top: 80px;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
|
margin-right: 14px;
|
||||||
|
border-right: 1px solid var(--code-border);
|
||||||
|
padding-right: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-title {
|
.side-title {
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
margin: 20px 0 8px 0;
|
margin: 20px 0 8px 0;
|
||||||
color: var(--fg);
|
color: var(--fg-heading);
|
||||||
}
|
}
|
||||||
|
|
||||||
#side-bar ul {
|
#side-bar ul {
|
||||||
@@ -87,6 +102,14 @@ a {
|
|||||||
padding: 1px 2px;
|
padding: 1px 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#side-bar a.current-page {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--fg);
|
||||||
|
border-left: 3px solid var(--fg-link);
|
||||||
|
padding-left: 7px;
|
||||||
|
margin-left: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
@@ -100,7 +123,7 @@ article {
|
|||||||
h3 {
|
h3 {
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
color: var(--fg);
|
color: var(--fg-heading);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,10 +220,11 @@ pre code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding-top: 80px;
|
padding-top: 60px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
color: var(--fg-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
article,
|
article,
|
||||||
@@ -208,3 +232,54 @@ footer {
|
|||||||
margin-left: 240px;
|
margin-left: 240px;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
image-rendering: auto;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
image-rendering: -webkit-optimize-contrast;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer img {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
height: 0;
|
||||||
|
margin: 24px 0;
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid var(--code-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
#side-bar {
|
||||||
|
position: relative;
|
||||||
|
top: auto;
|
||||||
|
left: auto;
|
||||||
|
width: auto;
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: 1px solid var(--code-border);
|
||||||
|
padding: 0 0 20px 0;
|
||||||
|
margin: 0 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
margin: 0 20px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-item {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-item-checkbox {
|
||||||
|
margin: 0 0.2em 0.25em -1.6em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<title>{{TITLE}}</title>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{CSS}}" type="text/css" />
|
|
||||||
{{HEAD_EXTRA}}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<h1>{{HEADER_BRAND}}</h1>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<nav id="side-bar">{{NAV}}</nav>
|
|
||||||
|
|
||||||
<article>{{CONTENT}}</article>
|
|
||||||
<footer>{{FOOTER}}</footer>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
39
tools/build-standalone.sh
Executable file
39
tools/build-standalone.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
|
||||||
|
if [ ! -f "$REPO_ROOT/kewt.sh" ]; then
|
||||||
|
echo "kewt.sh not found. Run from the repository root or tools/."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUT_FILE="$REPO_ROOT/kewt"
|
||||||
|
|
||||||
|
cat << 'EOF' > "$OUT_FILE"
|
||||||
|
#!/bin/sh
|
||||||
|
tmpdir=$(mktemp -d "/tmp/kewt.XXXXXX")
|
||||||
|
trap 'rm -rf "$tmpdir"' EXIT HUP INT TERM
|
||||||
|
|
||||||
|
# Extract payload
|
||||||
|
sed '1,/^#==PAYLOAD==$/d' "$0" | tar -xz -C "$tmpdir"
|
||||||
|
|
||||||
|
# Pass control to the extracted script
|
||||||
|
KEWT_INVOKED_AS="$0" "$tmpdir/kewt.sh" "$@"
|
||||||
|
exit $?
|
||||||
|
|
||||||
|
#==PAYLOAD==
|
||||||
|
EOF
|
||||||
|
|
||||||
|
VERSION=$(git describe --tags 2>/dev/null || echo "standalone")
|
||||||
|
tmpbuild=$(mktemp -d)
|
||||||
|
cp -r "$REPO_ROOT/kewt.sh" "$REPO_ROOT/markdown.sh" "$REPO_ROOT/awk" "$REPO_ROOT/styles" "$tmpbuild/"
|
||||||
|
sed -e "s/kewt version git/kewt version $VERSION/" "$tmpbuild/kewt.sh" > "$tmpbuild/kewt.sh.tmp" && mv "$tmpbuild/kewt.sh.tmp" "$tmpbuild/kewt.sh"
|
||||||
|
chmod +x "$tmpbuild/kewt.sh" "$tmpbuild/markdown.sh"
|
||||||
|
tar -cz -C "$tmpbuild" kewt.sh markdown.sh awk styles >> "$OUT_FILE"
|
||||||
|
rm -rf "$tmpbuild"
|
||||||
|
|
||||||
|
chmod +x "$OUT_FILE"
|
||||||
|
|
||||||
|
echo "Generated standalone executable at $OUT_FILE"
|
||||||
Reference in New Issue
Block a user