Files
zooqueen e0266e8a63 docs: point the skills and the docs site at our own stack
The workflow skills, the CLI reference, and the guides described a vendor's
services: a separate account to sign into, a credential file beside the
project, a music library and asset search that are not ours, and preview
media on a CDN we do not run.

Auth is now one Hanzo IAM token in $HANZO_API_KEY, read from Hanzo KMS —
one credential for voice, music, sound effects, images, video, the shared
catalog, and cloud rendering. The credential guide, the cloud-render
pages, and the CLI auth reference all say the same thing, because there
is now only one thing to say.

Docs previews resolve from the docs site's own /images/ path, produced by
our own generator. They are not committed (docs/images/ is ignored), so a
deploy must run `bun run generate:catalog-previews` first — the same gap
as before, minus a CDN we cannot publish to. Element grounding calls
zen-vl through api.hanzo.ai rather than a third-party vision endpoint,
and the LUT library builds every look from params, so no look needs a
host at all.

Command examples read `npx @hanzo/frame` / `hanzo frame` throughout.
Three navigation entries left dangling by the rebrand now resolve.

The changelog and the weekly archive keep their entries as written and
say plainly that pre-port entries describe the upstream product.
2026-08-13 17:29:50 -07:00

60 lines
1.6 KiB
React

export function TemplateCard({ id, title, description, href, portrait }) {
const [hovering, setHovering] = React.useState(false);
const imgSrc = `/images/templates/${id}.png`;
const videoSrc = `/images/templates/${id}.mp4`;
return (
<a
href={href}
className="not-prose group block rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden transition-shadow hover:shadow-lg no-underline"
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
>
<div
className="relative overflow-hidden bg-gray-100 dark:bg-gray-800"
style={{ aspectRatio: portrait ? "9/16" : "16/9" }}
>
<img
src={imgSrc}
alt={`${title} example`}
className="absolute inset-0 w-full h-full object-cover"
style={{
opacity: hovering ? 0 : 1,
transition: "opacity 0.2s ease",
}}
/>
{hovering && (
<video
src={videoSrc}
autoPlay
muted
loop
playsInline
className="absolute inset-0 w-full h-full object-cover"
/>
)}
</div>
<div className="p-4">
<h3 className="text-base font-semibold text-gray-900 dark:text-white m-0">
{title}
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-1 mb-0">
{description}
</p>
</div>
</a>
);
}
export function TemplateGrid({ children }) {
return (
<div
className="not-prose grid gap-4"
style={{ gridTemplateColumns: "repeat(2, 1fr)" }}
>
{children}
</div>
);
}