mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Improve the toggle buttons on the library menu
This commit is contained in:
parent
8851017100
commit
32b52efba7
3 changed files with 169 additions and 107 deletions
|
|
@ -0,0 +1,32 @@
|
|||
/* eslint-disable functional/no-class */
|
||||
/* eslint-disable functional/no-this-expression */
|
||||
import { IconProps } from './IconProps'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export class ToggleCaretDownIcon extends React.Component<IconProps> {
|
||||
render() {
|
||||
const size = (this.props.size || 26).toString()
|
||||
const color = (this.props.color || '#2A2A2A').toString()
|
||||
|
||||
return (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 26 26"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M6.57812 10.3379L12.8281 16.5879L19.0781 10.3379"
|
||||
stroke={color}
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* eslint-disable functional/no-class */
|
||||
/* eslint-disable functional/no-this-expression */
|
||||
import { IconProps } from './IconProps'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export class ToggleCaretLeftIcon extends React.Component<IconProps> {
|
||||
render() {
|
||||
const size = (this.props.size || 26).toString()
|
||||
const color = (this.props.color || '#2A2A2A').toString()
|
||||
|
||||
return (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 26 26"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M15.9531 6.77344L9.70312 13.0234L15.9531 19.2734"
|
||||
stroke={color}
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
import { ReactNode, useMemo, useState } from 'react'
|
||||
import { ReactNode, useMemo } from 'react'
|
||||
import { StyledText } from '../../elements/StyledText'
|
||||
import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
|
||||
import { Dropdown, DropdownOption } from '../../elements/DropdownElements'
|
||||
import { Button } from '../../elements/Button'
|
||||
import { CaretRight, Circle, DotsThree, Plus } from 'phosphor-react'
|
||||
import { CaretRight, Circle } from 'phosphor-react'
|
||||
import { useGetSubscriptionsQuery } from '../../../lib/networking/queries/useGetSubscriptionsQuery'
|
||||
import { useGetLabelsQuery } from '../../../lib/networking/queries/useGetLabelsQuery'
|
||||
import { Label } from '../../../lib/networking/fragments/labelFragment'
|
||||
|
|
@ -11,6 +10,10 @@ import { theme } from '../../tokens/stitches.config'
|
|||
import { useRegisterActions } from 'kbar'
|
||||
import { LogoBox } from '../../elements/LogoBox'
|
||||
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
|
||||
import { ToggleCaretDownIcon } from '../../elements/icons/ToggleCaretDownIcon'
|
||||
import { ToggleCaretLeftIcon } from '../../elements/icons/ToggleCaretLeftIcon'
|
||||
import Link from 'next/link'
|
||||
import { ArrowRightIcon } from '../../elements/icons/ArrowRightIcon'
|
||||
|
||||
export const LIBRARY_LEFT_MENU_WIDTH = '233px'
|
||||
|
||||
|
|
@ -130,16 +133,26 @@ function SavedSearches(props: LibraryFilterMenuProps): JSX.Element {
|
|||
[]
|
||||
)
|
||||
|
||||
const [collapsed, setCollapsed] = usePersistedState<boolean>({
|
||||
key: `--saved-searches-collapsed`,
|
||||
initialValue: false,
|
||||
})
|
||||
|
||||
return (
|
||||
<MenuPanel title="Saved Searches">
|
||||
{items.map((item) => (
|
||||
<FilterButton
|
||||
key={item.name}
|
||||
text={item.name}
|
||||
filterTerm={item.term}
|
||||
{...props}
|
||||
/>
|
||||
))}
|
||||
<MenuPanel
|
||||
title="Saved Searches"
|
||||
collapsed={collapsed}
|
||||
setCollapsed={setCollapsed}
|
||||
>
|
||||
{!collapsed &&
|
||||
items.map((item) => (
|
||||
<FilterButton
|
||||
key={item.name}
|
||||
text={item.name}
|
||||
filterTerm={item.term}
|
||||
{...props}
|
||||
/>
|
||||
))}
|
||||
|
||||
<Box css={{ height: '10px' }}></Box>
|
||||
</MenuPanel>
|
||||
|
|
@ -148,8 +161,8 @@ function SavedSearches(props: LibraryFilterMenuProps): JSX.Element {
|
|||
|
||||
function Subscriptions(props: LibraryFilterMenuProps): JSX.Element {
|
||||
const { subscriptions } = useGetSubscriptionsQuery()
|
||||
const [viewAll, setViewAll] = usePersistedState<boolean>({
|
||||
key: `--subscriptions-view-all`,
|
||||
const [collapsed, setCollapsed] = usePersistedState<boolean>({
|
||||
key: `--subscriptions-collapsed`,
|
||||
initialValue: false,
|
||||
})
|
||||
|
||||
|
|
@ -173,15 +186,10 @@ function Subscriptions(props: LibraryFilterMenuProps): JSX.Element {
|
|||
return (
|
||||
<MenuPanel
|
||||
title="Subscriptions"
|
||||
editTitle="Edit Subscriptions"
|
||||
editFunc={() => {
|
||||
window.location.href = '/settings/subscriptions'
|
||||
}}
|
||||
viewAll={() => {
|
||||
setViewAll(true)
|
||||
}}
|
||||
collapsed={collapsed}
|
||||
setCollapsed={setCollapsed}
|
||||
>
|
||||
{viewAll ? (
|
||||
{!collapsed ? (
|
||||
<>
|
||||
<FilterButton filterTerm={`label:RSS`} text="Feeds" {...props} />
|
||||
<FilterButton
|
||||
|
|
@ -199,7 +207,10 @@ function Subscriptions(props: LibraryFilterMenuProps): JSX.Element {
|
|||
/>
|
||||
)
|
||||
})}
|
||||
<ViewAllButton state={viewAll} setState={setViewAll} />
|
||||
<EditButton
|
||||
title="Edit Subscriptions"
|
||||
destination="/settings/subscriptions"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<SpanBox css={{ mb: '10px' }} />
|
||||
|
|
@ -210,8 +221,8 @@ function Subscriptions(props: LibraryFilterMenuProps): JSX.Element {
|
|||
|
||||
function Labels(props: LibraryFilterMenuProps): JSX.Element {
|
||||
const { labels } = useGetLabelsQuery()
|
||||
const [viewAll, setViewAll] = usePersistedState<boolean>({
|
||||
key: `--labels-view-all`,
|
||||
const [collapsed, setCollapsed] = usePersistedState<boolean>({
|
||||
key: `--labels-collapsed`,
|
||||
initialValue: false,
|
||||
})
|
||||
|
||||
|
|
@ -224,16 +235,18 @@ function Labels(props: LibraryFilterMenuProps): JSX.Element {
|
|||
return (
|
||||
<MenuPanel
|
||||
title="Labels"
|
||||
editTitle="Edit Labels"
|
||||
hideBottomBorder={true}
|
||||
editFunc={() => {
|
||||
window.location.href = '/settings/labels'
|
||||
}}
|
||||
collapsed={collapsed}
|
||||
setCollapsed={setCollapsed}
|
||||
>
|
||||
{sortedLabels.slice(0, viewAll ? undefined : 4).map((item) => {
|
||||
return <LabelButton key={item.id} label={item} {...props} />
|
||||
})}
|
||||
<ViewAllButton state={viewAll} setState={setViewAll} />
|
||||
{!collapsed && (
|
||||
<>
|
||||
{sortedLabels.map((item) => {
|
||||
return <LabelButton key={item.id} label={item} {...props} />
|
||||
})}
|
||||
<EditButton title="Edit Labels" destination="/settings/labels" />
|
||||
</>
|
||||
)}
|
||||
</MenuPanel>
|
||||
)
|
||||
}
|
||||
|
|
@ -241,10 +254,11 @@ function Labels(props: LibraryFilterMenuProps): JSX.Element {
|
|||
type MenuPanelProps = {
|
||||
title: string
|
||||
children: ReactNode
|
||||
editFunc?: () => void
|
||||
editTitle?: string
|
||||
|
||||
hideBottomBorder?: boolean
|
||||
viewAll?: () => void
|
||||
|
||||
collapsed: boolean
|
||||
setCollapsed: (collapsed: boolean) => void
|
||||
}
|
||||
|
||||
function MenuPanel(props: MenuPanelProps): JSX.Element {
|
||||
|
|
@ -278,57 +292,32 @@ function MenuPanel(props: MenuPanelProps): JSX.Element {
|
|||
</StyledText>
|
||||
<SpanBox
|
||||
css={{
|
||||
mt: '15px',
|
||||
mt: '17px',
|
||||
mr: '-2px',
|
||||
marginLeft: 'auto',
|
||||
height: '100%',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
>
|
||||
{props.editTitle && props.editFunc && (
|
||||
<Dropdown
|
||||
triggerElement={
|
||||
<Box
|
||||
css={{
|
||||
display: 'flex',
|
||||
height: '30px',
|
||||
width: '30px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '1000px',
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
bg: '$thBackground4',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DotsThree
|
||||
size={25}
|
||||
weight="bold"
|
||||
color={theme.colors.thTextSubtle2.toString()}
|
||||
/>
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
{props.viewAll && (
|
||||
<DropdownOption
|
||||
title="View All"
|
||||
onSelect={() => {
|
||||
if (props.viewAll) {
|
||||
props.viewAll()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<DropdownOption
|
||||
title={props.editTitle}
|
||||
onSelect={() => {
|
||||
if (props.editFunc) {
|
||||
props.editFunc()
|
||||
}
|
||||
}}
|
||||
<Button
|
||||
style="articleActionIcon"
|
||||
onClick={(event) => {
|
||||
props.setCollapsed(!props.collapsed)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
{props.collapsed ? (
|
||||
<ToggleCaretLeftIcon
|
||||
size={15}
|
||||
color={theme.colors.thLibraryMenuPrimary.toString()}
|
||||
/>
|
||||
</Dropdown>
|
||||
)}
|
||||
) : (
|
||||
<ToggleCaretDownIcon
|
||||
size={15}
|
||||
color={theme.colors.thLibraryMenuPrimary.toString()}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
</SpanBox>
|
||||
</HStack>
|
||||
{props.children}
|
||||
|
|
@ -492,34 +481,43 @@ function LabelButton(props: LabelButtonProps): JSX.Element {
|
|||
)
|
||||
}
|
||||
|
||||
type ViewAllButtonProps = {
|
||||
state: boolean
|
||||
setState: (state: boolean) => void
|
||||
type EditButtonProps = {
|
||||
title: string
|
||||
destination: string
|
||||
}
|
||||
|
||||
function ViewAllButton(props: ViewAllButtonProps): JSX.Element {
|
||||
function EditButton(props: EditButtonProps): JSX.Element {
|
||||
return (
|
||||
<Button
|
||||
style="ghost"
|
||||
css={{
|
||||
display: 'flex',
|
||||
pl: '10px',
|
||||
color: '#898989',
|
||||
fontWeight: '600',
|
||||
fontSize: '12px',
|
||||
py: '20px',
|
||||
gap: '2px',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
onClick={(e) => {
|
||||
props.setState(!props.state)
|
||||
e.preventDefault()
|
||||
}}
|
||||
>
|
||||
{props.state ? 'Hide' : 'View All'}
|
||||
{props.state ? null : (
|
||||
<CaretRight size={12} color="#898989" weight="bold" />
|
||||
)}
|
||||
</Button>
|
||||
<Link href={props.destination} passHref>
|
||||
<SpanBox
|
||||
css={{
|
||||
ml: '10px',
|
||||
mb: '10px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '2px',
|
||||
'&:hover': {
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
|
||||
width: '100%',
|
||||
maxWidth: '100%',
|
||||
height: '32px',
|
||||
|
||||
fontSize: '14px',
|
||||
fontWeight: 'regular',
|
||||
fontFamily: '$display',
|
||||
color: '$thLibraryMenuUnselected',
|
||||
verticalAlign: 'middle',
|
||||
borderRadius: '3px',
|
||||
cursor: 'pointer',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{props.title}
|
||||
</SpanBox>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue