feat: restructure game details layout, expand sys reqs by default, optimize for mobile and controller
This commit is contained in:
+150
-153
@@ -273,7 +273,7 @@ export function GamePageClient({
|
|||||||
})
|
})
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [selectedPresetId, setSelectedPresetId] = useState<string | null>(null)
|
const [selectedPresetId, setSelectedPresetId] = useState<string | null>(null)
|
||||||
const [showSystemReq, setShowSystemReq] = useState(false)
|
const [showSystemReq, setShowSystemReq] = useState(true)
|
||||||
const [reportedPresets, setReportedPresets] = useState<Set<string>>(new Set())
|
const [reportedPresets, setReportedPresets] = useState<Set<string>>(new Set())
|
||||||
const presetsRef = useRef<HTMLDivElement>(null)
|
const presetsRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
@@ -462,7 +462,7 @@ export function GamePageClient({
|
|||||||
>
|
>
|
||||||
<div className='max-w-7xl mx-auto flex gap-4 sm:gap-6'>
|
<div className='max-w-7xl mx-auto flex gap-4 sm:gap-6'>
|
||||||
{/* Cover image */}
|
{/* Cover image */}
|
||||||
<div className='relative shrink-0 aspect-2/3 w-28 sm:w-32 md:w-36 rounded-lg overflow-hidden border border-border bg-text/5 h-max'>
|
<div className='relative shrink-0 aspect-2/3 w-20 sm:w-28 md:w-36 rounded-lg overflow-hidden border border-border bg-text/5 h-max'>
|
||||||
{coverImage && !imgError ? (
|
{coverImage && !imgError ? (
|
||||||
<Image
|
<Image
|
||||||
src={coverImage}
|
src={coverImage}
|
||||||
@@ -574,6 +574,52 @@ export function GamePageClient({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Metadata pills */}
|
||||||
|
<div className='flex flex-wrap items-center gap-2 mt-2'>
|
||||||
|
{game.releaseDate && (
|
||||||
|
<span className='inline-flex items-center px-2 py-0.5 rounded-full bg-text/5 border border-border text-text/60 text-[10px]'>
|
||||||
|
{game.releaseDate}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{game.isFree && (
|
||||||
|
<span className='inline-flex items-center px-2 py-0.5 rounded-full bg-green-500/10 border border-green-500/20 text-green-400 text-[10px] font-semibold'>
|
||||||
|
Free to Play
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{game.priceCurrent != null && !game.isFree && game.priceCurrency && (
|
||||||
|
<span className='inline-flex items-center px-2 py-0.5 rounded-full bg-text/5 border border-border text-text/60 text-[10px]'>
|
||||||
|
{new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceCurrent / 100)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{game.priceCurrent != null && !game.isFree && game.priceInitial != null && game.priceInitial > game.priceCurrent && game.priceCurrency && (
|
||||||
|
<span className='inline-flex items-center px-2 py-0.5 rounded-full bg-text/5 border border-border text-text/40 text-[10px] line-through'>
|
||||||
|
{new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceInitial / 100)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{game.metacriticScore != null && (
|
||||||
|
<span className='inline-flex items-center px-2 py-0.5 rounded-full bg-yellow-500/10 border border-yellow-500/20 text-yellow-400 text-[10px] font-semibold'>
|
||||||
|
★ {game.metacriticScore}/100
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{game.onlineMultiplayerStatus && (
|
||||||
|
<span className='inline-flex items-center px-2 py-0.5 rounded-full bg-text/5 border border-border text-text/60 text-[10px]'>
|
||||||
|
{game.onlineMultiplayerStatus}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{game.platforms && (
|
||||||
|
<span className='inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-text/5 border border-border text-text/60 text-[10px]'>
|
||||||
|
{game.platforms.windows && <WindowsIcon className='h-3 w-3 text-blue-400' />}
|
||||||
|
{game.platforms.mac && <MacIcon className='h-3 w-3 text-text/60' />}
|
||||||
|
{game.platforms.linux && <LinuxIcon className='h-3 w-3 text-yellow-500' />}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{game.steamAppId !== null && (
|
||||||
|
<span className='inline-flex items-center px-2 py-0.5 rounded-full bg-text/5 border border-border text-text/40 text-[10px]'>
|
||||||
|
AppID {game.steamAppId}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* External links */}
|
{/* External links */}
|
||||||
<div className='flex flex-wrap items-center gap-3 mt-1'>
|
<div className='flex flex-wrap items-center gap-3 mt-1'>
|
||||||
{game.storeUrl && (
|
{game.storeUrl && (
|
||||||
@@ -638,11 +684,12 @@ export function GamePageClient({
|
|||||||
)}
|
)}
|
||||||
{stats && (
|
{stats && (
|
||||||
<div className='flex flex-wrap items-center gap-2 mt-2'>
|
<div className='flex flex-wrap items-center gap-2 mt-2'>
|
||||||
<BookmarkButton gameId={game.id} />
|
<BookmarkButton gameId={game.id} data-gamepad-focusable />
|
||||||
{session?.user && game.source !== "steam" && (
|
{session?.user && game.source !== "steam" && (
|
||||||
<Link
|
<Link
|
||||||
href={`/game/${gameId}/edit`}
|
href={`/game/${gameId}/edit`}
|
||||||
className='inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-sm text-text/70 hover:bg-text/5 transition-colors cursor-pointer'
|
className='inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-sm text-text/70 hover:bg-text/5 transition-colors cursor-pointer'
|
||||||
|
data-gamepad-focusable
|
||||||
>
|
>
|
||||||
<PencilIcon className='h-4 w-4' />
|
<PencilIcon className='h-4 w-4' />
|
||||||
Edit Game
|
Edit Game
|
||||||
@@ -652,6 +699,7 @@ export function GamePageClient({
|
|||||||
<Link
|
<Link
|
||||||
href={`/game/${game.id}/submit`}
|
href={`/game/${game.id}/submit`}
|
||||||
className='inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-primary text-white text-sm font-semibold hover:bg-primary/90 transition-colors cursor-pointer'
|
className='inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-primary text-white text-sm font-semibold hover:bg-primary/90 transition-colors cursor-pointer'
|
||||||
|
data-gamepad-focusable
|
||||||
>
|
>
|
||||||
<Plus className='h-4 w-4' />
|
<Plus className='h-4 w-4' />
|
||||||
Add Benchmark
|
Add Benchmark
|
||||||
@@ -683,9 +731,9 @@ export function GamePageClient({
|
|||||||
transition={{ duration: 0.4, delay: 0.1 }}
|
transition={{ duration: 0.4, delay: 0.1 }}
|
||||||
className='px-4 md:px-[10svw]'
|
className='px-4 md:px-[10svw]'
|
||||||
>
|
>
|
||||||
<div className='max-w-7xl mx-auto flex flex-col md:flex-row gap-6'>
|
<div className='max-w-7xl mx-auto flex flex-col gap-6'>
|
||||||
{/* Left: Description */}
|
{/* Description */}
|
||||||
<div className='flex-2'>
|
<div>
|
||||||
<h2 className='text-sm font-medium uppercase tracking-wider text-text/60 mb-3'>
|
<h2 className='text-sm font-medium uppercase tracking-wider text-text/60 mb-3'>
|
||||||
About
|
About
|
||||||
</h2>
|
</h2>
|
||||||
@@ -703,6 +751,7 @@ export function GamePageClient({
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowSystemReq(!showSystemReq)}
|
onClick={() => setShowSystemReq(!showSystemReq)}
|
||||||
className="flex items-center gap-2 text-sm font-medium text-text/80 hover:text-primary transition-colors cursor-pointer"
|
className="flex items-center gap-2 text-sm font-medium text-text/80 hover:text-primary transition-colors cursor-pointer"
|
||||||
|
data-gamepad-focusable
|
||||||
>
|
>
|
||||||
<ChevronDownIcon className={`h-4 w-4 transition-transform ${showSystemReq ? 'rotate-180' : ''}`} />
|
<ChevronDownIcon className={`h-4 w-4 transition-transform ${showSystemReq ? 'rotate-180' : ''}`} />
|
||||||
System Requirements
|
System Requirements
|
||||||
@@ -727,154 +776,87 @@ export function GamePageClient({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right: Metadata grid */}
|
{/* Platforms */}
|
||||||
<div className='flex-1'>
|
{game.platforms && (
|
||||||
<h2 className='text-sm font-medium uppercase tracking-wider text-text/60 mb-3'>
|
<div>
|
||||||
Details
|
<h3 className='text-xs font-medium uppercase tracking-wider text-text/50 mb-2'>
|
||||||
</h2>
|
Platforms
|
||||||
<div className='grid grid-cols-2 gap-3 text-sm'>
|
</h3>
|
||||||
<MetaItem
|
<div className='flex items-center gap-1.5'>
|
||||||
label='Source'
|
<span title="Windows">
|
||||||
value={game.source}
|
<WindowsIcon
|
||||||
/>
|
className={`h-3.5 w-3.5 ${game.platforms.windows ? "text-blue-400" : "text-text/20"}`}
|
||||||
{game.steamAppId !== null && (
|
/>
|
||||||
<MetaItem
|
</span>
|
||||||
label='Steam AppID'
|
<span title="macOS">
|
||||||
value={String(game.steamAppId)}
|
<MacIcon
|
||||||
/>
|
className={`h-3.5 w-3.5 ${game.platforms.mac ? "text-text/60" : "text-text/20"}`}
|
||||||
)}
|
/>
|
||||||
<MetaItem
|
</span>
|
||||||
label='Added'
|
<span title="Linux">
|
||||||
value={formatDate(game.createdAt)}
|
<LinuxIcon
|
||||||
/>
|
className={`h-3.5 w-3.5 ${game.platforms.linux ? "text-yellow-500" : "text-text/20"}`}
|
||||||
<MetaItem
|
/>
|
||||||
label='Last Sync'
|
</span>
|
||||||
value={formatDate(game.lastSync)}
|
</div>
|
||||||
/>
|
|
||||||
{game.onlineMultiplayerStatus && (
|
|
||||||
<MetaItem
|
|
||||||
label='Online Multiplayer'
|
|
||||||
value={game.onlineMultiplayerStatus}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{game.isFree && <MetaItem label="Price" value="Free to Play" />}
|
|
||||||
{game.priceCurrent != null && !game.isFree && game.priceCurrency && (
|
|
||||||
<MetaItem
|
|
||||||
label="Price"
|
|
||||||
value={new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceCurrent / 100)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{game.priceCurrent != null && !game.isFree && game.priceInitial != null && game.priceInitial > game.priceCurrent && game.priceCurrency && (
|
|
||||||
<MetaItem
|
|
||||||
label="Original Price"
|
|
||||||
value={new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceInitial / 100)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{game.metacriticScore != null && (
|
|
||||||
<MetaItem
|
|
||||||
label="Metacritic"
|
|
||||||
value={`${game.metacriticScore}/100`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{game.recommendationsTotal != null && (
|
|
||||||
<MetaItem
|
|
||||||
label="Reviews"
|
|
||||||
value={game.recommendationsTotal.toLocaleString()}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{game.releaseDate && <MetaItem label="Release Date" value={game.releaseDate} />}
|
|
||||||
{game.steamReviewScore != null && (
|
|
||||||
<div>
|
|
||||||
<span className="text-xs text-zinc-500">Steam Reviews</span>
|
|
||||||
<p className="text-sm">
|
|
||||||
{game.steamReviewSentiment} ({game.steamReviewScore}%)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
{/* Platforms */}
|
{platformSupport.length > 0 && (
|
||||||
{game.platforms && (
|
<div>
|
||||||
<div className='mt-4'>
|
<h3 className='text-xs font-medium uppercase tracking-wider text-text/50 mb-2'>
|
||||||
<h3 className='text-xs font-medium uppercase tracking-wider text-text/50 mb-2'>
|
Platform Support
|
||||||
Platforms
|
</h3>
|
||||||
</h3>
|
<div className='flex flex-col gap-2'>
|
||||||
<div className='flex items-center gap-1.5'>
|
{platformSupport.map((ps) => (
|
||||||
<span title="Windows">
|
<div
|
||||||
<WindowsIcon
|
key={ps.id}
|
||||||
className={`h-3.5 w-3.5 ${game.platforms.windows ? "text-blue-400" : "text-text/20"}`}
|
className='flex items-center justify-between p-2 rounded-md border border-border bg-text/3'
|
||||||
/>
|
>
|
||||||
</span>
|
<span className='text-xs font-medium capitalize'>
|
||||||
<span title="macOS">
|
{ps.hardwareSlug.replace(
|
||||||
<MacIcon
|
/-/g,
|
||||||
className={`h-3.5 w-3.5 ${game.platforms.mac ? "text-text/60" : "text-text/20"}`}
|
" ",
|
||||||
/>
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span title="Linux">
|
<div className='flex items-center gap-2'>
|
||||||
<LinuxIcon
|
<span
|
||||||
className={`h-3.5 w-3.5 ${game.platforms.linux ? "text-yellow-500" : "text-text/20"}`}
|
className={`text-[10px] px-1.5 py-0.5 rounded-full ${
|
||||||
/>
|
ps.isSupported
|
||||||
</span>
|
? "bg-green-500/20 text-green-400"
|
||||||
</div>
|
: "bg-red-500/20 text-red-400"
|
||||||
</div>
|
}`}
|
||||||
)}
|
>
|
||||||
{platformSupport.length > 0 && (
|
{ps.isSupported
|
||||||
<div className='mt-4'>
|
? "Supported"
|
||||||
<h3 className='text-xs font-medium uppercase tracking-wider text-text/50 mb-2'>
|
: "Unsupported"}
|
||||||
Platform Support
|
</span>
|
||||||
</h3>
|
<span className='text-[10px] text-text/50 capitalize'>
|
||||||
<div className='flex flex-col gap-2'>
|
{ps.protonStatus}
|
||||||
{platformSupport.map((ps) => (
|
|
||||||
<div
|
|
||||||
key={ps.id}
|
|
||||||
className='flex items-center justify-between p-2 rounded-md border border-border bg-text/3'
|
|
||||||
>
|
|
||||||
<span className='text-xs font-medium capitalize'>
|
|
||||||
{ps.hardwareSlug.replace(
|
|
||||||
/-/g,
|
|
||||||
" ",
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<span
|
|
||||||
className={`text-[10px] px-1.5 py-0.5 rounded-full ${
|
|
||||||
ps.isSupported
|
|
||||||
? "bg-green-500/20 text-green-400"
|
|
||||||
: "bg-red-500/20 text-red-400"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{ps.isSupported
|
|
||||||
? "Supported"
|
|
||||||
: "Unsupported"}
|
|
||||||
</span>
|
|
||||||
<span className='text-[10px] text-text/50 capitalize'>
|
|
||||||
{ps.protonStatus}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{/* Per-device playability */}
|
{/* Per-device playability */}
|
||||||
{ps.playabilityStatus && (
|
{ps.playabilityStatus && (
|
||||||
<PlayabilityBadge
|
<PlayabilityBadge
|
||||||
status={ps.playabilityStatus}
|
status={ps.playabilityStatus}
|
||||||
compact
|
compact
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Per-device anti-cheat */}
|
{/* Per-device anti-cheat */}
|
||||||
{ps.antiCheatRelevant && (
|
{ps.antiCheatRelevant && (
|
||||||
<AntiCheatBadge
|
<AntiCheatBadge
|
||||||
antiCheatRelevant={true}
|
antiCheatRelevant={true}
|
||||||
antiCheatStatus={ps.antiCheatStatus}
|
antiCheatStatus={ps.antiCheatStatus}
|
||||||
antiCheatName={ps.antiCheatName}
|
antiCheatName={ps.antiCheatName}
|
||||||
compact
|
compact
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
@@ -904,6 +886,7 @@ export function GamePageClient({
|
|||||||
? "bg-primary/20 border-primary text-primary"
|
? "bg-primary/20 border-primary text-primary"
|
||||||
: "bg-transparent border-border text-text/60 hover:text-text/80"
|
: "bg-transparent border-border text-text/60 hover:text-text/80"
|
||||||
}`}
|
}`}
|
||||||
|
data-gamepad-focusable
|
||||||
>
|
>
|
||||||
{device.hardwareName}
|
{device.hardwareName}
|
||||||
<span className='ml-1 text-text/40'>
|
<span className='ml-1 text-text/40'>
|
||||||
@@ -979,7 +962,7 @@ export function GamePageClient({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="flex gap-4 overflow-x-auto scrollbar-hide pb-4 px-1"
|
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"
|
||||||
>
|
>
|
||||||
{pinnedPresets.map((preset) => {
|
{pinnedPresets.map((preset) => {
|
||||||
const raw = isRawPerformerPreset(preset)
|
const raw = isRawPerformerPreset(preset)
|
||||||
@@ -988,11 +971,12 @@ export function GamePageClient({
|
|||||||
<motion.div
|
<motion.div
|
||||||
key={preset.id}
|
key={preset.id}
|
||||||
onClick={() => handlePresetOpen(preset.id)}
|
onClick={() => handlePresetOpen(preset.id)}
|
||||||
className={`shrink-0 w-72 flex flex-col gap-3 p-4 rounded-xl border transition-colors cursor-pointer hover:border-primary/30 ${
|
className={`flex flex-col gap-3 p-4 rounded-xl border transition-colors cursor-pointer hover:border-primary/30 ${
|
||||||
raw
|
raw
|
||||||
? "border-green-500/30 bg-green-500/5"
|
? "border-green-500/30 bg-green-500/5"
|
||||||
: "border-yellow-500/30 bg-yellow-500/5"
|
: "border-yellow-500/30 bg-yellow-500/5"
|
||||||
}`}
|
}`}
|
||||||
|
data-gamepad-focusable
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className='flex items-start justify-between gap-2'>
|
<div className='flex items-start justify-between gap-2'>
|
||||||
@@ -1143,7 +1127,7 @@ export function GamePageClient({
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
ref={presetsRef}
|
ref={presetsRef}
|
||||||
className="flex gap-4 overflow-x-auto scrollbar-hide pb-4 px-1"
|
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"
|
||||||
>
|
>
|
||||||
{regularPresets.map((preset) => {
|
{regularPresets.map((preset) => {
|
||||||
const raw = isRawPerformerPreset(preset)
|
const raw = isRawPerformerPreset(preset)
|
||||||
@@ -1152,11 +1136,12 @@ export function GamePageClient({
|
|||||||
<motion.div
|
<motion.div
|
||||||
key={preset.id}
|
key={preset.id}
|
||||||
onClick={() => handlePresetOpen(preset.id)}
|
onClick={() => handlePresetOpen(preset.id)}
|
||||||
className={`shrink-0 w-72 flex flex-col gap-3 p-4 rounded-xl border transition-colors cursor-pointer hover:border-primary/30 ${
|
className={`flex flex-col gap-3 p-4 rounded-xl border transition-colors cursor-pointer hover:border-primary/30 ${
|
||||||
raw
|
raw
|
||||||
? "border-green-500/30 bg-green-500/5"
|
? "border-green-500/30 bg-green-500/5"
|
||||||
: "border-border bg-text/3"
|
: "border-border bg-text/3"
|
||||||
}`}
|
}`}
|
||||||
|
data-gamepad-focusable
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className='flex items-start justify-between gap-2'>
|
<div className='flex items-start justify-between gap-2'>
|
||||||
@@ -1438,10 +1423,21 @@ export function GamePageClient({
|
|||||||
transition={{ duration: 0.4, delay: 0.3 }}
|
transition={{ duration: 0.4, delay: 0.3 }}
|
||||||
className='px-4 md:px-[10svw]'
|
className='px-4 md:px-[10svw]'
|
||||||
>
|
>
|
||||||
<div className='max-w-7xl mx-auto'>
|
<div className='max-w-7xl mx-auto' data-gamepad-focusable>
|
||||||
<CommentSection gameId={gameId} initialCount={counts.comments} />
|
<CommentSection gameId={gameId} initialCount={counts.comments} />
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Mobile FAB for Add Benchmark */}
|
||||||
|
{session && (
|
||||||
|
<Link
|
||||||
|
href={`/game/${game.id}/submit`}
|
||||||
|
className='fixed right-4 bottom-4 z-50 inline-flex items-center justify-center w-14 h-14 rounded-full bg-primary text-white shadow-lg hover:bg-primary/90 transition-colors cursor-pointer sm:hidden'
|
||||||
|
data-gamepad-focusable
|
||||||
|
>
|
||||||
|
<Plus className='h-6 w-6' />
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{selectedPresetId && (() => {
|
{selectedPresetId && (() => {
|
||||||
@@ -1533,6 +1529,7 @@ function FilterSelect({
|
|||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
className='text-xs bg-background border border-border rounded-md px-2 py-1 text-text/80 focus:outline-none focus:border-primary min-w-25'
|
className='text-xs bg-background border border-border rounded-md px-2 py-1 text-text/80 focus:outline-none focus:border-primary min-w-25'
|
||||||
|
data-gamepad-focusable
|
||||||
>
|
>
|
||||||
{options.map((opt) => (
|
{options.map((opt) => (
|
||||||
<option
|
<option
|
||||||
|
|||||||
Reference in New Issue
Block a user