mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 04:20:39 +00:00
Every word the landing, the header menus, the phone sheet, the footer,
the help corner and the way in (sign-in, sign-up, the reset, the
invitation, the callback, onboarding, the 404) write goes through
@hanzo/i18n's t(): one sentence is one message, its figures, names and
links arguments; copy written as data is phrase('…') where written and
t(label) where drawn. Plans, the chart, the API states and the lines
lib/kai and lib/enso build for the landing do the same.
Right to left: <html lang dir> is set before the first paint (the
package's bootScript first in the head); a figure, clock, range or
price outside a sentence is isolated; sides are logical gui props, the
layout's [data-join] corners logical, a bar grows from the start;
arrows along the line mirror (Onward for "words ->" links). The repo
dates read in the reader's language.
Gates select by slot, never by an English label (rtl, help). New gate
translated.spec.ts: in Arabic the landing at 1440 and 390, every menu
open, the phone sheet, sign-in, sign-up and the app signed in hold no
authored English, nothing scrolls sideways, every range is isolated;
French the same for English's commonest words. What another package
draws with no words prop is listed by name (@hanzo/ui's Footer label,
@hanzo/build's composer row and suggestions).
@hanzo/i18n 0.5.3 (the catalogs: 1,443 keys, every offered locale
complete), @hanzo/app 0.2.1 (the app's words). The link gate imports
the terms versions from @hanzo/app, the one SDK main now resolves.
81 lines
3.0 KiB
TypeScript
81 lines
3.0 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* What a section draws in place of api.hanzo.ai's answer: while it is on its
|
|
* way (`Loading`), and when it did not come (`Unreachable`). The second says the
|
|
* backend did not answer and shows nothing in its place, because the only
|
|
* other thing it could show is a number somebody else saw earlier.
|
|
*
|
|
* `data-api` names the state on the element, so a gate finds it without
|
|
* reading its words.
|
|
*
|
|
* `what` is a phrase naming what is read ("the plans"): it is translated where
|
|
* drawn, so a caller writes it inside `phrase()` (@hanzo/i18n) for the catalog
|
|
* to hold it, and one it does not hold reads in English.
|
|
*/
|
|
|
|
import type { ReactNode } from 'react'
|
|
import { useI18n } from '@hanzo/i18n/react'
|
|
import { Spinner, XStack, YStack } from '@hanzo/ui'
|
|
import { Line } from '@/components/type'
|
|
import type { Reading } from '@/lib/api/use'
|
|
|
|
/** The document is on its way: one spinner, one line saying what is being read. */
|
|
export function Loading({ what }: { what: string }) {
|
|
const { t } = useI18n()
|
|
return (
|
|
<XStack role="status" aria-live="polite" data-api="loading" items="center" justify="center" gap="$3" py="$8">
|
|
<Spinner size={16} />
|
|
<Line size="sm" tone="muted">
|
|
{t('Reading {what} from api.hanzo.ai', { what: t(what) })}
|
|
</Line>
|
|
</XStack>
|
|
)
|
|
}
|
|
|
|
/** The backend did not answer: said plainly, with nothing standing in for the numbers. */
|
|
export function Unreachable({ what }: { what: string }) {
|
|
const { t } = useI18n()
|
|
return (
|
|
<YStack
|
|
role="alert"
|
|
data-api="unreachable"
|
|
items="center"
|
|
gap="$2"
|
|
py="$6"
|
|
px="$5"
|
|
mx="auto"
|
|
maxW={560}
|
|
rounded="var(--radius-xl)"
|
|
borderWidth={1}
|
|
borderColor="$edge"
|
|
bg="$panel"
|
|
>
|
|
<Line weight="600" align="center">
|
|
{t('api.hanzo.ai is unreachable')}
|
|
</Line>
|
|
<Line size="sm" tone="muted" align="center">
|
|
{t('This reads {what} live from the backend, and it did not answer. Nothing older is shown instead. Reload to try again.', { what: t(what) })}
|
|
</Line>
|
|
</YStack>
|
|
)
|
|
}
|
|
|
|
/** A read drawn: `children` with its data once here, and the two states above until then. */
|
|
export function Ready<T>({ reading, what, children }: { reading: Reading<T>; what: string; children: (data: T) => ReactNode }) {
|
|
if (reading.state === 'loading') return <Loading what={what} />
|
|
if (reading.state === 'unreachable') return <Unreachable what={what} />
|
|
return <>{children(reading.data)}</>
|
|
}
|
|
|
|
/** A figure inside a sentence: an ellipsis while it is read, a dash where it could not be. */
|
|
export function Inline<T>({ reading, children }: { reading: Reading<T>; children: (data: T) => ReactNode }) {
|
|
const { t } = useI18n()
|
|
if (reading.state === 'ready') return <>{children(reading.data)}</>
|
|
return (
|
|
<span data-api={reading.state} title={reading.state === 'loading' ? t('Reading api.hanzo.ai') : t('api.hanzo.ai is unreachable')}>
|
|
{reading.state === 'loading' ? '…' : '—'}
|
|
</span>
|
|
)
|
|
}
|