mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +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.
72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, type ReactNode } from 'react'
|
|
import { useAnalytics } from '@hanzo/event/react'
|
|
import { useI18n } from '@hanzo/i18n/react'
|
|
import { Text, YStack } from '@hanzo/ui'
|
|
import { TextLink } from '@hanzo/ui/marketing'
|
|
import { Focus } from '@/components/shell/focus'
|
|
|
|
/**
|
|
* An account page's one screen (/login, /signup, /forget, /join, /login/mfa):
|
|
* the focused page (components/shell/focus) with the way in as its card. The
|
|
* title and the line under it, then the card, the switch to another page and
|
|
* the terms line, 16px apart, the whole column at the card's measure in the
|
|
* middle of the window under the bar, Hanzo's mark at the foot.
|
|
*
|
|
* SIGNING IN HAPPENS HERE. `signin` is the sign-in panel (components/auth/panel),
|
|
* unchanged. IAM checks every credential; no hanzo.id page is drawn. The panel
|
|
* keeps its place in the tree whatever the page settles into after hydration,
|
|
* so it is never mounted twice.
|
|
*
|
|
* The section is `data-slot="hero"` and its title `#hero-title`: a checkout's
|
|
* sign-in holds the section back until it has drawn the checkout's step
|
|
* (lib/auth/sale `HOLD`).
|
|
*
|
|
* The terms line is one sentence in the reader's language (@hanzo/i18n), the two
|
|
* documents its arguments, so a translation puts them where its grammar does.
|
|
*
|
|
* Events: landing_viewed.
|
|
*/
|
|
export default function Hero({
|
|
signin,
|
|
title,
|
|
line,
|
|
terms,
|
|
switcher,
|
|
}: {
|
|
signin: ReactNode
|
|
title: ReactNode
|
|
line?: ReactNode
|
|
terms?: ReactNode
|
|
switcher?: ReactNode
|
|
}) {
|
|
const events = useAnalytics()
|
|
const { t } = useI18n()
|
|
|
|
useEffect(() => {
|
|
events.capture('landing_viewed')
|
|
// The client is one per page; the view is counted once.
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [])
|
|
|
|
return (
|
|
<Focus slot="hero" id="hero-title" title={title} line={line}>
|
|
<YStack items="center" gap="$4">
|
|
{signin}
|
|
{switcher}
|
|
{terms === undefined ? (
|
|
<Text render="p" m={0} maxW={420} fontSize="$1" lineHeight="$1" color="var(--muted-foreground)" text="center">
|
|
{t("By continuing, you agree to Hanzo's {terms} and {privacy}.", {
|
|
terms: <TextLink href="/terms">{t('Terms')}</TextLink>,
|
|
privacy: <TextLink href="/privacy">{t('Privacy Policy')}</TextLink>,
|
|
})}
|
|
</Text>
|
|
) : (
|
|
terms
|
|
)}
|
|
</YStack>
|
|
</Focus>
|
|
)
|
|
}
|