@@ -124,13 +124,16 @@ export class SummaryViewProvider implements vscode.WebviewViewProvider {
124124 <meta charset="UTF-8">
125125 <meta name="viewport" content="width=device-width, initial-scale=1.0">
126126 <title>Coding Time Summary</title>
127+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
127128 <style>
128129 :root {
129130 --background-color: var(--vscode-editor-background);
130131 --text-color: var(--vscode-editor-foreground);
131132 --border-color: var(--vscode-panel-border);
132133 --header-background: var(--vscode-titleBar-activeBackground);
133134 --header-foreground: var(--vscode-titleBar-activeForeground);
135+ --chart-grid-color: var(--vscode-panel-border);
136+ --chart-text-color: var(--vscode-editor-foreground);
134137 }
135138 body {
136139 font-family: var(--vscode-font-family);
@@ -332,6 +335,27 @@ export class SummaryViewProvider implements vscode.WebviewViewProvider {
332335 font-size: 11px;
333336 color: var(--vscode-foreground);
334337 }
338+ .chart-container {
339+ background: var(--vscode-editor-background);
340+ border: 1px solid var(--vscode-panel-border);
341+ border-radius: 6px;
342+ padding: 20px;
343+ margin-bottom: 30px;
344+ }
345+ .chart-title {
346+ font-size: 16px;
347+ font-weight: 500;
348+ color: var(--vscode-foreground);
349+ margin-bottom: 15px;
350+ }
351+ .chart-wrapper {
352+ position: relative;
353+ height: 300px;
354+ width: 100%;
355+ }
356+ .search-results-chart {
357+ height: 400px;
358+ }
335359 </style>
336360 </head>
337361 <body>
@@ -381,7 +405,26 @@ export class SummaryViewProvider implements vscode.WebviewViewProvider {
381405 </select>
382406 <button id="search-button">Search</button>
383407 </div>
384- <div id="content">Loading...</div>
408+ <div id="content">
409+ <div class="chart-container">
410+ <div class="chart-title">Project Summary</div>
411+ <div class="chart-wrapper">
412+ <canvas id="projectChart"></canvas>
413+ </div>
414+ </div>
415+ <div class="chart-container">
416+ <div class="chart-title">Daily Summary (Last 7 Days)</div>
417+ <div class="chart-wrapper">
418+ <canvas id="dailyChart"></canvas>
419+ </div>
420+ </div>
421+ <div class="chart-container search-results-chart" style="display: none;">
422+ <div class="chart-title">Search Results</div>
423+ <div class="chart-wrapper">
424+ <canvas id="searchChart"></canvas>
425+ </div>
426+ </div>
427+ </div>
385428 </div>
386429 <script>
387430 const vscode = acquireVsCodeApi();
@@ -438,25 +481,121 @@ export class SummaryViewProvider implements vscode.WebviewViewProvider {
438481 function updateContent(data) {
439482 const content = document.getElementById('content');
440483 content.innerHTML = \`
441- <h2>Project Summary</h2>
442- <table>
443- <tr><th>Project</th><th>Coding Time</th></tr>
444- \${Object.entries(data.projectSummary)
445- .map(([project, time]) => \`<tr><td>\${project}</td><td>\${formatTime(time)}</td></tr>\`)
446- .join('')}
447- </table>
448-
449- <h2>Daily Summary (Last 7 Days)</h2>
450- <table>
451- <tr><th>Date</th><th>Coding Time</th></tr>
452- \${Object.entries(data.dailySummary)
453- .sort((a, b) => b[0].localeCompare(a[0]))
454- .slice(0, 7)
455- .map(([date, time]) => \`<tr><td>\${date}</td><td>\${formatTime(time)}</td></tr>\`)
456- .join('')}
457- </table>
484+ <div class="chart-container">
485+ <div class="chart-title">Project Summary</div>
486+ <div class="chart-wrapper">
487+ <canvas id="projectChart"></canvas>
488+ </div>
489+ </div>
490+ <div class="chart-container">
491+ <div class="chart-title">Daily Summary (Last 7 Days)</div>
492+ <div class="chart-wrapper">
493+ <canvas id="dailyChart"></canvas>
494+ </div>
495+ </div>
458496 \`;
459497
498+ // Create project summary chart
499+ const projectCtx = document.getElementById('projectChart').getContext('2d');
500+ const projectData = Object.entries(data.projectSummary)
501+ .sort((a, b) => b[1] - a[1])
502+ .slice(0, 5); // Show top 5 projects
503+
504+ new Chart(projectCtx, {
505+ type: 'bar',
506+ data: {
507+ labels: projectData.map(([project]) => project),
508+ datasets: [{
509+ label: 'Coding Time (hours)',
510+ data: projectData.map(([_, time]) => time / 60),
511+ backgroundColor: 'rgba(74, 114, 176, 0.7)',
512+ borderColor: 'rgba(74, 114, 176, 1)',
513+ borderWidth: 1
514+ }]
515+ },
516+ options: {
517+ responsive: true,
518+ maintainAspectRatio: false,
519+ scales: {
520+ y: {
521+ beginAtZero: true,
522+ grid: {
523+ color: 'var(--chart-grid-color)'
524+ },
525+ ticks: {
526+ color: 'var(--chart-text-color)'
527+ }
528+ },
529+ x: {
530+ grid: {
531+ color: 'var(--chart-grid-color)'
532+ },
533+ ticks: {
534+ color: 'var(--chart-text-color)'
535+ }
536+ }
537+ },
538+ plugins: {
539+ legend: {
540+ labels: {
541+ color: 'var(--chart-text-color)'
542+ }
543+ }
544+ }
545+ }
546+ });
547+
548+ // Create daily summary chart
549+ const dailyCtx = document.getElementById('dailyChart').getContext('2d');
550+ const dailyData = Object.entries(data.dailySummary)
551+ .sort((a, b) => b[0].localeCompare(a[0]))
552+ .slice(0, 7);
553+
554+ new Chart(dailyCtx, {
555+ type: 'line',
556+ data: {
557+ labels: dailyData.map(([date]) => date),
558+ datasets: [{
559+ label: 'Coding Time (hours)',
560+ data: dailyData.map(([_, time]) => time / 60),
561+ fill: true,
562+ backgroundColor: 'rgba(74, 114, 176, 0.2)',
563+ borderColor: 'rgba(74, 114, 176, 1)',
564+ tension: 0.4
565+ }]
566+ },
567+ options: {
568+ responsive: true,
569+ maintainAspectRatio: false,
570+ scales: {
571+ y: {
572+ beginAtZero: true,
573+ grid: {
574+ color: 'var(--chart-grid-color)'
575+ },
576+ ticks: {
577+ color: 'var(--chart-text-color)'
578+ }
579+ },
580+ x: {
581+ grid: {
582+ color: 'var(--chart-grid-color)'
583+ },
584+ ticks: {
585+ color: 'var(--chart-text-color)'
586+ }
587+ }
588+ },
589+ plugins: {
590+ legend: {
591+ labels: {
592+ color: 'var(--chart-text-color)'
593+ }
594+ }
595+ }
596+ }
597+ });
598+
460599 // Add heatmap creation
461600 createHeatmap(data);
462601 }
@@ -469,18 +608,59 @@ export class SummaryViewProvider implements vscode.WebviewViewProvider {
469608 }
470609
471610 let totalTime = 0;
472- const tableRows = entries.map( entry => {
611+ const searchData = entries.reduce((acc, entry) => {
473612 totalTime += entry.timeSpent;
474- return \`<tr><td>\${entry.date}</td><td>\${entry.project}</td><td>\${formatTime(entry.timeSpent)}</td></tr>\`;
475- }).join('');
613+ if (!acc[entry.project]) {
614+ acc[entry.project] = 0;
615+ }
616+ acc[entry.project] += entry.timeSpent;
617+ return acc;
618+ }, {});
476619
477620 content.innerHTML = \`
478- <h2>Search Results: (Coding Time is \${formatTime(totalTime)})</h2>
479- <table>
480- <tr><th>Date</th><th>Project</th><th>Coding Time</th></tr>
481- \${tableRows}
482- </table>
621+ <div class="chart-container search-results-chart">
622+ <div class="chart-title">Search Results (Total Time: \${formatTime(totalTime)})</div>
623+ <div class="chart-wrapper">
624+ <canvas id="searchChart"></canvas>
625+ </div>
626+ </div>
483627 \`;
628+
629+ // Create search results chart
630+ const searchCtx = document.getElementById('searchChart').getContext('2d');
631+ const searchChartData = Object.entries(searchData)
632+ .sort((a, b) => b[1] - a[1]);
633+
634+ new Chart(searchCtx, {
635+ type: 'pie',
636+ data: {
637+ labels: searchChartData.map(([project]) => project),
638+ datasets: [{
639+ data: searchChartData.map(([_, time]) => time / 60),
640+ backgroundColor: [
641+ 'rgba(74, 114, 176, 0.7)',
642+ 'rgba(56, 97, 165, 0.7)',
643+ 'rgba(37, 75, 145, 0.7)',
644+ 'rgba(26, 59, 124, 0.7)',
645+ 'rgba(15, 43, 103, 0.7)'
646+ ],
647+ borderColor: 'var(--vscode-editor-background)',
648+ borderWidth: 1
649+ }]
650+ },
651+ options: {
652+ responsive: true,
653+ maintainAspectRatio: false,
654+ plugins: {
655+ legend: {
656+ position: 'right',
657+ labels: {
658+ color: 'var(--chart-text-color)'
659+ }
660+ }
661+ }
662+ }
663+ });
484664 }
485665
486666 function formatTime(minutes) {
0 commit comments