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
38 changes: 38 additions & 0 deletions docs/post/grove/file-preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* global document, window */

if (window.location.protocol === "file:") {
const setText = (selector, value) => {
const element = document.querySelector(selector);
if (element) element.textContent = value;
};

const showLocalPreview = () => {
document.body.classList.remove("is-checking");
document.body.classList.add("is-local-preview");

setText("[data-view-state]", "Local preview · open the hosted Grove for live stats");
setText("[data-snapshot-state]", "Local preview");
setText("[data-network]", "Sepolia");
setText("[data-view-time]", "Not connected");
setText("[data-snapshot-cadence]", "15 min");
setText("[data-node-count]", "—");
setText("[data-view-age]", "Not connected");
setText("[data-node-hours]", "—");
setText("[data-history-low]", "—");
setText("[data-history-high]", "—");
setText("[data-history-samples]", "0");
setText("[data-history-coverage]", "0%");

const chart = document.querySelector("[data-history-chart]");
chart?.setAttribute(
"aria-label",
"Local file preview. Open the hosted Grove for live signed count history.",
);
};

if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", showLocalPreview, { once: true });
} else {
showLocalPreview();
}
}
4 changes: 2 additions & 2 deletions docs/post/grove/grove.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
background:
radial-gradient(circle at 50% 16%, rgba(101, 125, 95, 0.14), transparent 31rem),
linear-gradient(180deg, rgba(7, 12, 9, 0.86), rgba(7, 12, 9, 0.98)),
url("/fig/shade-tree-banner.webp") center / cover no-repeat;
url("../fig/shade-tree-banner.webp") center / cover no-repeat;
}

.network-hero {
Expand Down Expand Up @@ -761,7 +761,7 @@
}

@media (max-width: 360px) {
.network-page .nav-links a[href="/research/"] {
.network-page .nav-links a[href="../research/index.html"] {
display: none;
}

Expand Down
19 changes: 10 additions & 9 deletions docs/post/grove/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,25 @@
<meta property="og:image:alt" content="A non-geographic canopy with one tree per announced identity">
<meta name="twitter:card" content="summary_large_image">
<link rel="canonical" href="https://shade-tree-node.vercel.app/grove/">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="/site.css">
<link rel="stylesheet" href="/grove/grove.css">
<script type="module" src="/grove/network.js"></script>
<link rel="icon" href="../favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="../site.css">
<link rel="stylesheet" href="./grove.css">
<script type="module" src="./network.js"></script>
<script src="./file-preview.js" defer></script>
<title>Shade Tree Grove Network Stats</title>
</head>
<body class="network-page is-checking">
<a class="skip-link" href="#grove-main">Skip to Grove details</a>

<header class="network-hero" aria-labelledby="grove-title">
<nav class="site-nav" aria-label="Primary navigation">
<a class="wordmark" href="/" aria-label="Shade Tree Grove home">
<a class="wordmark" href="../index.html" aria-label="Shade Tree Grove home">
<span class="tree-mark" aria-hidden="true"><i></i><i></i><i></i></span>
<span>Shade Tree Grove</span>
</a>
<div class="nav-links">
<a href="/grove/" aria-current="page">Grove</a>
<a href="/research/">Research</a>
<a href="./index.html" aria-current="page">Grove</a>
<a href="../research/index.html">Research</a>
<a href="https://github.com/dmarzzz/shade-tree-node">Source</a>
</div>
</nav>
Expand Down Expand Up @@ -134,8 +135,8 @@ <h2 id="history-title">24 hours of shade</h2>
<footer class="site-footer">
<span>Research preview</span>
<nav aria-label="Project links">
<a href="/">Home</a>
<a href="/research/">Research</a>
<a href="../index.html">Home</a>
<a href="../research/index.html">Research</a>
<a href="https://github.com/dmarzzz/shade-tree-node">Source</a>
</nav>
</footer>
Expand Down
2 changes: 1 addition & 1 deletion docs/post/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ body:not(.home-page)::before {
content: "";
background:
linear-gradient(180deg, rgba(7, 16, 12, 0.8), rgba(7, 16, 12, 0.97)),
url("/fig/shade-tree-banner.webp") center / cover no-repeat;
url("./fig/shade-tree-banner.webp") center / cover no-repeat;
filter: saturate(0.72) contrast(1.05);
transform: scale(1.02);
}
Expand Down
5 changes: 4 additions & 1 deletion test/site.selftest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const labCss = read("lab/lab.css");
const labScript = read("lab/lab.js");
const groveCss = read("grove/grove.css");
const groveLoader = read("grove/network.js");
const groveFilePreview = read("grove/file-preview.js");
const groveScene = read("grove/scene.js");
const groveFreshness = read("grove/freshness.js");
const groveHistory = read("grove/history.js");
Expand Down Expand Up @@ -97,6 +98,7 @@ check("Protocol Lab keeps sensitive fields out of its public card", /IP, target,
check("Protocol Lab route is responsive and reduced-motion safe", /@media \(max-width: 650px\)[\s\S]*?\.route-stages\s*\{[\s\S]*?grid-template-columns:\s*1fr/.test(labCss) && /@media \(prefers-reduced-motion: reduce\)/.test(labCss) && /matchMedia\("\(prefers-reduced-motion: reduce\)"\)/.test(labScript));
check("Protocol Lab has replay, local-run, and post-success share actions", /Walk this route/.test(labPage) && /data-share>Share this route/.test(labPage) && /data-copy-link>Copy route link/.test(labPage) && /href="\.\.\/agent\/index\.html">Run locally/.test(labPage) && /result\.hidden = true/.test(labScript) && /result\.hidden = false/.test(labScript));
check("Protocol Lab opens as a styled app from direct-file and clean hosted URLs", /href="\.\/lab\/index\.html">Lab/.test(landing) && /href="\.\.\/site\.css"/.test(labPage) && /href="\.\.\/lab\/lab\.css"/.test(labPage) && /src="\.\.\/lab\/lab\.js"/.test(labPage) && /href="\.\.\/index\.html"/.test(labPage) && !/(?:href|src)="\/(?:site|favicon|lab|agent|grove|research)/.test(labPage) && /new URL\(canonicalLabUrl\)/.test(labScript) && /history\.replaceState\(null, "", `\?scenario=/.test(labScript));
check("Grove opens as a styled, honest preview from direct-file and a live app when hosted", /href="\.\.\/site\.css"/.test(grovePage) && /href="\.\/grove\.css"/.test(grovePage) && /src="\.\/network\.js"/.test(grovePage) && /src="\.\/file-preview\.js"/.test(grovePage) && /href="\.\.\/index\.html"/.test(grovePage) && /href="\.\.\/research\/index\.html"/.test(grovePage) && !/(?:href|src)="\/(?:site|favicon|fig|grove|research)/.test(grovePage) && /window\.location\.protocol === "file:"/.test(groveFilePreview) && /Local preview · open the hosted Grove for live stats/.test(groveFilePreview) && /data-node-count\]", "—"/.test(groveFilePreview));
check("Protocol Lab has a dedicated static social image", /og:image" content="https:\/\/shade-tree-node\.vercel\.app\/fig\/shade-tree-lab-og\.png"/.test(labPage));
check("landing has one H1 and one decorative canvas", (landing.match(/<h1\b/g) || []).length === 1 && (landing.match(/<canvas[^>]+aria-hidden="true"/g) || []).length === 1);
check("Grove has one H1, one focused detail section, and one live status", (grovePage.match(/<h1\b/g) || []).length === 1 && (grovePage.match(/<main\b/g) || []).length === 1 && (grovePage.match(/<section\b/g) || []).length === 1 && /role="status" aria-live="polite"/.test(grovePage));
Expand Down Expand Up @@ -188,6 +190,7 @@ for (const asset of [
"grove/index.html",
"grove/grove.css",
"grove/network.js",
"grove/file-preview.js",
"grove/scene.js",
"grove/freshness.js",
"grove/history.js",
Expand Down Expand Up @@ -283,7 +286,7 @@ check("tampering with the bundled count breaks its signature", !verifyPublicGrov
const fallbackText = JSON.stringify(fallbackSnapshot);
check("bundled snapshot contains no identity, place, activity, or pulse field", !/\.onion|pubkey|operator|wallet|address|region|country|coordinates?|asn|destination|tunnels?|bytes|requests?|queries|pulse/i.test(fallbackText));

for (const script of ["site.js", "grove.js", "grove/network.js", "grove/scene.js", "grove/freshness.js", "grove/history.js", "grove/visual-model.js", "grove/onchain.js", "api/grove.mjs", "api/_grove-contract.mjs", "api/grove-v2.mjs", "api/_grove-v2-contract.mjs", "api/_grove-onchain-contract.mjs"]) {
for (const script of ["site.js", "grove.js", "grove/network.js", "grove/file-preview.js", "grove/scene.js", "grove/freshness.js", "grove/history.js", "grove/visual-model.js", "grove/onchain.js", "api/grove.mjs", "api/_grove-contract.mjs", "api/grove-v2.mjs", "api/_grove-v2-contract.mjs", "api/_grove-onchain-contract.mjs"]) {
const result = spawnSync(process.execPath, ["--check", join(SITE, script)], { encoding: "utf8" });
check(`${script} parses as JavaScript`, result.status === 0);
}
Expand Down