commit-insights 0.1.1 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -767,58 +767,112 @@ function escapeHtml(s) {
|
|
|
767
767
|
}
|
|
768
768
|
|
|
769
769
|
// src/report/templates/sections/header.ts
|
|
770
|
-
function renderHeader(repoName, period) {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
<
|
|
770
|
+
function renderHeader(repoName, period, generatedAt, totals) {
|
|
771
|
+
const date = generatedAt.slice(0, 10);
|
|
772
|
+
return `<header class="hero">
|
|
773
|
+
<div class="hero-row"><span class="hero-number">${totals.commits}</span><span class="hero-label">commits</span></div>
|
|
774
|
+
<div class="hero-repo">${escapeHtml(repoName)}</div>
|
|
775
|
+
<div class="hero-period">${escapeHtml(period.start)} \u2013 ${escapeHtml(period.end)} <span class="hero-period-gen">\xB7 ${escapeHtml(date)}</span></div>
|
|
774
776
|
</header>`;
|
|
775
777
|
}
|
|
776
778
|
|
|
777
|
-
// src/report/templates/sections/
|
|
778
|
-
function
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
779
|
+
// src/report/templates/sections/statsBar.ts
|
|
780
|
+
function renderStatsBar(totals) {
|
|
781
|
+
const items = [
|
|
782
|
+
`<div class="stats-item"><span class="stats-value">${totals.commits}</span><span class="stats-label">commits</span></div>`,
|
|
783
|
+
`<div class="stats-item"><span class="stats-value">${totals.authors}</span><span class="stats-label">authors</span></div>`
|
|
784
|
+
];
|
|
785
|
+
if (totals.tickets > 0) {
|
|
786
|
+
items.push(`<div class="stats-item"><span class="stats-value">${totals.tickets}</span><span class="stats-label">tickets</span></div>`);
|
|
787
|
+
}
|
|
788
|
+
return `<div class="stats-bar">${items.join("")}</div>`;
|
|
784
789
|
}
|
|
785
790
|
|
|
786
791
|
// src/report/templates/sections/charts.ts
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
<
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
<
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
792
|
+
var TYPE_ORDER = ["feat", "fix", "docs", "refactor", "style", "test", "perf", "ci", "build", "chore", "revert", "merge", "other"];
|
|
793
|
+
function renderMonthlyChart() {
|
|
794
|
+
return `<section>
|
|
795
|
+
<h2 class="eyebrow">Activity</h2>
|
|
796
|
+
<div class="chart-container"><canvas id="chart-monthly" height="200"></canvas></div>
|
|
797
|
+
</section>`;
|
|
798
|
+
}
|
|
799
|
+
function renderTypeBars(typeCounts) {
|
|
800
|
+
const max = Math.max(...Object.values(typeCounts), 1);
|
|
801
|
+
const rows = TYPE_ORDER.filter((t) => typeCounts[t]).map((t) => {
|
|
802
|
+
const pct = typeCounts[t] / max * 100;
|
|
803
|
+
return `<div class="bar-row">
|
|
804
|
+
<span class="bar-label">${escapeHtml(t)}</span>
|
|
805
|
+
<div class="bar-track"><div class="bar-fill bar-type-${escapeHtml(t)}" style="width:${pct}%"></div></div>
|
|
806
|
+
<span class="bar-count">${typeCounts[t]}</span>
|
|
807
|
+
</div>`;
|
|
808
|
+
}).join("");
|
|
809
|
+
return `<section>
|
|
810
|
+
<h2 class="eyebrow">Types</h2>
|
|
811
|
+
<div class="type-bars">${rows}</div>
|
|
812
|
+
</section>`;
|
|
813
|
+
}
|
|
814
|
+
function renderAreaBars(areaCounts) {
|
|
815
|
+
if (areaCounts.length === 0) return "";
|
|
816
|
+
const max = Math.max(...areaCounts.map((a) => a.count), 1);
|
|
817
|
+
const rows = areaCounts.map((a) => {
|
|
818
|
+
const pct = a.count / max * 100;
|
|
819
|
+
return `<div class="bar-row">
|
|
820
|
+
<span class="bar-label">${escapeHtml(a.area)}</span>
|
|
821
|
+
<div class="bar-track"><div class="bar-fill bar-type-area" style="width:${pct}%"></div></div>
|
|
822
|
+
<span class="bar-count">${a.count}</span>
|
|
823
|
+
</div>`;
|
|
824
|
+
}).join("");
|
|
825
|
+
return `<section>
|
|
826
|
+
<h2 class="eyebrow">Areas</h2>
|
|
827
|
+
<div class="area-bars">${rows}</div>
|
|
805
828
|
</section>`;
|
|
806
829
|
}
|
|
807
830
|
|
|
808
|
-
// src/report/templates/sections/
|
|
809
|
-
function
|
|
831
|
+
// src/report/templates/sections/tickets.ts
|
|
832
|
+
function renderTickets(tickets) {
|
|
810
833
|
if (tickets.length === 0) return "";
|
|
811
|
-
const
|
|
812
|
-
(t) => `<
|
|
834
|
+
const items = tickets.map(
|
|
835
|
+
(t) => `<li><span class="ticket-id">${escapeHtml(t.id)}</span><span class="ticket-count">${t.count}</span></li>`
|
|
836
|
+
).join("");
|
|
837
|
+
return `<section>
|
|
838
|
+
<h2 class="eyebrow">Top Tickets</h2>
|
|
839
|
+
<ul class="ticket-list">${items}</ul>
|
|
840
|
+
</section>`;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/report/templates/sections/reviewers.ts
|
|
844
|
+
function renderReviewers(reviewers) {
|
|
845
|
+
if (reviewers.length === 0) return "";
|
|
846
|
+
const items = reviewers.map(
|
|
847
|
+
(r) => `<li><span class="reviewer-name">${escapeHtml(r.name)}</span><span class="reviewer-count">${r.collaborations}</span></li>`
|
|
813
848
|
).join("");
|
|
814
|
-
return `<section
|
|
849
|
+
return `<section>
|
|
850
|
+
<h2 class="eyebrow">Reviewers</h2>
|
|
851
|
+
<ul class="reviewer-list">${items}</ul>
|
|
852
|
+
</section>`;
|
|
815
853
|
}
|
|
854
|
+
|
|
855
|
+
// src/report/templates/sections/tables.ts
|
|
816
856
|
function renderRecentCommits(commits) {
|
|
817
857
|
const limited = commits.slice(0, 200);
|
|
858
|
+
const header = `<div class="commit-grid-header">
|
|
859
|
+
<div class="commit-cell hash">Hash</div>
|
|
860
|
+
<div class="commit-cell date">Date</div>
|
|
861
|
+
<div class="commit-cell type">Type</div>
|
|
862
|
+
<div class="commit-cell subject">Subject</div>
|
|
863
|
+
</div>`;
|
|
818
864
|
const rows = limited.map(
|
|
819
|
-
(c) => `<
|
|
865
|
+
(c) => `<div class="commit-row">
|
|
866
|
+
<div class="commit-cell hash">${escapeHtml(c.hash.slice(0, 7))}</div>
|
|
867
|
+
<div class="commit-cell date">${escapeHtml(c.date)}</div>
|
|
868
|
+
<div class="commit-cell type"><span class="type-badge type-${escapeHtml(c.type)}">${escapeHtml(c.type)}</span></div>
|
|
869
|
+
<div class="commit-cell subject">${escapeHtml(c.subject)}</div>
|
|
870
|
+
</div>`
|
|
820
871
|
).join("");
|
|
821
|
-
return `<section
|
|
872
|
+
return `<section>
|
|
873
|
+
<h2 class="eyebrow">Recent Commits</h2>
|
|
874
|
+
<div class="commit-scroll">${header}${rows}</div>
|
|
875
|
+
</section>`;
|
|
822
876
|
}
|
|
823
877
|
|
|
824
878
|
// src/report/templates/sections/narrative.ts
|
|
@@ -826,7 +880,7 @@ function renderNarrativeBlock(text) {
|
|
|
826
880
|
if (!text) return "";
|
|
827
881
|
const paragraphs = text.split(/\n\n+/).map((p) => `<p>${escapeHtml(p.trim())}</p>`).join("");
|
|
828
882
|
return `<section class="narrative-section">
|
|
829
|
-
<h2 class="
|
|
883
|
+
<h2 class="eyebrow">Summary</h2>
|
|
830
884
|
<div class="narrative-content">${paragraphs}</div>
|
|
831
885
|
</section>`;
|
|
832
886
|
}
|
|
@@ -843,28 +897,18 @@ function renderFooter(version, generatedAt) {
|
|
|
843
897
|
// src/report/templates/styles.ts
|
|
844
898
|
var STYLES = `/* \u2500\u2500 Tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
845
899
|
:root {
|
|
846
|
-
--bg: #
|
|
847
|
-
--surface:
|
|
848
|
-
--
|
|
849
|
-
--
|
|
850
|
-
--
|
|
851
|
-
--
|
|
852
|
-
--
|
|
853
|
-
--
|
|
854
|
-
--
|
|
855
|
-
--
|
|
856
|
-
--
|
|
857
|
-
--
|
|
858
|
-
--blue-muted: rgba(96, 165, 250, 0.12);
|
|
859
|
-
--purple: #a78bfa;
|
|
860
|
-
--purple-muted: rgba(167, 139, 250, 0.12);
|
|
861
|
-
--yellow: #fbbf24;
|
|
862
|
-
--orange: #fb923c;
|
|
863
|
-
--red: #f87171;
|
|
864
|
-
--pink: #f472b6;
|
|
865
|
-
--teal: #2dd4bf;
|
|
866
|
-
--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
867
|
-
--font-mono: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;
|
|
900
|
+
--bg: #0D0D0F;
|
|
901
|
+
--surface: #18160F;
|
|
902
|
+
--stone: #F2EDE6;
|
|
903
|
+
--stone-2: #B8A898;
|
|
904
|
+
--stone-3: #7A7060;
|
|
905
|
+
--amber: #C4763A;
|
|
906
|
+
--teal: #7EB8A4;
|
|
907
|
+
--rule: rgba(242,237,230,0.07);
|
|
908
|
+
--rule-light: rgba(242,237,230,0.12);
|
|
909
|
+
--font-serif: Georgia, 'Times New Roman', serif;
|
|
910
|
+
--font-body: system-ui, -apple-system, sans-serif;
|
|
911
|
+
--font-mono: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
|
|
868
912
|
}
|
|
869
913
|
|
|
870
914
|
/* \u2500\u2500 Reset & Base \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
@@ -872,135 +916,294 @@ var STYLES = `/* \u2500\u2500 Tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\
|
|
|
872
916
|
html { font-size: 16px; }
|
|
873
917
|
body {
|
|
874
918
|
font-family: var(--font-body);
|
|
919
|
+
font-weight: 300;
|
|
875
920
|
background: var(--bg);
|
|
876
|
-
|
|
921
|
+
background-image:
|
|
922
|
+
radial-gradient(circle, rgba(242,237,230,0.03) 0.5px, transparent 0.5px);
|
|
923
|
+
background-size: 20px 20px;
|
|
924
|
+
background-position: 0 0;
|
|
925
|
+
background-repeat: repeat;
|
|
926
|
+
color: var(--stone);
|
|
877
927
|
line-height: 1.7;
|
|
878
|
-
padding:
|
|
879
|
-
max-width:
|
|
928
|
+
padding: 80px 40px;
|
|
929
|
+
max-width: 880px;
|
|
880
930
|
margin: 0 auto;
|
|
881
931
|
-webkit-font-smoothing: antialiased;
|
|
882
932
|
-moz-osx-font-smoothing: grayscale;
|
|
883
933
|
}
|
|
884
|
-
code, .commit-hash, .ticket-id, .
|
|
934
|
+
code, .commit-hash, .type-badge, .stats-value, .ticket-id, .reviewer-name, .eyebrow, .bar-label, .bar-count {
|
|
885
935
|
font-family: var(--font-mono);
|
|
886
936
|
}
|
|
887
937
|
|
|
888
938
|
/* \u2500\u2500 Typography \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
889
|
-
|
|
890
|
-
p { max-width: 72ch; }
|
|
891
|
-
|
|
892
|
-
a
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
939
|
+
h2 { font-weight: 400; }
|
|
940
|
+
p { max-width: 72ch; color: var(--stone-2); }
|
|
941
|
+
.narrative-content p { max-width: none; }
|
|
942
|
+
a { color: var(--amber); }
|
|
943
|
+
a:hover { color: var(--stone); }
|
|
944
|
+
|
|
945
|
+
/* \u2500\u2500 Eyebrow pattern \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
946
|
+
section { margin-bottom: 56px; }
|
|
947
|
+
.eyebrow {
|
|
948
|
+
display: flex;
|
|
949
|
+
align-items: center;
|
|
950
|
+
gap: 16px;
|
|
951
|
+
margin-bottom: 24px;
|
|
898
952
|
font-size: 0.625rem;
|
|
899
953
|
font-weight: 500;
|
|
900
954
|
text-transform: uppercase;
|
|
901
|
-
letter-spacing: 0.
|
|
902
|
-
color: var(--
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
/* \u2500\u2500
|
|
912
|
-
.
|
|
913
|
-
.
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
955
|
+
letter-spacing: 0.2em;
|
|
956
|
+
color: var(--stone-3);
|
|
957
|
+
}
|
|
958
|
+
.eyebrow::after {
|
|
959
|
+
content: '';
|
|
960
|
+
flex: 1;
|
|
961
|
+
height: 1px;
|
|
962
|
+
background: var(--rule);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/* \u2500\u2500 Hero \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
966
|
+
.hero { margin-bottom: 64px; }
|
|
967
|
+
.hero-row { display: flex; align-items: flex-end; gap: 12px; }
|
|
968
|
+
.hero-number {
|
|
969
|
+
font-family: var(--font-serif);
|
|
970
|
+
font-size: clamp(72px, 12vw, 120px);
|
|
971
|
+
font-weight: 700;
|
|
972
|
+
color: var(--stone);
|
|
973
|
+
line-height: 1;
|
|
974
|
+
letter-spacing: -0.03em;
|
|
975
|
+
}
|
|
976
|
+
.hero-label {
|
|
977
|
+
font-family: var(--font-mono);
|
|
978
|
+
font-size: 1.25rem;
|
|
979
|
+
font-weight: 400;
|
|
980
|
+
color: var(--stone-3);
|
|
981
|
+
line-height: 1;
|
|
982
|
+
margin-top: 0.35em;
|
|
983
|
+
}
|
|
984
|
+
.hero-repo {
|
|
985
|
+
font-family: var(--font-mono);
|
|
986
|
+
font-size: 0.9375rem;
|
|
987
|
+
font-weight: 500;
|
|
988
|
+
color: var(--amber);
|
|
989
|
+
margin-top: 12px;
|
|
990
|
+
}
|
|
991
|
+
.hero-period {
|
|
992
|
+
font-family: var(--font-mono);
|
|
993
|
+
font-size: 0.75rem;
|
|
994
|
+
color: var(--stone-3);
|
|
995
|
+
margin-top: 4px;
|
|
996
|
+
}
|
|
997
|
+
.hero-period-gen {
|
|
998
|
+
color: #5A5040;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/* \u2500\u2500 Stats bar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1002
|
+
.stats-bar {
|
|
1003
|
+
display: flex;
|
|
1004
|
+
width: 100%;
|
|
1005
|
+
margin-bottom: 56px;
|
|
1006
|
+
font-size: 1.125rem;
|
|
1007
|
+
color: var(--stone-2);
|
|
1008
|
+
font-weight: 400;
|
|
1009
|
+
}
|
|
1010
|
+
.stats-item {
|
|
1011
|
+
flex: 1;
|
|
1012
|
+
display: flex;
|
|
1013
|
+
flex-direction: column;
|
|
1014
|
+
align-items: center;
|
|
1015
|
+
padding: 20px 16px;
|
|
1016
|
+
gap: 4px;
|
|
1017
|
+
}
|
|
1018
|
+
.stats-item + .stats-item {
|
|
1019
|
+
border-left: 1px solid var(--rule);
|
|
1020
|
+
}
|
|
1021
|
+
.stats-value {
|
|
1022
|
+
font-variant-numeric: tabular-nums;
|
|
1023
|
+
color: var(--stone);
|
|
1024
|
+
font-size: 1.75rem;
|
|
1025
|
+
font-weight: 500;
|
|
1026
|
+
line-height: 1.1;
|
|
1027
|
+
}
|
|
1028
|
+
.stats-label {
|
|
1029
|
+
font-size: 0.6875rem;
|
|
1030
|
+
color: var(--stone-3);
|
|
1031
|
+
text-transform: uppercase;
|
|
1032
|
+
letter-spacing: 0.1em;
|
|
1033
|
+
font-family: var(--font-mono);
|
|
920
1034
|
}
|
|
921
|
-
.metric-card:hover { background: var(--surface-raised); border-color: rgba(255,255,255,0.14); }
|
|
922
|
-
.metric-value { display: block; font-size: 2.25rem; font-weight: 400; color: var(--text-primary); line-height: 1; letter-spacing: -0.02em; }
|
|
923
|
-
.metric-label { display: block; font-size: 0.625rem; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.2em; color: var(--text-muted); margin-top: 8px; }
|
|
924
1035
|
|
|
925
1036
|
/* \u2500\u2500 Narrative \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
926
|
-
.narrative-
|
|
1037
|
+
.narrative-section { margin-bottom: 56px; }
|
|
1038
|
+
.narrative-section .eyebrow { margin-bottom: 24px; }
|
|
1039
|
+
.narrative-content { font-size: 0.9375rem; line-height: 1.8; }
|
|
927
1040
|
.narrative-content p + p { margin-top: 18px; }
|
|
928
1041
|
|
|
929
1042
|
/* \u2500\u2500 Charts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
930
|
-
.chart-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
.
|
|
934
|
-
.
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
thead { position: sticky; top: 0; z-index: 1; }
|
|
940
|
-
th {
|
|
941
|
-
background: var(--bg);
|
|
942
|
-
border-bottom: 1px solid var(--border);
|
|
943
|
-
padding: 12px 16px;
|
|
944
|
-
text-align: left;
|
|
1043
|
+
.chart-container { height: 220px; position: relative; margin-bottom: 0; }
|
|
1044
|
+
|
|
1045
|
+
/* \u2500\u2500 Type bars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1046
|
+
.type-bars, .area-bars { display: flex; flex-direction: column; gap: 12px; }
|
|
1047
|
+
.bar-row { display: flex; align-items: center; gap: 16px; }
|
|
1048
|
+
.bar-label {
|
|
1049
|
+
min-width: 60px;
|
|
1050
|
+
flex-shrink: 0;
|
|
1051
|
+
font-size: 0.6875rem;
|
|
945
1052
|
font-weight: 500;
|
|
1053
|
+
text-transform: uppercase;
|
|
1054
|
+
letter-spacing: 0.04em;
|
|
1055
|
+
color: var(--stone-3);
|
|
1056
|
+
text-align: right;
|
|
1057
|
+
white-space: nowrap;
|
|
1058
|
+
overflow: hidden;
|
|
1059
|
+
text-overflow: ellipsis;
|
|
1060
|
+
}
|
|
1061
|
+
.bar-track {
|
|
1062
|
+
flex: 1;
|
|
1063
|
+
height: 4px;
|
|
1064
|
+
background: var(--rule-light);
|
|
1065
|
+
border-radius: 2px;
|
|
1066
|
+
overflow: hidden;
|
|
1067
|
+
}
|
|
1068
|
+
.bar-fill {
|
|
1069
|
+
height: 100%;
|
|
1070
|
+
border-radius: 2px;
|
|
1071
|
+
transition: width 0.6s ease;
|
|
1072
|
+
}
|
|
1073
|
+
.bar-count {
|
|
1074
|
+
width: 32px;
|
|
1075
|
+
flex-shrink: 0;
|
|
1076
|
+
font-size: 0.6875rem;
|
|
1077
|
+
color: var(--stone-3);
|
|
1078
|
+
text-align: right;
|
|
1079
|
+
font-variant-numeric: tabular-nums;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
.bar-type-feat { background: var(--teal); }
|
|
1083
|
+
.bar-type-fix { background: var(--amber); }
|
|
1084
|
+
.bar-type-chore { background: #9A8868; }
|
|
1085
|
+
.bar-type-style { background: #8A7AB0; }
|
|
1086
|
+
.bar-type-refactor { background: #6A9EB8; }
|
|
1087
|
+
.bar-type-docs { background: #609A7A; }
|
|
1088
|
+
.bar-type-test { background: #A07A5A; }
|
|
1089
|
+
.bar-type-perf { background: #8A8860; }
|
|
1090
|
+
.bar-type-ci { background: #4A8A9A; }
|
|
1091
|
+
.bar-type-build { background: #7A8A5A; }
|
|
1092
|
+
.bar-type-revert { background: #A06A7A; }
|
|
1093
|
+
.bar-type-merge { background: #6A7A6A; }
|
|
1094
|
+
.bar-type-other { background: #4A4540; }
|
|
1095
|
+
|
|
1096
|
+
.bar-type-area { background: var(--amber); }
|
|
1097
|
+
|
|
1098
|
+
/* \u2500\u2500 Commit log \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1099
|
+
.commit-scroll {
|
|
1100
|
+
max-height: 600px;
|
|
1101
|
+
overflow-y: auto;
|
|
1102
|
+
border-top: 1px solid var(--rule);
|
|
1103
|
+
}
|
|
1104
|
+
.commit-scroll::-webkit-scrollbar { width: 6px; }
|
|
1105
|
+
.commit-scroll::-webkit-scrollbar-track { background: transparent; }
|
|
1106
|
+
.commit-scroll::-webkit-scrollbar-thumb { background: #3A3630; border-radius: 3px; }
|
|
1107
|
+
.commit-scroll::-webkit-scrollbar-thumb:hover { background: #5A5040; }
|
|
1108
|
+
.commit-scroll { scrollbar-width: thin; scrollbar-color: #3A3630 transparent; }
|
|
1109
|
+
.commit-grid-header {
|
|
1110
|
+
display: flex;
|
|
1111
|
+
position: sticky;
|
|
1112
|
+
top: 0;
|
|
1113
|
+
z-index: 1;
|
|
1114
|
+
background: var(--bg);
|
|
1115
|
+
border-bottom: 1px solid var(--rule);
|
|
1116
|
+
}
|
|
1117
|
+
.commit-grid-header .commit-cell {
|
|
946
1118
|
font-size: 0.625rem;
|
|
947
|
-
font-
|
|
1119
|
+
font-weight: 500;
|
|
948
1120
|
text-transform: uppercase;
|
|
949
1121
|
letter-spacing: 0.1em;
|
|
950
|
-
color: var(--
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
.
|
|
958
|
-
.
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
.
|
|
966
|
-
.
|
|
967
|
-
.type
|
|
968
|
-
.
|
|
969
|
-
.
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
.
|
|
979
|
-
.
|
|
1122
|
+
color: var(--stone-3);
|
|
1123
|
+
padding: 10px 8px;
|
|
1124
|
+
}
|
|
1125
|
+
.commit-row {
|
|
1126
|
+
display: flex;
|
|
1127
|
+
border-bottom: 1px solid var(--rule);
|
|
1128
|
+
}
|
|
1129
|
+
.commit-row:last-child { border-bottom: none; }
|
|
1130
|
+
.commit-row .commit-cell {
|
|
1131
|
+
padding: 10px 8px;
|
|
1132
|
+
font-size: 0.8125rem;
|
|
1133
|
+
overflow: hidden;
|
|
1134
|
+
text-overflow: ellipsis;
|
|
1135
|
+
white-space: nowrap;
|
|
1136
|
+
}
|
|
1137
|
+
.commit-cell.hash { width: 72px; flex-shrink: 0; font-family: var(--font-mono); color: var(--stone-3); font-size: 0.75rem; }
|
|
1138
|
+
.commit-cell.date { width: 96px; flex-shrink: 0; font-family: var(--font-mono); color: var(--stone-3); font-size: 0.75rem; }
|
|
1139
|
+
.commit-cell.type { width: 64px; flex-shrink: 0; }
|
|
1140
|
+
.commit-cell.subject { flex: 1; min-width: 0; color: var(--stone); }
|
|
1141
|
+
.commit-cell .type-badge {
|
|
1142
|
+
display: inline-block;
|
|
1143
|
+
padding: 1px 8px;
|
|
1144
|
+
border-radius: 10px;
|
|
1145
|
+
font-size: 0.625rem;
|
|
1146
|
+
font-weight: 500;
|
|
1147
|
+
text-transform: uppercase;
|
|
1148
|
+
letter-spacing: 0.04em;
|
|
1149
|
+
}
|
|
1150
|
+
.type-feat { background: rgba(126,184,164,0.15); color: var(--teal); }
|
|
1151
|
+
.type-fix { background: rgba(196,118,58,0.15); color: var(--amber); }
|
|
1152
|
+
.type-chore { background: rgba(154,136,104,0.2); color: #9A8868; }
|
|
1153
|
+
.type-style { background: rgba(138,122,176,0.15); color: #8A7AB0; }
|
|
1154
|
+
.type-refactor { background: rgba(106,158,184,0.15); color: #6A9EB8; }
|
|
1155
|
+
.type-docs { background: rgba(96,154,122,0.15); color: #609A7A; }
|
|
1156
|
+
.type-test { background: rgba(160,122,90,0.15); color: #A07A5A; }
|
|
1157
|
+
.type-perf { background: rgba(138,136,96,0.15); color: #8A8860; }
|
|
1158
|
+
.type-ci { background: rgba(74,138,154,0.15); color: #4A8A9A; }
|
|
1159
|
+
.type-build { background: rgba(122,138,90,0.15); color: #7A8A5A; }
|
|
1160
|
+
.type-revert { background: rgba(160,106,122,0.15); color: #A06A7A; }
|
|
1161
|
+
.type-merge { background: rgba(106,122,106,0.15); color: #6A7A6A; }
|
|
1162
|
+
.type-other { background: rgba(74,69,64,0.3); color: #4A4540; }
|
|
1163
|
+
|
|
1164
|
+
/* \u2500\u2500 Side-by-side grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1165
|
+
.side-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-bottom: 56px; }
|
|
1166
|
+
.side-grid > section { margin-bottom: 0; }
|
|
1167
|
+
|
|
1168
|
+
/* \u2500\u2500 Ticket / Reviewer list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1169
|
+
.ticket-list, .reviewer-list { list-style: none; }
|
|
1170
|
+
.ticket-list li, .reviewer-list li {
|
|
1171
|
+
display: flex;
|
|
1172
|
+
justify-content: space-between;
|
|
1173
|
+
align-items: center;
|
|
1174
|
+
padding: 8px 0;
|
|
1175
|
+
border-bottom: 1px solid var(--rule);
|
|
1176
|
+
}
|
|
1177
|
+
.ticket-list li:last-child, .reviewer-list li:last-child { border-bottom: none; }
|
|
1178
|
+
.ticket-id, .reviewer-name {
|
|
1179
|
+
font-size: 0.75rem;
|
|
1180
|
+
color: var(--stone);
|
|
1181
|
+
font-weight: 400;
|
|
1182
|
+
}
|
|
1183
|
+
.ticket-count, .reviewer-count {
|
|
1184
|
+
font-size: 0.75rem;
|
|
1185
|
+
color: var(--stone-3);
|
|
1186
|
+
font-variant-numeric: tabular-nums;
|
|
1187
|
+
font-family: var(--font-mono);
|
|
1188
|
+
}
|
|
980
1189
|
|
|
981
1190
|
/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
982
1191
|
.empty-state {
|
|
983
1192
|
text-align: center;
|
|
984
|
-
padding:
|
|
985
|
-
color: var(--
|
|
986
|
-
}
|
|
987
|
-
.empty-icon {
|
|
988
|
-
display: block;
|
|
989
|
-
font-size: 2rem;
|
|
990
|
-
line-height: 1;
|
|
991
|
-
margin-bottom: 16px;
|
|
992
|
-
opacity: 0.25;
|
|
993
|
-
font-family: var(--font-mono);
|
|
994
|
-
color: var(--text-muted);
|
|
995
|
-
letter-spacing: 0.1em;
|
|
1193
|
+
padding: 80px 24px;
|
|
1194
|
+
color: var(--stone-2);
|
|
996
1195
|
}
|
|
997
|
-
.empty-state p { font-size:
|
|
1196
|
+
.empty-state p { font-size: 1rem; margin: 0 auto; color: var(--stone-2); }
|
|
1197
|
+
|
|
1198
|
+
/* \u2500\u2500 Scroll-in animation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1199
|
+
section { opacity: 0; transform: translateY(6px); transition: opacity 0.5s ease-out, transform 0.5s ease-out; }
|
|
1200
|
+
section.section-visible { opacity: 1; transform: translateY(0); }
|
|
998
1201
|
|
|
999
1202
|
/* \u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1000
1203
|
.dashboard-footer {
|
|
1001
|
-
margin-top:
|
|
1204
|
+
margin-top: 80px;
|
|
1002
1205
|
padding-top: 20px;
|
|
1003
|
-
border-top: 1px solid var(--
|
|
1206
|
+
border-top: 1px solid var(--rule);
|
|
1004
1207
|
display: flex;
|
|
1005
1208
|
justify-content: flex-end;
|
|
1006
1209
|
align-items: center;
|
|
@@ -1008,15 +1211,15 @@ tr:hover td { background: var(--surface-raised); }
|
|
|
1008
1211
|
}
|
|
1009
1212
|
.dashboard-footer p {
|
|
1010
1213
|
font-size: 0.6875rem;
|
|
1011
|
-
color: var(--
|
|
1214
|
+
color: var(--stone-3);
|
|
1012
1215
|
max-width: none;
|
|
1013
1216
|
font-family: var(--font-mono);
|
|
1014
1217
|
}
|
|
1015
1218
|
.dashboard-footer .footer-badge {
|
|
1016
1219
|
font-size: 0.625rem;
|
|
1017
|
-
color: var(--
|
|
1018
|
-
border: 1px solid var(--
|
|
1019
|
-
border-radius:
|
|
1220
|
+
color: var(--stone-3);
|
|
1221
|
+
border: 1px solid var(--rule);
|
|
1222
|
+
border-radius: 10px;
|
|
1020
1223
|
padding: 2px 8px;
|
|
1021
1224
|
font-family: var(--font-mono);
|
|
1022
1225
|
text-transform: uppercase;
|
|
@@ -1026,31 +1229,38 @@ tr:hover td { background: var(--surface-raised); }
|
|
|
1026
1229
|
/* \u2500\u2500 Print \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1027
1230
|
@media print {
|
|
1028
1231
|
body { background: #fff; color: #000; padding: 0; max-width: none; -webkit-font-smoothing: auto; -moz-osx-font-smoothing: auto; }
|
|
1029
|
-
:root { --
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
tr:hover td { background: transparent; }
|
|
1034
|
-
.dashboard-footer { border-top-color: #ccc; }
|
|
1232
|
+
:root { --stone: #000; --stone-2: #555; --stone-3: #777; --bg: #fff; --rule: #ddd; --rule-light: #ddd; }
|
|
1233
|
+
section { opacity: 1; transform: none; }
|
|
1234
|
+
.stats-item + .stats-item { border-left-color: #ddd; }
|
|
1235
|
+
.dashboard-footer { border-top-color: #ddd; }
|
|
1035
1236
|
}
|
|
1036
1237
|
|
|
1037
1238
|
/* \u2500\u2500 Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1038
|
-
@media (max-width: 960px) {
|
|
1039
|
-
.charts-split { grid-template-columns: 1fr; gap: 16px; }
|
|
1040
|
-
}
|
|
1041
1239
|
@media (max-width: 700px) {
|
|
1042
|
-
body { padding: 24px
|
|
1043
|
-
.
|
|
1044
|
-
.
|
|
1045
|
-
.
|
|
1046
|
-
.
|
|
1240
|
+
body { padding: 48px 24px; }
|
|
1241
|
+
.hero { margin-bottom: 48px; }
|
|
1242
|
+
.stats-item { padding: 16px 12px; }
|
|
1243
|
+
.stats-value { font-size: 1.375rem; }
|
|
1244
|
+
.commit-grid-header { display: none; }
|
|
1245
|
+
.commit-cell.hash { width: 56px; }
|
|
1246
|
+
.commit-cell.date { width: 80px; }
|
|
1247
|
+
.commit-cell.type { width: 56px; }
|
|
1047
1248
|
}
|
|
1048
1249
|
@media (max-width: 480px) {
|
|
1049
|
-
body { padding: 16px
|
|
1050
|
-
.
|
|
1051
|
-
.
|
|
1250
|
+
body { padding: 32px 16px; }
|
|
1251
|
+
.commit-grid-header { display: none; }
|
|
1252
|
+
.commit-row { flex-wrap: wrap; gap: 0; }
|
|
1253
|
+
.commit-row .commit-cell { padding: 4px 8px; border-bottom: none; }
|
|
1254
|
+
.commit-row .commit-cell.hash { width: auto; order: 1; }
|
|
1255
|
+
.commit-row .commit-cell.date { width: auto; order: 2; }
|
|
1256
|
+
.commit-row .commit-cell.type { width: 100%; order: 3; padding-top: 0; }
|
|
1257
|
+
.commit-row .commit-cell.subject { width: 100%; flex: none; order: 4; padding-top: 0; }
|
|
1052
1258
|
.dashboard-footer { flex-direction: column; align-items: flex-start; }
|
|
1053
1259
|
}
|
|
1260
|
+
|
|
1261
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1262
|
+
section { opacity: 1; transform: none; transition: none; }
|
|
1263
|
+
}
|
|
1054
1264
|
`;
|
|
1055
1265
|
|
|
1056
1266
|
// src/report/dashboard.html.ts
|
|
@@ -1062,7 +1272,7 @@ function buildDashboardData(analysis, commits, repoName, narrative) {
|
|
|
1062
1272
|
analysis.classification.perCommit.map((c) => [c.hash, c.type])
|
|
1063
1273
|
);
|
|
1064
1274
|
const areaLookup = analysis.areas;
|
|
1065
|
-
const recentCommits = commits.slice(
|
|
1275
|
+
const recentCommits = commits.slice(0, 200).map((c) => ({
|
|
1066
1276
|
hash: c.hash,
|
|
1067
1277
|
date: c.date,
|
|
1068
1278
|
subject: c.subject,
|
|
@@ -1085,9 +1295,10 @@ function buildDashboardData(analysis, commits, repoName, narrative) {
|
|
|
1085
1295
|
typeCounts: analysis.classification.counts,
|
|
1086
1296
|
areaCounts: areaCountsArr,
|
|
1087
1297
|
topTickets,
|
|
1298
|
+
reviewers: analysis.reviewers,
|
|
1088
1299
|
recentCommits,
|
|
1089
1300
|
narrative,
|
|
1090
|
-
version: true ? "0.1.
|
|
1301
|
+
version: true ? "0.1.4" : "dev",
|
|
1091
1302
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1092
1303
|
};
|
|
1093
1304
|
}
|
|
@@ -1098,7 +1309,8 @@ function computePeriod(commits) {
|
|
|
1098
1309
|
const end = dates[dates.length - 1].slice(0, 7);
|
|
1099
1310
|
return { start, end };
|
|
1100
1311
|
}
|
|
1101
|
-
function assembleDashboard(
|
|
1312
|
+
function assembleDashboard(header, statsBar, narrative, monthlyChart, typeBars, areaBars, sideBySide, recentCommits, footer, chartJs, chartInitScript) {
|
|
1313
|
+
const scrollObserver = `document.addEventListener("DOMContentLoaded",function(){if(window.matchMedia("(prefers-reduced-motion:reduce)").matches)return;var o=new IntersectionObserver(function(e){e.forEach(function(e,i){if(e.isIntersecting){setTimeout(function(){e.target.classList.add("section-visible")},i*80);o.unobserve(e.target)}})},{threshold:0.1});document.querySelectorAll("section").forEach(function(e){o.observe(e)})});`;
|
|
1102
1314
|
return `<!DOCTYPE html>
|
|
1103
1315
|
<html lang="en">
|
|
1104
1316
|
<head>
|
|
@@ -1109,28 +1321,43 @@ function assembleDashboard(sections, chartJs, chartInitScript) {
|
|
|
1109
1321
|
<script>${chartJs}</script>
|
|
1110
1322
|
</head>
|
|
1111
1323
|
<body>
|
|
1112
|
-
${
|
|
1113
|
-
${
|
|
1114
|
-
${
|
|
1115
|
-
${
|
|
1116
|
-
${
|
|
1117
|
-
${
|
|
1118
|
-
${
|
|
1324
|
+
${header}
|
|
1325
|
+
${statsBar}
|
|
1326
|
+
${narrative}
|
|
1327
|
+
${monthlyChart}
|
|
1328
|
+
${typeBars}
|
|
1329
|
+
${areaBars}
|
|
1330
|
+
${sideBySide}
|
|
1331
|
+
${recentCommits}
|
|
1332
|
+
${footer}
|
|
1119
1333
|
<script>${chartInitScript}</script>
|
|
1334
|
+
<script>${scrollObserver}</script>
|
|
1120
1335
|
</body>
|
|
1121
1336
|
</html>`;
|
|
1122
1337
|
}
|
|
1123
1338
|
function buildSections(data, chartJs, chartInitScript) {
|
|
1124
|
-
const
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
}
|
|
1133
|
-
return assembleDashboard(
|
|
1339
|
+
const generatedAt = data.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1340
|
+
const ticketsHtml = renderTickets(data.topTickets);
|
|
1341
|
+
const reviewersHtml = renderReviewers(data.reviewers);
|
|
1342
|
+
let sideBySide = "";
|
|
1343
|
+
if (ticketsHtml && reviewersHtml) {
|
|
1344
|
+
sideBySide = `<div class="side-grid">${ticketsHtml}${reviewersHtml}</div>`;
|
|
1345
|
+
} else {
|
|
1346
|
+
sideBySide = ticketsHtml + reviewersHtml;
|
|
1347
|
+
}
|
|
1348
|
+
return assembleDashboard(
|
|
1349
|
+
renderHeader(data.repoName, data.period, generatedAt, data.totals),
|
|
1350
|
+
renderStatsBar(data.totals),
|
|
1351
|
+
renderNarrativeBlock(data.narrative),
|
|
1352
|
+
renderMonthlyChart(),
|
|
1353
|
+
renderTypeBars(data.typeCounts),
|
|
1354
|
+
renderAreaBars(data.areaCounts),
|
|
1355
|
+
sideBySide,
|
|
1356
|
+
renderRecentCommits(data.recentCommits),
|
|
1357
|
+
renderFooter(data.version ?? "0.0.0-dev", generatedAt),
|
|
1358
|
+
chartJs,
|
|
1359
|
+
chartInitScript
|
|
1360
|
+
);
|
|
1134
1361
|
}
|
|
1135
1362
|
|
|
1136
1363
|
// src/report/render.ts
|
|
@@ -1146,56 +1373,11 @@ function monthlyActivityConfig(timeline) {
|
|
|
1146
1373
|
{
|
|
1147
1374
|
label: "Commits",
|
|
1148
1375
|
data: timeline.map((b) => b.count),
|
|
1149
|
-
backgroundColor: "
|
|
1150
|
-
borderColor: "
|
|
1151
|
-
borderWidth:
|
|
1152
|
-
borderRadius:
|
|
1153
|
-
|
|
1154
|
-
]
|
|
1155
|
-
},
|
|
1156
|
-
options: {
|
|
1157
|
-
responsive: true,
|
|
1158
|
-
maintainAspectRatio: false,
|
|
1159
|
-
plugins: { legend: { display: false } },
|
|
1160
|
-
scales: {
|
|
1161
|
-
x: { ticks: { color: "#6b7280" }, grid: { color: "rgba(255,255,255,0.06)" } },
|
|
1162
|
-
y: {
|
|
1163
|
-
ticks: { color: "#6b7280", stepSize: 1 },
|
|
1164
|
-
grid: { color: "rgba(255,255,255,0.06)" }
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
};
|
|
1169
|
-
}
|
|
1170
|
-
function typeBreakdownConfig(counts) {
|
|
1171
|
-
const labels = Object.keys(counts);
|
|
1172
|
-
const data = Object.values(counts);
|
|
1173
|
-
const COLORS = {
|
|
1174
|
-
feat: "#34d399",
|
|
1175
|
-
fix: "#fbbf24",
|
|
1176
|
-
chore: "#6b7280",
|
|
1177
|
-
docs: "#60a5fa",
|
|
1178
|
-
refactor: "#a78bfa",
|
|
1179
|
-
test: "#f87171",
|
|
1180
|
-
style: "#34d399",
|
|
1181
|
-
perf: "#fb923c",
|
|
1182
|
-
ci: "#a78bfa",
|
|
1183
|
-
build: "#2dd4bf",
|
|
1184
|
-
revert: "#f87171",
|
|
1185
|
-
merge: "#e2e8f0",
|
|
1186
|
-
other: "#4b5563"
|
|
1187
|
-
};
|
|
1188
|
-
return {
|
|
1189
|
-
type: "doughnut",
|
|
1190
|
-
data: {
|
|
1191
|
-
labels,
|
|
1192
|
-
datasets: [
|
|
1193
|
-
{
|
|
1194
|
-
data,
|
|
1195
|
-
backgroundColor: labels.map(
|
|
1196
|
-
(l) => COLORS[l] ?? COLORS.other
|
|
1197
|
-
),
|
|
1198
|
-
borderWidth: 0
|
|
1376
|
+
backgroundColor: "#C4763A",
|
|
1377
|
+
borderColor: "#C4763A",
|
|
1378
|
+
borderWidth: 0,
|
|
1379
|
+
borderRadius: 2,
|
|
1380
|
+
hoverBackgroundColor: "#D48A4A"
|
|
1199
1381
|
}
|
|
1200
1382
|
]
|
|
1201
1383
|
},
|
|
@@ -1203,41 +1385,26 @@ function typeBreakdownConfig(counts) {
|
|
|
1203
1385
|
responsive: true,
|
|
1204
1386
|
maintainAspectRatio: false,
|
|
1205
1387
|
plugins: {
|
|
1206
|
-
legend: {
|
|
1207
|
-
|
|
1208
|
-
|
|
1388
|
+
legend: { display: false },
|
|
1389
|
+
tooltip: {
|
|
1390
|
+
backgroundColor: "#1A1810",
|
|
1391
|
+
titleFont: { size: 11, family: "ui-monospace, SFMono-Regular, Consolas, monospace" },
|
|
1392
|
+
bodyFont: { size: 12, family: "ui-monospace, SFMono-Regular, Consolas, monospace" },
|
|
1393
|
+
padding: 10,
|
|
1394
|
+
cornerRadius: 4,
|
|
1395
|
+
borderColor: "rgba(242,237,230,0.12)",
|
|
1396
|
+
borderWidth: 1
|
|
1209
1397
|
}
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
};
|
|
1213
|
-
}
|
|
1214
|
-
function areaBreakdownConfig(areas) {
|
|
1215
|
-
return {
|
|
1216
|
-
type: "bar",
|
|
1217
|
-
indexAxis: "y",
|
|
1218
|
-
data: {
|
|
1219
|
-
labels: areas.map((a) => a.area),
|
|
1220
|
-
datasets: [
|
|
1221
|
-
{
|
|
1222
|
-
label: "Commits",
|
|
1223
|
-
data: areas.map((a) => a.count),
|
|
1224
|
-
backgroundColor: "rgba(226, 232, 240, 0.5)",
|
|
1225
|
-
borderColor: "rgba(226, 232, 240, 0.8)",
|
|
1226
|
-
borderWidth: 1,
|
|
1227
|
-
borderRadius: 3
|
|
1228
|
-
}
|
|
1229
|
-
]
|
|
1230
|
-
},
|
|
1231
|
-
options: {
|
|
1232
|
-
responsive: true,
|
|
1233
|
-
maintainAspectRatio: false,
|
|
1234
|
-
plugins: { legend: { display: false } },
|
|
1398
|
+
},
|
|
1235
1399
|
scales: {
|
|
1236
1400
|
x: {
|
|
1237
|
-
ticks: { color: "#
|
|
1238
|
-
grid: { color: "rgba(
|
|
1401
|
+
ticks: { color: "#7A7060", font: { size: 10, family: "ui-monospace, SFMono-Regular, Consolas, monospace" } },
|
|
1402
|
+
grid: { color: "rgba(242,237,230,0.05)" }
|
|
1239
1403
|
},
|
|
1240
|
-
y: {
|
|
1404
|
+
y: {
|
|
1405
|
+
ticks: { color: "#7A7060", stepSize: 1, font: { size: 10, family: "ui-monospace, SFMono-Regular, Consolas, monospace" } },
|
|
1406
|
+
grid: { color: "rgba(242,237,230,0.05)" }
|
|
1407
|
+
}
|
|
1241
1408
|
}
|
|
1242
1409
|
}
|
|
1243
1410
|
};
|
|
@@ -1247,21 +1414,11 @@ function areaBreakdownConfig(areas) {
|
|
|
1247
1414
|
function buildMonthlyConfig(data) {
|
|
1248
1415
|
return monthlyActivityConfig(data.timeline);
|
|
1249
1416
|
}
|
|
1250
|
-
function buildTypeConfig(data) {
|
|
1251
|
-
return typeBreakdownConfig(data.typeCounts);
|
|
1252
|
-
}
|
|
1253
|
-
function buildAreaConfig(data) {
|
|
1254
|
-
return areaBreakdownConfig(data.areaCounts);
|
|
1255
|
-
}
|
|
1256
1417
|
function buildChartInitScript(data) {
|
|
1257
1418
|
const monthly = JSON.stringify(buildMonthlyConfig(data));
|
|
1258
|
-
const types = JSON.stringify(buildTypeConfig(data));
|
|
1259
|
-
const areas = JSON.stringify(buildAreaConfig(data));
|
|
1260
1419
|
return `
|
|
1261
1420
|
document.addEventListener("DOMContentLoaded", function () {
|
|
1262
1421
|
new Chart(document.getElementById("chart-monthly"), ${monthly});
|
|
1263
|
-
new Chart(document.getElementById("chart-types"), ${types});
|
|
1264
|
-
new Chart(document.getElementById("chart-areas"), ${areas});
|
|
1265
1422
|
});`;
|
|
1266
1423
|
}
|
|
1267
1424
|
|
|
@@ -1546,6 +1703,12 @@ function registerGenerateCommand(program) {
|
|
|
1546
1703
|
});
|
|
1547
1704
|
commits = result.commits;
|
|
1548
1705
|
}
|
|
1706
|
+
if (opts.author) {
|
|
1707
|
+
const needle = opts.author.toLowerCase();
|
|
1708
|
+
commits = commits.filter(
|
|
1709
|
+
(c) => c.authorName.toLowerCase().includes(needle) || c.authorEmail.toLowerCase().includes(needle)
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1549
1712
|
endPhase(t1, `${commits.length} commits `);
|
|
1550
1713
|
if (commits.length === 0) {
|
|
1551
1714
|
console.error("No commits found.");
|
|
@@ -1559,6 +1722,7 @@ function registerGenerateCommand(program) {
|
|
|
1559
1722
|
typeCounts: {},
|
|
1560
1723
|
areaCounts: [],
|
|
1561
1724
|
topTickets: [],
|
|
1725
|
+
reviewers: [],
|
|
1562
1726
|
recentCommits: []
|
|
1563
1727
|
},
|
|
1564
1728
|
chartJs: opts.cdnCharts ? "" : CHART_JS
|
|
@@ -1648,7 +1812,7 @@ function getRepoName(repoPath) {
|
|
|
1648
1812
|
}
|
|
1649
1813
|
|
|
1650
1814
|
// src/cli.ts
|
|
1651
|
-
var VERSION = true ? "0.1.
|
|
1815
|
+
var VERSION = true ? "0.1.4" : "0.0.0-dev";
|
|
1652
1816
|
function buildProgram() {
|
|
1653
1817
|
const program = new Command("commit-insights");
|
|
1654
1818
|
program.description("Generate a local git contribution dashboard from commit history").version(VERSION);
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commit-insights",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/hinedy/commit-insights.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/hinedy/commit-insights#readme",
|
|
5
10
|
"description": "Generate a local git contribution dashboard from commit history",
|
|
6
11
|
"type": "module",
|
|
7
12
|
"engines": {
|