|
| 1 | +import { Link } from "@tanstack/react-router"; |
1 | 2 | import type { ReactNode } from "react"; |
2 | 3 | import { cn } from "@/lib/utils"; |
3 | 4 |
|
@@ -107,13 +108,30 @@ export function Ol({ children }: { children: ReactNode }) { |
107 | 108 | ); |
108 | 109 | } |
109 | 110 |
|
| 111 | +const LINK_CLASS = "underline underline-offset-4 hover:text-primary"; |
| 112 | + |
| 113 | +/** |
| 114 | + * Every link on the site. |
| 115 | + * |
| 116 | + * An app-relative href routes through TanStack's `Link`, so moving between |
| 117 | + * pages does not reload the document and lose the router. Everything else |
| 118 | + * (http, mailto, and any other scheme) is a plain anchor, and anything |
| 119 | + * off-site opens in its own tab. |
| 120 | + */ |
110 | 121 | export function A({ href, children }: { href: string; children: ReactNode }) { |
| 122 | + if (href.startsWith("/")) { |
| 123 | + return ( |
| 124 | + <Link to={href} className={LINK_CLASS}> |
| 125 | + {children} |
| 126 | + </Link> |
| 127 | + ); |
| 128 | + } |
111 | 129 | const external = href.startsWith("http"); |
112 | 130 | return ( |
113 | 131 | <a |
114 | 132 | href={href} |
115 | 133 | {...(external ? { target: "_blank", rel: "noreferrer" } : {})} |
116 | | - className="underline underline-offset-4 hover:text-primary" |
| 134 | + className={LINK_CLASS} |
117 | 135 | > |
118 | 136 | {children} |
119 | 137 | </a> |
@@ -167,10 +185,12 @@ export function Shell({ lines }: { lines: string[] }) { |
167 | 185 | // Lines repeat in a transcript (blank ones, at least), so the index |
168 | 186 | // is the only key that is honest. |
169 | 187 | // biome-ignore lint/suspicious/noArrayIndexKey: transcript lines are not unique |
170 | | - <span key={i} className="block"> |
| 188 | + <span key={i} className="block" {...(line === "" ? { "aria-hidden": true } : {})}> |
171 | 189 | {line === "" ? ( |
172 | 190 | // An empty block has no height, so a blank line in the transcript |
173 | | - // would vanish. A space under `whitespace-pre` keeps the line. |
| 191 | + // would vanish. A space under `whitespace-pre` keeps the line, and |
| 192 | + // the row is hidden from assistive tech so it is not announced as |
| 193 | + // a spoken space. |
174 | 194 | " " |
175 | 195 | ) : line.startsWith("$") ? ( |
176 | 196 | <> |
|
0 commit comments