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 c11f654302..e132d6964f 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
@@ -41,6 +41,7 @@ import FormatCell from './table/cells/format-cell'
import OwnerCell from './table/cells/owner-cell'
import LastUpdatedCell from './table/cells/last-updated-cell'
import ActionsCell from './table/cells/actions-cell'
+import ActionsDropdown from './dropdown/actions-dropdown'
import InlineTags from './table/cells/inline-tags'
import WelcomePageContent from './welcome-page-content'
@@ -68,6 +69,12 @@ const ZOOM_OPTIONS: { value: ZoomLevel; label: string }[] = [
{ value: 1.35, label: 'M' },
{ value: 1.75, label: 'L' },
]
+// Mobile offers 3 sizes: XS (rows), M (2 tiles), L (1 tile)
+const MOBILE_ZOOM_OPTIONS: { value: ZoomLevel; label: string }[] = [
+ { value: 0, label: 'XS' },
+ { value: 1, label: 'M' },
+ { value: 1.35, label: 'L' },
+]
const ZOOM_STORAGE_KEY = 'lumiere-card-scale'
function useLumiereCardScale(): [ZoomLevel, (z: ZoomLevel) => void] {
@@ -245,7 +252,13 @@ const ProjectCardCompact = memo(function ProjectCardCompact({
-
+ {/* ⋮ dropdown on mobile (single button), icon strip on desktop */}
+
+
)
@@ -271,8 +284,14 @@ export function ProjectListLumiere() {
selectFilter,
} = useProjectListContext()
- // On mobile, always use the compact (XS) row view — cards overflow on small screens
- const effectiveScale = isMobile ? 0 : cardScale
+ // On mobile: M option (scale=1) → 2 tiles/row; L (scale≥1.35) → 1 tile/row.
+ // CSS overrides the card grid columns on mobile; we only add a class for L.
+ const mobileIsL = isMobile && cardScale !== 0 && cardScale >= 1.35
+ const activeMobileZoom = cardScale === 0
+ ? 0
+ : cardScale >= 1.35
+ ? 1.35
+ : 1
const selectedTag = tags.find(tag => tag._id === selectedTagId)
const allSelected =
@@ -351,19 +370,42 @@ export function ProjectListLumiere() {
))}
- {/* Mobile-only filter pills replacing the hidden sidebar */}
-
- {MOBILE_FILTERS.map(({ f, label }) => (
-
- ))}
+ {/* Mobile-only: filter pills + zoom control */}
+
+
+ {MOBILE_FILTERS.map(({ f, label }) => (
+
+ ))}
+
+
+ {MOBILE_ZOOM_OPTIONS.map(({ value, label }) => (
+
+ ))}
+
{t('no_projects')}
) : (
{visibleProjects.map(project =>
- effectiveScale === 0 ? (
+ cardScale === 0 ? (
) : (
diff --git a/services/web/frontend/stylesheets/pages/project-list-lumiere.scss b/services/web/frontend/stylesheets/pages/project-list-lumiere.scss
index 356c03c0fe..7fc0640d99 100644
--- a/services/web/frontend/stylesheets/pages/project-list-lumiere.scss
+++ b/services/web/frontend/stylesheets/pages/project-list-lumiere.scss
@@ -870,12 +870,15 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi
opacity: 1;
}
- // ── Mobile compact row — 2-line layout ────────────────────────────────────
- // On small screens the 6-column grid overflows. Switch to:
- // Row 1: [checkbox] [name+tags] [actions]
- // Row 2: [checkbox] [format · owner · date]
+ // ── Mobile layout overrides ────────────────────────────────────────────────
@media (max-width: 767px) {
+
+ // Compact row: 2-line layout
+ // Row 1: [checkbox] [name+tags] [⋮ action]
+ // Row 2: [checkbox] [format · owner · date]
+ // ActionsDropdown (single ⋮ button) is shown via d-md-none; ActionsCell
+ // (many icon buttons) is hidden on mobile, so the auto column stays tiny.
.lumiere-compact-row {
grid-template-columns: 28px 1fr auto;
grid-template-rows: auto auto;
@@ -896,6 +899,9 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi
grid-column: 3;
grid-row: 1;
align-self: center;
+ opacity: 1;
+
+ .action-btn { opacity: 1; }
}
// Meta wrapper becomes a flex row spanning the second line
@@ -907,30 +913,49 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi
grid-column: 2 / 4;
grid-row: 2;
}
+ }
- // Actions always visible — no hover on touch devices
- @media (hover: none) {
- .lumiere-compact-actions .action-btn {
- opacity: 1;
- }
+ // Card tile grid: M = 2 tiles/row, L = 1 tile/row.
+ // --lum-card-scale inline var is suppressed on mobile (isMobile=true in JS),
+ // so the CSS custom property here wins for thumbnail sizing.
+ .lumiere-card-grid:not(.lumiere-card-grid--compact) {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 0.75rem;
+ --lum-card-scale: 0.85;
+
+ &.lumiere-card-grid--mobile-1col {
+ grid-template-columns: 1fr;
+ --lum-card-scale: 1.3;
}
}
}
- // ── Mobile filter pills (replaces hidden sidebar on xs/sm) ────────────────
+ // ── Mobile toolbar: filter pills + zoom control ───────────────────────────
+
+ .lumiere-mobile-toolbar {
+ align-items: center;
+ gap: 0.5rem;
+ width: 100%;
+ padding: 0.25rem 0 0.5rem;
+ flex-shrink: 0;
+ }
.lumiere-mobile-filters {
overflow-x: auto;
+ display: flex;
gap: 0.45rem;
- padding: 0.25rem 0 0.5rem;
+ flex: 1;
+ min-width: 0;
scrollbar-width: none;
-ms-overflow-style: none;
- flex-shrink: 0;
- width: 100%;
&::-webkit-scrollbar { display: none; }
}
+ .lumiere-mobile-zoom {
+ flex-shrink: 0;
+ }
+
.lumiere-mobile-filter-pill {
flex-shrink: 0;
padding: 0.3rem 0.8rem;