Spaces:
Running
Running
| 'use client'; | |
| /** | |
| * @license | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| interface SearchSelectProps { | |
| label: string; | |
| value: string; | |
| options: string[]; | |
| onChange: (value: string) => void; | |
| className?: string; | |
| } | |
| export function SearchSelect({ label, value, options, onChange, className = "" }: SearchSelectProps) { | |
| return ( | |
| <div className={`space-y-4 ${className}`}> | |
| <label className="text-sm font-bold text-slate-400 uppercase tracking-[0.1em] block"> | |
| {label} | |
| </label> | |
| <div className="relative"> | |
| <select | |
| value={value} | |
| onChange={e => onChange(e.target.value)} | |
| className="w-full h-14 px-5 bg-slate-50 border border-slate-100 rounded-2xl text-slate-700 text-base font-bold appearance-none focus:bg-white focus:border-cyan-500 focus:ring-4 focus:ring-cyan-50/50 transition-all outline-none" | |
| > | |
| <option value="" disabled hidden>선택해주세요</option> | |
| {options.map(opt => <option key={opt} value={opt} className="text-base">{opt}</option>)} | |
| </select> | |
| <div className="absolute right-5 top-1/2 -translate-y-1/2 pointer-events-none text-slate-400"> | |
| <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M19 9l-7 7-7-7" /> | |
| </svg> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| interface SearchRadioGroupProps { | |
| label: string; | |
| value: string; | |
| options: string[]; | |
| onChange: (value: string) => void; | |
| name: string; | |
| } | |
| export function SearchRadioGroup({ label, value, options, onChange, name }: SearchRadioGroupProps) { | |
| return ( | |
| <div className="space-y-5"> | |
| <label className="text-sm font-bold text-slate-400 uppercase tracking-[0.1em] block"> | |
| {label} | |
| </label> | |
| <div className="grid grid-cols-2 md:grid-cols-3 gap-3 sm:gap-5"> | |
| {options.map(opt => ( | |
| <label | |
| key={opt} | |
| className={` | |
| flex items-center justify-center min-h-14 px-4 py-3 rounded-2xl text-sm sm:text-base text-center break-keep font-bold border transition-all cursor-pointer | |
| ${value === opt | |
| ? 'border-cyan-500 bg-cyan-50 text-cyan-700 ring-4 ring-cyan-50' | |
| : 'border-slate-100 bg-slate-50 text-slate-400 hover:border-slate-200'} | |
| `} | |
| > | |
| <input | |
| type="radio" | |
| name={name} | |
| value={opt} | |
| checked={value === opt} | |
| onChange={() => onChange(opt)} | |
| className="sr-only" | |
| /> | |
| {opt} | |
| </label> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| interface SearchInputProps { | |
| label: string; | |
| value: number; | |
| onChange: (value: number) => void; | |
| unit: string; | |
| } | |
| export function SearchInput({ label, value, onChange, unit }: SearchInputProps) { | |
| return ( | |
| <div className="space-y-4"> | |
| <div className="flex items-center justify-between"> | |
| <label className="text-sm font-bold text-slate-400 uppercase tracking-[0.1em]"> | |
| {label} | |
| </label> | |
| </div> | |
| <div className="relative"> | |
| <input | |
| type="number" | |
| value={value === 0 ? '' : value} | |
| onChange={e => onChange(Number(e.target.value))} | |
| className="w-full h-14 pl-5 pr-16 bg-slate-50 border border-slate-100 rounded-2xl text-base font-bold text-slate-800 focus:bg-white focus:border-cyan-500 focus:ring-4 focus:ring-cyan-50/50 transition-all outline-none" | |
| placeholder="0" | |
| /> | |
| <div className="absolute right-5 top-1/2 -translate-y-1/2 pointer-events-none font-bold text-slate-400">{unit}</div> | |
| </div> | |
| </div> | |
| ); | |
| } | |