From 72d40bf204d3e9c4a5a8ad4029b5c86ef54d333b Mon Sep 17 00:00:00 2001 From: Aria Minaei Date: Thu, 12 Aug 2021 11:52:23 +0200 Subject: [PATCH] Project conflict indicators in outline panel * OutlinePanel has a badge showing the number of conflicting projects * Each project list item gets a highlight if it has conflicts * Refactored Popover to prepare to merge it with tooltips --- .../src/components/SnapshotEditor.tsx | 7 ++-- .../src/components/Toolbar/Toolbar.tsx | 7 ++-- .../src/panels/OutlinePanel/OutlinePanel.tsx | 39 ++++++++++++++++++- .../KeyframeEditor/Dot.tsx | 1 + .../src/uiComponents/Popover/Popover.tsx | 13 ++++--- .../src/uiComponents/Popover/usePopover.tsx | 2 +- .../toolbar/ToolbarIconButton.tsx | 25 +----------- .../toolbar/ToolbarSwitchSelect.tsx | 2 +- 8 files changed, 57 insertions(+), 39 deletions(-) diff --git a/packages/plugin-r3f/src/components/SnapshotEditor.tsx b/packages/plugin-r3f/src/components/SnapshotEditor.tsx index cf2decd..71677ea 100644 --- a/packages/plugin-r3f/src/components/SnapshotEditor.tsx +++ b/packages/plugin-r3f/src/components/SnapshotEditor.tsx @@ -134,10 +134,11 @@ const SnapshotEditor: React.FC<{paneId: string}> = (props) => { } - label="Refresh Snapshot" + title="Refresh Snapshot" onClick={createSnapshot} - > + > + + diff --git a/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx b/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx index c9db5eb..8b6c13e 100644 --- a/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx +++ b/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx @@ -26,9 +26,10 @@ const Toolbar: VFC = () => { onClick={() => { studio.createPane('snapshotEditor') }} - icon={} - label="Create snapshot" - /> + title="Create snapshot" + > + + diff --git a/theatre/studio/src/panels/OutlinePanel/OutlinePanel.tsx b/theatre/studio/src/panels/OutlinePanel/OutlinePanel.tsx index eab3deb..30ec913 100644 --- a/theatre/studio/src/panels/OutlinePanel/OutlinePanel.tsx +++ b/theatre/studio/src/panels/OutlinePanel/OutlinePanel.tsx @@ -5,6 +5,9 @@ import ProjectsList from './ProjectsList/ProjectsList' import {pointerEventsAutoInNormalMode} from '@theatre/studio/css' import ToolbarIconButton from '@theatre/studio/uiComponents/toolbar/ToolbarIconButton' import {VscListTree} from 'react-icons/all' +import {usePrism} from '@theatre/dataverse-react' +import getStudio from '@theatre/studio/getStudio' +import {val} from '@theatre/dataverse' const Container = styled.div` background-color: transparent; @@ -103,11 +106,45 @@ const Body = styled.div` user-select: none; ` +const NumberOfConflictsIndicator = styled.div` + color: white; + width: 14px; + height: 14px; + background: #d00; + border-radius: 4px; + text-align: center; + line-height: 14px; + font-weight: 600; + font-size: 8px; + position: relative; + left: -6px; + top: -11px; + margin-right: -14px; + box-shadow: 0 4px 6px -4px #00000059; +` + const OutlinePanel: React.FC<{}> = (props) => { + const conflicts = usePrism(() => { + const ephemeralStateOfAllProjects = val( + getStudio().atomP.ephemeral.coreByProject, + ) + return Object.entries(ephemeralStateOfAllProjects).filter( + ([a, state]) => + state.loadingState.type === 'browserStateIsNotBasedOnDiskState', + ) + }, []) + return ( - } label="Outline" /> + + + + {conflicts.length > 0 ? ( + + {conflicts.length} + + ) : null} Outline diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx index a835567..790d32f 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx @@ -65,6 +65,7 @@ const HitZone = styled.div` display: block; content: ' '; background: url(${SnapCursor}) no-repeat 100% 100%; + // This icon might also fit: GiConvergenceTarget } } diff --git a/theatre/studio/src/uiComponents/Popover/Popover.tsx b/theatre/studio/src/uiComponents/Popover/Popover.tsx index ffe51ba..aeee2e6 100644 --- a/theatre/studio/src/uiComponents/Popover/Popover.tsx +++ b/theatre/studio/src/uiComponents/Popover/Popover.tsx @@ -29,11 +29,12 @@ const Container = styled.ul` ` const Popover: React.FC<{ - clickPoint: {clientX: number; clientY: number} + clickPoint?: {clientX: number; clientY: number} target: HTMLElement - onRequestClose: () => void + onPointerOutOfThreshold: () => void children: () => React.ReactNode pointerDistanceThreshold?: number + className?: string }> = (props) => { const pointerDistanceThreshold = props.pointerDistanceThreshold ?? defaultPointerDistanceThreshold @@ -101,13 +102,13 @@ const Popover: React.FC<{ e.clientY < pos.top - pointerDistanceThreshold || e.clientY > pos.top + containerRect.height + pointerDistanceThreshold ) { - props.onRequestClose() + props.onPointerOutOfThreshold() } } const onMouseDown = (e: MouseEvent) => { if (!e.composedPath().includes(container)) { - props.onRequestClose() + props.onPointerOutOfThreshold() } } @@ -125,11 +126,11 @@ const Popover: React.FC<{ props.target, targetRect, windowSize, - props.onRequestClose, + props.onPointerOutOfThreshold, ]) return createPortal( - + {props.children()} , diff --git a/theatre/studio/src/uiComponents/Popover/usePopover.tsx b/theatre/studio/src/uiComponents/Popover/usePopover.tsx index e68cfa6..8bd35e6 100644 --- a/theatre/studio/src/uiComponents/Popover/usePopover.tsx +++ b/theatre/studio/src/uiComponents/Popover/usePopover.tsx @@ -38,7 +38,7 @@ export default function usePopover( children={render} clickPoint={state.clickPoint} target={state.target} - onRequestClose={close} + onPointerOutOfThreshold={close} /> ) : ( <> diff --git a/theatre/studio/src/uiComponents/toolbar/ToolbarIconButton.tsx b/theatre/studio/src/uiComponents/toolbar/ToolbarIconButton.tsx index 5278bcc..5950655 100644 --- a/theatre/studio/src/uiComponents/toolbar/ToolbarIconButton.tsx +++ b/theatre/studio/src/uiComponents/toolbar/ToolbarIconButton.tsx @@ -1,14 +1,11 @@ -import type {ReactElement} from 'react' -import React from 'react' import styled from 'styled-components' -import type {ButtonProps} from 'reakit' import {outlinePanelTheme} from '@theatre/studio/panels/OutlinePanel/BaseItem' import {darken, opacify} from 'polished' import {pointerEventsAutoInNormalMode} from '@theatre/studio/css' const {baseBg, baseBorderColor, baseFontColor} = outlinePanelTheme -export const TheButton = styled.button` +const ToolbarIconButton = styled.button` ${pointerEventsAutoInNormalMode}; position: relative; display: flex; @@ -55,24 +52,4 @@ export const TheButton = styled.button` border: 0; ` -const ToolbarIconButton: React.FC< - Exclude & { - icon: ReactElement - label: string - } -> = ({label, icon, ...props}) => { - return ( - <> - - {icon} - - - ) -} - export default ToolbarIconButton diff --git a/theatre/studio/src/uiComponents/toolbar/ToolbarSwitchSelect.tsx b/theatre/studio/src/uiComponents/toolbar/ToolbarSwitchSelect.tsx index fa55aea..78100ca 100644 --- a/theatre/studio/src/uiComponents/toolbar/ToolbarSwitchSelect.tsx +++ b/theatre/studio/src/uiComponents/toolbar/ToolbarSwitchSelect.tsx @@ -3,7 +3,7 @@ import React from 'react' import type {IconType} from 'react-icons' import {Group, Button} from 'reakit' import styled from 'styled-components' -import {TheButton as ButtonImpl} from './ToolbarIconButton' +import ButtonImpl from './ToolbarIconButton' const Opt = styled(ButtonImpl)``