diff --git a/src/webview/maturity/main.ts b/src/webview/maturity/main.ts index 3f7dea7b..e2213d76 100644 --- a/src/webview/maturity/main.ts +++ b/src/webview/maturity/main.ts @@ -1,6 +1,7 @@ // Maturity Score webview import { buttonHtml } from '../shared/buttonConfig'; import type { ContextReferenceUsage } from '../shared/contextRefUtils'; +import themeStyles from '../shared/theme.css'; import styles from './styles.css'; // ── Types ────────────────────────────────────────────────────────────── @@ -113,7 +114,7 @@ function renderRadarChart(categories: CategoryScore[]): string { const angle = startAngle + i * angleStep; return `${cx + r * Math.cos(angle)},${cy + r * Math.sin(angle)}`; }).join(' '); - return ``; + return ``; }).join(''); // Axis lines @@ -121,7 +122,7 @@ function renderRadarChart(categories: CategoryScore[]): string { const angle = startAngle + i * angleStep; const x2 = cx + maxR * Math.cos(angle); const y2 = cy + maxR * Math.sin(angle); - return ``; + return ``; }).join(''); // Data polygon @@ -142,7 +143,7 @@ function renderRadarChart(categories: CategoryScore[]): string { if (Math.cos(angle) < -0.3) { anchor = 'end'; } else if (Math.cos(angle) > 0.3) { anchor = 'start'; } return `${cat.icon} ${cat.category}`; + class="radar-label" font-size="14" font-weight="600">${cat.icon} ${cat.category}`; }).join(''); // Stage dots @@ -152,13 +153,13 @@ function renderRadarChart(categories: CategoryScore[]): string { const x = cx + r * Math.cos(angle); const y = cy + r * Math.sin(angle); const color = stageColor(cat.stage); - return ``; + return ``; }).join(''); // Ring labels const ringLabels = [1, 2, 3, 4].map(level => { const r = (level / 4) * maxR; - return `${level}`; + return `${level}`; }).join(''); return ` @@ -384,6 +385,7 @@ function renderLayout(data: MaturityData): void { }).join(''); root.innerHTML = ` +
diff --git a/src/webview/maturity/styles.css b/src/webview/maturity/styles.css index 0fa6aca5..022dc8a4 100644 --- a/src/webview/maturity/styles.css +++ b/src/webview/maturity/styles.css @@ -6,19 +6,19 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background: #0e0e0f; - color: #e7e7e7; + background: var(--bg-primary); + color: var(--text-primary); padding: 16px; line-height: 1.5; min-width: 320px; } .container { - background: linear-gradient(135deg, #1b1b1e 0%, #1f1f22 100%); - border: 1px solid #2e2e34; + background: var(--bg-secondary); + border: 1px solid var(--border-color); border-radius: 10px; padding: 16px; - box-shadow: 0 4px 10px rgb(0 0 0 / 28%); + box-shadow: 0 4px 10px var(--shadow-color); max-width: 1200px; margin: 0 auto; } @@ -45,7 +45,7 @@ body { .header-title { font-size: 16px; font-weight: 700; - color: #fff; + color: var(--text-primary); letter-spacing: 0.2px; } @@ -57,8 +57,8 @@ body { /* Overall stage banner */ .stage-banner { - background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); - border: 1px solid #2a2a40; + background: var(--bg-tertiary); + border: 1px solid var(--border-color); border-radius: 10px; padding: 20px 24px; margin-bottom: 16px; @@ -67,7 +67,7 @@ body { .stage-banner-label { font-size: 12px; - color: #a0a0b0; + color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1.5px; margin-bottom: 6px; @@ -81,14 +81,25 @@ body { .stage-banner-subtitle { font-size: 13px; - color: #b8b8c8; + color: var(--text-secondary); } +/* Stage accent colors — dark theme defaults */ .stage-1 { color: #93c5fd; } .stage-2 { color: #6ee7b7; } .stage-3 { color: #3b82f6; } .stage-4 { color: #10b981; } +/* Light theme: darken pale stage colors for readable contrast */ +body[data-vscode-theme-kind="vscode-light"] .stage-1, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .stage-1 { color: #1d6fa4 !important; } +body[data-vscode-theme-kind="vscode-light"] .stage-2, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .stage-2 { color: #059669 !important; } +body[data-vscode-theme-kind="vscode-light"] .stage-3, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .stage-3 { color: #2563eb !important; } +body[data-vscode-theme-kind="vscode-light"] .stage-4, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .stage-4 { color: #059669 !important; } + /* Radar / spider chart container */ .radar-wrapper { display: flex; @@ -109,10 +120,27 @@ body { height: auto; } +/* SVG radar chart elements — use CSS fill/stroke so theme variables apply */ +.radar-svg .radar-label { + fill: var(--text-primary); +} + +.radar-svg .radar-ring-label { + fill: var(--text-muted); +} + +.radar-svg .radar-grid { + stroke: var(--border-subtle); +} + +.radar-svg .radar-dot { + stroke: var(--bg-primary); +} + /* Legend panel */ .legend-panel { - background: #18181b; - border: 1px solid #2a2a30; + background: var(--bg-tertiary); + border: 1px solid var(--border-subtle); border-radius: 8px; padding: 16px; min-width: 280px; @@ -123,10 +151,10 @@ body { .legend-title { font-size: 14px; font-weight: 700; - color: #fff; + color: var(--text-primary); margin-bottom: 14px; padding-bottom: 10px; - border-bottom: 1px solid #2a2a30; + border-bottom: 1px solid var(--border-subtle); } .legend-item { @@ -146,7 +174,7 @@ body { border-radius: 50%; flex-shrink: 0; margin-top: 2px; - border: 2px solid #fff; + border: 2px solid var(--bg-primary); } .stage-1-dot { background: #93c5fd; } @@ -161,13 +189,13 @@ body { .legend-label { font-size: 12px; font-weight: 600; - color: #e7e7e7; + color: var(--text-primary); margin-bottom: 2px; } .legend-desc { font-size: 11px; - color: #999; + color: var(--text-muted); line-height: 1.4; } @@ -180,11 +208,11 @@ body { } .category-card { - background: #18181b; - border: 1px solid #2a2a30; + background: var(--bg-tertiary); + border: 1px solid var(--border-subtle); border-radius: 8px; padding: 14px; - box-shadow: 0 2px 6px rgb(0 0 0 / 24%); + box-shadow: 0 2px 6px var(--shadow-color); } .category-header { @@ -197,7 +225,7 @@ body { .category-name { font-size: 14px; font-weight: 700; - color: #fff; + color: var(--text-primary); } .category-stage-badge { @@ -208,39 +236,50 @@ body { letter-spacing: 0.5px; } +/* Dark theme badge backgrounds */ .badge-1 { - background: #152040; + background: rgba(147, 197, 253, 0.15); color: #93c5fd; - border: 1px solid #93c5fd80; + border: 1px solid rgba(147, 197, 253, 0.4); } .badge-2 { - background: #0d2d20; + background: rgba(110, 231, 183, 0.15); color: #6ee7b7; - border: 1px solid #6ee7b780; + border: 1px solid rgba(110, 231, 183, 0.4); } .badge-3 { - background: #152040; + background: rgba(59, 130, 246, 0.15); color: #3b82f6; - border: 1px solid #3b82f680; + border: 1px solid rgba(59, 130, 246, 0.4); } .badge-4 { - background: #0d2d20; + background: rgba(16, 185, 129, 0.15); color: #10b981; - border: 1px solid #10b98180; + border: 1px solid rgba(16, 185, 129, 0.4); } +/* Light theme badge overrides — use darker text for contrast */ +body[data-vscode-theme-kind="vscode-light"] .badge-1, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .badge-1 { color: #1d6fa4; } +body[data-vscode-theme-kind="vscode-light"] .badge-2, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .badge-2 { color: #059669; } +body[data-vscode-theme-kind="vscode-light"] .badge-3, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .badge-3 { color: #2563eb; } +body[data-vscode-theme-kind="vscode-light"] .badge-4, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .badge-4 { color: #059669; } + .category-stage-label { font-size: 11px; - color: #999; + color: var(--text-muted); margin-bottom: 10px; } /* Progress bar for category */ .category-progress { - background: #242429; + background: var(--row-alternate-bg); height: 6px; border-radius: 3px; overflow: hidden; @@ -265,7 +304,7 @@ body { gap: 8px; padding: 4px 0; font-size: 12px; - color: #c0c0c0; + color: var(--text-secondary); } .evidence-icon { @@ -276,8 +315,8 @@ body { /* Tips section */ .tips-section { - background: #1b1b1e; - border: 1px solid #2a2a30; + background: var(--bg-secondary); + border: 1px solid var(--border-subtle); border-radius: 8px; padding: 14px; margin-bottom: 16px; @@ -286,7 +325,7 @@ body { .tips-title { font-size: 14px; font-weight: 700; - color: #fff; + color: var(--text-primary); margin-bottom: 10px; display: flex; align-items: center; @@ -294,36 +333,36 @@ body { } .tip-item { - background: #18181b; - border: 1px solid #2a2a30; + background: var(--list-hover-bg); + border: 1px solid var(--border-subtle); border-radius: 6px; padding: 10px 12px; margin-bottom: 8px; font-size: 12px; - color: #d0d0d0; + color: var(--text-primary); } .tip-item strong { - color: #60a5fa; + color: var(--link-color); } .tip-item a { - color: #60a5fa; + color: var(--link-color); text-decoration: none; border-bottom: 1px solid transparent; transition: border-color 0.2s ease; } .tip-item a:hover { - border-bottom-color: #60a5fa; + border-bottom-color: var(--link-color); } /* MCP Discovery Button */ .mcp-discover-btn { width: 100%; - background: linear-gradient(135deg, #1e3a5f 0%, #2a4a7c 100%); - border: 1px solid #3b82f6; - color: #60a5fa; + background: var(--button-bg); + border: 1px solid var(--button-bg); + color: var(--button-fg); padding: 10px 14px; border-radius: 6px; font-size: 12px; @@ -337,22 +376,19 @@ body { } .mcp-discover-btn:hover { - background: linear-gradient(135deg, #2a4a7c 0%, #3b5f99 100%); - border-color: #60a5fa; - color: #fff; + background: var(--button-hover-bg); transform: translateY(-1px); - box-shadow: 0 4px 8px rgb(59, 130, 246, 0.2); + box-shadow: 0 4px 8px var(--shadow-color); } .mcp-discover-btn:active { transform: translateY(0); - box-shadow: 0 2px 4px rgb(59, 130, 246, 0.15); } .dismiss-tips-btn { background: transparent; - border: 1px solid #3a3a40; - color: #888; + border: 1px solid var(--border-subtle); + color: var(--text-muted); padding: 2px 6px; border-radius: 4px; font-size: 11px; @@ -362,9 +398,9 @@ body { } .dismiss-tips-btn:hover { - background: #2a2a30; - border-color: #555; - color: #ccc; + background: var(--list-hover-bg); + border-color: var(--border-color); + color: var(--text-secondary); } .dismiss-tips-btn:active { @@ -372,27 +408,27 @@ body { } .info-box { - background: #1b1b1e; - border: 1px solid #2a2a30; + background: var(--bg-tertiary); + border: 1px solid var(--border-subtle); border-radius: 6px; padding: 12px; margin-bottom: 16px; font-size: 12px; - color: #c8c8c8; + color: var(--text-secondary); } .info-box-title { font-weight: 600; - color: #fff; + color: var(--text-primary); margin-bottom: 6px; } .footer { margin-top: 6px; padding-top: 12px; - border-top: 1px solid #2a2a30; + border-top: 1px solid var(--border-subtle); font-size: 11px; - color: #a0a0a0; + color: var(--text-muted); display: flex; justify-content: space-between; align-items: center; @@ -406,9 +442,9 @@ body { .reset-tips-btn { display: inline-block; padding: 4px 10px; - background: linear-gradient(135deg, #1e3a5f 0%, #2a4a70 100%); - border: 1px solid #3b82f6; - color: #93c5fd; + background: var(--button-secondary-bg); + border: 1px solid var(--border-color); + color: var(--button-secondary-fg); border-radius: 4px; font-size: 10px; font-weight: 600; @@ -419,24 +455,21 @@ body { } .reset-tips-btn:hover { - background: linear-gradient(135deg, #2a4a70 0%, #3a5a80 100%); - border-color: #60a5fa; - color: #dbeafe; + background: var(--button-secondary-hover-bg); transform: translateY(-1px); - box-shadow: 0 2px 6px rgb(59, 130, 246, 0.3); + box-shadow: 0 2px 6px var(--shadow-color); } .reset-tips-btn:active { transform: translateY(0); - box-shadow: 0 1px 3px rgb(59, 130, 246, 0.2); } .inline-action-btn { display: inline-block; padding: 2px 8px; - background: linear-gradient(135deg, #1e3a5f 0%, #2a4a70 100%); - border: 1px solid #3b82f6; - color: #93c5fd; + background: var(--button-secondary-bg); + border: 1px solid var(--border-color); + color: var(--button-secondary-fg); border-radius: 4px; font-size: 11px; font-weight: 600; @@ -447,16 +480,13 @@ body { } .inline-action-btn:hover { - background: linear-gradient(135deg, #2a4a70 0%, #3a5a80 100%); - border-color: #60a5fa; - color: #dbeafe; + background: var(--button-secondary-hover-bg); transform: translateY(-1px); - box-shadow: 0 2px 6px rgb(59, 130, 246, 0.3); + box-shadow: 0 2px 6px var(--shadow-color); } .inline-action-btn:active { transform: translateY(0); - box-shadow: 0 1px 3px rgb(59, 130, 246, 0.2); } /* Beta warning footer */ @@ -466,17 +496,17 @@ body { gap: 10px; margin-top: 12px; padding: 12px 14px; - background: #3b2c10; - border: 1px solid #f59e0b80; + background: rgba(245, 158, 11, 0.1); + border: 1px solid rgba(245, 158, 11, 0.4); border-radius: 6px; font-size: 12px; - color: #f5d78e; + color: var(--warning-fg); } /* Share to social media section */ .share-section { - background: linear-gradient(135deg, #1b1b1e 0%, #1f1f22 100%); - border: 1px solid #2a2a40; + background: var(--bg-tertiary); + border: 1px solid var(--border-color); border-radius: 8px; padding: 18px; margin-top: 16px; @@ -497,12 +527,12 @@ body { .share-title { font-size: 16px; font-weight: 700; - color: #fff; + color: var(--text-primary); } .share-description { font-size: 12px; - color: #b8b8c8; + color: var(--text-secondary); margin-bottom: 14px; line-height: 1.5; } @@ -525,7 +555,7 @@ body { cursor: pointer; transition: all 0.2s ease; border: 1px solid; - background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + background: var(--button-secondary-bg); } .share-btn-icon { @@ -535,56 +565,62 @@ body { .share-btn-linkedin { color: #0a66c2; - border-color: #0a66c280; - background: linear-gradient(135deg, #0a2540 0%, #0d3050 100%); + border-color: rgba(10, 102, 194, 0.5); } .share-btn-linkedin:hover { - background: linear-gradient(135deg, #0d3050 0%, #0f3d60 100%); + background: rgba(10, 102, 194, 0.12); border-color: #0a66c2; transform: translateY(-2px); - box-shadow: 0 4px 12px rgb(10, 102, 194, 0.3); + box-shadow: 0 4px 12px rgba(10, 102, 194, 0.25); } .share-btn-bluesky { color: #1285fe; - border-color: #1285fe80; - background: linear-gradient(135deg, #0a2540 0%, #0d3550 100%); + border-color: rgba(18, 133, 254, 0.5); } .share-btn-bluesky:hover { - background: linear-gradient(135deg, #0d3550 0%, #104060 100%); + background: rgba(18, 133, 254, 0.12); border-color: #1285fe; transform: translateY(-2px); - box-shadow: 0 4px 12px rgb(18, 133, 254, 0.3); + box-shadow: 0 4px 12px rgba(18, 133, 254, 0.25); } .share-btn-mastodon { color: #6364ff; - border-color: #6364ff80; - background: linear-gradient(135deg, #1a1a3e 0%, #20204e 100%); + border-color: rgba(99, 100, 255, 0.5); } .share-btn-mastodon:hover { - background: linear-gradient(135deg, #20204e 0%, #28285e 100%); + background: rgba(99, 100, 255, 0.12); border-color: #6364ff; transform: translateY(-2px); - box-shadow: 0 4px 12px rgb(99, 100, 255, 0.3); + box-shadow: 0 4px 12px rgba(99, 100, 255, 0.25); } .share-btn-download { color: #10b981; - border-color: #10b98180; - background: linear-gradient(135deg, #0d2d20 0%, #123d2a 100%); + border-color: rgba(16, 185, 129, 0.5); } .share-btn-download:hover { - background: linear-gradient(135deg, #123d2a 0%, #164d34 100%); + background: rgba(16, 185, 129, 0.12); border-color: #10b981; transform: translateY(-2px); - box-shadow: 0 4px 12px rgb(16, 185, 129, 0.3); + box-shadow: 0 4px 12px rgba(16, 185, 129, 0.25); } +/* Light theme overrides for share button text colors */ +body[data-vscode-theme-kind="vscode-light"] .share-btn-linkedin, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .share-btn-linkedin { color: #0a66c2; } +body[data-vscode-theme-kind="vscode-light"] .share-btn-bluesky, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .share-btn-bluesky { color: #0369a1; } +body[data-vscode-theme-kind="vscode-light"] .share-btn-mastodon, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .share-btn-mastodon { color: #4f46e5; } +body[data-vscode-theme-kind="vscode-light"] .share-btn-download, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .share-btn-download { color: #059669; } + .export-dropdown-container { position: relative; } @@ -601,10 +637,10 @@ body { left: 0; right: 0; margin-top: 4px; - background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); - border: 1px solid #2e2e34; + background: var(--bg-secondary); + border: 1px solid var(--border-color); border-radius: 6px; - box-shadow: 0 4px 12px rgb(0 0 0 / 30%); + box-shadow: 0 4px 12px var(--shadow-color); z-index: 1000; overflow: hidden; } @@ -617,7 +653,7 @@ body { padding: 12px 16px; border: none; background: transparent; - color: #e7e7e7; + color: var(--text-primary); font-size: 13px; font-weight: 600; cursor: pointer; @@ -626,11 +662,11 @@ body { } .export-menu-item:hover { - background: rgba(59, 130, 246, 0.15); + background: var(--list-hover-bg); } .export-menu-item:active { - background: rgba(59, 130, 246, 0.25); + background: var(--list-active-bg); } .export-menu-icon { @@ -653,19 +689,20 @@ body { } .beta-link { - color: #f59e0b; + color: var(--warning-fg); text-decoration: underline; } .beta-link:hover { - color: #fbbf24; + color: var(--warning-fg); + opacity: 0.8; } .share-issue-btn { flex-shrink: 0; - background: linear-gradient(135deg, #3b2c10 0%, #4a3815 100%); - border: 1px solid #f59e0b; - color: #f5d78e; + background: rgba(245, 158, 11, 0.1); + border: 1px solid var(--warning-fg); + color: var(--warning-fg); padding: 6px 14px; border-radius: 6px; font-size: 12px; @@ -676,16 +713,13 @@ body { } .share-issue-btn:hover { - background: linear-gradient(135deg, #4a3815 0%, #5a4520 100%); - border-color: #fbbf24; - color: #fff; + background: rgba(245, 158, 11, 0.2); transform: translateY(-1px); - box-shadow: 0 4px 8px rgb(245, 158, 11, 0.2); + box-shadow: 0 4px 8px rgba(245, 158, 11, 0.2); } .share-issue-btn:active { transform: translateY(0); - box-shadow: 0 2px 4px rgb(245, 158, 11, 0.15); } @media (width <= 768px) { @@ -710,8 +744,8 @@ body { /* Demo mode controls */ .demo-panel { - background: linear-gradient(135deg, #1a1a2e 0%, #1e2a3a 100%); - border: 1px solid #3b82f680; + background: var(--bg-tertiary); + border: 1px solid var(--border-color); border-radius: 8px; padding: 14px; margin-bottom: 16px; @@ -723,7 +757,7 @@ body { align-items: center; margin-bottom: 12px; padding-bottom: 10px; - border-bottom: 1px solid #2a3a50; + border-bottom: 1px solid var(--border-subtle); } .demo-panel-header.demo-collapsed { @@ -735,7 +769,7 @@ body { .demo-panel-title { font-size: 13px; font-weight: 700; - color: #60a5fa; + color: var(--link-color); display: flex; align-items: center; gap: 8px; @@ -744,7 +778,7 @@ body { .demo-expand-btn { background: transparent; border: none; - color: #60a5fa; + color: var(--link-color); font-size: 12px; cursor: pointer; padding: 2px 4px; @@ -753,7 +787,7 @@ body { } .demo-expand-btn:hover { - color: #93bbfd; + color: var(--link-hover-color); transform: scale(1.1); } @@ -777,26 +811,25 @@ body { } .demo-btn-toggle { - background: #1e3a5f; - border-color: #3b82f6; - color: #60a5fa; + background: var(--button-bg); + border-color: var(--button-bg); + color: var(--button-fg); } .demo-btn-toggle:hover { - background: #2a4a7c; - color: #93bbfd; + background: var(--button-hover-bg); } .demo-btn-reset { background: transparent; - border-color: #555; - color: #999; + border-color: var(--border-subtle); + color: var(--text-muted); } .demo-btn-reset:hover { - background: #2a2a30; - border-color: #888; - color: #ccc; + background: var(--list-hover-bg); + border-color: var(--border-color); + color: var(--text-secondary); } .demo-sliders { @@ -818,7 +851,7 @@ body { .demo-slider-label { font-size: 12px; - color: #c0c0d0; + color: var(--text-secondary); min-width: 160px; flex-shrink: 0; } @@ -828,20 +861,20 @@ body { gap: 0; border-radius: 6px; overflow: hidden; - border: 1px solid #3a3a50; + border: 1px solid var(--border-subtle); } .demo-step-btn { width: 36px; height: 28px; border: none; - background: #1a1a2e; - color: #888; + background: var(--bg-secondary); + color: var(--text-muted); font-size: 12px; font-weight: 700; cursor: pointer; transition: all 0.15s ease; - border-right: 1px solid #3a3a50; + border-right: 1px solid var(--border-subtle); } .demo-step-btn:last-child { @@ -849,14 +882,23 @@ body { } .demo-step-btn:hover { - background: #2a2a40; - color: #ccc; + background: var(--list-hover-bg); + color: var(--text-secondary); } -.demo-step-active.demo-step-1 { background: #152040; color: #93c5fd; } -.demo-step-active.demo-step-2 { background: #0d2d20; color: #6ee7b7; } -.demo-step-active.demo-step-3 { background: #152040; color: #3b82f6; } -.demo-step-active.demo-step-4 { background: #0d2d20; color: #10b981; } +.demo-step-active.demo-step-1 { background: rgba(147, 197, 253, 0.2); color: #93c5fd; } +.demo-step-active.demo-step-2 { background: rgba(110, 231, 183, 0.2); color: #6ee7b7; } +.demo-step-active.demo-step-3 { background: rgba(59, 130, 246, 0.2); color: #3b82f6; } +.demo-step-active.demo-step-4 { background: rgba(16, 185, 129, 0.2); color: #10b981; } + +body[data-vscode-theme-kind="vscode-light"] .demo-step-active.demo-step-1, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .demo-step-active.demo-step-1 { color: #1d6fa4; } +body[data-vscode-theme-kind="vscode-light"] .demo-step-active.demo-step-2, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .demo-step-active.demo-step-2 { color: #059669; } +body[data-vscode-theme-kind="vscode-light"] .demo-step-active.demo-step-3, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .demo-step-active.demo-step-3 { color: #2563eb; } +body[data-vscode-theme-kind="vscode-light"] .demo-step-active.demo-step-4, +body[data-vscode-theme-kind="vscode-high-contrast-light"] .demo-step-active.demo-step-4 { color: #059669; } .demo-slider-value { font-size: 11px; @@ -870,13 +912,13 @@ body { /* Demo mode card highlight */ .demo-card-highlight { - border-color: #3b82f680 !important; - box-shadow: 0 0 0 1px #3b82f640, 0 2px 8px rgba(59, 130, 246, 0.15) !important; + border-color: var(--border-color) !important; + box-shadow: 0 0 0 1px var(--focus-border), 0 2px 8px var(--shadow-color) !important; } .demo-card-description { font-size: 12px; - color: #a0a0b0; + color: var(--text-secondary); margin-bottom: 10px; font-style: italic; } @@ -884,6 +926,7 @@ body { .demo-section-label { font-size: 11px; font-weight: 600; - color: #d0d0e0; + color: var(--text-primary); margin-bottom: 6px; } + diff --git a/src/webview/usage/main.ts b/src/webview/usage/main.ts index 295536db..da7ef73c 100644 --- a/src/webview/usage/main.ts +++ b/src/webview/usage/main.ts @@ -181,7 +181,7 @@ function renderMissedPotential(stats: UsageAnalysisStats): string { if (missed.length === 0) { return `
-
+
✅ No other AI tool configs missing a Copilot counterpart
@@ -196,7 +196,7 @@ function renderMissedPotential(stats: UsageAnalysisStats): string { return `
-
+
⚠️ Missed Potential: Non-Copilot Instruction Files
@@ -386,15 +386,15 @@ function renderLayout(stats: UsageAnalysisStats): void {
🛠️Copilot Customization Files
Showing workspace customization status for active workspaces
-
No workspaces with customization files detected in the last 30 days.
+
No workspaces with customization files detected in the last 30 days.
`; } else { customizationHtml = ` -
-
+
+
🛠️ Copilot Customization Files
-
+
Showing ${matrix.totalWorkspaces} workspace(s) with Copilot activity in the last 30 days. ${matrix.workspacesWithIssues > 0 ? `⚠️ ${matrix.workspacesWithIssues} workspace(s) have no customization files.` @@ -404,10 +404,10 @@ function renderLayout(stats: UsageAnalysisStats): void { - - + + ${matrix.customizationTypes.map(type => ` - `).join('')} @@ -418,10 +418,10 @@ function renderLayout(stats: UsageAnalysisStats): void { const hasNoCustomization = Object.values(ws.typeStatuses).every(s => s === '❌'); return ` - - ${matrix.customizationTypes.map(type => { @@ -435,7 +435,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ? 'Missing' : 'Status unknown'; return ` - @@ -446,7 +446,7 @@ function renderLayout(stats: UsageAnalysisStats): void {
📂 WorkspaceSessions📂 WorkspaceSessions + ${escapeHtml(type.icon)}
+ ${escapeHtml(ws.workspaceName)}${hasNoCustomization ? ' ⚠️' : ''} + ${ws.sessionCount} + ${statusLabel}
-
+
${matrix.customizationTypes.map(type => ` ${escapeHtml(type.icon)} ${escapeHtml(type.label)} @@ -600,11 +600,11 @@ function renderLayout(stats: UsageAnalysisStats): void { ${renderMissedPotential(stats)} -
-
+
+
🏗️ Repository Hygiene Analysis
-
+
Analyze repository hygiene and structure to identify missing configuration files and best practices.
${matrix && matrix.workspaces && matrix.workspaces.length > 0 ? ` @@ -777,7 +777,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : '
'} ${stats.today.modelSwitching.premiumModels.length > 0 ? `
- ⭐ Premium: + ⭐ Premium: ${stats.today.modelSwitching.premiumModels.map(escapeHtml).join(', ')}
` : '
'} @@ -789,7 +789,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : ''}
${stats.today.modelSwitching.totalRequests > 0 ? ` -
+
Request Count:
${stats.today.modelSwitching.standardRequests > 0 ? `
@@ -799,7 +799,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : ''} ${stats.today.modelSwitching.premiumRequests > 0 ? `
- ⭐ Premium: + ⭐ Premium: ${formatNumber(stats.today.modelSwitching.premiumRequests)} (${formatPercent((stats.today.modelSwitching.premiumRequests / stats.today.modelSwitching.totalRequests) * 100)})
` : ''} @@ -812,7 +812,7 @@ function renderLayout(stats: UsageAnalysisStats): void {
` : ''} ${stats.today.modelSwitching.mixedTierSessions > 0 ? ` -
+
🔀 Mixed tier sessions: ${formatNumber(stats.today.modelSwitching.mixedTierSessions)}
` : ''} @@ -846,7 +846,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : '
'} ${stats.last30Days.modelSwitching.premiumModels.length > 0 ? `
- ⭐ Premium: + ⭐ Premium: ${stats.last30Days.modelSwitching.premiumModels.map(escapeHtml).join(', ')}
` : '
'} @@ -858,7 +858,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : ''}
${stats.last30Days.modelSwitching.totalRequests > 0 ? ` -
+
Request Count:
${stats.last30Days.modelSwitching.standardRequests > 0 ? `
@@ -868,7 +868,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : ''} ${stats.last30Days.modelSwitching.premiumRequests > 0 ? `
- ⭐ Premium: + ⭐ Premium: ${formatNumber(stats.last30Days.modelSwitching.premiumRequests)} (${formatPercent((stats.last30Days.modelSwitching.premiumRequests / stats.last30Days.modelSwitching.totalRequests) * 100)})
` : ''} @@ -881,7 +881,7 @@ function renderLayout(stats: UsageAnalysisStats): void {
` : ''} ${stats.last30Days.modelSwitching.mixedTierSessions > 0 ? ` -
+
🔀 Mixed tier sessions: ${formatNumber(stats.last30Days.modelSwitching.mixedTierSessions)}
` : ''} @@ -915,7 +915,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : '
'} ${stats.month.modelSwitching.premiumModels.length > 0 ? `
- ⭐ Premium: + ⭐ Premium: ${stats.month.modelSwitching.premiumModels.map(escapeHtml).join(', ')}
` : '
'} @@ -927,7 +927,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : ''}
${stats.month.modelSwitching.totalRequests > 0 ? ` -
+
Request Count:
${stats.month.modelSwitching.standardRequests > 0 ? `
@@ -937,7 +937,7 @@ function renderLayout(stats: UsageAnalysisStats): void { ` : ''} ${stats.month.modelSwitching.premiumRequests > 0 ? `
- ⭐ Premium: + ⭐ Premium: ${formatNumber(stats.month.modelSwitching.premiumRequests)} (${formatPercent((stats.month.modelSwitching.premiumRequests / stats.month.modelSwitching.totalRequests) * 100)})
` : ''} @@ -950,7 +950,7 @@ function renderLayout(stats: UsageAnalysisStats): void {
` : ''} ${stats.month.modelSwitching.mixedTierSessions > 0 ? ` -
+
🔀 Mixed tier sessions: ${formatNumber(stats.month.modelSwitching.mixedTierSessions)}
` : ''} @@ -1171,10 +1171,10 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl const header = el('div'); header.setAttribute('style', 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;'); const title = el('div'); - title.setAttribute('style', 'font-size: 14px; font-weight: 600; color: #fff;'); + title.setAttribute('style', 'font-size: 14px; font-weight: 600; color: var(--text-primary);'); title.textContent = '📊 Repository Hygiene Score'; const score = el('div'); - score.setAttribute('style', 'font-size: 24px; font-weight: 700; color: #60a5fa;'); + score.setAttribute('style', 'font-size: 24px; font-weight: 700; color: var(--link-color);'); score.textContent = `${Math.round(toFiniteNumber(summary.percentage))}%`; header.append(title, score); container.appendChild(header); @@ -1187,13 +1187,13 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl count: summary.passedChecks, label: 'Passed', cardStyle: 'text-align: center; padding: 8px; background: rgba(34, 197, 94, 0.1); border: 1px solid rgba(34, 197, 94, 0.3); border-radius: 4px;', - countStyle: 'font-size: 18px; font-weight: 600; color: #22c55e;' + countStyle: 'font-size: 18px; font-weight: 600; color: var(--success-fg);' }, { count: summary.warningChecks, label: 'Warnings', cardStyle: 'text-align: center; padding: 8px; background: rgba(245, 158, 11, 0.1); border: 1px solid rgba(245, 158, 11, 0.3); border-radius: 4px;', - countStyle: 'font-size: 18px; font-weight: 600; color: #f59e0b;' + countStyle: 'font-size: 18px; font-weight: 600; color: var(--warning-fg);' }, { count: summary.failedChecks, @@ -1210,7 +1210,7 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl count.setAttribute('style', statCard.countStyle); count.textContent = String(toFiniteNumber(statCard.count)); const label = el('div'); - label.setAttribute('style', 'font-size: 10px; color: #b8b8b8;'); + label.setAttribute('style', 'font-size: 10px; color: var(--text-secondary);'); label.textContent = statCard.label; card.append(count, label); statsGrid.appendChild(card); @@ -1219,7 +1219,7 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl container.appendChild(statsGrid); const scoreSummary = el('div'); - scoreSummary.setAttribute('style', 'font-size: 11px; color: #999; text-align: center; margin-bottom: 16px;'); + scoreSummary.setAttribute('style', 'font-size: 11px; color: var(--text-muted); text-align: center; margin-bottom: 16px;'); scoreSummary.textContent = `Score: ${toFiniteNumber(summary.totalScore)} / ${toFiniteNumber(summary.maxScore)} points`; container.appendChild(scoreSummary); @@ -1245,18 +1245,18 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl for (const [categoryId, categoryChecks] of Object.entries(categories)) { const section = el('div'); - section.setAttribute('style', 'margin-bottom: 12px; background: #0d0d0f; border: 1px solid #2a2a30; border-radius: 4px; overflow: hidden;'); + section.setAttribute('style', 'margin-bottom: 12px; background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 4px; overflow: hidden;'); const sectionHeader = el('div'); - sectionHeader.setAttribute('style', 'padding: 8px 12px; background: rgba(96, 165, 250, 0.1); border-bottom: 1px solid #2a2a30; display: flex; justify-content: space-between; align-items: center;'); + sectionHeader.setAttribute('style', 'padding: 8px 12px; background: var(--list-hover-bg); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center;'); const categoryName = el('span'); - categoryName.setAttribute('style', 'font-size: 12px; font-weight: 600; color: #fff;'); + categoryName.setAttribute('style', 'font-size: 12px; font-weight: 600; color: var(--text-primary);'); categoryName.textContent = categoryLabels[categoryId] || categoryId; const categorySummary = summary?.categories?.[categoryId]; const categoryPct = el('span'); - categoryPct.setAttribute('style', 'font-size: 11px; color: #60a5fa; font-weight: 600;'); + categoryPct.setAttribute('style', 'font-size: 11px; color: var(--link-color); font-weight: 600;'); categoryPct.textContent = `${Math.round(toFiniteNumber(categorySummary?.percentage))}%`; sectionHeader.append(categoryName, categoryPct); @@ -1268,7 +1268,7 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl const statusColor = status === 'pass' ? '#22c55e' : status === 'warning' ? '#f59e0b' : '#ef4444'; const checkRow = el('div'); - checkRow.setAttribute('style', 'padding: 8px; border-bottom: 1px solid #2a2a30; display: flex; align-items: flex-start; gap: 8px;'); + checkRow.setAttribute('style', 'padding: 8px; border-bottom: 1px solid var(--border-subtle); display: flex; align-items: flex-start; gap: 8px;'); const icon = el('span'); icon.setAttribute('style', 'font-size: 16px;'); @@ -1282,14 +1282,14 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl checkLabel.textContent = typeof check?.label === 'string' ? check.label : ''; const checkDetail = el('div'); - checkDetail.setAttribute('style', 'font-size: 11px; color: #b8b8b8; margin-top: 2px;'); + checkDetail.setAttribute('style', 'font-size: 11px; color: var(--text-secondary); margin-top: 2px;'); checkDetail.textContent = typeof check?.detail === 'string' ? check.detail : ''; content.append(checkLabel, checkDetail); if (typeof check?.hint === 'string' && check.hint.length > 0) { const hint = el('div'); - hint.setAttribute('style', 'font-size: 10px; color: #60a5fa; margin-top: 4px; font-style: italic;'); + hint.setAttribute('style', 'font-size: 10px; color: var(--link-color); margin-top: 4px; font-style: italic;'); hint.textContent = `💡 ${check.hint}`; content.appendChild(hint); } @@ -1299,14 +1299,14 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl if (docUrl) { const docLink = el('a'); docLink.setAttribute('href', docUrl); - docLink.setAttribute('style', 'font-size: 10px; color: #60a5fa; margin-top: 4px; display: inline-block;'); + docLink.setAttribute('style', 'font-size: 10px; color: var(--link-color); margin-top: 4px; display: inline-block;'); docLink.setAttribute('title', 'View official documentation'); docLink.textContent = '📖 View documentation'; content.appendChild(docLink); } const weight = el('span'); - weight.setAttribute('style', 'font-size: 10px; color: #999; min-width: 30px; text-align: right;'); + weight.setAttribute('style', 'font-size: 10px; color: var(--text-muted); min-width: 30px; text-align: right;'); weight.textContent = `+${toFiniteNumber(check?.weight)}`; checkRow.append(icon, content, weight); @@ -1318,12 +1318,12 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl if (recommendations.length > 0) { const recommendationsSection = el('div'); - recommendationsSection.setAttribute('style', 'margin-top: 16px; background: #0d0d0f; border: 1px solid #2a2a30; border-radius: 4px; overflow: hidden;'); + recommendationsSection.setAttribute('style', 'margin-top: 16px; background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 4px; overflow: hidden;'); const recommendationsHeader = el('div'); - recommendationsHeader.setAttribute('style', 'padding: 8px 12px; background: rgba(96, 165, 250, 0.1); border-bottom: 1px solid #2a2a30;'); + recommendationsHeader.setAttribute('style', 'padding: 8px 12px; background: var(--list-hover-bg); border-bottom: 1px solid var(--border-color);'); const recommendationsTitle = el('span'); - recommendationsTitle.setAttribute('style', 'font-size: 12px; font-weight: 600; color: #fff;'); + recommendationsTitle.setAttribute('style', 'font-size: 12px; font-weight: 600; color: var(--text-primary);'); recommendationsTitle.textContent = '💡 Top Recommendations'; recommendationsHeader.appendChild(recommendationsTitle); recommendationsSection.appendChild(recommendationsHeader); @@ -1333,7 +1333,7 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl const priorityColor = priority === 'high' ? '#ef4444' : priority === 'medium' ? '#f59e0b' : '#60a5fa'; const row = el('div'); - row.setAttribute('style', 'padding: 8px; border-bottom: 1px solid #2a2a30; display: flex; gap: 8px;'); + row.setAttribute('style', 'padding: 8px; border-bottom: 1px solid var(--border-subtle); display: flex; gap: 8px;'); const priorityLabel = el('span'); priorityLabel.setAttribute('style', `font-size: 10px; font-weight: 600; color: ${priorityColor}; min-width: 50px;`); @@ -1343,17 +1343,17 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl content.setAttribute('style', 'flex: 1;'); const action = el('div'); - action.setAttribute('style', 'font-size: 11px; color: #fff;'); + action.setAttribute('style', 'font-size: 11px; color: var(--text-primary);'); action.textContent = typeof recommendation?.action === 'string' ? recommendation.action : ''; const impact = el('div'); - impact.setAttribute('style', 'font-size: 10px; color: #999; margin-top: 2px;'); + impact.setAttribute('style', 'font-size: 10px; color: var(--text-muted); margin-top: 2px;'); impact.textContent = typeof recommendation?.impact === 'string' ? recommendation.impact : ''; content.append(action, impact); const weight = el('span'); - weight.setAttribute('style', 'font-size: 10px; color: #999; min-width: 30px; text-align: right;'); + weight.setAttribute('style', 'font-size: 10px; color: var(--text-muted); min-width: 30px; text-align: right;'); weight.textContent = `+${toFiniteNumber(recommendation?.weight)}`; row.append(priorityLabel, content, weight); @@ -1370,7 +1370,7 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl copilotSection.setAttribute('style', 'margin-top: 16px; padding: 12px; background: rgba(96, 165, 250, 0.07); border: 1px solid rgba(96, 165, 250, 0.3); border-radius: 4px; display: flex; align-items: center; justify-content: space-between; gap: 12px;'); const copilotText = el('div'); - copilotText.setAttribute('style', 'font-size: 11px; color: #b8b8b8; flex: 1;'); + copilotText.setAttribute('style', 'font-size: 11px; color: var(--text-secondary); flex: 1;'); copilotText.textContent = 'Let Copilot help you fix the identified issues in this repository.'; const copilotBtn = document.createElement('vscode-button'); @@ -1393,11 +1393,11 @@ function buildRepoAnalysisBodyElement(data: any, workspacePath?: string): HTMLEl copilotSection.setAttribute('style', 'margin-top: 16px; padding: 12px; background: rgba(251, 191, 36, 0.07); border: 1px solid rgba(251, 191, 36, 0.4); border-radius: 4px; display: flex; flex-direction: column; gap: 8px;'); const instructions = el('div'); - instructions.setAttribute('style', 'font-size: 11px; color: #fbbf24;'); + instructions.setAttribute('style', 'font-size: 11px; color: var(--warning-fg);'); instructions.textContent = `⚠️ Open "${repoFolderName}" in VS Code first, then paste this prompt into Copilot Chat:`; const promptBox = el('pre'); - promptBox.setAttribute('style', 'font-size: 10px; color: #b8b8b8; background: #0d0d0f; border: 1px solid #2a2a30; border-radius: 4px; padding: 8px; white-space: pre-wrap; word-break: break-word; max-height: 120px; overflow-y: auto; font-family: monospace; margin: 0;'); + promptBox.setAttribute('style', 'font-size: 10px; color: var(--text-secondary); background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 4px; padding: 8px; white-space: pre-wrap; word-break: break-word; max-height: 120px; overflow-y: auto; font-family: monospace; margin: 0;'); promptBox.textContent = prompt; const copyBtn = document.createElement('vscode-button'); @@ -1446,12 +1446,12 @@ function renderRepositoryHygienePanels(): void { const buttonAction = hasResult ? 'details' : 'analyze'; const isCurrentSelection = selectedRepoPath === ws.workspacePath && hasSelectedRepository; return ` -
+
-
+
${escapeHtml(ws.workspaceName)}
-
+
${Number(ws.sessionCount) || 0} ${ws.sessionCount === 1 ? 'session' : 'sessions'} · ${Number(ws.interactionCount) || 0} ${ws.interactionCount === 1 ? 'interaction' : 'interactions'} · Score: ${escapeHtml(scoreLabel)}
@@ -1472,17 +1472,17 @@ function renderRepositoryHygienePanels(): void { if (record?.data) { detailsPane.replaceChildren(); const card = el('div', 'repo-details-card'); - card.setAttribute('style', 'padding: 12px; background: #0d0d0f; border: 1px solid #2a2a30; border-radius: 6px;'); + card.setAttribute('style', 'padding: 12px; background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 6px;'); const header = el('div', 'repo-details-card-header'); header.setAttribute('style', 'display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 10px;'); const label = el('div'); - label.setAttribute('style', 'font-size: 12px; color: #b8b8b8;'); + label.setAttribute('style', 'font-size: 12px; color: var(--text-secondary);'); label.textContent = 'Repository: '; const repoName = el('span'); - repoName.setAttribute('style', "color: #fff; font-weight: 600; font-family: 'Courier New', monospace;"); + repoName.setAttribute('style', "color: var(--text-primary); font-weight: 600; font-family: 'Courier New', monospace;"); repoName.textContent = workspaceName; label.appendChild(repoName); @@ -1512,12 +1512,12 @@ function renderRepositoryHygienePanels(): void { } detailsPane.innerHTML = ` -
+
-
Repository: ${escapeHtml(workspaceName)}
+
Repository: ${escapeHtml(workspaceName)}
Switch Repository
-
No analysis data yet. Click Analyze in the list.
+
No analysis data yet. Click Analyze in the list.
`; } @@ -1543,7 +1543,7 @@ function displayRepoAnalysisResults(data: any, workspacePath?: string): void { if (resultsHost) { resultsHost.replaceChildren(); const card = el('div', 'repo-analysis-card'); - card.setAttribute('style', 'padding: 12px; background: #0d0d0f; border: 1px solid #2a2a30; border-radius: 6px; margin-bottom: 12px;'); + card.setAttribute('style', 'padding: 12px; background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 6px; margin-bottom: 12px;'); card.appendChild(buildRepoAnalysisBodyElement(data, workspacePath)); resultsHost.appendChild(card); } diff --git a/src/webview/usage/styles.css b/src/webview/usage/styles.css index 161d52ba..6afdfce4 100644 --- a/src/webview/usage/styles.css +++ b/src/webview/usage/styles.css @@ -197,23 +197,23 @@ body { width: 100%; border-collapse: collapse; font-size: 12px; - color: #d0d0d0; + color: var(--text-primary); } .customization-matrix th { - background: #1a1a1f; - color: #fff; + background: var(--list-hover-bg); + color: var(--text-primary); font-weight: 600; font-size: 11px; white-space: nowrap; } .customization-matrix td { - background: #18181b; + background: var(--bg-tertiary); } .customization-matrix tbody tr:hover td { - background: #1f1f24; + background: var(--list-hover-bg); } .stale-warning { @@ -269,19 +269,19 @@ body { } .repo-hygiene-pane { - border: 1px solid #2a2a30; + border: 1px solid var(--border-color); border-radius: 6px; margin-bottom: 12px; - background: #121216; + background: var(--bg-secondary); } .repo-hygiene-pane-header { padding: 8px 12px; font-size: 12px; font-weight: 600; - color: #f3f4f6; - border-bottom: 1px solid #2a2a30; - background: #17171c; + color: var(--text-primary); + border-bottom: 1px solid var(--border-color); + background: var(--list-hover-bg); } .repo-hygiene-pane-body {