diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index e578fbf..49b59fa 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -98,6 +98,17 @@ jobs: [ -f "$lf" ] && cp "$lf" "${STAGE}/" done + # Copy assets/ folder if it exists (favicon, images, etc.) + if [ -d "assets" ]; then + mkdir -p "${STAGE}/assets" + find ./assets -type f \( -name '*.svg' -o -name '*.png' -o -name '*.ico' -o -name '*.jpg' -o -name '*.webp' \) \ + | while read -r f; do + dest="${STAGE}/${f#./}" + mkdir -p "$(dirname "$dest")" + cp "$f" "$dest" + done + fi + find "${STAGE}" -name '.gitkeep' -delete echo "Staged files:" @@ -131,10 +142,9 @@ jobs:
No releases found.
'; return; } + function esc(s) { return s.replace(//g,'>'); } + function inline(s) { var codes = []; s = s.replace(/`([^`]+)`/g, function(m, code) { - codes.push(code.replace(//g,'>')); - return '\x00CODE' + (codes.length - 1) + '\x00'; + codes.push(esc(code)); + return '\x00C' + (codes.length - 1) + '\x00'; }); s = s .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1') - .replace(/(https?:\/\/[^\s<)]+)/g, function(m, url, offset, str) { - if (str.charAt(offset - 1) === '"' || str.charAt(offset - 1) === '>' || str.substring(offset - 6, offset) === 'href="') return m; - return '' + url + ''; + .replace(/(^|[^"'>])(https?:\/\/[^\s<)]+)/g, function(m, pre, url) { + return pre + '' + url + ''; }) .replace(/(^|[\s(])@([a-zA-Z0-9_-]+)/g, function(m, pre, user) { return pre + '@' + user + ''; }) .replace(/\*\*([^*]+)\*\*/g, '$1') - .replace(/(?$1'); - s = s.replace(/\x00CODE(\d+)\x00/g, function(m, idx) { + .replace(/(^|[^*])\*([^*\n]+)\*([^*]|$)/g, '$1$2$3'); + s = s.replace(/\x00C(\d+)\x00/g, function(m, idx) { return '' + codes[parseInt(idx)] + '';
});
return s;
@@ -344,52 +369,46 @@ jobs:
function md(s) {
if (!s) return '';
var lines = s.split('\n');
- var html = '';
+ var out = '';
var inList = false;
for (var i = 0; i < lines.length; i++) {
- var line = lines[i];
- var h3 = line.match(/^### (.+)$/);
- var h2 = line.match(/^## (.+)$/);
- var li = line.match(/^\* (.+)$/);
- var cb = line.match(/^```(.*)$/);
- if (cb) {
- if (inList) { html += ''; inList = false; }
- var lang = cb[1].trim();
- var escaped = '';
+ var L = lines[i];
+ var mH3 = L.match(/^### (.+)$/);
+ var mH2 = L.match(/^## (.+)$/);
+ var mLi = L.match(/^\* (.+)$/);
+ var mCb = L.match(/^```(.*)$/);
+ if (mCb) {
+ if (inList) { out += ''; inList = false; }
+ var lang = mCb[1].trim();
+ var code = '';
i++;
- while (i < lines.length && !lines[i].match(/^```/)) { escaped += lines[i] + '\n'; i++; }
- escaped = escaped.replace(//g,'>');
- var langClass = lang ? ' class="language-' + lang + '"' : '';
- html += '' + escaped + '';
- } else if (h2) {
- if (inList) { html += ''; inList = false; }
- html += '' + esc(code) + '';
+ } else if (mH2) {
+ if (inList) { out += ''; inList = false; }
+ out += '' + inline(line) + '
'; - } + if (inList) { out += ''; inList = false; } + var trimmed = L.trim(); + if (trimmed === '---') { out += '' + inline(L) + '
'; } } } - if (inList) html += ''; - return html; + if (inList) out += ''; + return out; } - // Fetch hash file contents for assets that are hash files - async function fetchHashContent(url) { + async function getHash(url) { try { - var r = await fetch(url); - if (r.ok) { - var text = await r.text(); - return text.trim(); - } + var r = await fetch(url, {headers:{'Accept':'application/octet-stream'}}); + if (r.ok) return (await r.text()).trim(); } catch(e) {} return null; } @@ -397,79 +416,65 @@ jobs: var html = ''; for (var i = 0; i < data.length; i++) { var r = data[i]; - var d = new Date(r.published_at).toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' }); - var latest = i === 0 ? 'latest' : ''; + var d = new Date(r.published_at).toLocaleDateString('en-GB', {day:'numeric',month:'short',year:'numeric'}); + var latest = i === 0 ? ' latest' : ''; var openAttr = i === 0 ? ' open' : ''; - // Commit SHA in header var sha = r.target_commitish || ''; - var shortSha = sha.substring(0, 7); - var shaHtml = ''; - if (sha.length >= 7) { - shaHtml = '' + shortSha + ''; - } + var shortSha = sha.length >= 7 ? sha.substring(0, 7) : ''; + var shaHtml = shortSha ? '' + shortSha + '' : ''; - // Assets — show ALL files, no filtering - var assets = ''; var allAssets = r.assets || []; var srcZip = 'https://github.com/' + repo + '/archive/refs/tags/' + r.tag_name + '.zip'; var srcTar = 'https://github.com/' + repo + '/archive/refs/tags/' + r.tag_name + '.tar.gz'; - var totalAssets = allAssets.length + 2; - assets += 'Unable to load releases. Visit GitHub directly.
'; } @@ -490,7 +495,6 @@ jobs: RELEOF echo "Created releases.md" - # ── License page (full content from LICENSE/LICENSE.txt) ────── LICENSE_SRC="" for lf in LICENSE LICENSE.txt; do [ -f "$lf" ] && LICENSE_SRC="$lf" && break @@ -513,7 +517,6 @@ jobs: echo "Processed LICENSE.md" fi - # ── CONTRIBUTING.md ─────────────────────────────────────────── if [ -f "CONTRIBUTING.md" ] && ! head -1 CONTRIBUTING.md | grep -q '^\-\-\-'; then TEMP=$(mktemp) printf -- '---\nlayout: default\ntitle: Contributing\npermalink: /contributing/\n---\n\n' > "$TEMP" @@ -522,7 +525,6 @@ jobs: echo "Processed CONTRIBUTING.md" fi - # ── CODE_OF_CONDUCT.md ──────────────────────────────────────── if [ -f "CODE_OF_CONDUCT.md" ] && ! head -1 CODE_OF_CONDUCT.md | grep -q '^\-\-\-'; then TEMP=$(mktemp) printf -- '---\nlayout: default\ntitle: Code of Conduct\npermalink: /code-of-conduct/\n---\n\n' > "$TEMP" diff --git a/assets/favicon.svg b/assets/favicon.svg new file mode 100644 index 0000000..6bdd79b --- /dev/null +++ b/assets/favicon.svg @@ -0,0 +1,42 @@ + + +