Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/about/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe("stripehistory.com about page", () => {
expect(html).toContain("founder side projects and aesthetics programs");
expect(html).toContain("timeline and its focused category views stay aligned");
expect(html).toContain('aria-current="page" href="/about">about</a>');
expect(html).toContain('aria-label="Appearance: light"');
expect(html).toContain('aria-label="Appearance: System"');
expect(html).toContain('href="https://hraness.com/"');
expect(html).toContain('href="https://github.com/hraness/stripe-history"');
expect(html).not.toContain("Atom feed");
Expand Down
37 changes: 37 additions & 0 deletions app/appearance.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { expect, test } from "bun:test";
import { DesignThemeProvider } from "@hraness/design-kit/react";
import { renderToStaticMarkup } from "react-dom/server";

import { ThemeToggle } from "@/support/theme";

test("appearance starts with System and keeps the existing product preference key", () => {
const html = renderToStaticMarkup(
<DesignThemeProvider storageKey="stripe-history-theme-v1">
<ThemeToggle />
</DesignThemeProvider>,
);

expect(html).toContain("stripe-history-theme-v1");
expect(html).toContain('data-hraness-design-theme-guard=""');
expect(html).toContain('data-theme-value="system"');
expect(html).toContain('aria-label="Appearance: System"');
});

test("Stripe History does not keep a second theme runtime", async () => {
const [source, layout, globalError] = await Promise.all([
Bun.file(new URL("../support/theme.tsx", import.meta.url)).text(),
Bun.file(new URL("./layout.tsx", import.meta.url)).text(),
Bun.file(new URL("./global-error.tsx", import.meta.url)).text(),
]);

expect(source).toContain('from "@hraness/design-kit/react"');
expect(source).not.toContain("localStorage");
expect(source).not.toContain("MutationObserver");
expect(source).not.toContain("useSyncExternalStore");
expect(layout).toContain(
'<DesignThemeProvider storageKey="stripe-history-theme-v1">',
);
expect(globalError).toContain(
'<DesignThemeProvider storageKey="stripe-history-theme-v1">',
);
});
20 changes: 14 additions & 6 deletions app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
"use client";

import {
DesignThemeProvider,
ThemeColorSync,
} from "@hraness/design-kit/react";
import type { RouteErrorPageProps } from "./error";
import "./globals.css";

export default function GlobalError({ reset }: RouteErrorPageProps) {
return (
<html lang="en-US">
<html data-theme="light" lang="en-US" suppressHydrationWarning>
<body className="plain-site">
<main className="plain-page stripe-history-main stripe-history-state" id="main-content">
<h1>Stripe History is temporarily unavailable</h1>
<p>The site could not finish loading.</p>
<button onClick={reset} type="button">Try again</button>
</main>
<DesignThemeProvider storageKey="stripe-history-theme-v1">
<ThemeColorSync darkColor="#151515" lightColor="#ffffff" />
<main className="plain-page stripe-history-main stripe-history-state" id="main-content">
<h1>Stripe History is temporarily unavailable</h1>
<p>The site could not finish loading.</p>
<button onClick={reset} type="button">Try again</button>
</main>
</DesignThemeProvider>
</body>
</html>
);
Expand Down
1 change: 1 addition & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import "@hraness/design-kit/styles.css";
@import "../support/styles.css";
@import "../support/brand.css";

Expand Down
9 changes: 6 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { siteThemes } from "@/support/design-kit";
import {
DesignThemeProvider,
SkipLink,
ThemeColorSync,
} from "@/support/theme";
} from "@hraness/design-kit/react";
import { SkipLink } from "@/support/theme";
import { JsonLdScript } from "@hraness/web-discovery/json-ld";
import type { Metadata, Viewport } from "next";
import type { ReactNode } from "react";
Expand Down Expand Up @@ -39,7 +39,10 @@ export const metadata: Metadata = {

export const viewport: Viewport = {
colorScheme: "light dark",
themeColor: "#ffffff",
themeColor: [
{ color: "#ffffff", media: "(prefers-color-scheme: light)" },
{ color: "#151515", media: "(prefers-color-scheme: dark)" },
],
};

export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
Expand Down
10 changes: 6 additions & 4 deletions app/mobile-design.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,19 @@ test("mobile filter overflow has a scroll affordance without a persistent scroll
);
});

test("theme control uses HugeIcons with a compact visual ring and full hit target", () => {
test("theme control uses the shared System-first menu with a full hit target", () => {
const html = renderToStaticMarkup(<ThemeToggle />);

expect(html).toContain('class="stripe-history-theme-icon"');
expect(html).toContain('data-theme-value="system"');
expect(html).toContain('data-presentation="menu"');
expect(html).toContain('aria-label="Appearance: System"');
expect(html).toContain("<svg");
expect(html).not.toMatch(/[☀☾]/u);
expect(supportCss).toMatch(
/\.stripe-history-theme-toggle\s*\{[^}]*min-block-size:\s*max\(2\.5rem, var\(--plain-link-target-min\)\);[^}]*min-inline-size:\s*max\(2\.5rem, var\(--plain-link-target-min\)\);/u,
/\.stripe-history-theme-toggle \.hraness-icon-button__control\s*\{[^}]*min-block-size:\s*max\(2\.5rem, var\(--plain-link-target-min\)\);[^}]*min-inline-size:\s*max\(2\.5rem, var\(--plain-link-target-min\)\);/u,
);
expect(supportCss).toMatch(
/\.stripe-history-theme-toggle::before\s*\{[^}]*block-size:\s*2rem;[^}]*border:\s*1px solid var\(--plain-line\);[^}]*inline-size:\s*2rem;/u,
/\.stripe-history-theme-toggle \.hraness-icon-button__control\s*\{[^}]*border:\s*1px solid var\(--plain-line\);/u,
);
});

Expand Down
4 changes: 2 additions & 2 deletions app/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ describe("canonical stripehistory.com history", () => {
expect(html).toContain('class="history-event-sources"');
expect(html).toContain('data-analytics-event="source link opened"');
expect(html).toContain('id="stripe-history-history-structured-data"');
expect(html).toContain('aria-label="Appearance: light"');
expect(html).toContain('class="stripe-history-theme-icon"');
expect(html).toContain('aria-label="Appearance: System"');
expect(html).toContain('data-theme-value="system"');
expect(html).toContain('class="hraness-brand stripe-history-footer-hraness" href="https://hraness.com"');
expect(html).toContain('href="https://github.com/hraness/stripe-history"');
expect(html).not.toContain('class="stripe-history-selector"');
Expand Down
Loading