diff --git a/apps/app/src/components/decisions/EmptyProposalsState.tsx b/apps/app/src/components/decisions/EmptyProposalsState.tsx deleted file mode 100644 index aaaa03707..000000000 --- a/apps/app/src/components/decisions/EmptyProposalsState.tsx +++ /dev/null @@ -1,19 +0,0 @@ -'use client'; - -import { ReactNode } from 'react'; -import { LuLeaf } from 'react-icons/lu'; - -export function EmptyProposalsState({ children }: { children: ReactNode }) { - return ( -
-
- -
-
-
- {children} -
-
-
- ); -} diff --git a/apps/app/src/components/decisions/MyBallot.tsx b/apps/app/src/components/decisions/MyBallot.tsx index ca704b060..f93568f73 100644 --- a/apps/app/src/components/decisions/MyBallot.tsx +++ b/apps/app/src/components/decisions/MyBallot.tsx @@ -3,11 +3,12 @@ import { useUser } from '@/utils/UserProvider'; import { trpc } from '@op/api/client'; import { Checkbox } from '@op/ui/Checkbox'; +import { EmptyState } from '@op/ui/EmptyState'; import { Header3 } from '@op/ui/Header'; +import { LuLeaf } from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n'; -import { EmptyProposalsState } from './EmptyProposalsState'; import { ProposalCardContent, ProposalCardDescription, @@ -20,11 +21,11 @@ import { VotingProposalCard } from './VotingProposalCard'; export const NoVoteFound = () => { const t = useTranslations(); return ( - + }> {t('You did not vote in this process.')} - + ); }; diff --git a/apps/app/src/components/decisions/ProposalsList.tsx b/apps/app/src/components/decisions/ProposalsList.tsx index 6059e32ab..c8183a716 100644 --- a/apps/app/src/components/decisions/ProposalsList.tsx +++ b/apps/app/src/components/decisions/ProposalsList.tsx @@ -7,6 +7,7 @@ import { match } from '@op/core'; import { Button, ButtonLink } from '@op/ui/Button'; import { Checkbox } from '@op/ui/Checkbox'; import { Dialog, DialogTrigger } from '@op/ui/Dialog'; +import { EmptyState } from '@op/ui/EmptyState'; import { Header3 } from '@op/ui/Header'; import { Modal } from '@op/ui/Modal'; import { Select, SelectItem } from '@op/ui/Select'; @@ -14,13 +15,12 @@ import { Skeleton } from '@op/ui/Skeleton'; import { Surface } from '@op/ui/Surface'; import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; -import { LuArrowDownToLine } from 'react-icons/lu'; +import { LuArrowDownToLine, LuLeaf } from 'react-icons/lu'; import type { z } from 'zod'; import { useTranslations } from '@/lib/i18n'; import { Bullet } from '../Bullet'; -import { EmptyProposalsState } from './EmptyProposalsState'; import { ProposalCard, ProposalCardActions, @@ -113,14 +113,14 @@ export const ProposalListSkeleton = () => { const NoProposalsFound = () => { const t = useTranslations(); return ( - + }> {t('No proposals found matching the current filters.')}

{t('Try adjusting your filter selection above.')}

-
+ ); }; diff --git a/apps/app/src/components/decisions/ResultsList.tsx b/apps/app/src/components/decisions/ResultsList.tsx index ac3704988..6362957de 100644 --- a/apps/app/src/components/decisions/ResultsList.tsx +++ b/apps/app/src/components/decisions/ResultsList.tsx @@ -1,11 +1,12 @@ 'use client'; import { trpc } from '@op/api/client'; +import { EmptyState } from '@op/ui/EmptyState'; import { Header3 } from '@op/ui/Header'; +import { LuLeaf } from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n'; -import { EmptyProposalsState } from './EmptyProposalsState'; import { ProposalCard, ProposalCardContent, @@ -18,14 +19,14 @@ import { const NoProposalsFound = () => { const t = useTranslations(); return ( - + }> {t('No results yet for this decision.')}

{t('Results are still being worked on.')}

-
+ ); }; diff --git a/apps/app/src/components/decisions/pages/ResultsPage.tsx b/apps/app/src/components/decisions/pages/ResultsPage.tsx index 1f89e5650..2ca04fa86 100644 --- a/apps/app/src/components/decisions/pages/ResultsPage.tsx +++ b/apps/app/src/components/decisions/pages/ResultsPage.tsx @@ -3,9 +3,11 @@ import { APIErrorBoundary } from '@/utils/APIErrorBoundary'; import { trpc } from '@op/api/client'; import { match } from '@op/core'; +import { EmptyState } from '@op/ui/EmptyState'; import { Header3 } from '@op/ui/Header'; import { Skeleton } from '@op/ui/Skeleton'; import { Suspense } from 'react'; +import { LuLeaf } from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n/routing'; @@ -15,7 +17,6 @@ import { DecisionResultsTabPanel, DecisionResultsTabs, } from '../DecisionResultsTabs'; -import { EmptyProposalsState } from '../EmptyProposalsState'; import { MyBallot, NoVoteFound } from '../MyBallot'; import { ProposalListSkeleton } from '../ProposalsList'; import { ResultsList } from '../ResultsList'; @@ -146,14 +147,14 @@ function ResultsPageContent({ + }> {t('Results are still being processed.')}

{t('Check back again shortly for the results.')}

- +
), }} > diff --git a/apps/app/src/components/decisions/pages/StandardDecisionPage.tsx b/apps/app/src/components/decisions/pages/StandardDecisionPage.tsx index 51edb68fa..e45c5c74a 100644 --- a/apps/app/src/components/decisions/pages/StandardDecisionPage.tsx +++ b/apps/app/src/components/decisions/pages/StandardDecisionPage.tsx @@ -3,14 +3,15 @@ import { getUniqueSubmitters } from '@/utils/proposalUtils'; import { trpc } from '@op/api/client'; import { match } from '@op/core'; +import { EmptyState } from '@op/ui/EmptyState'; import { Header3 } from '@op/ui/Header'; import { Suspense } from 'react'; +import { LuLeaf } from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n/routing'; import { DecisionActionBar } from '../DecisionActionBar'; import { DecisionHero } from '../DecisionHero'; -import { EmptyProposalsState } from '../EmptyProposalsState'; import { MemberParticipationFacePile } from '../MemberParticipationFacePile'; import { ProposalListSkeleton, ProposalsList } from '../ProposalsList'; @@ -135,14 +136,14 @@ export function StandardDecisionPage({
{proposals.length === 0 ? ( - + }> {t('No proposals yet')}

{t('You could be the first one to submit a proposal')}

-
+ ) : ( }> { + return ( +
+
+
+ {icon ?? } +
+ {children} +
+
+ ); +}; diff --git a/packages/ui/src/components/ui/table.tsx b/packages/ui/src/components/ui/table.tsx index 5084666e0..913f9f45c 100644 --- a/packages/ui/src/components/ui/table.tsx +++ b/packages/ui/src/components/ui/table.tsx @@ -27,9 +27,8 @@ import { import { LuArrowDown } from 'react-icons/lu'; import { twJoin, twMerge } from 'tailwind-merge'; -import { cx } from '@/lib/primitive'; - -import { Checkbox } from '@/components/Checkbox'; +import { cx } from '../../lib/primitive'; +import { Checkbox } from '../Checkbox'; interface TableProps extends Omit { allowResize?: boolean; diff --git a/packages/ui/stories/EmptyState.stories.tsx b/packages/ui/stories/EmptyState.stories.tsx new file mode 100644 index 000000000..c1ae001f0 --- /dev/null +++ b/packages/ui/stories/EmptyState.stories.tsx @@ -0,0 +1,73 @@ +import { LuFileText, LuInbox, LuSearch, LuUsers } from 'react-icons/lu'; + +import { Button } from '../src/components/Button'; +import { EmptyState } from '../src/components/EmptyState'; + +export default { + title: 'EmptyState', + component: EmptyState, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +}; + +export const Default = () => ( + +

No items found

+
+); + +export const WithCustomIcon = () => ( + }> +

Your inbox is empty

+
+); + +export const WithDescription = () => ( + }> +

No results found

+

Try adjusting your search or filters

+
+); + +export const WithAction = () => ( + }> +

No team members

+

+ Get started by inviting your first team member +

+ +
+); + +export const Examples = () => ( +
+
+ +

No items found

+
+
+ +
+ }> +

Your inbox is empty

+
+
+ +
+ }> +

No results found

+

Try adjusting your search

+
+
+ +
+ }> +

No documents

+

Upload your first document

+ +
+
+
+);