Files
zeekayandGitHub e20dc71ad8 i18n: /s* to /z*, the app's rooms and settings read their copy through t (#69)
The product pages from /s3 to /zap, /university and its course data,
/trust, /security, /sdks, /support, /tasks, /startups, /sms-opt-in, the
buying specialist, Zen, Kai's guide, Studio, the settings pages, and the
shared sales, solutions, zap and ui pieces. Client code draws with t(),
server components with <T>, copy held as data is marked with phrase()
and drawn through t() where it lands. A link or a figure inside a
sentence is a value, so a translator reorders the whole sentence.

Rebased on main: every page main moved onto Fold or Steps keeps main's
layout, with its words wrapped (label, title, lede, points). Steps now
draws a step's body through t, as it already drew the title. Settings
keeps main's usage panel, refresh, rewards wallet and sign-in wallet
rows, each label wrapped.

Left English: the skills page's install line (a command and two URLs),
and the solution eyebrow and sibling heading built from a kind label.

Claude-Session: https://claude.ai/code/session_015XYKLjZtDTJEnMo4eK3AFH
2026-10-29 23:51:44 -07:00

173 lines
6.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* /support — the Help Center, the docs, live status, and a way to reach a human.
*
* NO TAILWIND except one prose-link hover, named at its call site. This is a
* SERVER page and stays one: no `Head` here, because `Head` carries a scroll
* entrance and this page has never had motion — giving it one would be a change
* to the picture smuggled in as a conversion. The frame is `Box render="section"`
* with the paddings the page already stated; the type and the controls are the
* @hanzo/ui's `Display`, `Lede`, `Chip`, `Leaf` and `More`.
*
* Each channel card is a `Leaf`, the site's card-that-IS-a-link, and its call
* to action lifts with it: the card decides the hover, the content says who
* takes part.
*/
import type { Metadata } from 'next'
import { LifeBuoy, BookOpen, Activity, Mail, MessagesSquare, ArrowUpRight } from 'lucide-react'
import { Github } from '@/components/brand'
import { Box, Text } from '@/components/ui'
import { mix } from '@hanzo/app/lib/mix'
import { More, Leaf } from '@hanzo/ui/marketing'
import { Fold } from '@/components/marketing/fold'
import { Grid } from '@hanzo/ui/grid'
import { phrase } from '@hanzo/i18n'
import { T } from '@hanzo/i18n/react'
export const metadata: Metadata = {
title: 'Support — Hanzo',
description: 'Get help with Hanzo — the Help Center, documentation, live system status, and a way to reach a human.',
}
const CHANNELS = [
{
icon: LifeBuoy,
title: phrase('Help Center'),
body: phrase('Search answers, browse guides, and open a support ticket. The fastest path to a resolution.'),
href: 'https://hanzo.help',
cta: phrase('Open Help Center'),
},
{
icon: BookOpen,
title: phrase('Documentation'),
body: phrase('Guides, API references, and quickstarts for every product across the Hanzo Cloud.'),
href: 'https://docs.hanzo.ai',
cta: phrase('Read the docs'),
},
{
icon: Activity,
title: phrase('System Status'),
body: phrase('Live uptime and incident history for every Hanzo service. Check here first if something feels off.'),
href: 'https://status.hanzo.ai',
cta: phrase('View status'),
},
{
icon: MessagesSquare,
title: phrase('Community'),
body: phrase('Ask questions and share what you build with other developers on the Hanzo Discord and Community.'),
href: 'https://discord.gg/XthHQQj',
cta: phrase('Join the community'),
},
{
icon: Github,
title: 'GitHub',
body: phrase('Report a bug, request a feature, or contribute — our SDKs and tooling are open source.'),
href: 'https://github.com/hanzoai',
cta: phrase('Open an issue'),
},
{
icon: Mail,
title: phrase('Email us'),
body: phrase('Prefer email? Reach the team directly and we’ll get back to you.'),
href: 'mailto:[email protected]',
cta: '[email protected]',
},
]
/** The hairline tile this page sets a card and a footnote in. */
const TILE = {
borderRadius: 'var(--radius-xl)',
borderWidth: 1,
borderColor: 'var(--neutral-800)',
backgroundColor: 'color-mix(in oklab, var(--neutral-900) 50%, transparent)',
padding: 24,
} as const
/** A card: the tile above, plus the edge lift `Leaf` owns. */
const CARD = { p: 24, borderColor: "var(--neutral-800)", display: "flex", flexDirection: "column", bg: "color-mix(in oklab, var(--neutral-900) 50%, transparent)", hoverStyle: { borderColor: "var(--neutral-600)" } } as const
/** The disc a channel's mark sits on; the mark paints in its ink. */
const MARK = {
render: 'span',
mb: 16,
display: 'inline-flex',
height: 40,
width: 40,
items: 'center',
justify: 'center',
rounded: 'var(--radius-lg)',
borderWidth: 1,
borderColor: 'var(--neutral-800)',
bg: mix('var(--pure-white)', 5),
color: 'var(--foreground)',
} as const
export default function SupportPage() {
return (
<Box render="main" position="relative" overflow="hidden">
{/* The first screen: the question, and every channel that answers it under it. */}
<Fold
label={phrase('Support')}
mark={<LifeBuoy width={12} height={12} color="currentColor" />}
title={phrase('How can we help?')}
lede={phrase('Answers, docs, live status, and a direct line to the team.')}
>
<Box width="100%" maxW={1152} mx="auto">
<Grid columns={{ min: 300, max: 3 }} gap={16}>
{CHANNELS.map((c) => {
const Icon = c.icon
const external = c.href.startsWith('http')
return (
<Leaf
render="a"
key={c.title}
href={c.href}
target={external ? '_blank' : undefined}
rel={external ? 'noopener noreferrer' : undefined}
{...CARD}
hoverStyle={{ borderColor: "var(--neutral-600)" }}
>
<Text {...MARK}>
<Icon width={20} height={20} />
</Text>
<Text render="h2" mb={6} fontSize="$4" lineHeight="1.2891rem" fontWeight="600" color="var(--foreground)">
<T>{c.title}</T>
</Text>
<Text render="p" mb={20} grow={1} shrink={1} flexBasis="0%" fontSize="$2" lineHeight="1.3203rem" color="var(--muted-foreground)">
<T>{c.body}</T>
</Text>
<More render="span" gap={6} $group-hover={{ color: 'var(--text-primary)' }}>
<T>{c.cta}</T> <ArrowUpRight width={16} height={16} data-i18n-mirror />
</More>
</Leaf>
)
})}
</Grid>
{/* Enterprise footer note */}
<Box mt={24} {...TILE}>
<Text render="p" display="block" fontSize="$2" text="center" color="var(--muted-foreground)">
{/* A link in a sentence, not a control: the underline appearing on
approach is the whole treatment, and @hanzo/design's base
already states it once for every link inside a paragraph
(`:is(p,li,…) a:hover{text-decoration:underline}`), so this one
says nothing. */}
<T
values={{
link: (
<Text render="a" {...{ href: 'mailto:[email protected]' }} fontWeight="500" color="var(--foreground)">
<T values={{ email: '[email protected]' }}>{'Email {email}'}</T>
</Text>
),
}}
>
{'On an enterprise plan or need a dedicated channel? {link} and we’ll route you to your team.'}
</T>
</Text>
</Box>
</Box>
</Fold>
</Box>
)
}