chore(demo): add loader and minimal-mode preview pages
This commit is contained in:
parent
dfc763c7c5
commit
249eb663bb
708
static/demo/loaders-preview.html
Normal file
708
static/demo/loaders-preview.html
Normal 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
123
static/demo/loaders-v2.html
Normal 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>
|
||||||
195
static/demo/minimal-mode-v2/index.html
Normal file
195
static/demo/minimal-mode-v2/index.html
Normal 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>
|
||||||
413
static/demo/minimal-mode-v2/script.js
Normal file
413
static/demo/minimal-mode-v2/script.js
Normal 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);
|
||||||
448
static/demo/minimal-mode-v2/style.css
Normal file
448
static/demo/minimal-mode-v2/style.css
Normal 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);
|
||||||
|
}
|
||||||
191
static/demo/minimal-mode/index.html
Normal file
191
static/demo/minimal-mode/index.html
Normal 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>
|
||||||
191
static/demo/minimal-mode/index.html.backup
Normal file
191
static/demo/minimal-mode/index.html.backup
Normal 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>
|
||||||
333
static/demo/minimal-mode/script.js
Normal file
333
static/demo/minimal-mode/script.js
Normal 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);
|
||||||
503
static/demo/minimal-mode/style.css
Normal file
503
static/demo/minimal-mode/style.css
Normal 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
1
static/demo/test.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
test
|
||||||
Loading…
Reference in New Issue
Block a user