chore: show preferences notification count bubble on mobile
This commit is contained in:
@@ -7,7 +7,7 @@ import { PreferencePaneId } from '../Preferences/PreferenceId'
|
|||||||
|
|
||||||
export class StatusService extends AbstractService<StatusServiceEvent, string> implements StatusServiceInterface {
|
export class StatusService extends AbstractService<StatusServiceEvent, string> implements StatusServiceInterface {
|
||||||
private preferencesBubbleCounts: Record<PreferencePaneId, number> = {
|
private preferencesBubbleCounts: Record<PreferencePaneId, number> = {
|
||||||
general: 0,
|
general: 1,
|
||||||
account: 0,
|
account: 0,
|
||||||
security: 0,
|
security: 0,
|
||||||
'home-server': 0,
|
'home-server': 0,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { useApplication } from '../ApplicationProvider'
|
|||||||
import { useCommandService } from '../CommandProvider'
|
import { useCommandService } from '../CommandProvider'
|
||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import StyledTooltip from '../StyledTooltip/StyledTooltip'
|
import StyledTooltip from '../StyledTooltip/StyledTooltip'
|
||||||
|
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||||
|
import RoundIconButton from '../Button/RoundIconButton'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
openPreferences: (openWhatsNew: boolean) => void
|
openPreferences: (openWhatsNew: boolean) => void
|
||||||
@@ -46,6 +48,21 @@ const PreferencesButton = ({ openPreferences }: Props) => {
|
|||||||
})
|
})
|
||||||
}, [application.status])
|
}, [application.status])
|
||||||
|
|
||||||
|
const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
|
||||||
|
|
||||||
|
if (isMobileScreen) {
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<RoundIconButton className="ml-2.5 bg-default" onClick={onClick} label="Go to preferences" icon="tune" />
|
||||||
|
{bubbleCount && (
|
||||||
|
<div className="absolute right-0 top-0 aspect-square -translate-y-1/2 translate-x-2 rounded-full border border-info-contrast bg-info px-2 py-0.5 text-[0.65rem] font-bold text-info-contrast">
|
||||||
|
{bubbleCount}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTooltip label={`Open preferences (${shortcut})`}>
|
<StyledTooltip label={`Open preferences (${shortcut})`}>
|
||||||
<button onClick={onClick} className="group relative flex h-full w-8 cursor-pointer items-center justify-center">
|
<button onClick={onClick} className="group relative flex h-full w-8 cursor-pointer items-center justify-center">
|
||||||
|
|||||||
@@ -1,22 +1,43 @@
|
|||||||
import { PaneLayout } from '@/Controllers/PaneController/PaneLayout'
|
import { PaneLayout } from '@/Controllers/PaneController/PaneLayout'
|
||||||
import useIsTabletOrMobileScreen from '@/Hooks/useIsTabletOrMobileScreen'
|
import useIsTabletOrMobileScreen from '@/Hooks/useIsTabletOrMobileScreen'
|
||||||
import { classNames } from '@standardnotes/snjs'
|
import { StatusServiceEvent, classNames } from '@standardnotes/snjs'
|
||||||
import RoundIconButton from '../Button/RoundIconButton'
|
import RoundIconButton from '../Button/RoundIconButton'
|
||||||
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
|
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { useApplication } from '../ApplicationProvider'
|
||||||
|
|
||||||
/** This button is displayed in the items list header */
|
/** This button is displayed in the items list header */
|
||||||
export const NavigationMenuButton = () => {
|
export const NavigationMenuButton = () => {
|
||||||
|
const application = useApplication()
|
||||||
const { setPaneLayout } = useResponsiveAppPane()
|
const { setPaneLayout } = useResponsiveAppPane()
|
||||||
const { isTabletOrMobile } = useIsTabletOrMobileScreen()
|
const { isTabletOrMobile, isMobile } = useIsTabletOrMobileScreen()
|
||||||
|
|
||||||
|
const [bubbleCount, setBubbleCount] = useState<string | undefined>(() =>
|
||||||
|
application.status.totalPreferencesBubbleCount.toString(),
|
||||||
|
)
|
||||||
|
useEffect(() => {
|
||||||
|
return application.status.addEventObserver((event, message) => {
|
||||||
|
if (event !== StatusServiceEvent.PreferencesBubbleCountChanged) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setBubbleCount(message)
|
||||||
|
})
|
||||||
|
}, [application.status])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RoundIconButton
|
<div className={classNames(isTabletOrMobile ? 'flex' : 'hidden', 'relative h-10 w-10', 'mr-3')}>
|
||||||
className={classNames(isTabletOrMobile ? 'flex' : 'hidden', 'mr-3')}
|
<RoundIconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPaneLayout(PaneLayout.TagSelection)
|
setPaneLayout(PaneLayout.TagSelection)
|
||||||
}}
|
}}
|
||||||
label="Open navigation menu"
|
label="Open navigation menu"
|
||||||
icon="menu-variant"
|
icon="menu-variant"
|
||||||
/>
|
/>
|
||||||
|
{isMobile && bubbleCount && (
|
||||||
|
<div className="absolute -right-2 -top-2 aspect-square rounded-full border border-info-contrast bg-info px-2 py-0.5 text-[0.65rem] font-bold text-info-contrast">
|
||||||
|
{bubbleCount}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { mergeRefs } from '@/Hooks/mergeRefs'
|
|||||||
import { useAvailableSafeAreaPadding } from '@/Hooks/useSafeAreaPadding'
|
import { useAvailableSafeAreaPadding } from '@/Hooks/useSafeAreaPadding'
|
||||||
import QuickSettingsButton from '../Footer/QuickSettingsButton'
|
import QuickSettingsButton from '../Footer/QuickSettingsButton'
|
||||||
import VaultSelectionButton from '../Footer/VaultSelectionButton'
|
import VaultSelectionButton from '../Footer/VaultSelectionButton'
|
||||||
|
import PreferencesButton from '../Footer/PreferencesButton'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -121,14 +122,7 @@ const Navigation = forwardRef<HTMLDivElement, Props>(({ application, className,
|
|||||||
icon="lock-filled"
|
icon="lock-filled"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<RoundIconButton
|
<PreferencesButton openPreferences={() => application.preferencesController.openPreferences()} />
|
||||||
className="ml-2.5 bg-default"
|
|
||||||
onClick={() => {
|
|
||||||
application.preferencesController.openPreferences()
|
|
||||||
}}
|
|
||||||
label="Go to preferences"
|
|
||||||
icon="tune"
|
|
||||||
/>
|
|
||||||
<QuickSettingsButton application={application} isMobileNavigation />
|
<QuickSettingsButton application={application} isMobileNavigation />
|
||||||
{application.featuresController.isEntitledToVaults() && <VaultSelectionButton isMobileNavigation />}
|
{application.featuresController.isEntitledToVaults() && <VaultSelectionButton isMobileNavigation />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user