Add non prod env favicons to improve visual indicator difference (#45871)

## Context

Use a different favicon (black logo on white bg) for dashboard staging
or local CLI
to improve visual differentiation against hosted dashboard (green logo
on black bg)

<img width="357" height="52" alt="image"
src="https://github.com/user-attachments/assets/b5c88a6e-0ab3-40ce-9c85-fddd8d6ce92b"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Favicon routing now switches automatically to staging icons when
running in non-production or CLI-release contexts so the UI reflects the
environment.

* **Chores**
* Added staging favicon assets, a browserconfig, and a staging web app
manifest to support environment-specific branding.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45871)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Joshen Lim authored and GitHub committed 2026-05-15 16:51:57 +08:00
1 parent 88c43b31b9
commit fdeaaec098
32 files changed
+73 -4

No files matched your search

+22 -4
View File
@@ -1,10 +1,9 @@
import 'react-data-grid/lib/styles.css'
import '@/styles/code.css'
import '@/styles/editor.css'
import '@/styles/focus.css'
import '@/styles/globals.css'
import '@/styles/graphiql-base.css'
import '@/styles/grid.css'
import '@/styles/globals.css'
import '@/styles/markdown-preview.css'
import '@/styles/monaco.css'
import '@/styles/react-data-grid-logs.css'
@@ -12,6 +11,7 @@ import '@/styles/reactflow.css'
import '@/styles/storage.css'
import '@/styles/stripe.css'
import '@/styles/ui.css'
import 'react-data-grid/lib/styles.css'
import 'ui-patterns/ShimmeringLoader/index.css'
import { loader } from '@monaco-editor/react'
@@ -36,7 +36,7 @@ import { DevToolbar, DevToolbarProvider, DevToolbarTrigger, type ExtraTab } from
import dynamic from 'next/dynamic'
import Head from 'next/head'
import { NuqsAdapter } from 'nuqs/adapters/next/pages'
import { ErrorInfo, useCallback, type ComponentProps } from 'react'
import { ErrorInfo, useCallback, useEffect, useState, type ComponentProps } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import { TooltipProvider } from 'ui'
import { TimestampInfoProvider } from 'ui-patterns'
@@ -52,6 +52,7 @@ import { MainScrollContainerProvider } from '@/components/layouts/MainScrollCont
import { BannerStackProvider } from '@/components/ui/BannerStack/BannerStackProvider'
import { GlobalErrorBoundaryState } from '@/components/ui/ErrorBoundary/GlobalErrorBoundaryState'
import { GlobalShortcuts } from '@/components/ui/GlobalShortcuts/GlobalShortcuts'
import { getCLIReleaseVersion } from '@/data/misc/cli-release-version-query'
import { useRootQueryClient } from '@/data/query-client'
import { customFont, sourceCodePro } from '@/fonts'
import { useCustomContent } from '@/hooks/custom-content/useCustomContent'
@@ -124,6 +125,7 @@ loader.config({
function CustomApp({ Component, pageProps }: AppPropsWithLayout) {
const queryClient = useRootQueryClient()
const { appTitle } = useCustomContent(['app:title'])
const [isCLI, setIsCLI] = useState(false)
const getLayout = Component.getLayout ?? ((page) => page)
@@ -144,6 +146,9 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) {
const isTestEnv = process.env.NEXT_PUBLIC_NODE_ENV === 'test'
// [Joshen] Should target hosted staging, local dev, and local CLI only
const isNonProdEnv = (IS_PLATFORM && process.env.NEXT_PUBLIC_ENVIRONMENT !== 'prod') || isCLI
const cloudProvider = useDefaultProvider()
const getConfigCatFlags = useCallback(
@@ -154,6 +159,15 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) {
[cloudProvider]
)
const checkCliEnvironment = async () => {
const data = await getCLIReleaseVersion()
if (!!data.current) setIsCLI(true)
}
useEffect(() => {
if (!IS_PLATFORM) checkCliEnvironment()
}, [])
return (
<ErrorBoundary FallbackComponent={GlobalErrorBoundaryState} onError={errorBoundaryHandler}>
<QueryClientProvider client={queryClient}>
@@ -188,7 +202,11 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) {
/>
)}
</Head>
<MetaFaviconsPagesRouter applicationName="Supabase Studio" includeManifest />
<MetaFaviconsPagesRouter
includeManifest
applicationName="Supabase Studio"
route={isNonProdEnv ? '/favicon/staging' : '/favicon'}
/>
<TooltipProvider delayDuration={0}>
<RouteValidationWrapper>
<ThemeProvider>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/favicon/staging/ms-icon-70x70.png"/><square150x150logo src="/favicon/staging/ms-icon-150x150.png"/><square310x310logo src="/favicon/staging/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

@@ -0,0 +1,49 @@
{
"name": "Supabase Studio",
"short_name": "Supabase",
"description": "The Postgres Development Platform.",
"display_override": ["minimal-ui"],
"display": "standalone",
"theme_color": "#1C1C1C",
"background_color": "#1C1C1C",
"scope": "/",
"start_url": "/",
"icons": [
{
"src": "/favicon/staging/android-icon-36x36.png",
"sizes": "36x36",
"type": "image/png",
"density": "0.75"
},
{
"src": "/favicon/staging/android-icon-48x48.png",
"sizes": "48x48",
"type": "image/png",
"density": "1.0"
},
{
"src": "/favicon/staging/android-icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"density": "1.5"
},
{
"src": "/favicon/staging/android-icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"density": "2.0"
},
{
"src": "/favicon/staging/android-icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"density": "3.0"
},
{
"src": "/favicon/staging/android-icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"density": "4.0"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB