mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-30 18:12:27 +00:00
The kit shipped ten typefaces. One is ours. Deleted: font-inter, font-silkscreen, font-cherry-bomb, font-nohemi, font-dm-sans, font-dm-serif-display, font-fira-mono, font-glusp, font-munro. Six of those had no dependent in the workspace at all. font-zen stays, and so do font-size, get-font-sized and font, which size and register rather than name a face. Published versions remain on the registry, so anything pinned to one keeps resolving. @hanzogui/config's DEFAULT entry built heading and body from Inter — v4 was already system fonts and v5 already Zen, so an app on the default got a face nobody chose. It builds from Zen now. dev-config, which drives gui.hanzo.ai, was worse: Inter for text, Berkeley Mono for code, plus Cherry Bomb and Silkscreen. Every size, weight, letter-spacing and transform value is unchanged — only the faces moved. The pixel ROLE was worth keeping and only its face was borrowed, so font-zen gained Zen Pixel Square (createZenPixelFont, --font-zen-pixel-*) and the token is `$pixel`. `$silkscreen` and `$cherryBomb` are gone across ~35 call sites. Cherry Bomb had no role of its own and no Zen counterpart, so it is deleted rather than substituted. gui.hanzo.ai now self-hosts three Zen files in place of four foreign ones — one variable file per family instead of a weight per request — and its OG-image route renders cards in the same faces as the pages they link to. The Inter, Berkeley, Silkscreen and glusp binaries are gone from public/fonts, including an otf directory of 20 Inter cuts. Native is honestly short: @hanzo/font ships woff2 and react-native wants otf/ttf, so the expo starter and kitchen-sink's native entry load no custom face and say why, rather than keeping Inter because it happened to be there. bun install 0 · build 161/161 · typecheck passed. Co-authored-by: Hanzo Dev <[email protected]>
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { isClient } from '@hanzo/gui'
|
|
|
|
export const useFontLoaded = (fontFamily: string) => {
|
|
const [loaded, setLoaded] = useState(false)
|
|
|
|
useEffect(() => {
|
|
if (!isClient) return
|
|
|
|
// check if already loaded
|
|
if (document.fonts.check(`16px "${fontFamily}"`)) {
|
|
setLoaded(true)
|
|
return
|
|
}
|
|
|
|
// wait for font to load
|
|
document.fonts.ready.then(() => {
|
|
if (document.fonts.check(`16px "${fontFamily}"`)) {
|
|
setLoaded(true)
|
|
}
|
|
})
|
|
|
|
// also listen for load event
|
|
const onFontLoad = () => {
|
|
if (document.fonts.check(`16px "${fontFamily}"`)) {
|
|
setLoaded(true)
|
|
}
|
|
}
|
|
document.fonts.addEventListener('loadingdone', onFontLoad)
|
|
return () => {
|
|
document.fonts.removeEventListener('loadingdone', onFontLoad)
|
|
}
|
|
}, [fontFamily])
|
|
|
|
return loaded
|
|
}
|
|
|
|
export function LoadFont(props: {
|
|
cssFile?: string
|
|
woff2File?: string
|
|
prefetch?: boolean
|
|
}) {
|
|
const [show, setShow] = useState(!props.prefetch)
|
|
|
|
useEffect(() => {
|
|
if (!props.prefetch) return
|
|
// one-time warm on the first user interaction anywhere on the page (touch +
|
|
// mouse + keyboard), so the font is already loading by the time the user
|
|
// navigates to a page that uses it, without an eager preload that
|
|
// Lighthouse dings for being unused on the current page.
|
|
const events = ['pointerdown', 'touchstart', 'keydown', 'mouseover'] as const
|
|
const removeAll = () => {
|
|
for (const e of events) document.removeEventListener(e, reveal, true)
|
|
}
|
|
// function decl so removeAll (defined above) can reference it; on the first
|
|
// trigger we unregister ALL the listeners, not just the one that fired.
|
|
function reveal() {
|
|
removeAll()
|
|
setShow(true)
|
|
}
|
|
for (const e of events) {
|
|
document.addEventListener(e, reveal, { passive: true, capture: true })
|
|
}
|
|
return removeAll
|
|
}, [props.prefetch])
|
|
|
|
return (
|
|
<>
|
|
{show && props.cssFile && (
|
|
<link crossOrigin="anonymous" href={props.cssFile} rel="stylesheet" />
|
|
)}
|
|
{show && props.woff2File && (
|
|
<link
|
|
crossOrigin="anonymous"
|
|
rel="preload"
|
|
href={props.woff2File}
|
|
as="font"
|
|
type="font/woff2"
|
|
/>
|
|
)}
|
|
</>
|
|
)
|
|
}
|