chore(demo): add loader and minimal-mode preview pages

This commit is contained in:
JOJO 2026-04-04 19:47:36 +08:00
parent dfc763c7c5
commit 249eb663bb
10 changed files with 3106 additions and 0 deletions

View File

@ -0,0 +1,708 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>加载动画预览</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #1a1a1a;
color: #e0e0e0;
padding: 40px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 40px;
color: #fff;
}
.loader-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 40px;
margin-bottom: 40px;
}
.loader-item {
background: #2a2a2a;
border-radius: 12px;
padding: 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.loader-title {
font-size: 14px;
color: #999;
text-align: center;
}
.loader-wrapper {
width: 100%;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
/* 统一的颜色变量 */
:root {
--loader-color: #888;
}
/* ========== 0. 方格网格动画 (已有) ========== */
@keyframes loader_5191 {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.loader-0 {
position: relative;
width: 16px;
height: 16px;
}
.loader-0-square {
background: var(--loader-color);
width: 3px;
height: 3px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -1.5px;
margin-left: -1.5px;
border-radius: 0.5px;
}
.loader-0 #sq1 {
margin-top: -7.5px;
margin-left: -7.5px;
animation: loader_5191 675ms ease-in-out 0s infinite alternate;
}
.loader-0 #sq2 {
margin-top: -7.5px;
animation: loader_5191 675ms ease-in-out 75ms infinite alternate;
}
.loader-0 #sq3 {
margin-top: -7.5px;
margin-left: 4.5px;
animation: loader_5191 675ms ease-in-out 150ms infinite;
}
.loader-0 #sq4 {
margin-left: -7.5px;
animation: loader_5191 675ms ease-in-out 225ms infinite;
}
.loader-0 #sq5 {
animation: loader_5191 675ms ease-in-out 300ms infinite;
}
.loader-0 #sq6 {
margin-left: 4.5px;
animation: loader_5191 675ms ease-in-out 375ms infinite;
}
.loader-0 #sq7 {
margin-top: 4.5px;
margin-left: -7.5px;
animation: loader_5191 675ms ease-in-out 450ms infinite;
}
.loader-0 #sq8 {
margin-top: 4.5px;
animation: loader_5191 675ms ease-in-out 525ms infinite;
}
.loader-0 #sq9 {
margin-top: 4.5px;
margin-left: 4.5px;
animation: loader_5191 675ms ease-in-out 600ms infinite;
}
/* ========== 1. 方块旋转动画 ========== */
@keyframes square-animation {
0% { left: 0; top: 0; }
10.5% { left: 0; top: 0; }
12.5% { left: 16px; top: 0; }
23% { left: 16px; top: 0; }
25% { left: 32px; top: 0; }
35.5% { left: 32px; top: 0; }
37.5% { left: 32px; top: 16px; }
48% { left: 32px; top: 16px; }
50% { left: 16px; top: 16px; }
60.5% { left: 16px; top: 16px; }
62.5% { left: 16px; top: 32px; }
73% { left: 16px; top: 32px; }
75% { left: 0; top: 32px; }
85.5% { left: 0; top: 32px; }
87.5% { left: 0; top: 16px; }
98% { left: 0; top: 16px; }
100% { left: 0; top: 0; }
}
.loader-1 {
position: relative;
width: 48px;
height: 48px;
transform: rotate(45deg);
}
.loader-1-square {
position: absolute;
top: 0;
left: 0;
width: 14px;
height: 14px;
margin: 1px;
background: var(--loader-color);
animation: square-animation 10s ease-in-out infinite both;
}
.loader-1-square:nth-of-type(1) { animation-delay: -1.4285714286s; }
.loader-1-square:nth-of-type(2) { animation-delay: -2.8571428571s; }
.loader-1-square:nth-of-type(3) { animation-delay: -4.2857142857s; }
.loader-1-square:nth-of-type(4) { animation-delay: -5.7142857143s; }
.loader-1-square:nth-of-type(5) { animation-delay: -7.1428571429s; }
.loader-1-square:nth-of-type(6) { animation-delay: -8.5714285714s; }
.loader-1-square:nth-of-type(7) { animation-delay: -10s; }
/* ========== 2. 双方块追逐 ========== */
.loader-2 {
--size: 15px;
width: 50px;
height: 50px;
position: relative;
}
.loader-2::after,
.loader-2::before {
box-sizing: border-box;
position: absolute;
content: "";
width: var(--size);
height: var(--size);
top: 50%;
animation: loader-2-up 2.4s cubic-bezier(0, 0, 0.24, 1.21) infinite;
left: 50%;
background: var(--loader-color);
}
.loader-2::after {
top: calc(50% - var(--size));
left: calc(50% - var(--size));
animation: loader-2-down 2.4s cubic-bezier(0, 0, 0.24, 1.21) infinite;
}
@keyframes loader-2-down {
0%, 100% { transform: none; }
25% { transform: translateX(100%); }
50% { transform: translateX(100%) translateY(100%); }
75% { transform: translateY(100%); }
}
@keyframes loader-2-up {
0%, 100% { transform: none; }
25% { transform: translateX(-100%); }
50% { transform: translateX(-100%) translateY(-100%); }
75% { transform: translateY(-100%); }
}
/* ========== 3. 弹跳方块 ========== */
.loader-3 {
width: 60px;
height: 30px;
position: relative;
}
.loader-3-square {
width: 10px;
height: 10px;
position: absolute;
background-color: var(--loader-color);
left: 15%;
transform-origin: 50%;
animation: loader-3-bounce .5s alternate infinite ease;
}
@keyframes loader-3-bounce {
0% {
top: 30px;
height: 5px;
transform: scaleX(1.7);
}
40% {
height: 10px;
transform: scaleX(1);
}
100% {
top: 0%;
}
}
.loader-3-square:nth-child(2) {
left: 45%;
animation-delay: .2s;
}
.loader-3-square:nth-child(3) {
left: auto;
right: 15%;
animation-delay: .3s;
}
/* ========== 4. 五方块序列 ========== */
.loader-4 {
--square: 13px;
--offset: 15px;
--duration: 2.4s;
--delay: 0.2s;
width: calc(3 * var(--offset) + var(--square));
height: calc(2 * var(--offset) + var(--square));
position: relative;
}
.loader-4 div {
display: inline-block;
background: var(--loader-color);
border: none;
width: var(--square);
height: var(--square);
position: absolute;
}
.loader-4 #sq1 {
left: calc(0 * var(--offset));
top: calc(0 * var(--offset));
animation: loader-4-square1 var(--duration) var(--delay) ease-in-out infinite;
}
.loader-4 #sq2 {
left: calc(0 * var(--offset));
top: calc(1 * var(--offset));
animation: loader-4-square2 var(--duration) var(--delay) ease-in-out infinite;
}
.loader-4 #sq3 {
left: calc(1 * var(--offset));
top: calc(1 * var(--offset));
animation: loader-4-square3 var(--duration) var(--delay) ease-in-out infinite;
}
.loader-4 #sq4 {
left: calc(2 * var(--offset));
top: calc(1 * var(--offset));
animation: loader-4-square4 var(--duration) var(--delay) ease-in-out infinite;
}
.loader-4 #sq5 {
left: calc(3 * var(--offset));
top: calc(1 * var(--offset));
animation: loader-4-square5 var(--duration) var(--delay) ease-in-out infinite;
}
@keyframes loader-4-square1 {
0% { left: calc(0 * var(--offset)); top: calc(0 * var(--offset)); }
8.333% { left: calc(0 * var(--offset)); top: calc(1 * var(--offset)); }
100% { left: calc(0 * var(--offset)); top: calc(1 * var(--offset)); }
}
@keyframes loader-4-square2 {
0% { left: calc(0 * var(--offset)); top: calc(1 * var(--offset)); }
8.333% { left: calc(0 * var(--offset)); top: calc(2 * var(--offset)); }
16.67% { left: calc(1 * var(--offset)); top: calc(2 * var(--offset)); }
25.00% { left: calc(1 * var(--offset)); top: calc(1 * var(--offset)); }
83.33% { left: calc(1 * var(--offset)); top: calc(1 * var(--offset)); }
91.67% { left: calc(1 * var(--offset)); top: calc(0 * var(--offset)); }
100% { left: calc(0 * var(--offset)); top: calc(0 * var(--offset)); }
}
@keyframes loader-4-square3 {
0%, 100% { left: calc(1 * var(--offset)); top: calc(1 * var(--offset)); }
16.67% { left: calc(1 * var(--offset)); top: calc(1 * var(--offset)); }
25.00% { left: calc(1 * var(--offset)); top: calc(0 * var(--offset)); }
33.33% { left: calc(2 * var(--offset)); top: calc(0 * var(--offset)); }
41.67% { left: calc(2 * var(--offset)); top: calc(1 * var(--offset)); }
66.67% { left: calc(2 * var(--offset)); top: calc(1 * var(--offset)); }
75.00% { left: calc(2 * var(--offset)); top: calc(2 * var(--offset)); }
83.33% { left: calc(1 * var(--offset)); top: calc(2 * var(--offset)); }
91.67% { left: calc(1 * var(--offset)); top: calc(1 * var(--offset)); }
}
@keyframes loader-4-square4 {
0% { left: calc(2 * var(--offset)); top: calc(1 * var(--offset)); }
33.33% { left: calc(2 * var(--offset)); top: calc(1 * var(--offset)); }
41.67% { left: calc(2 * var(--offset)); top: calc(2 * var(--offset)); }
50.00% { left: calc(3 * var(--offset)); top: calc(2 * var(--offset)); }
58.33% { left: calc(3 * var(--offset)); top: calc(1 * var(--offset)); }
100% { left: calc(3 * var(--offset)); top: calc(1 * var(--offset)); }
}
@keyframes loader-4-square5 {
0% { left: calc(3 * var(--offset)); top: calc(1 * var(--offset)); }
50.00% { left: calc(3 * var(--offset)); top: calc(1 * var(--offset)); }
58.33% { left: calc(3 * var(--offset)); top: calc(0 * var(--offset)); }
66.67% { left: calc(2 * var(--offset)); top: calc(0 * var(--offset)); }
75.00% { left: calc(2 * var(--offset)); top: calc(1 * var(--offset)); }
100% { left: calc(2 * var(--offset)); top: calc(1 * var(--offset)); }
}
/* ========== 5. 九宫格动画 ========== */
.loader-5 {
position: relative;
width: 36px;
height: 36px;
}
.loader-5-box {
float: left;
position: relative;
width: 10px;
height: 10px;
margin-right: 3px;
}
.loader-5-box:before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: var(--loader-color);
}
.loader-5-box:nth-child(3n) {
margin-right: 0;
margin-bottom: 3px;
}
.loader-5-box:nth-child(1):before,
.loader-5-box:nth-child(4):before {
margin-left: 13px;
}
.loader-5-box:nth-child(3):before {
margin-top: 26px;
}
.loader-5-box:last-child {
margin-bottom: 0;
}
.loader-5-box:nth-child(1) { animation: loader-5-moveBox-1 4s infinite; }
.loader-5-box:nth-child(2) { animation: loader-5-moveBox-2 4s infinite; }
.loader-5-box:nth-child(3) { animation: loader-5-moveBox-3 4s infinite; }
.loader-5-box:nth-child(4) { animation: loader-5-moveBox-4 4s infinite; }
.loader-5-box:nth-child(5) { animation: loader-5-moveBox-5 4s infinite; }
.loader-5-box:nth-child(6) { animation: loader-5-moveBox-6 4s infinite; }
.loader-5-box:nth-child(7) { animation: loader-5-moveBox-7 4s infinite; }
.loader-5-box:nth-child(8) { animation: loader-5-moveBox-8 4s infinite; }
.loader-5-box:nth-child(9) { animation: loader-5-moveBox-9 4s infinite; }
@keyframes loader-5-moveBox-1 {
9.09% { transform: translate(-13px, 0); }
18.18% { transform: translate(0px, 0); }
27.27% { transform: translate(0px, 0); }
36.36% { transform: translate(13px, 0); }
45.45% { transform: translate(13px, 13px); }
54.55% { transform: translate(13px, 13px); }
63.64% { transform: translate(13px, 13px); }
72.73% { transform: translate(13px, 0px); }
81.82% { transform: translate(0px, 0px); }
90.91% { transform: translate(-13px, 0px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-2 {
9.09% { transform: translate(0, 0); }
18.18% { transform: translate(13px, 0); }
27.27% { transform: translate(0px, 0); }
36.36% { transform: translate(13px, 0); }
45.45% { transform: translate(13px, 13px); }
54.55% { transform: translate(13px, 13px); }
63.64% { transform: translate(13px, 13px); }
72.73% { transform: translate(13px, 13px); }
81.82% { transform: translate(0px, 13px); }
90.91% { transform: translate(0px, 13px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-3 {
9.09% { transform: translate(-13px, 0); }
18.18% { transform: translate(-13px, 0); }
27.27% { transform: translate(0px, 0); }
36.36% { transform: translate(-13px, 0); }
45.45% { transform: translate(-13px, 0); }
54.55% { transform: translate(-13px, 0); }
63.64% { transform: translate(-13px, 0); }
72.73% { transform: translate(-13px, 0); }
81.82% { transform: translate(-13px, -13px); }
90.91% { transform: translate(0px, -13px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-4 {
9.09% { transform: translate(-13px, 0); }
18.18% { transform: translate(-13px, 0); }
27.27% { transform: translate(-13px, -13px); }
36.36% { transform: translate(0px, -13px); }
45.45% { transform: translate(0px, 0px); }
54.55% { transform: translate(0px, -13px); }
63.64% { transform: translate(0px, -13px); }
72.73% { transform: translate(0px, -13px); }
81.82% { transform: translate(-13px, -13px); }
90.91% { transform: translate(-13px, 0px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-5 {
9.09% { transform: translate(0, 0); }
18.18% { transform: translate(0, 0); }
27.27% { transform: translate(0, 0); }
36.36% { transform: translate(13px, 0); }
45.45% { transform: translate(13px, 0); }
54.55% { transform: translate(13px, 0); }
63.64% { transform: translate(13px, 0); }
72.73% { transform: translate(13px, 0); }
81.82% { transform: translate(13px, -13px); }
90.91% { transform: translate(0px, -13px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-6 {
9.09% { transform: translate(0, 0); }
18.18% { transform: translate(-13px, 0); }
27.27% { transform: translate(-13px, 0); }
36.36% { transform: translate(0px, 0); }
45.45% { transform: translate(0px, 0); }
54.55% { transform: translate(0px, 0); }
63.64% { transform: translate(0px, 0); }
72.73% { transform: translate(0px, 13px); }
81.82% { transform: translate(-13px, 13px); }
90.91% { transform: translate(-13px, 0px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-7 {
9.09% { transform: translate(13px, 0); }
18.18% { transform: translate(13px, 0); }
27.27% { transform: translate(13px, 0); }
36.36% { transform: translate(0px, 0); }
45.45% { transform: translate(0px, -13px); }
54.55% { transform: translate(13px, -13px); }
63.64% { transform: translate(0px, -13px); }
72.73% { transform: translate(0px, -13px); }
81.82% { transform: translate(0px, 0px); }
90.91% { transform: translate(13px, 0px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-8 {
9.09% { transform: translate(0, 0); }
18.18% { transform: translate(-13px, 0); }
27.27% { transform: translate(-13px, -13px); }
36.36% { transform: translate(0px, -13px); }
45.45% { transform: translate(0px, -13px); }
54.55% { transform: translate(0px, -13px); }
63.64% { transform: translate(0px, -13px); }
72.73% { transform: translate(0px, -13px); }
81.82% { transform: translate(13px, -13px); }
90.91% { transform: translate(13px, 0px); }
100% { transform: translate(0px, 0px); }
}
@keyframes loader-5-moveBox-9 {
9.09% { transform: translate(-13px, 0); }
18.18% { transform: translate(-13px, 0); }
27.27% { transform: translate(0px, 0); }
36.36% { transform: translate(-13px, 0); }
45.45% { transform: translate(0px, 0); }
54.55% { transform: translate(0px, 0); }
63.64% { transform: translate(-13px, 0); }
72.73% { transform: translate(-13px, 0); }
81.82% { transform: translate(-26px, 0); }
90.91% { transform: translate(-13px, 0); }
100% { transform: translate(0px, 0); }
}
/* ========== 6. 波纹方块 ========== */
.loader-6 {
--cell-size: 10px;
--cell-spacing: 1px;
--cells: 3;
--total-size: calc(var(--cells) * (var(--cell-size) + 2 * var(--cell-spacing)));
display: flex;
flex-wrap: wrap;
width: var(--total-size);
height: var(--total-size);
}
.loader-6-cell {
flex: 0 0 var(--cell-size);
margin: var(--cell-spacing);
background-color: transparent;
box-sizing: border-box;
animation: 1.5s loader-6-ripple ease infinite;
}
.loader-6-cell.d-1 { animation-delay: 100ms; }
.loader-6-cell.d-2 { animation-delay: 200ms; }
.loader-6-cell.d-3 { animation-delay: 300ms; }
.loader-6-cell.d-4 { animation-delay: 400ms; }
.loader-6-cell:nth-child(1),
.loader-6-cell:nth-child(2),
.loader-6-cell:nth-child(3),
.loader-6-cell:nth-child(4),
.loader-6-cell:nth-child(5),
.loader-6-cell:nth-child(6),
.loader-6-cell:nth-child(7),
.loader-6-cell:nth-child(8),
.loader-6-cell:nth-child(9) {
--cell-color: var(--loader-color);
}
@keyframes loader-6-ripple {
0% { background-color: transparent; }
30% { background-color: var(--cell-color); }
60% { background-color: transparent; }
100% { background-color: transparent; }
}
</style>
</head>
<body>
<div class="container">
<h1>加载动画预览 - 统一风格</h1>
<div class="loader-grid">
<!-- 0. 方格网格 (已有) -->
<div class="loader-item">
<div class="loader-wrapper">
<div class="loader-0">
<div class="loader-0-square" id="sq1"></div>
<div class="loader-0-square" id="sq2"></div>
<div class="loader-0-square" id="sq3"></div>
<div class="loader-0-square" id="sq4"></div>
<div class="loader-0-square" id="sq5"></div>
<div class="loader-0-square" id="sq6"></div>
<div class="loader-0-square" id="sq7"></div>
<div class="loader-0-square" id="sq8"></div>
<div class="loader-0-square" id="sq9"></div>
</div>
</div>
<div class="loader-title">0. 方格网格 (已有)</div>
</div>
<!-- 1. 方块旋转 -->
<div class="loader-item">
<div class="loader-wrapper">
<div class="loader-1">
<div class="loader-1-square"></div>
<div class="loader-1-square"></div>
<div class="loader-1-square"></div>
<div class="loader-1-square"></div>
<div class="loader-1-square"></div>
<div class="loader-1-square"></div>
<div class="loader-1-square"></div>
</div>
</div>
<div class="loader-title">1. 方块旋转</div>
</div>
<!-- 2. 双方块追逐 -->
<div class="loader-item">
<div class="loader-wrapper">
<div class="loader-2"></div>
</div>
<div class="loader-title">2. 双方块追逐</div>
</div>
<!-- 3. 弹跳方块 -->
<div class="loader-item">
<div class="loader-wrapper">
<div class="loader-3">
<div class="loader-3-square"></div>
<div class="loader-3-square"></div>
<div class="loader-3-square"></div>
</div>
</div>
<div class="loader-title">3. 弹跳方块</div>
</div>
<!-- 4. 五方块序列 -->
<div class="loader-item">
<div class="loader-wrapper">
<div class="loader-4">
<div id="sq1"></div>
<div id="sq2"></div>
<div id="sq3"></div>
<div id="sq4"></div>
<div id="sq5"></div>
</div>
</div>
<div class="loader-title">4. 五方块序列</div>
</div>
<!-- 5. 九宫格动画 -->
<div class="loader-item">
<div class="loader-wrapper">
<div class="loader-5">
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
<div class="loader-5-box"></div>
</div>
</div>
<div class="loader-title">5. 九宫格动画</div>
</div>
<!-- 6. 波纹方块 -->
<div class="loader-item">
<div class="loader-wrapper">
<div class="loader-6">
<div class="loader-6-cell d-0"></div>
<div class="loader-6-cell d-1"></div>
<div class="loader-6-cell d-2"></div>
<div class="loader-6-cell d-1"></div>
<div class="loader-6-cell d-2"></div>
<div class="loader-6-cell d-2"></div>
<div class="loader-6-cell d-3"></div>
<div class="loader-6-cell d-3"></div>
<div class="loader-6-cell d-4"></div>
</div>
</div>
<div class="loader-title">6. 波纹方块</div>
</div>
</div>
</div>
</body>
</html>

123
static/demo/loaders-v2.html Normal file
View File

@ -0,0 +1,123 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>加载动画预览 V2</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a1a; color: #e0e0e0; padding: 40px; }
.container { max-width: 1400px; margin: 0 auto; }
h1 { text-align: center; margin-bottom: 40px; color: #fff; }
.loader-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 30px; }
.loader-item { background: #2a2a2a; border-radius: 12px; padding: 30px; display: flex; flex-direction: column; align-items: center; gap: 20px; }
.loader-title { font-size: 13px; color: #999; text-align: center; }
.loader-wrapper { width: 100%; height: 60px; display: flex; align-items: center; justify-content: center; position: relative; }
:root { --loader-color: #888; }
/* 0. 已有 */
@keyframes loader_5191 { from { opacity: 0; } to { opacity: 1; } }
.loader-0 { position: relative; width: 16px; height: 16px; }
.loader-0-square { background: var(--loader-color); width: 3px; height: 3px; position: absolute; top: 50%; left: 50%; margin-top: -1.5px; margin-left: -1.5px; border-radius: 0.5px; }
.loader-0 #sq1 { margin-top: -7.5px; margin-left: -7.5px; animation: loader_5191 675ms ease-in-out 0s infinite alternate; }
.loader-0 #sq2 { margin-top: -7.5px; animation: loader_5191 675ms ease-in-out 75ms infinite alternate; }
.loader-0 #sq3 { margin-top: -7.5px; margin-left: 4.5px; animation: loader_5191 675ms ease-in-out 150ms infinite; }
.loader-0 #sq4 { margin-left: -7.5px; animation: loader_5191 675ms ease-in-out 225ms infinite; }
.loader-0 #sq5 { animation: loader_5191 675ms ease-in-out 300ms infinite; }
.loader-0 #sq6 { margin-left: 4.5px; animation: loader_5191 675ms ease-in-out 375ms infinite; }
.loader-0 #sq7 { margin-top: 4.5px; margin-left: -7.5px; animation: loader_5191 675ms ease-in-out 450ms infinite; }
.loader-0 #sq8 { margin-top: 4.5px; animation: loader_5191 675ms ease-in-out 525ms infinite; }
.loader-0 #sq9 { margin-top: 4.5px; margin-left: 4.5px; animation: loader_5191 675ms ease-in-out 600ms infinite; }
/* 1. 方块旋转 */
@keyframes sq-anim-1 { 0% { left: 0; top: 0; } 10.5% { left: 0; top: 0; } 12.5% { left: 8px; top: 0; } 23% { left: 8px; top: 0; } 25% { left: 16px; top: 0; } 35.5% { left: 16px; top: 0; } 37.5% { left: 16px; top: 8px; } 48% { left: 16px; top: 8px; } 50% { left: 8px; top: 8px; } 60.5% { left: 8px; top: 8px; } 62.5% { left: 8px; top: 16px; } 73% { left: 8px; top: 16px; } 75% { left: 0; top: 16px; } 85.5% { left: 0; top: 16px; } 87.5% { left: 0; top: 8px; } 98% { left: 0; top: 8px; } 100% { left: 0; top: 0; } }
.loader-1 { position: relative; width: 24px; height: 24px; transform: rotate(45deg); }
.loader-1-square { position: absolute; top: 0; left: 0; width: 3px; height: 3px; margin: 0.5px; background: var(--loader-color); animation: sq-anim-1 10s ease-in-out infinite both; }
.loader-1-square:nth-of-type(1) { animation-delay: -1.43s; }
.loader-1-square:nth-of-type(2) { animation-delay: -2.86s; }
.loader-1-square:nth-of-type(3) { animation-delay: -4.29s; }
.loader-1-square:nth-of-type(4) { animation-delay: -5.71s; }
.loader-1-square:nth-of-type(5) { animation-delay: -7.14s; }
.loader-1-square:nth-of-type(6) { animation-delay: -8.57s; }
.loader-1-square:nth-of-type(7) { animation-delay: -10s; }
/* 2. 双方块 */
.loader-2 { --size: 6px; width: 16px; height: 16px; position: relative; }
.loader-2::after, .loader-2::before { box-sizing: border-box; position: absolute; content: ""; width: var(--size); height: var(--size); top: 50%; animation: l2-up 2.4s cubic-bezier(0, 0, 0.24, 1.21) infinite; left: 50%; background: var(--loader-color); }
.loader-2::after { top: calc(50% - var(--size)); left: calc(50% - var(--size)); animation: l2-down 2.4s cubic-bezier(0, 0, 0.24, 1.21) infinite; }
@keyframes l2-down { 0%, 100% { transform: none; } 25% { transform: translateX(100%); } 50% { transform: translateX(100%) translateY(100%); } 75% { transform: translateY(100%); } }
@keyframes l2-up { 0%, 100% { transform: none; } 25% { transform: translateX(-100%); } 50% { transform: translateX(-100%) translateY(-100%); } 75% { transform: translateY(-100%); } }
/* 3. 弹跳 */
.loader-3 { width: 40px; height: 20px; position: relative; }
.loader-3-square { width: 3px; height: 3px; position: absolute; background-color: var(--loader-color); left: 15%; transform-origin: 50%; animation: l3-bounce .5s alternate infinite ease; }
@keyframes l3-bounce { 0% { top: 20px; height: 2px; transform: scaleX(1.7); } 40% { height: 3px; transform: scaleX(1); } 100% { top: 0%; } }
.loader-3-square:nth-child(2) { left: 45%; animation-delay: .2s; }
.loader-3-square:nth-child(3) { left: auto; right: 15%; animation-delay: .3s; }
/* 4. 五方块 */
.loader-4 { --sq: 3px; --off: 7.5px; width: calc(3 * var(--off) + var(--sq)); height: calc(2 * var(--off) + var(--sq)); position: relative; }
.loader-4 div { display: inline-block; background: var(--loader-color); width: var(--sq); height: var(--sq); position: absolute; }
.loader-4 #s1 { left: 0; top: 0; animation: l4-s1 2.4s 0.2s ease-in-out infinite; }
.loader-4 #s2 { left: 0; top: var(--off); animation: l4-s2 2.4s 0.2s ease-in-out infinite; }
.loader-4 #s3 { left: var(--off); top: var(--off); animation: l4-s3 2.4s 0.2s ease-in-out infinite; }
.loader-4 #s4 { left: calc(2 * var(--off)); top: var(--off); animation: l4-s4 2.4s 0.2s ease-in-out infinite; }
.loader-4 #s5 { left: calc(3 * var(--off)); top: var(--off); animation: l4-s5 2.4s 0.2s ease-in-out infinite; }
@keyframes l4-s1 { 0% { left: 0; top: 0; } 8.33% { left: 0; top: var(--off); } 100% { left: 0; top: var(--off); } }
@keyframes l4-s2 { 0% { left: 0; top: var(--off); } 8.33% { left: 0; top: calc(2 * var(--off)); } 16.67% { left: var(--off); top: calc(2 * var(--off)); } 25% { left: var(--off); top: var(--off); } 83.33% { left: var(--off); top: var(--off); } 91.67% { left: var(--off); top: 0; } 100% { left: 0; top: 0; } }
@keyframes l4-s3 { 0%, 100% { left: var(--off); top: var(--off); } 16.67% { left: var(--off); top: var(--off); } 25% { left: var(--off); top: 0; } 33.33% { left: calc(2 * var(--off)); top: 0; } 41.67% { left: calc(2 * var(--off)); top: var(--off); } 66.67% { left: calc(2 * var(--off)); top: var(--off); } 75% { left: calc(2 * var(--off)); top: calc(2 * var(--off)); } 83.33% { left: var(--off); top: calc(2 * var(--off)); } 91.67% { left: var(--off); top: var(--off); } }
@keyframes l4-s4 { 0% { left: calc(2 * var(--off)); top: var(--off); } 33.33% { left: calc(2 * var(--off)); top: var(--off); } 41.67% { left: calc(2 * var(--off)); top: calc(2 * var(--off)); } 50% { left: calc(3 * var(--off)); top: calc(2 * var(--off)); } 58.33% { left: calc(3 * var(--off)); top: var(--off); } 100% { left: calc(3 * var(--off)); top: var(--off); } }
@keyframes l4-s5 { 0% { left: calc(3 * var(--off)); top: var(--off); } 50% { left: calc(3 * var(--off)); top: var(--off); } 58.33% { left: calc(3 * var(--off)); top: 0; } 66.67% { left: calc(2 * var(--off)); top: 0; } 75% { left: calc(2 * var(--off)); top: var(--off); } 100% { left: calc(2 * var(--off)); top: var(--off); } }
/* 5. 九宫格 */
.loader-5 { position: relative; width: 20px; height: 20px; }
.loader-5-box { float: left; position: relative; width: 3px; height: 3px; margin-right: 4px; }
.loader-5-box:before { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: var(--loader-color); }
.loader-5-box:nth-child(3n) { margin-right: 0; margin-bottom: 4px; }
.loader-5-box:nth-child(1):before, .loader-5-box:nth-child(4):before { margin-left: 7px; }
.loader-5-box:nth-child(3):before { margin-top: 14px; }
.loader-5-box:last-child { margin-bottom: 0; }
.loader-5-box:nth-child(1) { animation: l5-m1 4s infinite; }
.loader-5-box:nth-child(2) { animation: l5-m2 4s infinite; }
.loader-5-box:nth-child(3) { animation: l5-m3 4s infinite; }
.loader-5-box:nth-child(4) { animation: l5-m4 4s infinite; }
.loader-5-box:nth-child(5) { animation: l5-m5 4s infinite; }
.loader-5-box:nth-child(6) { animation: l5-m6 4s infinite; }
.loader-5-box:nth-child(7) { animation: l5-m7 4s infinite; }
.loader-5-box:nth-child(8) { animation: l5-m8 4s infinite; }
.loader-5-box:nth-child(9) { animation: l5-m9 4s infinite; }
@keyframes l5-m1 { 9% { transform: translate(-7px, 0); } 18% { transform: translate(0, 0); } 27% { transform: translate(0, 0); } 36% { transform: translate(7px, 0); } 45% { transform: translate(7px, 7px); } 54% { transform: translate(7px, 7px); } 63% { transform: translate(7px, 7px); } 72% { transform: translate(7px, 0); } 81% { transform: translate(0, 0); } 90% { transform: translate(-7px, 0); } 100% { transform: translate(0, 0); } }
@keyframes l5-m2 { 9% { transform: translate(0, 0); } 18% { transform: translate(7px, 0); } 27% { transform: translate(0, 0); } 36% { transform: translate(7px, 0); } 45% { transform: translate(7px, 7px); } 54% { transform: translate(7px, 7px); } 63% { transform: translate(7px, 7px); } 72% { transform: translate(7px, 7px); } 81% { transform: translate(0, 7px); } 90% { transform: translate(0, 7px); } 100% { transform: translate(0, 0); } }
@keyframes l5-m3 { 9% { transform: translate(-7px, 0); } 18% { transform: translate(-7px, 0); } 27% { transform: translate(0, 0); } 36% { transform: translate(-7px, 0); } 45% { transform: translate(-7px, 0); } 54% { transform: translate(-7px, 0); } 63% { transform: translate(-7px, 0); } 72% { transform: translate(-7px, 0); } 81% { transform: translate(-7px, -7px); } 90% { transform: translate(0, -7px); } 100% { transform: translate(0, 0); } }
@keyframes l5-m4 { 9% { transform: translate(-7px, 0); } 18% { transform: translate(-7px, 0); } 27% { transform: translate(-7px, -7px); } 36% { transform: translate(0, -7px); } 45% { transform: translate(0, 0); } 54% { transform: translate(0, -7px); } 63% { transform: translate(0, -7px); } 72% { transform: translate(0, -7px); } 81% { transform: translate(-7px, -7px); } 90% { transform: translate(-7px, 0); } 100% { transform: translate(0, 0); } }
@keyframes l5-m5 { 9% { transform: translate(0, 0); } 18% { transform: translate(0, 0); } 27% { transform: translate(0, 0); } 36% { transform: translate(7px, 0); } 45% { transform: translate(7px, 0); } 54% { transform: translate(7px, 0); } 63% { transform: translate(7px, 0); } 72% { transform: translate(7px, 0); } 81% { transform: translate(7px, -7px); } 90% { transform: translate(0, -7px); } 100% { transform: translate(0, 0); } }
@keyframes l5-m6 { 9% { transform: translate(0, 0); } 18% { transform: translate(-7px, 0); } 27% { transform: translate(-7px, 0); } 36% { transform: translate(0, 0); } 45% { transform: translate(0, 0); } 54% { transform: translate(0, 0); } 63% { transform: translate(0, 0); } 72% { transform: translate(0, 7px); } 81% { transform: translate(-7px, 7px); } 90% { transform: translate(-7px, 0); } 100% { transform: translate(0, 0); } }
@keyframes l5-m7 { 9% { transform: translate(7px, 0); } 18% { transform: translate(7px, 0); } 27% { transform: translate(7px, 0); } 36% { transform: translate(0, 0); } 45% { transform: translate(0, -7px); } 54% { transform: translate(7px, -7px); } 63% { transform: translate(0, -7px); } 72% { transform: translate(0, -7px); } 81% { transform: translate(0, 0); } 90% { transform: translate(7px, 0); } 100% { transform: translate(0, 0); } }
@keyframes l5-m8 { 9% { transform: translate(0, 0); } 18% { transform: translate(-7px, 0); } 27% { transform: translate(-7px, -7px); } 36% { transform: translate(0, -7px); } 45% { transform: translate(0, -7px); } 54% { transform: translate(0, -7px); } 63% { transform: translate(0, -7px); } 72% { transform: translate(0, -7px); } 81% { transform: translate(7px, -7px); } 90% { transform: translate(7px, 0); } 100% { transform: translate(0, 0); } }
@keyframes l5-m9 { 9% { transform: translate(-7px, 0); } 18% { transform: translate(-7px, 0); } 27% { transform: translate(0, 0); } 36% { transform: translate(-7px, 0); } 45% { transform: translate(0, 0); } 54% { transform: translate(0, 0); } 63% { transform: translate(-7px, 0); } 72% { transform: translate(-7px, 0); } 81% { transform: translate(-14px, 0); } 90% { transform: translate(-7px, 0); } 100% { transform: translate(0, 0); } }
/* 6. 波纹 */
.loader-6 { --cell-size: 3px; --cell-spacing: 2px; --cells: 3; --total-size: calc(var(--cells) * (var(--cell-size) + 2 * var(--cell-spacing))); display: flex; flex-wrap: wrap; width: var(--total-size); height: var(--total-size); }
.loader-6-cell { flex: 0 0 var(--cell-size); margin: var(--cell-spacing); background-color: transparent; box-sizing: border-box; animation: 1.5s l6-ripple ease infinite; }
.loader-6-cell.d-1 { animation-delay: 100ms; }
.loader-6-cell.d-2 { animation-delay: 200ms; }
.loader-6-cell.d-3 { animation-delay: 300ms; }
.loader-6-cell.d-4 { animation-delay: 400ms; }
.loader-6-cell:nth-child(1), .loader-6-cell:nth-child(2), .loader-6-cell:nth-child(3), .loader-6-cell:nth-child(4), .loader-6-cell:nth-child(5), .loader-6-cell:nth-child(6), .loader-6-cell:nth-child(7), .loader-6-cell:nth-child(8), .loader-6-cell:nth-child(9) { --cell-color: var(--loader-color); }
@keyframes l6-ripple { 0% { background-color: transparent; } 30% { background-color: var(--cell-color); } 60% { background-color: transparent; } 100% { background-color: transparent; } }
</style>
</head>
<body>
<div class="container">
<h1>加载动画预览 V2 - 统一风格</h1>
<div class="loader-grid">
<div class="loader-item"><div class="loader-wrapper"><div class="loader-0"><div class="loader-0-square" id="sq1"></div><div class="loader-0-square" id="sq2"></div><div class="loader-0-square" id="sq3"></div><div class="loader-0-square" id="sq4"></div><div class="loader-0-square" id="sq5"></div><div class="loader-0-square" id="sq6"></div><div class="loader-0-square" id="sq7"></div><div class="loader-0-square" id="sq8"></div><div class="loader-0-square" id="sq9"></div></div></div><div class="loader-title">0. 方格网格 (已有)</div></div>
<div class="loader-item"><div class="loader-wrapper"><div class="loader-1"><div class="loader-1-square"></div><div class="loader-1-square"></div><div class="loader-1-square"></div><div class="loader-1-square"></div><div class="loader-1-square"></div><div class="loader-1-square"></div><div class="loader-1-square"></div></div></div><div class="loader-title">1. 方块旋转</div></div>
<div class="loader-item"><div class="loader-wrapper"><div class="loader-2"></div></div><div class="loader-title">2. 双方块追逐</div></div>
<div class="loader-item"><div class="loader-wrapper"><div class="loader-3"><div class="loader-3-square"></div><div class="loader-3-square"></div><div class="loader-3-square"></div></div></div><div class="loader-title">3. 弹跳方块</div></div>
<div class="loader-item"><div class="loader-wrapper"><div class="loader-4"><div id="s1"></div><div id="s2"></div><div id="s3"></div><div id="s4"></div><div id="s5"></div></div></div><div class="loader-title">4. 五方块序列</div></div>
<div class="loader-item"><div class="loader-wrapper"><div class="loader-5"><div class="loader-5-box"></div><div class="loader-5-box"></div><div class="loader-5-box"></div><div class="loader-5-box"></div><div class="loader-5-box"></div><div class="loader-5-box"></div><div class="loader-5-box"></div><div class="loader-5-box"></div><div class="loader-5-box"></div></div></div><div class="loader-title">5. 九宫格动画</div></div>
<div class="loader-item"><div class="loader-wrapper"><div class="loader-6"><div class="loader-6-cell d-0"></div><div class="loader-6-cell d-1"></div><div class="loader-6-cell d-2"></div><div class="loader-6-cell d-1"></div><div class="loader-6-cell d-2"></div><div class="loader-6-cell d-2"></div><div class="loader-6-cell d-3"></div><div class="loader-6-cell d-3"></div><div class="loader-6-cell d-4"></div></div></div><div class="loader-title">6. 波纹方块</div></div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,195 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>极简模式 V2 - 无缝展开</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="chat-area">
<!-- 用户消息 -->
<div class="message-block user-message">
<div class="message-header">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
<span>用户</span>
</div>
<div class="message-text">
帮我搜索一下最新的AI技术发展趋势
</div>
</div>
<!-- AI 消息 -->
<div class="message-block assistant-message">
<div class="message-header">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
<span>AI Assistant</span>
</div>
<!-- 等待动画 -->
<div class="generating-placeholder" id="generatingPlaceholder">
<span class="letter"></span>
<span class="letter"></span>
<span class="letter"></span>
<span class="letter">.</span>
<span class="letter">.</span>
<span class="letter">.</span>
</div>
<!-- 摘要/第一步内容(可展开的) -->
<div class="summary-wrapper" id="summaryWrapper" style="display: none;">
<div class="summary-timeline">
<svg class="summary-icon" id="summaryIcon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
<div class="summary-line" id="summaryLine"></div>
</div>
<div class="summary-content" id="summaryContent">
<div class="summary-text collapsed" id="summaryText">
我需要搜索最新的AI技术发展趋势。首先我应该使用搜索工具来查找相关信息...
</div>
<div class="summary-text-full" id="summaryTextFull" style="display: none;">
我需要搜索最新的AI技术发展趋势。首先我应该使用搜索工具来查找相关信息。搜索关键词应该包括"AI技术"、"人工智能"、"2026"、"发展趋势"等。
</div>
</div>
</div>
<!-- 后续步骤 -->
<div class="steps-container" id="stepsContainer" style="display: none;">
<!-- 步骤1: 搜索网页 -->
<div class="step-item" data-step="1" style="display: none;">
<div class="step-timeline">
<svg class="step-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.35-4.35"></path>
</svg>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header">搜索网页</div>
<div class="step-body">
<div class="tool-intent">搜索AI技术发展趋势 2026</div>
<div class="tool-result">
<div class="result-item">
<div class="result-title">2026年AI技术十大趋势</div>
<div class="result-url">https://example.com/ai-trends-2026</div>
</div>
<div class="result-item">
<div class="result-title">人工智能最新突破</div>
<div class="result-url">https://example.com/ai-breakthrough</div>
</div>
</div>
</div>
</div>
</div>
<!-- 步骤2: 思考 -->
<div class="step-item" data-step="2" style="display: none;">
<div class="step-timeline">
<svg class="step-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-body">
<div class="thinking-content" id="thinkingContent2">
搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析。我将使用curl命令来获取第一个链接的内容然后进行分析。这将帮助我提供更准确和详细的答案。让我执行这个命令...
<button class="show-more-btn" onclick="expandThinking(2)">显示更多</button>
</div>
<div class="thinking-content-full" id="thinkingContentFull2" style="display: none;">
搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析。我将使用curl命令来获取第一个链接的内容然后进行分析。这将帮助我提供更准确和详细的答案。让我执行这个命令...
在执行之前我需要确保命令的安全性和有效性。curl命令是一个常用的网络请求工具可以帮助我获取网页内容。我会添加适当的参数来确保请求的稳定性比如设置超时时间、用户代理等。
同时我还需要考虑如何解析返回的HTML内容提取出关键信息。可能需要使用一些文本处理工具如grep、sed或awk来过滤和格式化数据。
<button class="show-less-btn" onclick="collapseThinking(2)">收起</button>
</div>
</div>
</div>
</div>
<!-- 步骤3: 执行命令 -->
<div class="step-item" data-step="3" style="display: none;">
<div class="step-timeline">
<svg class="step-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header">执行命令</div>
<div class="step-body">
<div class="tool-intent">获取网页内容并分析</div>
<div class="tool-result">
<div class="command-block">
<div class="command-header">
<span class="command-label">bash</span>
</div>
<pre class="command-code">curl -s "https://example.com/ai-trends-2026" | grep -i "trend"</pre>
<div class="command-output">
<div class="output-line">Trend 1: 多模态AI模型的普及</div>
<div class="output-line">Trend 2: AI安全性和可解释性</div>
<div class="output-line">Trend 3: 边缘AI计算</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 步骤4: 思考 -->
<div class="step-item" data-step="4" style="display: none;">
<div class="step-timeline">
<svg class="step-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-body">
<div class="thinking-content">
很好,我已经收集到了足够的信息。现在我可以整理这些内容,为用户提供一个清晰、全面的答案。我会按照趋势的重要性和影响力来组织内容。
</div>
</div>
</div>
</div>
</div>
<!-- 最终输出 -->
<div class="text-output" id="textOutput" style="display: none;">
<div class="text-content">
<p>根据我的搜索和分析2026年AI技术的主要发展趋势包括</p>
<ol>
<li><strong>多模态AI模型的普及</strong>能够同时处理文本、图像、音频等多种数据类型的AI模型将成为主流。</li>
<li><strong>AI安全性和可解释性</strong>随着AI应用的广泛部署确保AI系统的安全性和决策的可解释性变得越来越重要。</li>
<li><strong>边缘AI计算</strong>将AI计算能力部署到边缘设备实现更快的响应速度和更好的隐私保护。</li>
</ol>
<p>这些趋势将深刻影响各行各业的数字化转型进程。</p>
</div>
</div>
</div>
</div>
<!-- 控制面板 -->
<div class="control-panel">
<button onclick="startDemo()" class="control-btn">开始演示</button>
<button onclick="resetDemo()" class="control-btn">重置</button>
<button onclick="toggleExpand()" class="control-btn">切换展开/折叠</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

View File

@ -0,0 +1,413 @@
// 全局状态
let currentStep = 0;
let isExpanded = false;
let demoRunning = false;
// 步骤配置
const steps = [
{
type: 'thinking',
icon: 'brain',
summary: '我需要搜索最新的AI技术发展趋势。首先我应该使用搜索工具来查找相关信息...',
fullText: '我需要搜索最新的AI技术发展趋势。首先我应该使用搜索工具来查找相关信息。搜索关键词应该包括"AI技术"、"人工智能"、"2026"、"发展趋势"等。',
duration: 2000
},
{
type: 'tool',
icon: 'search',
summary: '搜索AI技术发展趋势 2026',
duration: 2500
},
{
type: 'thinking',
icon: 'brain',
summary: '搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析...',
fullText: '搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析。我将使用curl命令来获取第一个链接的内容然后进行分析。这将帮助我提供更准确和详细的答案。让我执行这个命令...\n\n在执行之前我需要确保命令的安全性和有效性。curl命令是一个常用的网络请求工具可以帮助我获取网页内容。我会添加适当的参数来确保请求的稳定性比如设置超时时间、用户代理等。\n\n同时我还需要考虑如何解析返回的HTML内容提取出关键信息。可能需要使用一些文本处理工具如grep、sed或awk来过滤和格式化数据。',
duration: 2000
},
{
type: 'tool',
icon: 'terminal',
summary: '执行命令:获取网页内容并分析',
duration: 2500
},
{
type: 'thinking',
icon: 'brain',
summary: '很好,我已经收集到了足够的信息。现在我可以整理这些内容,为用户提供一个清晰、全面的答案...',
fullText: '很好,我已经收集到了足够的信息。现在我可以整理这些内容,为用户提供一个清晰、全面的答案。我会按照趋势的重要性和影响力来组织内容。',
duration: 2000
}
];
// 最终输出文本
const finalOutputText = `根据我的搜索和分析2026年AI技术的主要发展趋势包括
1. **多模态AI模型的普及**能够同时处理文本图像音频等多种数据类型的AI模型将成为主流
2. **AI安全性和可解释性**随着AI应用的广泛部署确保AI系统的安全性和决策的可解释性变得越来越重要
3. **边缘AI计算**将AI计算能力部署到边缘设备实现更快的响应速度和更好的隐私保护
这些趋势将深刻影响各行各业的数字化转型进程`;
// 开始演示
async function startDemo() {
if (demoRunning) return;
demoRunning = true;
resetDemo();
// 显示等待动画
const placeholder = document.getElementById('generatingPlaceholder');
placeholder.style.display = 'flex';
await sleep(1500);
// 隐藏等待动画,显示摘要包装器
placeholder.style.display = 'none';
const summaryWrapper = document.getElementById('summaryWrapper');
summaryWrapper.style.display = 'flex';
summaryWrapper.classList.add('running');
// 执行每个步骤
for (let i = 0; i < steps.length; i++) {
currentStep = i;
await executeStep(i);
}
// 完成后移除运行状态
await sleep(500);
summaryWrapper.classList.remove('running');
// 如果展开状态,显示最后一步
if (isExpanded) {
await showDetailStep(currentStep, true);
} else {
// 折叠状态下,摘要显示第一步内容
updateSummary(steps[0]);
}
await sleep(800);
// 显示最终输出(流式)
const textOutput = document.getElementById('textOutput');
textOutput.style.display = 'block';
setTimeout(() => {
textOutput.classList.add('show');
}, 50);
// 流式输出最终文本
await streamText(document.querySelector('.text-content'), finalOutputText, 20);
demoRunning = false;
}
// 执行单个步骤
async function executeStep(stepIndex) {
const step = steps[stepIndex];
// 更新摘要(仅在折叠状态下)
if (!isExpanded) {
// 流式输出摘要文本
await streamSummary(step);
}
// 如果展开状态,显示详细内容
if (isExpanded) {
await showDetailStep(stepIndex, true);
// 如果是思考类型,流式输出完整内容
if (step.type === 'thinking' && step.fullText) {
const stepBody = document.querySelector(`.step-item[data-step="${stepIndex + 1}"] .step-body`);
if (stepBody) {
stepBody.textContent = '';
await streamText(stepBody, step.fullText, 30);
// 更新竖线高度
updateLineHeight(stepIndex + 1);
}
}
}
// 显示下一个步骤的竖线(如果有下一个步骤)
if (stepIndex < steps.length - 1) {
if (isExpanded) {
// 展开状态:显示当前步骤的竖线
const currentStepItem = document.querySelector(`.step-item[data-step="${stepIndex + 1}"]`);
if (currentStepItem) {
const line = currentStepItem.querySelector('.step-line');
if (line) {
updateLineHeight(stepIndex + 1);
}
}
} else {
// 折叠状态:显示摘要的竖线(暂时不需要,因为只在展开时才有步骤)
}
}
await sleep(step.duration);
}
// 流式输出摘要文本
async function streamSummary(step) {
const summaryIcon = document.getElementById('summaryIcon');
const summaryText = document.getElementById('summaryText');
// 更新图标
summaryIcon.innerHTML = getIconSVG(step.icon);
// 流式输出文本
summaryText.textContent = '';
await streamText(summaryText, step.summary, 30);
}
// 流式输出文本
async function streamText(element, text, speed = 30) {
element.textContent = '';
for (let i = 0; i < text.length; i++) {
element.textContent += text[i];
await sleep(speed);
}
}
// 更新摘要
function updateSummary(step) {
const summaryIcon = document.getElementById('summaryIcon');
const summaryText = document.getElementById('summaryText');
// 更新图标
summaryIcon.innerHTML = getIconSVG(step.icon);
// 更新文本
summaryText.textContent = step.summary;
}
// 显示详细步骤
async function showDetailStep(stepIndex, isNewStep = false) {
const stepItem = document.querySelector(`.step-item[data-step="${stepIndex + 1}"]`);
if (!stepItem) return;
// 添加动画类
if (isNewStep) {
stepItem.classList.add('animated');
} else {
stepItem.classList.add('instant');
}
// 显示步骤
stepItem.style.display = 'flex';
// 等待动画
await sleep(isNewStep ? 100 : 10);
// 如果有下一个步骤,显示当前步骤的竖线
if (stepIndex < steps.length - 1) {
updateLineHeight(stepIndex + 1);
}
await sleep(isNewStep ? 250 : 10);
}
// 更新竖线高度
function updateLineHeight(stepIndex) {
const stepItem = document.querySelector(`.step-item[data-step="${stepIndex}"]`);
if (!stepItem) return;
const line = stepItem.querySelector('.step-line');
const stepContent = stepItem.querySelector('.step-content');
if (!line || !stepContent) return;
// 获取内容的实际高度
const contentHeight = stepContent.offsetHeight;
// 如果是最后一个步骤,不需要竖线
if (stepIndex >= steps.length) {
line.style.height = '0';
return;
}
// 计算竖线高度:内容高度 + 间距
const gap = 16;
const lineHeight = Math.max(contentHeight + gap, 40);
line.style.height = `${lineHeight}px`;
}
// 切换展开/折叠
async function toggleExpand() {
const summaryWrapper = document.getElementById('summaryWrapper');
if (summaryWrapper.style.display === 'none') return;
isExpanded = !isExpanded;
if (isExpanded) {
// 展开:显示完整文本,隐藏摘要文本
summaryWrapper.classList.add('expanded');
const summaryText = document.getElementById('summaryText');
const summaryTextFull = document.getElementById('summaryTextFull');
const summaryLine = document.getElementById('summaryLine');
const stepsContainer = document.getElementById('stepsContainer');
// 切换文本显示
summaryText.style.display = 'none';
summaryTextFull.style.display = 'block';
// 显示连接线
await sleep(50);
summaryLine.style.height = '20px';
// 显示步骤容器
stepsContainer.style.display = 'block';
await sleep(50);
stepsContainer.classList.add('show');
// 快速显示已完成的步骤
for (let i = 0; i <= currentStep; i++) {
const isCurrentStep = i === currentStep && demoRunning;
await showDetailStep(i, isCurrentStep);
if (!isCurrentStep) {
await sleep(30); // 已有内容快速出现
}
}
} else {
// 折叠:显示摘要文本,隐藏完整文本
summaryWrapper.classList.remove('expanded');
const summaryText = document.getElementById('summaryText');
const summaryTextFull = document.getElementById('summaryTextFull');
const summaryLine = document.getElementById('summaryLine');
const stepsContainer = document.getElementById('stepsContainer');
// 隐藏步骤容器
stepsContainer.classList.remove('show');
await sleep(250);
stepsContainer.style.display = 'none';
// 隐藏连接线
summaryLine.style.height = '0';
// 切换文本显示
summaryText.style.display = 'block';
summaryTextFull.style.display = 'none';
// 更新摘要为第一步内容(不是当前步骤)
updateSummary(steps[0]);
// 重置所有步骤显示
document.querySelectorAll('.step-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
const line = item.querySelector('.step-line');
if (line) {
line.style.height = '0';
}
});
}
}
// 展开思考内容
function expandThinking(stepIndex) {
const thinkingContent = document.getElementById(`thinkingContent${stepIndex}`);
const thinkingContentFull = document.getElementById(`thinkingContentFull${stepIndex}`);
thinkingContent.style.display = 'none';
thinkingContentFull.style.display = 'block';
// 重新计算并更新竖线高度
setTimeout(() => {
updateLineHeight(stepIndex);
}, 50);
}
// 收起思考内容
function collapseThinking(stepIndex) {
const thinkingContent = document.getElementById(`thinkingContent${stepIndex}`);
const thinkingContentFull = document.getElementById(`thinkingContentFull${stepIndex}`);
thinkingContent.style.display = 'block';
thinkingContentFull.style.display = 'none';
// 重新计算并更新竖线高度
setTimeout(() => {
updateLineHeight(stepIndex);
}, 50);
}
// 重置演示
function resetDemo() {
currentStep = 0;
isExpanded = false;
demoRunning = false;
// 隐藏所有元素
document.getElementById('generatingPlaceholder').style.display = 'none';
const summaryWrapper = document.getElementById('summaryWrapper');
summaryWrapper.style.display = 'none';
summaryWrapper.classList.remove('running', 'expanded');
const summaryText = document.getElementById('summaryText');
const summaryTextFull = document.getElementById('summaryTextFull');
summaryText.style.display = 'block';
summaryTextFull.style.display = 'none';
const summaryLine = document.getElementById('summaryLine');
summaryLine.style.height = '0';
const stepsContainer = document.getElementById('stepsContainer');
stepsContainer.style.display = 'none';
stepsContainer.classList.remove('show');
const textOutput = document.getElementById('textOutput');
textOutput.style.display = 'none';
textOutput.classList.remove('show');
const textContent = textOutput.querySelector('.text-content');
if (textContent) {
textContent.innerHTML = `<p>根据我的搜索和分析2026年AI技术的主要发展趋势包括</p>
<ol>
<li><strong>多模态AI模型的普及</strong>AI</li>
<li><strong>AI安全性和可解释性</strong>AI广AI</li>
<li><strong>边缘AI计算</strong>AI</li>
</ol>
<p>这些趋势将深刻影响各行各业的数字化转型进程</p>`;
}
// 重置所有步骤
document.querySelectorAll('.step-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
const line = item.querySelector('.step-line');
if (line) {
line.style.height = '0';
}
});
// 重置思考内容
document.querySelectorAll('.thinking-content').forEach(item => {
item.style.display = 'block';
});
document.querySelectorAll('.thinking-content-full').forEach(item => {
item.style.display = 'none';
});
// 重置摘要文本
updateSummary(steps[0]);
}
// 获取图标SVG
function getIconSVG(iconType) {
const icons = {
brain: '<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path><path d="M12 6v6l4 2"></path>',
search: '<circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path>',
terminal: '<polyline points="4 17 10 11 4 5"></polyline><line x1="12" y1="19" x2="20" y2="19"></line>'
};
return icons[iconType] || icons.brain;
}
// 工具函数:延迟
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 点击摘要包装器切换展开/折叠
document.getElementById('summaryWrapper').addEventListener('click', toggleExpand);

View File

@ -0,0 +1,448 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica', 'Arial', sans-serif;
background: #f8f9fa;
color: #1a1a1a;
line-height: 1.6;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 40px 20px;
}
.chat-area {
background: white;
border-radius: 12px;
padding: 32px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
/* 消息块 */
.message-block {
margin-bottom: 32px;
}
.message-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
font-size: 14px;
font-weight: 600;
color: #666;
}
.icon {
flex-shrink: 0;
}
/* 用户消息 */
.user-message {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.user-message .message-text {
background: rgba(0, 0, 0, 0.03);
padding: 14px 18px;
border-radius: 16px;
max-width: 60%;
font-size: 15px;
line-height: 1.5;
}
/* AI消息 */
.assistant-message {
display: flex;
flex-direction: column;
align-items: flex-start;
}
/* 等待动画 */
.generating-placeholder {
display: flex;
gap: 4px;
padding: 12px 0;
font-size: 15px;
font-weight: 500;
color: #999;
}
.generating-placeholder .letter {
display: inline-block;
animation: wave 1.6s ease-in-out infinite;
opacity: 0.4;
}
.generating-placeholder .letter:nth-child(1) { animation-delay: 0s; }
.generating-placeholder .letter:nth-child(2) { animation-delay: 0.1s; }
.generating-placeholder .letter:nth-child(3) { animation-delay: 0.2s; }
.generating-placeholder .letter:nth-child(4) { animation-delay: 0.3s; }
.generating-placeholder .letter:nth-child(5) { animation-delay: 0.4s; }
.generating-placeholder .letter:nth-child(6) { animation-delay: 0.5s; }
@keyframes wave {
0%, 100% {
opacity: 0.4;
transform: translateY(0);
}
50% {
opacity: 1;
transform: translateY(-3px);
}
}
/* 摘要包装器 */
.summary-wrapper {
display: flex;
gap: 12px;
cursor: pointer;
position: relative;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.summary-wrapper:hover {
opacity: 0.7;
}
/* 摘要时间线 */
.summary-timeline {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
}
.summary-icon {
color: #999;
flex-shrink: 0;
margin-top: 2px;
}
.summary-line {
width: 2px;
height: 0;
background: #e0e0e0;
margin-top: 6px;
transition: height 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.summary-wrapper.expanded .summary-line {
height: 20px;
}
/* 摘要内容 */
.summary-content {
flex: 1;
min-width: 0;
position: relative;
}
.summary-text {
font-size: 13px;
color: #999;
line-height: 1.6;
display: block;
}
.summary-text.collapsed {
position: relative;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 100%;
}
.summary-text.collapsed::after {
content: '';
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 40px;
background: linear-gradient(to right, transparent, white);
pointer-events: none;
}
.summary-text-full {
font-size: 14px;
color: #666;
line-height: 1.7;
}
/* 运行中的发光效果(字体颜色变化) */
.summary-wrapper.running .summary-text,
.summary-wrapper.running .summary-text-full {
animation: textGlow 1.5s ease-in-out infinite;
}
@keyframes textGlow {
0%, 100% {
color: #999;
}
50% {
color: #6464ff;
}
}
/* 步骤容器 */
.steps-container {
opacity: 0;
max-height: 0;
overflow: hidden;
transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1),
max-height 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.steps-container.show {
opacity: 1;
max-height: 3000px;
}
/* 步骤项 */
.step-item {
display: flex;
gap: 12px;
opacity: 0;
transform: translateY(-8px);
transition: opacity 0.25s ease, transform 0.25s ease;
}
.step-item.instant {
animation: fadeInStep 0.15s ease forwards;
}
.step-item.animated {
animation: fadeInStep 0.35s ease forwards;
}
@keyframes fadeInStep {
to {
opacity: 1;
transform: translateY(0);
}
}
/* 步骤时间线 */
.step-timeline {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
}
.step-icon {
color: #666;
flex-shrink: 0;
margin-top: 2px;
}
.step-line {
width: 2px;
background: #e0e0e0;
margin-top: 6px;
transition: height 0.2s ease;
}
.step-item:last-child .step-line {
height: 0 !important;
}
/* 步骤内容 */
.step-content {
flex: 1;
min-width: 0;
padding-bottom: 16px;
}
.step-header {
font-size: 12px;
font-weight: 600;
color: #999;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
.step-body {
font-size: 14px;
line-height: 1.6;
color: #333;
}
/* 思考内容 */
.thinking-content {
color: #666;
font-size: 14px;
line-height: 1.7;
max-height: 100px;
overflow: hidden;
position: relative;
}
.thinking-content-full {
color: #666;
font-size: 14px;
line-height: 1.7;
}
.show-more-btn,
.show-less-btn {
display: inline-block;
margin-top: 8px;
padding: 4px 12px;
background: transparent;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 12px;
color: #666;
cursor: pointer;
transition: all 0.2s ease;
}
.show-more-btn:hover,
.show-less-btn:hover {
background: #f5f5f5;
border-color: #999;
}
/* 工具内容 */
.tool-intent {
font-weight: 500;
color: #444;
margin-bottom: 12px;
}
.tool-result {
background: #f8f9fa;
border-radius: 8px;
padding: 12px;
}
.result-item {
padding: 8px 0;
border-bottom: 1px solid #e0e0e0;
}
.result-item:last-child {
border-bottom: none;
}
.result-title {
font-weight: 500;
color: #333;
margin-bottom: 4px;
}
.result-url {
font-size: 12px;
color: #999;
}
/* 命令块 */
.command-block {
background: #f8f9fa;
border-radius: 8px;
overflow: hidden;
}
.command-header {
background: #e9ecef;
padding: 8px 12px;
font-size: 12px;
color: #666;
}
.command-code {
padding: 12px;
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
font-size: 13px;
color: #333;
overflow-x: auto;
}
.command-output {
padding: 12px;
border-top: 1px solid #e0e0e0;
}
.output-line {
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
font-size: 12px;
color: #666;
line-height: 1.8;
}
/* 最终输出 */
.text-output {
margin-top: 16px;
opacity: 0;
transform: translateY(10px);
transition: all 0.4s ease;
}
.text-output.show {
opacity: 1;
transform: translateY(0);
}
.text-content {
font-size: 15px;
line-height: 1.7;
color: #333;
}
.text-content p {
margin-bottom: 16px;
}
.text-content ol {
margin-left: 24px;
margin-bottom: 16px;
}
.text-content li {
margin-bottom: 12px;
}
.text-content strong {
font-weight: 600;
color: #1a1a1a;
}
/* 控制面板 */
.control-panel {
margin-top: 32px;
display: flex;
gap: 12px;
justify-content: center;
}
.control-btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.control-btn:hover {
background: #0056b3;
transform: translateY(-1px);
}
.control-btn:active {
transform: translateY(0);
}

View File

@ -0,0 +1,191 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>极简模式 Demo</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="chat-area">
<!-- 用户消息 -->
<div class="message-block user-message">
<div class="message-header">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
<span>用户</span>
</div>
<div class="message-text">
帮我搜索一下最新的AI技术发展趋势
</div>
</div>
<!-- AI 消息 -->
<div class="message-block assistant-message">
<div class="message-header">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
<span>AI Assistant</span>
</div>
<!-- 等待动画 -->
<div class="generating-placeholder" id="generatingPlaceholder">
<span class="letter"></span>
<span class="letter"></span>
<span class="letter"></span>
<span class="letter">.</span>
<span class="letter">.</span>
<span class="letter">.</span>
</div>
<!-- 摘要行 -->
<div class="summary-line" id="summaryLine" style="display: none;">
<svg class="summary-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</svg>
<span class="summary-text" id="summaryText">正在思考如何搜索...</span>
<div class="shimmer-overlay"></div>
</div>
<!-- 展开的详细内容 -->
<div class="detail-view" id="detailView" style="display: none;">
<div class="timeline-container">
<!-- 左侧时间线 -->
<div class="timeline">
<!-- 第一个步骤不显示图标,使用摘要行的图标 -->
<div class="timeline-item timeline-item-first" data-step="0">
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="1" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.35-4.35"></path>
</svg>
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="2" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="3" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="4" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
<div class="timeline-line"></div>
</div>
</div>
<!-- 右侧内容 -->
<div class="content-area">
<div class="content-item" data-step="0">
<div class="content-body">
<div class="thinking-content" id="thinkingContent0">
我需要搜索最新的AI技术发展趋势。首先我应该使用搜索工具来查找相关信息。搜索关键词应该包括"AI技术"、"人工智能"、"2026"、"发展趋势"等。
</div>
</div>
</div>
<div class="content-item" data-step="1" style="display: none;">
<div class="content-header">搜索网页</div>
<div class="content-body">
<div class="tool-intent">搜索AI技术发展趋势 2026</div>
<div class="tool-result">
<div class="result-item">
<div class="result-title">2026年AI技术十大趋势</div>
<div class="result-url">https://example.com/ai-trends-2026</div>
</div>
<div class="result-item">
<div class="result-title">人工智能最新突破</div>
<div class="result-url">https://example.com/ai-breakthrough</div>
</div>
</div>
</div>
</div>
<div class="content-item" data-step="2" style="display: none;">
<div class="content-body">
<div class="thinking-content" id="thinkingContent2">
搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析。我将使用curl命令来获取第一个链接的内容然后进行分析。这将帮助我提供更准确和详细的答案。让我执行这个命令...
<button class="show-more-btn" onclick="expandThinking(2)">显示更多</button>
</div>
<div class="thinking-content-full" id="thinkingContentFull2" style="display: none;">
搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析。我将使用curl命令来获取第一个链接的内容然后进行分析。这将帮助我提供更准确和详细的答案。让我执行这个命令...
在执行之前我需要确保命令的安全性和有效性。curl命令是一个常用的网络请求工具可以帮助我获取网页内容。我会添加适当的参数来确保请求的稳定性比如设置超时时间、用户代理等。
同时我还需要考虑如何解析返回的HTML内容提取出关键信息。可能需要使用一些文本处理工具如grep、sed或awk来过滤和格式化数据。
<button class="show-less-btn" onclick="collapseThinking(2)">收起</button>
</div>
</div>
</div>
<div class="content-item" data-step="3" style="display: none;">
<div class="content-header">执行命令</div>
<div class="content-body">
<div class="tool-intent">获取网页内容并分析</div>
<div class="tool-result">
<div class="command-block">
<div class="command-header">
<span class="command-label">bash</span>
</div>
<pre class="command-code">curl -s "https://example.com/ai-trends-2026" | grep -i "trend"</pre>
<div class="command-output">
<div class="output-line">Trend 1: 多模态AI模型的普及</div>
<div class="output-line">Trend 2: AI安全性和可解释性</div>
<div class="output-line">Trend 3: 边缘AI计算</div>
</div>
</div>
</div>
</div>
</div>
<div class="content-item" data-step="4" style="display: none;">
<div class="content-body">
<div class="thinking-content" id="thinkingContent4">
很好,我已经收集到了足够的信息。现在我可以整理这些内容,为用户提供一个清晰、全面的答案。我会按照趋势的重要性和影响力来组织内容。
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 最终输出 -->
<div class="text-output" id="textOutput" style="display: none;">
<div class="text-content">
<p>根据我的搜索和分析2026年AI技术的主要发展趋势包括</p>
<ol>
<li><strong>多模态AI模型的普及</strong>能够同时处理文本、图像、音频等多种数据类型的AI模型将成为主流。</li>
<li><strong>AI安全性和可解释性</strong>随着AI应用的广泛部署确保AI系统的安全性和决策的可解释性变得越来越重要。</li>
<li><strong>边缘AI计算</strong>将AI计算能力部署到边缘设备实现更快的响应速度和更好的隐私保护。</li>
</ol>
<p>这些趋势将深刻影响各行各业的数字化转型进程。</p>
</div>
</div>
</div>
</div>
<!-- 控制面板 -->
<div class="control-panel">
<button onclick="startDemo()" class="control-btn">开始演示</button>
<button onclick="resetDemo()" class="control-btn">重置</button>
<button onclick="toggleSummary()" class="control-btn">切换展开/折叠</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

View File

@ -0,0 +1,191 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>极简模式 Demo</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="chat-area">
<!-- 用户消息 -->
<div class="message-block user-message">
<div class="message-header">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
<span>用户</span>
</div>
<div class="message-text">
帮我搜索一下最新的AI技术发展趋势
</div>
</div>
<!-- AI 消息 -->
<div class="message-block assistant-message">
<div class="message-header">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
<span>AI Assistant</span>
</div>
<!-- 等待动画 -->
<div class="generating-placeholder" id="generatingPlaceholder">
<span class="letter">思</span>
<span class="letter">考</span>
<span class="letter">中</span>
<span class="letter">.</span>
<span class="letter">.</span>
<span class="letter">.</span>
</div>
<!-- 摘要行 -->
<div class="summary-line" id="summaryLine" style="display: none;">
<svg class="summary-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</svg>
<span class="summary-text" id="summaryText">正在思考如何搜索...</span>
<div class="shimmer-overlay"></div>
</div>
<!-- 展开的详细内容 -->
<div class="detail-view" id="detailView" style="display: none;">
<div class="timeline-container">
<!-- 左侧时间线 -->
<div class="timeline">
<!-- 第一个步骤不显示图标,使用摘要行的图标 -->
<div class="timeline-item timeline-item-first" data-step="0">
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="1" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.35-4.35"></path>
</svg>
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="2" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="3" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
<div class="timeline-line"></div>
</div>
<div class="timeline-item" data-step="4" style="display: none;">
<svg class="timeline-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path>
<path d="M12 6v6l4 2"></path>
</svg>
<div class="timeline-line"></div>
</div>
</div>
<!-- 右侧内容 -->
<div class="content-area">
<div class="content-item" data-step="0">
<div class="content-body">
<div class="thinking-content" id="thinkingContent0">
我需要搜索最新的AI技术发展趋势。首先我应该使用搜索工具来查找相关信息。搜索关键词应该包括"AI技术"、"人工智能"、"2026"、"发展趋势"等。
</div>
</div>
</div>
<div class="content-item" data-step="1" style="display: none;">
<div class="content-header">搜索网页</div>
<div class="content-body">
<div class="tool-intent">搜索AI技术发展趋势 2026</div>
<div class="tool-result">
<div class="result-item">
<div class="result-title">2026年AI技术十大趋势</div>
<div class="result-url">https://example.com/ai-trends-2026</div>
</div>
<div class="result-item">
<div class="result-title">人工智能最新突破</div>
<div class="result-url">https://example.com/ai-breakthrough</div>
</div>
</div>
</div>
</div>
<div class="content-item" data-step="2" style="display: none;">
<div class="content-body">
<div class="thinking-content" id="thinkingContent2">
搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析。我将使用curl命令来获取第一个链接的内容然后进行分析。这将帮助我提供更准确和详细的答案。让我执行这个命令...
<button class="show-more-btn" onclick="expandThinking(2)">显示更多</button>
</div>
<div class="thinking-content-full" id="thinkingContentFull2" style="display: none;">
搜索结果显示了一些有价值的信息。现在我需要执行一个命令来获取更详细的数据分析。我将使用curl命令来获取第一个链接的内容然后进行分析。这将帮助我提供更准确和详细的答案。让我执行这个命令...
在执行之前我需要确保命令的安全性和有效性。curl命令是一个常用的网络请求工具可以帮助我获取网页内容。我会添加适当的参数来确保请求的稳定性比如设置超时时间、用户代理等。
同时我还需要考虑如何解析返回的HTML内容提取出关键信息。可能需要使用一些文本处理工具如grep、sed或awk来过滤和格式化数据。
<button class="show-less-btn" onclick="collapseThinking(2)">收起</button>
</div>
</div>
</div>
<div class="content-item" data-step="3" style="display: none;">
<div class="content-header">执行命令</div>
<div class="content-body">
<div class="tool-intent">获取网页内容并分析</div>
<div class="tool-result">
<div class="command-block">
<div class="command-header">
<span class="command-label">bash</span>
</div>
<pre class="command-code">curl -s "https://example.com/ai-trends-2026" | grep -i "trend"</pre>
<div class="command-output">
<div class="output-line">Trend 1: 多模态AI模型的普及</div>
<div class="output-line">Trend 2: AI安全性和可解释性</div>
<div class="output-line">Trend 3: 边缘AI计算</div>
</div>
</div>
</div>
</div>
</div>
<div class="content-item" data-step="4" style="display: none;">
<div class="content-body">
<div class="thinking-content" id="thinkingContent4">
很好,我已经收集到了足够的信息。现在我可以整理这些内容,为用户提供一个清晰、全面的答案。我会按照趋势的重要性和影响力来组织内容。
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 最终输出 -->
<div class="text-output" id="textOutput" style="display: none;">
<div class="text-content">
<p>根据我的搜索和分析2026年AI技术的主要发展趋势包括</p>
<ol>
<li><strong>多模态AI模型的普及</strong>能够同时处理文本、图像、音频等多种数据类型的AI模型将成为主流。</li>
<li><strong>AI安全性和可解释性</strong>随着AI应用的广泛部署确保AI系统的安全性和决策的可解释性变得越来越重要。</li>
<li><strong>边缘AI计算</strong>将AI计算能力部署到边缘设备实现更快的响应速度和更好的隐私保护。</li>
</ol>
<p>这些趋势将深刻影响各行各业的数字化转型进程。</p>
</div>
</div>
</div>
</div>
<!-- 控制面板 -->
<div class="control-panel">
<button onclick="startDemo()" class="control-btn">开始演示</button>
<button onclick="resetDemo()" class="control-btn">重置</button>
<button onclick="toggleSummary()" class="control-btn">切换展开/折叠</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

View File

@ -0,0 +1,333 @@
// 全局状态
let currentStep = 0;
let isExpanded = false;
let demoRunning = false;
// 步骤配置
const steps = [
{
type: 'thinking',
icon: 'brain',
summary: '正在思考如何搜索...',
duration: 2000
},
{
type: 'tool',
icon: 'search',
summary: '搜索AI技术发展趋势 2026',
duration: 2500
},
{
type: 'thinking',
icon: 'brain',
summary: '搜索结果显示了一些有价值的信息。现在我需要执行...',
duration: 2000
},
{
type: 'tool',
icon: 'terminal',
summary: '执行命令:获取网页内容并分析',
duration: 2500
},
{
type: 'thinking',
icon: 'brain',
summary: '很好,我已经收集到了足够的信息。现在我可以整理...',
duration: 2000
}
];
// 开始演示
async function startDemo() {
if (demoRunning) return;
demoRunning = true;
resetDemo();
// 显示等待动画
const placeholder = document.getElementById('generatingPlaceholder');
placeholder.style.display = 'flex';
await sleep(1500);
// 隐藏等待动画,显示摘要行
placeholder.style.display = 'none';
const summaryLine = document.getElementById('summaryLine');
summaryLine.style.display = 'flex';
// 执行每个步骤
for (let i = 0; i < steps.length; i++) {
currentStep = i;
await executeStep(i);
}
// 完成后显示最终输出
await sleep(1000);
summaryLine.classList.add('completed');
// 如果展开状态,显示最后一步
if (isExpanded) {
await showDetailStep(currentStep, true);
}
// 淡化摘要并显示第一个步骤(极快)
await fadeAndSwitch(summaryLine, steps[0].summary, true);
await sleep(800);
// 显示最终输出
const textOutput = document.getElementById('textOutput');
textOutput.style.display = 'block';
setTimeout(() => {
textOutput.classList.add('show');
}, 50);
demoRunning = false;
}
// 执行单个步骤
async function executeStep(stepIndex) {
const step = steps[stepIndex];
// 更新摘要文本
updateSummary(step);
// 如果展开状态,显示详细内容
if (isExpanded) {
await showDetailStep(stepIndex);
}
await sleep(step.duration);
}
// 更新摘要
function updateSummary(step) {
const summaryText = document.getElementById('summaryText');
const summaryIcon = document.querySelector('.summary-icon');
// 更新图标
summaryIcon.innerHTML = getIconSVG(step.icon);
// 更新文本
summaryText.textContent = step.summary;
}
// 显示详细步骤
async function showDetailStep(stepIndex, isNewStep = false) {
const timelineItem = document.querySelector(`.timeline-item[data-step="${stepIndex}"]`);
const contentItem = document.querySelector(`.content-item[data-step="${stepIndex}"]`);
if (!timelineItem || !contentItem) return;
// 添加动画类
if (isNewStep) {
timelineItem.classList.add('animated');
contentItem.classList.add('animated');
} else {
timelineItem.classList.add('instant');
contentItem.classList.add('instant');
}
// 显示时间线项和内容
timelineItem.style.display = 'flex';
contentItem.style.display = 'block';
// 计算并设置竖线高度
await sleep(isNewStep ? 100 : 10);
updateLineHeight(stepIndex);
await sleep(isNewStep ? 200 : 10);
}
// 更新竖线高度
function updateLineHeight(stepIndex) {
const timelineItem = document.querySelector(`.timeline-item[data-step="${stepIndex}"]`);
const contentItem = document.querySelector(`.content-item[data-step="${stepIndex}"]`);
if (!timelineItem || !contentItem) return;
const line = timelineItem.querySelector('.timeline-line');
if (!line) return;
// 获取内容的实际高度
const contentHeight = contentItem.offsetHeight;
// 对于第一个步骤(没有图标),竖线从顶部开始
if (stepIndex === 0) {
const gap = 20; // 到下一个步骤的间距
const lineHeight = contentHeight + gap;
line.style.height = `${lineHeight}px`;
return;
}
// 对于其他步骤,计算竖线高度
const iconHeight = 20; // 图标高度
const gap = 20; // 间距
// 如果是最后一个步骤,不需要竖线
if (stepIndex >= steps.length - 1) {
line.style.height = '0';
return;
}
// 计算竖线应该的高度:内容高度 + 间距 - 图标高度
const lineHeight = Math.max(contentHeight + gap - iconHeight, 40);
line.style.height = `${lineHeight}px`;
}
// 切换展开/折叠
async function toggleSummary() {
const summaryLine = document.getElementById('summaryLine');
const detailView = document.getElementById('detailView');
if (summaryLine.style.display === 'none') return;
isExpanded = !isExpanded;
if (isExpanded) {
// 展开:极快淡化当前摘要,显示第一个步骤的内容
summaryLine.classList.add('expanded');
await fadeAndSwitch(summaryLine, steps[0].summary, true);
// 显示详细视图(快速)
detailView.style.display = 'block';
setTimeout(() => {
detailView.classList.add('show');
}, 10);
// 已完成的步骤快速显示,当前步骤慢速动画
for (let i = 0; i <= currentStep; i++) {
const isCurrentStep = i === currentStep && demoRunning;
await showDetailStep(i, isCurrentStep);
if (isCurrentStep) {
await sleep(400); // 只有新步骤才有较慢的动画
} else {
await sleep(50); // 已有内容快速出现
}
}
} else {
// 折叠:极快淡化第一个步骤,显示当前摘要
summaryLine.classList.remove('expanded');
await fadeAndSwitch(summaryLine, steps[currentStep].summary, true);
// 隐藏详细视图(快速)
detailView.classList.remove('show');
await sleep(150);
detailView.style.display = 'none';
// 重置所有步骤显示
document.querySelectorAll('.timeline-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
});
document.querySelectorAll('.content-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
});
}
}
// 淡化并切换文本
async function fadeAndSwitch(element, newText, fast = false) {
const summaryText = element.querySelector('.summary-text');
const duration = fast ? 75 : 200;
// 淡出
element.style.opacity = '0.3';
await sleep(duration);
// 切换文本
summaryText.textContent = newText;
// 淡入
element.style.opacity = '1';
await sleep(duration);
}
// 展开思考内容
function expandThinking(stepIndex) {
const thinkingContent = document.getElementById(`thinkingContent${stepIndex}`);
const thinkingContentFull = document.getElementById(`thinkingContentFull${stepIndex}`);
thinkingContent.style.display = 'none';
thinkingContentFull.style.display = 'block';
// 重新计算并更新竖线高度
setTimeout(() => {
updateLineHeight(stepIndex);
}, 50);
}
// 收起思考内容
function collapseThinking(stepIndex) {
const thinkingContent = document.getElementById(`thinkingContent${stepIndex}`);
const thinkingContentFull = document.getElementById(`thinkingContentFull${stepIndex}`);
thinkingContent.style.display = 'block';
thinkingContentFull.style.display = 'none';
// 重新计算并更新竖线高度
setTimeout(() => {
updateLineHeight(stepIndex);
}, 50);
}
// 重置演示
function resetDemo() {
currentStep = 0;
isExpanded = false;
demoRunning = false;
// 隐藏所有元素
document.getElementById('generatingPlaceholder').style.display = 'none';
const summaryLine = document.getElementById('summaryLine');
summaryLine.style.display = 'none';
summaryLine.classList.remove('completed', 'expanded');
summaryLine.style.opacity = '1';
document.getElementById('detailView').style.display = 'none';
document.getElementById('detailView').classList.remove('show');
document.getElementById('textOutput').style.display = 'none';
document.getElementById('textOutput').classList.remove('show');
// 重置所有步骤
document.querySelectorAll('.timeline-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
const line = item.querySelector('.timeline-line');
if (line) {
line.style.height = '0';
}
});
document.querySelectorAll('.content-item').forEach(item => {
item.style.display = 'none';
item.classList.remove('instant', 'animated');
});
// 重置思考内容
document.querySelectorAll('.thinking-content').forEach(item => {
item.style.display = 'block';
});
document.querySelectorAll('.thinking-content-full').forEach(item => {
item.style.display = 'none';
});
}
// 获取图标SVG
function getIconSVG(iconType) {
const icons = {
brain: '<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2z"></path><path d="M12 6v6l4 2"></path>',
search: '<circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path>',
terminal: '<polyline points="4 17 10 11 4 5"></polyline><line x1="12" y1="19" x2="20" y2="19"></line>'
};
return icons[iconType] || icons.brain;
}
// 工具函数:延迟
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 点击摘要行切换展开/折叠
document.getElementById('summaryLine').addEventListener('click', toggleSummary);

View File

@ -0,0 +1,503 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica', 'Arial', sans-serif;
background: #f8f9fa;
color: #1a1a1a;
line-height: 1.6;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 40px 20px;
}
.chat-area {
background: white;
border-radius: 12px;
padding: 32px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
/* 消息块 */
.message-block {
margin-bottom: 32px;
}
.message-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
font-size: 14px;
font-weight: 600;
color: #666;
}
.icon {
flex-shrink: 0;
}
/* 用户消息 */
.user-message {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.user-message .message-text {
background: rgba(0, 0, 0, 0.03);
padding: 14px 18px;
border-radius: 16px;
max-width: 60%;
font-size: 15px;
line-height: 1.5;
}
/* AI消息 */
.assistant-message {
display: flex;
flex-direction: column;
align-items: flex-start;
}
/* 等待动画 */
.generating-placeholder {
display: flex;
gap: 4px;
padding: 12px 0;
font-size: 15px;
font-weight: 500;
color: #999;
}
.generating-placeholder .letter {
display: inline-block;
animation: wave 1.6s ease-in-out infinite;
opacity: 0.4;
}
.generating-placeholder .letter:nth-child(1) { animation-delay: 0s; }
.generating-placeholder .letter:nth-child(2) { animation-delay: 0.1s; }
.generating-placeholder .letter:nth-child(3) { animation-delay: 0.2s; }
.generating-placeholder .letter:nth-child(4) { animation-delay: 0.3s; }
.generating-placeholder .letter:nth-child(5) { animation-delay: 0.4s; }
.generating-placeholder .letter:nth-child(6) { animation-delay: 0.5s; }
@keyframes wave {
0%, 100% {
opacity: 0.4;
transform: translateY(0);
}
50% {
opacity: 1;
transform: translateY(-3px);
}
}
/* 摘要行 */
.summary-line {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 10px 0;
cursor: pointer;
position: relative;
overflow: hidden;
transition: opacity 0.15s ease;
}
.summary-line:hover {
opacity: 0.7;
}
.summary-icon {
flex-shrink: 0;
color: #999;
margin-top: 2px;
}
.summary-text {
font-size: 13px;
color: #999;
position: relative;
display: inline-block;
line-height: 1.5;
}
/* 文字渐变消失效果 */
.summary-text::after {
content: '';
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 30px;
background: linear-gradient(to right, transparent, white);
pointer-events: none;
}
/* 运行中的闪光效果 */
.shimmer-overlay {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent 0%,
rgba(100, 100, 255, 0.15) 50%,
transparent 100%
);
animation: shimmer 2s infinite;
pointer-events: none;
}
@keyframes shimmer {
0% {
left: -100%;
}
100% {
left: 100%;
}
}
.summary-line.completed .shimmer-overlay {
display: none;
}
/* 摘要行展开时的连接线 */
.summary-line.expanded {
padding-bottom: 0;
}
.summary-line.expanded .summary-icon {
position: relative;
}
.summary-line.expanded .summary-icon::after {
content: '';
position: absolute;
left: 50%;
top: 100%;
transform: translateX(-50%);
width: 2px;
height: 8px;
background: #e0e0e0;
}
/* 详细视图 */
.detail-view {
margin-top: 0;
opacity: 0;
max-height: 0;
overflow: hidden;
transition: opacity 0.15s ease, max-height 0.15s ease;
}
.detail-view.show {
opacity: 1;
max-height: 2000px;
}
.timeline-container {
display: flex;
gap: 20px;
align-items: flex-start;
}
/* 时间线 */
.timeline {
display: flex;
flex-direction: column;
padding-top: 0;
flex-shrink: 0;
}
.timeline-item {
display: flex;
flex-direction: column;
align-items: center;
opacity: 0;
transform: translateY(-5px);
}
/* 第一个时间线项(没有图标,只有竖线) */
.timeline-item-first {
padding-top: 0;
}
.timeline-item-first .timeline-line {
margin-top: 0;
}
.timeline-item.instant {
animation: fadeInInstant 0.1s ease forwards;
}
.timeline-item.animated {
animation: fadeInDown 0.4s ease forwards;
}
.timeline-icon {
flex-shrink: 0;
color: #666;
background: white;
border-radius: 50%;
padding: 2px;
}
.timeline-line {
width: 2px;
background: #e0e0e0;
margin: 4px 0;
transition: height 0.2s ease;
}
.timeline-item:last-child .timeline-line {
display: none;
}
@keyframes fadeInDown {
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInInstant {
to {
opacity: 1;
transform: translateY(0);
}
}
/* 内容区域 */
.content-area {
flex: 1;
display: flex;
flex-direction: column;
gap: 0;
min-width: 0;
}
.content-item {
opacity: 0;
transform: translateX(-5px);
margin-bottom: 20px;
}
.content-item.instant {
animation: fadeInInstant 0.1s ease forwards;
}
.content-item.animated {
animation: fadeInLeft 0.4s ease forwards;
}
@keyframes fadeInLeft {
to {
opacity: 1;
transform: translateX(0);
}
}
.content-header {
font-size: 12px;
font-weight: 600;
color: #999;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
/* 第一个内容项不显示header */
.content-item[data-step="0"] .content-header {
display: none;
}
/* 思考类型的内容项不显示header */
.content-item.thinking-type .content-header {
display: none;
}
.content-body {
font-size: 14px;
line-height: 1.6;
color: #333;
}
/* 思考内容 */
.thinking-content {
color: #666;
font-size: 14px;
line-height: 1.7;
max-height: 100px;
overflow: hidden;
position: relative;
}
.thinking-content-full {
color: #666;
font-size: 14px;
line-height: 1.7;
}
.show-more-btn,
.show-less-btn {
display: inline-block;
margin-top: 8px;
padding: 4px 12px;
background: transparent;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 12px;
color: #666;
cursor: pointer;
transition: all 0.2s ease;
}
.show-more-btn:hover,
.show-less-btn:hover {
background: #f5f5f5;
border-color: #999;
}
/* 工具内容 */
.tool-intent {
font-weight: 500;
color: #444;
margin-bottom: 12px;
}
.tool-result {
background: #f8f9fa;
border-radius: 8px;
padding: 12px;
}
.result-item {
padding: 8px 0;
border-bottom: 1px solid #e0e0e0;
}
.result-item:last-child {
border-bottom: none;
}
.result-title {
font-weight: 500;
color: #333;
margin-bottom: 4px;
}
.result-url {
font-size: 12px;
color: #999;
}
/* 命令块 */
.command-block {
background: #f8f9fa;
border-radius: 8px;
overflow: hidden;
}
.command-header {
background: #e9ecef;
padding: 8px 12px;
font-size: 12px;
color: #666;
}
.command-code {
padding: 12px;
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
font-size: 13px;
color: #333;
overflow-x: auto;
}
.command-output {
padding: 12px;
border-top: 1px solid #e0e0e0;
}
.output-line {
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
font-size: 12px;
color: #666;
line-height: 1.8;
}
/* 最终输出 */
.text-output {
margin-top: 16px;
opacity: 0;
transform: translateY(10px);
transition: all 0.5s ease;
}
.text-output.show {
opacity: 1;
transform: translateY(0);
}
.text-content {
font-size: 15px;
line-height: 1.7;
color: #333;
}
.text-content p {
margin-bottom: 16px;
}
.text-content ol {
margin-left: 24px;
margin-bottom: 16px;
}
.text-content li {
margin-bottom: 12px;
}
.text-content strong {
font-weight: 600;
color: #1a1a1a;
}
/* 控制面板 */
.control-panel {
margin-top: 32px;
display: flex;
gap: 12px;
justify-content: center;
}
.control-btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.control-btn:hover {
background: #0056b3;
transform: translateY(-1px);
}
.control-btn:active {
transform: translateY(0);
}

1
static/demo/test.txt Normal file
View File

@ -0,0 +1 @@
test