diff --git a/.storybook/main.ts b/.storybook/main.ts
index ab80dbb..2987901 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -10,8 +10,7 @@ export default {
'@storybook/addon-interactions',
],
logLevel: 'error',
- // enable when you have a public folder with assets
- //staticDirs: ['../public'],
+ staticDirs: ['../public'],
typescript: { reactDocgen: false, check: false },
core: { disableTelemetry: true, disableWhatsNewNotifications: true },
framework: {
@@ -19,9 +18,13 @@ export default {
options: { builder: { useSWC: true } },
},
previewBody:
- '' +
// Warning: this should be same as the one in `src/styles/globals.css`
- '
',
+ `
+ `,
+
webpack: async config => ({
...config,
// Performance Hints do not make sense on Storybook as it is bloated by design
diff --git a/.storybook/preview.ts b/.storybook/preview.tsx
similarity index 72%
rename from .storybook/preview.ts
rename to .storybook/preview.tsx
index f6cfcd5..140eca9 100644
--- a/.storybook/preview.ts
+++ b/.storybook/preview.tsx
@@ -1,4 +1,6 @@
+import React from 'react';
import { withThemeByDataAttribute } from '@storybook/addon-themes';
+import { ToastProvider } from '../providers/toast';
import type { Preview, ReactRenderer } from '@storybook/react';
import '../styles/globals.css';
@@ -19,6 +21,11 @@ const preview: Preview = {
defaultTheme: 'light',
attributeName: 'data-theme',
}),
+ Story => (
+
+
+
+ ),
],
};
diff --git a/SECURITY.md b/SECURITY.md
index 4496ba7..6a963d5 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -9,4 +9,4 @@ The project is currently under development, so we only support this version(s) o
| 0.1.X | :white_check_mark: |
> \[!NOTE]\
->There is no compatibility yet with etherpad-lite
+> There is no compatibility yet with etherpad-lite
diff --git a/app/client/page.tsx b/app/client/page.tsx
index 041a541..7ef1dea 100644
--- a/app/client/page.tsx
+++ b/app/client/page.tsx
@@ -2,7 +2,9 @@
import { useEffect } from 'react';
import io from 'socket.io-client';
-const Page = () => {
+import type { FC } from 'react';
+
+const Page: FC = () => {
useEffect(() => {
const socket = io();
socket.on('connect', () => {
diff --git a/app/page.tsx b/app/page.tsx
new file mode 100644
index 0000000..94f28d9
--- /dev/null
+++ b/app/page.tsx
@@ -0,0 +1,6 @@
+import Landing from '@/components/Sections/Landing';
+import type { FC } from 'react';
+
+const Page: FC = () => ;
+
+export default Page;
diff --git a/components/Common/Background/index.module.css b/components/Common/Background/index.module.css
new file mode 100644
index 0000000..05ca869
--- /dev/null
+++ b/components/Common/Background/index.module.css
@@ -0,0 +1,23 @@
+.background {
+ @apply absolute
+ left-0
+ top-0
+ -z-10
+ size-full
+ bg-[url('/static/background.svg')]
+ bg-center
+ bg-no-repeat;
+
+ &::after {
+ @apply absolute
+ inset-0
+ m-auto
+ aspect-square
+ w-[300px]
+ rounded-full
+ bg-ether-400
+ blur-[120px]
+ content-['']
+ dark:bg-ether-700;
+ }
+}
diff --git a/components/Common/Background/index.stories.tsx b/components/Common/Background/index.stories.tsx
new file mode 100644
index 0000000..d164bcf
--- /dev/null
+++ b/components/Common/Background/index.stories.tsx
@@ -0,0 +1,9 @@
+import BluredBackground from './';
+import type { Meta as MetaObj, StoryObj } from '@storybook/react';
+
+type Story = StoryObj;
+type Meta = MetaObj;
+
+export const Default: Story = {};
+
+export default { component: BluredBackground } as Meta;
diff --git a/components/Common/Background/index.tsx b/components/Common/Background/index.tsx
new file mode 100644
index 0000000..9a30612
--- /dev/null
+++ b/components/Common/Background/index.tsx
@@ -0,0 +1,6 @@
+import styles from './index.module.css';
+import type { FC } from 'react';
+
+const BluredBackground: FC = () => ;
+
+export default BluredBackground;
diff --git a/components/Common/Button/index.stories.tsx b/components/Common/Button/index.stories.tsx
index 833d1df..0930227 100644
--- a/components/Common/Button/index.stories.tsx
+++ b/components/Common/Button/index.stories.tsx
@@ -1,4 +1,4 @@
-import { HeartIcon } from '@heroicons/react/20/solid';
+import { Heart } from 'lucide-react';
import Button from './';
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
@@ -9,7 +9,7 @@ const defaultStory: Story = {
args: {
children: (
<>
- We love Etherpad
+ We love Etherpad
>
),
// it's allow to have button on the storybook layout to toggle the disabled state
diff --git a/components/Common/Input/index.module.css b/components/Common/Input/index.module.css
index 6b9554d..668d1dd 100644
--- a/components/Common/Input/index.module.css
+++ b/components/Common/Input/index.module.css
@@ -1,5 +1,6 @@
.inputWrapper {
@apply flex
+ w-full
flex-col
gap-1.5;
diff --git a/components/Common/Select/index.tsx b/components/Common/Select/index.tsx
index 83db3b4..28ff30c 100644
--- a/components/Common/Select/index.tsx
+++ b/components/Common/Select/index.tsx
@@ -1,6 +1,6 @@
'use client';
import * as Primitive from '@radix-ui/react-select';
-import { ChevronDownIcon } from '@heroicons/react/24/outline';
+import { ChevronDown } from 'lucide-react';
import { useId, useMemo } from 'react';
import classNames from 'classnames';
import styles from './index.module.css';
@@ -70,7 +70,7 @@ const Select: FC = ({
id={id}
>
-
+
;
+type Meta = MetaObj;
+
+export const Default: Story = {
+ args: {
+ open: true,
+ duration: 5000,
+ children: 'OK, everything is fine!',
+ },
+};
+
+export const TimedNotification: Story = {
+ args: {
+ duration: 5000,
+ children: 'OK, everything is fine!',
+ },
+};
+
+export const WithJSX: Story = {
+ args: {
+ open: true,
+ children: (
+ <>
+
+ OK, everything is fine!
+ >
+ ),
+ },
+};
+
+export const Success: Story = {
+ args: {
+ open: true,
+ variant: 'success',
+ children: 'OK, everything is fine!',
+ },
+};
+
+export const Error: Story = {
+ args: {
+ open: true,
+ variant: 'error',
+ children: 'Something went wrong!',
+ },
+};
+
+export const Warning: Story = {
+ args: {
+ open: true,
+ variant: 'warning',
+ children: 'Be careful!',
+ },
+};
+
+export default { component: Notification } as Meta;
diff --git a/components/Common/Toast/index.tsx b/components/Common/Toast/index.tsx
new file mode 100644
index 0000000..d5e22f1
--- /dev/null
+++ b/components/Common/Toast/index.tsx
@@ -0,0 +1,35 @@
+import * as ToastPrimitive from '@radix-ui/react-toast';
+import classNames from 'classnames';
+import styles from './index.module.css';
+import type { FC, PropsWithChildren } from 'react';
+
+type ToastProps = PropsWithChildren<{
+ variant?: 'success' | 'error' | 'warning' | 'info';
+ open?: boolean;
+ duration?: number;
+ onChange?: (value: boolean) => void;
+ className?: string;
+}>;
+
+const Toast: FC = ({
+ variant = 'info',
+ open,
+ // 2s duration
+ duration = 2000,
+ onChange,
+ children,
+ className,
+}) => (
+
+
+ {children}
+
+
+);
+
+export default Toast;
diff --git a/components/Logo/Platform/Apple.tsx b/components/Logo/Platform/Apple.tsx
new file mode 100644
index 0000000..fa15ee4
--- /dev/null
+++ b/components/Logo/Platform/Apple.tsx
@@ -0,0 +1,23 @@
+import type { FC, SVGProps } from 'react';
+
+const Apple: FC> = props => (
+
+);
+
+export default Apple;
diff --git a/components/Logo/Platform/Generic.tsx b/components/Logo/Platform/Generic.tsx
new file mode 100644
index 0000000..bdae910
--- /dev/null
+++ b/components/Logo/Platform/Generic.tsx
@@ -0,0 +1,22 @@
+import type { FC, SVGProps } from 'react';
+
+const Generic: FC> = props => (
+
+);
+
+export default Generic;
diff --git a/components/Logo/Platform/Linux.tsx b/components/Logo/Platform/Linux.tsx
new file mode 100644
index 0000000..20d408e
--- /dev/null
+++ b/components/Logo/Platform/Linux.tsx
@@ -0,0 +1,969 @@
+import type { FC, SVGProps } from 'react';
+
+const Linux: FC> = props => (
+
+);
+
+export default Linux;
diff --git a/components/Logo/Platform/Microsoft.tsx b/components/Logo/Platform/Microsoft.tsx
new file mode 100644
index 0000000..4567525
--- /dev/null
+++ b/components/Logo/Platform/Microsoft.tsx
@@ -0,0 +1,19 @@
+import type { FC, SVGProps } from 'react';
+
+const Microsoft: FC> = props => (
+
+);
+
+export default Microsoft;
diff --git a/components/Logo/Platform/platform-logos.stories.tsx b/components/Logo/Platform/platform-logos.stories.tsx
new file mode 100644
index 0000000..4e23205
--- /dev/null
+++ b/components/Logo/Platform/platform-logos.stories.tsx
@@ -0,0 +1,21 @@
+import type { Meta as MetaObj, StoryObj } from '@storybook/react';
+
+import Apple from './Apple';
+import Generic from './Generic';
+import Linux from './Linux';
+import Microsoft from './Microsoft';
+
+export const PlatformLogos: StoryObj = {
+ render: () => (
+
+ ),
+};
+
+export default { title: 'Design System' } as MetaObj;
diff --git a/components/NoteBook/ToolsBar/index.module.css b/components/NoteBook/ToolsBar/index.module.css
new file mode 100644
index 0000000..347229a
--- /dev/null
+++ b/components/NoteBook/ToolsBar/index.module.css
@@ -0,0 +1,31 @@
+.toolsBar {
+ @apply flex
+ items-center
+ justify-between
+ border-b
+ border-gray-200
+ bg-white
+ p-2
+ dark:border-gray-800
+ dark:bg-gray-950;
+
+ .actionGroup {
+ @apply flex
+ items-center
+ justify-center
+ gap-2;
+ }
+
+ button {
+ @apply flex
+ items-center
+ justify-center
+ rounded-md
+ p-2
+ transition
+ duration-200
+ ease-in-out
+ hover:bg-gray-100
+ dark:hover:bg-gray-900;
+ }
+}
diff --git a/components/NoteBook/ToolsBar/index.stories.tsx b/components/NoteBook/ToolsBar/index.stories.tsx
new file mode 100644
index 0000000..ffed697
--- /dev/null
+++ b/components/NoteBook/ToolsBar/index.stories.tsx
@@ -0,0 +1,9 @@
+import ToolsBar from '.';
+import type { Meta as MetaObj, StoryObj } from '@storybook/react';
+
+type Story = StoryObj;
+type Meta = MetaObj;
+
+export const Default: Story = {};
+
+export default { component: ToolsBar } as Meta;
diff --git a/components/NoteBook/ToolsBar/index.tsx b/components/NoteBook/ToolsBar/index.tsx
new file mode 100644
index 0000000..2713a60
--- /dev/null
+++ b/components/NoteBook/ToolsBar/index.tsx
@@ -0,0 +1,122 @@
+import {
+ Bold,
+ Italic,
+ Underline,
+ Strikethrough,
+ ListOrdered,
+ List,
+ Indent,
+ AlignLeft,
+ AlignCenter,
+ AlignRight,
+ AlignJustify,
+ RotateCcw,
+ RotateCw,
+ Image as ImageIcon,
+} from 'lucide-react';
+import Select from '@/components/Common/Select';
+import styles from './index.module.css';
+import type { FC } from 'react';
+
+const colors = [
+ {
+ label: 'Default',
+ value: 'default',
+ },
+ {
+ label: 'Red',
+ value: 'red-500',
+ iconImage: ,
+ },
+ {
+ label: 'Green',
+ value: 'green-500',
+ iconImage: ,
+ },
+ {
+ label: 'Blue',
+ value: 'blue-500',
+ iconImage: ,
+ },
+];
+const fonts = [
+ { label: 'Arial', value: 'Arial' },
+ { label: 'Times New Roman', value: 'Times New Roman' },
+ { label: 'Courier New', value: 'Courier New' },
+ { label: 'Verdana', value: 'Verdana' },
+ { label: 'Georgia', value: 'Georgia' },
+ { label: 'Comic Sans MS', value: 'Comic Sans MS' },
+ { label: 'Trebuchet MS', value: 'Trebuchet MS' },
+ { label: 'Arial Black', value: 'Arial Black' },
+ { label: 'Impact', value: 'Impact' },
+ { label: 'Lucida Console', value: 'Lucida Console' },
+];
+
+const ToolsBar: FC = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+export default ToolsBar;
diff --git a/components/Sections/Landing/index.module.css b/components/Sections/Landing/index.module.css
new file mode 100644
index 0000000..de4db06
--- /dev/null
+++ b/components/Sections/Landing/index.module.css
@@ -0,0 +1,33 @@
+.landing {
+ @apply mx-auto
+ flex
+ size-full
+ max-w-md
+ flex-col
+ justify-center
+ gap-4
+ text-center;
+
+ p {
+ @apply text-2xl
+ font-bold;
+ }
+
+ .note {
+ @apply text-sm
+ font-light
+ text-gray-500
+ dark:text-gray-400;
+ }
+
+ form {
+ @apply flex
+ w-full
+ flex-col
+ gap-4;
+
+ button {
+ @apply border-gray-950 dark:border;
+ }
+ }
+}
diff --git a/components/Sections/Landing/index.stories.tsx b/components/Sections/Landing/index.stories.tsx
new file mode 100644
index 0000000..ea247bb
--- /dev/null
+++ b/components/Sections/Landing/index.stories.tsx
@@ -0,0 +1,9 @@
+import Landing from './';
+import type { Meta as MetaObj, StoryObj } from '@storybook/react';
+
+type Story = StoryObj;
+type Meta = MetaObj;
+
+export const Default: Story = {};
+
+export default { component: Landing } as Meta;
diff --git a/components/Sections/Landing/index.tsx b/components/Sections/Landing/index.tsx
new file mode 100644
index 0000000..6f5d0ed
--- /dev/null
+++ b/components/Sections/Landing/index.tsx
@@ -0,0 +1,24 @@
+import Button from '@/components/Common/Button';
+import BluredBackground from '@/components/Common/Background';
+import Input from '@/components/Common/Input';
+import style from './index.module.css';
+import type { FC } from 'react';
+
+const Landing: FC = () => (
+ <>
+
+
+ Create or open a new note book named:
+
+ If you keep the note book name empty, it will create a random name for
+ you.
+
+
+
+ >
+);
+
+export default Landing;
diff --git a/components/Sections/NotFound/index.tsx b/components/Sections/NotFound/index.tsx
index c2efa81..35340de 100644
--- a/components/Sections/NotFound/index.tsx
+++ b/components/Sections/NotFound/index.tsx
@@ -1,4 +1,4 @@
-import { ArrowRightIcon } from '@heroicons/react/20/solid';
+import { ArrowRight } from 'lucide-react';
import Link from 'next/link';
import style from './index.module.css';
import type { FC } from 'react';
@@ -9,7 +9,7 @@ const NotFoundSection: FC = () => (
The page you requested could not be found.
Go back home
-
+
);
diff --git a/docs/Techincal.md b/docs/Techincal.md
index 35976e6..e1eeef3 100644
--- a/docs/Techincal.md
+++ b/docs/Techincal.md
@@ -10,7 +10,7 @@ This documentation is for Etherpad-next collaborator.
- [PostCSS][]
- [TypeScript][]
- [Storybook][]
-- [heroicons](https://heroicons.com)
+- [`lucide-react`](https://www.lucide.dev)
- [prettier](https://www.prettier.io)
- [eslint](https://www.eslint.org)
diff --git a/package-lock.json b/package-lock.json
index 3c69fe2..29437a5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,10 +8,11 @@
"name": "etherpad-next",
"version": "0.1.0",
"dependencies": {
- "@heroicons/react": "~2.1.1",
"@radix-ui/react-avatar": "~1.0.4",
"@radix-ui/react-select": "~2.0.0",
+ "@radix-ui/react-toast": "~1.1.5",
"classnames": "~2.5.1",
+ "lucide-react": "~0.340.0",
"next": "~14.1.0",
"pino": "~8.19.0",
"pino-pretty": "~10.3.1",
@@ -28,7 +29,6 @@
"@storybook/addon-themes": "~7.6.17",
"@storybook/nextjs": "~7.6.17",
"@storybook/react": "~7.6.10",
- "@types/find-root": "~1.1.4",
"@types/node": "~20.11.20",
"@types/react": "~18.2.58",
"@types/react-dom": "~18.2.19",
@@ -2887,14 +2887,6 @@
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
},
- "node_modules/@heroicons/react": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.1.tgz",
- "integrity": "sha512-JyyN9Lo66kirbCMuMMRPtJxtKJoIsXKS569ebHGGRKbl8s4CtUfLnyKJxteA+vIKySocO4s1SkTkGS4xtG/yEA==",
- "peerDependencies": {
- "react": ">= 16"
- }
- },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -3786,6 +3778,30 @@
}
}
},
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz",
+ "integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-primitive": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz",
@@ -3926,6 +3942,40 @@
}
}
},
+ "node_modules/@radix-ui/react-toast": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.5.tgz",
+ "integrity": "sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-collection": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1",
+ "@radix-ui/react-visually-hidden": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-toggle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
@@ -6225,12 +6275,6 @@
"integrity": "sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==",
"dev": true
},
- "node_modules/@types/find-root": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@types/find-root/-/find-root-1.1.4.tgz",
- "integrity": "sha512-2EXK/+gVhVgtt4JqThbEncORvpYJKzi9tQGmI3EkU2jTgMzQsrPm/hbd5xe5uPdeFzIW5gh2PRvvPjaUsI8vpg==",
- "dev": true
- },
"node_modules/@types/graceful-fs": {
"version": "4.1.9",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
@@ -13544,6 +13588,14 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/lucide-react": {
+ "version": "0.340.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.340.0.tgz",
+ "integrity": "sha512-mWzYhbyy2d+qKuKHh+GWElPwa+kIquTnKbmSLGWOuZy+bjfZCkYD8DQWVFlqI4mQwc4HNxcqcOvtQ7ZS2PwURg==",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
diff --git a/package.json b/package.json
index d2975f7..84d4d7b 100644
--- a/package.json
+++ b/package.json
@@ -18,10 +18,11 @@
"test": "vitest"
},
"dependencies": {
- "@heroicons/react": "~2.1.1",
"@radix-ui/react-avatar": "~1.0.4",
"@radix-ui/react-select": "~2.0.0",
+ "@radix-ui/react-toast": "~1.1.5",
"classnames": "~2.5.1",
+ "lucide-react": "~0.340.0",
"next": "~14.1.0",
"pino": "~8.19.0",
"pino-pretty": "~10.3.1",
diff --git a/providers/toast.tsx b/providers/toast.tsx
new file mode 100644
index 0000000..11e438f
--- /dev/null
+++ b/providers/toast.tsx
@@ -0,0 +1,54 @@
+'use client';
+import * as ToastPrimitive from '@radix-ui/react-toast';
+import { createContext, useState } from 'react';
+import Toast from '@/components/Common/Toast';
+import type {
+ Dispatch,
+ FC,
+ PropsWithChildren,
+ ReactNode,
+ SetStateAction,
+} from 'react';
+
+type ToastContextType = {
+ variant?: 'success' | 'error' | 'warning' | 'info';
+ message: string | ReactNode;
+ duration?: number;
+} | null;
+
+type ToastProps = {
+ viewportClassName?: string;
+} & ToastPrimitive.ToastProviderProps;
+
+const ToastContext = createContext(null);
+
+export const ToastDispatch = createContext<
+ Dispatch>
+>(() => {});
+
+export const ToastProvider: FC> = ({
+ viewportClassName,
+ children,
+ ...props
+}) => {
+ const [notification, dispatch] = useState(null);
+
+ return (
+
+
+
+ {children}
+
+ {notification && (
+
+ {notification.message}
+
+ )}
+
+
+
+ );
+};
diff --git a/public/static/background.svg b/public/static/background.svg
new file mode 100644
index 0000000..05e9d63
--- /dev/null
+++ b/public/static/background.svg
@@ -0,0 +1,81 @@
+
diff --git a/styles/globals.css b/styles/globals.css
index 7dac0ce..adc994d 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -9,14 +9,15 @@
@tailwind utilities;
@tailwind variants;
-html {
- @apply scroll-smooth;
-}
-
+html,
body {
@apply h-screen
w-screen
- bg-gray-100
+ scroll-smooth;
+}
+
+body {
+ @apply bg-gray-100
text-gray-900
dark:bg-gray-900
dark:text-gray-100;