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
1 change: 0 additions & 1 deletion src/app/[lang]/search-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export function SearchButton({ label }: { label: string }) {
return (
<button
type="button"
aria-label={label}
data-command-palette-trigger
className="group relative inline-flex min-h-12 w-full max-w-xl items-center gap-3 overflow-hidden rounded-2xl border border-border/70 bg-card/80 px-4 py-3 text-sm text-muted-foreground shadow-xl shadow-black/10 backdrop-blur-md transition-[transform,border-color,background-color,color,box-shadow] duration-300 hover:-translate-y-0.5 hover:border-primary/45 hover:bg-card hover:text-foreground hover:shadow-2xl hover:shadow-cyan-500/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/45 dark:shadow-black/35"
>
Expand Down
9 changes: 8 additions & 1 deletion src/app/[lang]/trust-center/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,23 @@ function TrustPill({
icon,
title,
description,
titleAs = "h3",
}: {
icon: React.ReactNode
title: string
description: string
titleAs?: "h2" | "h3"
}) {
const Title = titleAs

return (
<article className="rounded-lg border border-border/70 bg-background/55 p-4">
<div className="flex gap-3">
<span className="mt-0.5 text-primary" aria-hidden="true">
{icon}
</span>
<div>
<h3 className="text-sm font-semibold">{title}</h3>
<Title className="text-sm font-semibold">{title}</Title>
<p className="mt-1.5 text-sm leading-relaxed text-muted-foreground">{description}</p>
</div>
</div>
Expand Down Expand Up @@ -201,16 +205,19 @@ export default async function TrustCenterPage({
icon={<ShieldCheck className="h-5 w-5" />}
title={p.trust_center_summary_local_title}
description={p.trust_center_summary_local_desc}
titleAs="h2"
/>
<TrustPill
icon={<Network className="h-5 w-5" />}
title={p.trust_center_summary_network_title}
description={p.trust_center_summary_network_desc}
titleAs="h2"
/>
<TrustPill
icon={<LockKeyhole className="h-5 w-5" />}
title={p.trust_center_summary_security_title}
description={p.trust_center_summary_security_desc}
titleAs="h2"
/>
</section>

Expand Down
4 changes: 2 additions & 2 deletions src/components/layout/footer-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ export function FooterContent({
</div>

<nav className="md:col-span-4" aria-label={navigationLabel}>
<h4 className="mb-3 text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground">
<p className="mb-3 text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground">
{navigationLabel}
</h4>
</p>
<ul className="space-y-1">
{pageLinks.map((page) => (
<li key={page.key}>
Expand Down
1 change: 0 additions & 1 deletion src/features/tool-discovery/all-tools-discovery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,6 @@ export function AllToolsDiscovery({
<div className="flex items-start justify-between gap-3">
<Link
href={`/${locale}/${tool.slug}`}
aria-label={tool.title}
className="min-w-0 flex-1 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/45"
>
<ToolCardBadges capabilityLabels={capabilityLabels} tool={tool} />
Expand Down
2 changes: 1 addition & 1 deletion src/features/tool-shell/tool-action-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export function ToolActionBar({
? "pending"
: lastActionStatus[action.id] || "idle"
const variantClass = isDestructive
? "border border-destructive/35 bg-background text-destructive shadow-xs hover:bg-destructive/10 dark:bg-input/30"
? "border border-destructive/35 bg-background text-destructive shadow-xs hover:bg-destructive/10 dark:border-red-400/45 dark:bg-red-950/25 dark:text-red-200 dark:hover:bg-red-950/45"
: ACTION_VARIANT_CLASS[action.variant ?? "outline"]

if (action.href) {
Expand Down
5 changes: 4 additions & 1 deletion tests/component/all-tools-discovery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,10 @@ describe("AllToolsDiscovery", () => {
it("keeps tool cards compact with only key badges", () => {
renderDiscovery()

const card = screen.getByRole("link", { name: "JSON Formatter" })
const card = screen.getAllByRole("link", { name: /JSON Formatter/ })
.find((link) => link.getAttribute("href") === "/en/json-formatter")

if (!card) throw new Error("JSON Formatter card link was not found")
expect(card.closest("article")).toContainElement(screen.getByRole("button", { name: "Add to favorites: JSON Formatter" }))
const badges = within(card).getAllByText(/Data formats|Browser-local|File input|Offline capable|Pipeline ready/)
expect(badges.length).toBeLessThanOrEqual(3)
Expand Down
39 changes: 39 additions & 0 deletions tests/guards/lighthouse-a11y-followups.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import fs from "node:fs"
import path from "node:path"
import { describe, expect, it } from "vitest"

const ROOT = process.cwd()

function read(relativePath: string) {
return fs.readFileSync(path.join(ROOT, relativePath), "utf8")
}

describe("Lighthouse accessibility follow-ups", () => {
it("keeps visible command and tool-card labels aligned with accessible names", () => {
const homeSearchButton = read("src/app/[lang]/search-button.tsx")
const allToolsDiscovery = read("src/features/tool-discovery/all-tools-discovery.tsx")

expect(homeSearchButton).toContain("data-command-palette-trigger")
expect(homeSearchButton).not.toContain("aria-label={label}")
expect(allToolsDiscovery).toContain("<ToolCardBadges capabilityLabels={capabilityLabels} tool={tool} />")
expect(allToolsDiscovery).not.toContain("aria-label={tool.title}")
})

it("keeps non-section labels out of heading order and preserves Trust Center heading sequence", () => {
const footer = read("src/components/layout/footer-content.tsx")
const trustCenter = read("src/app/[lang]/trust-center/page.tsx")

expect(footer).toContain("<nav className=\"md:col-span-4\" aria-label={navigationLabel}>")
expect(footer).not.toContain("<h4 className=\"mb-3")
expect(trustCenter).toContain('titleAs="h2"')
expect(trustCenter).toContain('titleAs?: "h2" | "h3"')
})

it("keeps destructive tool actions contrast-safe in dark mode", () => {
const actionBar = read("src/features/tool-shell/tool-action-bar.tsx")

expect(actionBar).toContain("dark:text-red-200")
expect(actionBar).toContain("dark:bg-red-950/25")
expect(actionBar).not.toContain("bg-background text-destructive shadow-xs hover:bg-destructive/10 dark:bg-input/30")
})
})