Files
supabase/apps/www/next.config.test.ts
Danny White 2e7a8a3362 chore(www): rename customer logo folders to on-dark and on-light (#48962)
## What kind of change does this PR introduce?

Chore: rename customer logo folders and document the theme contract. No
intended visual change, aside from Phoenix Energy whose two marks were
in the wrong folders.

## What is the current behavior?

Customer logos live at:

- `/images/customers/logos/{slug}.png` (`logo`, light mode)
- `/images/customers/logos/light/{slug}.png` (`logo_inverse`, dark mode)

`light/` actually means “use me on a dark background”.

## What is the new behavior?

Same assets, clearer paths:

- `/images/customers/logos/on-light/{slug}.png` → dark/black mark →
`logo` → light mode
- `/images/customers/logos/on-dark/{slug}.png` → light/white mark →
`logo_inverse` → dark mode

Icon chips stay at `/images/customers/logos/{slug}-icon.svg`. Old
`/images/customers/logos/light/*` URLs redirect to `on-dark`. www README
now has the contract.

# To test

Use the [www
preview](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app).
Toggle light/dark from the site header on each page. Logos should stay
readable (no white-on-white or black-on-black).

1. [Customers
grid](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/customers)
— main `logo` / `logo_inverse` surface. Spot-check Juniver, Phoenix
Energy, and one other card.
2. [Phoenix Energy
story](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/customers/phoenix-energy)
— story header uses `logo` only (on-light, plus a dark-mode brightness
filter). We swapped this pair.
3.
[Homepage](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/)
— “How industry leaders…” section. Icon chips only (`*-icon.svg`); the
wordmark `logo` field is unused here.
4. [Solutions /
Agents](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/solutions/agents)
— Chatbase quote near the top shows both theme variants. Same pattern on
[/healthcare](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/solutions/healthcare),
[/finserv](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/solutions/finserv),
and
[/b2b-saas](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/solutions/b2b-saas).
5. [Contact
sales](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/contact/sales)
— Good Tape / Xendit / Chatbase wordmarks (`on-light`). Same logos on
the demo form at
[/solutions/enterprise](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/solutions/enterprise).
6.
[Enterprise](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/solutions/enterprise)
— Mozilla / Epsilon3 / Pebblely icons in the use-cases section
(`on-dark`).
7.
[Vector](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/modules/vector)
— customer quotes. This is the only page that builds `on-light` /
`on-dark` paths at runtime from the customer slug.
8. [Mobbin
event](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/events/migrating-from-firebase-mobbin)
— company logo uses event `logo` / `logo_light` (dark vs light).
Optional second:
[/events/scale-to-millions-goodtape-auth](https://zone-www-dot-com-git-dnywh-chorecustomer-logo-o-0d7bc1-supabase.vercel.app/events/scale-to-millions-goodtape-auth).

Quick extra: hover **Product** in the site nav. The customer story
thumbnail uses `imgUrl` (`on-light`).

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

## Documentation
- Clarified customer logo requirements, including separate light and
dark asset locations, monochrome formats, and dark PNG assets for image
generation.

## Updates
- Standardized customer logos across stories, events, sales pages,
solution pages, testimonials, and generated images.
- Improved logo rendering across light and dark themes with dedicated
variants.
- Added permanent redirects for legacy logo URLs while preserving
filename suffixes.

## Tests
- Added coverage verifying legacy logo redirects resolve correctly,
including supported exceptions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-12 03:49:21 +00:00

94 lines
3.5 KiB
TypeScript

import type { NextConfig } from 'next'
import { getPathMatch } from 'next/dist/shared/lib/router/utils/path-match'
import { describe, expect, it, vi } from 'vitest'
vi.mock('@sentry/nextjs', () => ({
withSentryConfig: (configFn: any) => (typeof configFn === 'function' ? configFn() : configFn),
}))
describe('next.config.mjs', () => {
it('expect the headers to always have X-Robots-Tag', async () => {
const { default: config } = (await import('./next.config.mjs')) as { default: NextConfig }
const headers = (await config.headers?.()) || []
expect(headers).toEqual(
expect.arrayContaining([
expect.objectContaining({
source: '/(docs|blog)/:path*',
headers: [{ key: 'X-Robots-Tag', value: 'all' }],
}),
expect.objectContaining({
source: '/dashboard/:path*',
headers: [{ key: 'X-Robots-Tag', value: 'noindex' }],
}),
])
)
})
it('routes the library and permanently redirects the legacy UI URLs', async () => {
const { default: config } = (await import('./next.config.mjs')) as { default: NextConfig }
const rewrites = (await config.rewrites?.()) || []
const redirects = (await config.redirects?.()) || []
expect(rewrites).toEqual(
expect.arrayContaining([
expect.objectContaining({ source: '/library' }),
expect.objectContaining({ source: '/library/:path*' }),
])
)
expect(redirects).toEqual(
expect.arrayContaining([
expect.objectContaining({
source: '/images/customers/logos/light/:path*',
destination: '/images/customers/logos/on-dark/:path*',
permanent: true,
}),
expect.objectContaining({
source: '/images/customers/logos/:slug((?!dreambase-mark\\.png)[^/.]+).png',
destination: '/images/customers/logos/on-light/:slug.png',
permanent: true,
}),
expect.objectContaining({ source: '/ui', destination: '/library', permanent: true }),
expect.objectContaining({
source: '/ui/:path*',
destination: '/library/:path*',
permanent: true,
}),
])
)
expect(
redirects.findIndex((redirect) => redirect.source === '/ui/docs/ai-editors-rules/prompts')
).toBeLessThan(redirects.findIndex((redirect) => redirect.source === '/ui/:path*'))
})
it('preserves the filename when redirecting legacy customer logos', async () => {
const { default: config } = (await import('./next.config.mjs')) as { default: NextConfig }
const redirects = (await config.redirects?.()) || []
const darkModeRedirect = redirects.find(
(redirect) => redirect.source === '/images/customers/logos/light/:path*'
)
const lightModeRedirect = redirects.find(
(redirect) =>
redirect.source === '/images/customers/logos/:slug((?!dreambase-mark\\.png)[^/.]+).png'
)
expect(darkModeRedirect).toBeDefined()
expect(lightModeRedirect).toBeDefined()
const matchLegacyDark = getPathMatch(darkModeRedirect!.source)
const matchLegacyLight = getPathMatch(lightModeRedirect!.source)
expect(matchLegacyDark('/images/customers/logos/light/good-tape.png')).toEqual({
path: ['good-tape.png'],
})
expect(matchLegacyLight('/images/customers/logos/good-tape.png')).toEqual({
slug: 'good-tape',
})
expect(matchLegacyLight('/images/customers/logos/dreambase-mark.png')).toBe(false)
expect(matchLegacyLight('/images/customers/logos/dreambase-marketing.png')).toEqual({
slug: 'dreambase-marketing',
})
})
})