Refresh releases and magazines UI
Apply sidebar filter layout and header summary to releases and magazines list pages. Signed-off-by: codex@lucy.xalior.com
This commit is contained in:
@@ -27,30 +27,58 @@ export default async function Page({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h1 className="mb-3">Magazines</h1>
|
<div className="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h1 className="mb-1">Magazines</h1>
|
||||||
|
<div className="text-secondary">{data.total.toLocaleString()} results</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form className="mb-3" action="/zxdb/magazines" method="get">
|
<div className="row g-3">
|
||||||
<div className="input-group">
|
<div className="col-lg-3">
|
||||||
|
<div className="card shadow-sm">
|
||||||
|
<div className="card-body">
|
||||||
|
<form className="d-flex flex-column gap-2" action="/zxdb/magazines" method="get">
|
||||||
|
<div>
|
||||||
|
<label className="form-label small text-secondary">Search</label>
|
||||||
<input type="text" className="form-control" name="q" placeholder="Search magazines..." defaultValue={q} />
|
<input type="text" className="form-control" name="q" placeholder="Search magazines..." defaultValue={q} />
|
||||||
<button className="btn btn-outline-secondary" type="submit">
|
</div>
|
||||||
<span className="bi bi-search" aria-hidden />
|
<div className="d-grid">
|
||||||
<span className="visually-hidden">Search</span>
|
<button className="btn btn-primary" type="submit">Search</button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="list-group">
|
<div className="col-lg-9">
|
||||||
|
<div className="table-responsive">
|
||||||
|
<table className="table table-striped table-hover align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th style={{ width: 140 }}>Language</th>
|
||||||
|
<th style={{ width: 120 }}>Issues</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
{data.items.map((m) => (
|
{data.items.map((m) => (
|
||||||
<Link key={m.id} className="list-group-item list-group-item-action d-flex justify-content-between align-items-center" href={`/zxdb/magazines/${m.id}`}>
|
<tr key={m.id}>
|
||||||
<span>
|
<td>
|
||||||
{m.title}
|
<Link href={`/zxdb/magazines/${m.id}`}>{m.title}</Link>
|
||||||
<span className="text-secondary ms-2">({m.languageId})</span>
|
</td>
|
||||||
</span>
|
<td>{m.languageId}</td>
|
||||||
|
<td>
|
||||||
<span className="badge bg-secondary rounded-pill" title="Issues">
|
<span className="badge bg-secondary rounded-pill" title="Issues">
|
||||||
{m.issueCount}
|
{m.issueCount}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</td>
|
||||||
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Pagination page={data.page} pageSize={data.pageSize} total={data.total} q={q} />
|
<Pagination page={data.page} pageSize={data.pageSize} total={data.total} q={q} />
|
||||||
|
|||||||
@@ -238,9 +238,22 @@ export default function ReleasesExplorer({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h1 className="mb-3">Releases</h1>
|
<div className="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-3">
|
||||||
<form className="row gy-2 gx-2 align-items-center" onSubmit={onSubmit}>
|
<div>
|
||||||
<div className="col-sm-8 col-md-6 col-lg-4">
|
<h1 className="mb-1">Releases</h1>
|
||||||
|
<div className="text-secondary">
|
||||||
|
{data ? `${data.total.toLocaleString()} results` : "Loading results..."}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row g-3">
|
||||||
|
<div className="col-lg-3">
|
||||||
|
<div className="card shadow-sm">
|
||||||
|
<div className="card-body">
|
||||||
|
<form className="d-flex flex-column gap-2" onSubmit={onSubmit}>
|
||||||
|
<div>
|
||||||
|
<label className="form-label small text-secondary">Search title</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
@@ -249,84 +262,93 @@ export default function ReleasesExplorer({
|
|||||||
onChange={(e) => setQ(e.target.value)}
|
onChange={(e) => setQ(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div className="d-grid">
|
||||||
<button className="btn btn-primary" type="submit" disabled={loading}>Search</button>
|
<button className="btn btn-primary" type="submit" disabled={loading}>Search</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">Year</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder="Year"
|
placeholder="Any"
|
||||||
value={year}
|
value={year}
|
||||||
onChange={(e) => { setYear(e.target.value); setPage(1); }}
|
onChange={(e) => { setYear(e.target.value); setPage(1); }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">DL Language</label>
|
||||||
<select className="form-select" value={dLanguageId} onChange={(e) => { setDLanguageId(e.target.value); setPage(1); }}>
|
<select className="form-select" value={dLanguageId} onChange={(e) => { setDLanguageId(e.target.value); setPage(1); }}>
|
||||||
<option value="">DL Language</option>
|
<option value="">All languages</option>
|
||||||
{langs.map((l) => (
|
{langs.map((l) => (
|
||||||
<option key={l.id} value={l.id}>{l.name}</option>
|
<option key={l.id} value={l.id}>{l.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">DL Machine</label>
|
||||||
<select className="form-select" value={dMachinetypeId} onChange={(e) => { setDMachinetypeId(e.target.value); setPage(1); }}>
|
<select className="form-select" value={dMachinetypeId} onChange={(e) => { setDMachinetypeId(e.target.value); setPage(1); }}>
|
||||||
<option value="">DL Machine</option>
|
<option value="">All machines</option>
|
||||||
{machines.map((m) => (
|
{machines.map((m) => (
|
||||||
<option key={m.id} value={m.id}>{m.name}</option>
|
<option key={m.id} value={m.id}>{m.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">File type</label>
|
||||||
<select className="form-select" value={filetypeId} onChange={(e) => { setFiletypeId(e.target.value); setPage(1); }}>
|
<select className="form-select" value={filetypeId} onChange={(e) => { setFiletypeId(e.target.value); setPage(1); }}>
|
||||||
<option value="">File type</option>
|
<option value="">All file types</option>
|
||||||
{filetypes.map((ft) => (
|
{filetypes.map((ft) => (
|
||||||
<option key={ft.id} value={ft.id}>{ft.name}</option>
|
<option key={ft.id} value={ft.id}>{ft.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">Scheme</label>
|
||||||
<select className="form-select" value={schemetypeId} onChange={(e) => { setSchemetypeId(e.target.value); setPage(1); }}>
|
<select className="form-select" value={schemetypeId} onChange={(e) => { setSchemetypeId(e.target.value); setPage(1); }}>
|
||||||
<option value="">Scheme</option>
|
<option value="">All schemes</option>
|
||||||
{schemes.map((s) => (
|
{schemes.map((s) => (
|
||||||
<option key={s.id} value={s.id}>{s.name}</option>
|
<option key={s.id} value={s.id}>{s.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">Source</label>
|
||||||
<select className="form-select" value={sourcetypeId} onChange={(e) => { setSourcetypeId(e.target.value); setPage(1); }}>
|
<select className="form-select" value={sourcetypeId} onChange={(e) => { setSourcetypeId(e.target.value); setPage(1); }}>
|
||||||
<option value="">Source</option>
|
<option value="">All sources</option>
|
||||||
{sources.map((s) => (
|
{sources.map((s) => (
|
||||||
<option key={s.id} value={s.id}>{s.name}</option>
|
<option key={s.id} value={s.id}>{s.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">Case</label>
|
||||||
<select className="form-select" value={casetypeId} onChange={(e) => { setCasetypeId(e.target.value); setPage(1); }}>
|
<select className="form-select" value={casetypeId} onChange={(e) => { setCasetypeId(e.target.value); setPage(1); }}>
|
||||||
<option value="">Case</option>
|
<option value="">All cases</option>
|
||||||
{cases.map((c) => (
|
{cases.map((c) => (
|
||||||
<option key={c.id} value={c.id}>{c.name}</option>
|
<option key={c.id} value={c.id}>{c.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto form-check ms-2">
|
<div className="form-check">
|
||||||
<input id="demoCheck" className="form-check-input" type="checkbox" checked={isDemo} onChange={(e) => { setIsDemo(e.target.checked); setPage(1); }} />
|
<input id="demoCheck" className="form-check-input" type="checkbox" checked={isDemo} onChange={(e) => { setIsDemo(e.target.checked); setPage(1); }} />
|
||||||
<label className="form-check-label" htmlFor="demoCheck">Demo only</label>
|
<label className="form-check-label" htmlFor="demoCheck">Demo only</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div>
|
||||||
|
<label className="form-label small text-secondary">Sort</label>
|
||||||
<select className="form-select" value={sort} onChange={(e) => { setSort(e.target.value as typeof sort); setPage(1); }}>
|
<select className="form-select" value={sort} onChange={(e) => { setSort(e.target.value as typeof sort); setPage(1); }}>
|
||||||
<option value="year_desc">Sort: Newest</option>
|
<option value="year_desc">Newest</option>
|
||||||
<option value="year_asc">Sort: Oldest</option>
|
<option value="year_asc">Oldest</option>
|
||||||
<option value="title">Sort: Title</option>
|
<option value="title">Title</option>
|
||||||
<option value="entry_id_desc">Sort: Entry ID</option>
|
<option value="entry_id_desc">Entry ID</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{loading && (
|
{loading && <div className="text-secondary small">Loading...</div>}
|
||||||
<div className="col-auto text-secondary">Loading...</div>
|
|
||||||
)}
|
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mt-3">
|
<div className="col-lg-9">
|
||||||
{data && data.items.length === 0 && !loading && (
|
{data && data.items.length === 0 && !loading && (
|
||||||
<div className="alert alert-warning">No results.</div>
|
<div className="alert alert-warning">No results.</div>
|
||||||
)}
|
)}
|
||||||
@@ -375,11 +397,10 @@ export default function ReleasesExplorer({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="d-flex align-items-center gap-2 mt-2">
|
<div className="d-flex align-items-center gap-2 mt-4">
|
||||||
<span>
|
<span>Page {data?.page ?? 1} / {totalPages}</span>
|
||||||
Page {data?.page ?? 1} / {totalPages}
|
|
||||||
</span>
|
|
||||||
<div className="ms-auto d-flex gap-2">
|
<div className="ms-auto d-flex gap-2">
|
||||||
<Link
|
<Link
|
||||||
className={`btn btn-outline-secondary ${!data || (data.page <= 1) ? "disabled" : ""}`}
|
className={`btn btn-outline-secondary ${!data || (data.page <= 1) ? "disabled" : ""}`}
|
||||||
|
|||||||
Reference in New Issue
Block a user