feat: restyle SubmitForm with Tailwind, inline button, and violet glow
This commit is contained in:
@@ -7,6 +7,18 @@ import { useRouter } from '@/navigation'
|
|||||||
const FORMATS = ['mp4', 'mp3', 'webm', 'mkv']
|
const FORMATS = ['mp4', 'mp3', 'webm', 'mkv']
|
||||||
const QUALITIES = ['best', '1080p', '720p', '480p', '360p']
|
const QUALITIES = ['best', '1080p', '720p', '480p', '360p']
|
||||||
|
|
||||||
|
function Spinner() {
|
||||||
|
return (
|
||||||
|
<svg className="animate-spin w-4 h-4" viewBox="0 0 24 24" fill="none" aria-hidden>
|
||||||
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
|
||||||
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectClass =
|
||||||
|
'rounded-lg border border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-2 py-1 text-gray-900 dark:text-gray-50 text-sm outline-none focus:ring-2 focus:ring-violet-500'
|
||||||
|
|
||||||
export function SubmitForm() {
|
export function SubmitForm() {
|
||||||
const t = useTranslations('home')
|
const t = useTranslations('home')
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -52,58 +64,82 @@ export function SubmitForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: 480 }}>
|
<form onSubmit={handleSubmit} className="w-full max-w-2xl mx-auto">
|
||||||
<label>
|
{/* URL input with inline submit button */}
|
||||||
{t('urlLabel')}
|
<div className="relative">
|
||||||
<input
|
{/* Violet glow behind the input */}
|
||||||
type="url"
|
<div className="absolute inset-0 -z-10 rounded-xl bg-violet-500 blur-3xl opacity-15 dark:opacity-20" aria-hidden />
|
||||||
value={url}
|
<div className="flex rounded-xl border border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 overflow-hidden shadow-sm focus-within:ring-2 focus-within:ring-violet-500">
|
||||||
onChange={(e) => setUrl(e.target.value)}
|
<input
|
||||||
required
|
type="url"
|
||||||
placeholder="https://www.youtube.com/watch?v=..."
|
value={url}
|
||||||
style={{ display: 'block', width: '100%' }}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
/>
|
required
|
||||||
</label>
|
placeholder="https://www.youtube.com/watch?v=..."
|
||||||
|
className="flex-1 px-4 py-3 bg-transparent text-sm outline-none placeholder:text-gray-400 dark:placeholder:text-slate-500"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={loading}
|
||||||
|
className="flex items-center gap-2 px-5 py-3 bg-violet-600 hover:bg-violet-700 dark:bg-violet-500 dark:hover:bg-violet-600 text-white text-sm font-medium transition-colors disabled:opacity-60"
|
||||||
|
>
|
||||||
|
{loading && <Spinner />}
|
||||||
|
{loading ? t('submitting') : t('submit')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label>
|
{/* Options row */}
|
||||||
{t('format')}
|
<div className="mt-4 flex flex-wrap items-center gap-x-5 gap-y-3 text-sm text-gray-600 dark:text-gray-400">
|
||||||
<select value={format} onChange={(e) => setFormat(e.target.value)} style={{ display: 'block' }}>
|
<label className="flex items-center gap-2">
|
||||||
{FORMATS.map((f) => <option key={f}>{f}</option>)}
|
<span>{t('format')}</span>
|
||||||
</select>
|
<select
|
||||||
</label>
|
value={format}
|
||||||
|
onChange={(e) => setFormat(e.target.value)}
|
||||||
|
className={selectClass}
|
||||||
|
>
|
||||||
|
{FORMATS.map((f) => <option key={f}>{f}</option>)}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
<label>
|
<label className="flex items-center gap-2">
|
||||||
{t('quality')}
|
<span>{t('quality')}</span>
|
||||||
<select value={quality} onChange={(e) => setQuality(e.target.value)} style={{ display: 'block' }}>
|
<select
|
||||||
{QUALITIES.map((q) => <option key={q}>{q}</option>)}
|
value={quality}
|
||||||
</select>
|
onChange={(e) => setQuality(e.target.value)}
|
||||||
</label>
|
className={selectClass}
|
||||||
|
>
|
||||||
|
{QUALITIES.map((q) => <option key={q}>{q}</option>)}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
<label>
|
<label className="flex items-center gap-2 cursor-pointer">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={subtitles}
|
checked={subtitles}
|
||||||
onChange={(e) => setSubtitles(e.target.checked)}
|
onChange={(e) => setSubtitles(e.target.checked)}
|
||||||
/>{' '}
|
className="accent-violet-600 w-4 h-4"
|
||||||
{t('subtitles')}
|
/>
|
||||||
</label>
|
<span>{t('subtitles')}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
<label>
|
<details className="w-full mt-1">
|
||||||
{t('advanced')}
|
<summary className="cursor-pointer select-none text-gray-500 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition-colors">
|
||||||
<input
|
{t('advanced')}
|
||||||
type="text"
|
</summary>
|
||||||
value={extraArgs}
|
<input
|
||||||
onChange={(e) => setExtraArgs(e.target.value)}
|
type="text"
|
||||||
placeholder='["--sponsorblock-remove","all"]'
|
value={extraArgs}
|
||||||
style={{ display: 'block', width: '100%' }}
|
onChange={(e) => setExtraArgs(e.target.value)}
|
||||||
/>
|
placeholder='["--sponsorblock-remove","all"]'
|
||||||
</label>
|
className="mt-2 w-full rounded-lg border border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-3 py-2 text-sm text-gray-900 dark:text-gray-50 outline-none focus:ring-2 focus:ring-violet-500"
|
||||||
|
/>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
{error && <p style={{ color: 'red' }}>{error}</p>}
|
{error && (
|
||||||
|
<p className="mt-3 text-sm text-red-600 dark:text-red-400">{error}</p>
|
||||||
<button type="submit" disabled={loading}>
|
)}
|
||||||
{loading ? t('submitting') : t('submit')}
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user