diff --git a/src/App.svelte b/src/App.svelte index ea472a7..b07f449 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -6,6 +6,7 @@ import SamplePreview from "./components/SamplePreview.svelte"; import DailyTrackingButton from "./components/DailyTrackingButton.svelte"; import ResultsView from "./components/ResultsView.svelte"; + import SiteFooter from "./components/SiteFooter.svelte"; import TagInput from "./components/TagInput.svelte"; import ThemeToggle from "./components/ThemeToggle.svelte"; import TrustGlossary from "./components/TrustGlossary.svelte"; @@ -618,15 +619,7 @@ - +
{ afterEach(() => vi.unstubAllGlobals()); + test("links to the source repository from the footer", () => { + render(App); + + expect(screen.getByRole("link", { name: "npm.report on GitHub" })).toHaveAttribute( + "href", + "https://github.com/serhalp/npm.report", + ); + }); + test("validates required organizations before running", async () => { const user = userEvent.setup(); render(App); diff --git a/src/SharedReport.svelte b/src/SharedReport.svelte index f981cd7..79670e0 100644 --- a/src/SharedReport.svelte +++ b/src/SharedReport.svelte @@ -3,6 +3,7 @@ import HistoryPanel from "./components/HistoryPanel.svelte"; import DailyTrackingButton from "./components/DailyTrackingButton.svelte"; import ResultsView from "./components/ResultsView.svelte"; + import SiteFooter from "./components/SiteFooter.svelte"; import ThemeToggle from "./components/ThemeToggle.svelte"; import TrustGlossary from "./components/TrustGlossary.svelte"; import Logo from "./components/Logo.svelte"; @@ -211,6 +212,8 @@ {/if} + +
{ expect(screen.getByText("netlify")).toBeInTheDocument(); expect(screen.getByText(/generated 2026-06-27/)).toBeInTheDocument(); expect(screen.getAllByText("last 12 months").length).toBeGreaterThan(0); + expect(screen.getByRole("link", { name: "npm.report on GitHub" })).toHaveAttribute( + "href", + "https://github.com/serhalp/npm.report", + ); expect(fetch).toHaveBeenCalledWith("/api/reports/report%2Fid"); }); diff --git a/src/components/SiteFooter.svelte b/src/components/SiteFooter.svelte new file mode 100644 index 0000000..5e87872 --- /dev/null +++ b/src/components/SiteFooter.svelte @@ -0,0 +1,27 @@ + diff --git a/src/styles.css b/src/styles.css index c2b4b6c..074dd3a 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1991,8 +1991,10 @@ table.data tbody tr:hover td { .footer { display: flex; - flex-direction: column; - gap: 0.85rem; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: var(--space-md) var(--space-xl); margin-top: 3.75rem; padding-top: 1.375rem; border-top: 1px solid var(--line); @@ -2004,10 +2006,37 @@ table.data tbody tr:hover td { .footer p { margin: 0; } +.footer__brand { + flex: 1 1 32rem; +} +.footer__credits { + display: flex; + align-items: center; + gap: var(--space-sm); + margin-inline-start: auto; + white-space: nowrap; +} .footer a { text-decoration: underline; text-underline-offset: 0.18em; } +.footer__github { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.75rem; + height: 2.75rem; + border-radius: var(--radius); + color: var(--fg-dim); + text-decoration: none; +} +.footer__github:hover { + color: var(--gold); +} +.footer__github:focus-visible { + outline: 2px solid var(--gold-dim); + outline-offset: 2px; +} .footer__mark { color: var(--fg-dim); } @@ -2025,6 +2054,7 @@ table.data tbody tr:hover td { .report-frame > [role="tabpanel"]:focus-visible, .history-stack:focus-visible, .trust-trend__target:focus-visible, + .footer__github:focus-visible, table.data th .sort-button:focus-visible { outline: 2px solid Highlight; outline-offset: 2px;