File size: 3,468 Bytes
b91e262 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | import './devtools-indicator.css'
import type { CSSProperties } from 'react'
import type { DevToolsIndicatorPosition } from '../../shared'
import { NextLogo } from './next-logo'
import { Toast } from '../toast'
import {
MENU_CURVE,
MENU_DURATION_MS,
} from '../errors/dev-tools-indicator/utils'
import {
ACTION_DEVTOOLS_POSITION,
STORE_KEY_SHARED_PANEL_LOCATION,
STORAGE_KEY_PANEL_POSITION_PREFIX,
ACTION_DEVTOOLS_PANEL_POSITION,
} from '../../shared'
import { Draggable } from '../errors/dev-tools-indicator/draggable'
import { useDevOverlayContext } from '../../../dev-overlay.browser'
import { usePanelRouterContext } from '../../menu/context'
import { saveDevToolsConfig } from '../../utils/save-devtools-config'
export const INDICATOR_PADDING = 20
export function DevToolsIndicator() {
const { state, dispatch } = useDevOverlayContext()
const { panel, setPanel, setSelectedIndex } = usePanelRouterContext()
const updateAllPanelPositions = useUpdateAllPanelPositions()
const [vertical, horizontal] = state.devToolsPosition.split('-', 2)
return (
// TODO: why is this called a toast
<Toast
id="devtools-indicator"
data-nextjs-toast
style={
{
'--animate-out-duration-ms': `${MENU_DURATION_MS}ms`,
'--animate-out-timing-function': MENU_CURVE,
boxShadow: 'none',
[vertical]: `${INDICATOR_PADDING}px`,
[horizontal]: `${INDICATOR_PADDING}px`,
} as CSSProperties
}
>
<Draggable
// avoids a lot of weird edge cases that would cause jank if the logo and panel were de-synced
disableDrag={panel !== null}
padding={INDICATOR_PADDING}
position={state.devToolsPosition}
setPosition={(p) => {
dispatch({
type: ACTION_DEVTOOLS_POSITION,
devToolsPosition: p,
})
saveDevToolsConfig({ devToolsPosition: p })
updateAllPanelPositions(p)
}}
>
<NextLogo
onTriggerClick={() => {
const newPanel =
panel === 'panel-selector' ? null : 'panel-selector'
setPanel(newPanel)
if (!newPanel) {
setSelectedIndex(-1)
return
}
}}
/>
</Draggable>
</Toast>
)
}
/**
* makes sure we eventually sync the panel to the logo, otherwise
* it will be jarring if the panels start appearing on the other
* side of the logo. This wont teleport the panel because the indicator
* cannot be dragged when any panel is open
*/
export const useUpdateAllPanelPositions = () => {
const { state, dispatch } = useDevOverlayContext()
return (position: DevToolsIndicatorPosition) => {
dispatch({
type: ACTION_DEVTOOLS_PANEL_POSITION,
devToolsPanelPosition: position,
key: STORE_KEY_SHARED_PANEL_LOCATION,
})
const panelPositionKeys = Object.keys(state.devToolsPanelPosition).filter(
(key) => key.startsWith(STORAGE_KEY_PANEL_POSITION_PREFIX)
)
const panelPositionPatch: Record<string, DevToolsIndicatorPosition> = {
[STORE_KEY_SHARED_PANEL_LOCATION]: position,
}
panelPositionKeys.forEach((key) => {
dispatch({
type: ACTION_DEVTOOLS_PANEL_POSITION,
devToolsPanelPosition: position,
key,
})
panelPositionPatch[key] = position
})
saveDevToolsConfig({
devToolsPanelPosition: panelPositionPatch,
})
}
}
|