From 03997aab5b52c771532976d1ac1dab0f25c00c6b Mon Sep 17 00:00:00 2001 From: Rhythm Aich Date: Thu, 17 Oct 2024 14:36:29 +0530 Subject: [PATCH] feat: add entry list empty state (#28) * Added empty state messages * moved no entries overlay component to page components * removed inline styling * Made NoEntriesOverlay into a separate component * chore: apply nits * chore: wrap text with Text component --------- Co-authored-by: ayoung19 --- popup/components/EntryList.tsx | 29 +++++++++++++++++---------- popup/components/NoEntriesOverlay.tsx | 26 ++++++++++++++++++++++++ popup/pages/AllPage.tsx | 11 ++++++++++ popup/pages/FavoritesPage.tsx | 22 ++++++++++++++++++++ 4 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 popup/components/NoEntriesOverlay.tsx diff --git a/popup/components/EntryList.tsx b/popup/components/EntryList.tsx index b6f43fb..80642fe 100644 --- a/popup/components/EntryList.tsx +++ b/popup/components/EntryList.tsx @@ -2,7 +2,7 @@ import { ActionIcon, Box, Checkbox, Divider, Group, Text } from "@mantine/core"; import { useSet } from "@mantine/hooks"; import { IconStar, IconTrash } from "@tabler/icons-react"; import { useAtomValue } from "jotai"; -import { useEffect, useMemo, type CSSProperties } from "react"; +import { useEffect, useMemo, type CSSProperties, type ReactNode } from "react"; import { FixedSizeList } from "react-window"; import { favoriteEntryIdsSetAtom } from "~popup/states/atoms"; @@ -15,6 +15,7 @@ import { EntryRow } from "./EntryRow"; interface Props { entries: Entry[]; + noEntriesOverlay: ReactNode; } const EntryRowRenderer = ({ @@ -38,7 +39,7 @@ const EntryRowRenderer = ({ ); }; -export const EntryList = ({ entries }: Props) => { +export const EntryList = ({ entries, noEntriesOverlay }: Props) => { const favoriteEntryIdsSet = useAtomValue(favoriteEntryIdsSetAtom); const selectedEntryIds = useSet(); @@ -106,15 +107,21 @@ export const EntryList = ({ entries }: Props) => { ({ borderColor: defaultBorderColor(theme) })} /> - - {EntryRowRenderer} - + {entries.length === 0 ? ( + + {noEntriesOverlay} + + ) : ( + + {EntryRowRenderer} + + )} ); }; diff --git a/popup/components/NoEntriesOverlay.tsx b/popup/components/NoEntriesOverlay.tsx new file mode 100644 index 0000000..270a4e2 --- /dev/null +++ b/popup/components/NoEntriesOverlay.tsx @@ -0,0 +1,26 @@ +import { Stack, Text } from "@mantine/core"; +import type { ReactNode } from "react"; + +interface Props { + title: ReactNode; + subtitle?: ReactNode; + description?: ReactNode; +} + +export const NoEntriesOverlay = ({ title, subtitle, description }: Props) => { + return ( + + {title} + {subtitle && ( + + {subtitle} + + )} + {description && ( + + {description} + + )} + + ); +}; diff --git a/popup/pages/AllPage.tsx b/popup/pages/AllPage.tsx index a17839e..a2674a7 100644 --- a/popup/pages/AllPage.tsx +++ b/popup/pages/AllPage.tsx @@ -1,6 +1,7 @@ import { useAtomValue } from "jotai"; import { EntryList } from "~popup/components/EntryList"; +import { NoEntriesOverlay } from "~popup/components/NoEntriesOverlay"; import { entryIdToTagsAtom, reversedEntriesAtom, searchAtom } from "~popup/states/atoms"; export const AllPage = () => { @@ -10,6 +11,16 @@ export const AllPage = () => { return ( + ) : ( + + ) + } entries={reversedEntries.filter( (entry) => search.length === 0 || diff --git a/popup/pages/FavoritesPage.tsx b/popup/pages/FavoritesPage.tsx index eee70ec..2b4da42 100644 --- a/popup/pages/FavoritesPage.tsx +++ b/popup/pages/FavoritesPage.tsx @@ -1,12 +1,16 @@ +import { ActionIcon, Group, Text } from "@mantine/core"; +import { IconStar } from "@tabler/icons-react"; import { useAtomValue } from "jotai"; import { EntryList } from "~popup/components/EntryList"; +import { NoEntriesOverlay } from "~popup/components/NoEntriesOverlay"; import { entryIdToTagsAtom, favoriteEntryIdsSetAtom, reversedEntriesAtom, searchAtom, } from "~popup/states/atoms"; +import { commonActionIconSx } from "~utils/sx"; export const FavoritesPage = () => { const reversedEntries = useAtomValue(reversedEntriesAtom); @@ -16,6 +20,24 @@ export const FavoritesPage = () => { return ( + Mark an item as favorite by clicking on + commonActionIconSx({ theme })}> + + + + } + description="Favorite items are protected from deletion" + /> + ) : ( + + ) + } entries={reversedEntries.filter( (entry) => favoriteEntryIdsSet.has(entry.id) &&