Shortcuts editor

This commit is contained in:
Jackson Harper
2024-08-07 14:37:39 +08:00
parent 332583d5c1
commit 3f73a969f4

View File

@ -4,6 +4,7 @@ import {
useEffect,
useMemo,
useReducer,
useRef,
useState,
} from 'react'
import { applyStoredTheme } from '../../lib/themeUpdater'
@ -35,7 +36,12 @@ import { SavedSearch } from '../../lib/networking/fragments/savedSearchFragment'
import { escapeQuotes } from '../../utils/helper'
import { useGetLabels } from '../../lib/networking/labels/useLabels'
import { useGetSavedSearches } from '../../lib/networking/savedsearches/useSavedSearches'
import { Shortcut } from '../../lib/networking/shortcuts/useShortcuts'
import {
Shortcut,
useResetShortcuts,
} from '../../lib/networking/shortcuts/useShortcuts'
import { ShortcutsTree } from '../../components/templates/ShortcutsTree'
import { TreeApi } from 'react-arborist'
type ListAction = 'RESET' | 'ADD_ITEM' | 'REMOVE_ITEM'
@ -147,8 +153,11 @@ export default function Shortcuts(): JSX.Element {
<StyledText style="fixedHeadline" css={{ my: '6px' }}>
Shortcuts
</StyledText>
<StyledText style="caption" css={{}}>
Use shortcuts to access your most important reads quickly
<StyledText css={{}}>
Use shortcuts to access your most important reads quickly. You can
create folders for your shortcuts, remove shortcuts, and select
items from your labels, subscriptions, and saved searches to be
added to your shortcuts.
</StyledText>
</Box>
<HStack
@ -281,161 +290,175 @@ const AvailableItems = (props: ListProps): JSX.Element => {
return (
<VStack
css={{
width: '420px',
py: '30px',
pl: '28px', // becomes labels have some margin built in
pr: '30px',
m: '0px',
gap: '10px',
bg: '$thLeftMenuBackground',
width: '100%',
maxWidth: '400px',
px: '0px',
pb: '25px',
}}
alignment="start"
distribution="start"
>
<StyledText style="settingsSection">Saved Searches</StyledText>
{sortedsavedSearches?.map((search) => {
return (
<Button
style="plainIcon"
css={{
display: 'flex',
width: '100%',
p: '5px',
alignItems: 'center',
borderRadius: '5px',
'&:hover': {
bg: '$thLibrarySelectionColor',
color: '$thLibraryMenuSecondary',
},
}}
key={`search-${search.id}`}
onClick={(event) => {
const item: Shortcut = {
id: search.id,
name: search.name,
type: 'label',
section: 'library',
filter: search.filter,
}
props.dispatchList({
item,
type: searchSelected(search) ? 'REMOVE_ITEM' : 'ADD_ITEM',
})
<StyledText style="settingsSection">Available items</StyledText>
<VStack
css={{
width: '420px',
py: '30px',
pl: '28px', // becomes labels have some margin built in
pr: '30px',
gap: '10px',
bg: '$thLeftMenuBackground',
}}
>
<StyledText style="settingsSection">Saved Searches</StyledText>
{sortedsavedSearches?.map((search) => {
return (
<Button
style="plainIcon"
css={{
display: 'flex',
width: '100%',
p: '5px',
alignItems: 'center',
borderRadius: '5px',
'&:hover': {
bg: '$thLibrarySelectionColor',
color: '$thLibraryMenuSecondary',
},
}}
key={`search-${search.id}`}
onClick={(event) => {
const item: Shortcut = {
id: search.id,
name: search.name,
type: 'label',
section: 'library',
filter: search.filter,
}
props.dispatchList({
item,
type: searchSelected(search) ? 'REMOVE_ITEM' : 'ADD_ITEM',
})
event.preventDefault()
}}
>
{' '}
<StyledText style="settingsItem">{search.name}</StyledText>
<SpanBox css={{ ml: 'auto' }}>
{searchSelected(search) ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
</SpanBox>
</Button>
)
})}
<SectionSeparator />
event.preventDefault()
}}
>
{' '}
<StyledText style="settingsItem">{search.name}</StyledText>
<SpanBox css={{ ml: 'auto' }}>
{searchSelected(search) ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
</SpanBox>
</Button>
)
})}
<SectionSeparator />
<StyledText style="settingsSection">Labels</StyledText>
{sortedLabels.map((label) => {
return (
<Button
style="plainIcon"
css={{
display: 'flex',
width: '100%',
p: '5px',
alignItems: 'center',
borderRadius: '5px',
'&:hover': {
bg: '$thLibrarySelectionColor',
color: '$thLibraryMenuSecondary',
},
}}
key={`label-${label.id}`}
onClick={(event) => {
const item: Shortcut = {
id: label.id,
type: 'label',
label: label,
section: 'library',
name: label.name,
filter: `label:\"${escapeQuotes(label.name)}\"`,
}
props.dispatchList({
item,
type: labelSelected(label) ? 'REMOVE_ITEM' : 'ADD_ITEM',
})
<StyledText style="settingsSection">Labels</StyledText>
{sortedLabels.map((label) => {
return (
<Button
style="plainIcon"
css={{
display: 'flex',
width: '100%',
p: '5px',
alignItems: 'center',
borderRadius: '5px',
'&:hover': {
bg: '$thLibrarySelectionColor',
color: '$thLibraryMenuSecondary',
},
}}
key={`label-${label.id}`}
onClick={(event) => {
const item: Shortcut = {
id: label.id,
type: 'label',
label: label,
section: 'library',
name: label.name,
filter: `label:\"${escapeQuotes(label.name)}\"`,
}
props.dispatchList({
item,
type: labelSelected(label) ? 'REMOVE_ITEM' : 'ADD_ITEM',
})
event.preventDefault()
}}
>
<LabelChip text={label.name} color={label.color} />
<SpanBox css={{ ml: 'auto' }}>
{labelSelected(label) ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
</SpanBox>
</Button>
)
})}
<SectionSeparator />
event.preventDefault()
}}
>
<LabelChip text={label.name} color={label.color} />
<SpanBox css={{ ml: 'auto' }}>
{labelSelected(label) ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
</SpanBox>
</Button>
)
})}
<SectionSeparator />
<StyledText style="settingsSection">Subscriptions</StyledText>
{sortedSubscriptions.map((subscription) => {
return (
<Button
style="plainIcon"
css={{
display: 'flex',
width: '100%',
p: '5px',
alignItems: 'center',
borderRadius: '5px',
'&:hover': {
bg: '$thLibrarySelectionColor',
color: '$thLibraryMenuSecondary',
},
}}
key={`subscription-${subscription.id}`}
onClick={(event) => {
const item: Shortcut = {
id: subscription.id,
section: 'subscriptions',
name: subscription.name,
icon: subscription.icon,
type:
subscription.type == SubscriptionType.NEWSLETTER
? 'newsletter'
: 'feed',
filter:
subscription.type == SubscriptionType.NEWSLETTER
? `subscription:\"${escapeQuotes(subscription.name)}\"`
: `rss:\"${subscription.url}\"`,
}
props.dispatchList({
item,
type: subscriptionSelected(subscription)
? 'REMOVE_ITEM'
: 'ADD_ITEM',
})
<StyledText style="settingsSection">Subscriptions</StyledText>
{sortedSubscriptions.map((subscription) => {
return (
<Button
style="plainIcon"
css={{
display: 'flex',
width: '100%',
p: '5px',
alignItems: 'center',
borderRadius: '5px',
'&:hover': {
bg: '$thLibrarySelectionColor',
color: '$thLibraryMenuSecondary',
},
}}
key={`subscription-${subscription.id}`}
onClick={(event) => {
const item: Shortcut = {
id: subscription.id,
section: 'subscriptions',
name: subscription.name,
icon: subscription.icon,
type:
subscription.type == SubscriptionType.NEWSLETTER
? 'newsletter'
: 'feed',
filter:
subscription.type == SubscriptionType.NEWSLETTER
? `subscription:\"${escapeQuotes(subscription.name)}\"`
: `rss:\"${subscription.url}\"`,
}
props.dispatchList({
item,
type: subscriptionSelected(subscription)
? 'REMOVE_ITEM'
: 'ADD_ITEM',
})
event.preventDefault()
}}
>
<StyledText style="settingsItem">{subscription.name}</StyledText>
<SpanBox css={{ ml: 'auto' }}>
{subscriptionSelected(subscription) ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
</SpanBox>
</Button>
)
})}
event.preventDefault()
}}
>
<StyledText style="settingsItem">{subscription.name}</StyledText>
<SpanBox css={{ ml: 'auto' }}>
{subscriptionSelected(subscription) ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
</SpanBox>
</Button>
)
})}
</VStack>
</VStack>
)
}
@ -462,36 +485,49 @@ const AvailableItemButton = (props: AvailableItemButtonProps): JSX.Element => {
}
const SelectedItems = (props: ListProps): JSX.Element => {
const treeRef = useRef<TreeApi<Shortcut> | undefined>(undefined)
const resetShortcuts = useResetShortcuts()
const createNewFolder = useCallback(async () => {
if (treeRef.current) {
const result = await treeRef.current.create({
type: 'internal',
index: 0,
})
}
}, [treeRef])
return (
<VStack
css={{
m: '0px',
gap: '10px',
width: '100%',
maxWidth: '400px',
px: '0px',
pb: '25px',
}}
alignment="start"
distribution="start"
css={{
width: '420px',
py: '30px',
pl: '28px', // becomes labels have some margin built in
pr: '30px',
gap: '15px',
bg: '$thLeftMenuBackground',
}}
>
<StyledText style="settingsSection">Your shortcuts</StyledText>
{props.shortcuts.map((shortcut) => {
return (
<HStack
alignment="center"
distribution="start"
css={{ width: '100%', gap: '10px' }}
key={`search-${shortcut.id}`}
>
<CoverImage src={shortcut.icon} width={20} height={20} />
<StyledText style="settingsItem">{shortcut.name}</StyledText>
<HStack css={{ ml: 'auto' }}>
<DragIcon />
</HStack>
</HStack>
)
})}
<Box
css={{
width: '100%',
height: '100%',
pt: '10px',
bg: '$thLeftMenuBackground',
'[role="treeitem"]': {
outline: 'none',
},
'[role="treeitem"]:focus': {
outline: 'none',
},
}}
>
<ShortcutsTree treeRef={treeRef} />
</Box>
</VStack>
)
}