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
4 changes: 2 additions & 2 deletions app/src/components/AboutButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export default function AboutButton({ ui, links, people, variant = 'circle' }: P
aria-label={ui.close}
title={ui.close}
onClick={close}
class="absolute top-5 right-5 flex h-9 w-9 items-center justify-center rounded-full border border-border-strong text-muted hover:border-border-hover hover:text-fg"
class="absolute top-4 right-4 flex h-11 w-11 items-center justify-center rounded-full border border-border-strong text-muted hover:border-border-hover hover:text-fg"
>
<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none">
<path d="M6 6l12 12M18 6 6 18" stroke="currentColor" stroke-width="2" />
Expand All @@ -169,7 +169,7 @@ export default function AboutButton({ ui, links, people, variant = 'circle' }: P
href={l.href}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 rounded-full border border-border-strong px-3 py-1 text-sm text-fg-soft hover:border-border-hover hover:text-fg"
class="inline-flex min-h-11 items-center gap-1.5 rounded-full border border-border-strong px-3 py-1 text-sm sm:min-h-0 text-fg-soft hover:border-border-hover hover:text-fg"
>
{l.label}
<ExternalIcon />
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface Props {
}

const button =
'rounded border border-border-strong px-3 py-1.5 text-sm hover:border-border-hover disabled:opacity-50';
'min-h-11 rounded border border-border-strong px-3 py-1.5 text-sm hover:border-border-hover disabled:opacity-50 sm:min-h-0';

/** What the signed-out view offers (A87): email only behind EMAIL_SIGNIN, providers by build variable. */
const options = signInOptions({ emailSignin: EMAIL_SIGNIN, providers: AUTH_PROVIDERS });
Expand Down Expand Up @@ -148,7 +148,7 @@ export default function Account({ lang, ui }: Props) {
type="email"
required
autocomplete="email"
class="min-w-0 flex-1 rounded border border-border-strong bg-surface px-2 py-1.5 text-sm"
class="min-w-0 flex-1 rounded border border-border-strong bg-surface px-2 py-1.5 text-base sm:text-sm"
value={email}
onInput={(e) => setEmail(e.currentTarget.value)}
/>
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/AccountMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default function AccountMenu({ href, ui }: Props) {
if (s.status === 'loading' || s.status === 'off') return null;
if (s.status === 'signed-out') {
return (
<a class="py-1.5 hover:text-fg md:py-0" href={href}>
<a class="flex min-h-11 items-center hover:text-fg md:min-h-0" href={href}>
{ui.signIn}
</a>
);
Expand Down Expand Up @@ -79,7 +79,7 @@ export default function AccountMenu({ href, ui }: Props) {
) : null;

return (
<span class="inline-flex items-center gap-2 py-1.5 md:py-0">
<span class="inline-flex min-h-11 items-center gap-2 md:min-h-0">
<a class="hover:text-fg" href={href} title={s.email}>
{ui.account}
</a>
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/KnowledgeStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function KnowledgeStatus({ termId, ui }: Props) {
<div class="flex flex-wrap gap-2">
{STATUSES.map((s) => (
<button
class={`rounded border px-2 py-1 text-xs ${status === s ? ACTIVE[s] : 'border-border-strong text-muted hover:border-border-hover'}`}
class={`min-h-11 rounded border px-3 py-1 text-sm sm:min-h-0 sm:px-2 sm:text-xs ${status === s ? ACTIVE[s] : 'border-border-strong text-muted hover:border-border-hover'}`}
aria-pressed={status === s}
onClick={() => choose(s)}
>
Expand Down
8 changes: 4 additions & 4 deletions app/src/components/Quiz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default function Quiz({
if (!session) {
return (
<button
class="rounded border border-border-hover px-3 py-1.5 text-sm hover:bg-surface"
class="min-h-11 rounded border border-border-hover px-3 py-1.5 text-sm hover:bg-surface sm:min-h-0"
onClick={start}
>
{ui.start}
Expand All @@ -106,7 +106,7 @@ export default function Quiz({
{ui.score.replace('{n}', String(score)).replace('{m}', String(session.length))}
</p>
<button
class="rounded border border-border-hover px-3 py-1.5 text-sm hover:bg-surface"
class="min-h-11 rounded border border-border-hover px-3 py-1.5 text-sm hover:bg-surface sm:min-h-0"
onClick={start}
>
{ui.again}
Expand Down Expand Up @@ -148,7 +148,7 @@ export default function Quiz({
: 'border-border opacity-60';
return (
<button
class={`rounded border px-3 py-2 text-left text-sm ${state}`}
class={`min-h-11 rounded border px-3 py-2 text-left text-sm ${state}`}
onClick={() => answer(o.id)}
>
{o.label}
Expand Down Expand Up @@ -183,7 +183,7 @@ export default function Quiz({
</p>
)}
<button
class="rounded border border-border-hover px-3 py-1 hover:bg-surface"
class="min-h-11 rounded border border-border-hover px-3 py-1 hover:bg-surface sm:min-h-0"
onClick={() => {
setIndex(index + 1);
setChosen(null);
Expand Down
8 changes: 6 additions & 2 deletions app/src/components/RecentTerms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,19 @@ export default function RecentTerms({ names, termBase, ui }: Props) {
<div class="mt-6">
<div class="mb-2 flex items-baseline gap-3">
<h3 class="text-xs tracking-widest text-subtle uppercase">{ui.recentlyViewed}</h3>
<button type="button" class="text-xs text-subtle hover:text-fg-soft" onClick={clear}>
<button
type="button"
class="min-h-11 text-xs text-subtle hover:text-fg-soft sm:min-h-0"
onClick={clear}
>
{ui.clearRecent}
</button>
</div>
<ul class="flex flex-wrap gap-2">
{ids.map((id) => (
<li key={id}>
<a
class="inline-block rounded border border-border px-2 py-1 text-sm text-fg-soft hover:border-border-hover hover:text-fg"
class="inline-flex min-h-11 items-center rounded border border-border px-2 py-1 text-sm sm:min-h-0 text-fg-soft hover:border-border-hover hover:text-fg"
href={`${termBase}${id}/`}
>
{names[id]}
Expand Down
7 changes: 4 additions & 3 deletions app/src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export default function Search({
onInput={(e) => setQuery((e.target as HTMLInputElement).value)}
placeholder={placeholder}
aria-label={placeholder}
class="w-full rounded border border-border-strong bg-surface px-3 py-2 text-fg placeholder:text-subtle focus:border-border-hover focus:outline-none"
class="w-full rounded border border-border-strong bg-surface px-3 py-2.5 text-base sm:py-2 text-fg placeholder:text-subtle focus:border-border-hover focus:outline-none"
/>
{q && !engine && (
<p
Expand All @@ -181,7 +181,7 @@ export default function Search({
)}
{q && engine && (
<ul
class="absolute z-10 mt-1 w-full overflow-hidden rounded border border-border bg-surface shadow-lg"
class="absolute z-10 mt-1 max-h-[70dvh] w-full overflow-y-auto overscroll-contain rounded border border-border bg-surface shadow-lg"
aria-live="polite"
>
{action && (
Expand Down Expand Up @@ -227,7 +227,8 @@ export default function Search({
)}
</ul>
)}
{hint && <p class="mt-2 text-xs text-subtle">{hint}</p>}
{/* The "/" shortcut means nothing without a keyboard. */}
{hint && <p class="mt-2 text-xs text-subtle pointer-coarse:hidden">{hint}</p>}
</div>
);
}
4 changes: 2 additions & 2 deletions app/src/components/StudyHub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default function StudyHub({
{next.map((n) => (
<li>
<a
class="rounded border border-border-strong px-2 py-1 text-sm hover:border-border-hover"
class="inline-flex min-h-11 items-center rounded border border-border-strong px-2 py-1 text-sm hover:border-border-hover sm:min-h-0"
href={`${termBase}${n.id}/`}
>
{n.term[lang]}
Expand All @@ -94,7 +94,7 @@ export default function StudyHub({
<label class="mb-4 flex flex-wrap items-center gap-2 text-sm text-muted">
{ui.quizMeOn}
<select
class="rounded border border-border-strong bg-surface px-2 py-1 text-sm text-fg"
class="min-h-11 rounded border border-border-strong bg-surface px-2 py-1 text-base text-fg sm:min-h-0 sm:text-sm"
value={scope}
onChange={(e) => {
setScope((e.target as HTMLSelectElement).value as Scope);
Expand Down
25 changes: 14 additions & 11 deletions app/src/components/Timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const SSR_WIDTH = 1280;
const SSR_BUDGET = 560;
// Vertical (small screens) geometry, px.
const V_ZOOM = [4, 6, 10, 16, 22];
const V_ITEM = 20;
const V_ITEM = 24; // one phone row (h-6): a 24px tap target, the WCAG 2.5.8 minimum
const AXIS_COL = 44;
const DEFAULT_ZOOM = 0;

Expand Down Expand Up @@ -329,7 +329,7 @@ export default function Timeline(props: Props) {
}, [more?.pinned]);

const chip =
'rounded-full border px-3 py-1 text-xs transition-colors hover:border-border-hover aria-pressed:text-fg';
'min-h-11 min-w-11 rounded-full border px-3 py-1 text-xs transition-colors sm:min-h-0 sm:min-w-0 hover:border-border-hover aria-pressed:text-fg';
const selItem = sel ? byId.get(sel.id) : undefined;
const single = shown.length === 1;

Expand Down Expand Up @@ -368,7 +368,7 @@ export default function Timeline(props: Props) {
<span class="ml-auto flex items-center gap-1" role="group" aria-label={text.zoom}>
<button
type="button"
class="h-7 w-7 rounded border border-border-strong text-fg-soft hover:border-border-hover disabled:opacity-40"
class="h-11 w-11 rounded border border-border-strong text-fg-soft hover:border-border-hover disabled:opacity-40 sm:h-7 sm:w-7"
aria-label={text.zoomOut}
title={text.zoomOut}
disabled={zoom === 0}
Expand All @@ -378,7 +378,7 @@ export default function Timeline(props: Props) {
</button>
<button
type="button"
class="h-7 w-7 rounded border border-border-strong text-fg-soft hover:border-border-hover disabled:opacity-40"
class="h-11 w-11 rounded border border-border-strong text-fg-soft hover:border-border-hover disabled:opacity-40 sm:h-7 sm:w-7"
aria-label={text.zoomIn}
title={text.zoomIn}
disabled={zoom === H_ZOOM.length - 1}
Expand Down Expand Up @@ -594,7 +594,7 @@ export default function Timeline(props: Props) {
<span style={{ width: AXIS_COL }} class="shrink-0" />
{[...lanes.keys()].map((lane) => (
<h2
class="map-ink min-w-0 flex-1 truncate px-1 py-2 text-[11px] font-medium"
class="map-ink min-w-0 flex-1 truncate px-1 py-2 text-xs font-medium"
style={`${inkVars(ink(lane))}color:var(--ink)`}
>
{domainLabels[lane] ?? lane}
Expand Down Expand Up @@ -624,7 +624,7 @@ export default function Timeline(props: Props) {
}}
>
<span
class="absolute top-1 left-0.5 text-[9px] tracking-widest whitespace-nowrap text-subtle uppercase"
class="absolute top-1 left-0.5 text-[10px] tracking-widest whitespace-nowrap text-subtle uppercase"
style={{ writingMode: 'vertical-rl', transform: 'rotate(180deg)' }}
>
{eraLabels[b.id]}
Expand All @@ -650,13 +650,13 @@ export default function Timeline(props: Props) {
<ul class="relative min-w-0 flex-1 border-l border-border">
{list.map((it) => (
<li
class="absolute right-0 left-0 flex h-5 items-center px-1"
class="absolute right-0 left-0 flex h-6 items-center px-1"
style={{ top: v.pos.get(it.id) }}
>
<a
href={it.href}
data-tl-item
class={`flex min-w-0 items-center gap-1 ${it.hub ? 'font-semibold text-fg' : 'text-fg-soft'} ${single ? 'text-xs' : 'text-[10px]'}`}
class={`flex h-6 min-w-0 items-center gap-1 ${it.hub ? 'font-semibold text-fg' : 'text-fg-soft'} ${single ? 'text-sm' : 'text-[11px]'}`}
aria-label={`${it.name}, ${it.year}`}
{...handlers(it)}
>
Expand Down Expand Up @@ -693,7 +693,7 @@ export default function Timeline(props: Props) {
ref={popRef}
role={sel.pinned ? 'dialog' : 'tooltip'}
aria-label={selItem.name}
class="fixed inset-x-4 bottom-4 z-50 rounded-lg border border-border-strong bg-surface/95 p-4 text-sm shadow-xl shadow-black/20 dark:shadow-black/50 backdrop-blur sm:inset-x-auto sm:bottom-auto sm:w-80"
class="fixed inset-x-4 bottom-[max(1rem,env(safe-area-inset-bottom))] z-50 rounded-lg border border-border-strong bg-surface/95 p-4 text-sm shadow-xl shadow-black/20 dark:shadow-black/50 backdrop-blur sm:inset-x-auto sm:bottom-auto sm:w-80"
style={popStyle(sel.x, sel.y)}
>
<div class="mb-1 flex items-baseline gap-2">
Expand All @@ -709,13 +709,16 @@ export default function Timeline(props: Props) {
</p>
{selItem.summary && <p class="mb-3 text-fg-soft">{selItem.summary}</p>}
<div class="flex items-center justify-between">
<a class="text-accent hover:underline" href={selItem.href}>
<a
class="inline-flex min-h-11 items-center text-accent hover:underline sm:min-h-0"
href={selItem.href}
>
{text.openTerm} →
</a>
{sel.pinned && (
<button
type="button"
class="text-xs text-muted hover:text-fg"
class="min-h-11 px-2 text-sm text-muted hover:text-fg sm:min-h-0 sm:px-0 sm:text-xs"
onClick={() => setSel(null)}
>
{text.close}
Expand Down
18 changes: 11 additions & 7 deletions app/src/components/Tour.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -461,16 +461,20 @@ export default function Tour({ steps, langBase, autoStart = true, ui }: Props) {

if (view.kind === 'resume') {
return (
<div class="tour-pill fixed bottom-4 left-4 flex items-center gap-2 rounded border border-border-strong bg-surface px-3 py-2 text-sm shadow-lg print:hidden">
<div class="tour-pill fixed bottom-[max(1rem,env(safe-area-inset-bottom))] left-[max(1rem,env(safe-area-inset-left))] flex items-center gap-2 rounded border border-border-strong bg-surface px-3 py-2 text-sm shadow-lg print:hidden">
<button
type="button"
class="text-accent hover:underline"
class="min-h-11 text-accent hover:underline sm:min-h-0"
onClick={() => go(view.step)}
data-tour-resume
>
{fillCount(ui.tourContinue, view.step, total)} →
</button>
<button type="button" class="text-subtle hover:text-fg-soft" onClick={() => finish(false)}>
<button
type="button"
class="min-h-11 text-subtle hover:text-fg-soft sm:min-h-0"
onClick={() => finish(false)}
>
{ui.tourEnd}
</button>
</div>
Expand All @@ -480,7 +484,7 @@ export default function Tour({ steps, langBase, autoStart = true, ui }: Props) {

const titleId = 'tour-title';
const bodyId = 'tour-body';
const btn = 'rounded border px-3 py-1.5 text-sm';
const btn = 'min-h-11 rounded border px-3 py-1.5 text-sm sm:min-h-0';
const primary = `${btn} border-amber-400 bg-amber-400 font-medium text-on-accent hover:bg-amber-300`;
const secondary = `${btn} border-border-strong text-fg-soft hover:border-border-hover`;
const sv = shown?.view;
Expand All @@ -501,7 +505,7 @@ export default function Tour({ steps, langBase, autoStart = true, ui }: Props) {
aria-labelledby={titleId}
aria-describedby={bodyId}
tabIndex={-1}
class="tour-card max-h-[60vh] overflow-y-auto rounded border border-border-strong bg-surface p-4 text-fg shadow-2xl focus:outline-none"
class="tour-card max-h-[60dvh] overflow-y-auto rounded border border-border-strong bg-surface p-4 text-fg shadow-2xl focus:outline-none"
>
<div class="mb-1 flex items-start justify-between gap-4">
<h2 id={titleId} class="text-base font-semibold">
Expand All @@ -511,7 +515,7 @@ export default function Tour({ steps, langBase, autoStart = true, ui }: Props) {
type="button"
aria-label={ui.tourClose}
title={ui.tourClose}
class="-mt-1 -mr-1 px-1 text-lg leading-none text-subtle hover:text-fg"
class="-mt-3 -mr-3 flex h-11 w-11 shrink-0 items-center justify-center text-lg leading-none text-subtle hover:text-fg sm:-mt-1 sm:-mr-1 sm:h-auto sm:w-auto sm:px-1"
onClick={() => finish(welcome ? dontShow : false)}
>
×
Expand All @@ -530,7 +534,7 @@ export default function Tour({ steps, langBase, autoStart = true, ui }: Props) {
{ui.tourNotNow}
</button>
</div>
<label class="flex items-center gap-2 text-xs text-muted">
<label class="flex min-h-11 items-center gap-2 text-sm text-muted sm:min-h-0 sm:text-xs">
<input
type="checkbox"
checked={dontShow}
Expand Down
Loading
Loading