diff --git a/package.json b/package.json index 40da872..92e30f2 100644 --- a/package.json +++ b/package.json @@ -143,6 +143,10 @@ "types": "./dist/molecules/Notifications.d.ts", "default": "./dist/molecules/Notifications.js" }, + "./molecules/NotFound": { + "types": "./dist/molecules/NotFound.d.ts", + "default": "./dist/molecules/NotFound.js" + }, "./SpeziProvider": { "types": "./dist/SpeziProvider.d.ts", "default": "./dist/SpeziProvider.js" diff --git a/src/index.ts b/src/index.ts index 89e9a2e..d32295c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,12 @@ import './main.css' export * from './utils/className' +export * from './utils/date' +export * from './utils/file' +export * from './utils/misc' export * from './utils/tailwind' +export * from './utils/useOpenState' +export * from './utils/navigator' export * from './theme/light' export * from './theme/utils' export * from './components/Avatar' @@ -43,6 +48,7 @@ export * from './molecules/AsideBrandLayout' export * from './molecules/DashboardLayout' export * from './molecules/ConfirmDeleteDialog' export * from './molecules/Notifications' +export * from './molecules/NotFound' export * from './modules/auth/user' export * from './modules/auth/SignInForm' export * from './modules/auth/hooks' diff --git a/src/molecules/NotFound/NotFound.stories.tsx b/src/molecules/NotFound/NotFound.stories.tsx new file mode 100644 index 0000000..11cebac --- /dev/null +++ b/src/molecules/NotFound/NotFound.stories.tsx @@ -0,0 +1,30 @@ +// +// This source file is part of the Stanford Biodesign Digital Health Spezi Web Design System open-source project +// +// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import { type Meta, type StoryObj } from '@storybook/react' +import { NotFound } from './NotFound' + +const meta: Meta = { + title: 'Molecules/NotFound', + component: NotFound, +} + +export default meta + +type Story = StoryObj + +export const Generic: Story = { + args: { backPage: { href: '/', name: 'home' }, entityName: 'page' }, +} + +export const UserNotFound: Story = { + args: { + backPage: { href: '/users', name: 'users list' }, + entityName: 'user', + }, +} diff --git a/src/molecules/NotFound/NotFound.test.tsx b/src/molecules/NotFound/NotFound.test.tsx new file mode 100644 index 0000000..52da2fc --- /dev/null +++ b/src/molecules/NotFound/NotFound.test.tsx @@ -0,0 +1,28 @@ +// +// This source file is part of the Stanford Biodesign Digital Health Spezi Web Design System open-source project +// +// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import { screen } from '@testing-library/react' +import { renderWithProviders } from '@/tests/helpers' +import { NotFound } from './' + +describe('NotFound', () => { + it('renders not found error page', () => { + renderWithProviders( + , + ) + + const backLink = screen.getByRole('link', { name: /users/ }) + expect(backLink).toBeInTheDocument() + + const title = screen.getByText(`This user doesn't exist`) + expect(title).toBeInTheDocument() + }) +}) diff --git a/src/molecules/NotFound/NotFound.tsx b/src/molecules/NotFound/NotFound.tsx new file mode 100644 index 0000000..2aef818 --- /dev/null +++ b/src/molecules/NotFound/NotFound.tsx @@ -0,0 +1,89 @@ +// +// This source file is part of the Stanford Biodesign Digital Health Spezi Web Design System open-source project +// +// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import { Link } from '@tanstack/react-router' +import { RouteOff } from 'lucide-react' +import { type ComponentProps, type ReactNode } from 'react' +import { Button } from '@/components/Button' +import { cn } from '@/utils/className' + +export const NotFoundIcon = ({ + className, + ...props +}: Omit, 'children'>) => ( +
+ +
+) + +export const NotFoundContainer = ({ + className, + ...props +}: ComponentProps<'div'>) => ( +
+) + +export const NotFoundTitle = ({ + className, + ...props +}: ComponentProps<'h1'>) => ( +

+) + +export const NotFoundParagraph = ({ + className, + ...props +}: ComponentProps<'p'>) => ( +

+) + +interface NotFoundActionProps extends ComponentProps {} + +export const NotFoundAction = (props: NotFoundActionProps) => ( +