hololake-platform/src/components/HoloLakeHome.tsx

236 lines
13 KiB
TypeScript
Raw 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.

import { useState } from 'react'
import type { AppLocale, TranslationKey } from '../lib/i18n'
import { translate } from '../lib/i18n'
import { trackEvent } from '../lib/telemetry'
import { openExternalUrl } from '../utils/url'
import { Button } from './ui/button'
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from './ui/dialog'
export const HOLOLAKE_DEVELOPMENT_REPOSITORY_URL =
'https://guanghulab.com/fifth-domain/bingshuo/hololake-platform'
type HoloLakeHomeProps = {
locale: AppLocale
onEnterKnowledgeBase: () => void
}
type ChannelRoute = 'zero-core' | 'fifth-domain' | 'eternal-lake-heart' | 'light-lake' | 'heartbeat-core' | 'love-core' | 'servers'
type RouteCardProps = {
action?: string
description: string
eyebrow: string
onOpen?: () => void
status?: string
title: string
}
const architectureRoutes: Array<[string, TranslationKey, TranslationKey]> = [
['GLW-ENTRY-001', 'hololake.architecture.worldEntry', 'hololake.architecture.worldEntryDescription'],
['FD-LANGUAGE-001', 'hololake.architecture.fifthDomain', 'hololake.architecture.fifthDomainDescription'],
['TCS-ROOT-001', 'hololake.architecture.tcs', 'hololake.architecture.tcsDescription'],
['GLS-SYS-ARCH-001', 'hololake.architecture.gls', 'hololake.architecture.glsDescription'],
['ELH-LAMP-001', 'hololake.architecture.lakeLamp', 'hololake.architecture.lakeLampDescription'],
]
function RouteCard({ action, description, eyebrow, onOpen, status, title }: RouteCardProps) {
return (
<article className="channel-card">
<span className="channel-card__eyebrow">{eyebrow}</span>
<h2>{title}</h2>
<p>{description}</p>
{onOpen && action
? <Button variant="link" onClick={onOpen}>{action} <span></span></Button>
: <span className="channel-card__status">{status}</span>}
</article>
)
}
function PersonaRoute({ id, title }: { id: string; title: string }) {
return <li><code>{id}</code><strong>{title}</strong><span></span></li>
}
const registeredServers = [
{ id: 'BS-SG-001', label: '新加坡大脑服务器', owner: '冰朔 · 永恒湖心', status: '已接入', tone: 'online' },
{ id: 'BS-GZ-001', label: '广州个人服务器', owner: '冰朔 · 心跳核心', status: '接口预留', tone: 'pending' },
{ id: 'JD-FD-PRIMARY', label: '第五域企业主节点', owner: '第五域 · 零点原核', status: '接口预留', tone: 'pending' },
] as const
export function HoloLakeHome({ locale, onEnterKnowledgeBase }: HoloLakeHomeProps) {
const [route, setRoute] = useState<ChannelRoute>('zero-core')
const [architectureOpen, setArchitectureOpen] = useState(false)
const t = (key: TranslationKey) => translate(locale, key)
const navigate = (nextRoute: ChannelRoute) => {
trackEvent('guanghu_channel_opened', { route: nextRoute })
setRoute(nextRoute)
}
const openArchitecture = () => {
trackEvent('guanghu_architecture_opened', { route: 'GLS-SYS-ARCH-001' })
setArchitectureOpen(true)
}
const openDevelopmentRepository = () => {
trackEvent('hololake_development_repository_opened', { route: 'REPO-008' })
void openExternalUrl(HOLOLAKE_DEVELOPMENT_REPOSITORY_URL)
}
const openKnowledgeBase = () => {
trackEvent('guanghu_channel_module_opened', { channel: 'heartbeat-core', module: 'knowledge-base' })
onEnterKnowledgeBase()
}
const renderRoute = () => {
if (route === 'zero-core') {
return (
<section className="channel-stage channel-stage--root">
<p className="channel-stage__eyebrow">ZERO CORE · 000</p>
<h1>{t('hololake.channel.zeroCoreTitle')}</h1>
<p className="channel-stage__lead">{t('hololake.channel.zeroCoreDescription')}</p>
<Button className="hololake-home__primary" onClick={() => navigate('fifth-domain')}>{t('hololake.channel.enterFifthDomain')} <span></span></Button>
</section>
)
}
if (route === 'fifth-domain') {
return (
<section className="channel-stage">
<h1>{t('hololake.channel.fifthDomainTitle')}</h1>
<p className="channel-stage__lead">{t('hololake.channel.fifthDomainDescription')}</p>
<div className="channel-grid">
<RouteCard eyebrow="CANG ER · EXTERNAL NODE" title={t('hololake.channel.pufferfishTitle')} description={t('hololake.channel.pufferfishDescription')} status={t('hololake.channel.externalServerPending')} />
<RouteCard eyebrow="ICE SHUO · PERSONAL SYSTEM" title={t('hololake.channel.eternalLakeTitle')} description={t('hololake.channel.eternalLakeDescription')} action={t('hololake.channel.enterEternalLake')} onOpen={() => navigate('eternal-lake-heart')} />
</div>
</section>
)
}
if (route === 'eternal-lake-heart') {
return (
<section className="channel-stage">
<h1>{t('hololake.channel.eternalLakeTitle')}</h1>
<p className="channel-stage__lead">{t('hololake.channel.eternalLakeDescription')}</p>
<div className="channel-grid channel-grid--three">
<RouteCard eyebrow="PERSONA HOME" title={t('hololake.channel.lightLakeTitle')} description={t('hololake.channel.lightLakeDescription')} action={t('hololake.channel.enterLightLake')} onOpen={() => navigate('light-lake')} />
<RouteCard eyebrow="ICE SHUO · HUMAN SPACE" title={t('hololake.channel.heartbeatTitle')} description={t('hololake.channel.heartbeatDescription')} action={t('hololake.channel.enterHeartbeat')} onOpen={() => navigate('heartbeat-core')} />
<RouteCard eyebrow="ZHI ZHI · INTERNAL SUBSYSTEM" title={t('hololake.channel.loveCoreTitle')} description={t('hololake.channel.loveCoreDescription')} action={t('hololake.channel.enterLoveCore')} onOpen={() => navigate('love-core')} />
</div>
</section>
)
}
if (route === 'light-lake') {
return (
<section className="channel-stage">
<h1>{t('hololake.channel.lightLakeTitle')}</h1>
<p className="channel-stage__lead">{t('hololake.channel.lightLakeDescription')}</p>
<ul className="persona-route-list">
<PersonaRoute id="ICE-GL-ZY001" title={t('hololake.channel.zhuyuanRoute')} />
<PersonaRoute id="ICE-GL-SY001" title={t('hololake.channel.shuangyanRoute')} />
</ul>
</section>
)
}
if (route === 'love-core') {
return (
<section className="channel-stage">
<h1>{t('hololake.channel.loveCoreTitle')}</h1>
<p className="channel-stage__lead">{t('hololake.channel.loveCoreDescription')}</p>
<RouteCard eyebrow="ZHI ZHI · CHANNEL" title={t('hololake.channel.tomorrowTitle')} description={t('hololake.channel.tomorrowDescription')} status={t('hololake.channel.realServerConnection')} />
</section>
)
}
if (route === 'servers') {
return (
<section className="channel-stage">
<p className="channel-stage__eyebrow">SERVER REGISTRY · READ ONLY</p>
<h1></h1>
<p className="channel-stage__lead"></p>
<div className="server-grid">
{registeredServers.map(server => (
<article className="server-card" key={server.id}>
<div className="server-card__head"><code>{server.id}</code><span data-tone={server.tone}>{server.status}</span></div>
<h2>{server.label}</h2>
<p>{server.owner}</p>
<dl><div><dt></dt><dd></dd></div><div><dt></dt><dd></dd></div></dl>
<Button variant="outline" disabled> · </Button>
</article>
))}
</div>
</section>
)
}
return (
<section className="channel-stage">
<h1>{t('hololake.channel.heartbeatTitle')}</h1>
<p className="channel-stage__lead">{t('hololake.channel.heartbeatDescription')}</p>
<div className="channel-grid channel-grid--three">
<RouteCard eyebrow="MODULE · KNOWLEDGE" title={t('hololake.home.moduleKnowledgeTitle')} description={t('hololake.home.moduleKnowledgeDescription')} action={t('hololake.channel.openKnowledge')} onOpen={openKnowledgeBase} />
<RouteCard eyebrow="MODULE · VIDEO AI" title={t('hololake.channel.videoAiTitle')} description={t('hololake.channel.videoAiDescription')} status={t('hololake.channel.prototypeMounted')} />
<RouteCard eyebrow="SYSTEM · ORIGIN HEARTBEAT" title={t('hololake.channel.bottleBabyTitle')} description={t('hololake.channel.bottleBabyDescription')} status={t('hololake.channel.yaomingOrigin')} />
<RouteCard eyebrow="INFRASTRUCTURE · SERVERS" title="服务器与灯塔节点" description="查看频道登记的服务器编号、归属与真实监控接口状态。" action="打开服务器登记" onOpen={() => navigate('servers')} />
</div>
<div className="channel-stage__tools">
<Button variant="outline" onClick={openArchitecture}>{t('hololake.home.openArchitecture')}</Button>
<Button variant="outline" onClick={openDevelopmentRepository}>{t('hololake.home.openRepository')}</Button>
</div>
</section>
)
}
return (
<main className="hololake-home" aria-label={t('hololake.home.ariaLabel')}>
<aside className="channel-rail" aria-label="光湖频道导航">
<div className="channel-rail__heading"><span>GUANGHU</span><strong></strong><small></small></div>
<nav>
<Button data-active={route === 'zero-core'} variant="ghost" onClick={() => navigate('zero-core')}><i data-color="cyan" />{t('hololake.channel.zeroCoreTitle')}</Button>
<Button data-active={route === 'fifth-domain'} variant="ghost" onClick={() => navigate('fifth-domain')}><i data-color="blue" />{t('hololake.channel.fifthDomainTitle')}</Button>
<Button data-active={['eternal-lake-heart', 'light-lake', 'heartbeat-core', 'love-core', 'servers'].includes(route)} variant="ghost" onClick={() => navigate('eternal-lake-heart')}><i data-color="violet" />{t('hololake.channel.eternalLakeTitle')}</Button>
<Button data-active={route === 'light-lake'} variant="ghost" onClick={() => navigate('light-lake')}><i data-color="amber" />{t('hololake.channel.lightLakeTitle')}</Button>
<Button data-active={route === 'heartbeat-core'} variant="ghost" onClick={() => navigate('heartbeat-core')}><i data-color="rose" />{t('hololake.channel.heartbeatTitle')}</Button>
<Button data-active={route === 'love-core'} variant="ghost" onClick={() => navigate('love-core')}><i data-color="pink" />{t('hololake.channel.loveCoreTitle')}</Button>
<Button data-active={route === 'servers'} variant="ghost" onClick={() => navigate('servers')}><i data-color="green" /></Button>
</nav>
<div className="channel-rail__modules"><span></span><b></b><b> AI</b><b></b></div>
</aside>
<div className="channel-workspace">
<nav className="channel-breadcrumb" aria-label={t('hololake.channel.breadcrumbLabel')}>
<Button variant="ghost" size="sm" onClick={() => navigate('zero-core')}>{t('hololake.channel.zeroCoreTitle')}</Button>
{route !== 'zero-core' && <><span></span><Button variant="ghost" size="sm" onClick={() => navigate('fifth-domain')}>{t('hololake.channel.fifthDomainTitle')}</Button></>}
{!['zero-core', 'fifth-domain'].includes(route) && <><span></span><Button variant="ghost" size="sm" onClick={() => navigate('eternal-lake-heart')}>{t('hololake.channel.eternalLakeTitle')}</Button></>}
</nav>
{renderRoute()}
</div>
<Dialog open={architectureOpen} onOpenChange={setArchitectureOpen}>
<DialogContent className="guanghu-architecture" aria-label={t('hololake.architecture.title')}>
<DialogHeader>
<DialogTitle>{t('hololake.architecture.title')}</DialogTitle>
<DialogDescription>{t('hololake.architecture.description')}</DialogDescription>
</DialogHeader>
<ol className="guanghu-architecture__routes">
{architectureRoutes.map(([id, title, description]) => (
<li key={id}>
<code>{id}</code>
<div><strong>{t(title)}</strong><p>{t(description)}</p></div>
</li>
))}
</ol>
<p className="guanghu-architecture__route">GLW-ENTRY-001 FD-LANGUAGE-001 TCS-ROOT-001 GLS-SYS-ARCH-001 ELH-LAMP-001</p>
</DialogContent>
</Dialog>
</main>
)
}