feat(ui): mejorar estilos y estructura de componentes en el dashboard
Se ajustan los estilos y la estructura de varios componentes en el dashboard, incluyendo ExportDropdown, ResearcherCard, SwordProfileSelect y SyncButton, para mejorar la presentación y la responsividad. Se añade soporte para clases personalizadas en SyncButton y se integra el nuevo sistema de exportación en GroupResultsPage.
This commit is contained in:
@@ -49,19 +49,20 @@ export function ExportDropdown({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap items-center justify-end gap-2 sm:flex-nowrap">
|
||||
<div className="mx-auto flex w-full max-w-[440px] flex-col items-stretch gap-2 sm:mx-0 sm:w-auto sm:max-w-none sm:flex-row sm:items-center sm:justify-end">
|
||||
<SwordProfileSelect
|
||||
id="dashboard-export-destination"
|
||||
value={exportDestination}
|
||||
onChange={onExportDestinationChange}
|
||||
includeZip
|
||||
className="w-full"
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDownload}
|
||||
disabled={isBusy || nothingToDownload}
|
||||
className="inline-flex items-center gap-2 rounded-lg border border-surface-border-strong bg-surface-primary px-[18px] py-2.5 text-sm font-medium text-ink-primary transition-colors enabled:hover:bg-surface-secondary disabled:cursor-not-allowed disabled:opacity-70"
|
||||
className="inline-flex w-full items-center justify-center gap-2 rounded-lg border border-surface-border-strong bg-surface-primary px-[18px] py-2.5 text-sm font-medium text-ink-primary transition-colors enabled:hover:bg-surface-secondary disabled:cursor-not-allowed disabled:opacity-70 sm:w-auto"
|
||||
>
|
||||
{isBusy ? (
|
||||
<Spinner size={15} />
|
||||
|
||||
@@ -44,7 +44,7 @@ export function ResearcherCard({ researcher, actions = null }) {
|
||||
</div>
|
||||
|
||||
{actions && (
|
||||
<div className="ml-auto flex shrink-0 flex-col items-end gap-2.5">
|
||||
<div className="flex w-full flex-col items-stretch gap-2.5 md:ml-auto md:w-auto md:shrink-0 md:items-end">
|
||||
{actions}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -48,28 +48,32 @@ export function SwordProfileSelect({
|
||||
return (
|
||||
<div
|
||||
ref={rootRef}
|
||||
className={`flex items-center gap-2 text-sm ${className}`.trim()}
|
||||
className={`flex w-full flex-col items-start gap-1.5 text-sm sm:w-auto sm:flex-row sm:items-center sm:gap-2 ${className}`.trim()}
|
||||
>
|
||||
<span className="whitespace-nowrap text-ink-tertiary">Destino:</span>
|
||||
<div className="relative">
|
||||
<span className="w-full whitespace-nowrap text-center text-ink-tertiary sm:w-auto sm:text-left">
|
||||
Destino:
|
||||
</span>
|
||||
<div className="relative w-full sm:w-auto sm:flex-none">
|
||||
<button
|
||||
type="button"
|
||||
id={id}
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded={open}
|
||||
onClick={() => setOpen((o) => !o)}
|
||||
className="inline-flex min-w-44 items-center gap-2 rounded-lg border border-surface-border-strong bg-surface-primary px-3 py-2.5 text-sm font-medium text-ink-primary transition-colors hover:bg-surface-secondary"
|
||||
className="relative inline-flex w-full min-w-44 items-center justify-center rounded-lg border border-surface-border-strong bg-surface-primary px-3 py-2.5 pr-10 text-sm font-medium text-ink-primary transition-colors hover:bg-surface-secondary sm:w-auto"
|
||||
>
|
||||
<ExportProfileIcon profile={selected.value} size={20} />
|
||||
<span className="truncate">{selected.label}</span>
|
||||
<ChevronDownIcon className="ml-auto shrink-0" />
|
||||
<span className="inline-flex min-w-0 items-center gap-2">
|
||||
<ExportProfileIcon profile={selected.value} size={20} />
|
||||
<span className="truncate text-center">{selected.label}</span>
|
||||
</span>
|
||||
<ChevronDownIcon className="pointer-events-none absolute right-3 top-1/2 shrink-0 -translate-y-1/2" />
|
||||
</button>
|
||||
|
||||
{open && (
|
||||
<div
|
||||
role="listbox"
|
||||
aria-labelledby={id}
|
||||
className="absolute left-0 top-[calc(100%+6px)] z-50 min-w-80 overflow-hidden rounded-xl border border-surface-border-strong bg-surface-primary shadow-lg"
|
||||
className="absolute left-0 top-[calc(100%+6px)] z-50 w-full min-w-0 overflow-hidden rounded-xl border border-surface-border-strong bg-surface-primary shadow-lg sm:min-w-80"
|
||||
>
|
||||
{options.map(({ value: optionValue, label, desc }, idx) => (
|
||||
<button
|
||||
@@ -91,7 +95,7 @@ export function SwordProfileSelect({
|
||||
<div className="text-sm font-medium text-ink-primary">
|
||||
{label}
|
||||
</div>
|
||||
<div className="whitespace-nowrap text-xs text-ink-tertiary">
|
||||
<div className="text-xs text-ink-tertiary sm:whitespace-nowrap">
|
||||
{desc}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Spinner } from "../ui/Spinner";
|
||||
* Primary action button on the dashboard. Swaps icon + colour scheme
|
||||
* depending on the sync lifecycle (idle → loading → success flash).
|
||||
*/
|
||||
export function SyncButton({ onClick, status = "idle" }) {
|
||||
export function SyncButton({ onClick, status = "idle", className = "" }) {
|
||||
const isLoading = status === "loading";
|
||||
const isSuccess = status === "success";
|
||||
|
||||
@@ -20,7 +20,7 @@ export function SyncButton({ onClick, status = "idle" }) {
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
disabled={isLoading}
|
||||
className={`inline-flex items-center gap-2 rounded-lg px-[18px] py-2.5 text-sm font-medium transition-colors disabled:cursor-not-allowed ${palette}`}
|
||||
className={`inline-flex items-center justify-center gap-2 rounded-lg px-[18px] py-2.5 text-sm font-medium transition-colors disabled:cursor-not-allowed ${palette} ${className}`.trim()}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Spinner size={15} />
|
||||
|
||||
Reference in New Issue
Block a user