@@ -241,7 +241,7 @@ function CharacterTable({ rows, known, sorting }: { rows: CharacterRow[]; known:
241241 < Table
242242 head = {
243243 < >
244- < SortHeader column = "name" label = "Character" sorting = { sorting } className = { headClass } />
244+ < SortHeader column = "name" label = "Character" sorting = { sorting } className = { `sm:w-[45%] ${ headClass } ` } />
245245 < th scope = "col" className = { `hidden sm:table-cell ${ headClass } ` } > Player</ th >
246246 < SortHeader column = "last_seen" label = "Player last seen" sorting = { sorting } className = { lastSeenHeadClass } />
247247 </ >
@@ -373,79 +373,81 @@ export default function PlayersDirectory({ initialQuery, initialListing, initial
373373
374374 return (
375375 < section aria-label = "Players" className = "mt-6" >
376- { /* Search gets a row of its own, so the view tabs never squeeze it. */ }
377- < label className = "sr-only" htmlFor = "player-search" >
378- Search players
379- </ label >
380- < div className = "relative" >
381- < svg
382- aria-hidden
383- viewBox = "0 0 20 20"
384- className = "pointer-events-none absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-[var(--tfmc-stone)]"
385- fill = "none"
386- stroke = "currentColor"
387- strokeWidth = "2"
388- >
389- < circle cx = "8.5" cy = "8.5" r = "5.5" />
390- < path d = "M13 13l4 4" strokeLinecap = "round" />
391- </ svg >
392- < input
393- id = "player-search"
394- type = "search"
395- value = { query }
396- onChange = { ( e ) => {
397- setQuery ( e . target . value ) ;
398- setPage ( 1 ) ;
399- } }
400- placeholder = "Search by Minecraft, Discord (handle or nickname) or character name, or UUID"
401- autoComplete = "off"
402- spellCheck = { false }
403- className = { inputClass }
404- />
405- { query ? (
406- < button
407- type = "button"
408- aria-label = "Clear search"
409- onClick = { ( ) => {
410- setQuery ( "" ) ;
411- setSearch ( "" ) ;
412- setPage ( 1 ) ;
413- } }
414- className = "absolute right-0 top-0 flex h-full w-11 items-center justify-center text-xl text-[var(--tfmc-stone)] hover:text-[var(--tfmc-cream)]"
376+ { /* Search and the view tabs share a row on wide screens; the tabs move under it before they squeeze it. */ }
377+ < div className = "flex flex-col gap-3 lg:flex-row lg:items-center" >
378+ < label className = "sr-only" htmlFor = "player-search" >
379+ Search players
380+ </ label >
381+ < div className = "relative min-w-0 flex-1" >
382+ < svg
383+ aria-hidden
384+ viewBox = "0 0 20 20"
385+ className = "pointer-events-none absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-[var(--tfmc-stone)]"
386+ fill = "none"
387+ stroke = "currentColor"
388+ strokeWidth = "2"
415389 >
416- ×
417- </ button >
418- ) : null }
419- </ div >
420-
421- < div
422- role = "tablist"
423- aria-label = "Player views"
424- className = "mt-3 grid grid-cols-3 rounded-sm border border-[color-mix(in_srgb,var(--tfmc-cream)_20%,transparent)] p-0.5 sm:inline-grid"
425- >
426- { VIEWS . map ( ( option , index ) => (
427- < button
428- key = { option . key }
429- ref = { ( el ) => {
430- tabs . current [ index ] = el ;
390+ < circle cx = "8.5" cy = "8.5" r = "5.5" />
391+ < path d = "M13 13l4 4" strokeLinecap = "round" />
392+ </ svg >
393+ < input
394+ id = "player-search"
395+ type = "search"
396+ value = { query }
397+ onChange = { ( e ) => {
398+ setQuery ( e . target . value ) ;
399+ setPage ( 1 ) ;
431400 } }
432- id = { `players-tab-${ option . key } ` }
433- type = "button"
434- role = "tab"
435- aria-selected = { view === option . key }
436- aria-controls = { PANEL_ID }
437- tabIndex = { view === option . key ? 0 : - 1 }
438- onClick = { ( ) => choose ( option . key ) }
439- onKeyDown = { ( event ) => onTabKey ( event , index ) }
440- className = { `min-h-11 rounded-sm px-2 text-sm transition-colors sm:min-h-9 sm:px-4 ${
441- view === option . key
442- ? "bg-[var(--tfmc-accent)] font-semibold text-[var(--tfmc-forest-deep)]"
443- : "text-[var(--tfmc-stone)] hover:text-[var(--tfmc-cream)]"
444- } `}
445- >
446- { option . label }
447- </ button >
448- ) ) }
401+ placeholder = "Search by Minecraft, Discord (handle or nickname) or character name, or UUID"
402+ autoComplete = "off"
403+ spellCheck = { false }
404+ className = { inputClass }
405+ />
406+ { query ? (
407+ < button
408+ type = "button"
409+ aria-label = "Clear search"
410+ onClick = { ( ) => {
411+ setQuery ( "" ) ;
412+ setSearch ( "" ) ;
413+ setPage ( 1 ) ;
414+ } }
415+ className = "absolute right-0 top-0 flex h-full w-11 items-center justify-center text-xl text-[var(--tfmc-stone)] hover:text-[var(--tfmc-cream)]"
416+ >
417+ ×
418+ </ button >
419+ ) : null }
420+ </ div >
421+
422+ < div
423+ role = "tablist"
424+ aria-label = "Player views"
425+ className = "grid shrink-0 grid-cols-3 rounded-sm border border-[color-mix(in_srgb,var(--tfmc-cream)_20%,transparent)] p-0.5 sm:self-start lg:self-auto"
426+ >
427+ { VIEWS . map ( ( option , index ) => (
428+ < button
429+ key = { option . key }
430+ ref = { ( el ) => {
431+ tabs . current [ index ] = el ;
432+ } }
433+ id = { `players-tab-${ option . key } ` }
434+ type = "button"
435+ role = "tab"
436+ aria-selected = { view === option . key }
437+ aria-controls = { PANEL_ID }
438+ tabIndex = { view === option . key ? 0 : - 1 }
439+ onClick = { ( ) => choose ( option . key ) }
440+ onKeyDown = { ( event ) => onTabKey ( event , index ) }
441+ className = { `min-h-11 rounded-sm px-2 text-sm transition-colors sm:min-h-9 sm:px-4 ${
442+ view === option . key
443+ ? "bg-[var(--tfmc-accent)] font-semibold text-[var(--tfmc-forest-deep)]"
444+ : "text-[var(--tfmc-stone)] hover:text-[var(--tfmc-cream)]"
445+ } `}
446+ >
447+ { option . label }
448+ </ button >
449+ ) ) }
450+ </ div >
449451 </ div >
450452
451453 < div id = { PANEL_ID } role = "tabpanel" aria-labelledby = { `players-tab-${ view } ` } >
0 commit comments