Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/site/src/shared/components/ThemeToggle/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
// Copyright (c) Walrus Foundation
// SPDX-License-Identifier: Apache-2.0


import React from "react";
import NavbarColorModeToggle from "@theme/Navbar/ColorModeToggle";
import { useLocation } from "@docusaurus/router";

export default function ThemeToggle() {
const location = useLocation();
return (
<div className="theme-toggle-wrapper text-white max-[996px]:hidden">
<div className="theme-toggle-wrapper text-white max-[1279px]:hidden">
{location.pathname !== "/" && <NavbarColorModeToggle />}
</div>
);
Expand Down
45 changes: 27 additions & 18 deletions docs/site/src/shared/plugins/remark-glossary.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@
// plugins/remark-glossary.js
// Auto-wraps glossary terms with <Term>…</Term> in MDX content.
//
// Requires: `js-yaml`, `unist-util-visit`
// Requires: `unist-util-visit`
// pnpm add -D js-yaml unist-util-visit

import fs from "fs";
import path from "path";
import * as yaml from "js-yaml";
import { visit } from "unist-util-visit";

function escapeRegex(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

function buildMatcher(entries) {
// Build alternation, longest-first to prefer JSON API over API
// Build alternation, longest-first to prefer "JSON API" over "API"
const terms = entries.flatMap((e) => [e.label, ...(e.aliases || [])]).filter(Boolean);

// De-duplicate (case-insensitive)
Expand All @@ -33,21 +32,21 @@ function buildMatcher(entries) {

unique.sort((a, b) => b.length - a.length);

// \b isnt great for Unicode; use custom boundaries: start|non-word on left/right
// \b isn't great for Unicode; use custom boundaries: start|non-word on left/right
// Also allow inside parentheses/quotes by treating those as boundaries too.
const pattern = unique.map(escapeRegex).join("|");
// If no entries, make a regex that never matches
if (!pattern) return { regex: /$a/, keys: [] };

// Left boundary: start or not letter/number/underscore
// Right boundary: end or not letter/number/underscore
const regex = new RegExp(`(^|[^\\p{L}\\p{N}_])(${pattern})(?=([^\\p{L}\\p{N}_]|$))`, "giu");
const regex = new RegExp(`(^|[^\\p{L}\\p{N}_])(${pattern})(?=[^\\p{L}\\p{N}_]|$)`, "giu");
return { regex, keys: unique };
}

function loadGlossary(glossaryPath) {
const raw = fs.readFileSync(glossaryPath, "utf8");
const data = yaml.load(raw);
const data = JSON.parse(raw);

/** @type {{label:string,definition:string,id?:string,aliases?:string[]}[]} */
const entries = [];
Expand Down Expand Up @@ -75,6 +74,8 @@ function loadGlossary(glossaryPath) {
* @param {{glossaryFile?: string}} options
*/
function remarkGlossary(options = {}) {
console.log(">>> remarkGlossary plugin loaded");

const glossaryFile = options.glossaryFile || "static/glossary.json";
const absPath = path.isAbsolute(glossaryFile)
? glossaryFile
Expand All @@ -93,10 +94,9 @@ function remarkGlossary(options = {}) {
// Nodes we should NOT process beneath
const BLOCK_SKIP = new Set(["code", "pre"]);
const INLINE_SKIP = new Set(["inlineCode", "link", "linkReference"]);
// If author already used <Term>, skip inside it
const MDX_SKIP = new Set(["mdxJsxTextElement", "mdxJsxFlowElement"]);

return function transformer(tree) {

// Track which terms have been processed on this page (case-insensitive)
const processedTerms = new Set();

Expand All @@ -121,16 +121,25 @@ function remarkGlossary(options = {}) {
/** @type {any[]} */
const nextChildren = [];

// Reset regex lastIndex for each node
regex.lastIndex = 0;

// Iterate all matches while preserving unmatched segments
while ((m = regex.exec(value)) !== null) {
const [full, leftBoundary, term] = m;
const start = m.index;
const before = value.slice(last, start);
if (before)
nextChildren.push({
type: "text",
value: before + (leftBoundary || ""),
});
const matchStart = m.index;
const termStart = matchStart + (leftBoundary?.length || 0);

// Text before the match (not including leftBoundary)
const before = value.slice(last, matchStart);
if (before) {
nextChildren.push({ type: "text", value: before });
}

// Add leftBoundary as separate text if present
if (leftBoundary) {
nextChildren.push({ type: "text", value: leftBoundary });
}

const key = String(term).toLowerCase();
const entry = byKey.get(key);
Expand All @@ -156,8 +165,6 @@ function remarkGlossary(options = {}) {
name: "Term",
attributes: [
{ type: "mdxJsxAttribute", name: "lookup", value: entry.label },
// You can also add data attributes if you want:
// {type: 'mdxJsxAttribute', name: 'data-term', value: entry.label},
],
children: [{ type: "text", value: term }],
});
Expand All @@ -166,7 +173,9 @@ function remarkGlossary(options = {}) {
nextChildren.push({ type: "text", value: term });
}
}
last = start + full.length;

// Move past the full match
last = matchStart + full.length;
}

if (last === 0) return; // no matches, keep node as-is
Expand Down
Loading