Move notifications trigger to toolbar (#333)

* Move notification trigger to toolbar

* Make notifications unpinned by default
This commit is contained in:
Andrew Prifer 2022-11-07 14:40:17 +01:00 committed by GitHub
parent 455ac7736d
commit cb8fa2f20f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 53 deletions

View file

@ -302,28 +302,16 @@ const Button = styled.button<{danger?: boolean}>`
} }
` `
const Dots = styled.span`
display: flex;
gap: 4px;
`
const NotificationsDot = styled.div<{type: NotificationType}>`
width: 8px;
height: 8px;
border-radius: 999999px;
background-color: ${({type}) => COLORS[type]};
`
const NotifierContainer = styled.div` const NotifierContainer = styled.div`
z-index: 9999; z-index: 10;
display: flex; display: flex;
flex-direction: column-reverse; flex-direction: column;
gap: 8px; gap: 8px;
position: fixed; position: fixed;
right: 8px; right: 8px;
bottom: 8px; top: 50px;
width: 500px; width: 500px;
height: 50vh; height: 85vh;
min-height: 400px; min-height: 400px;
` `
@ -371,42 +359,10 @@ export const Notifier = () => {
const {startPause, endPause} = handlers const {startPause, endPause} = handlers
const pinNotifications = const pinNotifications =
useVal(getStudio().atomP.ahistoric.pinNotifications) ?? true useVal(getStudio().atomP.ahistoric.pinNotifications) ?? false
const togglePinNotifications = () =>
getStudio().transaction(({stateEditors, drafts}) => {
stateEditors.studio.ahistoric.setPinNotifications(
!(drafts.ahistoric.pinNotifications ?? true),
)
})
return ( return (
<NotifierContainer> <NotifierContainer>
<ButtonContainer align="side">
<>
{pinNotifications && toasts.length > 0 && (
<Button
onClick={() => {
notificationTypeChecker.clear()
notificationUniquenessChecker.clear()
toast.remove()
}}
danger
>
Clear
</Button>
)}
<Button onClick={() => togglePinNotifications()}>
<span>Notifications</span>
{notificationTypeChecker.types.length > 0 && (
<Dots>
{notificationTypeChecker.types.map((type) => (
<NotificationsDot type={type} key={type} />
))}
</Dots>
)}
</Button>
</>
</ButtonContainer>
{!pinNotifications ? null : toasts.length > 0 ? ( {!pinNotifications ? null : toasts.length > 0 ? (
<NotificationScroller onMouseEnter={startPause} onMouseLeave={endPause}> <NotificationScroller onMouseEnter={startPause} onMouseLeave={endPause}>
<div> <div>
@ -427,6 +383,28 @@ export const Notifier = () => {
Notifications will appear here when you get them. Notifications will appear here when you get them.
</EmptyState> </EmptyState>
)} )}
<ButtonContainer align="side">
{pinNotifications && toasts.length > 0 && (
<Button
onClick={() => {
notificationTypeChecker.clear()
notificationUniquenessChecker.clear()
toast.remove()
}}
danger
>
Clear
</Button>
)}
</ButtonContainer>
</NotifierContainer> </NotifierContainer>
) )
} }
export const useNotifications = () => {
const {toasts} = useToaster()
return {
hasNotifications: toasts.length > 0,
}
}

View file

@ -9,12 +9,18 @@ import BasicTooltip from '@theatre/studio/uiComponents/Popover/BasicTooltip'
import {val} from '@theatre/dataverse' import {val} from '@theatre/dataverse'
import ExtensionToolbar from './ExtensionToolbar/ExtensionToolbar' import ExtensionToolbar from './ExtensionToolbar/ExtensionToolbar'
import PinButton from './PinButton' import PinButton from './PinButton'
import {Details, Ellipsis, Outline} from '@theatre/studio/uiComponents/icons' import {
Details,
Ellipsis,
Outline,
Bell,
} from '@theatre/studio/uiComponents/icons'
import DoubleChevronLeft from '@theatre/studio/uiComponents/icons/DoubleChevronLeft' import DoubleChevronLeft from '@theatre/studio/uiComponents/icons/DoubleChevronLeft'
import DoubleChevronRight from '@theatre/studio/uiComponents/icons/DoubleChevronRight' import DoubleChevronRight from '@theatre/studio/uiComponents/icons/DoubleChevronRight'
import ToolbarIconButton from '@theatre/studio/uiComponents/toolbar/ToolbarIconButton' import ToolbarIconButton from '@theatre/studio/uiComponents/toolbar/ToolbarIconButton'
import usePopover from '@theatre/studio/uiComponents/Popover/usePopover' import usePopover from '@theatre/studio/uiComponents/Popover/usePopover'
import MoreMenu from './MoreMenu/MoreMenu' import MoreMenu from './MoreMenu/MoreMenu'
import {useNotifications} from '@theatre/studio/notify'
const Container = styled.div` const Container = styled.div`
height: 36px; height: 36px;
@ -47,9 +53,9 @@ const SubContainer = styled.div`
gap: 8px; gap: 8px;
` `
const HasUpdatesBadge = styled.div` const HasUpdatesBadge = styled.div<{type: 'info' | 'warning'}>`
position: absolute; position: absolute;
background: #40aaa4; background: ${({type}) => (type === 'info' ? '#40aaa4' : '#f59e0b')};
width: 6px; width: 6px;
height: 6px; height: 6px;
border-radius: 50%; border-radius: 50%;
@ -139,6 +145,8 @@ const GlobalToolbar: React.FC = () => {
return hasUpdates return hasUpdates
}, [hasUpdates]) }, [hasUpdates])
const {hasNotifications} = useNotifications()
return ( return (
<Container> <Container>
<SubContainer> <SubContainer>
@ -166,6 +174,18 @@ const GlobalToolbar: React.FC = () => {
<ExtensionToolbar showLeftDivider toolbarId="global" /> <ExtensionToolbar showLeftDivider toolbarId="global" />
</SubContainer> </SubContainer>
<SubContainer> <SubContainer>
<ToolbarIconButton
onClick={() => {
getStudio().transaction(({stateEditors, drafts}) => {
stateEditors.studio.ahistoric.setPinNotifications(
!(drafts.ahistoric.pinNotifications ?? false),
)
})
}}
>
<Bell />
{hasNotifications && <HasUpdatesBadge type="warning" />}
</ToolbarIconButton>
{moreMenu.node} {moreMenu.node}
<ToolbarIconButton <ToolbarIconButton
ref={moreMenuTriggerRef} ref={moreMenuTriggerRef}
@ -174,7 +194,7 @@ const GlobalToolbar: React.FC = () => {
}} }}
> >
<Ellipsis /> <Ellipsis />
{showUpdatesBadge && <HasUpdatesBadge />} {showUpdatesBadge && <HasUpdatesBadge type="info" />}
</ToolbarIconButton> </ToolbarIconButton>
<PinButton <PinButton
ref={triggerButtonRef as $IntentionalAny} ref={triggerButtonRef as $IntentionalAny}

View file

@ -0,0 +1,22 @@
import * as React from 'react'
function Bell(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
width={16}
height={16}
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M8 1.57c-.416 0-.752.36-.752.804v.482c-1.715.372-3.006 1.994-3.006 3.938v.473c0 1.18-.407 2.32-1.14 3.205l-.173.208a.85.85 0 00-.125.864.75.75 0 00.686.475h9.019a.752.752 0 00.686-.475.845.845 0 00-.125-.864l-.174-.208a5.026 5.026 0 01-1.139-3.205v-.473c0-1.944-1.291-3.566-3.006-3.938v-.482c0-.445-.336-.804-.752-.804zm1.063 12.39c.282-.301.44-.71.44-1.138H6.496c0 .428.158.837.44 1.138.281.302.664.47 1.063.47.4 0 .783-.168 1.064-.47z"
fill="#fff"
fillOpacity={0.6}
/>
</svg>
)
}
export default Bell

View file

@ -14,3 +14,4 @@ export {default as Ellipsis} from './Ellipsis'
export {default as GlobeSimple} from './GlobeSimple' export {default as GlobeSimple} from './GlobeSimple'
export {default as Resize} from './Resize' export {default as Resize} from './Resize'
export {default as Package} from './Package' export {default as Package} from './Package'
export {default as Bell} from './Bell'