mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #4092 from omnivore-app/feat/web-home-tweaks-02
Implement actions on the home view
This commit is contained in:
commit
59866510b0
6 changed files with 149 additions and 6 deletions
|
|
@ -27,6 +27,7 @@ import {
|
|||
import { Box, HStack, SpanBox, VStack } from '../elements/LayoutPrimitives'
|
||||
import { Toaster } from 'react-hot-toast'
|
||||
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
|
||||
import useLibraryItemActions from '../../lib/hooks/useLibraryItemActions'
|
||||
|
||||
export function HomeContainer(): JSX.Element {
|
||||
const router = useRouter()
|
||||
|
|
@ -153,6 +154,12 @@ const JustAddedHomeSection = (props: HomeSectionProps): JSX.Element => {
|
|||
fontSize: '16px',
|
||||
fontWeight: '600',
|
||||
color: '$homeTextTitle',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
wordBreak: 'break-word',
|
||||
display: '-webkit-box',
|
||||
'-webkit-line-clamp': '2',
|
||||
'-webkit-box-orient': 'vertical',
|
||||
}}
|
||||
>
|
||||
{props.homeSection.title}
|
||||
|
|
@ -571,6 +578,8 @@ const TopPicksItemView = (
|
|||
props: HomeItemViewProps & TopPicksItemViewProps
|
||||
): JSX.Element => {
|
||||
const router = useRouter()
|
||||
const { archiveItem, deleteItem, moveItem } = useLibraryItemActions()
|
||||
|
||||
return (
|
||||
<VStack
|
||||
css={{
|
||||
|
|
@ -633,7 +642,7 @@ const TopPicksItemView = (
|
|||
{props.homeItem.canSave && (
|
||||
<Button
|
||||
style="homeAction"
|
||||
onClick={(event) => {
|
||||
onClick={async (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
|
|
@ -641,6 +650,12 @@ const TopPicksItemView = (
|
|||
type: 'REMOVE_ITEM',
|
||||
itemId: props.homeItem.id,
|
||||
})
|
||||
if (!(await moveItem(props.homeItem.id))) {
|
||||
props.dispatchList({
|
||||
type: 'REPLACE_ITEM',
|
||||
itemId: props.homeItem.id,
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AddToLibraryActionIcon
|
||||
|
|
@ -651,7 +666,7 @@ const TopPicksItemView = (
|
|||
{props.homeItem.canArchive && (
|
||||
<Button
|
||||
style="homeAction"
|
||||
onClick={(event) => {
|
||||
onClick={async (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
|
|
@ -659,6 +674,12 @@ const TopPicksItemView = (
|
|||
type: 'REMOVE_ITEM',
|
||||
itemId: props.homeItem.id,
|
||||
})
|
||||
if (!(await archiveItem(props.homeItem.id))) {
|
||||
props.dispatchList({
|
||||
type: 'REPLACE_ITEM',
|
||||
itemId: props.homeItem.id,
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ArchiveActionIcon
|
||||
|
|
@ -669,7 +690,7 @@ const TopPicksItemView = (
|
|||
{props.homeItem.canDelete && (
|
||||
<Button
|
||||
style="homeAction"
|
||||
onClick={(event) => {
|
||||
onClick={async (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
|
|
@ -677,6 +698,18 @@ const TopPicksItemView = (
|
|||
type: 'REMOVE_ITEM',
|
||||
itemId: props.homeItem.id,
|
||||
})
|
||||
const undo = () => {
|
||||
props.dispatchList({
|
||||
type: 'REPLACE_ITEM',
|
||||
itemId: props.homeItem.id,
|
||||
})
|
||||
}
|
||||
if (!(await deleteItem(props.homeItem.id, undo))) {
|
||||
props.dispatchList({
|
||||
type: 'REPLACE_ITEM',
|
||||
itemId: props.homeItem.id,
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
<RemoveActionIcon color={theme.colors.homeActionIcons.toString()} />
|
||||
|
|
@ -416,7 +416,7 @@ const blackThemeSpec = {
|
|||
|
||||
const apolloThemeSpec = {
|
||||
colors: {
|
||||
readerBg: '#6A6968',
|
||||
readerBg: '#474747',
|
||||
readerFont: '#F3F3F3',
|
||||
readerMargin: '#474747',
|
||||
readerFontHighContrast: 'white',
|
||||
|
|
|
|||
69
packages/web/lib/hooks/useLibraryItemActions.tsx
Normal file
69
packages/web/lib/hooks/useLibraryItemActions.tsx
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { setLinkArchivedMutation } from '../networking/mutations/setLinkArchivedMutation'
|
||||
import {
|
||||
showErrorToast,
|
||||
showSuccessToast,
|
||||
showSuccessToastWithUndo,
|
||||
} from '../toastHelpers'
|
||||
import { deleteLinkMutation } from '../networking/mutations/deleteLinkMutation'
|
||||
import { updatePageMutation } from '../networking/mutations/updatePageMutation'
|
||||
import { State } from '../networking/fragments/articleFragment'
|
||||
|
||||
export default function useLibraryItemActions() {
|
||||
const archiveItem = useCallback(async (itemId: string) => {
|
||||
const result = await setLinkArchivedMutation({
|
||||
linkId: itemId,
|
||||
archived: true,
|
||||
})
|
||||
|
||||
if (result) {
|
||||
showSuccessToast('Link archived', { position: 'bottom-right' })
|
||||
} else {
|
||||
showErrorToast('Error archiving link', { position: 'bottom-right' })
|
||||
}
|
||||
|
||||
return !!result
|
||||
}, [])
|
||||
|
||||
const deleteItem = useCallback(async (itemId: string, undo: () => void) => {
|
||||
const result = await deleteLinkMutation(itemId)
|
||||
|
||||
if (result) {
|
||||
showSuccessToastWithUndo('Item removed', async () => {
|
||||
const result = await updatePageMutation({
|
||||
pageId: itemId,
|
||||
state: State.SUCCEEDED,
|
||||
})
|
||||
|
||||
undo()
|
||||
|
||||
if (result) {
|
||||
showSuccessToast('Item recovered')
|
||||
} else {
|
||||
showErrorToast('Error recovering, check your deleted items')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
showErrorToast('Error removing item', { position: 'bottom-right' })
|
||||
}
|
||||
|
||||
return !!result
|
||||
}, [])
|
||||
|
||||
const moveItem = useCallback(async (itemId: string) => {
|
||||
const result = await setLinkArchivedMutation({
|
||||
linkId: itemId,
|
||||
archived: true,
|
||||
})
|
||||
|
||||
if (result) {
|
||||
showSuccessToast('Link archived', { position: 'bottom-right' })
|
||||
} else {
|
||||
showErrorToast('Error archiving link', { position: 'bottom-right' })
|
||||
}
|
||||
|
||||
return !!result
|
||||
}, [])
|
||||
|
||||
return { archiveItem, deleteItem, moveItem }
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import { gql } from 'graphql-request'
|
||||
import { gqlFetcher } from '../networkHelpers'
|
||||
|
||||
type MoveToFolderResponseData = {
|
||||
success?: boolean
|
||||
errorCodes?: string[]
|
||||
}
|
||||
|
||||
type MoveToFolderResponse = {
|
||||
moveToFolder?: MoveToFolderResponseData
|
||||
}
|
||||
|
||||
export async function moveToFolderMutation(
|
||||
itemId: string,
|
||||
folder: string
|
||||
): Promise<boolean> {
|
||||
const mutation = gql`
|
||||
mutation MoveToFolder($id: ID!, $folder: String!) {
|
||||
moveToFolder(id: $id, folder: $folder) {
|
||||
... on MoveToFolderSuccess {
|
||||
success
|
||||
}
|
||||
... on MoveToFolderError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
try {
|
||||
const response = await gqlFetcher(mutation, { id: itemId, folder })
|
||||
const data = response as MoveToFolderResponse | undefined
|
||||
if (data?.moveToFolder?.errorCodes) {
|
||||
return false
|
||||
}
|
||||
return data?.moveToFolder?.success ?? false
|
||||
} catch (error) {
|
||||
console.log('MoveToFolder error', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -4,10 +4,10 @@ import {
|
|||
NavigationLayout,
|
||||
NavigationSection,
|
||||
} from '../../components/templates/NavigationLayout'
|
||||
import { HomeContainer } from '../../components/nav-containers/home'
|
||||
import { HomeContainer } from '../../components/nav-containers/HomeContainer'
|
||||
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
|
||||
import { useMemo } from 'react'
|
||||
import { HighlightsContainer } from '../../components/nav-containers/highlights'
|
||||
import { HighlightsContainer } from '../../components/nav-containers/HighlightsContainer'
|
||||
|
||||
export default function Home(): JSX.Element {
|
||||
const router = useRouter()
|
||||
|
|
|
|||
Loading…
Reference in a new issue