From 464aee7612447ae34502942d2adcdb24692552a8 Mon Sep 17 00:00:00 2001 From: claude Date: Fri, 12 Jun 2026 08:17:45 +0000 Subject: [PATCH] =?UTF-8?q?Add=20per-card=20action=20buttons=20to=20Lumi?= =?UTF-8?q?=C3=A8re=20project=20grid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructures ProjectCard so the card is a
container instead of (buttons cannot be nested inside anchor elements). A .lumiere-card-link anchor wraps the thumb+body area; a .lumiere-card-actions strip sits below it and fades in on hover. Buttons added (reusing the same tooltip components as the classic table): - Copy project (opens CloneProjectModal) - Download project zip - Compile & download PDF - Archive project (skipped when already archived) - Trash project (skipped when already trashed) Action icons are coloured $lum-text-muted at rest and shift to $lum-teal on hover, matching the Lumière palette. Co-Authored-By: Claude Sonnet 4.6 --- .../components/project-list-lumiere.tsx | 60 ++++++++++++------- .../pages/project-list-lumiere.scss | 47 ++++++++++++++- 2 files changed, 81 insertions(+), 26 deletions(-) diff --git a/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx b/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx index ccd47ceb81..60dcc66ecd 100644 --- a/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx +++ b/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx @@ -20,6 +20,11 @@ import DashApiError from './dash-api-error' import { ProjectCheckbox } from './table/project-checkbox' import ProjectTools from './table/project-tools/project-tools' import OLFormCheckbox from '@/shared/components/ol/ol-form-checkbox' +import { CopyProjectButtonTooltip } from './table/cells/action-buttons/copy-project-button' +import { DownloadProjectButtonTooltip } from './table/cells/action-buttons/download-project-button' +import { CompileAndDownloadProjectPDFButtonTooltip } from './table/cells/action-buttons/compile-and-download-project-pdf-button' +import { ArchiveProjectButtonTooltip } from './table/cells/action-buttons/archive-project-button' +import { TrashProjectButtonTooltip } from './table/cells/action-buttons/trash-project-button' type FormatVariant = 'latex' | 'typst' | 'quarto' | 'quarto-slides' @@ -62,31 +67,40 @@ const ProjectCard = memo(function ProjectCard({
-
-
- {initial} -
-
- {project.name} -
- - {getFormatLabel(variant)} - - {ownerName && ( - - {ownerName} - - )} +
+ +
+ {initial}
- {date} +
+ {project.name} +
+ + {getFormatLabel(variant)} + + {ownerName && ( + + {ownerName} + + )} +
+ {date} +
+
+
+ + + + +
- +
) }) diff --git a/services/web/frontend/stylesheets/pages/project-list-lumiere.scss b/services/web/frontend/stylesheets/pages/project-list-lumiere.scss index a9b1187a2b..d99750ac5c 100644 --- a/services/web/frontend/stylesheets/pages/project-list-lumiere.scss +++ b/services/web/frontend/stylesheets/pages/project-list-lumiere.scss @@ -450,10 +450,10 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi // ── Individual card ─────────────────────────────────────────────────────── + // Card container is now a
; the clickable area is .lumiere-card-link .lumiere-card { display: flex; flex-direction: column; - text-decoration: none; border-radius: 10px; background: rgba(255, 255, 255, 0.82); backdrop-filter: blur(8px); @@ -462,17 +462,58 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi box-shadow: 0 2px 8px rgba(0, 0, 0, 0.07); transition: transform 0.18s ease, box-shadow 0.18s ease; overflow: hidden; + + &:hover, + &:focus-within { + transform: translateY(-3px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); + } + } + + // The anchor covers thumb + body, with no underline or color bleed + .lumiere-card-link { + display: flex; + flex-direction: column; + flex: 1; + text-decoration: none; color: inherit; &:hover, &:focus-visible { - transform: translateY(-3px); - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); text-decoration: none; color: inherit; } } + // Action strip — icon buttons that fade in when the card is hovered + .lumiere-card-actions { + display: flex; + align-items: center; + justify-content: center; + gap: 2px; + padding: 3px 6px 5px; + border-top: 1px solid rgba($lum-teal, 0.10); + opacity: 0; + transition: opacity 0.15s ease; + + // Recolour OLIconButton's action-btn class for the Lumière palette + .action-btn { + color: $lum-text-muted !important; + border-radius: 6px !important; + + &:hover, + &:focus { + color: $lum-teal !important; + background: rgba($lum-teal, 0.09) !important; + } + } + } + + .lumiere-card:hover .lumiere-card-actions, + .lumiere-card:focus-within .lumiere-card-actions { + opacity: 1; + } + // ── Card thumbnail ──────────────────────────────────────────────────────── .lumiere-card-thumb {