Skip to content

Commit 265e04b

Browse files
committed
update from review comments
1 parent 579283f commit 265e04b

File tree

8 files changed

+138
-132
lines changed

8 files changed

+138
-132
lines changed

src/components/code-snippet/CodeSnippet.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export const CodeSnippet: FC<Props> = ({ lang, allowCopy, code, children, tags }
132132

133133
{allowCopy && (
134134
<div className="goa-code-snippet-actions--copy">
135-
<GoabTooltip content={isCopied ? `Copy.` : `Copy?`} position="left">
135+
<GoabTooltip content={isCopied ? "Copied" : "Copy"} key={isCopied ? "copied" : "copy"} position="left">
136136
<GoabIconButton icon="copy" onClick={copyCode} />
137137
</GoabTooltip>
138138
</div>

src/components/component-card/ComponentCard.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,15 @@
2727
font: var(--goa-typography-body-s);
2828
margin-top: 1rem;
2929
margin-bottom: 0;
30+
}
31+
32+
.card-content a:focus {
33+
outline: none;
34+
box-shadow: none;
35+
background: none;
36+
}
37+
38+
.card:focus-within {
39+
outline: 3px solid var(--goa-color-interactive-focus);
40+
border-radius: 4px;
3041
}

src/components/component-card/ComponentCard.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { toKebabCase } from "../../utils";
44
import { GoabBadge, GoabText } from "@abgov/react-components";
55
import { useState, useEffect } from "react";
66

7+
export type ComponentStatus = "Published" | "Not Published" | "In Progress";
8+
79
// Define allowed group options as a union type
810
type Group =
911
| "Content layout"
@@ -17,7 +19,7 @@ export interface Props {
1719
description: string;
1820
groups: Group[]; // Use the Group type here
1921
tags?: string[];
20-
status: "Published" | "Not Published" | "In Progress";
22+
status: ComponentStatus;
2123
githubLink?: string;
2224
openIssues?: number;
2325
}
@@ -35,7 +37,7 @@ export function ComponentCard(props: Props) {
3537
testImage.onerror = () => setImageUrl("/images/not-yet-available.png");
3638
}, [imageUrl]);
3739

38-
const getBadgeType = (status: string) => {
40+
const getBadgeType = (status: ComponentStatus) => {
3941
switch (status) {
4042
case "Published":
4143
return null; // No badge for "Published"
@@ -53,7 +55,7 @@ export function ComponentCard(props: Props) {
5355
return (
5456
<div className="card">
5557
{props.status === "Published" ? (
56-
<Link to={toKebabCase(props.name)}>
58+
<Link to={toKebabCase(props.name)} tabIndex={-1}>
5759
<div
5860
className="card-image"
5961
style={{ backgroundImage: `url(${imageUrl})` }}
@@ -62,6 +64,7 @@ export function ComponentCard(props: Props) {
6264
) : (
6365
<div
6466
className="card-image"
67+
tabIndex={-1}
6568
style={{ backgroundImage: `url(${imageUrl})` }}
6669
/>
6770
)}

src/components/component-header/ComponentHeader.tsx

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { GoabBadge, GoabBlock, GoabText } from "@abgov/react-components";
22
import "./ComponentHeader.css";
33
import { Link } from "react-router-dom";
44
import { useEffect, useState } from "react";
5+
import { toSentenceCase, fetchIssueCount } from "../../utils";
56

67
export enum Category {
78
CONTENT_AND_LAYOUT = "Content and layout",
@@ -21,60 +22,18 @@ interface Props {
2122
}
2223

2324
export const ComponentHeader: React.FC<Props> = (props) => {
24-
// Helper to transform "button" -> "Button" for GitHub label
25-
function toSentenceCase(str: string): string {
26-
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
27-
}
28-
2925
const [issueCount, setIssueCount] = useState<number | null>(null);
3026

3127
useEffect(() => {
3228
if (!props.githubLink) return;
3329

34-
const fetchIssueCount = async () => {
35-
const token =
36-
import.meta.env.VITE_GITHUB_TOKEN ||
37-
import.meta.env.VITE_GITHUB_TOKEN_ALTERNATE;
38-
39-
if (!token) {
40-
console.error("GitHub token not provided");
41-
return;
42-
}
43-
30+
const getCount = async () => {
4431
const label = toSentenceCase(props.githubLink!);
45-
const labelQuery = label.includes(" ") ? `\\"${label}\\"` : label;
46-
47-
const query = `
48-
query {
49-
issues: search(query: "is:issue is:open repo:GovAlta/ui-components label:${labelQuery}", type: ISSUE, first: 1) {
50-
issueCount
51-
}
52-
}
53-
`;
54-
55-
try {
56-
const response = await fetch("https://api.github.com/graphql", {
57-
method: "POST",
58-
headers: {
59-
"Content-Type": "application/json",
60-
Authorization: `Bearer ${token}`
61-
},
62-
body: JSON.stringify({ query })
63-
});
64-
65-
const result = await response.json();
66-
if (result.errors) {
67-
console.error("GraphQL errors:", result.errors);
68-
return;
69-
}
70-
71-
setIssueCount(result.data.issues.issueCount);
72-
} catch (error) {
73-
console.error("Error fetching issue count:", error);
74-
}
32+
const count = await fetchIssueCount(label);
33+
setIssueCount(count);
7534
};
7635

77-
fetchIssueCount();
36+
getCount();
7837
}, [props.githubLink]);
7938

8039
return (

src/components/empty-states/examples-empty/ExamplesEmpty.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { GoabContainer, GoabText } from "@abgov/react-components";
22

3-
export interface Props {
4-
figmaLink?: string;
5-
}
63
export function ExamplesEmpty( ) {
74
return (
85
<div className="examples-empty">

src/components/sandbox/sandbox-header/sandboxHeader.tsx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GoabTooltip } from "@abgov/react-components";
2-
import { useState, useEffect, useRef } from "react";
2+
import { useState, useRef } from "react";
33
import "./sandboxHeader.css";
4+
import { toKebabCase } from "../../../utils";
45

56
export interface Props {
67
exampleTitle: string;
@@ -10,23 +11,11 @@ export interface Props {
1011
export function SandboxHeader(props: Props) {
1112
const [isCopied, setIsCopied] = useState(false);
1213
const headingRef = useRef<HTMLDivElement>(null);
13-
const [anchorId, setAnchorId] = useState("");
1414
const [isHovering, setIsHovering] = useState(false);
15-
16-
// Generate a unique anchor ID based on the heading text
17-
useEffect(() => {
18-
if (headingRef.current) {
19-
const generatedId = props.exampleTitle
20-
.toLowerCase()
21-
.replace(/\s+/g, "-") // Replace spaces with dashes
22-
.replace(/[^a-z0-9-]/g, ""); // Remove special characters
23-
setAnchorId(generatedId);
24-
}
25-
}, [props.exampleTitle]);
15+
const anchorId = toKebabCase(props.exampleTitle);
2616

2717
function copyAnchorLink() {
2818
const url = `${window.location.origin}${window.location.pathname}#${anchorId}`;
29-
3019
navigator.clipboard.writeText(url).then(() => {
3120
setIsCopied(true);
3221
setTimeout(() => setIsCopied(false), 2000); // Reset tooltip text after 2s
@@ -44,7 +33,7 @@ export function SandboxHeader(props: Props) {
4433
</h3>
4534

4635
{/* Copy link icon (consistent with CodeSnippet.tsx) */}
47-
<GoabTooltip content={isCopied ? "Copied" : "Copy link"}>
36+
<GoabTooltip content={isCopied ? "Copied" : "Copy link"} key={isCopied ? "copied" : "copy"}>
4837
<button
4938
onClick={copyAnchorLink}
5039
className="copy-icon-button"

src/routes/components/AllComponents.tsx

Lines changed: 8 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { useEffect, useState } from "react";
2+
import { ComponentStatus } from "@components/component-card/ComponentCard";
3+
import { toSentenceCase, fetchAllIssueCounts } from "../../utils";
24
import {
35
GoabTable,
46
GoabTableSortHeader,
@@ -461,7 +463,7 @@ const AllComponents = () => {
461463
];
462464

463465
return initialCards.sort((a, b) => {
464-
const statusOrder = ["Published", "In Progress", "Not Published"];
466+
const statusOrder: ComponentStatus[] = ["Published", "In Progress", "Not Published"];
465467
const statusComparison = statusOrder.indexOf(a.status) - statusOrder.indexOf(b.status);
466468
if (statusComparison !== 0) return statusComparison;
467469
return a.name.localeCompare(b.name);
@@ -486,7 +488,7 @@ const AllComponents = () => {
486488
const newDirection = sortDirection[sortBy] === 1 ? -1 : 1;
487489
const sorted = [...cards].sort((a, b) => {
488490
if (sortBy === "status") {
489-
const statusOrder = ["Published", "In Progress", "Not Published"];
491+
const statusOrder: ComponentStatus[] = ["Published", "In Progress", "Not Published"];
490492
const statusComparison = statusOrder.indexOf(a.status) - statusOrder.indexOf(b.status);
491493
if (statusComparison !== 0) return statusComparison * newDirection;
492494
}
@@ -516,78 +518,20 @@ const AllComponents = () => {
516518
setSortDirection({ [sortBy]: newDirection });
517519
};
518520

519-
// Helper to convert to sentence case
520-
const toSentenceCase = (str: string) => {
521-
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
522-
};
523-
524521
// Helper to format the label query for REST URLs
525522
const getLabelQuery = (name: string) => {
526523
const formatted = toSentenceCase(name);
527524
return formatted.includes(" ") ? `"${formatted}"` : formatted;
528525
};
529526

530527
// Helper to format the label query for GraphQL (escaping inner quotes)
531-
const getGraphQLLabelQuery = (name: string) => {
532-
const formatted = toSentenceCase(name);
533-
return formatted.includes(" ") ? `\\"${formatted}\\"` : formatted;
534-
};
535-
536528
useEffect(() => {
537-
const fetchIssueCountsGraphQL = async () => {
538-
const token =
539-
import.meta.env.VITE_GITHUB_TOKEN ||
540-
import.meta.env.VITE_GITHUB_TOKEN_ALTERNATE;
541-
if (!token) {
542-
console.error("GitHub token not provided");
543-
return;
544-
}
545-
546-
// Build a single GraphQL query for all cards
547-
const queryFields = cards.map((card) => {
548-
const alias = card.name.replace(/\s+/g, "").toLowerCase();
549-
const labelQuery = getGraphQLLabelQuery(card.name);
550-
return `${alias}: search(query: "is:issue is:open repo:GovAlta/ui-components label:${labelQuery}", type: ISSUE, first: 1) { issueCount }`;
551-
}).join("\n");
552-
553-
const graphQLQuery = `
554-
query {
555-
${queryFields}
556-
}
557-
`;
558-
559-
try {
560-
const response = await fetch("https://api.github.com/graphql", {
561-
method: "POST",
562-
headers: {
563-
"Content-Type": "application/json",
564-
Authorization: `Bearer ${token}`,
565-
},
566-
body: JSON.stringify({ query: graphQLQuery }),
567-
});
568-
569-
const result = await response.json();
570-
if (result.errors) {
571-
console.error("GraphQL errors:", result.errors);
572-
return;
573-
}
574-
575-
const newIssueCounts: Record<string, number> = {};
576-
cards.forEach((card) => {
577-
const alias = card.name.replace(/\s+/g, "").toLowerCase();
578-
newIssueCounts[card.name] =
579-
result.data[alias] && result.data[alias].issueCount
580-
? result.data[alias].issueCount
581-
: 0;
582-
});
583-
584-
setIssueCounts(newIssueCounts);
585-
} catch (error) {
586-
console.error("Error fetching issue counts:", error);
587-
}
529+
const loadIssueCounts = async () => {
530+
const issueCounts = await fetchAllIssueCounts(cards);
531+
setIssueCounts(issueCounts);
588532
};
589533

590-
fetchIssueCountsGraphQL();
534+
loadIssueCounts();
591535
}, [cards]);
592536

593537
const renderTable = () => (

0 commit comments

Comments
 (0)