hololake-platform/src/components/HoloLakeHome.tsx

236 lines
13 KiB
TypeScript
Raw Normal View History

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'
2026-07-13 23:33:23 +08:00
type HoloLakeHomeProps = {
locale: AppLocale
2026-07-13 23:33:23 +08:00
onEnterKnowledgeBase: () => void
}
2026-07-18 18:25:32 +08:00
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
}
2026-07-13 23:33:23 +08:00
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>
}
2026-07-18 18:25:32 +08:00
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>
)
}
2026-07-13 23:33:23 +08:00
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>
)
}
2026-07-13 23:33:23 +08:00
2026-07-18 18:25:32 +08:00
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')} />
2026-07-18 18:25:32 +08:00
<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>
2026-07-13 23:33:23 +08:00
</div>
</section>
)
}
return (
<main className="hololake-home" aria-label={t('hololake.home.ariaLabel')}>
2026-07-18 18:25:32 +08:00
<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>
2026-07-13 23:33:23 +08:00
</main>
)
}