Skip to content

Commit 5e33e5d

Browse files
pfranktestingclaude
andcommitted
Add navigable category index to Report Summary (v1.3.0)
Replace single-count summary badges with per-category clickable links (Paper formatting / References / Citations) that jump directly to the relevant cards in the report. Color-code summary cells with status borders, add category headings with inline Back to top links throughout the report, and fix long-filename overflow in the summary copy line. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent be48fc5 commit 5e33e5d

5 files changed

Lines changed: 271 additions & 44 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## [1.3.0] - 2026-05-23
4+
5+
### Added
6+
7+
- **Report Summary navigation index** — The three summary cards (Failed / Review / Passed) now show a per-category breakdown (Paper formatting, References, Citations) with counts instead of a single total number. Each row is a clickable link that jumps directly to that category's cards in the report.
8+
- **Color-coded summary cards** — Failed card has a red left border, Review amber, Passed green, consistent with the check card convention.
9+
- **Category headings with Back to top** — Every group of cards within a status section is headed by its category name (e.g. "REFERENCES") with a "Back to top" link on the right, replacing the old standalone back-to-top links at the bottom of each section.
10+
11+
### Fixed
12+
13+
- **Long filenames no longer overflow** — Added `overflow-wrap: break-word` to the summary copy line so filenames with no natural break points wrap rather than overflow their container.
14+
315
## [1.2.0] - 2026-05-23
416

517
### Added

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cff-version: 1.2.0
22
message: "If you use this software, please cite it as below."
33
type: software
44
title: APA Coach
5-
version: 1.2.0
5+
version: 1.3.0
66
date-released: 2026-05-23
77
license: GPL-3.0
88
repository-code: https://github.com/PatrickFrankAIU/APA-Coach

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "apa-coach",
3-
"version": "1.2.0",
3+
"version": "1.3.0",
44
"description": "",
55
"main": "index.js",
66
"scripts": {

src/browser/main.jsx

Lines changed: 134 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,143 @@ const STATUS_ORDER = {
5151
skipped: 4,
5252
};
5353

54+
const CHECK_CATEGORY = {
55+
// Paper formatting
56+
"Page numbering": "Paper formatting",
57+
"Title page": "Paper formatting",
58+
"Margins": "Paper formatting",
59+
"Body line spacing": "Paper formatting",
60+
"Heading line spacing": "Paper formatting",
61+
"Body paragraph spacing": "Paper formatting",
62+
"Heading paragraph spacing": "Paper formatting",
63+
"Body first-line indents": "Paper formatting",
64+
"Body alignment": "Paper formatting",
65+
"Font": "Paper formatting",
66+
"Unconverted markup symbols": "Paper formatting",
67+
// References
68+
"References page": "References",
69+
"References heading alignment": "References",
70+
"References line spacing": "References",
71+
"Reference hanging indent": "References",
72+
"Reference DOI/URL": "References",
73+
"Reference short link": "References",
74+
"Unapproved source": "References",
75+
"Reference authors": "References",
76+
"Reference year format": "References",
77+
"Reference title capitalization": "References",
78+
"Reference italics": "References",
79+
"Reference punctuation": "References",
80+
"Reference DOI format": "References",
81+
"Reference link verification": "References",
82+
// Citations
83+
"Inline citations": "Citations",
84+
"Uncited references": "Citations",
85+
"Unmatched citations": "Citations",
86+
"Personal communication": "Citations",
87+
"Citation ampersand": "Citations",
88+
"Citation et al. format": "Citations",
89+
"Citation no-date format": "Citations",
90+
"Citation page format": "Citations",
91+
"Citation multiple sources": "Citations",
92+
"Citation year suffix": "Citations",
93+
"Secondary citations": "Citations",
94+
};
95+
96+
const CATEGORY_ORDER = ["Paper formatting", "References", "Citations"];
97+
5498
function sortChecks(checks) {
5599
return [...checks].sort((a, b) => STATUS_ORDER[a.status] - STATUS_ORDER[b.status]);
56100
}
57101

58-
function SummaryCell({ count, label, href }) {
59-
const Tag = href ? "a" : "div";
102+
function categorySlug(label) {
103+
return label.toLowerCase().replace(/\s+/g, "-");
104+
}
105+
106+
function getCategoryLinksForStatuses(checks, statuses) {
107+
const groups = new Map();
108+
for (const check of checks) {
109+
if (!statuses.includes(check.status)) continue;
110+
const cat = CHECK_CATEGORY[check.rule] ?? "Other";
111+
if (!groups.has(cat)) groups.set(cat, { count: 0, primaryStatus: check.status });
112+
const g = groups.get(cat);
113+
g.count++;
114+
if (STATUS_ORDER[check.status] < STATUS_ORDER[g.primaryStatus]) g.primaryStatus = check.status;
115+
}
116+
const links = [];
117+
for (const cat of [...CATEGORY_ORDER, "Other"]) {
118+
if (groups.has(cat)) {
119+
const { count, primaryStatus } = groups.get(cat);
120+
links.push({ label: cat, count, href: `#${primaryStatus}-${categorySlug(cat)}` });
121+
}
122+
}
123+
return links;
124+
}
125+
126+
function CheckList({ checks, status }) {
127+
const categories = useMemo(() => {
128+
const groups = new Map();
129+
for (const check of checks) {
130+
const cat = CHECK_CATEGORY[check.rule] ?? "Other";
131+
if (!groups.has(cat)) groups.set(cat, []);
132+
groups.get(cat).push(check);
133+
}
134+
const ordered = [];
135+
for (const cat of [...CATEGORY_ORDER, "Other"]) {
136+
if (groups.has(cat)) ordered.push({ label: cat, checks: groups.get(cat) });
137+
}
138+
return ordered;
139+
}, [checks]);
140+
141+
return (
142+
<>
143+
{categories.map(({ label, checks: catChecks }) => (
144+
<React.Fragment key={label}>
145+
<div id={`${status}-${categorySlug(label)}`} className="check-category-label">
146+
<span>{label}</span>
147+
<a href="#top" className="check-category-top">Back to top</a>
148+
</div>
149+
{catChecks.map((check) => (
150+
<CheckCard key={check.rule} check={check} />
151+
))}
152+
</React.Fragment>
153+
))}
154+
</>
155+
);
156+
}
157+
158+
function SummaryCell({ label, links, colorClass }) {
60159
return (
61-
<Tag className={`summary-cell${href ? " summary-cell-link" : ""}`} href={href || undefined}>
160+
<div className={`summary-cell summary-cell--${colorClass}`}>
62161
<dt>{label}</dt>
63-
<dd>{count}</dd>
64-
</Tag>
162+
<dd>
163+
{links.length === 0 ? (
164+
<span className="summary-cell-zero"></span>
165+
) : (
166+
<ul className="summary-cat-links" role="list">
167+
{links.map(({ label: catLabel, count, href }) => (
168+
<li key={catLabel}>
169+
<a href={href} className="summary-cat-link">
170+
<span className="summary-cat-name">{catLabel}</span>
171+
<span className="summary-cat-count">{count}</span>
172+
</a>
173+
</li>
174+
))}
175+
</ul>
176+
)}
177+
</dd>
178+
</div>
65179
);
66180
}
67181

68-
function Summary({ report }) {
69-
const { failed, warn = 0, review, passed } = report.summary;
182+
function Summary({ report, checks }) {
183+
const { failed, warn = 0, review } = report.summary;
70184
const issueCount = failed + warn;
71185
const isReady = issueCount === 0;
72186
const issueText = issueCount === 1 ? "issue" : "issues";
73-
const failHref = failed > 0 ? "#fail-section" : warn > 0 ? "#warn-section" : null;
187+
188+
const failLinks = useMemo(() => getCategoryLinksForStatuses(checks, ["fail", "warn"]), [checks]);
189+
const reviewLinks = useMemo(() => getCategoryLinksForStatuses(checks, ["review"]), [checks]);
190+
const passLinks = useMemo(() => getCategoryLinksForStatuses(checks, ["pass"]), [checks]);
74191

75192
return (
76193
<section className="summary" aria-labelledby="summary-heading">
@@ -99,9 +216,9 @@ function Summary({ report }) {
99216
</button>
100217
</div>
101218
<dl className="summary-grid" aria-label="Check totals">
102-
<SummaryCell count={issueCount} label="Failed" href={failHref} />
103-
<SummaryCell count={review} label="Review" href={review > 0 ? "#review-section" : null} />
104-
<SummaryCell count={passed} label="Passed" href={passed > 0 ? "#pass-section" : null} />
219+
<SummaryCell label="Failed" links={failLinks} colorClass="fail" />
220+
<SummaryCell label="Review" links={reviewLinks} colorClass="review" />
221+
<SummaryCell label="Passed" links={passLinks} colorClass="pass" />
105222
</dl>
106223
</section>
107224
);
@@ -611,26 +728,20 @@ function Report({ report }) {
611728
<p className="print-report-title">APA Formatting Report</p>
612729
<p className="print-report-meta">{report.file} &mdash; Checked {printDate} &mdash; APA Coach v{APP_INFO.version}</p>
613730
</div>
614-
<Summary report={report} />
731+
<Summary report={report} checks={report.checks} />
615732
<section className="checks" aria-label="APA checks">
616733
{failChecks.length > 0 && (
617734
<section id="fail-section" className="check-group" aria-labelledby="fail-heading">
618735
<h3 id="fail-heading" className="check-group-heading">Issues to fix (Required)</h3>
619736
<p className="fail-intro">These items should be corrected before you submit your paper.</p>
620-
{failChecks.map((check) => (
621-
<CheckCard key={check.rule} check={check} />
622-
))}
623-
<a href="#top" className="back-to-top">↑ Back to top</a>
737+
<CheckList checks={failChecks} status="fail" />
624738
</section>
625739
)}
626740
{warnChecks.length > 0 && (
627741
<section id="warn-section" className="check-group" aria-labelledby="warn-heading">
628742
<h3 id="warn-heading" className="check-group-heading">Warnings — verify before submitting</h3>
629743
<p className="warn-intro">These items may indicate a problem. Open each link and confirm it leads to the source you intended.</p>
630-
{warnChecks.map((check) => (
631-
<CheckCard key={check.rule} check={check} />
632-
))}
633-
<a href="#top" className="back-to-top">↑ Back to top</a>
744+
<CheckList checks={warnChecks} status="warn" />
634745
</section>
635746
)}
636747
{reviewChecks.length > 0 && (
@@ -639,28 +750,20 @@ function Report({ report }) {
639750
<p className="review-intro">
640751
These items may not require changes, but are worth double-checking.
641752
</p>
642-
{reviewChecks.map((check) => (
643-
<CheckCard key={check.rule} check={check} />
644-
))}
645-
<a href="#top" className="back-to-top">↑ Back to top</a>
753+
<CheckList checks={reviewChecks} status="review" />
646754
</section>
647755
)}
648756
{passChecks.length > 0 && (
649757
<section id="pass-section" className="check-group" aria-labelledby="pass-heading">
650758
<h3 id="pass-heading" className="check-group-heading">Looks good (Passed)</h3>
651759
<p className="pass-intro">These items meet APA expectations.</p>
652-
{passChecks.map((check) => (
653-
<CheckCard key={check.rule} check={check} />
654-
))}
655-
<a href="#top" className="back-to-top">↑ Back to top</a>
760+
<CheckList checks={passChecks} status="pass" />
656761
</section>
657762
)}
658763
{skippedChecks.length > 0 && (
659764
<section id="skipped-section" className="check-group" aria-labelledby="skipped-heading">
660765
<h3 id="skipped-heading" className="check-group-heading">Not checked (Offline)</h3>
661-
{skippedChecks.map((check) => (
662-
<CheckCard key={check.rule} check={check} />
663-
))}
766+
<CheckList checks={skippedChecks} status="skipped" />
664767
</section>
665768
)}
666769
</section>

0 commit comments

Comments
 (0)