view mrjunejune/src/public/component-sandbox.html @ 273:e02e2036ef84 default tip

add Layer 2 JRPG component system Add reusable content and window modals, an isolated component sandbox, shared cyberpunk scroll areas, production-safe cache freshness, and server-rendered JRPG panel state. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Sat, 08 Aug 2026 02:08:08 -0700
parents
children
line wrap: on
line source

<!doctype html>
<html lang="en" data-zen-theme="cyberpunk">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI Component Sandbox | MrJuneJune</title>
    <link rel="stylesheet" href="/public/design-system/styles/tokens.css">
    <link rel="stylesheet" href="/public/design-system/styles/themes.css">
    <link rel="stylesheet" href="/public/design-system/styles/components.css">
    <script type="module" src="/public/design-system/components/index.js"></script>
    <script type="module">
      const version = Date.now();
      const styles = [
        "/public/mjj-modal.css",
        "/public/component-sandbox.css",
      ];
      await Promise.all(styles.map(href => new Promise((resolve, reject) => {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.href = `${href}?sandbox=${version}`;
        link.addEventListener("load", resolve, { once: true });
        link.addEventListener("error", reject, { once: true });
        document.head.append(link);
      })));
      await import(`/public/mjj-modal.js?sandbox=${version}`);
      void navigator.serviceWorker?.getRegistration()
        .then(registration => registration?.update());
    </script>
  </head>
  <body>
    <main>
      <header class="sandbox-heading">
        <p class="sandbox-muted">Isolated browser fixture</p>
        <h1>AI Component Sandbox</h1>
        <p>
          Edit one component family, refresh this page, and inspect desktop or
          mobile behavior without application chrome.
        </p>
        <dl class="sandbox-layers" aria-label="Component dependency layers">
          <div>
            <dt>Layer 0 · Foundation</dt>
            <dd>API mapping, i18n, and semantic themes.</dd>
          </div>
          <div>
            <dt>Layer 1 · Primitives</dt>
            <dd>Zenbu icons, fields, buttons, and dialog behavior.</dd>
          </div>
          <div>
            <dt>Layer 2 · Composites</dt>
            <dd>MrJuneJune composers and modal families.</dd>
          </div>
        </dl>
        <p class="sandbox-rule">
          Dependency rule: Layer 2 may consume Layers 1 and 0. Application
          routes, persistence, and business state stay above this sandbox.
        </p>
      </header>

      <section class="sandbox-grid" aria-label="Modal component variants">
        <article class="sandbox-card">
          <h2>Content modal</h2>
          <p>
            Editorial reading surface for blogs, notes, release details, and
            long-form content.
          </p>
          <mjj-content-modal data-component-layer="2">
            <zen-dialog>
              <zen-button size="md">
                <button type="button" data-zen-trigger>
                  Open article
                  <zen-icon name="external"></zen-icon>
                </button>
              </zen-button>
              <dialog>
                <header data-modal-header>
                  <div data-modal-heading>
                    <p data-modal-kicker>Engineering note · 8 min read</p>
                    <h2 data-modal-title>Designing durable agent interfaces</h2>
                  </div>
                  <div data-modal-header-actions>
                    <zen-button variant="quiet" size="sm">
                      <button type="button" data-zen-close aria-label="Close article">
                        <zen-icon name="close"></zen-icon>
                      </button>
                    </zen-button>
                  </div>
                </header>
                <zen-scroll-area
                  data-modal-body
                  data-cyber-scroll
                  tabindex="0"
                  aria-label="Article content"
                >
                  <article data-modal-article>
                    <p data-modal-description>
                      A content modal should feel like a focused reading room:
                      enough structure to orient the reader, but no window chrome
                      competing with the article.
                    </p>
                    <h2>Start with a strict shell</h2>
                    <p>
                      Header, body, and footer are stable regions. The article
                      owns its semantic headings, paragraphs, lists, and code.
                      The modal only supplies rhythm, containment, scrolling,
                      and depth.
                    </p>
                    <blockquote>
                      Content should remain ordinary HTML even when the
                      presentation becomes cinematic.
                    </blockquote>
                    <h3>Keep the body readable</h3>
                    <p>
                      The reading column stays bounded while the dialog itself
                      can grow. This avoids very long lines on desktop and keeps
                      padding deliberate on small screens.
                    </p>
                    <h3>Use a visible scroll channel</h3>
                    <p>
                      Cyan marks the active rail, violet separates the track,
                      and magenta appears on hover. Keyboard users can focus the
                      region and scroll without moving the modal chrome.
                    </p>
                    <p>
                      The header and footer stay fixed while this article moves.
                      That stable frame keeps context visible during longer blog
                      posts, documentation, and generated explanations.
                    </p>
                    <p>
                      Layer 2 only chooses layout and presentation. The Layer 1
                      scroll primitive still owns the native overflow behavior.
                    </p>
                    <pre><code>&lt;mjj-content-modal&gt;
  &lt;header data-modal-header&gt;...&lt;/header&gt;
  &lt;zen-scroll-area data-modal-body data-cyber-scroll&gt;
    ...
  &lt;/zen-scroll-area&gt;
  &lt;footer data-modal-footer&gt;...&lt;/footer&gt;
&lt;/mjj-content-modal&gt;</code></pre>
                  </article>
                </zen-scroll-area>
                <footer data-modal-footer>
                  <p>Updated August 7, 2026</p>
                  <div data-modal-footer-actions>
                    <zen-button variant="quiet" size="md">
                      <button type="button" data-zen-close>Done reading</button>
                    </zen-button>
                  </div>
                </footer>
              </dialog>
            </zen-dialog>
          </mjj-content-modal>
        </article>

        <article class="sandbox-card">
          <h2>Window modal</h2>
          <p>
            Structured workspace for tools and multi-region interfaces with
            fixed chrome and a bounded scrolling body.
          </p>
          <mjj-window-modal data-component-layer="2">
            <zen-dialog>
              <zen-button size="md">
                <button type="button" data-zen-trigger>
                  Open workspace
                  <zen-icon name="external"></zen-icon>
                </button>
              </zen-button>
              <dialog>
                <header data-modal-header>
                  <div data-modal-heading>
                    <p data-modal-kicker>Workspace · Read only</p>
                    <h2 data-modal-title>Component inspector</h2>
                  </div>
                  <div data-modal-header-actions>
                    <zen-button variant="quiet" size="sm">
                      <button type="button" aria-label="Component settings">
                        <zen-icon name="settings"></zen-icon>
                      </button>
                    </zen-button>
                    <zen-button variant="quiet" size="sm">
                      <button type="button" data-zen-close aria-label="Close workspace">
                        <zen-icon name="close"></zen-icon>
                      </button>
                    </zen-button>
                  </div>
                </header>
                <zen-scroll-area
                  data-modal-body
                  data-modal-layout="split"
                  data-cyber-scroll
                  tabindex="0"
                  aria-label="Workspace content"
                >
                  <zen-scroll-area
                    data-modal-pane
                    data-cyber-scroll
                    tabindex="0"
                    aria-label="Inspector regions"
                  >
                    <aside class="sandbox-pane">
                      <h3>Regions</h3>
                      <ul class="sandbox-list">
                        <li>Header</li>
                        <li>Body</li>
                        <li>Footer</li>
                      </ul>
                    </aside>
                  </zen-scroll-area>
                  <zen-scroll-area
                    data-modal-pane="primary"
                    data-cyber-scroll
                    tabindex="0"
                    aria-label="Inspector body content"
                  >
                    <article class="sandbox-pane">
                      <h3>Body content</h3>
                      <p data-modal-description>
                        The window body can host split panes, editors, previews,
                        or tools without changing the surrounding contract.
                      </p>
                      <zen-field size="md">
                        <label for="sandbox-component-name">Component name</label>
                        <input
                          id="sandbox-component-name"
                          value="mjj-window-modal"
                          readonly
                        >
                        <small>The active light-DOM fixture.</small>
                      </zen-field>
                      <ol class="sandbox-audit">
                        <li><strong>01</strong> Header region validated</li>
                        <li><strong>02</strong> Title association generated</li>
                        <li><strong>03</strong> Body region bounded</li>
                        <li><strong>04</strong> Scroll primitive connected</li>
                        <li><strong>05</strong> Footer actions discovered</li>
                        <li><strong>06</strong> Pixel typography inherited</li>
                        <li><strong>07</strong> Cyberpunk theme resolved</li>
                        <li><strong>08</strong> Keyboard scrolling enabled</li>
                        <li><strong>09</strong> Responsive split verified</li>
                        <li><strong>10</strong> Layer contract ready</li>
                      </ol>
                    </article>
                  </zen-scroll-area>
                </zen-scroll-area>
                <footer data-modal-footer>
                  <p>3 required regions · contract valid</p>
                  <div data-modal-footer-actions>
                    <zen-button variant="quiet" size="md">
                      <button type="button" data-zen-close>Cancel</button>
                    </zen-button>
                    <zen-button size="md">
                      <button type="button" data-zen-close>Apply</button>
                    </zen-button>
                  </div>
                </footer>
              </dialog>
            </zen-dialog>
          </mjj-window-modal>
        </article>
      </section>
    </main>
  </body>
</html>