Skip to content

Commit fe0f38e

Browse files
committed
chore(assets): add self-hosted fonts and custom JS components
Serve Inter and JetBrains Mono from /assets/fonts (latin variable woff2) to eliminate render-blocking cross-origin requests to fonts.googleapis.com. Inter Fallback is a metric-matched local Arial face to prevent CLS on the hero headline during font-swap. Add five custom Oxidoc components as JS modules: LandingNav, LandingHero, CodeWindow, Faq, and WaitlistForm — used by the redesigned landing page.
1 parent 5d081c8 commit fe0f38e

7 files changed

Lines changed: 314 additions & 0 deletions

File tree

assets/fonts/inter-latin.woff2

47.1 KB
Binary file not shown.
30.7 KB
Binary file not shown.

assets/js/code-window.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Landing-page code window — a fixed-palette alternative to oxidoc's
2+
// <CodeBlock>. Oxidoc's syntax tokens are theme-aware (their colours come
3+
// from --oxidoc-tok-* vars that flip with the colour scheme); this one uses
4+
// literal hex on .cw-* classes, so the panel looks identical regardless of
5+
// light/dark. It also lets us highlight NodeDB SQL extensions (e.g.
6+
// `GRAPH RAG FUSION`) that a generic tokenizer doesn't know.
7+
//
8+
// Rendered by <CodeWindow snippet="..." title="..." lang="..." />. RDX emits
9+
// a bare lowercased <codewindow>, so we upgrade by query selector. Custom
10+
// components can't carry RDX children, so snippets live here, pre-highlighted.
11+
12+
(function () {
13+
var SNIPPETS = {
14+
"graphrag-fusion":
15+
'<span class="cw-cm">-- Semantic retrieval + graph context for your LLM. One statement.</span>\n' +
16+
'<span class="cw-kw">GRAPH RAG FUSION ON</span> entities\n' +
17+
' <span class="cw-kw">QUERY</span> <span class="cw-nm">$1</span>\n' +
18+
' <span class="cw-kw">VECTOR_TOP_K</span> <span class="cw-nm">50</span>\n' +
19+
' <span class="cw-kw">EXPANSION_DEPTH</span> <span class="cw-nm">2</span>\n' +
20+
' <span class="cw-kw">EDGE_LABEL</span> <span class="cw-st">&#39;related_to&#39;</span>\n' +
21+
' <span class="cw-kw">DIRECTION</span> both\n' +
22+
' <span class="cw-kw">FINAL_TOP_K</span> <span class="cw-nm">10</span>\n' +
23+
' <span class="cw-kw">RRF_K</span> (<span class="cw-nm">60.0</span>, <span class="cw-nm">35.0</span>)\n' +
24+
' <span class="cw-kw">MAX_VISITED</span> <span class="cw-nm">1000</span>;',
25+
};
26+
27+
function build(host) {
28+
var key = host.getAttribute("snippet") || "";
29+
var title = host.getAttribute("title") || "";
30+
var lang = host.getAttribute("lang") || "";
31+
var code = SNIPPETS[key] || "";
32+
host.innerHTML =
33+
'<div class="cw">' +
34+
'<div class="cw-bar">' +
35+
'<span class="cw-dots"><i></i><i></i><i></i></span>' +
36+
(title ? '<span class="cw-title">' + title + "</span>" : "") +
37+
(lang ? '<span class="cw-lang">' + lang + "</span>" : "") +
38+
"</div>" +
39+
'<pre class="cw-body"><code>' + code + "</code></pre>" +
40+
"</div>";
41+
}
42+
43+
function init() {
44+
document.querySelectorAll("codewindow, CodeWindow").forEach(build);
45+
}
46+
47+
if (document.readyState === "loading") {
48+
document.addEventListener("DOMContentLoaded", init);
49+
} else {
50+
init();
51+
}
52+
})();

assets/js/faq.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Landing-page FAQ — a custom accordion instead of oxidoc's <Accordion>
2+
// (whose <details> + grid-row animation is hard to retheme cleanly on the
3+
// dark page). Content lives here, pre-written, since custom components can't
4+
// carry RDX children. Rendered by <Faq />. RDX emits a bare lowercased
5+
// <faq>, so we upgrade by query selector.
6+
7+
(function () {
8+
var ITEMS = [
9+
{
10+
q: "Isn't one binary with 8 engines just a monolith?",
11+
a: "Yes — deliberately. Sharing one process means cross-engine queries run in the same address space with zero network hops. The alternative (5 services) is a distributed monolith pretending not to be one, with worse latency and worse consistency. We scale horizontally with auto-rebalancing vShards, not by splitting engines.",
12+
},
13+
{
14+
q: "Why not just Postgres + pgvector + extensions?",
15+
a: "Postgres is our wire protocol — that's why your existing client works unchanged. But pgvector bolts a vector index onto a row-store planner that doesn't understand hybrid ranking. We built the planner from scratch to route each sub-query to the engine that fits: graph traversals use CSR, vector search uses HNSW, analytics use columnar.",
16+
},
17+
{
18+
q: "What about multi-tenancy, RLS, and audit logs?",
19+
a: "All first-class. Row-Level Security via <code>CREATE RLS POLICY</code> with <code>$auth.id</code> / <code>$auth.role</code> context — applied transparently to every engine, no app changes. Audit logging captures who did what and when, tamper-evident. Tenant isolation, RBAC, and RLS compose so you can run real multi-tenant SaaS on one cluster without writing your own row filters.",
20+
},
21+
{
22+
q: "Can I query the database as of a past point in time?",
23+
a: "Yes — for the engines where it matters. Bitemporal covers graph, strict documents, columnar (plain + timeseries), arrays, and CRDT sync. Every write there records both <em>valid time</em> (when the fact was true in the real world) and <em>system time</em> (when the database learned it). Run any query <code>AS OF</code> a past moment, audit a row's full history, or do GDPR-compliant erasure that preserves the audit trail. Vector, FTS, KV, and spatial indexes stay current-state-only by design — that's where you want speed, not history.",
24+
},
25+
{
26+
q: "Do you actually handle scientific array data, or is that marketing?",
27+
a: "Real engine. ND coordinate-indexed sparse arrays with Hilbert/Z-order locality, per-tile MBR pruning, compression via our codec stack, WAL-durable, Raft-replicated. Built to replace TileDB / SciDB / Zarr for genomics (variant × sample × position), earth observation (lat × lon × band × time), and climate cubes. And yes — you can join an array slice against a vector ANN search in one SQL query.",
28+
},
29+
{
30+
q: "Does it run on mobile / offline / in the browser?",
31+
a: "Yes. NodeDB-Lite is a 4.5MB WASM + iOS/Android FFI build — the same 8 engines, embedded. Edge-to-cloud sync is CRDT-native via Loro, so offline writes merge deterministically when the device reconnects.",
32+
},
33+
];
34+
35+
function build(host) {
36+
var openFirst = host.getAttribute("open-first") !== "false";
37+
var html = '<div class="ndb-faq-list">';
38+
ITEMS.forEach(function (it, i) {
39+
var open = i === 0 && openFirst;
40+
html +=
41+
'<div class="ndb-faq-item' + (open ? " is-open" : "") + '">' +
42+
'<button class="ndb-faq-q" type="button" aria-expanded="' + (open ? "true" : "false") + '">' +
43+
"<span>" + it.q + "</span>" +
44+
'<span class="ndb-faq-icon" aria-hidden="true">+</span>' +
45+
"</button>" +
46+
'<div class="ndb-faq-panel"><div class="ndb-faq-a">' + it.a + "</div></div>" +
47+
"</div>";
48+
});
49+
html += "</div>";
50+
host.innerHTML = html;
51+
52+
host.querySelectorAll(".ndb-faq-q").forEach(function (btn) {
53+
btn.addEventListener("click", function () {
54+
var item = btn.parentElement;
55+
var nowOpen = item.classList.toggle("is-open");
56+
btn.setAttribute("aria-expanded", nowOpen ? "true" : "false");
57+
});
58+
});
59+
}
60+
61+
function init() {
62+
document.querySelectorAll("faq, Faq").forEach(build);
63+
}
64+
65+
if (document.readyState === "loading") {
66+
document.addEventListener("DOMContentLoaded", init);
67+
} else {
68+
init();
69+
}
70+
})();

assets/js/landing-hero.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Landing-page hero — replaces the built-in <Hero> so we control the
2+
// Product Hunt badge, the gradient on "1 universal engine.", and the icons
3+
// on the action buttons (none of which the built-in component supports).
4+
// Rendered by <LandingHero />. RDX emits a bare lowercased <landinghero>,
5+
// so we upgrade by query selector rather than customElements.define.
6+
7+
(function () {
8+
var GITHUB =
9+
'<svg viewBox="0 0 496 512" width="18" height="18" fill="currentColor" aria-hidden="true">' +
10+
'<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>';
11+
var DISCORD =
12+
'<svg viewBox="0 0 640 512" width="20" height="20" fill="currentColor" aria-hidden="true">' +
13+
'<path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.3 337.6 417.9 337.6z"/></svg>';
14+
15+
function attr(host, name, fallback) {
16+
var v = host.getAttribute(name);
17+
return v && v.length ? v : fallback;
18+
}
19+
20+
function build(host) {
21+
var ph = attr(host, "producthunt", "https://www.producthunt.com/products/nodedb");
22+
var phKicker = attr(host, "ph-kicker", "Featured on");
23+
var github = attr(host, "github", "https://github.com/NodeDB-Lab/nodedb");
24+
var discord = attr(host, "discord", "https://discord.gg/s54gDMVc7B");
25+
var title = attr(host, "title", "Replace 5 databases with");
26+
var accent = attr(host, "accent", "1 universal engine.");
27+
var sub = attr(
28+
host,
29+
"sub",
30+
"Stop wrestling with fragmented data silos. NodeDB natively combines relational, vector (AI), graph, document, columnar, and scientific array data into a hyper-efficient Rust architecture. Your existing PostgreSQL client just works."
31+
);
32+
33+
host.innerHTML =
34+
'<div class="ndb-hero">' +
35+
'<a class="ndb-ph-badge" href="' + ph + '" target="_blank" rel="noopener">' +
36+
'<span class="ndb-ph-mark">P</span>' +
37+
'<span class="ndb-ph-text">' +
38+
'<span class="ndb-ph-kicker">' + phKicker + '</span>' +
39+
'<span class="ndb-ph-name">Product Hunt</span>' +
40+
"</span>" +
41+
"</a>" +
42+
'<h1 class="ndb-hero-title">' + title + '<br /><span class="ndb-grad-text">' + accent + "</span></h1>" +
43+
'<p class="ndb-hero-sub">' + sub + "</p>" +
44+
'<div class="ndb-hero-actions">' +
45+
'<a class="ndb-btn ndb-btn-primary" href="' + github + '" target="_blank" rel="noopener">' + GITHUB + "<span>Star on GitHub</span></a>" +
46+
'<a class="ndb-btn ndb-btn-soft" href="#waitlist"><span>Get Early Access</span></a>' +
47+
'<a class="ndb-btn ndb-btn-outline" href="' + discord + '" target="_blank" rel="noopener">' + DISCORD + "<span>Join Discord</span></a>" +
48+
"</div>" +
49+
"</div>";
50+
}
51+
52+
function init() {
53+
document.querySelectorAll("landinghero, LandingHero").forEach(build);
54+
}
55+
56+
if (document.readyState === "loading") {
57+
document.addEventListener("DOMContentLoaded", init);
58+
} else {
59+
init();
60+
}
61+
})();

assets/js/landing-nav.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Landing-page top navigation — replaces the oxidoc theme header (which
2+
// hides its nav links and renders a search/dark-mode toolbar that looks
3+
// out of place on the dark marketing page). Rendered by <LandingNav />.
4+
// RDX emits a bare lowercased <landingnav> element, so we upgrade by query
5+
// selector rather than customElements.define.
6+
7+
(function () {
8+
var GITHUB =
9+
'<svg viewBox="0 0 496 512" width="18" height="18" fill="currentColor" aria-hidden="true">' +
10+
'<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>';
11+
var DISCORD =
12+
'<svg viewBox="0 0 640 512" width="20" height="20" fill="currentColor" aria-hidden="true">' +
13+
'<path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.3 337.6 417.9 337.6z"/></svg>';
14+
15+
function build(host) {
16+
var logo = host.getAttribute("logo") || "/assets/logo.svg";
17+
var github = host.getAttribute("github") || "https://github.com/NodeDB-Lab/nodedb";
18+
var discord = host.getAttribute("discord") || "https://discord.gg/s54gDMVc7B";
19+
host.innerHTML =
20+
'<nav class="ndb-nav" aria-label="Primary">' +
21+
'<a class="ndb-nav-brand" href="/"><img src="' + logo + '" alt="" />' +
22+
'<span>NodeDB</span></a>' +
23+
'<div class="ndb-nav-links">' +
24+
'<a class="ndb-nav-link" href="/docs">Docs</a>' +
25+
'<a class="ndb-nav-link" href="/use-cases">Use Cases</a>' +
26+
'<a class="ndb-nav-icon" href="' + github + '" target="_blank" rel="noopener" aria-label="GitHub">' + GITHUB + '</a>' +
27+
'<a class="ndb-nav-icon" href="' + discord + '" target="_blank" rel="noopener" aria-label="Discord">' + DISCORD + '</a>' +
28+
'<a class="ndb-nav-cta" href="#waitlist">Join Waitlist</a>' +
29+
"</div>" +
30+
"</nav>";
31+
}
32+
33+
function init() {
34+
document.querySelectorAll("landingnav, LandingNav").forEach(build);
35+
}
36+
37+
if (document.readyState === "loading") {
38+
document.addEventListener("DOMContentLoaded", init);
39+
} else {
40+
init();
41+
}
42+
})();

0 commit comments

Comments
 (0)