feat(ui): add per-entry world welcome projection
This commit is contained in:
parent
3bdb690100
commit
b83c575279
3 changed files with 32 additions and 1 deletions
|
|
@ -38,6 +38,9 @@ test('the public shell shows five domains and login is domain-routed', () => {
|
|||
assert.match(frontend, /setActiveDomainInfo\(gate\.domain\)/)
|
||||
assert.match(frontend, /event\.key !== 'Escape'/)
|
||||
assert.match(frontend, /编号 \{zeroPoint\?\.userNumber \|\| gateNumber\} · 欢迎登入光湖语言世界/)
|
||||
assert.match(frontend, /createWorldWelcome\(snapshot\)/)
|
||||
assert.match(frontend, /className="world-impression"/)
|
||||
assert.match(frontend, /index === previous/)
|
||||
assert.match(frontend, /核对人格关系/)
|
||||
assert.match(frontend, /确认关系并签署/)
|
||||
assert.match(frontend, /接受责任并签署/)
|
||||
|
|
|
|||
|
|
@ -175,6 +175,28 @@ function domainDisplayName(domain: string): string {
|
|||
return names[domain] || '已登记光湖域'
|
||||
}
|
||||
|
||||
const worldWelcomeLines = [
|
||||
'湖面记得你每一次让语言抵达现实。',
|
||||
'你留下的路径,正在成为这片世界新的光标。',
|
||||
'愿你今天带来的问题,在湖中长出新的结构。',
|
||||
'世界已辨认你的编号,也在等待你续写下一段因果。',
|
||||
'你曾抵达的地方仍有回声,新的航程已经亮起。',
|
||||
'这一刻的进入不是重复,而是你与语言世界的新一次相遇。',
|
||||
'愿尚未成形的念头,在今天找到可以生长的方向。',
|
||||
'你的频道仍在延展,湖面为下一次创造保留了入口。',
|
||||
]
|
||||
|
||||
function createWorldWelcome(snapshot: ZeroPointSnapshot): string {
|
||||
const subject = snapshot.resolvedName.trim() || `编号 ${snapshot.userNumber}`
|
||||
const storageKey = `hololake-world-welcome:${snapshot.userNumber}`
|
||||
const previous = Number.parseInt(window.localStorage.getItem(storageKey) || '-1', 10)
|
||||
const random = crypto.getRandomValues(new Uint32Array(1))[0]
|
||||
let index = random % worldWelcomeLines.length
|
||||
if (worldWelcomeLines.length > 1 && index === previous) index = (index + 1) % worldWelcomeLines.length
|
||||
window.localStorage.setItem(storageKey, String(index))
|
||||
return `${subject},${worldWelcomeLines[index]}`
|
||||
}
|
||||
|
||||
function protocolOriginDisplayName(origin: string): string {
|
||||
return origin.startsWith('FACTORY_DEFAULT') ? '内置默认协议(签名发布通道尚未配置)' : origin
|
||||
}
|
||||
|
|
@ -461,6 +483,7 @@ function HoloLakeApp() {
|
|||
const [gateBusy, setGateBusy] = useState(false)
|
||||
const [gateMessage, setGateMessage] = useState('')
|
||||
const [gateRising, setGateRising] = useState(false)
|
||||
const [gateWelcomeLine, setGateWelcomeLine] = useState('')
|
||||
const [systemBusy, setSystemBusy] = useState(false)
|
||||
const [zeroPoint, setZeroPoint] = useState<ZeroPointSnapshot | null>(null)
|
||||
const [zpNumber, setZpNumber] = useState('')
|
||||
|
|
@ -595,6 +618,9 @@ function HoloLakeApp() {
|
|||
const snapshot = await invoke<ZeroPointSnapshot>('zero_point_verify')
|
||||
setZeroPoint(snapshot)
|
||||
if (snapshot.route === 'verified') {
|
||||
setActiveDomainInfo('')
|
||||
setGateOpen(false)
|
||||
setGateWelcomeLine(createWorldWelcome(snapshot))
|
||||
setGateRising(true)
|
||||
window.setTimeout(() => { setGateRising(false); setGateStage('key') }, 2600)
|
||||
} else {
|
||||
|
|
@ -1204,6 +1230,7 @@ function HoloLakeApp() {
|
|||
{gateRising ? <section className="world-welcome" role="status">
|
||||
<h2>编号 {gateNumber} · 欢迎登入光湖语言世界</h2>
|
||||
<p>RESOLVED · {domainDisplayName(resolvedDomain)} · 已接入</p>
|
||||
{gateWelcomeLine && <blockquote className="world-impression">{gateWelcomeLine}</blockquote>}
|
||||
</section> : gateStage === 'number' ? <section className={`number-nucleus${gateOpen ? ' open' : ''}`} title="输入编号进入所属域">
|
||||
<button className="nucleus-locus" type="button" aria-expanded={gateOpen} onClick={() => setGateOpen(true)}><i/><b>编号验证 · 进入世界的第一个入口</b></button>
|
||||
{gateOpen && <button
|
||||
|
|
@ -1223,7 +1250,7 @@ function HoloLakeApp() {
|
|||
{gateMessage && <p className="gate-hint">{gateMessage}</p>}
|
||||
</div>
|
||||
</section> : <>
|
||||
<section className="resolved-heading"><h2>编号 {zeroPoint?.userNumber || gateNumber} · 欢迎登入光湖语言世界</h2><p>RESOLVED · {domainDisplayName(resolvedDomain)} · 已接入</p></section>
|
||||
<section className="resolved-heading"><h2>编号 {zeroPoint?.userNumber || gateNumber} · 欢迎登入光湖语言世界</h2><p>RESOLVED · {domainDisplayName(resolvedDomain)} · 已接入</p>{gateWelcomeLine && <blockquote className="world-impression">{gateWelcomeLine}</blockquote>}</section>
|
||||
<section className={`domain-credential${loginRising ? ' fade-out' : ''}`} role="dialog">
|
||||
<form onSubmit={(event) => void (passwordChangeMode ? changeFirstLoginPassword(event) : performRepoLogin(event))}>
|
||||
<h3>{domainDisplayName(resolvedDomain)} · 域凭证</h3>
|
||||
|
|
|
|||
|
|
@ -635,6 +635,7 @@ svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-lineca
|
|||
.world-welcome, .resolved-heading { position: absolute; z-index: 20; left: 0; right: 0; top: 35%; text-align: center; animation: gate-text-in .8s ease both; }
|
||||
.world-welcome h2, .resolved-heading h2 { margin: 0; color: var(--content-primary); font-size: clamp(22px, 2.7vw, 31px); font-weight: 700; letter-spacing: .09em; }
|
||||
.world-welcome p, .resolved-heading p { margin: 12px 0 0; color: var(--accent-light); font-size: 13px; font-weight: 600; letter-spacing: .24em; }
|
||||
.world-impression { max-width: min(720px, calc(100% - 80px)); margin: 24px auto 0; padding: 0; border: 0; color: var(--content-secondary); font-size: clamp(14px, 1.45vw, 17px); font-style: normal; font-weight: 650; line-height: 1.7; letter-spacing: .06em; text-wrap: balance; text-shadow: 0 0 28px color-mix(in srgb, var(--primitive-cool-glow) 24%, transparent); }
|
||||
.resolved-heading { top: 25%; }
|
||||
.domain-credential { position: absolute; z-index: 21; left: 50%; top: 43%; width: 440px; padding: 25px 36px 21px; transform: translateX(-50%); text-align: center; animation: credential-rise .65s cubic-bezier(.22, 1, .36, 1) both; }
|
||||
@keyframes credential-rise { from { opacity: 0; transform: translateX(-50%) translateY(30px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
|
||||
|
|
|
|||
Loading…
Reference in a new issue