Files
hanzo.ai/components/home/nav-data.ts
zeekay 4382b0cfcf booking: a call with the team is cal.com/hanzo
BOOKING is Hanzo AI's page at cal.com, where a visitor picks the 15- or
30-minute call. The sales form and "Book a 30-minute call" open INTRO, the
30-minute event page, which takes the name, email and notes the form fills
in; the profile does not. A click to cal.com/hanzo is the sales_contacted
moment, as cal.hanzo.ai was.

Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
2026-10-25 18:16:35 -07:00

609 lines
23 KiB
TypeScript

/**
* Where the site goes: the hosts it links out to, and the one nav tree.
*
* The hosts come first, named once so no page hard-codes a URL. The tree comes
* last (`COMPANY`, `MENUS`, `LOGIN`, `TRY`, `LEGAL`). The bar and the phone
* sheet draw that whole tree. The footer draws `FOOT`: a short set of doors.
* Everything else is found from those doors and from the menus, on the page
* it belongs to.
*/
import type { GlyphName } from '@hanzogui/shell'
import { phrase } from '@hanzo/i18n'
import { LOGIN as SIGNIN, signUp } from '@hanzo/app/lib/destination'
import { dev, GET, WORKSPACE } from '@hanzo/app/lib/host'
import { NOW } from '@/lib/zen'
import blog from '@/lib/data/blog.json' with { type: 'json' }
// Solutions' and Hanzo OS's rows, derived at prebuild from lib/data/solutions.ts
// and lib/layers.ts (scripts/sync-menu.mjs): names and addresses only, since
// this tree is in every page's first load and those lists carry their pages' copy.
import menu from '@/lib/data/menu.json' with { type: 'json' }
const INDEX = menu.index
const kind = (id: string) => menu.solutions.find((k) => k.id === id)?.links ?? []
// The app IS this site: `/` signed in, and it signs in here, at /login and
// /signup, never on another host.
//
// APP is what hanzo.app is now: the page you get the Hanzo App from — the
// download, the CLI, or the app in the browser. A link that means "get the
// product" and a link that means "open it" are different promises, and one
// constant serving both is how a download button quietly becomes a second
// front door.
export const APP = GET
export const SH = 'https://hanzo.sh'
export const CLOUD = 'https://cloud.hanzo.ai'
export const CONSOLE = 'https://platform.hanzo.ai'
/**
* Where a reader gets the one key everything is billed against. The console
* signs a reader in or up on the way, and a key costs nothing to hold, so this
* is where every "free" call to action ends: /signup ends at /chat, whose
* workspace is the paid plan. `/api-keys` is the address the console's own
* bundle links to; platform.hanzo.ai answers 200 with identical HTML for any
* path, so read the console's resolver before changing it.
*/
export const KEYS = `${CONSOLE}/api-keys`
/** Where a reader sets up Claude Code, Codex, Cursor or Antigravity to run through Hanzo:
* install, sign in, `hanzo code <tool>`. The platform page, not a second copy of it here. */
export const CODING = `${CONSOLE}/accelerate`
/** Hanzo Dev, the builder: the door that signs a stranger in and opens the
* app in Dev. hanzo.build forwards here. */
export const BUILD = dev()
/** Where a new person starts: this site's sign-up, then the app at `/`. Try
* Hanzo and the fold's Get started are both this one door. */
export { signUp }
export const STATUS = 'https://status.hanzo.ai'
export const GITHUB = 'https://github.com/hanzoai'
export const DOCS = 'https://docs.hanzo.ai'
export const BLOG = 'https://blog.hanzo.ai'
export const AGENCY = 'https://hanzo.agency'
export const STUDIO = 'https://studio.hanzo.ai'
export const UNIVERSITY = 'https://hanzo.university'
/** A call with the team, booked: Hanzo AI's page at Cal.com, where a visitor
* picks the 15- or 30-minute call. */
export const BOOKING = 'https://cal.com/hanzo'
/** The 30-minute intro itself. An event page, unlike the profile, takes the
* `name`, `email` and `notes` the sales form fills in. */
export const INTRO = `${BOOKING}/30min`
/** The ONE way into the chat, and it is no longer a hand-off.
*
* It used to forward the prompt to hanzo.chat, because this site did not
* implement a chat. It does: /chat on this origin IS the product. So the text
* travels as `?q=` on a same-origin navigation and the reader never leaves.
*
* `hz_ref=site` is gone with the crossing it existed for: hanzo.ai and
* hanzo.chat were separate origins, so a logged-out visitor had a DIFFERENT
* anonymousId on each and no per-person funnel could span them — the param
* carried the source surface so the far side could stamp its own event. One
* origin has one identity and the funnel joins itself.
*
* `submit=true` is gone for a stronger reason: it asked the far side to SEND
* on arrival, and /chat deliberately refuses to. A link is not consent to
* spend somebody's credits, so the text is TYPED INTO the composer and a
* human presses send. Passing a flag that the destination is right to ignore
* is a promise this code should stop making. */
/** The chat's address, WITH ITS TRAILING SLASH, named once.
*
* /chat is a mounted single-page app, not a Next route, and its index declares
* `<base href="/chat/">`. So the slash is not cosmetic and it is not optional:
* fetched at `/chat` the shell still answers 200, the base resolves against
* `/chat` as a FILE, the router matches nothing, and the app renders an empty
* body — 1016 bytes against 24990, no console error, no failed request. A
* blank page that reports success is the worst shape a bug can take, and it
* was on this site's primary call to action.
*
* hanzo.chat redirects to `/chat/` and therefore always worked; every link on
* this site said `/chat` and therefore never did. That asymmetry is why nobody
* caught it: the door people tested was not the door people clicked.
*
* IT IS `/chat`, WITHOUT THE SLASH — the trailing form was the fix for that and
* it moved the failure rather than removing it. `next.config.mjs` sets
* `trailingSlash: false`, so the export writes `out/chat.html` and no
* `out/chat/index.html`: a static host answers `/chat` with the page and
* `/chat/` with a 404. Every submitted question went to the second one.
*
* Measured on both planes. The export: `/chat` 200, `/chat/` 404. Production:
* `/chat?q=hi` 301s to `/chat/?q=hi` — the query rides the redirect, so the
* slashless form reaches the same room there with the question intact. One
* spelling that works in the export, in dev, and in production.
*
* One constant because there were nine spellings of this address and the tenth
* would have been wrong too. */
export const CHAT = '/chat'
export function goToChat(prompt = '') {
const q = prompt.trim()
window.location.href = q ? `${CHAT}?q=${encodeURIComponent(q)}` : CHAT
}
// ── The nav tree ─────────────────────────────────────────────────────────────
//
// Shaped after openai.com's sitemap, entry for entry where Hanzo has the page:
// Company, Research, Products, Solutions (their Business), Developers, Learn
// (their Support and More), and Terms & Policies at the foot. A label with no
// page on this site has no row; a row is a page that answers.
//
// Every label, title and hint is English marked with `phrase` (@hanzo/i18n), so
// the extractor finds it, and drawn through `t` in the reader's language. A name
// standing alone (Hanzo Dev, Enso 1, Koma, GitHub) is not marked and is drawn as
// written, and so are the blog's article titles, which are English articles.
/** A destination. `hint` is a short second line, used only where a row needs one. */
export interface Link {
label: string
href: string
hint?: string
}
/** A titled column. A `lead` column sets its links in display type, first. */
export interface Group {
title: string
links: Link[]
lead?: boolean
}
/**
* A top-level entry: its label and mark, the page it stands for, and the
* columns it opens. `glyph` names a mark from the shell's one set. An entry
* with no columns opens nothing: it is a link to its page.
*/
export interface Menu {
id: string
label: string
href: string
glyph: GlyphName
groups: Group[]
}
/** A link leaves the site when it names a host. It says so with ↗ and a new tab. */
export const away = (href: string): boolean => /^https?:\/\//.test(href)
/** The company, opened from the wordmark. */
export const COMPANY: Menu = {
id: 'company',
label: phrase('Company'),
href: '/about',
glyph: 'user',
groups: [
{
title: phrase('Explore Company'),
lead: true,
links: [
{ label: phrase('About Us'), href: '/about' },
{ label: phrase('Reviews'), href: '/reviews' },
{ label: phrase('Careers'), href: '/careers' },
{ label: phrase('News'), href: '/press' },
],
},
{
title: phrase('Resources'),
links: [
{ label: phrase('Brand Guidelines'), href: '/brand' },
{ label: phrase('Philosophy'), href: '/philosophy' },
{ label: phrase('Investors'), href: '/investors' },
{ label: phrase('Contact'), href: '/contact' },
],
},
],
}
/** The bar, left to right after the wordmark. */
export const MENUS: Menu[] = [
{
id: 'research',
label: phrase('Research'),
href: '/research',
glyph: 'pulse',
groups: [
{
title: phrase('Releases'),
lead: true,
links: [
{ label: 'Enso 1', href: '/enso' },
{ label: 'Kai 1', href: '/kai' },
{ label: NOW.name, href: '/zen' },
{ label: 'Kata 1', href: '/kata' },
{ label: 'Gen 1', href: '/gen' },
],
},
{
title: phrase('Creative AI'),
links: [
{ label: 'Koma', href: '/koma' },
{ label: 'Iro', href: '/iro' },
{ label: 'Mori', href: '/mori' },
{ label: 'Oto', href: '/oto' },
{ label: 'Koe', href: '/koe' },
{ label: 'Uta', href: '/uta' },
],
},
{
title: phrase('Explore Research'),
links: [
{ label: phrase('Overview'), href: '/research' },
{ label: phrase('Benchmarks'), href: '/benchmarks' },
{ label: phrase('Compare'), href: '/compare' },
{ label: phrase('Open source'), href: '/open-source' },
{ label: phrase('Specifications'), href: 'https://hips.hanzo.ai' },
],
},
{
title: phrase('Safety'),
links: [
{ label: phrase('Security'), href: '/security' },
{ label: phrase('Trust & transparency'), href: '/trust' },
],
},
],
},
{
id: 'products',
label: phrase('Products'),
href: '/products',
glyph: 'blocks',
groups: [
{
title: phrase('AI Models'),
lead: true,
links: [
{ label: phrase('All models'), href: '/models' },
{ label: phrase('LLMs'), href: '/zen' },
{ label: phrase('Decisions'), href: '/kai' },
{ label: phrase('Routing'), href: '/enso' },
],
},
{
title: phrase('Creative AI'),
links: [
{ label: phrase('Video'), href: '/koma' },
{ label: phrase('Images'), href: '/iro' },
{ label: phrase('3D'), href: '/mori' },
{ label: phrase('Sound effects'), href: '/oto' },
{ label: phrase('Voice'), href: '/koe' },
{ label: phrase('Music'), href: '/uta' },
],
},
{
title: phrase('API Platform'),
links: [
{ label: phrase('Overview'), href: '/platform' },
{ label: phrase('API'), href: '/api' },
{ label: phrase('Playground'), href: '/playground' },
{ label: phrase('Gateway'), href: '/gateway' },
{ label: phrase('Agents'), href: '/agents' },
{ label: 'Base', href: '/base' },
{ label: phrase('Machines'), href: '/machines' },
],
},
{
title: phrase('Apps and tools'),
links: [
{ label: 'Hanzo App', href: APP },
{ label: 'Hanzo Bot', href: '/bot' },
{ label: 'Hanzo CLI', href: '/cli' },
{ label: 'Hanzo Dev', href: BUILD },
{ label: 'Hanzo Gen', href: '/gen' },
{ label: 'Hanzo Kata', href: '/kata' },
{ label: 'Hanzo Team', href: WORKSPACE },
{ label: 'MCP', href: '/mcp' },
{ label: phrase('Skills'), href: '/skills' },
],
},
{
title: phrase('Install'),
links: [
{ label: phrase('CLI'), href: '/cli' },
{ label: phrase('Desktop app'), href: '/desktop' },
{ label: phrase('Browser extension'), href: '/extension' },
{ label: phrase('IDE'), href: '/ide' },
{ label: phrase('All downloads'), href: '/download' },
{ label: phrase('Release notes'), href: `${GITHUB}/cli/releases` },
],
},
// Hanzo OS: the product index and its layers (lib/layers.ts). Every
// product page is linked from its layer, so it is two clicks from here.
{
title: 'Hanzo OS',
links: [{ label: phrase('All products'), href: '/products' }, ...menu.layers],
},
{
title: phrase('More from Hanzo'),
links: [
{ label: phrase('Start from a template'), href: '/templates' },
{ label: phrase('Agents at work'), href: '/agents/crew' },
{ label: phrase('Cloud on your laptop'), href: '/cloud/local' },
{ label: phrase('Start a company'), href: '/start' },
],
},
],
},
{
id: 'solutions',
label: phrase('Solutions'),
href: INDEX,
glyph: 'puzzle',
groups: [
{
title: phrase('Explore Solutions'),
lead: true,
links: [
{ label: phrase('All solutions'), href: INDEX },
{ label: phrase('Enterprise'), href: '/enterprise' },
{ label: phrase('Agency'), href: AGENCY },
{ label: phrase('Customer stories'), href: '/customers' },
{ label: phrase('Contact sales'), href: '/contact-sales' },
],
},
// Teams, Industries, Use cases: every entry lib/data/solutions.ts holds, by kind.
...menu.solutions.filter((k) => k.id !== 'reserved').map((k) => ({ title: k.title, links: k.links })),
{
title: phrase('Programs'),
links: [
...kind('reserved'),
{ label: phrase('Startups'), href: '/startups' },
{ label: phrase('Partner network'), href: '/affiliate' },
{ label: phrase('Cost calculator'), href: '/calculator' },
],
},
],
},
{
id: 'developers',
label: phrase('Developers'),
href: DOCS,
glyph: 'code',
groups: [
{
title: phrase('Explore Developers'),
lead: true,
links: [
{ label: phrase('Documentation'), href: DOCS },
{ label: phrase('API reference'), href: `${DOCS}/docs/openapi/` },
{ label: phrase('Quickstart'), href: `${DOCS}/docs/quickstart/` },
{ label: phrase('SDKs'), href: '/sdks' },
{ label: phrase('Open models'), href: 'https://huggingface.co/zenlm' },
],
},
{
title: phrase('Resources'),
links: [
{ label: phrase('API keys'), href: KEYS },
{ label: 'Claude Code, Codex, Cursor', href: CODING, hint: phrase('Use Hanzo with your coding tools') },
{ label: phrase('Integrations'), href: '/integrations' },
{ label: phrase('Examples'), href: '/gallery' },
],
},
{
title: phrase('Community'),
links: [
{ label: 'GitHub', href: GITHUB },
{ label: phrase('Status'), href: STATUS },
],
},
],
},
{
id: 'learn',
label: phrase('Learn'),
href: '/learn',
glyph: 'book',
groups: [
{
title: phrase('Blog'),
links: [
...blog.posts.slice(0, 3).map((post) => ({
label: post.title,
href: post.link,
hint: post.category ? post.category.toUpperCase() : undefined,
})),
{ label: phrase('All articles'), href: '/blog' },
],
},
{
title: phrase('Research & Guides'),
links: [
{ label: phrase('Overview'), href: '/learn' },
{ label: phrase('Technical Blog'), href: BLOG },
{ label: phrase('Kai & Decision Models'), href: '/blog/kai-decision-models' },
{ label: phrase('Coding agents'), href: `${DOCS}/docs/coding` },
{ label: phrase('Guides'), href: `${DOCS}/docs/guides/` },
{ label: phrase('Cookbook'), href: `${DOCS}/docs/guides/cookbook/` },
],
},
{
title: phrase('Support'),
links: [
{ label: phrase('Documentation'), href: DOCS },
{ label: phrase('Help center'), href: '/support' },
],
},
// Last: the university, then each of its courses (app/(marketing)/university/courses-data.ts).
{
title: 'Hanzo University',
links: [
{ label: 'Hanzo University', href: UNIVERSITY, hint: phrase('Courses and certifications') },
{ label: phrase('Agentic coding'), href: '/university/agentic-coding' },
{ label: phrase('Reinforcement learning'), href: '/university/reinforcement-learning' },
{ label: phrase('Systems engineering'), href: '/university/systems-engineering' },
{ label: phrase('AI practitioner'), href: '/university/ai-practitioner' },
{ label: phrase('AI architect'), href: '/university/ai-architect' },
{ label: phrase('Agentic marketing'), href: '/university/agentic-marketing' },
],
},
],
},
// Last: Pricing is one page, so it is a link to it rather than a menu.
{ id: 'pricing', label: phrase('Pricing'), href: '/pricing', glyph: 'card', groups: [] },
]
/** Log in ▾: the two products a person signs in to. The app signs in here. */
export const LOGIN: Link[] = [
{ label: 'Hanzo App', href: SIGNIN, hint: phrase('Build, chat and ship') },
{ label: phrase('API Platform'), href: KEYS, hint: phrase('Keys, usage and billing') },
]
/** The one filled control in the bar: onboarding, dropping into personal or business plans first. */
export const TRY: Link = { label: phrase('Try Hanzo'), href: '/signup' }
/** What the same control says to a reader who is signed in: the app, at `/`. */
export const OPEN: Link = { label: phrase('Open Hanzo'), href: '/' }
/** Terms & Policies. The documents live here so the export keeps them; the
* footer shows the short line below, and /legal indexes the rest. */
export const LEGAL: Link[] = [
{ label: phrase('Terms of use'), href: '/terms' },
{ label: phrase('Privacy policy'), href: '/privacy' },
{ label: phrase('Usage policy'), href: '/aup' },
{ label: phrase('Cookie policy'), href: '/cookies' },
{ label: phrase('Privacy choices'), href: '#choices' },
{ label: phrase('Other policies'), href: '/legal' },
]
/**
* The footer: the header's menus, in the header's order and under the same
* names (MENUS), then Company — a few of each menu's links under its title,
* the title opening the page where the rest of that subject lives. The two are
* held in step by e2e/nav.spec.ts.
*/
export const FOOT: Menu[] = [
{
id: 'research-foot',
label: phrase('Research'),
href: '/research',
glyph: 'pulse',
groups: [
{
title: phrase('Research'),
lead: true,
links: [
{ label: 'Enso 1', href: '/enso' },
{ label: 'Kai 1', href: '/kai' },
{ label: NOW.name, href: '/zen' },
{ label: phrase('Creative AI'), href: '/models#creative' },
{ label: phrase('Benchmarks'), href: '/benchmarks' },
{ label: phrase('Compare'), href: '/compare' },
{ label: phrase('Open source'), href: '/open-source' },
{ label: phrase('Security'), href: '/security' },
],
},
],
},
{
id: 'products-foot',
label: phrase('Products'),
href: '/products',
glyph: 'blocks',
groups: [
{
title: phrase('Products'),
lead: true,
links: [
{ label: phrase('All models'), href: '/models' },
{ label: phrase('LLMs'), href: '/zen' },
{ label: phrase('Decisions'), href: '/kai' },
{ label: phrase('Routing'), href: '/enso' },
{ label: phrase('Video'), href: '/koma' },
{ label: phrase('Images'), href: '/iro' },
{ label: phrase('API Platform'), href: '/platform' },
{ label: 'Hanzo App', href: APP },
{ label: 'Hanzo Dev', href: BUILD },
{ label: phrase('Download'), href: '/download' },
],
},
],
},
{
id: 'solutions-foot',
label: phrase('Solutions'),
href: INDEX,
glyph: 'puzzle',
groups: [
{
title: phrase('Solutions'),
lead: true,
links: [
{ label: phrase('All solutions'), href: INDEX },
{ label: phrase('Enterprise'), href: '/enterprise' },
{ label: phrase('Agency'), href: AGENCY },
{ label: phrase('Customer stories'), href: '/customers' },
{ label: phrase('Pricing'), href: '/pricing' },
{ label: phrase('Startups'), href: '/startups' },
{ label: phrase('Contact sales'), href: '/contact-sales' },
],
},
],
},
{
id: 'developers-foot',
label: phrase('Developers'),
href: DOCS,
glyph: 'code',
groups: [
{
title: phrase('Developers'),
lead: true,
links: [
{ label: phrase('Documentation'), href: DOCS },
{ label: phrase('API reference'), href: `${DOCS}/docs/openapi/` },
{ label: phrase('Quickstart'), href: `${DOCS}/docs/quickstart/` },
{ label: phrase('SDKs'), href: '/sdks' },
{ label: phrase('API keys'), href: KEYS },
{ label: 'GitHub', href: GITHUB },
{ label: phrase('Status'), href: STATUS },
],
},
],
},
{
id: 'learn-foot',
label: phrase('Learn'),
href: '/learn',
glyph: 'book',
groups: [
{
title: phrase('Learn'),
lead: true,
links: [
{ label: phrase('Blog'), href: '/blog' },
{ label: phrase('Guides'), href: `${DOCS}/docs/guides/` },
{ label: phrase('Cookbook'), href: `${DOCS}/docs/guides/cookbook/` },
{ label: phrase('Help center'), href: '/support' },
{ label: 'Hanzo University', href: UNIVERSITY },
],
},
],
},
{
id: 'company-foot',
label: phrase('Company'),
href: '/about',
glyph: 'user',
groups: [
{
title: phrase('Company'),
lead: true,
links: [
{ label: phrase('About'), href: '/about' },
{ label: phrase('Reviews'), href: '/reviews' },
{ label: phrase('Careers'), href: '/careers' },
{ label: phrase('News'), href: '/press' },
{ label: phrase('Investors'), href: '/investors' },
{ label: phrase('Brand'), href: '/brand' },
{ label: phrase('Contact'), href: '/contact' },
],
},
],
},
]
/** The line under the columns. /legal holds the policies that are not named here. */
export const FOOT_LINE: Link[] = [
{ label: phrase('Terms'), href: '/terms' },
{ label: phrase('Privacy'), href: '/privacy' },
{ label: phrase('Usage policy'), href: '/aup' },
{ label: phrase('Privacy choices'), href: '#choices' },
]