Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dev-overlay] control dark theme in one place #76528

Merged
merged 5 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,9 @@ export function ComponentStyles() {
)
}
```

### Dark Theme

The dev overlay implements a dark theme automatically by system preferences. Users can manually toggle between light and dark themes via the DevTools Indicator preferences panel.

To make changes to the dark theme, you can edit the [`ui/styles/dark-theme.tsx`](./ui/styles/dark-theme.tsx) file.
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ export const DIALOG_STYLES = `
box-shadow: var(--shadow-menu);
position: relative;

@media (prefers-color-scheme: dark) {
border-color: var(--color-gray-400);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

&:has(
~ [data-nextjs-error-overlay-nav] .error-overlay-notch[data-side='left']
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,4 @@ export const styles = `
}
}
}

@media (prefers-color-scheme: dark) {
.error-overlay-bottom-stack-layer {
border-color: var(--color-gray-400);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
}
`
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Colors } from './styles/colors'
import { ErrorOverlay } from './components/errors/error-overlay/error-overlay'
import { DevToolsIndicator } from './components/errors/dev-tools-indicator/dev-tools-indicator'
import { RenderError } from './container/runtime-error/render-error'
import { DarkTheme } from './styles/dark-theme'

export function DevOverlay({
state,
Expand All @@ -26,6 +27,7 @@ export function DevOverlay({
<Base />
<Colors />
<ComponentStyles />
<DarkTheme />

<RenderError state={state} isAppDir={true}>
{({ runtimeErrors, totalErrorCount }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { Colors } from '../styles/colors'
import { CssReset } from '../styles/css-reset'
import { ComponentStyles } from '../styles/component-styles'
import { ShadowPortal } from '../components/shadow-portal'
import { DarkTheme } from '../styles/dark-theme'

export const withShadowPortal = (Story: any) => (
<ShadowPortal>
<CssReset />
<Base />
<Colors />
<ComponentStyles />
<DarkTheme />
<Story />
</ShadowPortal>
)
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
import { css } from '../../utils/css'

const darkTheme = css`
--color-font: white;
--color-backdrop: rgba(0, 0, 0, 0.8);
--color-border-shadow: rgba(255, 255, 255, 0.145);

--color-title-color: #fafafa;
--color-stack-notes: #a9a9a9;
`

export function Base() {
return (
<style>
{css`
:host {
/*
Although the style applied to the shadow host is isolated,
the element that attached the shadow host (i.e. "nextjs-portal")
is still affected by the parent's style (e.g. "body"). This may
occur style conflicts like "display: flex", with other children
elements therefore give the shadow host an absolute position.
*/
* Although the style applied to the shadow host is isolated,
* the element that attached the shadow host (i.e. "nextjs-portal")
* is still affected by the parent's style (e.g. "body"). This may
* occur style conflicts like "display: flex", with other children
* elements therefore give the shadow host an absolute position.
*/
position: absolute;

--color-font: #757575;
Expand Down Expand Up @@ -123,16 +114,6 @@ export function Base() {
}
}

:host(.dark) {
${darkTheme}
}

@media (prefers-color-scheme: dark) {
:host(:not(.light)) {
${darkTheme}
}
}

h1,
h2,
h3,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,119 +1,20 @@
import { css } from '../../utils/css'

const darkTheme = css`
/* Background Dark */
--color-background-100: #0a0a0a;
--color-background-200: #000000;

/* Syntax Dark */
--color-syntax-comment: #a0a0a0;
--color-syntax-constant: #ededed;
--color-syntax-function: #52a9ff;
--color-syntax-keyword: #f76e99;
--color-syntax-link: #0ac5b2;
--color-syntax-parameter: #f1a10d;
--color-syntax-punctuation: #ededed;
--color-syntax-string: #0ac5b2;
--color-syntax-string-expression: #0ac5b2;

/* Gray Scale Dark */
--color-gray-100: #1a1a1a;
--color-gray-200: #1f1f1f;
--color-gray-300: #292929;
--color-gray-400: #2e2e2e;
--color-gray-500: #454545;
--color-gray-600: #878787;
--color-gray-700: #8f8f8f;
--color-gray-800: #7d7d7d;
--color-gray-900: #a0a0a0;
--color-gray-1000: #ededed;

/* Gray Alpha Scale Dark */
--color-gray-alpha-100: rgba(255, 255, 255, 0.066);
--color-gray-alpha-200: rgba(255, 255, 255, 0.087);
--color-gray-alpha-300: rgba(255, 255, 255, 0.125);
--color-gray-alpha-400: rgba(255, 255, 255, 0.145);
--color-gray-alpha-500: rgba(255, 255, 255, 0.239);
--color-gray-alpha-600: rgba(255, 255, 255, 0.506);
--color-gray-alpha-700: rgba(255, 255, 255, 0.54);
--color-gray-alpha-800: rgba(255, 255, 255, 0.47);
--color-gray-alpha-900: rgba(255, 255, 255, 0.61);
--color-gray-alpha-1000: rgba(255, 255, 255, 0.923);

/* Blue Scale Dark */
--color-blue-100: #0f1b2d;
--color-blue-200: #10243e;
--color-blue-300: #0f3058;
--color-blue-400: #0d3868;
--color-blue-500: #0a4481;
--color-blue-600: #0091ff;
--color-blue-700: #0070f3;
--color-blue-800: #0060d1;
--color-blue-900: #52a9ff;
--color-blue-1000: #eaf6ff;

/* Red Scale Dark */
--color-red-100: #2a1314;
--color-red-200: #3d1719;
--color-red-300: #551a1e;
--color-red-400: #671e22;
--color-red-500: #822025;
--color-red-600: #e5484d;
--color-red-700: #e5484d;
--color-red-800: #da3036;
--color-red-900: #ff6369;
--color-red-1000: #ffecee;

/* Amber Scale Dark */
--color-amber-100: #271700;
--color-amber-200: #341c00;
--color-amber-300: #4a2900;
--color-amber-400: #573300;
--color-amber-500: #693f05;
--color-amber-600: #e79c13;
--color-amber-700: #ffb224;
--color-amber-800: #ff990a;
--color-amber-900: #f1a10d;
--color-amber-1000: #fef3dd;

/* Green Scale Dark */
--color-green-100: #0b2211;
--color-green-200: #0f2c17;
--color-green-300: #11351b;
--color-green-400: #0c461b;
--color-green-500: #126427;
--color-green-600: #1a9338;
--color-green-700: #46a758;
--color-green-800: #388e4a;
--color-green-900: #63c174;
--color-green-1000: #e5fbeb;

/* Turbopack Dark - Temporary */
--color-turbopack-text-red: #ff6d92;
--color-turbopack-text-blue: #45b2ff;
--color-turbopack-border-red: #6e293b;
--color-turbopack-border-blue: #284f80;
--color-turbopack-background-red: #250d12;
--color-turbopack-background-blue: #0a1723;
`

// TODO: Replace the existing colors in Base.tsx.
export function Colors() {
return (
<style>
{css`
:host {
${
// CAUTION: THIS IS A WORKAROUND!
// For now, we use @babel/code-frame to parse the code frame which does not support option to change the color.
// x-ref: https://github.com/babel/babel/blob/efa52324ff835b794c48080f14877b6caf32cd15/packages/babel-code-frame/src/defs.ts#L40-L54
// So, we do a workaround mapping to change the color matching the theme.

// For example, in @babel/code-frame, the `keyword` is mapped to ANSI "cyan".
// We want the `keyword` to use the `syntax-keyword` color in the theme.
// So, we map the "cyan" to the `syntax-keyword` in the theme.
''
}
/*
* CAUTION: THIS IS A WORKAROUND!
* For now, we use @babel/code-frame to parse the code frame which does not support option to change the color.
* x-ref: https://github.com/babel/babel/blob/efa52324ff835b794c48080f14877b6caf32cd15/packages/babel-code-frame/src/defs.ts#L40-L54
* So, we do a workaround mapping to change the color matching the theme.
*
* For example, in @babel/code-frame, the "keyword" is mapped to ANSI "cyan".
* We want the "keyword" to use the "syntax-keyword" color in the theme.
* So, we map the "cyan" to the "syntax-keyword" in the theme.
*/
/* cyan: keyword */
--color-ansi-cyan: var(--color-syntax-keyword);
/* yellow: capitalized, jsxIdentifier, punctuation */
Expand Down Expand Up @@ -237,16 +138,6 @@ export function Colors() {
--color-turbopack-background-red: #fff7f9;
--color-turbopack-background-blue: #f6fbff;
}

:host(.dark) {
${darkTheme}
}

@media (prefers-color-scheme: dark) {
:host(:not(.light)) {
${darkTheme}
}
}
`}
</style>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { css } from '../../utils/css'

const colors = `
/* Background Dark */
--color-background-100: #0a0a0a;
--color-background-200: #000000;

/* Syntax Dark */
--color-syntax-comment: #a0a0a0;
--color-syntax-constant: #ededed;
--color-syntax-function: #52a9ff;
--color-syntax-keyword: #f76e99;
--color-syntax-link: #0ac5b2;
--color-syntax-parameter: #f1a10d;
--color-syntax-punctuation: #ededed;
--color-syntax-string: #0ac5b2;
--color-syntax-string-expression: #0ac5b2;

/* Gray Scale Dark */
--color-gray-100: #1a1a1a;
--color-gray-200: #1f1f1f;
--color-gray-300: #292929;
--color-gray-400: #2e2e2e;
--color-gray-500: #454545;
--color-gray-600: #878787;
--color-gray-700: #8f8f8f;
--color-gray-800: #7d7d7d;
--color-gray-900: #a0a0a0;
--color-gray-1000: #ededed;

/* Gray Alpha Scale Dark */
--color-gray-alpha-100: rgba(255, 255, 255, 0.066);
--color-gray-alpha-200: rgba(255, 255, 255, 0.087);
--color-gray-alpha-300: rgba(255, 255, 255, 0.125);
--color-gray-alpha-400: rgba(255, 255, 255, 0.145);
--color-gray-alpha-500: rgba(255, 255, 255, 0.239);
--color-gray-alpha-600: rgba(255, 255, 255, 0.506);
--color-gray-alpha-700: rgba(255, 255, 255, 0.54);
--color-gray-alpha-800: rgba(255, 255, 255, 0.47);
--color-gray-alpha-900: rgba(255, 255, 255, 0.61);
--color-gray-alpha-1000: rgba(255, 255, 255, 0.923);

/* Blue Scale Dark */
--color-blue-100: #0f1b2d;
--color-blue-200: #10243e;
--color-blue-300: #0f3058;
--color-blue-400: #0d3868;
--color-blue-500: #0a4481;
--color-blue-600: #0091ff;
--color-blue-700: #0070f3;
--color-blue-800: #0060d1;
--color-blue-900: #52a9ff;
--color-blue-1000: #eaf6ff;

/* Red Scale Dark */
--color-red-100: #2a1314;
--color-red-200: #3d1719;
--color-red-300: #551a1e;
--color-red-400: #671e22;
--color-red-500: #822025;
--color-red-600: #e5484d;
--color-red-700: #e5484d;
--color-red-800: #da3036;
--color-red-900: #ff6369;
--color-red-1000: #ffecee;

/* Amber Scale Dark */
--color-amber-100: #271700;
--color-amber-200: #341c00;
--color-amber-300: #4a2900;
--color-amber-400: #573300;
--color-amber-500: #693f05;
--color-amber-600: #e79c13;
--color-amber-700: #ffb224;
--color-amber-800: #ff990a;
--color-amber-900: #f1a10d;
--color-amber-1000: #fef3dd;

/* Green Scale Dark */
--color-green-100: #0b2211;
--color-green-200: #0f2c17;
--color-green-300: #11351b;
--color-green-400: #0c461b;
--color-green-500: #126427;
--color-green-600: #1a9338;
--color-green-700: #46a758;
--color-green-800: #388e4a;
--color-green-900: #63c174;
--color-green-1000: #e5fbeb;

/* Turbopack Dark - Temporary */
--color-turbopack-text-red: #ff6d92;
--color-turbopack-text-blue: #45b2ff;
--color-turbopack-border-red: #6e293b;
--color-turbopack-border-blue: #284f80;
--color-turbopack-background-red: #250d12;
--color-turbopack-background-blue: #0a1723;
`

const base = `
--color-font: white;
--color-backdrop: rgba(0, 0, 0, 0.8);
--color-border-shadow: rgba(255, 255, 255, 0.145);

--color-title-color: #fafafa;
--color-stack-notes: #a9a9a9;
`

export function DarkTheme() {
return (
<style>{css`
:host(.dark) {
${base}
${colors}

@media (prefers-color-scheme: dark) {
:host(:not(.light)) {
${base}
${colors}
}
`}</style>
)
}
Loading
Loading