Replace native selects with NovaSelect
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import NovaSelect from '../../../ui/NovaSelect'
|
||||
|
||||
function Button({ tone = 'default', children, ...props }) {
|
||||
const tones = {
|
||||
default: 'border-white/10 bg-white/[0.04] text-slate-200',
|
||||
sky: 'border-sky-300/20 bg-sky-400/10 text-sky-100',
|
||||
emerald: 'border-emerald-300/20 bg-emerald-400/10 text-emerald-100',
|
||||
amber: 'border-amber-300/20 bg-amber-400/10 text-amber-100',
|
||||
rose: 'border-rose-300/20 bg-rose-400/10 text-rose-100',
|
||||
}
|
||||
|
||||
return <button type="button" {...props} className={`rounded-2xl border px-3 py-2 text-sm font-semibold transition disabled:cursor-not-allowed disabled:opacity-50 ${tones[tone] || tones.default} ${props.className || ''}`.trim()}>{children}</button>
|
||||
}
|
||||
|
||||
export default function WorldSuggestionActions({ item, busyKey = '', onAddFeatured, onAddSection, onPin, onDismiss, onNotRelevant, onRestore }) {
|
||||
const targets = Array.isArray(item?.section_targets) ? item.section_targets : []
|
||||
const [selectedSection, setSelectedSection] = useState(item?.default_section_key || targets[0]?.value || '')
|
||||
const isBusy = Boolean(busyKey)
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedSection(item?.state?.section_key || item?.default_section_key || targets[0]?.value || '')
|
||||
}, [item?.default_section_key, item?.state?.section_key, targets])
|
||||
|
||||
if (!item) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (item.state?.status === 'dismissed' || item.state?.status === 'not_relevant') {
|
||||
return (
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
<Button tone="sky" disabled={isBusy} onClick={() => onRestore(item)}>Restore</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-4 grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-end">
|
||||
<div className="grid gap-2">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">Section target</span>
|
||||
<div className="flex flex-col gap-2 sm:flex-row">
|
||||
<NovaSelect value={selectedSection} onChange={(val) => setSelectedSection(val)} options={targets} searchable={false} className="min-w-0 flex-1" />
|
||||
<Button tone="emerald" disabled={isBusy || !selectedSection} onClick={() => onAddSection(item, selectedSection, false)}>Add to section</Button>
|
||||
<Button tone="amber" disabled={isBusy || !selectedSection} onClick={() => onAddFeatured(item, selectedSection)}>Add as featured</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap justify-start gap-2 lg:justify-end">
|
||||
<Button tone={item.state?.status === 'pinned' ? 'sky' : 'default'} disabled={isBusy || !selectedSection} onClick={() => item.state?.status === 'pinned' ? onRestore(item) : onPin(item, selectedSection)}>{item.state?.status === 'pinned' ? 'Unpin' : 'Pin for later'}</Button>
|
||||
<Button tone="default" disabled={isBusy} onClick={() => onDismiss(item)}>Dismiss</Button>
|
||||
<Button tone="rose" disabled={isBusy} onClick={() => onNotRelevant(item)}>Not relevant</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
import Checkbox from '../../../ui/Checkbox'
|
||||
import NovaSelect from '../../../ui/NovaSelect'
|
||||
|
||||
function FilterSelect({ label, value, onChange, options = [] }) {
|
||||
const novaOptions = [{ value: '', label: 'All' }, ...options.map((o) => ({ value: o.value, label: typeof o.count === 'number' ? `${o.label} (${o.count})` : o.label }))]
|
||||
return (
|
||||
<div className="grid gap-2 text-sm text-slate-300">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">{label}</span>
|
||||
<NovaSelect value={value || ''} onChange={onChange} options={novaOptions} searchable={false} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function WorldSuggestionFilters({ filters, value, onChange }) {
|
||||
return (
|
||||
<div className="grid gap-4 rounded-[24px] border border-white/10 bg-black/20 p-4 xl:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_minmax(0,0.9fr)]">
|
||||
<FilterSelect label="Category" value={value.category} onChange={(nextValue) => onChange({ ...value, category: nextValue })} options={filters?.category_options || []} />
|
||||
<FilterSelect label="Entity type" value={value.type} onChange={(nextValue) => onChange({ ...value, type: nextValue })} options={filters?.type_options || []} />
|
||||
<FilterSelect label="Section target" value={value.section} onChange={(nextValue) => onChange({ ...value, section: nextValue })} options={filters?.section_options || []} />
|
||||
<FilterSelect label="Sort" value={value.sort} onChange={(nextValue) => onChange({ ...value, sort: nextValue })} options={filters?.sort_options || []} />
|
||||
|
||||
<div className="flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-200">
|
||||
<Checkbox checked={value.challengeOnly} onChange={(event) => onChange({ ...value, challengeOnly: event.target.checked })} label="Challenge-linked only" />
|
||||
</div>
|
||||
<div className="flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-200">
|
||||
<Checkbox checked={value.communityOnly} onChange={(event) => onChange({ ...value, communityOnly: event.target.checked })} label="Community submissions only" />
|
||||
</div>
|
||||
<div className="flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-200">
|
||||
<Checkbox checked={value.recurringOnly} onChange={(event) => onChange({ ...value, recurringOnly: event.target.checked })} label="Recurring-history informed" />
|
||||
</div>
|
||||
<div className="flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-200">
|
||||
<Checkbox checked={value.analyticsOnly} onChange={(event) => onChange({ ...value, analyticsOnly: event.target.checked })} label="Analytics-informed only" />
|
||||
</div>
|
||||
<div className="flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-200">
|
||||
<Checkbox checked={value.showSuppressed} onChange={(event) => onChange({ ...value, showSuppressed: event.target.checked })} label="Show suppressed" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user