diff --git a/frontend/src/components/dashboard/ExportDropdown.jsx b/frontend/src/components/dashboard/ExportDropdown.jsx index d9a5c23..88e38d8 100644 --- a/frontend/src/components/dashboard/ExportDropdown.jsx +++ b/frontend/src/components/dashboard/ExportDropdown.jsx @@ -49,19 +49,20 @@ export function ExportDropdown({ } return ( -
+
-
+
-
+
@@ -303,49 +304,80 @@ export function PublicationsTable({ {filtersOpen && (
-
- - ({ - value: String(y), - label: String(y), - }))} - /> +
+

+ Filtrar por año de publicación +

+ {yearFilterSummary && ( + + {yearFilterSummary} + + )}
-
- - ({ - value: String(y), - label: String(y), - }))} - /> + +
+
+ + ({ + value: String(y), + label: String(y), + }))} + className="w-full" + /> +
+ +
+ — +
+ +
+ + ({ + value: String(y), + label: String(y), + }))} + className="w-full" + /> +
+ + {hasYearFilter && ( + + )}
+ {hasYearFilter && ( @@ -366,123 +398,217 @@ export function PublicationsTable({ ) : loading ? ( ) : ( - - - - - {COLUMNS.map((col) => ( - - ))} - - - + <> +
{filtered.length === 0 ? ( -
- - +

+ No se encontraron publicaciones con los filtros aplicados. +

) : ( - pageRows.map((pub, i) => { - const isSelected = selectedIds.has(pub.id); - return ( - +
+ +
+
+ {pageRows.map((pub, i) => { + const isSelected = selectedIds.has(pub.id); + return ( +
+
+ toggleRow(pub.id)} + ariaLabel={`Seleccionar publicación ${pub.title}`} + /> +
+
+ {isAuthenticated && pub.downloaded_by_me === false && ( + + + Nuevo + + )} +

+ {pub.title} +

+
+
+
+
+

+ Revista:{" "} + {pub.journal || "—"} +

+

+ Año:{" "} + {pub.publication_year ?? "—"} +

+

+ DOI:{" "} + {pub.doi ? ( + + {pub.doi} + + ) : ( + + — + + )} +

+
+ +
+
+
+ ); + })} +
+ + )} + + +
e.stopPropagation()} - > - - toggleSort(col.key)} - className={`select-none border-b border-surface-border/60 px-4 py-2.5 text-left text-xs font-medium tracking-wide text-ink-secondary${col.thClass ? ` ${col.thClass}` : ""}`} - > - - {col.label.toUpperCase()} - - -
- No se encontraron publicaciones con los filtros aplicados. -
+ + + + {COLUMNS.map((col) => ( + - + + + {filtered.length === 0 ? ( + + + + ) : ( + pageRows.map((pub, i) => { + const isSelected = selectedIds.has(pub.id); + return ( + + + + + + - - - - - - ); - }) - )} - -
e.stopPropagation()} + > + + toggleSort(col.key)} + className={`select-none border-b border-surface-border/60 px-4 py-2.5 text-left text-xs font-medium tracking-wide text-ink-secondary${col.thClass ? ` ${col.thClass}` : ""}`} > - { - e.stopPropagation(); - toggleRow(pub.id); - }} - > - toggleRow(pub.id)} - ariaLabel={`Seleccionar publicación ${pub.title}`} + + {col.label.toUpperCase()} + - - - {isAuthenticated && pub.downloaded_by_me === false && ( - + + ))} +
+ No se encontraron publicaciones con los filtros aplicados. +
{ + e.stopPropagation(); + toggleRow(pub.id); + }} + > + toggleRow(pub.id)} + ariaLabel={`Seleccionar publicación ${pub.title}`} + /> + + + {isAuthenticated && pub.downloaded_by_me === false && ( + + + Nuevo + + )} + {pub.title} + + + {pub.journal || "—"} + + {pub.publication_year ?? "—"} + + {pub.doi ? ( + e.stopPropagation()} + className="whitespace-nowrap font-mono text-xs text-brand-accent hover:underline" > - - Nuevo + {pub.doi} + + ) : ( + + — )} - {pub.title} - - - {pub.journal || "—"} - - {pub.publication_year ?? "—"} - - {pub.doi ? ( - e.stopPropagation()} - className="whitespace-nowrap font-mono text-xs text-brand-accent hover:underline" - > - {pub.doi} - - ) : ( - - — - - )} - - -
+ + + + + + ); + }) + )} + + + )}
diff --git a/frontend/src/components/dashboard/ResearcherCard.jsx b/frontend/src/components/dashboard/ResearcherCard.jsx index c869fbf..88c0025 100644 --- a/frontend/src/components/dashboard/ResearcherCard.jsx +++ b/frontend/src/components/dashboard/ResearcherCard.jsx @@ -44,7 +44,7 @@ export function ResearcherCard({ researcher, actions = null }) {
{actions && ( -
+
{actions}
)} diff --git a/frontend/src/components/dashboard/SwordProfileSelect.jsx b/frontend/src/components/dashboard/SwordProfileSelect.jsx index 77c7fc1..2d9f651 100644 --- a/frontend/src/components/dashboard/SwordProfileSelect.jsx +++ b/frontend/src/components/dashboard/SwordProfileSelect.jsx @@ -48,28 +48,32 @@ export function SwordProfileSelect({ return (
- Destino: -
+ + Destino: + +
{open && (
{options.map(({ value: optionValue, label, desc }, idx) => (
-
+
{desc}
diff --git a/frontend/src/components/dashboard/SyncButton.jsx b/frontend/src/components/dashboard/SyncButton.jsx index 70a6469..bca8420 100644 --- a/frontend/src/components/dashboard/SyncButton.jsx +++ b/frontend/src/components/dashboard/SyncButton.jsx @@ -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 ? ( diff --git a/frontend/src/components/layout/Footer.jsx b/frontend/src/components/layout/Footer.jsx index eb9b709..04d29aa 100644 --- a/frontend/src/components/layout/Footer.jsx +++ b/frontend/src/components/layout/Footer.jsx @@ -6,11 +6,11 @@ export default function Footer() {
{/* Main row */} -
+
{/* Brand */} -
-
+
+
ORCID2SWORD @@ -19,16 +19,16 @@ export default function Footer() {

- Sincronización de publicaciones ORCID al repositorio institucional. + Extracción y preparación de publicaciones ORCID para repositorios académicos.

{/* Compatible con */}
- + Compatible con -
+
{technologies.map((tech) => ( {/* Institutional links */} -
+
{/* Universidad de Jaén */}
@@ -65,7 +65,7 @@ export default function Footer() {
diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx index bedf4dd..b0c60a4 100644 --- a/frontend/src/pages/DashboardPage.jsx +++ b/frontend/src/pages/DashboardPage.jsx @@ -224,7 +224,11 @@ export function DashboardPage() { researcher={researcher} actions={ <> - + 0 - ? `Descargar lo nuevo de todos (${allNewIds.length})` - : "Todo descargado" - : `Descargar todo (${allIds.length})`; - - const globalDisabled = - Boolean(globalExporting) || - (isAuthenticated ? allNewIds.length === 0 : allIds.length === 0); - return (
+ + + Volver al inicio + + {/* Page header */}
@@ -233,33 +247,15 @@ export function GroupResultsPage() { {/* Global export buttons */} {!loading && results.length > 0 && ( -
- - {["xml", "zip"].map((fmt) => ( - - ))} -
+ )}
@@ -294,7 +290,6 @@ export function GroupResultsPage() { swordProfile, ) } - swordProfile={swordProfile} /> ))}
@@ -355,7 +350,6 @@ function ResearcherResultCard({ isAuthenticated, exporting, onExport, - swordProfile, }) { const researcher = bundle.researcher ?? {}; const publications = bundle.publications ?? []; diff --git a/frontend/src/pages/LandingPage.jsx b/frontend/src/pages/LandingPage.jsx index 8a9ce27..f26d92f 100644 --- a/frontend/src/pages/LandingPage.jsx +++ b/frontend/src/pages/LandingPage.jsx @@ -221,7 +221,7 @@ export function LandingPage() { Tus publicaciones, listas para depositar.

- Conecta tu ORCID y descárgalas en XML cuando quieras. + Conecta tu ORCID y descárgalas cuando quieras.