mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Rendering improvements, remove unused
This commit is contained in:
parent
742772fdb7
commit
d51aed5b7c
12 changed files with 111 additions and 476 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { DEFAULT_HOME_PATH } from '../../../lib/navigations'
|
||||
import { Box } from '../LayoutPrimitives'
|
||||
export type OmnivoreLogoBaseProps = {
|
||||
color?: string
|
||||
href?: string
|
||||
|
|
@ -9,13 +10,8 @@ export type OmnivoreLogoBaseProps = {
|
|||
}
|
||||
|
||||
export function OmnivoreLogoBase(props: OmnivoreLogoBaseProps): JSX.Element {
|
||||
const href = props.href || '/home'
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<Link
|
||||
passHref
|
||||
href={href}
|
||||
<Box
|
||||
style={{
|
||||
textDecoration: 'none',
|
||||
display: 'flex',
|
||||
|
|
@ -38,6 +34,6 @@ export function OmnivoreLogoBase(props: OmnivoreLogoBaseProps): JSX.Element {
|
|||
aria-label="Omnivore logo"
|
||||
>
|
||||
{props.children}
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
|
|||
import { StyledText } from '../../elements/StyledText'
|
||||
import { styled, theme } from '../../tokens/stitches.config'
|
||||
import { SettingsLayout } from '../SettingsLayout'
|
||||
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
|
||||
import { FeatureHelpBox } from '../../elements/FeatureHelpBox'
|
||||
|
||||
// Styles
|
||||
export const Header = styled(Box, {
|
||||
|
|
@ -26,8 +24,6 @@ type SettingsTableProps = {
|
|||
createTitle?: string
|
||||
createAction?: () => void
|
||||
|
||||
suggestionInfo: SuggestionInfo
|
||||
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
|
|
@ -63,16 +59,6 @@ type MoreOptionsProps = {
|
|||
onEdit?: () => void
|
||||
}
|
||||
|
||||
type SuggestionInfo = {
|
||||
title: string
|
||||
message: string
|
||||
docs: string
|
||||
key: string
|
||||
|
||||
CTAText?: string
|
||||
onClickCTA?: () => void
|
||||
}
|
||||
|
||||
const MoreOptions = (props: MoreOptionsProps) => (
|
||||
<Dropdown
|
||||
align={'end'}
|
||||
|
|
@ -294,11 +280,6 @@ const CreateButton = (props: CreateButtonProps): JSX.Element => {
|
|||
}
|
||||
|
||||
export const SettingsTable = (props: SettingsTableProps): JSX.Element => {
|
||||
const [showSuggestion, setShowSuggestion] = usePersistedState<boolean>({
|
||||
key: props.suggestionInfo.key,
|
||||
initialValue: !!props.suggestionInfo,
|
||||
})
|
||||
|
||||
return (
|
||||
<SettingsLayout>
|
||||
<Toaster
|
||||
|
|
@ -327,19 +308,6 @@ export const SettingsTable = (props: SettingsTableProps): JSX.Element => {
|
|||
},
|
||||
}}
|
||||
>
|
||||
{props.suggestionInfo && showSuggestion && (
|
||||
<FeatureHelpBox
|
||||
helpTitle={props.suggestionInfo.title}
|
||||
helpMessage={props.suggestionInfo.message}
|
||||
docsMessage={'Read the Docs'}
|
||||
docsDestination={props.suggestionInfo.docs}
|
||||
onDismiss={() => {
|
||||
setShowSuggestion(false)
|
||||
}}
|
||||
helpCTAText={props.suggestionInfo.CTAText}
|
||||
onClickCTA={props.suggestionInfo.onClickCTA}
|
||||
/>
|
||||
)}
|
||||
<Box
|
||||
css={{
|
||||
width: '100%',
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
"@radix-ui/react-switch": "^1.0.1",
|
||||
"@sentry/nextjs": "^7.42.0",
|
||||
"@stitches/react": "^1.2.5",
|
||||
"@tanstack/query-async-storage-persister": "^5.51.21",
|
||||
"@tanstack/query-sync-storage-persister": "^5.51.21",
|
||||
"@tanstack/react-query": "^5.51.21",
|
||||
"@tanstack/react-query-persist-client": "^5.51.21",
|
||||
|
|
@ -111,4 +112,4 @@
|
|||
"volta": {
|
||||
"extends": "../../package.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import type { AppProps } from 'next/app'
|
|||
import { IdProvider } from '@radix-ui/react-id'
|
||||
import { NextRouter, useRouter } from 'next/router'
|
||||
import { ReactNode, useEffect, useState } from 'react'
|
||||
import { HydrationBoundary } from '@tanstack/react-query'
|
||||
import TopBarProgress from 'react-topbar-progress-indicator'
|
||||
import {
|
||||
KBarProvider,
|
||||
|
|
@ -23,7 +24,7 @@ import { updateTheme } from '../lib/themeUpdater'
|
|||
import { ThemeId } from '../components/tokens/stitches.config'
|
||||
import { posthog } from 'posthog-js'
|
||||
import { GoogleReCaptchaProvider } from '@google-recaptcha/react'
|
||||
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
|
||||
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { persistQueryClient } from '@tanstack/react-query-persist-client'
|
||||
import React from 'react'
|
||||
|
|
@ -31,7 +32,7 @@ import React from 'react'
|
|||
const queryClient = new QueryClient()
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
const localStoragePersister = createSyncStoragePersister({
|
||||
const localStoragePersister = createAsyncStoragePersister({
|
||||
storage: window.localStorage,
|
||||
})
|
||||
|
||||
|
|
@ -44,7 +45,7 @@ if (typeof window !== 'undefined') {
|
|||
shouldDehydrateQuery: ({ queryKey }) => {
|
||||
// Don't cache the library items in local storage
|
||||
const [firstKey] = queryKey
|
||||
return firstKey !== 'library-items'
|
||||
return firstKey !== 'library-items' && firstKey !== 'shortcuts'
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -120,21 +120,6 @@ export default function Api(): JSX.Element {
|
|||
setExpiresAt(neverExpiresDate)
|
||||
setAddModalOpen(true)
|
||||
}}
|
||||
suggestionInfo={{
|
||||
title:
|
||||
'Use API keys to Integrate Omnivore with other apps and services',
|
||||
message:
|
||||
'Create API keys to connect Omnivore to other apps such as Logseq and Obsidian or to query the API. Check out the integrations documentation for more info on connecting to Omnivore via the API.',
|
||||
docs: 'https://docs.omnivore.app/integrations/api.html',
|
||||
key: '--settings-apikeys-show-help',
|
||||
CTAText: 'Create an API Key',
|
||||
onClickCTA: () => {
|
||||
onAdd()
|
||||
setName('')
|
||||
setExpiresAt(neverExpiresDate)
|
||||
setAddModalOpen(true)
|
||||
},
|
||||
}}
|
||||
>
|
||||
{sortedApiKeys.length > 0 ? (
|
||||
sortedApiKeys.map((apiKey, i) => {
|
||||
|
|
|
|||
|
|
@ -76,17 +76,6 @@ export default function DiscoverFeedsSettings(): JSX.Element {
|
|||
createAction={() => {
|
||||
router.push('/settings/discover-feeds/add')
|
||||
}}
|
||||
suggestionInfo={{
|
||||
title: 'Add RSS and Atom feeds to your Omnivore account',
|
||||
message:
|
||||
'When you add a new feed the last 24hrs of items, or at least one item will be added to your account. Feeds will be checked for updates every four hours, and new items will be added to your Following. You can also add feeds to your Library by checking the box below.',
|
||||
docs: 'https://docs.omnivore.app/using/feeds.html',
|
||||
key: '--settings-feeds-show-help',
|
||||
CTAText: 'Add a feed',
|
||||
onClickCTA: () => {
|
||||
router.push('/settings/discover-feeds/add')
|
||||
},
|
||||
}}
|
||||
>
|
||||
{sortedFeeds.length === 0 ? (
|
||||
<EmptySettingsRow text={isValidating ? '-' : 'No feeds subscribed'} />
|
||||
|
|
|
|||
|
|
@ -80,9 +80,8 @@ function CopyTextButton(props: CopyTextButtonProps): JSX.Element {
|
|||
export default function EmailsPage(): JSX.Element {
|
||||
const { emailAddresses, revalidate, isValidating } =
|
||||
useGetNewsletterEmailsQuery()
|
||||
const [confirmDeleteEmailId, setConfirmDeleteEmailId] = useState<
|
||||
undefined | string
|
||||
>(undefined)
|
||||
const [confirmDeleteEmailId, setConfirmDeleteEmailId] =
|
||||
useState<undefined | string>(undefined)
|
||||
|
||||
applyStoredTheme()
|
||||
|
||||
|
|
@ -121,17 +120,6 @@ export default function EmailsPage(): JSX.Element {
|
|||
headerTitle="Address"
|
||||
createTitle="Create a new email address"
|
||||
createAction={createEmail}
|
||||
suggestionInfo={{
|
||||
title: 'Subscribe to newsletters with an Omnivore Email Address',
|
||||
message:
|
||||
'Create an Omnivore email address and use it to subscribe to newsletters or send yourself documents. Newsletters and documents will be categorized and added to your library when we receive a message. View all received emails with the "Recently Received Emails" link at the bottom of this page.',
|
||||
docs: 'https://docs.omnivore.app/using/inbox.html',
|
||||
key: '--settings-emails-show-help',
|
||||
CTAText: 'Create an email address',
|
||||
onClickCTA: () => {
|
||||
createEmail()
|
||||
},
|
||||
}}
|
||||
>
|
||||
{sortedEmailAddresses.length > 0 ? (
|
||||
sortedEmailAddresses.map((email, i) => {
|
||||
|
|
|
|||
|
|
@ -151,13 +151,11 @@ const ViewRecentEmailModal = (
|
|||
|
||||
export default function RecentEmails(): JSX.Element {
|
||||
const { recentEmails, revalidate, isValidating } = useGetRecentEmailsQuery()
|
||||
const [viewingEmailText, setViewingEmailText] = useState<
|
||||
RecentEmail | undefined
|
||||
>(undefined)
|
||||
const [viewingEmailText, setViewingEmailText] =
|
||||
useState<RecentEmail | undefined>(undefined)
|
||||
|
||||
const [viewingEmailHtml, setViewingEmailHtml] = useState<
|
||||
RecentEmail | undefined
|
||||
>(undefined)
|
||||
const [viewingEmailHtml, setViewingEmailHtml] =
|
||||
useState<RecentEmail | undefined>(undefined)
|
||||
|
||||
applyStoredTheme()
|
||||
|
||||
|
|
@ -170,14 +168,6 @@ export default function RecentEmails(): JSX.Element {
|
|||
pageId="recent-emails"
|
||||
pageInfoLink="https://docs.omnivore.app/using/inbox.html"
|
||||
headerTitle="Recently Received Emails"
|
||||
suggestionInfo={{
|
||||
title:
|
||||
'View original emails that have been recently received in your Omnivore inbox.',
|
||||
message:
|
||||
"Your 30 most recent emails are stored below. You can click on each email to view its original content or it's text content. If an email was not correctly classified as an article you can mark it as an article and it will be added to your library.",
|
||||
docs: 'https://docs.omnivore.app/using/inbox.html',
|
||||
key: '--settings-recent-emails-show-help',
|
||||
}}
|
||||
>
|
||||
{sortedRecentEmails.length > 0 ? (
|
||||
sortedRecentEmails.map((recentEmail: RecentEmail, i) => {
|
||||
|
|
|
|||
|
|
@ -128,17 +128,6 @@ export default function Rss(): JSX.Element {
|
|||
createAction={() => {
|
||||
router.push('/settings/feeds/add')
|
||||
}}
|
||||
suggestionInfo={{
|
||||
title: 'Add RSS and Atom feeds to your Omnivore account',
|
||||
message:
|
||||
'When you add a new feed the last 24hrs of items, or at least one item will be added to your account. Feeds will be checked for updates every four hours, and new items will be added to your Following. You can also add feeds to your Library by checking the box below.',
|
||||
docs: 'https://docs.omnivore.app/using/feeds.html',
|
||||
key: '--settings-feeds-show-help',
|
||||
CTAText: 'Add a feed',
|
||||
onClickCTA: () => {
|
||||
router.push('/settings/feeds/add')
|
||||
},
|
||||
}}
|
||||
>
|
||||
{sortedSubscriptions.length === 0 ? (
|
||||
<EmptySettingsRow text={isValidating ? '-' : 'No feeds subscribed'} />
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import {
|
|||
import { applyStoredTheme } from '../../lib/themeUpdater'
|
||||
|
||||
import { SettingsLayout } from '../../components/templates/SettingsLayout'
|
||||
import { NavigationLayout } from '../../components/templates/NavigationLayout'
|
||||
|
||||
import { Toaster } from 'react-hot-toast'
|
||||
import {
|
||||
Box,
|
||||
|
|
@ -38,185 +40,73 @@ import { useGetLabels } from '../../lib/networking/labels/useLabels'
|
|||
import { useGetSavedSearches } from '../../lib/networking/savedsearches/useSavedSearches'
|
||||
import {
|
||||
Shortcut,
|
||||
useGetShortcuts,
|
||||
useResetShortcuts,
|
||||
} from '../../lib/networking/shortcuts/useShortcuts'
|
||||
import { ShortcutsTree } from '../../components/templates/ShortcutsTree'
|
||||
import { TreeApi } from 'react-arborist'
|
||||
|
||||
type ListAction = 'RESET' | 'ADD_ITEM' | 'REMOVE_ITEM'
|
||||
|
||||
const SHORTCUTS_KEY = 'library-shortcuts'
|
||||
|
||||
export default function Shortcuts(): JSX.Element {
|
||||
applyStoredTheme()
|
||||
const [navMenuStyle, setNavMenuStyle] = usePersistedState<
|
||||
'legacy' | 'shortcuts'
|
||||
>({
|
||||
key: 'library-nav-menu-style',
|
||||
initialValue: 'legacy',
|
||||
})
|
||||
/**
|
||||
* Use this function when you want to fix the "hydration" error in NextJS
|
||||
* @param store
|
||||
* @param callback
|
||||
*/
|
||||
export const useAsyncStore = <T, F>(
|
||||
store: (callback: (state: T) => unknown) => unknown,
|
||||
callback: (state: T) => F
|
||||
) => {
|
||||
const result = store(callback) as F
|
||||
const [data, setData] = useState<F>()
|
||||
|
||||
const listReducer = (
|
||||
state: { state: string; items: Shortcut[] },
|
||||
action: {
|
||||
type: ListAction
|
||||
item?: Shortcut
|
||||
useEffect(() => {
|
||||
setData(typeof result === 'function' ? () => result : result)
|
||||
}, [result])
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this function when you want to fix the "hydration" error in NextJS
|
||||
* @param key
|
||||
*/
|
||||
export const useAsyncStoreValue = <K extends keyof ContextData>(key: K) => {
|
||||
return useAsyncStore(yourContextNameHere, (state) => state[key])
|
||||
}
|
||||
|
||||
function flattenShortcuts(shortcuts: Shortcut[]): string[] {
|
||||
let result: string[] = []
|
||||
|
||||
for (const shortcut of shortcuts) {
|
||||
if (shortcut.type !== 'folder') {
|
||||
result.push(shortcut.id)
|
||||
}
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case 'RESET': {
|
||||
const itemStr = window['localStorage'].getItem(SHORTCUTS_KEY)
|
||||
if (itemStr) {
|
||||
try {
|
||||
const parsed = JSON.parse(itemStr)
|
||||
if (Array.isArray(parsed)) {
|
||||
return { state: 'CURRENT', items: parsed as Shortcut[] }
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('error: ', err)
|
||||
}
|
||||
}
|
||||
return { state: 'CURRENT', items: [] }
|
||||
}
|
||||
case 'ADD_ITEM': {
|
||||
const item = action.item
|
||||
if (!item) {
|
||||
return state
|
||||
}
|
||||
const existing = state.items.find(
|
||||
(existing) => existing.type == item.type && existing.id == item.id
|
||||
)
|
||||
if (existing) {
|
||||
return state
|
||||
}
|
||||
state.items.push(item)
|
||||
return { state: 'CURRENT', items: [...state.items] }
|
||||
}
|
||||
case 'REMOVE_ITEM': {
|
||||
const item = action.item
|
||||
if (!item) {
|
||||
return state
|
||||
}
|
||||
const updated = state.items.filter((existing) => existing.id != item.id)
|
||||
return { state: 'CURRENT', items: [...updated] }
|
||||
}
|
||||
default:
|
||||
throw new Error('unknown action')
|
||||
if (shortcut.children && shortcut.children?.length > 0) {
|
||||
result = result.concat(flattenShortcuts(shortcut.children))
|
||||
}
|
||||
}
|
||||
|
||||
const [shortcuts, dispatchList] = useReducer(listReducer, {
|
||||
state: 'INITIAL',
|
||||
items: [],
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (shortcuts.state == 'CURRENT') {
|
||||
window['localStorage'].setItem(
|
||||
SHORTCUTS_KEY,
|
||||
JSON.stringify(shortcuts.items)
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('error": ', error)
|
||||
export default function Shortcuts(): JSX.Element {
|
||||
const { data: shortcuts, isLoading } = useGetShortcuts()
|
||||
const shortcutIds = useMemo(() => {
|
||||
if (shortcuts) {
|
||||
return flattenShortcuts(shortcuts)
|
||||
}
|
||||
return []
|
||||
}, [shortcuts])
|
||||
|
||||
useEffect(() => {
|
||||
dispatchList({ type: 'RESET' })
|
||||
}, [])
|
||||
console.log('shortcutIds: ', shortcutIds)
|
||||
|
||||
return (
|
||||
<SettingsLayout>
|
||||
<Toaster
|
||||
containerStyle={{
|
||||
top: '5rem',
|
||||
}}
|
||||
/>
|
||||
<VStack
|
||||
css={{ width: '100%', height: '100%' }}
|
||||
distribution="start"
|
||||
alignment="center"
|
||||
>
|
||||
<VStack
|
||||
css={{
|
||||
padding: '24px',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
gap: '25px',
|
||||
minWidth: '300px',
|
||||
maxWidth: '880px',
|
||||
}}
|
||||
>
|
||||
<Box css={{}}>
|
||||
<StyledText style="fixedHeadline" css={{ my: '6px' }}>
|
||||
Shortcuts
|
||||
</StyledText>
|
||||
<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
|
||||
css={{
|
||||
px: '10px',
|
||||
pt: '2px',
|
||||
height: '30px',
|
||||
gap: '5px',
|
||||
|
||||
fontSize: '14px',
|
||||
fontWeight: 'regular',
|
||||
fontFamily: '$display',
|
||||
color:
|
||||
navMenuStyle !== 'shortcuts'
|
||||
? '$thLibraryMenuSecondary'
|
||||
: '$thLibraryMenuUnselected',
|
||||
|
||||
verticalAlign: 'middle',
|
||||
borderRadius: '3px',
|
||||
cursor: 'pointer',
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: '$thBackground4',
|
||||
},
|
||||
}}
|
||||
alignment="center"
|
||||
distribution="start"
|
||||
onClick={(event) => {
|
||||
setNavMenuStyle(
|
||||
navMenuStyle == 'shortcuts' ? 'legacy' : 'shortcuts'
|
||||
)
|
||||
event.preventDefault()
|
||||
}}
|
||||
></HStack>
|
||||
<Box
|
||||
css={{
|
||||
py: '$3',
|
||||
display: 'grid',
|
||||
width: '100%',
|
||||
gridAutoRows: 'auto',
|
||||
borderRadius: '6px',
|
||||
gridGap: '40px',
|
||||
gridTemplateColumns: 'repeat(2, 1fr)',
|
||||
'@mdDown': {
|
||||
gridTemplateColumns: 'repeat(1, 1fr)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SelectedItems
|
||||
shortcuts={shortcuts.items}
|
||||
dispatchList={dispatchList}
|
||||
/>
|
||||
<AvailableItems
|
||||
shortcuts={shortcuts.items}
|
||||
dispatchList={dispatchList}
|
||||
/>
|
||||
</Box>
|
||||
</VStack>
|
||||
</VStack>
|
||||
{!isLoading &&
|
||||
shortcutIds.map((shortcutId) => {
|
||||
return <Box key={shortcutId}>{shortcutId}</Box>
|
||||
})}
|
||||
</SettingsLayout>
|
||||
)
|
||||
}
|
||||
|
|
@ -228,8 +118,8 @@ export const SectionSeparator = styled(Separator, {
|
|||
})
|
||||
|
||||
type ListProps = {
|
||||
shortcuts: Shortcut[]
|
||||
dispatchList: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
|
||||
shortcutIds: string[]
|
||||
// dispatchList: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
|
||||
}
|
||||
|
||||
const AvailableItems = (props: ListProps): JSX.Element => {
|
||||
|
|
@ -266,27 +156,29 @@ const AvailableItems = (props: ListProps): JSX.Element => {
|
|||
|
||||
const searchSelected = useCallback(
|
||||
(search: SavedSearch) => {
|
||||
return !!props.shortcuts.find((shortcut) => shortcut.id == search.id)
|
||||
return !!props.shortcutIds.find((shortcutId) => shortcutId == search.id)
|
||||
},
|
||||
[props]
|
||||
)
|
||||
|
||||
const labelSelected = useCallback(
|
||||
(label: Label) => {
|
||||
return !!props.shortcuts.find((shortcut) => shortcut.id == label.id)
|
||||
return !!props.shortcutIds.find((shortcutId) => shortcutId == label.id)
|
||||
},
|
||||
[props]
|
||||
)
|
||||
|
||||
const subscriptionSelected = useCallback(
|
||||
(subscription: Subscription) => {
|
||||
return !!props.shortcuts.find(
|
||||
(shortcut) => shortcut.id == subscription.id
|
||||
return !!props.shortcutIds.find(
|
||||
(shortcutId) => shortcutId == subscription.id
|
||||
)
|
||||
},
|
||||
[props]
|
||||
)
|
||||
|
||||
console.log('sortedsavedSearchesL: ', sortedsavedSearches)
|
||||
|
||||
return (
|
||||
<VStack
|
||||
css={{
|
||||
|
|
@ -300,68 +192,16 @@ const AvailableItems = (props: ListProps): JSX.Element => {
|
|||
alignment="start"
|
||||
distribution="start"
|
||||
>
|
||||
<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 />
|
||||
|
||||
{/* <StyledText style="settingsSection">Available items</StyledText> */}
|
||||
<SavedSearches {...props} />
|
||||
<SectionSeparator />
|
||||
{/*
|
||||
<StyledText style="settingsSection">Labels</StyledText>
|
||||
{sortedLabels.map((label) => {
|
||||
console.log('label: ', label)
|
||||
return (
|
||||
<Button
|
||||
key={`label-${label.id}`}
|
||||
style="plainIcon"
|
||||
css={{
|
||||
display: 'flex',
|
||||
|
|
@ -374,7 +214,6 @@ const AvailableItems = (props: ListProps): JSX.Element => {
|
|||
color: '$thLibraryMenuSecondary',
|
||||
},
|
||||
}}
|
||||
key={`label-${label.id}`}
|
||||
onClick={(event) => {
|
||||
const item: Shortcut = {
|
||||
id: label.id,
|
||||
|
|
@ -407,8 +246,10 @@ const AvailableItems = (props: ListProps): JSX.Element => {
|
|||
|
||||
<StyledText style="settingsSection">Subscriptions</StyledText>
|
||||
{sortedSubscriptions.map((subscription) => {
|
||||
console.log('subscription: ', subscription)
|
||||
return (
|
||||
<Button
|
||||
key={`subscription-${subscription.id}`}
|
||||
style="plainIcon"
|
||||
css={{
|
||||
display: 'flex',
|
||||
|
|
@ -421,7 +262,6 @@ const AvailableItems = (props: ListProps): JSX.Element => {
|
|||
color: '$thLibraryMenuSecondary',
|
||||
},
|
||||
}}
|
||||
key={`subscription-${subscription.id}`}
|
||||
onClick={(event) => {
|
||||
const item: Shortcut = {
|
||||
id: subscription.id,
|
||||
|
|
@ -457,147 +297,35 @@ const AvailableItems = (props: ListProps): JSX.Element => {
|
|||
</SpanBox>
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</VStack>
|
||||
})} */}
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
||||
type AvailableItemButtonProps = {
|
||||
shortcut: Shortcut
|
||||
isSelected: boolean
|
||||
listAction: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
|
||||
}
|
||||
const SavedSearches = (props: ListProps) => {
|
||||
const { data: savedSearches, isLoading } = useGetSavedSearches()
|
||||
|
||||
const AvailableItemButton = (props: AvailableItemButtonProps): JSX.Element => {
|
||||
const shortcutId = `checkbox-search-${props.shortcut.id}`
|
||||
return (
|
||||
<CheckboxButton
|
||||
itemKey={shortcutId}
|
||||
title={props.shortcut.filter}
|
||||
isSelected={props.isSelected}
|
||||
item={props.shortcut}
|
||||
listAction={props.listAction}
|
||||
>
|
||||
<SpanBox css={{}}>{props.shortcut.name}</SpanBox>
|
||||
</CheckboxButton>
|
||||
)
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
const sortedsavedSearches = useMemo(() => {
|
||||
if (!savedSearches) {
|
||||
return []
|
||||
}
|
||||
}, [treeRef])
|
||||
|
||||
return savedSearches.sort((a, b) =>
|
||||
a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase())
|
||||
)
|
||||
}, [savedSearches])
|
||||
return (
|
||||
<VStack
|
||||
css={{
|
||||
m: '0px',
|
||||
gap: '10px',
|
||||
width: '100%',
|
||||
maxWidth: '400px',
|
||||
px: '0px',
|
||||
pb: '25px',
|
||||
}}
|
||||
alignment="start"
|
||||
distribution="start"
|
||||
>
|
||||
<StyledText style="settingsSection">Your shortcuts</StyledText>
|
||||
<Box
|
||||
css={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
pt: '10px',
|
||||
bg: '$thLeftMenuBackground',
|
||||
|
||||
'[role="treeitem"]': {
|
||||
outline: 'none',
|
||||
},
|
||||
'[role="treeitem"]:focus': {
|
||||
outline: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ShortcutsTree treeRef={treeRef} />
|
||||
</Box>
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
||||
type CheckboxButtonProps = {
|
||||
itemKey: string
|
||||
title: string
|
||||
isSelected: boolean
|
||||
item: Shortcut
|
||||
|
||||
listAction: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
function CheckboxButton(props: CheckboxButtonProps): JSX.Element {
|
||||
const handleChange = useCallback(
|
||||
(selected: boolean) => {
|
||||
if (!selected) {
|
||||
props.listAction({
|
||||
type: 'REMOVE_ITEM',
|
||||
item: props.item,
|
||||
})
|
||||
} else {
|
||||
props.listAction({
|
||||
type: 'ADD_ITEM',
|
||||
item: props.item,
|
||||
})
|
||||
}
|
||||
},
|
||||
[props]
|
||||
)
|
||||
return (
|
||||
<HStack
|
||||
key={props.itemKey}
|
||||
title={props.title}
|
||||
css={{
|
||||
px: '10px',
|
||||
pt: '2px',
|
||||
height: '30px',
|
||||
gap: '5px',
|
||||
|
||||
fontSize: '14px',
|
||||
fontWeight: 'regular',
|
||||
fontFamily: '$display',
|
||||
color: props.isSelected
|
||||
? '$thLibraryMenuSecondary'
|
||||
: '$thLibraryMenuUnselected',
|
||||
|
||||
verticalAlign: 'middle',
|
||||
borderRadius: '3px',
|
||||
cursor: 'pointer',
|
||||
|
||||
m: '0px',
|
||||
'&:hover': {
|
||||
backgroundColor: '$thBackground4',
|
||||
},
|
||||
}}
|
||||
alignment="center"
|
||||
distribution="start"
|
||||
onClick={(event) => {
|
||||
handleChange(!props.isSelected)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
{props.isSelected ? (
|
||||
<CheckSquare size={20} weight="duotone" />
|
||||
) : (
|
||||
<Square size={20} weight="duotone" />
|
||||
)}
|
||||
{props.children}
|
||||
</HStack>
|
||||
<>
|
||||
{/* <StyledText style="settingsSection">Saved Searches</StyledText> */}
|
||||
{/* <Box> */}
|
||||
{!isLoading &&
|
||||
(savedSearches ?? []).map((search) => {
|
||||
return (
|
||||
<Box key={`saved-search-${search.id}`} suppressHydrationWarning>
|
||||
{search.name}
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
{/* </Box> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,13 +48,6 @@ export default function SubscriptionsPage(): JSX.Element {
|
|||
pageId="settings-subscriptions-tag"
|
||||
pageInfoLink="https://docs.omnivore.app/using/feeds.html"
|
||||
headerTitle="Subscriptions"
|
||||
suggestionInfo={{
|
||||
title: 'View and manage all your Feed and Newsletter subscriptions',
|
||||
message:
|
||||
'Use this page to view and manage all the Feeds (RSS & Atom) and Newsletters you have subscribed to.',
|
||||
docs: 'https://docs.omnivore.app/using/inbox.html',
|
||||
key: '--settings-recent-subscriptions-show-help',
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{sortedSubscriptions.length > 0 ? (
|
||||
|
|
|
|||
|
|
@ -7575,6 +7575,13 @@
|
|||
dependencies:
|
||||
defer-to-connect "^1.0.1"
|
||||
|
||||
"@tanstack/query-async-storage-persister@^5.51.21":
|
||||
version "5.51.21"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-5.51.21.tgz#27e6635d89e0814c65586b8047372349698c7841"
|
||||
integrity sha512-T22f99fDKk+XrT0kCEwETNehn8gjGfdNaaYM0xRA7VvwFKUKNYETOwUQgXV6kZ+xg6LKbZeI22YsTcuYDFOx5w==
|
||||
dependencies:
|
||||
"@tanstack/query-persist-client-core" "5.51.21"
|
||||
|
||||
"@tanstack/query-core@5.51.21":
|
||||
version "5.51.21"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.51.21.tgz#a510469c6c30d3de2a8b8798e340169a4b0fd08f"
|
||||
|
|
|
|||
Loading…
Reference in a new issue