From 42b29f01079b878a4737d3d34aac5dc8cd17dbcc Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 26 Aug 2026 11:20:01 +0200 Subject: [PATCH] Support separate header logo images for light and dark themes (#36362) Server Pro/CE admins can set a custom header logo via OVERLEAF_HEADER_IMAGE_URL, but the same image is used for both the light and dark navbar themes. A logo with good contrast on one background can be hard to see on the other (e.g. a dark logo on the dark dashboard navbar). Add two optional env vars, OVERLEAF_HEADER_IMAGE_URL_LIGHT and OVERLEAF_HEADER_IMAGE_URL_DARK, each falling back to OVERLEAF_HEADER_IMAGE_URL when unset, so existing configurations are unaffected. The light/dark fallback is resolved server-side and exposed to the frontend as customLogo (light-effective) and customLogoDark (dark-effective); the two theme-aware navbars (project dashboard and library) pick between them using the existing overall-theme hook, so the logo tracks both the user's theme setting and live OS theme changes. Co-authored-by: Claude Opus 4.8 GitOrigin-RevId: 587a5679c650717cba6251e6d612146f434e8730 --- docker-compose.yml | 2 ++ server-ce/config/settings.js | 8 ++++++++ services/web/app/views/layout-react.pug | 3 ++- services/web/app/views/layout/navbar-marketing.pug | 7 ++++--- .../project-list/components/project-list-ds-nav.tsx | 5 +++++ .../js/shared/components/types/default-navbar-metadata.ts | 1 + 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5d50667085..628efa2ad0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -47,6 +47,8 @@ services: # OVERLEAF_SITE_URL: http://overleaf.example.com # OVERLEAF_NAV_TITLE: Overleaf Community Edition # OVERLEAF_HEADER_IMAGE_URL: http://example.com/mylogo.png + # OVERLEAF_HEADER_IMAGE_URL_LIGHT: http://example.com/mylogo-light.png + # OVERLEAF_HEADER_IMAGE_URL_DARK: http://example.com/mylogo-dark.png # OVERLEAF_ADMIN_EMAIL: support@it.com # OVERLEAF_LEFT_FOOTER: '[{"text": "Another page I want to link to can be found here"} ]' diff --git a/server-ce/config/settings.js b/server-ce/config/settings.js index 3ecb620a33..be2a6e3997 100644 --- a/server-ce/config/settings.js +++ b/server-ce/config/settings.js @@ -340,6 +340,14 @@ if (process.env.OVERLEAF_HEADER_IMAGE_URL != null) { settings.nav.custom_logo = process.env.OVERLEAF_HEADER_IMAGE_URL } +if (process.env.OVERLEAF_HEADER_IMAGE_URL_LIGHT != null) { + settings.nav.custom_logo_light = process.env.OVERLEAF_HEADER_IMAGE_URL_LIGHT +} + +if (process.env.OVERLEAF_HEADER_IMAGE_URL_DARK != null) { + settings.nav.custom_logo_dark = process.env.OVERLEAF_HEADER_IMAGE_URL_DARK +} + if (process.env.OVERLEAF_HEADER_EXTRAS != null) { try { settings.nav.header_extras = JSON.parse(process.env.OVERLEAF_HEADER_EXTRAS) diff --git a/services/web/app/views/layout-react.pug b/services/web/app/views/layout-react.pug index 6054e6cb39..45accda5b1 100644 --- a/services/web/app/views/layout-react.pug +++ b/services/web/app/views/layout-react.pug @@ -22,7 +22,8 @@ block append meta name='ol-navbar' data-type='json' content={ - customLogo: settings.nav.custom_logo, + customLogo: settings.nav.custom_logo_light || settings.nav.custom_logo, + customLogoDark: settings.nav.custom_logo_dark || settings.nav.custom_logo, title: nav.title, canDisplayAdminMenu, canDisplayAdminRedirect, diff --git a/services/web/app/views/layout/navbar-marketing.pug b/services/web/app/views/layout/navbar-marketing.pug index 3f532047ef..a3b94c7c14 100644 --- a/services/web/app/views/layout/navbar-marketing.pug +++ b/services/web/app/views/layout/navbar-marketing.pug @@ -9,12 +9,13 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg( ) .container-fluid.navbar-container .navbar-header + - var customLogo = settings.nav.custom_logo_light || settings.nav.custom_logo a.navbar-brand(href='/' aria-label=settings.appName) - if settings.nav.custom_logo - .navbar-logo(style=`background-image:url("${settings.nav.custom_logo}")`) + if customLogo + .navbar-logo(style=`background-image:url("${customLogo}")`) if nav.title .navbar-title #{nav.title} - if !nav.title && !settings.nav.custom_logo + if !nav.title && !customLogo .navbar-logo - var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on') diff --git a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx index 0698408269..2680d96e3b 100644 --- a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx +++ b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx @@ -78,6 +78,11 @@ export function ProjectListDsNav() {