diff --git a/docs/site/docusaurus.config.js b/docs/site/docusaurus.config.js
index d4524451db..d4e4a9d1cd 100644
--- a/docs/site/docusaurus.config.js
+++ b/docs/site/docusaurus.config.js
@@ -93,6 +93,7 @@ const config = {
clientModules: [
"./src/client/webmcp.js",
+ "./src/client/kapa-sidebar.js",
],
onBrokenLinks: "throw",
@@ -297,6 +298,9 @@ const config = {
"data-project-name": "Walrus Knowledge",
"data-project-color": "#37c3b0ff",
"data-button-hide": "true",
+ "data-view-mode": "sidebar",
+ "data-modal-overlay-hidden": "true",
+ "data-modal-lock-scroll": "false",
"data-modal-title": "Ask Walrus AI",
"data-modal-ask-ai-input-placeholder": "Ask me anything about Walrus!",
"data-modal-example-questions":
diff --git a/docs/site/src/client/kapa-sidebar.js b/docs/site/src/client/kapa-sidebar.js
new file mode 100644
index 0000000000..636d3928b1
--- /dev/null
+++ b/docs/site/src/client/kapa-sidebar.js
@@ -0,0 +1,85 @@
+// Copyright (c) Walrus Foundation
+// SPDX-License-Identifier: Apache-2.0
+
+// Detects Kapa sidebar open/close and toggles .kapa-sidebar-open on .
+// Kapa renders in Shadow DOM so we can't query its internals.
+// Strategy: hook Kapa.open for instant open detection, then use
+// elementFromPoint to detect close (checks if right edge of screen
+// is covered by a non-docusaurus element).
+
+if (typeof window !== "undefined") {
+ const OPEN_CLASS = "kapa-sidebar-open";
+ let kapaOpen = false;
+ let hookedRef = null;
+
+ function syncClass() {
+ document.documentElement.classList.toggle(OPEN_CLASS, kapaOpen);
+ }
+
+ function hookKapa() {
+ if (!window.Kapa || !window.Kapa.open || window.Kapa.open === hookedRef)
+ return;
+
+ const origOpen = window.Kapa.open;
+ const origClose = window.Kapa.close;
+
+ window.Kapa.open = function (...args) {
+ kapaOpen = true;
+ syncClass();
+ return origOpen.apply(this, args);
+ };
+
+ window.Kapa.close = function (...args) {
+ kapaOpen = false;
+ syncClass();
+ return origClose.apply(this, args);
+ };
+
+ hookedRef = window.Kapa.open;
+ }
+
+ // Check if Kapa sidebar is covering the right side of the viewport.
+ // Since Kapa uses Shadow DOM, we can't query its elements directly.
+ // Instead, check if the element at the right edge of the screen
+ // belongs to the doc app or to something else (Kapa's panel).
+ function isSidebarVisible() {
+ const x = window.innerWidth - 50;
+ const y = window.innerHeight / 2;
+ const el = document.elementFromPoint(x, y);
+ if (!el) return false;
+ const docRoot = document.getElementById("__docusaurus");
+ if (docRoot && docRoot.contains(el)) return false;
+ if (el === document.body || el === document.documentElement) return false;
+ return true;
+ }
+
+ // Hook into History API so the class persists across SPA navigation.
+ // Docusaurus uses pushState for client-side routing.
+ const origPush = history.pushState.bind(history);
+ const origReplace = history.replaceState.bind(history);
+ history.pushState = function (...args) {
+ const r = origPush(...args);
+ syncClass();
+ return r;
+ };
+ history.replaceState = function (...args) {
+ const r = origReplace(...args);
+ syncClass();
+ return r;
+ };
+ window.addEventListener("popstate", syncClass);
+
+ // Poll every 300ms: re-hook Kapa if it reinitializes, and
+ // detect open/close state via elementFromPoint fallback.
+ setInterval(() => {
+ hookKapa();
+
+ const visible = isSidebarVisible();
+ if (visible && !kapaOpen) {
+ kapaOpen = true;
+ } else if (!visible && kapaOpen) {
+ kapaOpen = false;
+ }
+ syncClass();
+ }, 300);
+}
diff --git a/docs/site/src/components/LandingPage.tsx b/docs/site/src/components/LandingPage.tsx
index f620b62f37..b6b997a3f0 100644
--- a/docs/site/src/components/LandingPage.tsx
+++ b/docs/site/src/components/LandingPage.tsx
@@ -1,9 +1,11 @@
// Copyright (c) Walrus Foundation
// SPDX-License-Identifier: Apache-2.0
-import React, { useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
+import { createPortal } from 'react-dom';
import Head from '@docusaurus/Head';
import WalrusLogo from '@site/static/img/Walrus_Docs.svg';
+import SearchModal from '@site/src/components/Search/SearchModal';
function hideEl(el: HTMLElement): () => void {
const prev = el.style.display;
@@ -129,225 +131,143 @@ html, body { background: #0d0f12 !important; }
/* ── Hero ── */
.landing-root .hero {
- position: relative; padding: 72px 0 56px; overflow: hidden;
+ position: relative; padding: 48px 0 24px; overflow: hidden;
background: var(--black);
}
.landing-root .hero-inner {
- position: relative; z-index: 5; max-width: 1500px;
- margin-bottom: 28px; padding-top: 20px;
-}
-.landing-root .hero-badge {
- display: inline-block;
- font-family: var(--mono); font-size: 0.72rem; font-weight: 500;
- letter-spacing: 0.08em; text-transform: uppercase;
- color: var(--purple); margin-bottom: 16px;
+ position: relative; z-index: 5;
+ margin-bottom: 0; padding-top: 0;
+ text-align: center;
opacity: 0; animation: landingFadeIn 0.5s ease forwards 0.1s;
}
-.landing-root .hero h1 {
- font-size: clamp(2rem, 5vw, 3rem);
- font-weight: 500; line-height: 1.08; letter-spacing: -0.025em;
- margin-bottom: 14px; color: var(--white);
- opacity: 0; animation: landingFadeIn 0.6s ease forwards 0.2s;
+.landing-root .hero-title {
+ font-size: clamp(1.75rem, 4vw, 2.5rem);
+ font-weight: 600; line-height: 1.15; letter-spacing: -0.03em;
+ margin: 0 0 12px; color: var(--white);
}
-.landing-root .hero p {
- font-size: 1rem; color: var(--white); line-height: 1.6;
- max-width: 1500px;
- opacity: 0; animation: landingFadeIn 0.6s ease forwards 0.35s;
+.landing-root .hero-sub {
+ font-size: 1rem; color: var(--white); opacity: 0.55;
+ line-height: 1.55; max-width: 560px; margin: 0 auto;
}
-/* ── Quick-start cards ── */
-.landing-root .quickstart {
- display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
- padding-bottom: 15px;
- opacity: 0; animation: landingFadeIn 0.6s ease forwards 0.5s;
+/* ── Product card grid (Mem0-inspired) ── */
+.landing-root .product-grid {
+ display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px;
+ padding: 32px 0 0;
+ opacity: 0; animation: landingFadeIn 0.6s ease forwards 0.3s;
}
-@media (max-width: 900px) {
- .landing-root .quickstart { grid-template-columns: repeat(2, 1fr); }
+@media (max-width: 640px) {
+ .landing-root .product-grid { grid-template-columns: 1fr; }
}
-@media (max-width: 520px) {
- .landing-root .quickstart { grid-template-columns: 1fr; }
-}
-.landing-root .qs-card {
+
+.landing-root .product-card {
background: var(--surface); border: 1px solid var(--border);
- border-radius: var(--radius); padding: 22px 18px;
- transition: all 0.25s ease; cursor: pointer;
- display: flex; flex-direction: column; gap: 8px;
-}
-.landing-root .qs-card:hover {
- border-color: var(--purple); background: var(--surface-hover);
+ border-radius: 14px; padding: 0;
+ transition: all 0.2s ease; cursor: pointer;
+ display: flex; flex-direction: column;
+ text-decoration: none !important;
+ overflow: hidden;
+}
+.landing-root .product-card:hover {
+ border-color: rgba(255,255,255,0.18);
transform: translateY(-2px);
- box-shadow: 0 8px 32px rgba(0,0,0,0.3);
-}
-.landing-root .qs-card .qs-icon {
- width: 34px; height: 34px; border-radius: 9px;
- background: var(--purple-dim);
- display: flex; align-items: center; justify-content: center;
-}
-.landing-root .qs-card .qs-icon svg {
- width: 17px; height: 17px; color: var(--purple);
-}
-.landing-root .qs-card h3 {
- font-size: 0.9rem; font-weight: 600;
- line-height: 1.3; margin: 0; color: var(--white);
-}
-.landing-root .qs-card p {
- font-size: 0.8rem; color: var(--white);
- line-height: 1.45; flex: 1; margin: 0;
-}
-.landing-root .qs-card .qs-arrow {
- font-size: 0.75rem; color: var(--purple); font-weight: 500;
- display: flex; align-items: center; gap: 4px; margin-top: 2px;
-}
-.landing-root .qs-card .qs-arrow svg { width: 10px; height: 10px; }
-
-/* ── Divider ── */
-.landing-root .divider {
- border: none; border-top: 1px solid var(--border); margin: 0;
-}
-
-/* ── Section heading ── */
-.landing-root .section-head {
- padding: 20px 0 10px;
- display: flex; align-items: baseline; gap: 12px;
-}
-.landing-root .section-head .mono-label {
- font-family: var(--mono); font-size: 1.5rem; font-weight: 500;
- letter-spacing: 0.1em; text-transform: uppercase;
- color: var(--purple); flex-shrink: 0;
-}
-.landing-root .section-head h2 {
- font-size: 1.4rem; font-weight: 500;
- letter-spacing: -0.015em; margin: 0; color: var(--white);
+ box-shadow: 0 8px 24px rgba(0,0,0,0.25);
}
-/* ── Capabilities ── */
-.landing-root .cap-grid {
- display: grid; grid-template-columns: 1fr 1fr;
- gap: 10px; padding-bottom: 15px;
-}
-@media (max-width: 700px) {
- .landing-root .cap-grid { grid-template-columns: 1fr; }
-}
-.landing-root .cap-card {
- background: var(--surface); border: 1px solid var(--border);
- border-radius: var(--radius); padding: 24px 22px;
- transition: border-color 0.2s, background 0.2s;
-}
-.landing-root .cap-card:hover {
- border-color: var(--border-hover);
- background: var(--surface-hover);
-}
-.landing-root .cap-card h3 {
- font-size: 0.9rem; font-weight: 600;
- margin: 0 0 6px 0; color: var(--white);
- display: flex; align-items: center; gap: 8px;
+.landing-root .product-card-thumb {
+ height: 120px;
+ background: linear-gradient(135deg, rgba(202,177,255,0.06) 0%, rgba(152,239,221,0.04) 100%);
+ display: flex; align-items: center; justify-content: center;
+ border-bottom: 1px solid var(--border);
}
-.landing-root .cap-card h3 .tag {
- font-family: var(--mono); font-size: 0.62rem; font-weight: 500;
- color: var(--purple); background: var(--purple-dim);
- padding: 2px 7px; border-radius: 4px; letter-spacing: 0.03em;
+.landing-root .product-card-thumb svg {
+ width: 48px; height: 48px; color: var(--purple); opacity: 0.5;
}
-.landing-root .cap-card p {
- font-size: 0.85rem; color: var(--white);
- line-height: 1.55; margin: 0;
+.landing-root .product-card-thumb--muted {
+ background: linear-gradient(135deg, rgba(255,255,255,0.02) 0%, rgba(255,255,255,0.01) 100%);
}
-.landing-root .cap-card .cap-detail {
- margin-top: 10px; padding-top: 10px;
- border-top: 1px solid var(--border);
- font-family: var(--mono); font-size: 0.72rem;
- color: var(--white); line-height: 1.6; opacity: 0.5;
+.landing-root .product-card-thumb--muted svg {
+ color: var(--gray-muted); opacity: 0.3;
}
-/* ── Use-case rows ── */
-.landing-root .usecase-grid {
- display: grid; grid-template-columns: repeat(4, 1fr);
- gap: 10px; padding-bottom: 15px;
-}
-@media (max-width: 900px) {
- .landing-root .usecase-grid { grid-template-columns: repeat(2, 1fr); }
-}
-@media (max-width: 520px) {
- .landing-root .usecase-grid { grid-template-columns: 1fr; }
-}
-.landing-root .uc-card {
+.landing-root .product-card h3 {
+ font-size: 0.95rem; font-weight: 700;
+ line-height: 1.3; margin: 0;
+ color: var(--white);
+ padding: 16px 18px 0;
+}
+.landing-root .product-card p {
+ font-size: 0.82rem; color: var(--white); opacity: 0.5;
+ line-height: 1.5; margin: 0;
+ padding: 6px 18px 0;
+ flex: 1;
+}
+.landing-root .product-card .under-hood {
+ font-style: italic; opacity: 0.6;
+}
+.landing-root .coming-soon-badge {
+ font-size: 0.6rem; font-weight: 500; letter-spacing: 0.03em;
+ text-transform: uppercase; opacity: 0.5;
+ background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.1);
+ border-radius: 4px; padding: 2px 6px; margin-left: 8px;
+ vertical-align: middle;
+}
+.landing-root .product-card .product-arrow {
+ display: flex; align-items: center; justify-content: flex-end;
+ padding: 12px 18px;
+ color: var(--purple); opacity: 0.4;
+ transition: opacity 0.2s ease;
+}
+.landing-root .product-card:hover .product-arrow { opacity: 1; }
+.landing-root .product-card .product-arrow svg { width: 12px; height: 12px; }
+.landing-root .product-card--muted { opacity: 0.7; }
+.landing-root .product-card--muted:hover { opacity: 1; }
+
+/* ── Landing search bar ── */
+.landing-root .landing-search {
+ max-width: 560px; margin: 0 auto;
+ padding: 20px 0 0;
+ opacity: 0; animation: landingFadeIn 0.5s ease forwards 0.2s;
+}
+.landing-root .landing-search-btn {
+ width: 100%; display: flex; align-items: center; gap: 14px;
background: var(--surface); border: 1px solid var(--border);
- border-radius: var(--radius); padding: 22px 18px;
- transition: border-color 0.2s;
-}
-.landing-root .uc-card:hover {
- border-color: var(--border-hover);
-}
-.landing-root .uc-card h4 {
- font-size: 0.85rem; font-weight: 600;
- margin: 0 0 8px 0; color: var(--white);
-}
-.landing-root .uc-card ul {
- list-style: none; padding: 0; margin: 0;
-}
-.landing-root .uc-card li {
- font-size: 0.78rem; color: var(--white); line-height: 1.5;
- padding: 2px 0 2px 14px; position: relative; opacity: 0.7;
+ border-radius: var(--radius); padding: 18px 24px;
+ cursor: pointer; transition: all 0.2s ease;
+ font-family: var(--sans);
}
-.landing-root .uc-card li::before {
- content: ''; position: absolute; left: 0; top: 9px;
- width: 4px; height: 4px; border-radius: 50%;
- background: var(--purple); opacity: 0.6;
+.landing-root .landing-search-btn:hover {
+ border-color: rgba(255,255,255,0.16); background: var(--surface-hover);
+ box-shadow: 0 6px 24px rgba(0,0,0,0.25);
}
-
-.landing-root .hero-lead {
- font-size: 1.1rem;
- line-height: 1.5;
- margin-bottom: 1px;
- color: var(--white);
+.landing-root .landing-search-btn svg {
+ width: 20px; height: 20px; color: var(--purple); flex-shrink: 0;
}
-
-.landing-root .hero-body {
- font-size: 0.9rem;
- line-height: 1.6;
- margin-bottom: 1px;
- color: var(--white);
- opacity: 0.6;
+.landing-root .landing-search-btn span {
+ font-size: 1rem; color: rgba(255,255,255,0.35); font-weight: 400;
}
-
-.landing-root .hero-features {
- list-style: none;
- padding: 0;
- margin: 0;
- display: flex;
- gap: 24px;
- flex-wrap: wrap;
+.landing-root .landing-search-btn kbd {
+ margin-left: auto; font-family: var(--sans);
+ font-size: 0.72rem; color: rgba(255,255,255,0.25);
+ background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.08);
+ border-radius: 6px; padding: 3px 9px; font-weight: 500;
}
-.landing-root .hero-features li {
- font-size: 0.85rem;
- font-weight: 500;
- color: var(--white);
- display: flex;
- align-items: center;
- gap: 8px;
+/* ── Search modal z-index fix ── */
+.landing-root .fixed.inset-0,
+.landing-root [class*="z-500"] {
+ z-index: 9999 !important;
}
-.landing-root .hero-features li::before {
- content: '';
- width: 6px;
- height: 6px;
- border-radius: 50%;
- background: var(--purple);
- flex-shrink: 0;
+/* ── Divider ── */
+.landing-root .divider {
+ border: none; border-top: 1px solid var(--border); margin: 0;
}
-/* ── Not-for ── */
-.landing-root .notfor { padding-bottom: 64px; }
-.landing-root .notfor-row { display: flex; gap: 8px; flex-wrap: wrap; }
-.landing-root .notfor-chip {
- font-size: 0.8rem; color: var(--white); opacity: 0.7;
- background: var(--surface); border: 1px solid var(--border);
- border-radius: 10px; padding: 9px 16px;
-}
/* ── Footer ── */
.landing-root .page-footer {
- border-top: 1px solid var(--border); padding: 36px 0;
+ border-top: 1px solid var(--border); margin-top: 80px; padding: 36px 0;
display: flex; align-items: center;
justify-content: space-between;
flex-wrap: wrap; gap: 16px;
@@ -378,6 +298,8 @@ html, body { background: #0d0f12 !important; }
`;
export default function LandingPage() {
+ const [searchOpen, setSearchOpen] = useState(false);
+
useEffect(() => {
const cleanups: Array<() => void> = [];
@@ -421,9 +343,21 @@ export default function LandingPage() {
.querySelectorAll('.landing-root .scroll-reveal')
.forEach((el) => obs.observe(el));
+ // "/" key opens the search bar
+ function handleKey(e: KeyboardEvent) {
+ if (e.key === '/' && !e.metaKey && !e.ctrlKey
+ && !(e.target instanceof HTMLInputElement)
+ && !(e.target instanceof HTMLTextAreaElement)) {
+ e.preventDefault();
+ setSearchOpen(true);
+ }
+ }
+ document.addEventListener('keydown', handleKey);
+
return () => {
cleanups.forEach((fn) => fn());
obs.disconnect();
+ document.removeEventListener('keydown', handleKey);
};
}, []);
@@ -454,346 +388,84 @@ export default function LandingPage() {
-
- A verifiable data platform for high-stakes systems that - require provable, programmable, always-available data - with no performance tradeoffs. -
-- Modern financial systems and AI agents depend on fast, - reliable, and verifiable data. Traditional storage assumes - integrity and pushes trust outside the data layer. Walrus - embeds availability, integrity, and programmability - directly into storage itself. +
+ Keep critical data persistent, portable, and under your control + across apps, providers, and agents.
-