diff --git a/web/src/components/CatalogCharts.test.js b/web/src/components/CatalogCharts.test.js
index 36d99e2..53022e6 100644
--- a/web/src/components/CatalogCharts.test.js
+++ b/web/src/components/CatalogCharts.test.js
@@ -5,6 +5,7 @@ import CatalogCharts from "./CatalogCharts.svelte";
const repos = [
{
name: "cais",
+ html_url: "https://github.com/puppe1990/cais",
language: "Go",
stargazers_count: 2,
traffic: {
@@ -19,6 +20,7 @@ const repos = [
},
{
name: "atlas",
+ html_url: "https://github.com/puppe1990/atlas",
language: "Python",
stargazers_count: 40,
traffic: {
@@ -41,10 +43,10 @@ describe("CatalogCharts", () => {
test("shows top unique visitors and unique cloners", () => {
render(CatalogCharts, { props: { repos } });
const visitors = screen.getByRole("region", { name: "Top unique visitors" });
- expect(within(visitors).getByText("cais")).toBeInTheDocument();
+ expect(within(visitors).getByRole("link", { name: "cais" })).toHaveAttribute("href", "https://github.com/puppe1990/cais");
expect(within(visitors).getByText("70")).toBeInTheDocument();
const cloners = screen.getByRole("region", { name: "Top unique cloners" });
- expect(within(cloners).getByText("atlas")).toBeInTheDocument();
+ expect(within(cloners).getByRole("link", { name: "atlas" })).toHaveAttribute("href", "https://github.com/puppe1990/atlas");
expect(within(cloners).getByText("60")).toBeInTheDocument();
});
@@ -55,6 +57,7 @@ describe("CatalogCharts", () => {
expect(screen.getByRole("region", { name: "Unique visitors by language" })).toBeInTheDocument();
expect(screen.getByRole("region", { name: "Last 14 days" })).toBeInTheDocument();
const quiet = screen.getByRole("region", { name: "Quiet stars" });
- expect(within(quiet).getByText("cais")).toBeInTheDocument();
+ expect(within(quiet).getByRole("link", { name: "cais" })).toHaveAttribute("href", "https://github.com/puppe1990/cais");
+ expect(within(screen.getByRole("region", { name: "Unique visitors by language" })).queryByRole("link")).not.toBeInTheDocument();
});
});
diff --git a/web/src/components/RankChart.svelte b/web/src/components/RankChart.svelte
index b242f46..a04afbf 100644
--- a/web/src/components/RankChart.svelte
+++ b/web/src/components/RankChart.svelte
@@ -18,7 +18,11 @@
{#each rows as row}
-
- {row[nameKey]}
+ {#if row.href}
+ {row[nameKey]}
+ {:else}
+ {row[nameKey]}
+ {/if}
diff --git a/web/src/lib/trafficCharts.js b/web/src/lib/trafficCharts.js
index e830efe..f7843b8 100644
--- a/web/src/lib/trafficCharts.js
+++ b/web/src/lib/trafficCharts.js
@@ -11,6 +11,7 @@ export function rankTraffic(repos, key, limit = 10) {
const rows = trafficRepos(repos)
.map((repo) => ({
name: repo.name,
+ href: repo.html_url || "",
language: repo.language || "Not specified",
stars: repo.stargazers_count || 0,
value: Number(repo.traffic?.[key]) || 0,
@@ -113,7 +114,7 @@ export function quietStarsRank(repos, limit = 10) {
.map((repo) => {
const uniques = repo.traffic.view_uniques || 0;
const stars = repo.stargazers_count || 0;
- return { name: repo.name, uniques, stars, score: uniques / Math.max(stars, 1) };
+ return { name: repo.name, href: repo.html_url || "", uniques, stars, score: uniques / Math.max(stars, 1) };
})
.filter((row) => row.uniques > 0)
.sort((a, b) => b.score - a.score || b.uniques - a.uniques)
diff --git a/web/src/lib/trafficCharts.test.js b/web/src/lib/trafficCharts.test.js
index 9ae8b60..ba2cfd9 100644
--- a/web/src/lib/trafficCharts.test.js
+++ b/web/src/lib/trafficCharts.test.js
@@ -68,6 +68,12 @@ describe("rankTraffic", () => {
]);
});
+ test("keeps the repository html url on ranked rows", () => {
+ const withUrls = catalog.map((repo, i) => ({ ...repo, html_url: `https://github.com/octocat/${repo.name}` }));
+ expect(rankTraffic(withUrls, "view_uniques", 1)[0].href).toBe("https://github.com/octocat/beta");
+ expect(quietStarsRank(withUrls)[0].href).toBe("https://github.com/octocat/beta");
+ });
+
test("scales bar share against the peak value", () => {
const [lead, second] = rankTraffic(catalog, "view_uniques", 10);
expect(lead.share).toBe(100);
diff --git a/web/src/pages/Home.test.js b/web/src/pages/Home.test.js
index 89ea02f..e5d3daa 100644
--- a/web/src/pages/Home.test.js
+++ b/web/src/pages/Home.test.js
@@ -120,8 +120,9 @@ describe("Home", () => {
await fireEvent.click(screen.getByRole("tab", { name: "Charts" }));
expect(screen.getByRole("tab", { name: "Charts" })).toHaveAttribute("aria-selected", "true");
expect(screen.getByRole("region", { name: "Top unique visitors" })).toBeInTheDocument();
- expect(screen.queryByRole("link", { name: "hello-world" })).not.toBeInTheDocument();
+ expect(screen.queryByRole("tabpanel", { name: "Catalog" })).not.toBeInTheDocument();
await fireEvent.click(screen.getByRole("tab", { name: "Catalog" }));
+ expect(screen.getByRole("tabpanel", { name: "Catalog" })).toBeInTheDocument();
expect(screen.getByRole("link", { name: "hello-world" })).toBeInTheDocument();
});
diff --git a/web/static/css/atlas.css b/web/static/css/atlas.css
index 8322174..c316739 100644
--- a/web/static/css/atlas.css
+++ b/web/static/css/atlas.css
@@ -1265,6 +1265,14 @@ a.stat:hover {
font-family: var(--font-mono);
font-size: 0.78rem;
color: var(--ink-dim);
+ text-decoration: none;
+}
+
+a.rank-name:hover,
+a.rank-name:focus-visible {
+ color: var(--copper-hot);
+ text-decoration: underline;
+ outline: none;
}
.rank-track {