feat: 扩展多CLI详细页面样式,更新任务卡片和决策状态显示

This commit is contained in:
catlog22
2026-01-14 18:47:23 +08:00
parent aeb111420e
commit 49845fe1ae
2 changed files with 372 additions and 16 deletions

View File

@@ -2012,3 +2012,357 @@
font-size: 0.875rem;
}
/* ===================================
Multi-CLI Detail Page Extended Styles
=================================== */
/* Scope Lists */
.scope-list {
display: flex;
flex-direction: column;
gap: 0.375rem;
margin: 0;
padding-left: 1rem;
font-size: 0.85rem;
}
.scope-list li {
padding: 0.375rem 0.5rem;
background: hsl(var(--muted) / 0.3);
border-radius: 0.25rem;
font-family: var(--font-mono);
color: hsl(var(--foreground));
line-height: 1.4;
}
.scope-list.excluded li {
background: hsl(var(--destructive) / 0.08);
color: hsl(var(--muted-foreground));
text-decoration: line-through;
opacity: 0.8;
}
/* Acceptance List */
.acceptance-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.acceptance-item {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.75rem;
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 0.375rem;
transition: border-color 0.2s ease;
}
.acceptance-item:hover {
border-color: hsl(var(--primary) / 0.3);
}
.acceptance-item.met {
border-color: hsl(var(--success, 142 70% 45%) / 0.5);
background: hsl(var(--success, 142 70% 45%) / 0.03);
}
.acceptance-item.unmet {
border-color: hsl(var(--destructive) / 0.3);
background: hsl(var(--destructive) / 0.02);
}
.acceptance-check {
display: flex;
align-items: center;
justify-content: center;
width: 1.25rem;
height: 1.25rem;
border-radius: 0.25rem;
flex-shrink: 0;
margin-top: 0.125rem;
}
.acceptance-item.met .acceptance-check {
background: hsl(var(--success, 142 70% 45%));
color: white;
}
.acceptance-item.unmet .acceptance-check {
background: hsl(var(--muted));
border: 1px solid hsl(var(--border));
color: hsl(var(--muted-foreground));
}
.acceptance-check i {
width: 0.75rem;
height: 0.75rem;
}
.acceptance-id {
font-weight: 600;
font-size: 0.75rem;
color: hsl(var(--primary));
margin-bottom: 0.25rem;
}
.acceptance-desc {
font-size: 0.85rem;
color: hsl(var(--foreground));
line-height: 1.5;
}
/* Decision Status Bar */
.decision-status-bar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 1rem;
background: hsl(var(--muted) / 0.3);
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
margin-bottom: 1rem;
}
.decision-status-bar.converged {
border-color: hsl(var(--success, 142 70% 45%) / 0.5);
background: hsl(var(--success, 142 70% 45%) / 0.05);
}
.decision-status-bar.divergent {
border-color: hsl(var(--warning, 45 90% 50%) / 0.5);
background: hsl(var(--warning, 45 90% 50%) / 0.05);
}
.decision-summary {
display: flex;
flex-direction: column;
gap: 0.5rem;
flex: 1;
}
.decision-summary-text {
font-size: 0.875rem;
color: hsl(var(--foreground));
line-height: 1.5;
}
.decision-confidence {
display: flex;
align-items: center;
gap: 0.75rem;
}
.decision-confidence-label {
font-size: 0.75rem;
font-weight: 500;
color: hsl(var(--muted-foreground));
}
.decision-confidence-bar {
width: 100px;
height: 8px;
background: hsl(var(--muted));
border-radius: 4px;
overflow: hidden;
}
.decision-confidence-fill {
height: 100%;
border-radius: 4px;
transition: width 0.3s ease;
}
.decision-status-bar.converged .decision-confidence-fill {
background: hsl(var(--success, 142 70% 45%));
}
.decision-status-bar.divergent .decision-confidence-fill {
background: hsl(var(--warning, 45 90% 50%));
}
.decision-confidence-value {
font-size: 0.8rem;
font-weight: 600;
color: hsl(var(--foreground));
}
/* Pros and Cons Lists */
.pros-list,
.cons-list {
display: flex;
flex-direction: column;
gap: 0.375rem;
margin: 0;
padding: 0;
list-style: none;
}
.pro-item,
.con-item {
display: flex;
align-items: flex-start;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
border-radius: 0.375rem;
font-size: 0.85rem;
line-height: 1.5;
color: hsl(var(--foreground));
}
.pro-item {
background: hsl(142 71% 45% / 0.08);
border-left: 3px solid #10b981;
}
.pro-item::before {
content: "+";
font-weight: 700;
color: #10b981;
flex-shrink: 0;
}
.con-item {
background: hsl(0 84% 60% / 0.08);
border-left: 3px solid #ef4444;
}
.con-item::before {
content: "-";
font-weight: 700;
color: #ef4444;
flex-shrink: 0;
}
/* Rounds Navigation */
.rounds-nav {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
padding-bottom: 0.75rem;
border-bottom: 1px solid hsl(var(--border));
margin-bottom: 1rem;
}
.round-item {
padding: 0.5rem 0.875rem;
background: hsl(var(--muted));
border: 1px solid hsl(var(--border));
border-radius: 0.375rem;
font-size: 0.8rem;
font-weight: 500;
color: hsl(var(--muted-foreground));
cursor: pointer;
transition: all 0.2s ease;
}
.round-item:hover {
background: hsl(var(--hover));
border-color: hsl(var(--purple, 280 60% 50%) / 0.4);
color: hsl(var(--foreground));
}
.round-item.active {
background: hsl(var(--purple, 280 60% 50%));
border-color: hsl(var(--purple, 280 60% 50%));
color: white;
}
/* Timeline Event Parts */
.event-type {
display: inline-block;
padding: 0.125rem 0.5rem;
background: hsl(var(--primary) / 0.1);
color: hsl(var(--primary));
border-radius: 0.25rem;
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.025em;
}
.event-type.proposal {
background: hsl(var(--primary) / 0.1);
color: hsl(var(--primary));
}
.event-type.analysis {
background: hsl(var(--info, 220 80% 55%) / 0.1);
color: hsl(var(--info, 220 80% 55%));
}
.event-type.decision {
background: hsl(var(--success, 142 70% 45%) / 0.1);
color: hsl(var(--success, 142 70% 45%));
}
.event-type.conflict {
background: hsl(var(--warning, 45 90% 50%) / 0.1);
color: hsl(var(--warning, 45 90% 40%));
}
.event-type.resolution {
background: hsl(var(--purple, 280 60% 50%) / 0.1);
color: hsl(var(--purple, 280 60% 50%));
}
.event-contributor {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.8rem;
font-weight: 500;
color: hsl(var(--purple, 280 60% 50%));
}
.event-contributor i {
width: 0.875rem;
height: 0.875rem;
}
.event-summary {
font-size: 0.875rem;
font-weight: 500;
color: hsl(var(--foreground));
line-height: 1.5;
margin: 0.5rem 0;
}
.event-evidence {
font-size: 0.8rem;
color: hsl(var(--muted-foreground));
line-height: 1.5;
padding: 0.5rem 0.75rem;
background: hsl(var(--muted) / 0.5);
border-radius: 0.375rem;
border-left: 2px solid hsl(var(--border));
margin-top: 0.5rem;
}
.event-evidence code {
font-size: 0.75rem;
padding: 0.125rem 0.375rem;
background: hsl(var(--muted));
border-radius: 0.25rem;
color: hsl(var(--primary));
}
/* Timeline Connecting Line */
.timeline-event::before {
content: "";
position: absolute;
left: 0.9375rem;
top: 1.75rem;
bottom: -0.5rem;
width: 2px;
background: hsl(var(--border));
z-index: 0;
}
.timeline-event:last-child::before {
display: none;
}

View File

@@ -750,7 +750,7 @@ function renderMultiCliPlanningTab(session) {
<div class="acceptance-list">
${acceptanceCriteria.map(ac => `
<div class="acceptance-item ${ac.isMet ? 'met' : 'unmet'}">
<span class="acceptance-check">${ac.isMet ? '&#10003;' : '&#9675;'}</span>
<span class="acceptance-check"><i data-lucide="${ac.isMet ? 'check' : 'circle'}" class="w-3 h-3"></i></span>
<span class="acceptance-id">${escapeHtml(ac.id || '')}</span>
<span class="acceptance-desc">${escapeHtml(getI18nText(ac.description))}</span>
</div>
@@ -822,17 +822,19 @@ function renderMultiCliDecisionTab(session) {
// Decision Status and Summary
sections.push(`
<div class="multi-cli-section decision-header-section">
<div class="decision-status-bar">
<span class="decision-status ${status}">${escapeHtml(status)}</span>
<span class="confidence-meter">
<span class="confidence-label">${t('multiCli.confidence') || 'Confidence'}:</span>
<span class="confidence-bar">
<span class="confidence-fill" style="width: ${(confidenceScore * 100).toFixed(0)}%"></span>
</span>
<span class="confidence-value">${(confidenceScore * 100).toFixed(0)}%</span>
</span>
<div class="decision-status-bar ${confidenceScore >= 0.7 ? 'converged' : 'divergent'}">
<div class="decision-status-wrapper">
<span class="decision-status ${status}">${escapeHtml(status)}</span>
</div>
<div class="decision-confidence">
<span class="decision-confidence-label">${t('multiCli.confidence') || 'Confidence'}:</span>
<div class="decision-confidence-bar">
<div class="decision-confidence-fill" style="width: ${(confidenceScore * 100).toFixed(0)}%"></div>
</div>
<span class="decision-confidence-value">${(confidenceScore * 100).toFixed(0)}%</span>
</div>
</div>
${summary ? `<p class="decision-summary">${escapeHtml(summary)}</p>` : ''}
${summary ? `<p class="decision-summary-text">${escapeHtml(summary)}</p>` : ''}
</div>
`);
@@ -888,15 +890,15 @@ function renderSolutionCard(solution, isSelected) {
${rejectionReason ? `<div class="rejection-reason"><strong>${t('multiCli.rejectionReason') || 'Reason'}:</strong> ${escapeHtml(rejectionReason)}</div>` : ''}
<div class="solution-details">
${pros.length ? `
<div class="pros-list">
<div class="pros-section">
<strong>${t('multiCli.pros') || 'Pros'}:</strong>
<ul>${pros.map(p => `<li class="pro-item">${escapeHtml(getI18nText(p))}</li>`).join('')}</ul>
<ul class="pros-list">${pros.map(p => `<li class="pro-item">${escapeHtml(getI18nText(p))}</li>`).join('')}</ul>
</div>
` : ''}
${cons.length ? `
<div class="cons-list">
<div class="cons-section">
<strong>${t('multiCli.cons') || 'Cons'}:</strong>
<ul>${cons.map(c => `<li class="con-item">${escapeHtml(getI18nText(c))}</li>`).join('')}</ul>
<ul class="cons-list">${cons.map(c => `<li class="con-item">${escapeHtml(getI18nText(c))}</li>`).join('')}</ul>
</div>
` : ''}
${effort ? `<div class="effort-estimate"><strong>${t('multiCli.effort') || 'Effort'}:</strong> ${escapeHtml(effort)}</div>` : ''}
@@ -950,7 +952,7 @@ function renderMultiCliTimelineTab(session) {
<div class="timeline-content">
<div class="event-header">
<span class="event-type ${event.type || ''}">${escapeHtml(event.type || 'event')}</span>
<span class="event-contributor">${escapeHtml(contributor.name || 'Unknown')}</span>
<span class="event-contributor"><i data-lucide="user" class="w-3.5 h-3.5"></i>${escapeHtml(contributor.name || 'Unknown')}</span>
<span class="event-time">${formatDate(event.timestamp)}</span>
</div>
<div class="event-summary">${escapeHtml(summary)}</div>