Replace native selects with NovaSelect

This commit is contained in:
2026-05-01 07:45:37 +02:00
parent 67be537c86
commit 35011001ba
55 changed files with 3136 additions and 1662 deletions

View File

@@ -1,6 +1,8 @@
import React from 'react'
import { Head, usePage } from '@inertiajs/react'
import CollectionCard from '../../components/profile/collections/CollectionCard'
import Checkbox from '../../components/ui/Checkbox'
import NovaSelect from '../../components/ui/NovaSelect'
const DEFAULT_SEARCH_FILTERS = {
q: '',
@@ -262,13 +264,7 @@ function BulkActionsPanel({
<div className="mt-4 grid gap-4 lg:grid-cols-4">
<SearchField label="Action">
<select value={form.action} onChange={(event) => onFormChange('action', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="archive">Archive</option>
<option value="assign_campaign">Assign campaign</option>
<option value="update_lifecycle">Update lifecycle</option>
<option value="request_ai_review">Request AI review</option>
<option value="mark_editorial_review">Mark editorial review</option>
</select>
<NovaSelect value={form.action} onChange={(val) => onFormChange('action', val)} searchable={false} options={[{ value: 'archive', label: 'Archive' }, { value: 'assign_campaign', label: 'Assign campaign' }, { value: 'update_lifecycle', label: 'Update lifecycle' }, { value: 'request_ai_review', label: 'Request AI review' }, { value: 'mark_editorial_review', label: 'Mark editorial review' }]} />
</SearchField>
{form.action === 'assign_campaign' ? (
@@ -284,11 +280,7 @@ function BulkActionsPanel({
{form.action === 'update_lifecycle' ? (
<SearchField label="Lifecycle state">
<select value={form.lifecycle_state} onChange={(event) => onFormChange('lifecycle_state', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="draft">Draft</option>
<option value="published">Published</option>
<option value="archived">Archived</option>
</select>
<NovaSelect value={form.lifecycle_state} onChange={(val) => onFormChange('lifecycle_state', val)} searchable={false} options={[{ value: 'draft', label: 'Draft' }, { value: 'published', label: 'Published' }, { value: 'archived', label: 'Archived' }]} />
</SearchField>
) : null}
@@ -344,15 +336,13 @@ function SearchResults({ state, endpoints, selectedIds, onToggleSelected }) {
{state.collections.map((collection) => (
<div key={collection.id} className="space-y-3 rounded-[28px] border border-white/10 bg-[#0d1726] p-5">
<div className="flex items-center justify-between gap-3">
<label className="inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.12em] text-slate-400">
<input
type="checkbox"
<div className="inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.12em] text-slate-400">
<Checkbox
checked={selectedIds.includes(collection.id)}
onChange={() => onToggleSelected(collection.id)}
className="h-4 w-4 rounded border-white/20 bg-[#09111d] text-sky-400 focus:ring-sky-300/30"
label="Select"
/>
Select
</label>
</div>
</div>
<CollectionCard collection={collection} isOwner />
<div className="flex flex-wrap gap-2 text-[11px] font-semibold uppercase tracking-[0.12em] text-slate-400">
@@ -584,56 +574,27 @@ export default function CollectionDashboard() {
</SearchField>
<SearchField label="Type">
<select value={searchFilters.type} onChange={(event) => updateFilter('type', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="">Any type</option>
{(Array.isArray(filterOptions.types) ? filterOptions.types : []).map((option) => (
<option key={option} value={option}>{titleize(option)}</option>
))}
</select>
<NovaSelect value={searchFilters.type} onChange={(val) => updateFilter('type', val)} placeholder="Any type" options={(Array.isArray(filterOptions.types) ? filterOptions.types : []).map((o) => ({ value: o, label: titleize(o) }))} />
</SearchField>
<SearchField label="Visibility">
<select value={searchFilters.visibility} onChange={(event) => updateFilter('visibility', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="">Any visibility</option>
{(Array.isArray(filterOptions.visibilities) ? filterOptions.visibilities : []).map((option) => (
<option key={option} value={option}>{titleize(option)}</option>
))}
</select>
<NovaSelect value={searchFilters.visibility} onChange={(val) => updateFilter('visibility', val)} placeholder="Any visibility" options={(Array.isArray(filterOptions.visibilities) ? filterOptions.visibilities : []).map((o) => ({ value: o, label: titleize(o) }))} />
</SearchField>
<SearchField label="Lifecycle">
<select value={searchFilters.lifecycle_state} onChange={(event) => updateFilter('lifecycle_state', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="">Any lifecycle</option>
{(Array.isArray(filterOptions.lifecycleStates) ? filterOptions.lifecycleStates : []).map((option) => (
<option key={option} value={option}>{titleize(option)}</option>
))}
</select>
<NovaSelect value={searchFilters.lifecycle_state} onChange={(val) => updateFilter('lifecycle_state', val)} placeholder="Any lifecycle" options={(Array.isArray(filterOptions.lifecycleStates) ? filterOptions.lifecycleStates : []).map((o) => ({ value: o, label: titleize(o) }))} />
</SearchField>
<SearchField label="Workflow">
<select value={searchFilters.workflow_state} onChange={(event) => updateFilter('workflow_state', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="">Any workflow</option>
{(Array.isArray(filterOptions.workflowStates) ? filterOptions.workflowStates : []).map((option) => (
<option key={option} value={option}>{titleize(option)}</option>
))}
</select>
<NovaSelect value={searchFilters.workflow_state} onChange={(val) => updateFilter('workflow_state', val)} placeholder="Any workflow" options={(Array.isArray(filterOptions.workflowStates) ? filterOptions.workflowStates : []).map((o) => ({ value: o, label: titleize(o) }))} />
</SearchField>
<SearchField label="Health">
<select value={searchFilters.health_state} onChange={(event) => updateFilter('health_state', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="">Any health state</option>
{(Array.isArray(filterOptions.healthStates) ? filterOptions.healthStates : []).map((option) => (
<option key={option} value={option}>{titleize(option)}</option>
))}
</select>
<NovaSelect value={searchFilters.health_state} onChange={(val) => updateFilter('health_state', val)} placeholder="Any health state" options={(Array.isArray(filterOptions.healthStates) ? filterOptions.healthStates : []).map((o) => ({ value: o, label: titleize(o) }))} />
</SearchField>
<SearchField label="Placement">
<select value={searchFilters.placement_eligibility} onChange={(event) => updateFilter('placement_eligibility', event.target.value)} className="w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/40">
<option value="">Any placement state</option>
<option value="1">Eligible</option>
<option value="0">Blocked</option>
</select>
<NovaSelect value={searchFilters.placement_eligibility} onChange={(val) => updateFilter('placement_eligibility', val)} placeholder="Any placement state" searchable={false} options={[{ value: '1', label: 'Eligible' }, { value: '0', label: 'Blocked' }]} />
</SearchField>
<div className="flex items-end gap-3 xl:col-span-1">