Use custom dropdown

This commit is contained in:
Lncvrt committed 2026-05-30 12:53:08 -07:00
1 parent bde6b252d7
commit 873b46230c
5 files changed
+159 -38

No files matched your search

+11 -11
View File
@@ -6,6 +6,7 @@ import { DiscordButton } from '../../components/DiscordButton'
import { useEffect, useRef, useState } from 'react'
import axios from 'axios'
import { UAParser } from 'ua-parser-js'
import Dropdown from '@/components/Dropdown'
export default function DownloadPage () {
const [platform, setPlatform] = useState<string>('')
@@ -67,18 +68,17 @@ export default function DownloadPage () {
The official downloads for Lncvrt Games Launcher
</p>
<div className='flex justify-center'>
<select
<Dropdown
value={platform}
onChange={e => setPlatform(e.target.value)}
className=''
>
<option value=''>Select platform</option>
<option value='windows'>Windows</option>
<option value='macos'>macOS</option>
<option value='linux'>Linux</option>
<option value='android'>Android</option>
<option value='ios'>iOS</option>
</select>
options={[
{ label: 'Windows', value: 'windows' },
{ label: 'macOS', value: 'macos' },
{ label: 'Linux', value: 'linux' },
{ label: 'Android', value: 'android' },
{ label: 'iOS', value: 'ios' }
]}
onChange={val => setPlatform(String(val))}
/>
</div>
{(platform == 'windows' || platform == 'macos' || platform == 'linux') &&
(version === null || version === -1 ? (
+12 -12
View File
@@ -4,6 +4,7 @@ import { HomeButton } from '../../components/HomeButton'
import { DiscordButton } from '../../components/DiscordButton'
import { useEffect, useRef, useState } from 'react'
import axios from 'axios'
import Dropdown from '@/components/Dropdown'
interface Version {
id: string
@@ -99,18 +100,17 @@ export default function GameDownloadsPage () {
<div>
<p className='text-center'>Game Filter</p>
<div className='flex justify-center mb-4'>
<select
className='w-full max-w-xs'
value={game}
onChange={e => setGame(Number(e.target.value))}
>
<option value='-1'>Off</option>
{versionManifest.games.map(g => (
<option key={g.id} value={g.id}>
{g.name}
</option>
))}
</select>
<Dropdown
value={String(game)}
options={[
{ label: 'Off', value: '-1' },
...versionManifest.games.map(g => ({
label: g.name,
value: String(g.id)
}))
]}
onChange={val => setGame(Number(val))}
/>
</div>
</div>
<div className='flex flex-col gap-2'>
+16 -15
View File
@@ -9,6 +9,7 @@ import axios from 'axios'
import { GetIconForUser } from '@/util/bd'
import Image from 'next/image'
import { useSearchParams } from 'next/navigation'
import Dropdown from '@/components/Dropdown'
interface BaseEntry {
id: number
@@ -268,21 +269,21 @@ function BerryDashLeaderboardsSuspence () {
</div>
{selected == 1 && (
<div className='flex justify-center'>
<select
value={selectedBerryOption}
onChange={e => setSelectedBerryOption(Number(e.target.value))}
className='-my-4 mt-2'
>
<option value='0'>Normal Berry</option>
<option value='1'>Poison Berry</option>
<option value='2'>Slow Berry</option>
<option value='3'>Ultra Berry</option>
<option value='4'>Speedy Berry</option>
<option value='5'>Coin Berry</option>
<option value='6'>Random Berry</option>
<option value='7'>Anti Berry</option>
<option value='8'>Golden Berry</option>
</select>
<Dropdown
value={String(selectedBerryOption)}
options={[
{ label: 'Normal Berry', value: '0' },
{ label: 'Poison Berry', value: '1' },
{ label: 'Slow Berry', value: '2' },
{ label: 'Ultra Berry', value: '3' },
{ label: 'Speedy Berry', value: '4' },
{ label: 'Coin Berry', value: '5' },
{ label: 'Random Berry', value: '6' },
{ label: 'Anti Berry', value: '7' },
{ label: 'Golden Berry', value: '8' }
]}
onChange={val => setSelectedBerryOption(Number(val))}
/>
</div>
)}
</>
+61
View File
@@ -0,0 +1,61 @@
import { useState, useRef, useEffect } from 'react'
import '@/styles/dropdown.css'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faChevronDown } from '@fortawesome/free-solid-svg-icons'
type Option = {
label: string
value: string | number
}
type Props = {
value: string | number
options: Option[]
onChange: (value: string | number) => void | Promise<void>
}
export default function Dropdown ({ value, options, onChange }: Props) {
const [open, setOpen] = useState(false)
const ref = useRef<HTMLDivElement>(null)
const selected = options.find(o => o.value === value)
useEffect(() => {
const handleClick = (e: MouseEvent) => {
if (!ref.current?.contains(e.target as Node)) {
setOpen(false)
}
}
window.addEventListener('mousedown', handleClick)
return () => window.removeEventListener('mousedown', handleClick)
}, [])
return (
<div ref={ref} className='dropdown'>
<button className='dropdown-btn' onClick={() => setOpen(o => !o)}>
<span>{selected?.label ?? 'Select...'}</span>
<FontAwesomeIcon
icon={faChevronDown}
className={`dropdown-arrow ${open ? 'open' : ''}`}
/>
</button>
<div className={`dropdown-menu ${open ? 'open' : ''}`}>
{options.map((option, i) => (
<div
key={option.value}
className={`dropdown-item ${
option.value === value ? 'active' : ''
}`}
style={{ ['--i']: i } as React.CSSProperties}
onClick={async () => {
await onChange(option.value)
setOpen(false)
}}
>
{option.label}
</div>
))}
</div>
</div>
)
}
+59
View File
@@ -0,0 +1,59 @@
@import "tailwindcss";
.dropdown {
@apply relative w-40;
}
.dropdown-btn {
@apply w-full flex items-center justify-between px-2 py-1 rounded-md cursor-pointer
bg-(--col2) hover:bg-(--col3)
border border-(--col4) hover:border-(--col5);
}
.dropdown-arrow {
@apply w-3 h-3 transition-transform stroke-current stroke-2 fill-none;
}
.dropdown-arrow.open {
@apply rotate-180;
}
.dropdown-menu {
@apply absolute z-50 mt-1 w-full rounded-md shadow-2xl overflow-hidden
bg-(--col2) border border-(--col4)
origin-top
opacity-0 scale-95 -translate-y-1 pointer-events-none
transition-[opacity,transform] duration-150 ease-out;
}
.dropdown-menu.open {
@apply opacity-100 scale-100 translate-y-0 pointer-events-auto;
}
.dropdown-item {
@apply px-2 py-1 cursor-pointer transition-colors border-b border-(--col4) last:border-b-0;
opacity: 0;
transform: translateY(-10px);
}
.dropdown-item:hover,
.dropdown-item.active {
@apply bg-(--col3);
}
.dropdown-menu.open .dropdown-item {
animation: dropIn 220ms ease-out forwards;
animation-delay: calc(var(--i) * 40ms);
}
@keyframes dropIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}