parent
a8a9b5ef05
commit
a55a34d48f
4 changed files with 59 additions and 39 deletions
|
@ -11,6 +11,8 @@ import type {
|
|||
import {useVal} from '@theatre/react'
|
||||
import getStudio from './getStudio'
|
||||
import {marked} from 'marked'
|
||||
import useTooltip from './uiComponents/Popover/useTooltip'
|
||||
import MinimalTooltip from './uiComponents/Popover/MinimalTooltip'
|
||||
|
||||
/**
|
||||
* Creates a string key unique to a notification with a certain title and message.
|
||||
|
@ -181,9 +183,9 @@ const COLORS = {
|
|||
|
||||
const IndicatorDot = styled.div<{type: NotificationType}>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 12px;
|
||||
padding-top: 21px;
|
||||
|
||||
::before {
|
||||
content: '';
|
||||
|
@ -308,7 +310,7 @@ const NotifierContainer = styled.div`
|
|||
flex-direction: column;
|
||||
gap: 8px;
|
||||
position: fixed;
|
||||
right: 8px;
|
||||
right: 92px;
|
||||
top: 50px;
|
||||
width: 500px;
|
||||
height: 85vh;
|
||||
|
@ -330,27 +332,31 @@ const NotificationScroller = styled.div`
|
|||
`
|
||||
|
||||
const EmptyState = styled.div`
|
||||
align-self: flex-end;
|
||||
width: fit-content;
|
||||
padding: 12px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
${pointerEventsAutoInNormalMode};
|
||||
background-color: rgba(40, 43, 47, 0.8);
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.25), 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
backdrop-filter: blur(14px);
|
||||
color: #b4b4b4;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
|
||||
@supports not (backdrop-filter: blur()) {
|
||||
background: rgba(40, 43, 47, 0.95);
|
||||
}
|
||||
`
|
||||
//endregion
|
||||
|
||||
export const useEmptyNotificationsTooltip = () => {
|
||||
const {hasNotifications} = useNotifications()
|
||||
|
||||
return useTooltip({enabled: !hasNotifications}, () => (
|
||||
<MinimalTooltip>
|
||||
<EmptyState>
|
||||
<NotificationTitle>No notifications</NotificationTitle>
|
||||
Notifications will appear here when you get them.
|
||||
</EmptyState>
|
||||
</MinimalTooltip>
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* The component responsible for rendering the notifications.
|
||||
*/
|
||||
|
@ -363,26 +369,26 @@ export const Notifier = () => {
|
|||
|
||||
return (
|
||||
<NotifierContainer>
|
||||
{!pinNotifications ? null : toasts.length > 0 ? (
|
||||
<NotificationScroller onMouseEnter={startPause} onMouseLeave={endPause}>
|
||||
<div>
|
||||
{toasts.map((toast) => {
|
||||
return (
|
||||
<div key={toast.id}>
|
||||
{/* message is always a function in our case */}
|
||||
{/* @ts-ignore */}
|
||||
{toast.message(toast)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</NotificationScroller>
|
||||
) : (
|
||||
<EmptyState>
|
||||
<NotificationTitle>No notifications</NotificationTitle>
|
||||
Notifications will appear here when you get them.
|
||||
</EmptyState>
|
||||
)}
|
||||
{!pinNotifications
|
||||
? null
|
||||
: toasts.length > 0 && (
|
||||
<NotificationScroller
|
||||
onMouseEnter={startPause}
|
||||
onMouseLeave={endPause}
|
||||
>
|
||||
<div>
|
||||
{toasts.map((toast) => {
|
||||
return (
|
||||
<div key={toast.id}>
|
||||
{/* message is always a function in our case */}
|
||||
{/* @ts-ignore */}
|
||||
{toast.message(toast)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</NotificationScroller>
|
||||
)}
|
||||
<ButtonContainer align="side">
|
||||
{pinNotifications && toasts.length > 0 && (
|
||||
<Button
|
||||
|
|
|
@ -20,7 +20,10 @@ import DoubleChevronRight from '@theatre/studio/uiComponents/icons/DoubleChevron
|
|||
import ToolbarIconButton from '@theatre/studio/uiComponents/toolbar/ToolbarIconButton'
|
||||
import usePopover from '@theatre/studio/uiComponents/Popover/usePopover'
|
||||
import MoreMenu from './MoreMenu/MoreMenu'
|
||||
import {useNotifications} from '@theatre/studio/notify'
|
||||
import {
|
||||
useNotifications,
|
||||
useEmptyNotificationsTooltip,
|
||||
} from '@theatre/studio/notify'
|
||||
|
||||
const Container = styled.div`
|
||||
height: 36px;
|
||||
|
@ -147,6 +150,9 @@ const GlobalToolbar: React.FC = () => {
|
|||
|
||||
const {hasNotifications} = useNotifications()
|
||||
|
||||
const [notificationsTooltip, notificationsTriggerRef] =
|
||||
useEmptyNotificationsTooltip()
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<SubContainer>
|
||||
|
@ -174,7 +180,9 @@ const GlobalToolbar: React.FC = () => {
|
|||
<ExtensionToolbar showLeftDivider toolbarId="global" />
|
||||
</SubContainer>
|
||||
<SubContainer>
|
||||
<ToolbarIconButton
|
||||
{notificationsTooltip}
|
||||
<PinButton
|
||||
ref={notificationsTriggerRef as $IntentionalAny}
|
||||
onClick={() => {
|
||||
getStudio().transaction(({stateEditors, drafts}) => {
|
||||
stateEditors.studio.ahistoric.setPinNotifications(
|
||||
|
@ -182,10 +190,13 @@ const GlobalToolbar: React.FC = () => {
|
|||
)
|
||||
})
|
||||
}}
|
||||
icon={<Bell />}
|
||||
pinHintIcon={<Bell />}
|
||||
unpinHintIcon={<Bell />}
|
||||
pinned={useVal(getStudio().atomP.ahistoric.pinNotifications) ?? false}
|
||||
>
|
||||
<Bell />
|
||||
{hasNotifications && <HasUpdatesBadge type="warning" />}
|
||||
</ToolbarIconButton>
|
||||
</PinButton>
|
||||
{moreMenu.node}
|
||||
<ToolbarIconButton
|
||||
ref={moreMenuTriggerRef}
|
||||
|
|
|
@ -20,7 +20,10 @@ interface PinButtonProps extends ComponentPropsWithRef<'button'> {
|
|||
}
|
||||
|
||||
const PinButton = forwardRef<HTMLButtonElement, PinButtonProps>(
|
||||
({hint, pinned, icon, pinHintIcon, unpinHintIcon, ...props}, ref) => {
|
||||
(
|
||||
{children, hint, pinned, icon, pinHintIcon, unpinHintIcon, ...props},
|
||||
ref,
|
||||
) => {
|
||||
const [hovered, setHovered] = useState(false)
|
||||
|
||||
const showHint = hovered || hint
|
||||
|
@ -48,6 +51,7 @@ const PinButton = forwardRef<HTMLButtonElement, PinButtonProps>(
|
|||
? unpinHintIcon
|
||||
: icon}
|
||||
</div>
|
||||
{children}
|
||||
</Container>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -12,8 +12,7 @@ function Bell(props: React.SVGProps<SVGSVGElement>) {
|
|||
>
|
||||
<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}
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue