diff --git a/src/components/Contact/ContactForm.tsx b/src/components/Contact/ContactForm.tsx index 58f664c..6f99903 100644 --- a/src/components/Contact/ContactForm.tsx +++ b/src/components/Contact/ContactForm.tsx @@ -4,6 +4,7 @@ import React, { useActionState } from "react"; import { useSearchParams } from "next/navigation"; import { validateEmail } from "@/utils/auth"; import { sendContact, type ContactActionState } from "@/app/contact/actions"; +import Select from "@/components/Primitives/Select"; type Topic = | "general" @@ -70,17 +71,16 @@ export default function ContactForm() { )}
- + onChange={(value) => setTopic(value as Topic)} + options={(Object.keys(topicLabels) as Topic[]).map((key) => ({ + value: key, + label: topicLabels[key], + }))} + /> Choose the most relevant topic so we can help you better. diff --git a/src/components/Dashboard/ArchivesList.tsx b/src/components/Dashboard/ArchivesList.tsx index 199961d..dde0afc 100644 --- a/src/components/Dashboard/ArchivesList.tsx +++ b/src/components/Dashboard/ArchivesList.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; import { FiExternalLink, FiEdit2, FiTrash2, FiChevronLeft, FiChevronRight, FiArrowDown, FiSearch, FiLoader, FiDownload, FiInfo, FiBarChart2 } from "react-icons/fi"; import { getArchives, deleteArchive } from "@/app/dashboard/archives/actions"; import { baseRoms } from "@/data/baseRoms"; +import Select from "@/components/Primitives/Select"; type Archive = { slug: string; @@ -118,24 +119,26 @@ export default function ArchivesList({ initialData, isAdmin = false }: { initial )}
- - setSortBy(e.target.value as any)} - className="w-full md:w-auto rounded-md bg-[var(--surface-2)] px-3 py-2 text-sm ring-1 ring-inset ring-[var(--border)] focus:outline-none focus:ring-2 focus:ring-[var(--ring)]" - > - - - - + onChange={(value) => setSortBy(value as any)} + className="w-full md:w-auto" + options={[ + { value: "created_at", label: "Sort by date" }, + { value: "title", label: "Sort by title" }, + { value: "original_author", label: "Sort by author" }, + ]} + />
)} - + { if ((newCoverFiles.length) > 0) return; setPlatform(e.target.value as any); setBaseRom(""); }} + onChange={(value) => { if ((newCoverFiles.length) > 0) return; setPlatform(value as any); setBaseRom(""); }} disabled={newCoverFiles.length > 0} - className="h-11 rounded-md bg-[var(--surface-2)] px-3 text-sm ring-1 ring-inset ring-[var(--border)] focus:outline-none focus:ring-2 focus:ring-[var(--ring)] disabled:opacity-50" - > - - {(["GB","GBC","GBA","NDS"] as const).map(p => ( - - ))} - + placeholder="Select platform" + options={(["GB","GBC","GBA","NDS"] as const).map(p => ({ + value: p, + label: p, + }))} + /> ) : (
{platform || ""}
)} @@ -755,19 +755,16 @@ export default function HackSubmitForm({
{!isDummy ? ( - + placeholder={platform ? "Select base rom" : "Select platform first"} + options={baseRoms.filter(r => !platform || r.platform === platform).map(({ id, name, region }) => ({ + value: id, + label: `${name.replace('Pokémon ', '')} (${region})`, + }))} + /> ) : (
{baseRoms.find(r=>r.id===baseRom)?.name || baseRom}
)} @@ -776,16 +773,15 @@ export default function HackSubmitForm({
{!isDummy ? ( - + onChange={setLanguage} + placeholder="Select language" + options={['English','Spanish','French','German','Italian','Portuguese','Japanese','Chinese','Korean','Other'].map(l => ({ + value: l, + label: l, + }))} + /> ) : (
{language}
)} diff --git a/src/components/Primitives/Select.tsx b/src/components/Primitives/Select.tsx new file mode 100644 index 0000000..93e0bbf --- /dev/null +++ b/src/components/Primitives/Select.tsx @@ -0,0 +1,90 @@ +"use client"; + +import React, { Fragment } from "react"; +import { Listbox, ListboxButton, ListboxOptions, ListboxOption, Transition } from "@headlessui/react"; +import { FiChevronDown, FiCheck } from "react-icons/fi"; + +export interface SelectOption { + value: string; + label: string; + disabled?: boolean; +} + +interface SelectProps { + value: string; + onChange: (value: string) => void; + options: SelectOption[]; + placeholder?: string; + disabled?: boolean; + className?: string; + id?: string; + name?: string; +} + +export default function Select({ + value, + onChange, + options, + placeholder = "Select an option", + disabled = false, + className = "", + id, + name, +}: SelectProps) { + const selectedOption = options.find((opt) => opt.value === value); + + return ( + + {({ open }) => ( +
+ + + {selectedOption?.label || placeholder} + + + + + {name && } + + + {options.map((option) => ( + + `relative cursor-pointer select-none py-2 pl-10 pr-4 ${ + focus ? "bg-black/5 dark:bg-white/10" : "" + } ${option.disabled ? "opacity-50 cursor-not-allowed" : ""}` + } + > + {({ selected }) => ( + <> + + {option.label} + + {selected && ( + + + )} + + )} + + ))} + + +
+ )} +
+ ); +}