diff --git a/packages/web/components/nav-containers/highlights.tsx b/packages/web/components/nav-containers/HighlightsContainer.tsx similarity index 100% rename from packages/web/components/nav-containers/highlights.tsx rename to packages/web/components/nav-containers/HighlightsContainer.tsx diff --git a/packages/web/components/nav-containers/home.tsx b/packages/web/components/nav-containers/HomeContainer.tsx similarity index 94% rename from packages/web/components/nav-containers/home.tsx rename to packages/web/components/nav-containers/HomeContainer.tsx index 8c4a3d6b6..59ff4e84a 100644 --- a/packages/web/components/nav-containers/home.tsx +++ b/packages/web/components/nav-containers/HomeContainer.tsx @@ -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 ( { + 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, + }) + } }} > { + 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, + }) + } }} > { + 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, + }) + } }} > diff --git a/packages/web/components/tokens/stitches.config.ts b/packages/web/components/tokens/stitches.config.ts index 4351694c9..99dd8d755 100644 --- a/packages/web/components/tokens/stitches.config.ts +++ b/packages/web/components/tokens/stitches.config.ts @@ -416,7 +416,7 @@ const blackThemeSpec = { const apolloThemeSpec = { colors: { - readerBg: '#6A6968', + readerBg: '#474747', readerFont: '#F3F3F3', readerMargin: '#474747', readerFontHighContrast: 'white', diff --git a/packages/web/lib/hooks/useLibraryItemActions.tsx b/packages/web/lib/hooks/useLibraryItemActions.tsx new file mode 100644 index 000000000..d2b4d28ab --- /dev/null +++ b/packages/web/lib/hooks/useLibraryItemActions.tsx @@ -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 } +} diff --git a/packages/web/lib/networking/mutations/moveToLibraryMutation.ts b/packages/web/lib/networking/mutations/moveToLibraryMutation.ts new file mode 100644 index 000000000..205312dd6 --- /dev/null +++ b/packages/web/lib/networking/mutations/moveToLibraryMutation.ts @@ -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 { + 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 + } +} diff --git a/packages/web/pages/l/[section].tsx b/packages/web/pages/l/[section].tsx index fc943e05b..782e7e14f 100644 --- a/packages/web/pages/l/[section].tsx +++ b/packages/web/pages/l/[section].tsx @@ -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()