LifeFlow-AI / ui /components /progress_stepper.py
Marco310's picture
feat: Complete UI/UX redesign and fix critical workflow bugs
6b71d3d
raw
history blame
5 kB
"""
LifeFlow AI - Progress Stepper Component
✅ 顯示用戶當前所在步驟
✅ 視覺化流程進度
"""
import gradio as gr
def create_progress_stepper(current_step: int = 1):
"""
創建流程進度條
Args:
current_step: 當前步驟 (1-4)
1: Analyze
2: Confirm
3: Optimize
4: Review
Returns:
HTML 組件
"""
steps = [
{'num': 1, 'label': 'Analyze', 'icon': '📋', 'desc': 'Extract tasks'},
{'num': 2, 'label': 'Confirm', 'icon': '✅', 'desc': 'Review & modify'},
{'num': 3, 'label': 'Optimize', 'icon': '⚡', 'desc': 'Route planning'},
{'num': 4, 'label': 'Review', 'icon': '🎉', 'desc': 'Check results'}
]
html = '<div class="progress-stepper">'
for i, step in enumerate(steps):
is_active = step['num'] == current_step
is_complete = step['num'] < current_step
state_class = ''
if is_complete:
state_class = 'complete'
elif is_active:
state_class = 'active'
html += f"""
<div class="step {state_class}">
<div class="step-number">{step['icon']}</div>
<div class="step-label">{step['label']}</div>
<div class="step-desc">{step['desc']}</div>
</div>
"""
# 添加連接線
if i < len(steps) - 1:
connector_class = 'complete' if is_complete else ''
html += f'<div class="step-connector {connector_class}"></div>'
html += '</div>'
# 內嵌樣式
css = """
<style>
.progress-stepper {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24px;
background: white;
border-radius: 16px;
margin-bottom: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.step {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
flex: 1;
min-width: 80px;
}
.step-number {
width: 56px;
height: 56px;
border-radius: 50%;
background: #e2e8f0;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin-bottom: 8px;
}
.step.active .step-number {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
color: white;
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.2), 0 4px 8px rgba(0, 0, 0, 0.15);
transform: scale(1.1);
animation: pulse-ring 2s infinite;
}
.step.complete .step-number {
background: #10b981;
color: white;
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
}
.step-label {
margin-top: 8px;
font-size: 14px;
font-weight: 600;
color: #64748b;
transition: color 0.3s;
}
.step.active .step-label {
color: #6366f1;
font-weight: 700;
}
.step.complete .step-label {
color: #10b981;
}
.step-desc {
font-size: 11px;
color: #94a3b8;
margin-top: 4px;
text-align: center;
}
.step-connector {
flex: 1;
height: 3px;
background: #e2e8f0;
margin: 0 8px;
transition: background 0.3s;
position: relative;
top: -20px;
}
.step-connector.complete {
background: #10b981;
}
@keyframes pulse-ring {
0% {
box-shadow: 0 0 0 0 rgba(99, 102, 241, 0.7), 0 4px 8px rgba(0, 0, 0, 0.15);
}
50% {
box-shadow: 0 0 0 8px rgba(99, 102, 241, 0), 0 4px 8px rgba(0, 0, 0, 0.15);
}
100% {
box-shadow: 0 0 0 0 rgba(99, 102, 241, 0), 0 4px 8px rgba(0, 0, 0, 0.15);
}
}
/* 響應式 */
@media (max-width: 768px) {
.progress-stepper {
padding: 16px 8px;
}
.step {
min-width: 60px;
}
.step-number {
width: 44px;
height: 44px;
font-size: 18px;
}
.step-label {
font-size: 12px;
}
.step-desc {
display: none;
}
.step-connector {
margin: 0 4px;
}
}
@media (max-width: 480px) {
.progress-stepper {
flex-wrap: wrap;
gap: 12px;
}
.step-connector {
display: none;
}
.step {
flex-direction: row;
gap: 8px;
width: calc(50% - 6px);
}
.step-number {
width: 36px;
height: 36px;
font-size: 16px;
}
}
</style>
"""
return gr.HTML(css + html)
def update_stepper(step_number: int):
"""更新進度條到指定步驟"""
return create_progress_stepper(step_number)