From b8d5cb9816c88b9f1fd2422b21172c95a1a0e535 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Jun 2026 16:33:23 +0000 Subject: [PATCH] fix: XS badge column, lumiere on welcome and 404 pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - XS compact row: format column 70px→96px so "QUARTO SLIDES" stays on one line; trim owner/date cols slightly to compensate - Welcome page (0 projects): Lumière branch now renders before the 0-projects check; ProjectListLumiere renders WelcomePageContent when totalProjectsCount=0 so new users get the full onboarding experience in the Lumière shell - 404 page: notFound() now detects the user's overallTheme and passes isLumiere to the template; layout-base.pug sets data-lumiere on the body; error-pages.scss and project-list-lumiere.scss add [data-lumiere='true'] rules for the body background gradient, navbar white+stripe, and styled error box Co-Authored-By: Claude Sonnet 4.6 --- .../src/Features/Errors/ErrorController.mjs | 16 +++++++-- services/web/app/views/layout-base.pug | 1 + .../components/project-list-lumiere.tsx | 6 +++- .../components/project-list-root.tsx | 16 ++++----- .../stylesheets/pages/error-pages.scss | 36 +++++++++++++++++++ .../pages/project-list-lumiere.scss | 32 ++++++++++++++++- 6 files changed, 95 insertions(+), 12 deletions(-) diff --git a/services/web/app/src/Features/Errors/ErrorController.mjs b/services/web/app/src/Features/Errors/ErrorController.mjs index 810c44ef1c..a03963d074 100644 --- a/services/web/app/src/Features/Errors/ErrorController.mjs +++ b/services/web/app/src/Features/Errors/ErrorController.mjs @@ -5,14 +5,26 @@ import { } from '@overleaf/validation-tools' import Errors, { NotFoundError } from './Errors.js' import SessionManager from '../Authentication/SessionManager.mjs' +import UserGetter from '../User/UserGetter.mjs' import SamlLogHandler from '../SamlLog/SamlLogHandler.mjs' import HttpErrorHandler from './HttpErrorHandler.mjs' import { plainTextResponse } from '../../infrastructure/Response.mjs' import { expressifyErrorHandler } from '@overleaf/promise-utils' -function notFound(req, res) { +async function notFound(req, res) { res.status(404) - res.render('general/404', { title: 'page_not_found' }) + const sessionUser = SessionManager.getSessionUser(req.session) + let isLumiere = false + if (sessionUser?._id) { + try { + const user = await UserGetter.promises.getUser(sessionUser._id, { + 'ace.overallTheme': 1, + signUpDate: 1, + }) + isLumiere = (user?.ace?.overallTheme ?? '') === 'lumiere-' + } catch {} + } + res.render('general/404', { title: 'page_not_found', isLumiere }) } function forbidden(req, res) { diff --git a/services/web/app/views/layout-base.pug b/services/web/app/views/layout-base.pug index 8691b39969..1556a93b9e 100644 --- a/services/web/app/views/layout-base.pug +++ b/services/web/app/views/layout-base.pug @@ -106,6 +106,7 @@ html( 'red-nav-bar-for-admins': !settings.isDevEnv && hasFeature('saas') && hasAdminAccess(), } data-theme='light' + data-lumiere=isLumiere ? 'true' : 'false' ) if settings.recaptcha && settings.recaptcha.siteKeyV3 script( 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 3f77935149..33e656c9fd 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 @@ -32,6 +32,7 @@ import OwnerCell from './table/cells/owner-cell' import LastUpdatedCell from './table/cells/last-updated-cell' import ActionsCell from './table/cells/actions-cell' import InlineTags from './table/cells/inline-tags' +import WelcomePageContent from './welcome-page-content' // ── Tile zoom ───────────────────────────────────────────────────────────────── @@ -227,6 +228,7 @@ export function ProjectListLumiere() { const { error, visibleProjects, + totalProjectsCount, searchText, setSearchText, filter, @@ -344,7 +346,9 @@ export function ProjectListLumiere() { )} - {visibleProjects.length === 0 ? ( + {totalProjectsCount === 0 ? ( + + ) : visibleProjects.length === 0 ? (

{t('no_projects')}

) : (
+ + + ) + } + if (totalProjectsCount === 0) { return ( <> @@ -111,14 +119,6 @@ function ProjectListPageContent() { ) } - if (overallTheme === 'lumiere-') { - return ( - - - - ) - } - return ( diff --git a/services/web/frontend/stylesheets/pages/error-pages.scss b/services/web/frontend/stylesheets/pages/error-pages.scss index ac21364f9d..76f93c6868 100644 --- a/services/web/frontend/stylesheets/pages/error-pages.scss +++ b/services/web/frontend/stylesheets/pages/error-pages.scss @@ -1,3 +1,39 @@ +// Lumière-themed overrides for 404 / error pages. +// $lum-* vars are declared in project-list-lumiere.scss which is imported +// earlier in all.scss, so they are available here. +[data-lumiere='true'] { + .error-container { + min-height: 60vh; + justify-content: center; + } + + .error-details { + background: rgba(255, 255, 255, 0.88); + border-radius: 16px; + padding: 3rem; + box-shadow: 0 4px 24px rgba(42, 157, 143, 0.12); + } + + .error-status { + color: #2a9d8f; + } + + .error-description { + color: #64748b; + } + + .error-btn { + background: #2a9d8f !important; + border-color: #2a9d8f !important; + border-radius: 8px; + + &:hover { + background: #21867a !important; + border-color: #21867a !important; + } + } +} + .error-container { display: flex; align-items: center; diff --git a/services/web/frontend/stylesheets/pages/project-list-lumiere.scss b/services/web/frontend/stylesheets/pages/project-list-lumiere.scss index 783752380c..7a07804b32 100644 --- a/services/web/frontend/stylesheets/pages/project-list-lumiere.scss +++ b/services/web/frontend/stylesheets/pages/project-list-lumiere.scss @@ -746,7 +746,7 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi .lumiere-compact-row { display: grid; // checkbox | name+tags | format | owner | date | actions - grid-template-columns: 28px 1fr 70px 130px 160px auto; + grid-template-columns: 28px 1fr 96px 120px 150px auto; align-items: center; column-gap: 0.85rem; padding: 0.45rem 0.75rem; @@ -987,3 +987,33 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi --link-hover-color: #{$lum-teal}; --link-visited-color: #64748b; } + +// ── Global Lumière rules (apply to every page when data-lumiere is set) ──── +// These cover pages that don't carry .project-list-lumiere (404, welcome). + +[data-lumiere='true'] { + background: linear-gradient(160deg, #f0faf8 0%, #e4f4f1 50%, #daeef5 100%); + min-height: 100vh; + + // Shared white navbar with teal accent stripe (marketing pages + welcome) + .navbar-default { + background-color: #ffffff !important; + border-bottom: none !important; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06), 0 2px 8px rgba(0, 0, 0, 0.04); + position: relative; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, $lum-teal 0%, $lum-blue 100%); + } + + .navbar-brand { color: $lum-text !important; } + .navbar-nav > li > a { color: $lum-text-sub !important; } + .navbar-nav > li > a:hover { color: $lum-teal !important; } + } +}