Mercurial
view design_system/src/catalog.js @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -0700 |
| parents | 60a876c4587a |
| children |
line wrap: on
line source
import "./components/index.js"; import { componentCatalog } from "./component_catalog.js"; import { ICON_NAMES } from "./components/icon.js"; const stackComponent = { name: "Stack", slug: "stack", element: "zen-stack", group: "Layout", description: "A Zenbu-specific flex layout primitive with tokenized gaps.", existing: true, }; const displayedComponents = [...componentCatalog, stackComponent]; const pages = new Map([ ["/", "overview"], ["/components", "overview"], ["/tokens", "tokens"], ["/icons", "icons"], ["/components/button", "button"], ["/components/card", "card"], ["/components/alert", "alert"], ["/components/field", "field"], ["/components/notifications", "notifications"], ["/components/stack", "stack"], ]); for (const component of componentCatalog) { pages.set(`/components/${component.slug}`, component.slug); } function createCatalogLink(component) { const link = document.createElement("a"); link.href = `/components/${component.slug}`; link.dataset.catalogLink = ""; link.dataset.zenElement = component.element; link.textContent = component.name; return link; } function createComponentCard(component) { const link = createCatalogLink(component); const card = document.createElement("zen-card"); card.setAttribute("interactive", ""); const article = document.createElement("article"); const heading = document.createElement("h3"); heading.textContent = component.name; const description = document.createElement("p"); description.textContent = component.description; const element = document.createElement("code"); element.textContent = component.element; article.append(heading, description, element); card.append(article); link.replaceChildren(card); return link; } function createCatalogPage(component) { const section = document.createElement("section"); section.className = "catalog-page"; section.dataset.catalogPage = component.slug; section.hidden = true; const header = document.createElement("header"); header.className = "page-heading"; const eyebrow = document.createElement("p"); eyebrow.className = "eyebrow"; eyebrow.textContent = component.group; const heading = document.createElement("h1"); heading.textContent = component.name; const description = document.createElement("p"); description.textContent = component.description; header.append(eyebrow, heading, description); const story = document.createElement("zen-story"); story.setAttribute("name", `${component.name} example`); const template = document.createElement("template"); template.innerHTML = component.markup; story.append(template); section.append(header, story); return section; } function installComponentCatalog() { const navigation = document.querySelector( '.catalog-nav[aria-label="Components"]', ); const componentGrid = document.querySelector(".component-grid"); const main = document.querySelector("#catalogMain"); if (!navigation || !componentGrid || !main) return; navigation.replaceChildren( ...displayedComponents.map(createCatalogLink), ); componentGrid.replaceChildren( ...displayedComponents.map(createComponentCard), ); for (const component of componentCatalog) { if (component.existing) continue; main.append(createCatalogPage(component)); } } function installIconCatalog() { const grid = document.querySelector("#iconGrid"); if (!grid) return; const items = ICON_NAMES.map(name => { const figure = document.createElement("figure"); const icon = document.createElement("zen-icon"); icon.setAttribute("name", name); icon.setAttribute("size", "2rem"); const caption = document.createElement("figcaption"); const code = document.createElement("code"); code.textContent = name; caption.append(code); figure.append(icon, caption); return figure; }); grid.replaceChildren(...items); } function installComponentSearch() { const input = document.querySelector("#componentSearch"); const status = document.querySelector("#componentSearchStatus"); if (!input || !status) return; const links = [ ...document.querySelectorAll( '.catalog-nav[aria-label="Components"] a', ), ]; const cards = [...document.querySelectorAll(".component-grid > a")]; const descriptions = new Map( displayedComponents.map(component => [ component.slug, [ component.name, component.element, component.group, component.description, ].join(" ").toLocaleLowerCase(), ]), ); const filter = () => { const query = input.value.trim().toLocaleLowerCase(); let matches = 0; for (const link of links) { const slug = new URL(link.href).pathname.split("/").pop(); const visible = !query || descriptions.get(slug)?.includes(query); link.hidden = !visible; if (visible) matches++; } for (const card of cards) { const slug = new URL(card.href).pathname.split("/").pop(); card.hidden = Boolean(query) && !descriptions.get(slug)?.includes(query); } status.textContent = query ? `${matches} component${matches === 1 ? "" : "s"} found` : `${links.length} components`; }; input.addEventListener("input", filter); input.addEventListener("keydown", event => { if (event.key !== "Escape" || !input.value) return; input.value = ""; filter(); }); document.addEventListener("keydown", event => { const target = event.target; const typing = target instanceof HTMLElement && target.matches("input, textarea, select, [contenteditable]"); if (event.key !== "/" || typing || event.metaKey || event.ctrlKey || event.altKey) return; event.preventDefault(); input.focus(); input.select(); }); filter(); } function showPage(pathname) { const pageName = pages.get(pathname) || "overview"; for (const page of document.querySelectorAll("[data-catalog-page]")) { page.hidden = page.dataset.catalogPage !== pageName; } for (const link of document.querySelectorAll( ".catalog-sidebar [data-catalog-link]", )) { const active = new URL(link.href).pathname === pathname; if (active) link.setAttribute("aria-current", "page"); else link.removeAttribute("aria-current"); } const heading = document.querySelector( `[data-catalog-page="${pageName}"] h1`, ); if (heading) document.title = `${heading.textContent} ยท Zenbu UI`; } window.addEventListener("DOMContentLoaded", () => { installComponentCatalog(); installIconCatalog(); installComponentSearch(); const root = document.documentElement; const systemTheme = matchMedia("(prefers-color-scheme: dark)"); const storedTheme = localStorage.getItem("zen-theme"); if (storedTheme) root.dataset.zenTheme = storedTheme; const themeToggle = document.querySelector("#themeToggle"); const isDark = () => { if (root.dataset.zenTheme) { return root.dataset.zenTheme === "dark"; } return systemTheme.matches; }; const updateThemeButton = () => { const dark = isDark(); themeToggle?.setAttribute("aria-pressed", String(dark)); if (themeToggle) { themeToggle.textContent = dark ? "Use light theme" : "Use dark theme"; } }; updateThemeButton(); themeToggle?.addEventListener("click", () => { const next = isDark() ? "light" : "dark"; root.dataset.zenTheme = next; localStorage.setItem("zen-theme", next); updateThemeButton(); }); systemTheme.addEventListener("change", () => { if (!root.dataset.zenTheme) updateThemeButton(); }); document.addEventListener("click", event => { const notificationDemo = event.target.closest( "[data-notification-demo]", ); if (notificationDemo) { const scope = notificationDemo.closest("zen-notifications"); if (!scope) return; const tone = notificationDemo.dataset.tone || "info"; const baseId = notificationDemo.dataset.notificationId || tone; const count = notificationDemo.dataset.burst === "true" ? 5 : 1; for (let index = 0; index < count; index++) { notificationDemo.dispatchEvent(new CustomEvent("zen-notify", { bubbles: true, composed: false, detail: { version: 1, id: count > 1 ? `${baseId}-${Date.now()}-${index}` : baseId, tone, message: notificationDemo.dataset.message || "Notification", description: notificationDemo.dataset.description, announcement: tone === "error" ? "assertive" : "polite", durationMs: 5000, persistent: notificationDemo.dataset.persistent === "true", action: notificationDemo.dataset.action === "true" ? { token: `catalog-action-${Date.now()}`, label: "Retry" } : undefined, }, })); } return; } const dismissDemo = event.target.closest( "[data-notification-dismiss-demo]", ); if (dismissDemo) { dismissDemo.dispatchEvent(new CustomEvent( "zen-dismiss-notification", { bubbles: true, composed: false, detail: { version: 1, id: dismissDemo.dataset.notificationDismissDemo, }, }, )); return; } const link = event.target.closest("a[data-catalog-link]"); if (!link || link.origin !== location.origin || event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || link.hasAttribute("download") || link.target) return; event.preventDefault(); history.pushState({}, "", link.href); showPage(location.pathname); document.querySelector("#catalogMain")?.focus(); }); window.addEventListener("popstate", () => showPage(location.pathname)); showPage(location.pathname); });