diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4e6226c3..57bb52c6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -697,11 +697,25 @@ jobs: # mrdocs documenting mrdocs demo mrdocs --config="$(pwd)/docs/mrdocs.yml" "$(pwd)/CMakeLists.txt" --output="$(pwd)/demos/mrdocs/$variant/$generator" --multipage=$multipage --generator="$generator" --log-level=debug done + # Render the asciidoc files to html using asciidoctor if [[ ${{ runner.os }} == 'Linux' ]]; then for project in boost-url mrdocs; do - mkdir -p "$(pwd)/demos/$project/$variant/adoc-asciidoc" - asciidoctor -D "$(pwd)/demos/$project/$variant/adoc-asciidoc" "$(pwd)/demos/$project/$variant/adoc/*.adoc" + root="$(pwd)/demos/$project/$variant" + src="$root/adoc" + dst="$root/adoc-asciidoc" + + # Create the top-level output dir + mkdir -p "$dst" + + # Find every .adoc (recursively), mirror the directory structure, and render + find "$src" -type f -name '*.adoc' -print0 | + while IFS= read -r -d '' f; do + rel="${f#"$src/"}" # path relative to $src + outdir="$dst/$(dirname "$rel")" # mirror subdir inside $dst + mkdir -p "$outdir" + asciidoctor -D "$outdir" "$f" + done done fi done diff --git a/docs/build_docs.sh b/docs/build_docs.sh old mode 100644 new mode 100755 diff --git a/docs/build_local_docs.sh b/docs/build_local_docs.sh old mode 100644 new mode 100755 diff --git a/docs/extensions/mrdocs-demos.js b/docs/extensions/mrdocs-demos.js index 57a8d266b..a722abff3 100644 --- a/docs/extensions/mrdocs-demos.js +++ b/docs/extensions/mrdocs-demos.js @@ -13,11 +13,14 @@ const fs = require("fs"); function getSubdirectoriesSync(url) { try { + // cache setup let urlPath = new URL(url).pathname; let cacheFilenamePath = urlPath.replace(/[^a-zA-Z0-9]/g, '') + '.json'; let cachePath = `${__dirname}/../build/requests/${cacheFilenamePath}`; fs.mkdirSync(`${__dirname}/../build/requests/`, {recursive: true}); const readFromCacheFile = fs.existsSync(cachePath) && fs.statSync(cachePath).mtime > new Date(Date.now() - 1000 * 60 * 60 * 24); + + // read file or make request const data = readFromCacheFile ? fs.readFileSync(cachePath, 'utf-8') : @@ -25,15 +28,68 @@ function getSubdirectoriesSync(url) { if (!readFromCacheFile) { fs.writeFileSync(cachePath, data); } - const regex = //g; - const directories = []; + + // parse entries: name + date (if present) + // Matches: name/ [spaces] 11-Sep-2025 20:51 + const entryRe = /[^<]*<\/a>\s+(\d{2}-[A-Za-z]{3}-\d{4}\s+\d{2}:\d{2})?/g; + + const month = { Jan:0,Feb:1,Mar:2,Apr:3,May:4,Jun:5,Jul:6,Aug:7,Sep:8,Oct:9,Nov:10,Dec:11 }; + const parseDate = (s) => { + if (!s) return null; // missing or no date in listing + // "11-Sep-2025 20:51" + const m = /^(\d{2})-([A-Za-z]{3})-(\d{4})\s+(\d{2}):(\d{2})$/.exec(s.trim()); + if (!m) return null; + const [, d, mon, y, hh, mm] = m; + return new Date(Date.UTC(+y, month[mon], +d, +hh, +mm)); + }; + + const isSemver = (name) => { + // allow optional leading 'v', ignore pre-release/build metadata for ordering + const m = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(name); + if (!m) return null; + return { major: +m[1], minor: +m[2], patch: +m[3] }; + }; + + const entries = []; let match; - while ((match = regex.exec(data)) !== null) { - if (match[1] !== '..' && match[1] !== '.') { - directories.push(match[1]); - } + while ((match = entryRe.exec(data)) !== null) { + const name = match[1]; + if (name === '.' || name === '..') continue; + const dt = parseDate(match[2] || null); + const sv = isSemver(name); + entries.push({ + name, + date: dt, // may be null + semver: !!sv, + major: sv ? sv.major : 0, + minor: sv ? sv.minor : 0, + patch: sv ? sv.patch : 0, + }); } - return directories; + + // sort + entries.sort((a, b) => { + // 1) non-semver first + if (a.semver !== b.semver) return a.semver ? 1 : -1; + + if (!a.semver && !b.semver) { + // non-semver: newer date first; if no date, push to end among non-semver + const ad = a.date ? a.date.getTime() : -Infinity; + const bd = b.date ? b.date.getTime() : -Infinity; + if (ad !== bd) return bd - ad; + // tie-breaker: name asc for stability + return a.name.localeCompare(b.name); + } + + // semver: major ↓, minor ↓, patch ↓ + if (a.major !== b.major) return b.major - a.major; + if (a.minor !== b.minor) return b.minor - a.minor; + if (a.patch !== b.patch) return b.patch - a.patch; + // final tie-breaker: name asc + return a.name.localeCompare(b.name); + }); + + return entries.map(e => e.name); } catch (error) { console.error('Error:', error); return []; @@ -144,8 +200,6 @@ module.exports = function (registry) { } // Remove Rendered Asciidoc from the list of formats - // - The raw Asciidoc is already rendered by the mrdocs.com server as HTML - versionFormats = versionFormats.filter(format => format !== 'adoc-asciidoc'); let multipageFormats = versionFormats.filter(format => format !== 'xml'); let versionFormatColumns = versionFormats.map(format => `*${humanizeFormat(format)}*`).join(' | '); @@ -194,11 +248,14 @@ module.exports = function (registry) { } return ''; })() - if (['adoc', 'xml', 'html'].includes(format)) { - const adoc_icon = 'https://avatars.githubusercontent.com/u/3137042?s=200&v=4' - const html_icon = 'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/refs/heads/6.x/svgs/brands/html5.svg' - const code_file_icon = 'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/6.x/svgs/solid/file-code.svg' - const icon = format === 'adoc' ? adoc_icon : format === 'html' ? html_icon : code_file_icon + if (['adoc', 'xml', 'html', 'adoc-asciidoc'].includes(format)) { + const formatIcons = { + adoc: 'https://avatars.githubusercontent.com/u/3137042?s=200&v=4', + html: 'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/refs/heads/6.x/svgs/brands/html5.svg', + 'adoc-asciidoc': 'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/refs/heads/6.x/svgs/brands/html5.svg', + default: 'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/6.x/svgs/solid/file-code.svg' + }; + const icon = formatIcons[format] || formatIcons.default; text += `| image:${icon}[${humanizeLibrary(library)} reference in ${humanizeFormat(format)} format,width=16,height=16,link=${demoUrlWithSuffix},window=_blank]` } else { text += `| ${demoUrlWithSuffix}[🔗,window=_blank]` diff --git a/docs/extensions/mrdocs-releases.js b/docs/extensions/mrdocs-releases.js index ec5c14996..5eb708523 100644 --- a/docs/extensions/mrdocs-releases.js +++ b/docs/extensions/mrdocs-releases.js @@ -174,7 +174,7 @@ module.exports = function (registry) { for (const suffix of assetSuffixes) { const asset = release.assets.find(asset => asset.name.endsWith(suffix)) if (asset) { - text += `| ${asset.browser_download_url}[🔗 ${asset.name}]\n\n(${humanizeBytes(asset.size)}) ` + text += `| ${asset.browser_download_url}[${asset.name}]\n\n(${humanizeBytes(asset.size)}) ` } else { text += '| - ' } diff --git a/docs/modules/ROOT/images/icons/apple.svg b/docs/modules/ROOT/images/icons/apple.svg new file mode 100644 index 000000000..2ad7d19a3 --- /dev/null +++ b/docs/modules/ROOT/images/icons/apple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/modules/ROOT/images/icons/asciidoc.svg b/docs/modules/ROOT/images/icons/asciidoc.svg new file mode 100644 index 000000000..2c525a981 --- /dev/null +++ b/docs/modules/ROOT/images/icons/asciidoc.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modules/ROOT/images/icons/code_blocks.svg b/docs/modules/ROOT/images/icons/code_blocks.svg new file mode 100644 index 000000000..cd01e11a5 --- /dev/null +++ b/docs/modules/ROOT/images/icons/code_blocks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/modules/ROOT/images/icons/html5.svg b/docs/modules/ROOT/images/icons/html5.svg new file mode 100644 index 000000000..1c994a7bf --- /dev/null +++ b/docs/modules/ROOT/images/icons/html5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/modules/ROOT/images/icons/link.svg b/docs/modules/ROOT/images/icons/link.svg new file mode 100644 index 000000000..13cf8ebd7 --- /dev/null +++ b/docs/modules/ROOT/images/icons/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/modules/ROOT/images/icons/linux.svg b/docs/modules/ROOT/images/icons/linux.svg new file mode 100644 index 000000000..6ffc1d99d --- /dev/null +++ b/docs/modules/ROOT/images/icons/linux.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/modules/ROOT/images/icons/package.svg b/docs/modules/ROOT/images/icons/package.svg new file mode 100644 index 000000000..2b977b49d --- /dev/null +++ b/docs/modules/ROOT/images/icons/package.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/modules/ROOT/images/icons/windows.svg b/docs/modules/ROOT/images/icons/windows.svg new file mode 100644 index 000000000..77db4cc65 --- /dev/null +++ b/docs/modules/ROOT/images/icons/windows.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/ui/build.sh b/docs/ui/build.sh old mode 100644 new mode 100755