Style tweaks in ProjectDetailPanel
This commit is contained in:
parent
efc52592ba
commit
5f8cdfd886
4 changed files with 154 additions and 73 deletions
|
@ -10,7 +10,7 @@ import {
|
||||||
} from '@theatre/studio/panels/BasePanel/common'
|
} from '@theatre/studio/panels/BasePanel/common'
|
||||||
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
|
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
|
||||||
import ObjectDetails from './ObjectDetails'
|
import ObjectDetails from './ObjectDetails'
|
||||||
import ProjectDetails from './ProjectDetails'
|
import ProjectDetails from './ProjectDetails/ProjectDetails'
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import type Project from '@theatre/core/projects/Project'
|
import type Project from '@theatre/core/projects/Project'
|
||||||
import {val} from '@theatre/dataverse'
|
|
||||||
import {usePrism} from '@theatre/dataverse-react'
|
|
||||||
import getStudio from '@theatre/studio/getStudio'
|
import getStudio from '@theatre/studio/getStudio'
|
||||||
import {generateDiskStateRevision} from '@theatre/studio/StudioStore/generateDiskStateRevision'
|
|
||||||
import BasicPopover from '@theatre/studio/uiComponents/Popover/BasicPopover'
|
import BasicPopover from '@theatre/studio/uiComponents/Popover/BasicPopover'
|
||||||
import usePopover from '@theatre/studio/uiComponents/Popover/usePopover'
|
import usePopover from '@theatre/studio/uiComponents/Popover/usePopover'
|
||||||
import React, {useCallback, useState} from 'react'
|
import React, {useCallback, useState} from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import {rowBgColor} from './propEditors/utils/SingleRowPropEditor'
|
import {rowBgColor} from '@theatre/studio/panels/DetailPanel/propEditors/utils/SingleRowPropEditor'
|
||||||
|
import StateConflictRow from './StateConflictRow'
|
||||||
|
import DetailPanelButton from '@theatre/studio/uiComponents/DetailPanelButton'
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
background-color: ${rowBgColor};
|
background-color: ${rowBgColor};
|
||||||
|
@ -20,26 +19,6 @@ const TheExportRow = styled.div`
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Button = styled.button<{disabled?: boolean}>`
|
|
||||||
text-align: center;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 2px;
|
|
||||||
border: 1px solid #627b7b87;
|
|
||||||
background-color: #4b787d3d;
|
|
||||||
color: #eaeaea;
|
|
||||||
font-weight: 400;
|
|
||||||
display: block;
|
|
||||||
appearance: none;
|
|
||||||
flex-grow: 1;
|
|
||||||
cursor: ${(props) => (props.disabled ? 'none' : 'pointer')};
|
|
||||||
opacity: ${(props) => (props.disabled ? 0.4 : 1)};
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #7dc1c878;
|
|
||||||
border-color: #9ebcbf;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const ExportTooltip = styled(BasicPopover)`
|
const ExportTooltip = styled(BasicPopover)`
|
||||||
width: 280px;
|
width: 280px;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
@ -51,51 +30,6 @@ const ProjectDetails: React.FC<{
|
||||||
const project = projects[0]
|
const project = projects[0]
|
||||||
|
|
||||||
const projectId = project.address.projectId
|
const projectId = project.address.projectId
|
||||||
const nn = usePrism(() => {
|
|
||||||
const loadingState = val(
|
|
||||||
getStudio().atomP.ephemeral.coreByProject[projectId].loadingState,
|
|
||||||
)
|
|
||||||
if (!loadingState) return
|
|
||||||
if (loadingState.type === 'browserStateIsNotBasedOnDiskState') {
|
|
||||||
/**
|
|
||||||
* This stuff is not undo-safe, but once we switch to the new persistence
|
|
||||||
* scheme, these will be unnecessary anyway.
|
|
||||||
*/
|
|
||||||
const useBrowserState = () => {
|
|
||||||
getStudio().transaction(({drafts, stateEditors}) => {
|
|
||||||
stateEditors.coreByProject.historic.revisionHistory.add({
|
|
||||||
projectId,
|
|
||||||
revision: loadingState.onDiskState.revisionHistory[0],
|
|
||||||
})
|
|
||||||
|
|
||||||
stateEditors.coreByProject.historic.revisionHistory.add({
|
|
||||||
projectId,
|
|
||||||
revision: generateDiskStateRevision(),
|
|
||||||
})
|
|
||||||
|
|
||||||
drafts.ephemeral.coreByProject[projectId].loadingState = {
|
|
||||||
type: 'loaded',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const useOnDiskState = () => {
|
|
||||||
getStudio().transaction(({drafts}) => {
|
|
||||||
drafts.historic.coreByProject[projectId] = loadingState.onDiskState
|
|
||||||
drafts.ephemeral.coreByProject[projectId].loadingState = {
|
|
||||||
type: 'loaded',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Browser state is not based on disk state.
|
|
||||||
<button onClick={useBrowserState}>Use browser's state</button>
|
|
||||||
<button onClick={useOnDiskState}>Use disk state</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}, [project])
|
|
||||||
|
|
||||||
const [downloaded, setDownloaded] = useState(false)
|
const [downloaded, setDownloaded] = useState(false)
|
||||||
|
|
||||||
|
@ -140,11 +74,11 @@ const ProjectDetails: React.FC<{
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{nn}
|
|
||||||
{tooltip}
|
{tooltip}
|
||||||
<Container>
|
<Container>
|
||||||
|
<StateConflictRow projectId={projectId} />
|
||||||
<TheExportRow>
|
<TheExportRow>
|
||||||
<Button
|
<DetailPanelButton
|
||||||
onMouseEnter={(e) =>
|
onMouseEnter={(e) =>
|
||||||
openExportTooltip(e, e.target as unknown as HTMLButtonElement)
|
openExportTooltip(e, e.target as unknown as HTMLButtonElement)
|
||||||
}
|
}
|
||||||
|
@ -152,7 +86,7 @@ const ProjectDetails: React.FC<{
|
||||||
disabled={downloaded}
|
disabled={downloaded}
|
||||||
>
|
>
|
||||||
{downloaded ? '(Exported)' : `Export ${projectId} to JSON`}
|
{downloaded ? '(Exported)' : `Export ${projectId} to JSON`}
|
||||||
</Button>
|
</DetailPanelButton>
|
||||||
</TheExportRow>
|
</TheExportRow>
|
||||||
</Container>
|
</Container>
|
||||||
</>
|
</>
|
|
@ -0,0 +1,124 @@
|
||||||
|
import {useVal} from '@theatre/dataverse-react'
|
||||||
|
import getStudio from '@theatre/studio/getStudio'
|
||||||
|
import React from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import {generateDiskStateRevision} from '@theatre/studio/StudioStore/generateDiskStateRevision'
|
||||||
|
import type {ProjectEphemeralState} from '@theatre/core/projects/store/storeTypes'
|
||||||
|
import useTooltip from '@theatre/studio/uiComponents/Popover/useTooltip'
|
||||||
|
import BasicTooltip from '@theatre/studio/uiComponents/Popover/BasicTooltip'
|
||||||
|
import type {$FixMe} from '@theatre/shared/utils/types'
|
||||||
|
import DetailPanelButton from '@theatre/studio/uiComponents/DetailPanelButton'
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
padding: 8px 10px;
|
||||||
|
position: relative;
|
||||||
|
background-color: #6d232352;
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
content: ' ';
|
||||||
|
display: block;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 2px;
|
||||||
|
background-color: #ff000070;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Message = styled.div`
|
||||||
|
margin-bottom: 1em;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ChooseStateRow = styled.div`
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const StateConflictRow: React.FC<{projectId: string}> = ({projectId}) => {
|
||||||
|
const loadingState = useVal(
|
||||||
|
getStudio().atomP.ephemeral.coreByProject[projectId].loadingState,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!loadingState) return null
|
||||||
|
|
||||||
|
if (loadingState.type === 'browserStateIsNotBasedOnDiskState') {
|
||||||
|
return <InConflict loadingState={loadingState} projectId={projectId} />
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InConflict: React.FC<{
|
||||||
|
projectId: string
|
||||||
|
loadingState: Extract<
|
||||||
|
ProjectEphemeralState['loadingState'],
|
||||||
|
{type: 'browserStateIsNotBasedOnDiskState'}
|
||||||
|
>
|
||||||
|
}> = ({projectId, loadingState}) => {
|
||||||
|
/**
|
||||||
|
* This stuff is not undo-safe, but once we switch to the new persistence
|
||||||
|
* scheme, these will be unnecessary anyway.
|
||||||
|
*/
|
||||||
|
const useBrowserState = () => {
|
||||||
|
getStudio().transaction(({drafts, stateEditors}) => {
|
||||||
|
stateEditors.coreByProject.historic.revisionHistory.add({
|
||||||
|
projectId,
|
||||||
|
revision: loadingState.onDiskState.revisionHistory[0],
|
||||||
|
})
|
||||||
|
|
||||||
|
stateEditors.coreByProject.historic.revisionHistory.add({
|
||||||
|
projectId,
|
||||||
|
revision: generateDiskStateRevision(),
|
||||||
|
})
|
||||||
|
|
||||||
|
drafts.ephemeral.coreByProject[projectId]!.loadingState = {
|
||||||
|
type: 'loaded',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const useOnDiskState = () => {
|
||||||
|
getStudio().transaction(({drafts}) => {
|
||||||
|
drafts.historic.coreByProject[projectId] = loadingState.onDiskState
|
||||||
|
drafts.ephemeral.coreByProject[projectId]!.loadingState = {
|
||||||
|
type: 'loaded',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const [browserStateNode, browserStateRef] = useTooltip({}, () => (
|
||||||
|
<BasicTooltip>
|
||||||
|
The browser's state will override the disk state.
|
||||||
|
</BasicTooltip>
|
||||||
|
))
|
||||||
|
|
||||||
|
const [diskStateNode, diskStateRef] = useTooltip({}, () => (
|
||||||
|
<BasicTooltip>
|
||||||
|
The disk's state will override the browser's state.
|
||||||
|
</BasicTooltip>
|
||||||
|
))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Message>Browser state is not based on disk state.</Message>
|
||||||
|
<ChooseStateRow>
|
||||||
|
{browserStateNode}
|
||||||
|
<DetailPanelButton
|
||||||
|
onClick={useBrowserState}
|
||||||
|
ref={browserStateRef as $FixMe}
|
||||||
|
>
|
||||||
|
Use browser's state
|
||||||
|
</DetailPanelButton>
|
||||||
|
{diskStateNode}
|
||||||
|
<DetailPanelButton
|
||||||
|
onClick={useOnDiskState}
|
||||||
|
ref={diskStateRef as $FixMe}
|
||||||
|
>
|
||||||
|
Use disk state
|
||||||
|
</DetailPanelButton>
|
||||||
|
</ChooseStateRow>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StateConflictRow
|
23
theatre/studio/src/uiComponents/DetailPanelButton.tsx
Normal file
23
theatre/studio/src/uiComponents/DetailPanelButton.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const DetailPanelButton = styled.button<{disabled?: boolean}>`
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid #627b7b87;
|
||||||
|
background-color: #4b787d3d;
|
||||||
|
color: #eaeaea;
|
||||||
|
font-weight: 400;
|
||||||
|
display: block;
|
||||||
|
appearance: none;
|
||||||
|
flex-grow: 1;
|
||||||
|
cursor: ${(props) => (props.disabled ? 'none' : 'pointer')};
|
||||||
|
opacity: ${(props) => (props.disabled ? 0.4 : 1)};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #7dc1c878;
|
||||||
|
border-color: #9ebcbf;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default DetailPanelButton
|
Loading…
Reference in a new issue