mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
The hero routes one request down one of three lanes (write, decide, act), weighed on quality, latency, cost and policy; Decide is Kai, drawn dashed and marked in progress. Under it: one runtime for every layer, the paths, the balance, the presets, one request end to end, the glue it replaces, models from the catalog's labs, agents, decisions, the measurement with the paper caveat, frontier standing computed from the board (on and off), infrastructure, the call, enterprise. Viewport rises and a magnetic start control, both still under reduced motion and touch. Gate: e2e/gates/enso.spec.ts. Co-authored-by: Hanzo Dev <[email protected]>
46 lines
1.6 KiB
TypeScript
46 lines
1.6 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* Rise — a block rises into place the first time it scrolls into view.
|
|
*
|
|
* It borrows the house entrance whole: `data-motion="rise"` is
|
|
* @hanzo/ui/styles/motion.css's keyframe, `data-beat` its stagger, and the
|
|
* sheet stills both under `prefers-reduced-motion`. What this adds is WHEN.
|
|
*
|
|
* Nothing ships hidden. The block is rendered opaque and in place; the rise is
|
|
* attached only as it crosses into the viewport, so a page whose script never
|
|
* runs, a crawler, a print and a reader who declines motion all read the same
|
|
* page. A block already on screen at load is left alone — the first screen is
|
|
* not a reveal.
|
|
*/
|
|
|
|
import { useEffect, useRef, type ComponentProps, type ReactNode } from 'react'
|
|
import { YStack } from '@hanzo/ui'
|
|
|
|
export function Rise({ beat = 0, children, ...props }: { beat?: number; children: ReactNode } & ComponentProps<typeof YStack>) {
|
|
const ref = useRef<HTMLElement | null>(null)
|
|
|
|
useEffect(() => {
|
|
const el = ref.current
|
|
if (!el || typeof IntersectionObserver === 'undefined') return
|
|
if (el.getBoundingClientRect().top < window.innerHeight) return
|
|
const io = new IntersectionObserver(
|
|
(entries) => {
|
|
if (!entries.some((e) => e.isIntersecting)) return
|
|
el.setAttribute('data-motion', 'rise')
|
|
if (beat > 0) el.setAttribute('data-beat', String(Math.min(beat, 7)))
|
|
io.disconnect()
|
|
},
|
|
{ rootMargin: '0px 0px -6% 0px' },
|
|
)
|
|
io.observe(el)
|
|
return () => io.disconnect()
|
|
}, [beat])
|
|
|
|
return (
|
|
<YStack ref={ref as never} {...props}>
|
|
{children}
|
|
</YStack>
|
|
)
|
|
}
|