Files
zeekay 6bc8094492 feat(oss): redesign oss.hanzo.ai into an educational, discoverable OSS explorer + one-click launcher
Replaces the old lorem-ipsum e-commerce demo with a best-in-class human gallery over the
REAL 1,030-app catalog (meta.json), sharing templates.hanzo.ai's machine-readable contract
(meta.json + blueprints/ UNTOUCHED — only the human UI changed).

- Educational: hero + live app count + a 'How it works' Pick→Deploy→Manage strip + a
  'Why Hanzo' (managed / scalable / pay-as-you-go / your own org) section.
- Discoverable: fast debounced client-side search (name/desc/id/tags) + 16 data-driven
  category chips + Load-more, with #q=&tag= URL sync for shareable views + keyboard (/ , Esc).
- Quick-launcher: each card's Deploy CTA deep-links the REAL PaaS deploy flow
  platform.hanzo.ai/templates?deploy=<id> (verified against platform source + a live 200).
- Removed the public 'earn 20% compute revenue' claims; fixed a latent CSP bug (inline
  onerror → DOM-attached). 100% self-contained/CSP-safe (inline SVG icons, data-URI favicon,
  NO external CDN/font/style), theme-aware (light/dark), responsive (390 mobile → 1680 desktop,
  no horizontal scroll). Purged the old demo cruft (18 CSS + 11 JS + 30 img + fonts + stubs).

Verified headless under the exact prod CSP: cards render (0 violations/0 JS errors), search/
filter/load-more/96-of-96-logos/theme-toggle all work, 390px no-h-scroll. Catalog contract
untouched (UI only READS meta.json/blueprints).
2026-07-24 17:18:29 -07:00

37 lines
1.2 KiB
JavaScript

// Theme bootstrap — applied before first paint (loaded blocking in <head>) so
// an explicit choice never flashes. With no saved choice the CSS follows the OS
// via prefers-color-scheme. CSP-safe: same-origin external script, no inline.
'use strict';
(function () {
var KEY = 'hz-theme';
try {
var saved = localStorage.getItem(KEY);
if (saved === 'light' || saved === 'dark') {
document.documentElement.setAttribute('data-theme', saved);
}
} catch (e) { /* private mode / storage blocked — fall back to OS */ }
function effective() {
var set = document.documentElement.getAttribute('data-theme');
if (set) return set;
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark' : 'light';
}
function wire() {
var btn = document.getElementById('theme-toggle');
if (!btn) return;
btn.addEventListener('click', function () {
var next = effective() === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
try { localStorage.setItem(KEY, next); } catch (e) { /* ignore */ }
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', wire);
} else {
wire();
}
})();