view design_system/src/storybook.js @ 252:7a7581f040e8

[ui] Add scoped notification component Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Tue, 04 Aug 2026 11:57:16 -0700
parents 117c4d53c9a4
children 2b6e732087ff
line wrap: on
line source

import "./components/index.js";

const pages = new Map([
  ["/", "overview"],
  ["/components", "overview"],
  ["/tokens", "tokens"],
  ["/components/button", "button"],
  ["/components/card", "card"],
  ["/components/alert", "alert"],
  ["/components/field", "field"],
  ["/components/notifications", "notifications"],
  ["/components/stack", "stack"],
]);

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", () => {
  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);
});