mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
48 lines
2.4 KiB
TypeScript
48 lines
2.4 KiB
TypeScript
import type { ComponentType } from 'react'
|
|
import { Building2, CreditCard, Gauge, IdCard, KeyRound, Users } from 'lucide-react'
|
|
|
|
/**
|
|
* Every settings page, once: the column draws these rows, ⌘K searches them, and
|
|
* the phone's strip names the open one from them, so a page cannot be reachable
|
|
* one way and missing another.
|
|
*
|
|
* `team` marks a page a personal organization does not have. An org of one holds
|
|
* one person and takes no invitations (HIP-0527 I5), so its Members row is
|
|
* replaced by the Organization page's "Convert to team".
|
|
*/
|
|
export interface Place {
|
|
href: string
|
|
label: string
|
|
Icon: ComponentType<{ size?: number; 'aria-hidden'?: boolean }>
|
|
/** Words a person might search for that the label does not say. */
|
|
words: string
|
|
/** Part of an organization's settings rather than the person's own. */
|
|
org: boolean
|
|
team?: boolean
|
|
}
|
|
|
|
export const SETTINGS = '/settings'
|
|
export const ORGANIZATION = '/settings/organization'
|
|
/** API keys live in one place, the platform's keys page; this app keeps no copy. */
|
|
export const KEYS = 'https://platform.hanzo.ai/api-keys'
|
|
|
|
export const PLACES: Place[] = [
|
|
{ href: SETTINGS, label: 'General', Icon: IdCard, words: 'profile name picture photo theme appearance dark light account', org: false },
|
|
{ href: ORGANIZATION, label: 'Organization', Icon: Building2, words: 'name address country id delete convert team', org: true },
|
|
{ href: `${ORGANIZATION}/members`, label: 'Members', Icon: Users, words: 'people invite invitations roles remove teammates', org: true, team: true },
|
|
{ href: `${ORGANIZATION}/billing`, label: 'Billing', Icon: CreditCard, words: 'plan card payment invoices credits balance add funds', org: true },
|
|
{ href: `${ORGANIZATION}/usage`, label: 'Usage', Icon: Gauge, words: 'usage plan limits spend credit premium models', org: true },
|
|
{ href: KEYS, label: 'API keys', Icon: KeyRound, words: 'secret publishable default token credential revoke program automation', org: true },
|
|
]
|
|
|
|
/** The places a person can reach, narrowed by what they typed. */
|
|
export function find(places: Place[], query: string): Place[] {
|
|
const q = query.trim().toLowerCase()
|
|
if (!q) return places
|
|
return places.filter((p) => `${p.label} ${p.words}`.toLowerCase().includes(q))
|
|
}
|
|
|
|
/** The place an address is, or the nearest one above it. */
|
|
export const here = (route: string): Place | undefined =>
|
|
PLACES.find((p) => p.href === route) ?? PLACES.find((p) => p.href !== SETTINGS && route.startsWith(`${p.href}/`))
|