facc04aa65
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交 (5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。 一、docs 结构整改(整改 #14) 根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入, 随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录 树并存于 docs/,共 791 文件、双分类体系冲突。 修复动作: - b2 同名异主题文件改名迁移保全 9 个 - C 类 39 个孤立文件按主题正确归类 - A/B1 类 222 个重复文件删除(新结构已有内容副本) - 9 个旧独有空目录删除 - 270 处内部引用按 verified 映射改写 - 整改记录 #14 登记于 04-运维文档/部署运维 结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。 残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。 二、compose 双目录对齐(消除踩坑 A) - docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist 改为 src/frontend-*/dist(h5 / agent / admin / terminal) - docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/ - 效果:本地 docker compose up 不再把根目录 stale dist 挂回, 与线上一致,分叉隐患消除(已 docker compose config 校验通过) 防复发铁律: - 重构须提交;仓库修复须 git stash -u 或先 commit - 新结构须 git add 并提交,避免再次 untracked 复活 - H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
551 lines
23 KiB
HTML
551 lines
23 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>工具栏统一设计 v0.5 - 玻璃拟态 + 立体图标</title>
|
||
<style>
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body {
|
||
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
|
||
background: linear-gradient(135deg, #e0e7ff 0%, #f3e8ff 50%, #fce7f3 100%);
|
||
color: #1a1a1a;
|
||
padding: 32px;
|
||
line-height: 1.5;
|
||
-webkit-font-smoothing: antialiased;
|
||
min-height: 100vh;
|
||
}
|
||
h1 { font-size: 24px; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 8px; color: #1a1a1a; }
|
||
h2 { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; margin: 40px 0 12px; color: #1a1a1a; }
|
||
h3 { font-size: 14px; font-weight: 600; margin: 16px 0 8px; color: #333; }
|
||
.meta { color: #6b7280; font-size: 12.5px; margin-bottom: 24px; }
|
||
|
||
/* === 整体玻璃拟态背景工具栏 === */
|
||
.glass-toolbar {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 6px 8px;
|
||
background: rgba(255, 255, 255, 0.55);
|
||
backdrop-filter: blur(28px) saturate(180%);
|
||
-webkit-backdrop-filter: blur(28px) saturate(180%);
|
||
border: 1px solid rgba(255, 255, 255, 0.7);
|
||
border-radius: 18px;
|
||
box-shadow:
|
||
0 1px 0 rgba(255, 255, 255, 0.9) inset,
|
||
0 -1px 0 rgba(99, 102, 241, 0.08) inset,
|
||
0 2px 4px rgba(99, 102, 241, 0.05),
|
||
0 8px 16px rgba(99, 102, 241, 0.08),
|
||
0 24px 48px rgba(99, 102, 241, 0.05);
|
||
position: relative;
|
||
}
|
||
/* 顶部高光(模拟光照) */
|
||
.glass-toolbar::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: 18px;
|
||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.6) 0%, rgba(255, 255, 255, 0.1) 40%, transparent 60%);
|
||
pointer-events: none;
|
||
}
|
||
.glass-toolbar::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: 18px;
|
||
background: radial-gradient(circle at 20% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 50%),
|
||
radial-gradient(circle at 80% 80%, rgba(236, 72, 153, 0.12) 0%, transparent 50%);
|
||
pointer-events: none;
|
||
z-index: 0;
|
||
}
|
||
.glass-divider {
|
||
width: 1px;
|
||
height: 24px;
|
||
background: linear-gradient(180deg, transparent 0%, rgba(99, 102, 241, 0.2) 50%, transparent 100%);
|
||
margin: 0 4px;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
/* === 玻璃拟态按钮(38px 圆形) === */
|
||
.glass-btn {
|
||
width: 38px;
|
||
height: 38px;
|
||
border: 1px solid rgba(255, 255, 255, 0.6);
|
||
background: rgba(255, 255, 255, 0.5);
|
||
backdrop-filter: blur(20px);
|
||
-webkit-backdrop-filter: blur(20px);
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||
-webkit-tap-highlight-color: transparent;
|
||
position: relative;
|
||
z-index: 2;
|
||
box-shadow:
|
||
0 1px 0 rgba(255, 255, 255, 0.9) inset,
|
||
0 -1px 0 rgba(0, 0, 0, 0.04) inset,
|
||
0 1px 2px rgba(0, 0, 0, 0.04),
|
||
0 2px 4px rgba(0, 0, 0, 0.04);
|
||
}
|
||
.glass-btn:hover {
|
||
background: rgba(255, 255, 255, 0.7);
|
||
transform: translateY(-1px) scale(1.04);
|
||
box-shadow:
|
||
0 1px 0 rgba(255, 255, 255, 1) inset,
|
||
0 -1px 0 rgba(0, 0, 0, 0.04) inset,
|
||
0 2px 4px rgba(0, 0, 0, 0.06),
|
||
0 6px 12px rgba(99, 102, 241, 0.12);
|
||
}
|
||
.glass-btn:active { transform: translateY(0) scale(0.95); }
|
||
.glass-btn svg { width: 20px; height: 20px; }
|
||
|
||
/* === 立体感图标通用(渐变填充 + 高光) === */
|
||
.ico-3d path.face { fill: url(#grad-cool); }
|
||
.ico-3d path.highlight { fill: url(#grad-highlight); opacity: 0.6; }
|
||
.ico-3d path.shadow { fill: url(#grad-shadow); opacity: 0.4; }
|
||
|
||
/* === 客服按钮 6 态(玻璃拟态) === */
|
||
.agent-btn.is-active {
|
||
background: linear-gradient(135deg, rgba(99, 102, 241, 0.85) 0%, rgba(168, 85, 247, 0.85) 50%, rgba(236, 72, 153, 0.85) 100%);
|
||
border-color: rgba(255, 255, 255, 0.4);
|
||
}
|
||
.agent-btn.is-active::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 1px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.3) 0%, transparent 50%);
|
||
pointer-events: none;
|
||
}
|
||
.agent-btn.is-active svg { filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.2)); }
|
||
|
||
.agent-btn.is-disabled { opacity: 0.4; cursor: not-allowed; }
|
||
.agent-btn.is-disabled:hover { transform: none; box-shadow: none; background: rgba(255, 255, 255, 0.5); }
|
||
.agent-btn.is-disabled svg { filter: grayscale(1); }
|
||
|
||
.agent-btn.is-urgent {
|
||
background: linear-gradient(135deg, rgba(239, 68, 68, 0.9) 0%, rgba(220, 38, 38, 0.9) 50%, rgba(185, 28, 28, 0.9) 100%);
|
||
border-color: rgba(255, 255, 255, 0.4);
|
||
animation: agentGlow 1.6s ease-in-out infinite;
|
||
}
|
||
@keyframes agentGlow {
|
||
0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0), 0 1px 0 rgba(255, 255, 255, 0.9) inset, 0 1px 2px rgba(0, 0, 0, 0.04), 0 2px 4px rgba(0, 0, 0, 0.04); }
|
||
50% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0.18), 0 1px 0 rgba(255, 255, 255, 0.9) inset, 0 1px 2px rgba(0, 0, 0, 0.04), 0 2px 4px rgba(0, 0, 0, 0.04); }
|
||
}
|
||
|
||
.agent-btn.is-waiting {
|
||
background: linear-gradient(135deg, rgba(245, 158, 11, 0.9) 0%, rgba(217, 119, 6, 0.9) 50%, rgba(180, 83, 9, 0.9) 100%);
|
||
border-color: rgba(255, 255, 255, 0.4);
|
||
}
|
||
.agent-btn.is-end {
|
||
background: linear-gradient(135deg, rgba(16, 185, 129, 0.9) 0%, rgba(5, 150, 105, 0.9) 50%, rgba(4, 120, 87, 0.9) 100%);
|
||
border-color: rgba(255, 255, 255, 0.4);
|
||
}
|
||
.agent-btn.is-reopen {
|
||
background: linear-gradient(135deg, rgba(59, 130, 246, 0.9) 0%, rgba(37, 99, 235, 0.9) 50%, rgba(29, 78, 216, 0.9) 100%);
|
||
border-color: rgba(255, 255, 255, 0.4);
|
||
}
|
||
|
||
/* === 演示容器 === */
|
||
.demo-block {
|
||
background: rgba(255, 255, 255, 0.6);
|
||
backdrop-filter: blur(20px);
|
||
-webkit-backdrop-filter: blur(20px);
|
||
border: 1px solid rgba(255, 255, 255, 0.7);
|
||
border-radius: 18px;
|
||
padding: 32px;
|
||
margin-bottom: 20px;
|
||
box-shadow:
|
||
0 1px 0 rgba(255, 255, 255, 0.9) inset,
|
||
0 8px 16px rgba(99, 102, 241, 0.06);
|
||
}
|
||
.demo-label { font-size: 11.5px; color: #6b7280; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 14px; font-weight: 500; }
|
||
.demo-stage-bg {
|
||
background: linear-gradient(135deg, #e0e7ff 0%, #f3e8ff 50%, #fce7f3 100%);
|
||
border-radius: 14px;
|
||
padding: 48px 32px;
|
||
min-height: 140px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* === 状态切换 tab === */
|
||
.state-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid rgba(99, 102, 241, 0.12); }
|
||
.state-tab {
|
||
padding: 6px 12px;
|
||
border: 1px solid rgba(99, 102, 241, 0.2);
|
||
background: rgba(255, 255, 255, 0.6);
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-size: 12.5px;
|
||
color: #4b5563;
|
||
transition: all 0.15s;
|
||
font-family: inherit;
|
||
}
|
||
.state-tab:hover { background: rgba(255, 255, 255, 0.8); }
|
||
.state-tab.active { background: linear-gradient(135deg, #6366f1, #8b5cf6); color: #fff; border-color: transparent; }
|
||
|
||
.state-desc { color: #4b5563; font-size: 12.5px; line-height: 1.7; background: rgba(255, 255, 255, 0.5); padding: 12px 14px; border-radius: 10px; border-left: 2px solid #6366f1; margin-top: 12px; backdrop-filter: blur(10px); }
|
||
.state-desc strong { color: #1a1a1a; }
|
||
|
||
/* === 4 按钮并排 === */
|
||
.four-btns {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* === 对比表 === */
|
||
.cmp-table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12.5px; }
|
||
.cmp-table th, .cmp-table td { border: 1px solid rgba(99, 102, 241, 0.15); padding: 8px 10px; text-align: left; }
|
||
.cmp-table th { background: rgba(255, 255, 255, 0.6); font-weight: 600; }
|
||
.yes { color: #059669; }
|
||
.no { color: #dc2626; }
|
||
.partial { color: #d97706; }
|
||
|
||
.note { background: rgba(254, 243, 199, 0.6); border-left: 3px solid #d97706; padding: 12px 16px; border-radius: 4px; font-size: 12.5px; color: #78350f; margin: 16px 0; backdrop-filter: blur(10px); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- 全局 SVG 渐变定义 -->
|
||
<svg width="0" height="0" style="position: absolute;">
|
||
<defs>
|
||
<!-- 通用渐变 -->
|
||
<linearGradient id="grad-cool" x1="0%" y1="0%" x2="100%" y2="100%">
|
||
<stop offset="0%" stop-color="#a5b4fc"/>
|
||
<stop offset="50%" stop-color="#c4b5fd"/>
|
||
<stop offset="100%" stop-color="#f0abfc"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-warm" x1="0%" y1="0%" x2="100%" y2="100%">
|
||
<stop offset="0%" stop-color="#fbbf24"/>
|
||
<stop offset="50%" stop-color="#fb923c"/>
|
||
<stop offset="100%" stop-color="#f87171"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-cool-3d" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#c7d2fe"/>
|
||
<stop offset="50%" stop-color="#a5b4fc"/>
|
||
<stop offset="100%" stop-color="#818cf8"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-document" x1="0%" y1="0%" x2="100%" y2="100%">
|
||
<stop offset="0%" stop-color="#e0e7ff"/>
|
||
<stop offset="100%" stop-color="#c7d2fe"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-microphone" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#a78bfa"/>
|
||
<stop offset="50%" stop-color="#8b5cf6"/>
|
||
<stop offset="100%" stop-color="#7c3aed"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-agent-head" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#fbbf24"/>
|
||
<stop offset="100%" stop-color="#f59e0b"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-agent-head-active" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#fde68a"/>
|
||
<stop offset="100%" stop-color="#fbbf24"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-earphone" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#cbd5e1"/>
|
||
<stop offset="100%" stop-color="#64748b"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-highlight" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="white" stop-opacity="0.95"/>
|
||
<stop offset="100%" stop-color="white" stop-opacity="0"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-urgent" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#fca5a5"/>
|
||
<stop offset="100%" stop-color="#ef4444"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-waiting" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#fcd34d"/>
|
||
<stop offset="100%" stop-color="#f59e0b"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-success" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#6ee7b7"/>
|
||
<stop offset="100%" stop-color="#10b981"/>
|
||
</linearGradient>
|
||
<linearGradient id="grad-reopen" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" stop-color="#93c5fd"/>
|
||
<stop offset="100%" stop-color="#3b82f6"/>
|
||
</linearGradient>
|
||
</defs>
|
||
</svg>
|
||
|
||
<h1>工具栏统一设计 v0.5 — 玻璃拟态 + 立体图标</h1>
|
||
<p class="meta">整体水晶玻璃背景 + 立体感 SVG 图标(渐变填充 + 高光 + 阴影)· 2026-08-04 凌晨</p>
|
||
|
||
<div class="note">
|
||
📌 本版核心改动(对比 v0.4):<br>
|
||
• <strong>整体玻璃拟态背景</strong>:工具栏 = 半透明 + backdrop-filter blur(28px) + 顶部高光 + 多层阴影 + 紫粉径向渐变 — 整个工具栏是一个"水晶玻璃容器"<br>
|
||
• <strong>立体感图标</strong>:不再用简单几何,采用 SVG <strong>渐变填充 + 高光 + 阴影</strong> 表现立体感(类似 iOS 立体图标)<br>
|
||
• <strong>多层 box-shadow</strong>:深 + 浅 + 内嵌高光,模拟真实光照<br>
|
||
• <strong>backdrop-filter</strong>:背景模糊,所有按钮"浮"在玻璃上
|
||
</div>
|
||
|
||
<h2>🎨 整体水晶玻璃工具栏</h2>
|
||
<div class="demo-block">
|
||
<div class="demo-label">InputBar 工具栏完整效果(4 按钮浮在水晶玻璃上)</div>
|
||
<div class="demo-stage-bg">
|
||
<div class="glass-toolbar">
|
||
<!-- 表情(立体感) -->
|
||
<button class="glass-btn" title="表情">
|
||
<svg class="ico-3d" viewBox="0 0 22 22" fill="none">
|
||
<!-- 脸(渐变填充) -->
|
||
<circle cx="11" cy="11" r="8" fill="url(#grad-cool-3d)"/>
|
||
<!-- 顶部高光 -->
|
||
<ellipse cx="11" cy="6" rx="5" ry="2" fill="url(#grad-highlight)"/>
|
||
<!-- 眼睛 -->
|
||
<ellipse cx="8" cy="10" rx="1.2" ry="1.4" fill="#1e1b4b"/>
|
||
<ellipse cx="14" cy="10" rx="1.2" ry="1.4" fill="#1e1b4b"/>
|
||
<ellipse cx="8.4" cy="9.5" rx="0.4" ry="0.4" fill="white"/>
|
||
<ellipse cx="14.4" cy="9.5" rx="0.4" ry="0.4" fill="white"/>
|
||
<!-- 嘴(弧形) -->
|
||
<path d="M7.5 13.5 Q11 16 14.5 13.5" fill="none" stroke="#1e1b4b" stroke-width="1.4" stroke-linecap="round"/>
|
||
</svg>
|
||
</button>
|
||
<!-- 文件(立体感) -->
|
||
<button class="glass-btn" title="文件">
|
||
<svg class="ico-3d" viewBox="0 0 22 22" fill="none">
|
||
<!-- 文档主体(渐变填充) -->
|
||
<path d="M4 2 L13 2 L19 8 L19 19 L4 19 Z" fill="url(#grad-document)" stroke="#818cf8" stroke-width="0.8" stroke-linejoin="round"/>
|
||
<!-- 折角(渐变) -->
|
||
<path d="M13 2 L13 8 L19 8" fill="url(#grad-cool-3d)" stroke="#818cf8" stroke-width="0.8" stroke-linejoin="round"/>
|
||
<!-- 顶部高光 -->
|
||
<path d="M5 3 L12 3" stroke="white" stroke-width="0.8" stroke-linecap="round" opacity="0.8"/>
|
||
<!-- 文字行 -->
|
||
<line x1="6" y1="11" x2="16" y2="11" stroke="#6366f1" stroke-width="0.8" opacity="0.6"/>
|
||
<line x1="6" y1="14" x2="14" y2="14" stroke="#6366f1" stroke-width="0.8" opacity="0.6"/>
|
||
<line x1="6" y1="17" x2="12" y2="17" stroke="#6366f1" stroke-width="0.8" opacity="0.6"/>
|
||
</svg>
|
||
</button>
|
||
<div class="glass-divider"></div>
|
||
<!-- 语音(立体感) -->
|
||
<button class="glass-btn" title="语音">
|
||
<svg class="ico-3d" viewBox="0 0 22 22" fill="none">
|
||
<!-- 麦克风主体(渐变 + 圆柱) -->
|
||
<rect x="7" y="2" width="8" height="12" rx="4" fill="url(#grad-microphone)"/>
|
||
<!-- 顶部高光 -->
|
||
<rect x="8" y="3" width="2" height="9" rx="1" fill="white" opacity="0.5"/>
|
||
<!-- 麦克风底座弧线 -->
|
||
<path d="M3 11 Q3 17 11 17 Q19 17 19 11" fill="none" stroke="url(#grad-microphone)" stroke-width="2" stroke-linecap="round"/>
|
||
<!-- 支柱 -->
|
||
<line x1="11" y1="17" x2="11" y2="20" stroke="#7c3aed" stroke-width="2" stroke-linecap="round"/>
|
||
<line x1="8" y1="20" x2="14" y2="20" stroke="#7c3aed" stroke-width="2" stroke-linecap="round"/>
|
||
</svg>
|
||
</button>
|
||
<!-- 客服(立体感) -->
|
||
<button class="glass-btn agent-btn is-active" title="客服在线 · 点击呼叫">
|
||
<svg class="ico-3d" viewBox="0 0 22 22" fill="none">
|
||
<!-- 头部(渐变 + 高光) -->
|
||
<circle cx="11" cy="9" r="5" fill="url(#grad-agent-head)"/>
|
||
<ellipse cx="11" cy="6.5" rx="3.5" ry="1.5" fill="white" opacity="0.5"/>
|
||
<!-- 耳罩(渐变 + 立体) -->
|
||
<ellipse cx="4" cy="9" rx="1.8" ry="2.5" fill="url(#grad-earphone)"/>
|
||
<ellipse cx="18" cy="9" rx="1.8" ry="2.5" fill="url(#grad-earphone)"/>
|
||
<!-- 耳罩内侧(深色) -->
|
||
<ellipse cx="4" cy="9" rx="1" ry="1.5" fill="#475569"/>
|
||
<ellipse cx="18" cy="9" rx="1" ry="1.5" fill="#475569"/>
|
||
<!-- 眼睛 -->
|
||
<circle cx="9" cy="9" r="0.9" fill="#1e1b4b"/>
|
||
<circle cx="13" cy="9" r="0.9" fill="#1e1b4b"/>
|
||
<circle cx="9.3" cy="8.7" r="0.3" fill="white"/>
|
||
<circle cx="13.3" cy="8.7" r="0.3" fill="white"/>
|
||
<!-- 微笑嘴 -->
|
||
<path d="M9 11.5 Q11 13 13 11.5" fill="none" stroke="#1e1b4b" stroke-width="1.2" stroke-linecap="round"/>
|
||
<!-- 麦克风臂(连接耳罩的小线) -->
|
||
<path d="M4 9 Q4 14 11 14" fill="none" stroke="url(#grad-earphone)" stroke-width="1.2" opacity="0.6"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<p style="font-size: 12px; color: #6b7280; margin-top: 12px;">
|
||
视觉特点: 半透明紫粉渐变 + 顶部高光 + 多层阴影 + 4 按钮浮在上面 + 立体感 SVG 图标(渐变 + 高光)
|
||
</p>
|
||
</div>
|
||
|
||
<h2>🎬 客服按钮 6 态切换</h2>
|
||
<div class="demo-block">
|
||
<div class="state-tabs">
|
||
<button class="state-tab active" data-state="active">active</button>
|
||
<button class="state-tab" data-state="disabled">disabled</button>
|
||
<button class="state-tab" data-state="urgent">urgent</button>
|
||
<button class="state-tab" data-state="waiting">waiting</button>
|
||
<button class="state-tab" data-state="end">end</button>
|
||
<button class="state-tab" data-state="reopen">reopen</button>
|
||
</div>
|
||
|
||
<div class="demo-stage-bg">
|
||
<div class="glass-toolbar">
|
||
<div id="stage" style="display: flex; align-items: center; justify-content: center;"></div>
|
||
</div>
|
||
</div>
|
||
<div class="state-desc" id="desc"></div>
|
||
</div>
|
||
|
||
<h2>📊 与之前版本对比(v0.5 关键升级)</h2>
|
||
<table class="cmp-table">
|
||
<thead>
|
||
<tr>
|
||
<th>维度</th>
|
||
<th>v0.1 方块</th>
|
||
<th>v0.2 灵动岛</th>
|
||
<th>v0.3 克制</th>
|
||
<th>v0.4 圆形渐变</th>
|
||
<th>v0.5 玻璃拟态 ⭐</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>整体背景</td>
|
||
<td class="no">无(纯白)</td>
|
||
<td class="no">无</td>
|
||
<td class="no">无</td>
|
||
<td class="partial">白底 + 阴影</td>
|
||
<td class="yes"><strong>水晶玻璃 + 紫粉径向渐变</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>图标质感</td>
|
||
<td class="no">emoji</td>
|
||
<td class="no">夸张卡通</td>
|
||
<td class="partial">简单几何</td>
|
||
<td class="partial">抽象 + 客服图</td>
|
||
<td class="yes"><strong>渐变填充 + 高光 + 阴影(立体感)</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>backdrop-filter</td>
|
||
<td class="no">×</td>
|
||
<td class="no">×</td>
|
||
<td class="no">×</td>
|
||
<td class="no">×</td>
|
||
<td class="yes"><strong>✓ blur(28px) saturate(180%)</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>多层阴影</td>
|
||
<td class="no">1 层</td>
|
||
<td class="no">1 层</td>
|
||
<td class="no">1 层</td>
|
||
<td class="partial">2 层</td>
|
||
<td class="yes"><strong>3 层(深 + 浅 + 内嵌高光)</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>按钮形态</td>
|
||
<td>方块</td>
|
||
<td>方块</td>
|
||
<td>方块</td>
|
||
<td>圆形</td>
|
||
<td class="yes"><strong>圆形 + 玻璃质感</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>高级感</td>
|
||
<td>★★★</td>
|
||
<td>★</td>
|
||
<td>★★★★</td>
|
||
<td>★★★★★</td>
|
||
<td class="yes"><strong>★★★★★+(顶级 SaaS 工具级)</strong></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2>❓ 待你拍板</h2>
|
||
<ol style="margin-left: 20px; line-height: 1.8;">
|
||
<li><strong>整体玻璃背景</strong>符合你期望吗?(水晶质感 + 紫粉渐变 + 顶部高光)</li>
|
||
<li><strong>立体感图标</strong>的"质变效果"如何?如仍需更大优化(比如复杂 3D 渲染、动态光影),需要请设计师重画</li>
|
||
<li><strong>工具栏大小</strong>:当前 38px 按钮,需要更大(40px)或更小(36px)吗?</li>
|
||
<li><strong>渐变色调</strong>:紫粉(当前)还是其他?(蓝绿、纯蓝、暖橙、对比色?)</li>
|
||
</ol>
|
||
|
||
<p style="margin-top: 32px; padding-top: 16px; border-top: 1px solid rgba(99, 102, 241, 0.15); color: #6b7280; font-size: 11.5px;">
|
||
v0.5 玻璃拟态 · 2026-08-04 · Duckula 主理人 · 等待用户拍板
|
||
</p>
|
||
|
||
<script>
|
||
const states = {
|
||
active: {
|
||
cls: 'is-active',
|
||
desc: '<strong>active</strong>: 紫粉渐变(蓝→紫→粉)+ 顶部高光 + 立体感图标 — 默认"客服在线"。玻璃质感最强,像 iOS 控制中心按钮'
|
||
},
|
||
disabled: {
|
||
cls: 'is-disabled',
|
||
desc: '<strong>disabled</strong>: 半透明白 + 灰度滤镜(grayscale)+ opacity 0.4 — 表达"不可用",保留玻璃质感但无彩色'
|
||
},
|
||
urgent: {
|
||
cls: 'is-urgent',
|
||
desc: '<strong>urgent</strong>: 红色渐变 + 1.6s 发光呼吸(box-shadow 扩散 6px 红色光晕) — 表达"紧急,需关注"'
|
||
},
|
||
waiting: {
|
||
cls: 'is-waiting',
|
||
desc: '<strong>waiting</strong>: 橙黄渐变(浅黄→深橙)+ 立体感图标 — 表达"排队中"'
|
||
},
|
||
end: {
|
||
cls: 'is-end',
|
||
desc: '<strong>end</strong>: 绿色渐变(浅绿→深绿)+ 立体感图标 — 表达"已接入坐席,通话中"'
|
||
},
|
||
reopen: {
|
||
cls: 'is-reopen',
|
||
desc: '<strong>reopen</strong>: 蓝色渐变(浅蓝→深蓝)+ 立体感图标 — 表达"会话已关闭,可重新打开"'
|
||
}
|
||
};
|
||
|
||
const svgAgent = `<svg class="ico-3d" viewBox="0 0 22 22" fill="none">
|
||
<circle cx="11" cy="9" r="5" fill="url(#grad-agent-head)"/>
|
||
<ellipse cx="11" cy="6.5" rx="3.5" ry="1.5" fill="white" opacity="0.5"/>
|
||
<ellipse cx="4" cy="9" rx="1.8" ry="2.5" fill="url(#grad-earphone)"/>
|
||
<ellipse cx="18" cy="9" rx="1.8" ry="2.5" fill="url(#grad-earphone)"/>
|
||
<ellipse cx="4" cy="9" rx="1" ry="1.5" fill="#475569"/>
|
||
<ellipse cx="18" cy="9" rx="1" ry="1.5" fill="#475569"/>
|
||
<circle cx="9" cy="9" r="0.9" fill="#1e1b4b"/>
|
||
<circle cx="13" cy="9" r="0.9" fill="#1e1b4b"/>
|
||
<circle cx="9.3" cy="8.7" r="0.3" fill="white"/>
|
||
<circle cx="13.3" cy="8.7" r="0.3" fill="white"/>
|
||
<path d="M9 11.5 Q11 13 13 11.5" fill="none" stroke="#1e1b4b" stroke-width="1.2" stroke-linecap="round"/>
|
||
<path d="M4 9 Q4 14 11 14" fill="none" stroke="url(#grad-earphone)" stroke-width="1.2" opacity="0.6"/>
|
||
</svg>`;
|
||
|
||
const stage = document.getElementById('stage');
|
||
const descEl = document.getElementById('desc');
|
||
const tabs = document.querySelectorAll('.state-tab');
|
||
|
||
function render(state) {
|
||
const s = states[state];
|
||
const gradMap = {
|
||
active: 'url(#grad-agent-head)',
|
||
urgent: 'url(#grad-urgent)',
|
||
waiting: 'url(#grad-waiting)',
|
||
end: 'url(#grad-success)',
|
||
reopen: 'url(#grad-reopen)',
|
||
};
|
||
const headGrad = state === 'active' ? 'url(#grad-agent-head-active)' : (gradMap[state] || 'url(#grad-agent-head)');
|
||
const svg = `<svg class="ico-3d" viewBox="0 0 22 22" fill="none">
|
||
<circle cx="11" cy="9" r="5" fill="${headGrad}"/>
|
||
<ellipse cx="11" cy="6.5" rx="3.5" ry="1.5" fill="white" opacity="0.5"/>
|
||
<ellipse cx="4" cy="9" rx="1.8" ry="2.5" fill="url(#grad-earphone)"/>
|
||
<ellipse cx="18" cy="9" rx="1.8" ry="2.5" fill="url(#grad-earphone)"/>
|
||
<ellipse cx="4" cy="9" rx="1" ry="1.5" fill="#475569"/>
|
||
<ellipse cx="18" cy="9" rx="1" ry="1.5" fill="#475569"/>
|
||
<circle cx="9" cy="9" r="0.9" fill="#1e1b4b"/>
|
||
<circle cx="13" cy="9" r="0.9" fill="#1e1b4b"/>
|
||
<circle cx="9.3" cy="8.7" r="0.3" fill="white"/>
|
||
<circle cx="13.3" cy="8.7" r="0.3" fill="white"/>
|
||
<path d="M9 11.5 Q11 13 13 11.5" fill="none" stroke="#1e1b4b" stroke-width="1.2" stroke-linecap="round"/>
|
||
</svg>`;
|
||
stage.innerHTML = `<button class="glass-btn agent-btn ${s.cls}" style="width: 60px; height: 60px;">${svg}</button>`;
|
||
descEl.innerHTML = s.desc;
|
||
}
|
||
|
||
tabs.forEach(tab => {
|
||
tab.addEventListener('click', () => {
|
||
tabs.forEach(t => t.classList.remove('active'));
|
||
tab.classList.add('active');
|
||
render(tab.dataset.state);
|
||
});
|
||
});
|
||
|
||
render('active');
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|