Skip to content

Commit 814e0a6

Browse files
committed
[segment explorer] builtin slots style
1 parent 33477b7 commit 814e0a6

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

packages/next/src/next-devtools/dev-overlay/components/overview/segment-explorer.tsx

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { useSegmentTree, type SegmentTrieNode } from '../../segment-explorer'
22
import { css } from '../../utils/css'
33
import { cx } from '../../utils/cx'
44

5+
const BUILTIN_PREFIX = '__next_builtin__'
6+
57
const isFileNode = (node: SegmentTrieNode) => {
68
return !!node.value?.type && !!node.value?.pagePath
79
}
@@ -115,7 +117,10 @@ function PageSegmentTreeLayerPresentation({
115117
return null
116118
}
117119
const filePath = childNode.value.pagePath
118-
const fileName = filePath.split('/').pop() || ''
120+
const lastSegment = filePath.split('/').pop() || ''
121+
const isBuiltin = filePath.startsWith(BUILTIN_PREFIX)
122+
const fileName = lastSegment.replace(BUILTIN_PREFIX, '')
123+
119124
return (
120125
<span
121126
key={fileChildSegment}
@@ -124,10 +129,18 @@ function PageSegmentTreeLayerPresentation({
124129
}}
125130
className={cx(
126131
'segment-explorer-file-label',
127-
`segment-explorer-file-label--${childNode.value.type}`
132+
`segment-explorer-file-label--${childNode.value.type}`,
133+
isBuiltin && 'segment-explorer-file-label--builtin'
128134
)}
129135
>
130136
{fileName}
137+
{isBuiltin && (
138+
<TooltipSpan
139+
title={`The default Next.js not found is being shown. You can customize this page by adding your own ${fileName} file to the app/ directory.`}
140+
>
141+
<InfoIcon />
142+
</TooltipSpan>
143+
)}
131144
</span>
132145
)
133146
})}
@@ -250,6 +263,17 @@ export const DEV_TOOLS_INFO_RENDER_FILES_STYLES = css`
250263
background-color: var(--color-red-300);
251264
color: var(--color-red-900);
252265
}
266+
267+
.segment-explorer-file-label--builtin {
268+
background-color: transparent;
269+
color: var(--color-gray-900);
270+
border: 1px dashed var(--color-gray-500);
271+
}
272+
273+
.segment-explorer-file-label--builtin svg {
274+
margin-left: 4px;
275+
margin-right: -4px;
276+
}
253277
`
254278

255279
function openInEditor({ filePath }: { filePath: string }) {
@@ -265,3 +289,35 @@ function openInEditor({ filePath }: { filePath: string }) {
265289
}/__nextjs_launch-editor?${params.toString()}`
266290
)
267291
}
292+
293+
function InfoIcon(props: React.SVGProps<SVGSVGElement>) {
294+
return (
295+
<svg
296+
width="16"
297+
height="16"
298+
viewBox="0 0 16 16"
299+
fill="none"
300+
xmlns="http://www.w3.org/2000/svg"
301+
{...props}
302+
>
303+
<path
304+
d="M14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2C11.3137 2 14 4.68629 14 8Z"
305+
fill="var(--color-gray-400)"
306+
/>
307+
<path
308+
d="M7.75 7C8.30228 7.00001 8.75 7.44772 8.75 8V11.25H7.25V8.5H6.25V7H7.75ZM8 4C8.55228 4 9 4.44772 9 5C9 5.55228 8.55228 6 8 6C7.44772 6 7 5.55228 7 5C7 4.44772 7.44772 4 8 4Z"
309+
fill="var(--color-gray-900)"
310+
/>
311+
</svg>
312+
)
313+
}
314+
315+
function TooltipSpan({
316+
children,
317+
title,
318+
}: {
319+
children: React.ReactNode
320+
title: string
321+
}) {
322+
return <span title={title}>{children}</span>
323+
}

packages/next/src/next-devtools/userspace/app/app-dev-overlay-error-boundary.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PureComponent } from 'react'
1+
import { Fragment, PureComponent } from 'react'
22
import { dispatcher } from 'next/dist/compiled/next-devtools'
33
import { RuntimeErrorHandler } from '../../../client/dev/runtime-error-handler'
44
import { ErrorBoundary } from '../../../client/components/error-boundary'
@@ -31,8 +31,10 @@ function ErroredHtml({
3131
}
3232
return (
3333
<ErrorBoundary errorComponent={DefaultGlobalError}>
34-
{globalErrorStyles}
35-
<GlobalError error={error} />
34+
<>
35+
{globalErrorStyles}
36+
<GlobalError error={error} />
37+
</>
3638
</ErrorBoundary>
3739
)
3840
}

packages/next/src/server/app-render/app-render.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3980,7 +3980,13 @@ const getGlobalErrorStyles = async (
39803980
if (ctx.renderOpts.devtoolSegmentExplorer && globalErrorModulePath) {
39813981
const SegmentViewNode = ctx.componentMod.SegmentViewNode
39823982
globalErrorStyles = (
3983-
<SegmentViewNode type="global-error" pagePath={globalErrorModulePath}>
3983+
// This will be rendered next to GlobalError component under ErrorBoundary,
3984+
// it requires a key to avoid React warning about duplicate keys.
3985+
<SegmentViewNode
3986+
key="ge-svn"
3987+
type="global-error"
3988+
pagePath={globalErrorModulePath}
3989+
>
39843990
{globalErrorStyles}
39853991
</SegmentViewNode>
39863992
)

packages/next/src/server/app-render/segment-explorer-path.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export function normalizeConventionFilePath(
2121
// If it's internal file only keep the filename, strip nextjs internal prefix
2222
if (nextInternalPrefixRegex.test(relativePath)) {
2323
relativePath = relativePath.replace(nextInternalPrefixRegex, '')
24+
// Add a special prefix to let segment explorer know it's a built-in component
25+
relativePath = `__next_builtin__${relativePath}`
2426
}
2527

2628
return relativePath

0 commit comments

Comments
 (0)