mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-30 04:40:18 +08:00
替换原卡片网格为「左上 OpenClaw(石墨黑)vs 右下 Hermes(象牙白)」对角线全屏设计。
启动屏 / 引擎切换时给用户一个有冲击力的「选择时刻」。
## 核心设计
- position: fixed 跳出 #content 范围,覆盖整个 viewport(含 sidebar)
- 双三角形 clip-path: polygon (0 0, 0 100%, 100% 0) / (100% 0, 100% 100%, 0 100%)
- 内容用 absolute 定位到三角形质心(左上 11%/6.5% / 右下 11%/6.5%),永不重叠
- 微妙的 60px 网格纹 + 角落极光(紫蓝 / 橙金)+ 极细中线分割
- clamp(80px, 13vw, 200px) 巨字标题 + 序号 + Logo + tagline + 特性列表 + CTA
## 交互
- hover 联动:用 [data-hover] attribute 替代 :has(),兼容旧 WebKit
- 鼠标悬停一侧 → 该侧亮起 + 内容平移 + CTA 反白;另一侧变暗 + 内容模糊缩小
- 点击三角形 → 三角形 clip-path 扩满(0.8s)→ 中心圆扩散(0.9s)→ 进入主页
- reveal 节点 attach 到 body,跨路由切换存活,新页面渲染后再淡出
## Both / Later 处理
- 两个次级选项保留,做成底部居中的玻璃 pill 链接(不抢戏)
- 不走对角线扩散动画,点击后直接 applyEngineSelection + navigate
## 兼容性
- prefers-reduced-motion: reduce → 关闭所有动画
- 移动端响应式:< 760px 调整字号 / 边距 / 角标
- 用 Vite define 注入的 __APP_VERSION__ 显示版本号(与 main.js / sidebar.js 一致)
## i18n
- engine.choiceTopBanner / choiceCtaEnter
- choiceOpenclaw{Tagline,Feat1,Feat2,Feat3,Category}
- choiceHermes{Tagline,Feat1,Feat2,Feat3,Category}
- choiceSecondary{Both,Later}
- 三语完整(zh-CN / en / zh-TW)
## 抽卡 prototype
保留 docs/engine-select-mockups/ 下的 V2 4 张设计 + 索引页(v2-monolith.html
即本次接入的最终版本)。
340 lines
9.9 KiB
HTML
340 lines
9.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Mockup C — 玻璃拟态 + 粒子(沉浸高级感)</title>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box }
|
||
html, body { height: 100%; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif }
|
||
|
||
body {
|
||
background: #0a0d1a;
|
||
}
|
||
|
||
.stage { position: fixed; inset: 0; overflow: hidden }
|
||
|
||
/* 动态背景层:色块缓慢移动 */
|
||
.bg-aurora {
|
||
position: absolute;
|
||
inset: -50%;
|
||
background:
|
||
radial-gradient(circle at 20% 30%, rgba(140, 100, 255, 0.4) 0%, transparent 30%),
|
||
radial-gradient(circle at 80% 70%, rgba(255, 140, 60, 0.4) 0%, transparent 30%),
|
||
radial-gradient(circle at 50% 50%, rgba(100, 180, 255, 0.2) 0%, transparent 50%);
|
||
filter: blur(80px);
|
||
animation: drift 20s ease-in-out infinite alternate;
|
||
}
|
||
@keyframes drift {
|
||
0% { transform: translate(0, 0) rotate(0deg) }
|
||
100% { transform: translate(-10%, 10%) rotate(8deg) }
|
||
}
|
||
|
||
/* 粒子层 */
|
||
.particles {
|
||
position: absolute;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
}
|
||
.particle {
|
||
position: absolute;
|
||
width: 3px;
|
||
height: 3px;
|
||
border-radius: 50%;
|
||
background: #fff;
|
||
opacity: 0;
|
||
animation: float 6s ease-in-out infinite;
|
||
}
|
||
@keyframes float {
|
||
0%, 100% { opacity: 0; transform: translateY(0) scale(0.5) }
|
||
50% { opacity: 0.8; transform: translateY(-30px) scale(1) }
|
||
}
|
||
|
||
/* 三角形 panel — 玻璃拟态 */
|
||
.panel {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
transition: backdrop-filter 0.5s ease;
|
||
}
|
||
.panel-openclaw {
|
||
clip-path: polygon(0 0, 0 100%, 100% 0);
|
||
background: rgba(120, 100, 200, 0.08);
|
||
backdrop-filter: blur(20px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(20px) saturate(1.4);
|
||
}
|
||
.panel-hermes {
|
||
clip-path: polygon(100% 100%, 0 100%, 100% 0);
|
||
background: rgba(255, 140, 80, 0.08);
|
||
backdrop-filter: blur(20px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(20px) saturate(1.4);
|
||
}
|
||
|
||
/* 玻璃边缘高光(细线) */
|
||
.panel::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(45deg, transparent 49.7%, rgba(255, 255, 255, 0.5) 49.9%, rgba(255, 255, 255, 0.9) 50%, rgba(255, 255, 255, 0.5) 50.1%, transparent 50.3%);
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 内容定位 */
|
||
.panel-inner {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 24px;
|
||
text-align: center;
|
||
color: #fff;
|
||
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1), letter-spacing 0.6s ease;
|
||
z-index: 2;
|
||
}
|
||
.panel-openclaw .panel-inner { margin-top: -100px; margin-left: -160px }
|
||
.panel-hermes .panel-inner { margin-bottom: -100px; margin-right: -160px }
|
||
|
||
/* hover:内容浮起 + 字距张开 */
|
||
.panel:hover { backdrop-filter: blur(25px) saturate(1.8) brightness(1.1) }
|
||
.panel:hover .panel-inner { transform: scale(1.05) translateY(-4px) }
|
||
.panel:hover .title { letter-spacing: 0em }
|
||
.panel:hover .glass-card { box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4), inset 0 0 0 1px rgba(255, 255, 255, 0.3) }
|
||
|
||
/* 玻璃卡片 — logo 容器 */
|
||
.glass-card {
|
||
width: 110px;
|
||
height: 110px;
|
||
display: grid;
|
||
place-items: center;
|
||
border-radius: 24px;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
backdrop-filter: blur(20px);
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(255, 255, 255, 0.18);
|
||
transition: box-shadow 0.5s ease, transform 0.5s ease;
|
||
}
|
||
.panel:hover .glass-card { transform: rotate(-4deg) scale(1.05) }
|
||
|
||
.glass-card svg { width: 56px; height: 56px; stroke: #fff; fill: none; stroke-width: 1.5 }
|
||
|
||
.label {
|
||
font-size: 11px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.3em;
|
||
opacity: 0.7;
|
||
font-weight: 300;
|
||
}
|
||
|
||
.title {
|
||
font-size: 60px;
|
||
font-weight: 200;
|
||
letter-spacing: -0.02em;
|
||
line-height: 1;
|
||
background: linear-gradient(180deg, #fff 0%, rgba(255, 255, 255, 0.7) 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
transition: letter-spacing 0.6s ease;
|
||
}
|
||
|
||
.subtitle {
|
||
font-size: 13px;
|
||
opacity: 0.8;
|
||
max-width: 280px;
|
||
line-height: 1.7;
|
||
font-weight: 300;
|
||
}
|
||
|
||
.features {
|
||
display: flex;
|
||
gap: 14px;
|
||
margin-top: 4px;
|
||
}
|
||
.feature-pill {
|
||
font-size: 10px;
|
||
padding: 4px 10px;
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
border-radius: 12px;
|
||
backdrop-filter: blur(10px);
|
||
background: rgba(255, 255, 255, 0.05);
|
||
letter-spacing: 0.05em;
|
||
}
|
||
|
||
/* 中央分割线提示 */
|
||
.divider-hint {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%) rotate(-45deg);
|
||
color: rgba(255, 255, 255, 0.4);
|
||
font-size: 10px;
|
||
letter-spacing: 0.4em;
|
||
pointer-events: none;
|
||
z-index: 10;
|
||
text-transform: uppercase;
|
||
font-weight: 300;
|
||
}
|
||
|
||
/* —— 选中展开动画 —— */
|
||
.panel.expanding { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); z-index: 5 }
|
||
.panel.expanding::before { opacity: 0 }
|
||
.panel { transition: clip-path 0.8s cubic-bezier(0.7, 0, 0.3, 1), backdrop-filter 0.5s ease }
|
||
|
||
/* 反向 reveal: 中心圆向外扩散 */
|
||
.reveal {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
width: 0;
|
||
height: 0;
|
||
border-radius: 50%;
|
||
transform: translate(-50%, -50%);
|
||
z-index: 20;
|
||
pointer-events: none;
|
||
transition: width 0.9s cubic-bezier(0.65, 0, 0.35, 1), height 0.9s cubic-bezier(0.65, 0, 0.35, 1);
|
||
}
|
||
.reveal.active { width: 250vmax; height: 250vmax }
|
||
|
||
.home-mock {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 30;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
gap: 20px;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 0.6s ease;
|
||
}
|
||
.home-mock.show { opacity: 1; pointer-events: auto }
|
||
.home-card {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
backdrop-filter: blur(30px);
|
||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||
border-radius: 24px;
|
||
padding: 40px 60px;
|
||
color: #fff;
|
||
text-align: center;
|
||
box-shadow: 0 20px 80px rgba(0, 0, 0, 0.5);
|
||
}
|
||
.home-card .ht { font-size: 28px; font-weight: 200; margin-bottom: 8px }
|
||
.home-card .hs { font-size: 12px; opacity: 0.6; letter-spacing: 0.2em; text-transform: uppercase }
|
||
|
||
.reset-hint {
|
||
position: fixed;
|
||
bottom: 24px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
color: rgba(255, 255, 255, 0.5);
|
||
font-size: 12px;
|
||
z-index: 40;
|
||
letter-spacing: 0.08em;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="stage" id="stage">
|
||
<div class="bg-aurora"></div>
|
||
<div class="particles" id="particles"></div>
|
||
|
||
<div class="panel panel-openclaw" data-engine="openclaw">
|
||
<div class="panel-inner">
|
||
<div class="label">通用助理</div>
|
||
<div class="glass-card">
|
||
<svg viewBox="0 0 24 24">
|
||
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
||
<path d="M2 17l10 5 10-5"/>
|
||
<path d="M2 12l10 5 10-5"/>
|
||
</svg>
|
||
</div>
|
||
<div class="title">OpenClaw</div>
|
||
<div class="subtitle">模型管理 · 渠道集成 · 记忆系统 · 智能体编排</div>
|
||
<div class="features">
|
||
<div class="feature-pill">Models</div>
|
||
<div class="feature-pill">Channels</div>
|
||
<div class="feature-pill">Memory</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="panel panel-hermes" data-engine="hermes">
|
||
<div class="panel-inner">
|
||
<div class="label">Agent 工作流</div>
|
||
<div class="glass-card">
|
||
<svg viewBox="0 0 24 24">
|
||
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
|
||
</svg>
|
||
</div>
|
||
<div class="title">Hermes</div>
|
||
<div class="subtitle">工具调用 · Kanban · Skills · OAuth · Multi Profile</div>
|
||
<div class="features">
|
||
<div class="feature-pill">Tools</div>
|
||
<div class="feature-pill">Skills</div>
|
||
<div class="feature-pill">Profiles</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider-hint">CHOOSE YOUR PATH</div>
|
||
</div>
|
||
|
||
<div class="reveal" id="reveal"></div>
|
||
<div class="home-mock" id="home">
|
||
<div class="home-card">
|
||
<div class="ht" id="home-name"></div>
|
||
<div class="hs">Loading workspace…</div>
|
||
</div>
|
||
</div>
|
||
<div class="reset-hint">点击预览 · 按 R 重置</div>
|
||
|
||
<script>
|
||
// 生成粒子
|
||
const pc = document.getElementById('particles')
|
||
for (let i = 0; i < 40; i++) {
|
||
const p = document.createElement('div')
|
||
p.className = 'particle'
|
||
p.style.left = Math.random() * 100 + '%'
|
||
p.style.top = Math.random() * 100 + '%'
|
||
p.style.animationDelay = (Math.random() * 6) + 's'
|
||
p.style.animationDuration = (4 + Math.random() * 6) + 's'
|
||
pc.appendChild(p)
|
||
}
|
||
|
||
const stage = document.getElementById('stage')
|
||
const reveal = document.getElementById('reveal')
|
||
const home = document.getElementById('home')
|
||
const homeName = document.getElementById('home-name')
|
||
|
||
const colors = {
|
||
openclaw: 'radial-gradient(circle at center, rgba(140, 100, 255, 0.5), #1a1530)',
|
||
hermes: 'radial-gradient(circle at center, rgba(255, 140, 60, 0.5), #2a1a10)',
|
||
}
|
||
|
||
document.querySelectorAll('.panel').forEach(panel => {
|
||
panel.addEventListener('click', () => {
|
||
const engine = panel.dataset.engine
|
||
const other = stage.querySelector(`.panel:not([data-engine="${engine}"])`)
|
||
panel.classList.add('expanding')
|
||
other.style.opacity = '0'
|
||
other.style.transition = 'opacity 0.5s'
|
||
setTimeout(() => {
|
||
reveal.style.background = colors[engine]
|
||
home.style.background = colors[engine]
|
||
homeName.textContent = engine === 'openclaw' ? 'OpenClaw' : 'Hermes'
|
||
reveal.classList.add('active')
|
||
}, 700)
|
||
setTimeout(() => home.classList.add('show'), 1500)
|
||
})
|
||
})
|
||
|
||
document.addEventListener('keydown', (e) => {
|
||
if (e.key.toLowerCase() === 'r') location.reload()
|
||
})
|
||
</script>
|
||
</body>
|
||
</html>
|