mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Add Rules menu item to dropdown menu
This commit is contained in:
parent
c8b687fa63
commit
cd42ce56d8
1 changed files with 313 additions and 305 deletions
|
|
@ -6,9 +6,9 @@ import { currentTheme, updateTheme } from '../../lib/themeUpdater'
|
|||
import { Avatar } from '../elements/Avatar'
|
||||
import { AvatarDropdown } from '../elements/AvatarDropdown'
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownOption,
|
||||
DropdownSeparator,
|
||||
Dropdown,
|
||||
DropdownOption,
|
||||
DropdownSeparator,
|
||||
} from '../elements/DropdownElements'
|
||||
import GridLayoutIcon from '../elements/images/GridLayoutIcon'
|
||||
import ListLayoutIcon from '../elements/images/ListLayoutIcon'
|
||||
|
|
@ -18,327 +18,335 @@ import { styled, theme, ThemeId } from '../tokens/stitches.config'
|
|||
import { LayoutType } from './homeFeed/HomeFeedContainer'
|
||||
|
||||
type PrimaryDropdownProps = {
|
||||
children?: ReactNode
|
||||
showThemeSection: boolean
|
||||
children?: ReactNode
|
||||
showThemeSection: boolean
|
||||
|
||||
layout?: LayoutType
|
||||
updateLayout?: (layout: LayoutType) => void
|
||||
layout?: LayoutType
|
||||
updateLayout?: (layout: LayoutType) => void
|
||||
|
||||
showAddLinkModal?: () => void
|
||||
showAddLinkModal?: () => void
|
||||
}
|
||||
|
||||
export type HeaderDropdownAction =
|
||||
| 'navigate-to-install'
|
||||
| 'navigate-to-feeds'
|
||||
| 'navigate-to-emails'
|
||||
| 'navigate-to-labels'
|
||||
| 'navigate-to-profile'
|
||||
| 'navigate-to-subscriptions'
|
||||
| 'navigate-to-api'
|
||||
| 'navigate-to-integrations'
|
||||
| 'navigate-to-saved-searches'
|
||||
| 'increaseFontSize'
|
||||
| 'decreaseFontSize'
|
||||
| 'logout'
|
||||
| 'navigate-to-install'
|
||||
| 'navigate-to-feeds'
|
||||
| 'navigate-to-emails'
|
||||
| 'navigate-to-labels'
|
||||
| 'navigate-to-rules'
|
||||
| 'navigate-to-profile'
|
||||
| 'navigate-to-subscriptions'
|
||||
| 'navigate-to-api'
|
||||
| 'navigate-to-integrations'
|
||||
| 'navigate-to-saved-searches'
|
||||
| 'increaseFontSize'
|
||||
| 'decreaseFontSize'
|
||||
| 'logout'
|
||||
|
||||
export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element {
|
||||
const { viewerData } = useGetViewerQuery()
|
||||
const router = useRouter()
|
||||
const { viewerData } = useGetViewerQuery()
|
||||
const router = useRouter()
|
||||
|
||||
const headerDropdownActionHandler = useCallback(
|
||||
(action: HeaderDropdownAction) => {
|
||||
switch (action) {
|
||||
case 'navigate-to-install':
|
||||
router.push('/settings/installation')
|
||||
break
|
||||
case 'navigate-to-feeds':
|
||||
router.push('/settings/feeds')
|
||||
break
|
||||
case 'navigate-to-emails':
|
||||
router.push('/settings/emails')
|
||||
break
|
||||
case 'navigate-to-labels':
|
||||
router.push('/settings/labels')
|
||||
break
|
||||
case 'navigate-to-subscriptions':
|
||||
router.push('/settings/subscriptions')
|
||||
break
|
||||
case 'navigate-to-api':
|
||||
router.push('/settings/api')
|
||||
break
|
||||
case 'navigate-to-integrations':
|
||||
router.push('/settings/integrations')
|
||||
break
|
||||
case 'navigate-to-saved-searches':
|
||||
router.push('/settings/saved-searches')
|
||||
break
|
||||
case 'logout':
|
||||
document.dispatchEvent(new Event('logout'))
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
[router]
|
||||
)
|
||||
const headerDropdownActionHandler = useCallback(
|
||||
(action: HeaderDropdownAction) => {
|
||||
switch (action) {
|
||||
case 'navigate-to-install':
|
||||
router.push('/settings/installation')
|
||||
break
|
||||
case 'navigate-to-feeds':
|
||||
router.push('/settings/feeds')
|
||||
break
|
||||
case 'navigate-to-emails':
|
||||
router.push('/settings/emails')
|
||||
break
|
||||
case 'navigate-to-labels':
|
||||
router.push('/settings/labels')
|
||||
break
|
||||
case 'navigate-to-rules':
|
||||
router.push('/settings/rules')
|
||||
break
|
||||
case 'navigate-to-subscriptions':
|
||||
router.push('/settings/subscriptions')
|
||||
break
|
||||
case 'navigate-to-api':
|
||||
router.push('/settings/api')
|
||||
break
|
||||
case 'navigate-to-integrations':
|
||||
router.push('/settings/integrations')
|
||||
break
|
||||
case 'navigate-to-saved-searches':
|
||||
router.push('/settings/saved-searches')
|
||||
break
|
||||
case 'logout':
|
||||
document.dispatchEvent(new Event('logout'))
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
[router]
|
||||
)
|
||||
|
||||
if (!viewerData?.me) {
|
||||
return <></>
|
||||
}
|
||||
if (!viewerData?.me) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
triggerElement={
|
||||
props.children ?? (
|
||||
<AvatarDropdown userInitials={viewerData?.me?.name.charAt(0) ?? ''} />
|
||||
)
|
||||
}
|
||||
css={{ width: '240px' }}
|
||||
>
|
||||
<HStack
|
||||
alignment="center"
|
||||
distribution="start"
|
||||
css={{
|
||||
width: '100%',
|
||||
height: '64px',
|
||||
p: '15px',
|
||||
gap: '15px',
|
||||
cursor: 'pointer',
|
||||
mouseEvents: 'all',
|
||||
}}
|
||||
onClick={(event) => {
|
||||
router.push('/settings/account')
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
imageURL={viewerData.me.profile.pictureUrl}
|
||||
height="40px"
|
||||
fallbackText={viewerData?.me?.name.charAt(0) ?? ''}
|
||||
/>
|
||||
<VStack
|
||||
css={{ height: '40px', maxWidth: '240px' }}
|
||||
alignment="start"
|
||||
distribution="around"
|
||||
return (
|
||||
<Dropdown
|
||||
triggerElement={
|
||||
props.children ?? (
|
||||
<AvatarDropdown userInitials={viewerData?.me?.name.charAt(0) ?? ''} />
|
||||
)
|
||||
}
|
||||
css={{ width: '240px' }}
|
||||
>
|
||||
{viewerData.me && (
|
||||
<>
|
||||
<StyledText
|
||||
<HStack
|
||||
alignment="center"
|
||||
distribution="start"
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '500',
|
||||
color: '$thTextContrast2',
|
||||
m: '0px',
|
||||
p: '0px',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%',
|
||||
height: '64px',
|
||||
p: '15px',
|
||||
gap: '15px',
|
||||
cursor: 'pointer',
|
||||
mouseEvents: 'all',
|
||||
}}
|
||||
>
|
||||
{viewerData.me.name}
|
||||
</StyledText>
|
||||
<StyledText
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '400',
|
||||
color: '#898989',
|
||||
m: '0px',
|
||||
p: '0px',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
onClick={(event) => {
|
||||
router.push('/settings/account')
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
{`@${viewerData.me.profile.username}`}
|
||||
</StyledText>
|
||||
</>
|
||||
)}
|
||||
</VStack>
|
||||
</HStack>
|
||||
<DropdownSeparator />
|
||||
{props.showThemeSection && <ThemeSection {...props} />}
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-install')}
|
||||
title="Install"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-feeds')}
|
||||
title="Feeds"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-emails')}
|
||||
title="Emails"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-labels')}
|
||||
title="Labels"
|
||||
/>
|
||||
{props.showAddLinkModal && (
|
||||
<>
|
||||
<DropdownSeparator />
|
||||
>
|
||||
<Avatar
|
||||
imageURL={viewerData.me.profile.pictureUrl}
|
||||
height="40px"
|
||||
fallbackText={viewerData?.me?.name.charAt(0) ?? ''}
|
||||
/>
|
||||
<VStack
|
||||
css={{ height: '40px', maxWidth: '240px' }}
|
||||
alignment="start"
|
||||
distribution="around"
|
||||
>
|
||||
{viewerData.me && (
|
||||
<>
|
||||
<StyledText
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '500',
|
||||
color: '$thTextContrast2',
|
||||
m: '0px',
|
||||
p: '0px',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{viewerData.me.name}
|
||||
</StyledText>
|
||||
<StyledText
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '400',
|
||||
color: '#898989',
|
||||
m: '0px',
|
||||
p: '0px',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{`@${viewerData.me.profile.username}`}
|
||||
</StyledText>
|
||||
</>
|
||||
)}
|
||||
</VStack>
|
||||
</HStack>
|
||||
<DropdownSeparator />
|
||||
{props.showThemeSection && <ThemeSection {...props} />}
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-install')}
|
||||
title="Install"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-feeds')}
|
||||
title="Feeds"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-emails')}
|
||||
title="Emails"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-labels')}
|
||||
title="Labels"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-rules')}
|
||||
title="Rules"
|
||||
/>
|
||||
{props.showAddLinkModal && (
|
||||
<>
|
||||
<DropdownSeparator />
|
||||
|
||||
<DropdownOption
|
||||
onSelect={() => props.showAddLinkModal && props.showAddLinkModal()}
|
||||
title="Add Link"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-api')}
|
||||
title="API Keys"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-integrations')}
|
||||
title="Integrations"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => window.open('https://docs.omnivore.app', '_blank')}
|
||||
title="Documentation"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => window.Intercom('show')}
|
||||
title="Feedback"
|
||||
/>
|
||||
<DropdownSeparator />
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('logout')}
|
||||
title="Logout"
|
||||
/>
|
||||
</Dropdown>
|
||||
)
|
||||
<DropdownOption
|
||||
onSelect={() => props.showAddLinkModal && props.showAddLinkModal()}
|
||||
title="Add Link"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-api')}
|
||||
title="API Keys"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('navigate-to-integrations')}
|
||||
title="Integrations"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => window.open('https://docs.omnivore.app', '_blank')}
|
||||
title="Documentation"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => window.Intercom('show')}
|
||||
title="Feedback"
|
||||
/>
|
||||
<DropdownSeparator />
|
||||
<DropdownOption
|
||||
onSelect={() => headerDropdownActionHandler('logout')}
|
||||
title="Logout"
|
||||
/>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
|
||||
export const StyledToggleButton = styled('button', {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '$thTextContrast2',
|
||||
backgroundColor: 'transparent',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
width: '70px',
|
||||
height: '100%',
|
||||
borderRadius: '5px',
|
||||
fontSize: '12px',
|
||||
fontFamily: '$inter',
|
||||
gap: '5px',
|
||||
m: '2px',
|
||||
'&:hover': {
|
||||
opacity: 0.8,
|
||||
},
|
||||
'&[data-state="on"]': {
|
||||
bg: '$thBackground',
|
||||
},
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '$thTextContrast2',
|
||||
backgroundColor: 'transparent',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
width: '70px',
|
||||
height: '100%',
|
||||
borderRadius: '5px',
|
||||
fontSize: '12px',
|
||||
fontFamily: '$inter',
|
||||
gap: '5px',
|
||||
m: '2px',
|
||||
'&:hover': {
|
||||
opacity: 0.8,
|
||||
},
|
||||
'&[data-state="on"]': {
|
||||
bg: '$thBackground',
|
||||
},
|
||||
})
|
||||
|
||||
function ThemeSection(props: PrimaryDropdownProps): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<VStack>
|
||||
<HStack
|
||||
alignment="center"
|
||||
css={{
|
||||
width: '100%',
|
||||
px: '15px',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '400',
|
||||
cursor: 'default',
|
||||
color: '$utilityTextDefault',
|
||||
}}
|
||||
>
|
||||
Mode
|
||||
</StyledText>
|
||||
<Box
|
||||
css={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bg: '$thBackground4',
|
||||
borderRadius: '5px',
|
||||
height: '34px',
|
||||
p: '3px',
|
||||
px: '1px',
|
||||
}}
|
||||
>
|
||||
<StyledToggleButton
|
||||
data-state={currentTheme() != ThemeId.Dark ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
updateTheme(ThemeId.Light)
|
||||
}}
|
||||
>
|
||||
Light
|
||||
<Sun size={15} color={theme.colors.thTextContrast2.toString()} />
|
||||
</StyledToggleButton>
|
||||
<StyledToggleButton
|
||||
data-state={currentTheme() == ThemeId.Dark ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
updateTheme(ThemeId.Dark)
|
||||
}}
|
||||
>
|
||||
Dark
|
||||
<Moon size={15} color={theme.colors.thTextContrast2.toString()} />
|
||||
</StyledToggleButton>
|
||||
</Box>
|
||||
</HStack>
|
||||
{props.layout && (
|
||||
<HStack
|
||||
alignment="center"
|
||||
css={{
|
||||
width: '100%',
|
||||
px: '15px',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '400',
|
||||
cursor: 'default',
|
||||
color: '$utilityTextDefault',
|
||||
}}
|
||||
>
|
||||
Layout
|
||||
</StyledText>
|
||||
<Box
|
||||
css={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bg: '$thBackground4',
|
||||
borderRadius: '5px',
|
||||
height: '34px',
|
||||
p: '3px',
|
||||
px: '1px',
|
||||
}}
|
||||
>
|
||||
<StyledToggleButton
|
||||
data-state={props.layout == 'LIST_LAYOUT' ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
props.updateLayout && props.updateLayout('LIST_LAYOUT')
|
||||
}}
|
||||
>
|
||||
<ListLayoutIcon
|
||||
color={theme.colors.thTextContrast2.toString()}
|
||||
/>
|
||||
</StyledToggleButton>
|
||||
<StyledToggleButton
|
||||
data-state={props.layout == 'GRID_LAYOUT' ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
props.updateLayout && props.updateLayout('GRID_LAYOUT')
|
||||
}}
|
||||
>
|
||||
<GridLayoutIcon
|
||||
color={theme.colors.thTextContrast2.toString()}
|
||||
/>
|
||||
</StyledToggleButton>
|
||||
</Box>
|
||||
</HStack>
|
||||
)}
|
||||
</VStack>
|
||||
<DropdownSeparator />
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<VStack>
|
||||
<HStack
|
||||
alignment="center"
|
||||
css={{
|
||||
width: '100%',
|
||||
px: '15px',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '400',
|
||||
cursor: 'default',
|
||||
color: '$utilityTextDefault',
|
||||
}}
|
||||
>
|
||||
Mode
|
||||
</StyledText>
|
||||
<Box
|
||||
css={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bg: '$thBackground4',
|
||||
borderRadius: '5px',
|
||||
height: '34px',
|
||||
p: '3px',
|
||||
px: '1px',
|
||||
}}
|
||||
>
|
||||
<StyledToggleButton
|
||||
data-state={currentTheme() != ThemeId.Dark ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
updateTheme(ThemeId.Light)
|
||||
}}
|
||||
>
|
||||
Light
|
||||
<Sun size={15} color={theme.colors.thTextContrast2.toString()} />
|
||||
</StyledToggleButton>
|
||||
<StyledToggleButton
|
||||
data-state={currentTheme() == ThemeId.Dark ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
updateTheme(ThemeId.Dark)
|
||||
}}
|
||||
>
|
||||
Dark
|
||||
<Moon size={15} color={theme.colors.thTextContrast2.toString()} />
|
||||
</StyledToggleButton>
|
||||
</Box>
|
||||
</HStack>
|
||||
{props.layout && (
|
||||
<HStack
|
||||
alignment="center"
|
||||
css={{
|
||||
width: '100%',
|
||||
px: '15px',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
css={{
|
||||
fontSize: '14px',
|
||||
fontWeight: '400',
|
||||
cursor: 'default',
|
||||
color: '$utilityTextDefault',
|
||||
}}
|
||||
>
|
||||
Layout
|
||||
</StyledText>
|
||||
<Box
|
||||
css={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bg: '$thBackground4',
|
||||
borderRadius: '5px',
|
||||
height: '34px',
|
||||
p: '3px',
|
||||
px: '1px',
|
||||
}}
|
||||
>
|
||||
<StyledToggleButton
|
||||
data-state={props.layout == 'LIST_LAYOUT' ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
props.updateLayout && props.updateLayout('LIST_LAYOUT')
|
||||
}}
|
||||
>
|
||||
<ListLayoutIcon
|
||||
color={theme.colors.thTextContrast2.toString()}
|
||||
/>
|
||||
</StyledToggleButton>
|
||||
<StyledToggleButton
|
||||
data-state={props.layout == 'GRID_LAYOUT' ? 'on' : 'off'}
|
||||
onClick={() => {
|
||||
props.updateLayout && props.updateLayout('GRID_LAYOUT')
|
||||
}}
|
||||
>
|
||||
<GridLayoutIcon
|
||||
color={theme.colors.thTextContrast2.toString()}
|
||||
/>
|
||||
</StyledToggleButton>
|
||||
</Box>
|
||||
</HStack>
|
||||
)}
|
||||
</VStack>
|
||||
<DropdownSeparator />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue