Skip to content

Commit 74b8382

Browse files
authored
[dev-overlay] control dark theme in one place (#76528)
1 parent 9d1c6fd commit 74b8382

File tree

9 files changed

+167
-160
lines changed

9 files changed

+167
-160
lines changed

packages/next/src/client/components/react-dev-overlay/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,9 @@ export function ComponentStyles() {
6969
)
7070
}
7171
```
72+
73+
### Dark Theme
74+
75+
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.
76+
77+
To make changes to the dark theme, you can edit the [`ui/styles/dark-theme.tsx`](./ui/styles/dark-theme.tsx) file.

packages/next/src/client/components/react-dev-overlay/ui/components/errors/dialog/dialog.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ export const DIALOG_STYLES = `
3636
box-shadow: var(--shadow-menu);
3737
position: relative;
3838
39-
@media (prefers-color-scheme: dark) {
40-
border-color: var(--color-gray-400);
41-
}
42-
4339
&:has(
4440
~ [data-nextjs-error-overlay-nav] .error-overlay-notch[data-side='left']
4541
) {

packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay-bottom-stack/index.tsx

-6
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,4 @@ export const styles = `
101101
}
102102
}
103103
}
104-
105-
@media (prefers-color-scheme: dark) {
106-
.error-overlay-bottom-stack-layer {
107-
border-color: var(--color-gray-400);
108-
}
109-
}
110104
`

packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Colors } from './styles/colors'
88
import { ErrorOverlay } from './components/errors/error-overlay/error-overlay'
99
import { DevToolsIndicator } from './components/errors/dev-tools-indicator/dev-tools-indicator'
1010
import { RenderError } from './container/runtime-error/render-error'
11+
import { DarkTheme } from './styles/dark-theme'
1112

1213
export function DevOverlay({
1314
state,
@@ -26,6 +27,7 @@ export function DevOverlay({
2627
<Base />
2728
<Colors />
2829
<ComponentStyles />
30+
<DarkTheme />
2931

3032
<RenderError state={state} isAppDir={true}>
3133
{({ runtimeErrors, totalErrorCount }) => {

packages/next/src/client/components/react-dev-overlay/ui/storybook/with-shadow-portal.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { Colors } from '../styles/colors'
33
import { CssReset } from '../styles/css-reset'
44
import { ComponentStyles } from '../styles/component-styles'
55
import { ShadowPortal } from '../components/shadow-portal'
6+
import { DarkTheme } from '../styles/dark-theme'
67

78
export const withShadowPortal = (Story: any) => (
89
<ShadowPortal>
910
<CssReset />
1011
<Base />
1112
<Colors />
1213
<ComponentStyles />
14+
<DarkTheme />
1315
<Story />
1416
</ShadowPortal>
1517
)

packages/next/src/client/components/react-dev-overlay/ui/styles/base.tsx

+6-25
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,17 @@
11
import { css } from '../../utils/css'
22

3-
const darkTheme = css`
4-
--color-font: white;
5-
--color-backdrop: rgba(0, 0, 0, 0.8);
6-
--color-border-shadow: rgba(255, 255, 255, 0.145);
7-
8-
--color-title-color: #fafafa;
9-
--color-stack-notes: #a9a9a9;
10-
`
11-
123
export function Base() {
134
return (
145
<style>
156
{css`
167
:host {
178
/*
18-
Although the style applied to the shadow host is isolated,
19-
the element that attached the shadow host (i.e. "nextjs-portal")
20-
is still affected by the parent's style (e.g. "body"). This may
21-
occur style conflicts like "display: flex", with other children
22-
elements therefore give the shadow host an absolute position.
23-
*/
9+
* Although the style applied to the shadow host is isolated,
10+
* the element that attached the shadow host (i.e. "nextjs-portal")
11+
* is still affected by the parent's style (e.g. "body"). This may
12+
* occur style conflicts like "display: flex", with other children
13+
* elements therefore give the shadow host an absolute position.
14+
*/
2415
position: absolute;
2516
2617
--color-font: #757575;
@@ -123,16 +114,6 @@ export function Base() {
123114
}
124115
}
125116
126-
:host(.dark) {
127-
${darkTheme}
128-
}
129-
130-
@media (prefers-color-scheme: dark) {
131-
:host(:not(.light)) {
132-
${darkTheme}
133-
}
134-
}
135-
136117
h1,
137118
h2,
138119
h3,

packages/next/src/client/components/react-dev-overlay/ui/styles/colors.tsx

+10-119
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,20 @@
11
import { css } from '../../utils/css'
22

3-
const darkTheme = css`
4-
/* Background Dark */
5-
--color-background-100: #0a0a0a;
6-
--color-background-200: #000000;
7-
8-
/* Syntax Dark */
9-
--color-syntax-comment: #a0a0a0;
10-
--color-syntax-constant: #ededed;
11-
--color-syntax-function: #52a9ff;
12-
--color-syntax-keyword: #f76e99;
13-
--color-syntax-link: #0ac5b2;
14-
--color-syntax-parameter: #f1a10d;
15-
--color-syntax-punctuation: #ededed;
16-
--color-syntax-string: #0ac5b2;
17-
--color-syntax-string-expression: #0ac5b2;
18-
19-
/* Gray Scale Dark */
20-
--color-gray-100: #1a1a1a;
21-
--color-gray-200: #1f1f1f;
22-
--color-gray-300: #292929;
23-
--color-gray-400: #2e2e2e;
24-
--color-gray-500: #454545;
25-
--color-gray-600: #878787;
26-
--color-gray-700: #8f8f8f;
27-
--color-gray-800: #7d7d7d;
28-
--color-gray-900: #a0a0a0;
29-
--color-gray-1000: #ededed;
30-
31-
/* Gray Alpha Scale Dark */
32-
--color-gray-alpha-100: rgba(255, 255, 255, 0.066);
33-
--color-gray-alpha-200: rgba(255, 255, 255, 0.087);
34-
--color-gray-alpha-300: rgba(255, 255, 255, 0.125);
35-
--color-gray-alpha-400: rgba(255, 255, 255, 0.145);
36-
--color-gray-alpha-500: rgba(255, 255, 255, 0.239);
37-
--color-gray-alpha-600: rgba(255, 255, 255, 0.506);
38-
--color-gray-alpha-700: rgba(255, 255, 255, 0.54);
39-
--color-gray-alpha-800: rgba(255, 255, 255, 0.47);
40-
--color-gray-alpha-900: rgba(255, 255, 255, 0.61);
41-
--color-gray-alpha-1000: rgba(255, 255, 255, 0.923);
42-
43-
/* Blue Scale Dark */
44-
--color-blue-100: #0f1b2d;
45-
--color-blue-200: #10243e;
46-
--color-blue-300: #0f3058;
47-
--color-blue-400: #0d3868;
48-
--color-blue-500: #0a4481;
49-
--color-blue-600: #0091ff;
50-
--color-blue-700: #0070f3;
51-
--color-blue-800: #0060d1;
52-
--color-blue-900: #52a9ff;
53-
--color-blue-1000: #eaf6ff;
54-
55-
/* Red Scale Dark */
56-
--color-red-100: #2a1314;
57-
--color-red-200: #3d1719;
58-
--color-red-300: #551a1e;
59-
--color-red-400: #671e22;
60-
--color-red-500: #822025;
61-
--color-red-600: #e5484d;
62-
--color-red-700: #e5484d;
63-
--color-red-800: #da3036;
64-
--color-red-900: #ff6369;
65-
--color-red-1000: #ffecee;
66-
67-
/* Amber Scale Dark */
68-
--color-amber-100: #271700;
69-
--color-amber-200: #341c00;
70-
--color-amber-300: #4a2900;
71-
--color-amber-400: #573300;
72-
--color-amber-500: #693f05;
73-
--color-amber-600: #e79c13;
74-
--color-amber-700: #ffb224;
75-
--color-amber-800: #ff990a;
76-
--color-amber-900: #f1a10d;
77-
--color-amber-1000: #fef3dd;
78-
79-
/* Green Scale Dark */
80-
--color-green-100: #0b2211;
81-
--color-green-200: #0f2c17;
82-
--color-green-300: #11351b;
83-
--color-green-400: #0c461b;
84-
--color-green-500: #126427;
85-
--color-green-600: #1a9338;
86-
--color-green-700: #46a758;
87-
--color-green-800: #388e4a;
88-
--color-green-900: #63c174;
89-
--color-green-1000: #e5fbeb;
90-
91-
/* Turbopack Dark - Temporary */
92-
--color-turbopack-text-red: #ff6d92;
93-
--color-turbopack-text-blue: #45b2ff;
94-
--color-turbopack-border-red: #6e293b;
95-
--color-turbopack-border-blue: #284f80;
96-
--color-turbopack-background-red: #250d12;
97-
--color-turbopack-background-blue: #0a1723;
98-
`
99-
100-
// TODO: Replace the existing colors in Base.tsx.
1013
export function Colors() {
1024
return (
1035
<style>
1046
{css`
1057
:host {
106-
${
107-
// CAUTION: THIS IS A WORKAROUND!
108-
// For now, we use @babel/code-frame to parse the code frame which does not support option to change the color.
109-
// x-ref: https://github.com/babel/babel/blob/efa52324ff835b794c48080f14877b6caf32cd15/packages/babel-code-frame/src/defs.ts#L40-L54
110-
// So, we do a workaround mapping to change the color matching the theme.
111-
112-
// For example, in @babel/code-frame, the `keyword` is mapped to ANSI "cyan".
113-
// We want the `keyword` to use the `syntax-keyword` color in the theme.
114-
// So, we map the "cyan" to the `syntax-keyword` in the theme.
115-
''
116-
}
8+
/*
9+
* CAUTION: THIS IS A WORKAROUND!
10+
* For now, we use @babel/code-frame to parse the code frame which does not support option to change the color.
11+
* x-ref: https://github.com/babel/babel/blob/efa52324ff835b794c48080f14877b6caf32cd15/packages/babel-code-frame/src/defs.ts#L40-L54
12+
* So, we do a workaround mapping to change the color matching the theme.
13+
*
14+
* For example, in @babel/code-frame, the "keyword" is mapped to ANSI "cyan".
15+
* We want the "keyword" to use the "syntax-keyword" color in the theme.
16+
* So, we map the "cyan" to the "syntax-keyword" in the theme.
17+
*/
11718
/* cyan: keyword */
11819
--color-ansi-cyan: var(--color-syntax-keyword);
11920
/* yellow: capitalized, jsxIdentifier, punctuation */
@@ -237,16 +138,6 @@ export function Colors() {
237138
--color-turbopack-background-red: #fff7f9;
238139
--color-turbopack-background-blue: #f6fbff;
239140
}
240-
241-
:host(.dark) {
242-
${darkTheme}
243-
}
244-
245-
@media (prefers-color-scheme: dark) {
246-
:host(:not(.light)) {
247-
${darkTheme}
248-
}
249-
}
250141
`}
251142
</style>
252143
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { css } from '../../utils/css'
2+
3+
const colors = `
4+
/* Background Dark */
5+
--color-background-100: #0a0a0a;
6+
--color-background-200: #000000;
7+
8+
/* Syntax Dark */
9+
--color-syntax-comment: #a0a0a0;
10+
--color-syntax-constant: #ededed;
11+
--color-syntax-function: #52a9ff;
12+
--color-syntax-keyword: #f76e99;
13+
--color-syntax-link: #0ac5b2;
14+
--color-syntax-parameter: #f1a10d;
15+
--color-syntax-punctuation: #ededed;
16+
--color-syntax-string: #0ac5b2;
17+
--color-syntax-string-expression: #0ac5b2;
18+
19+
/* Gray Scale Dark */
20+
--color-gray-100: #1a1a1a;
21+
--color-gray-200: #1f1f1f;
22+
--color-gray-300: #292929;
23+
--color-gray-400: #2e2e2e;
24+
--color-gray-500: #454545;
25+
--color-gray-600: #878787;
26+
--color-gray-700: #8f8f8f;
27+
--color-gray-800: #7d7d7d;
28+
--color-gray-900: #a0a0a0;
29+
--color-gray-1000: #ededed;
30+
31+
/* Gray Alpha Scale Dark */
32+
--color-gray-alpha-100: rgba(255, 255, 255, 0.066);
33+
--color-gray-alpha-200: rgba(255, 255, 255, 0.087);
34+
--color-gray-alpha-300: rgba(255, 255, 255, 0.125);
35+
--color-gray-alpha-400: rgba(255, 255, 255, 0.145);
36+
--color-gray-alpha-500: rgba(255, 255, 255, 0.239);
37+
--color-gray-alpha-600: rgba(255, 255, 255, 0.506);
38+
--color-gray-alpha-700: rgba(255, 255, 255, 0.54);
39+
--color-gray-alpha-800: rgba(255, 255, 255, 0.47);
40+
--color-gray-alpha-900: rgba(255, 255, 255, 0.61);
41+
--color-gray-alpha-1000: rgba(255, 255, 255, 0.923);
42+
43+
/* Blue Scale Dark */
44+
--color-blue-100: #0f1b2d;
45+
--color-blue-200: #10243e;
46+
--color-blue-300: #0f3058;
47+
--color-blue-400: #0d3868;
48+
--color-blue-500: #0a4481;
49+
--color-blue-600: #0091ff;
50+
--color-blue-700: #0070f3;
51+
--color-blue-800: #0060d1;
52+
--color-blue-900: #52a9ff;
53+
--color-blue-1000: #eaf6ff;
54+
55+
/* Red Scale Dark */
56+
--color-red-100: #2a1314;
57+
--color-red-200: #3d1719;
58+
--color-red-300: #551a1e;
59+
--color-red-400: #671e22;
60+
--color-red-500: #822025;
61+
--color-red-600: #e5484d;
62+
--color-red-700: #e5484d;
63+
--color-red-800: #da3036;
64+
--color-red-900: #ff6369;
65+
--color-red-1000: #ffecee;
66+
67+
/* Amber Scale Dark */
68+
--color-amber-100: #271700;
69+
--color-amber-200: #341c00;
70+
--color-amber-300: #4a2900;
71+
--color-amber-400: #573300;
72+
--color-amber-500: #693f05;
73+
--color-amber-600: #e79c13;
74+
--color-amber-700: #ffb224;
75+
--color-amber-800: #ff990a;
76+
--color-amber-900: #f1a10d;
77+
--color-amber-1000: #fef3dd;
78+
79+
/* Green Scale Dark */
80+
--color-green-100: #0b2211;
81+
--color-green-200: #0f2c17;
82+
--color-green-300: #11351b;
83+
--color-green-400: #0c461b;
84+
--color-green-500: #126427;
85+
--color-green-600: #1a9338;
86+
--color-green-700: #46a758;
87+
--color-green-800: #388e4a;
88+
--color-green-900: #63c174;
89+
--color-green-1000: #e5fbeb;
90+
91+
/* Turbopack Dark - Temporary */
92+
--color-turbopack-text-red: #ff6d92;
93+
--color-turbopack-text-blue: #45b2ff;
94+
--color-turbopack-border-red: #6e293b;
95+
--color-turbopack-border-blue: #284f80;
96+
--color-turbopack-background-red: #250d12;
97+
--color-turbopack-background-blue: #0a1723;
98+
`
99+
100+
const base = `
101+
--color-font: white;
102+
--color-backdrop: rgba(0, 0, 0, 0.8);
103+
--color-border-shadow: rgba(255, 255, 255, 0.145);
104+
105+
--color-title-color: #fafafa;
106+
--color-stack-notes: #a9a9a9;
107+
`
108+
109+
export function DarkTheme() {
110+
return (
111+
<style>{css`
112+
:host(.dark) {
113+
${base}
114+
${colors}
115+
116+
@media (prefers-color-scheme: dark) {
117+
:host(:not(.light)) {
118+
${base}
119+
${colors}
120+
}
121+
`}</style>
122+
)
123+
}

0 commit comments

Comments
 (0)