mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: state inspector
This commit is contained in:
parent
b28c9e0fe8
commit
1d099d23b8
5 changed files with 87 additions and 15 deletions
7
src/common.d.ts
vendored
Normal file
7
src/common.d.ts
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// Similar to `global.d.ts` but with import/export
|
||||
import { Dispatch, SetStateAction } from 'react'
|
||||
|
||||
type ReactIO<T> = {
|
||||
value: T
|
||||
onChange: Dispatch<SetStateAction<T>>
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { SideBar } from 'components/SideBar'
|
||||
import { ConfigsContextWrapper } from 'containers/ConfigsContext'
|
||||
import { ReloadContextWrapper } from 'containers/ReloadContext'
|
||||
import { InspectorContextWrapper } from 'containers/StateInspector'
|
||||
import * as React from 'react'
|
||||
import { ErrorBoundary } from '../containers/ErrorBoundary'
|
||||
import { StateBarErrorContextWrapper } from '../containers/ErrorContext'
|
||||
|
|
@ -10,20 +11,22 @@ import { StateBarStateContextWrapper } from '../containers/SideBarState'
|
|||
|
||||
export function Gitako() {
|
||||
return (
|
||||
<ReloadContextWrapper>
|
||||
<ErrorBoundary>
|
||||
<ConfigsContextWrapper>
|
||||
<StateBarStateContextWrapper>
|
||||
<StateBarErrorContextWrapper>
|
||||
<OAuthWrapper>
|
||||
<RepoContextWrapper>
|
||||
<SideBar />
|
||||
</RepoContextWrapper>
|
||||
</OAuthWrapper>
|
||||
</StateBarErrorContextWrapper>
|
||||
</StateBarStateContextWrapper>
|
||||
</ConfigsContextWrapper>
|
||||
</ErrorBoundary>
|
||||
</ReloadContextWrapper>
|
||||
<InspectorContextWrapper>
|
||||
<ReloadContextWrapper>
|
||||
<ErrorBoundary>
|
||||
<ConfigsContextWrapper>
|
||||
<StateBarStateContextWrapper>
|
||||
<StateBarErrorContextWrapper>
|
||||
<OAuthWrapper>
|
||||
<RepoContextWrapper>
|
||||
<SideBar />
|
||||
</RepoContextWrapper>
|
||||
</OAuthWrapper>
|
||||
</StateBarErrorContextWrapper>
|
||||
</StateBarStateContextWrapper>
|
||||
</ConfigsContextWrapper>
|
||||
</ErrorBoundary>
|
||||
</ReloadContextWrapper>
|
||||
</InspectorContextWrapper>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { useInspector } from 'containers/StateInspector'
|
||||
import * as React from 'react'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
|
||||
|
|
@ -7,6 +8,7 @@ export const SideBarErrorContext = React.createContext<SideBarErrorContextShape
|
|||
|
||||
export function StateBarErrorContextWrapper({ children }: React.PropsWithChildren<{}>) {
|
||||
const $error = useStateIO<string | null>(null)
|
||||
useInspector('SideBarErrorContext', $error.value)
|
||||
|
||||
return <SideBarErrorContext.Provider value={$error}>{children}</SideBarErrorContext.Provider>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
import { useInspector } from './StateInspector'
|
||||
|
||||
export type SideBarState =
|
||||
| 'disabled'
|
||||
|
|
@ -19,6 +20,7 @@ export const SideBarStateContext = React.createContext<SideBarStateContextShape
|
|||
|
||||
export function StateBarStateContextWrapper({ children }: React.PropsWithChildren<{}>) {
|
||||
const $state = useStateIO<SideBarState>('disabled')
|
||||
useInspector('SideBarStateContext', $state.value)
|
||||
|
||||
return (
|
||||
<SideBarStateContext.Provider value={$state}>
|
||||
|
|
|
|||
58
src/containers/StateInspector.tsx
Normal file
58
src/containers/StateInspector.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { ReactIO } from 'common'
|
||||
import { IN_PRODUCTION_MODE } from 'env'
|
||||
import * as React from 'react'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
|
||||
export type InspectorContextShape = ReactIO<JSONObject>
|
||||
|
||||
export const InspectorContext = React.createContext<InspectorContextShape | null>(null)
|
||||
|
||||
export const InspectorContextWrapper = IN_PRODUCTION_MODE
|
||||
? React.Fragment
|
||||
: function InspectorContextWrapper({ children }: React.PropsWithChildren<{}>) {
|
||||
const $ = useStateIO<JSONObject>({})
|
||||
const [show, setShow] = React.useState(true)
|
||||
|
||||
return (
|
||||
<InspectorContext.Provider value={$}>
|
||||
{show ? (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: '0',
|
||||
right: '0',
|
||||
height: '100vh',
|
||||
width: '360px',
|
||||
overflow: 'auto',
|
||||
background: 'rgba(255, 255, 255, 0.75)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<pre style={{ flex: 1 }}>{JSON.stringify($.value, null, 2)}</pre>
|
||||
<div>
|
||||
<button onClick={() => setShow(false)}>❌</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
bottom: '0',
|
||||
right: '0',
|
||||
}}
|
||||
>
|
||||
<button onClick={() => setShow(true)}>🔎</button>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</InspectorContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useInspector(key: string, value: JSONValue) {
|
||||
const $ = React.useContext(InspectorContext)
|
||||
React.useEffect(() => {
|
||||
$?.onChange(prev => ({ ...prev, [key]: value }))
|
||||
}, [key, value]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}
|
||||
Loading…
Reference in a new issue