diff --git a/frontend/README.md b/frontend/README.md index 84e17f4..aaba163 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -12,7 +12,7 @@ pnpm dev Open [http://localhost:3001](http://localhost:3000) with your browser to see the result. -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +You can start editing the page by modifying `app/workspace-members.tsx`. The page auto-updates as you edit the file. This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. diff --git a/frontend/components.json b/frontend/components.json deleted file mode 100644 index b4caaa7..0000000 --- a/frontend/components.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": true, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "src/app/globals.css", - "baseColor": "zinc", - "cssVariables": true - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils" - } -} diff --git a/frontend/package.json b/frontend/package.json index fb28adf..0c87674 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,17 +11,9 @@ }, "dependencies": { "@hocuspocus/provider": "^2.5.0", - "@hookform/resolvers": "^3.3.1", - "@radix-ui/react-dialog": "^1.0.4", - "@radix-ui/react-icons": "^1.3.0", - "@radix-ui/react-label": "^2.0.2", - "@radix-ui/react-popover": "^1.0.6", - "@radix-ui/react-scroll-area": "^1.0.4", - "@radix-ui/react-select": "^1.2.2", - "@radix-ui/react-separator": "^1.0.3", - "@radix-ui/react-slot": "^1.0.2", - "@radix-ui/react-toast": "^1.1.4", - "@radix-ui/react-tooltip": "^1.0.6", + "@mantine/core": "^7.0.0", + "@mantine/form": "^7.0.0", + "@mantine/hooks": "^7.0.0", "@tabler/icons-react": "^2.32.0", "@tanstack/react-query": "^4.33.0", "@tanstack/react-table": "^8.9.3", @@ -33,35 +25,30 @@ "@tiptap/pm": "^2.1.8", "@tiptap/react": "^2.1.8", "@tiptap/starter-kit": "^2.1.8", - "@types/node": "20.4.8", - "@types/react": "18.2.18", - "@types/react-dom": "18.2.7", - "autoprefixer": "10.4.14", "axios": "^1.4.0", - "class-variance-authority": "^0.7.0", - "clsx": "^2.0.0", - "cmdk": "^0.2.0", - "eslint": "8.46.0", - "eslint-config-next": "13.4.13", "jotai": "^2.3.1", "jotai-optics": "^0.3.1", "js-cookie": "^3.0.5", - "next": "13.4.13", - "next-themes": "^0.2.1", - "postcss": "8.4.27", + "next": "13.5.3", "react": "18.2.0", "react-dom": "18.2.0", - "react-hook-form": "^7.45.4", "react-hot-toast": "^2.4.1", - "tailwind-merge": "^1.14.0", - "tailwindcss": "3.3.3", - "tailwindcss-animate": "^1.0.6", - "typescript": "5.1.6", + "typescript": "5.2.2", "yjs": "^13.6.7", "zod": "^3.22.2" }, "devDependencies": { "@types/js-cookie": "^3.0.3", - "optics-ts": "^2.4.1" + "@types/node": "20.4.8", + "@types/react": "18.2.18", + "@types/react-dom": "18.2.7", + "autoprefixer": "^10.4.16", + "eslint": "8.46.0", + "eslint-config-next": "13.4.13", + "optics-ts": "^2.4.1", + "postcss": "^8.4.30", + "postcss-preset-env": "^9.1.4", + "postcss-preset-mantine": "^1.7.0", + "postcss-simple-vars": "^7.0.1" } } diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js index 33ad091..6d7b423 100644 --- a/frontend/postcss.config.js +++ b/frontend/postcss.config.js @@ -1,6 +1,16 @@ module.exports = { plugins: { - tailwindcss: {}, autoprefixer: {}, + "postcss-preset-env": {}, + "postcss-preset-mantine": {}, + "postcss-simple-vars": { + variables: { + "mantine-breakpoint-xs": "36em", + "mantine-breakpoint-sm": "48em", + "mantine-breakpoint-md": "62em", + "mantine-breakpoint-lg": "75em", + "mantine-breakpoint-xl": "88em", + }, + }, }, -} +}; diff --git a/frontend/src/app/(auth)/layout.tsx b/frontend/src/app/(auth)/layout.tsx index 65aae78..bf542f1 100644 --- a/frontend/src/app/(auth)/layout.tsx +++ b/frontend/src/app/(auth)/layout.tsx @@ -3,5 +3,5 @@ interface AuthLayoutProps { } export default function AuthLayout({ children }: AuthLayoutProps) { - return
{children}
+ return
{children}
} diff --git a/frontend/src/app/(auth)/login/page.tsx b/frontend/src/app/(auth)/login/page.tsx index 3ba8c90..287f941 100644 --- a/frontend/src/app/(auth)/login/page.tsx +++ b/frontend/src/app/(auth)/login/page.tsx @@ -1,49 +1,7 @@ -"use client" +'use client'; -import Link from "next/link"; -import { cn } from "@/lib/utils"; -import { buttonVariants } from "@/components/ui/button"; -import { Icons } from "@/components/icons"; -import { ChevronLeftIcon } from "@radix-ui/react-icons"; -import { LoginForm } from "@/features/auth/components/login-form"; -import LegalTerms from "@/features/auth/components/legal-terms"; +import { LoginForm } from '@/features/auth/components/login-form'; export default function LoginPage() { - return ( -
- - - <> - Back - - - -
-
- -

- Welcome back -

-

- Enter your email and password to continue -

-
- -

- - Don't have an account? Sign Up - -

- - - -
-
- ); + return ; } diff --git a/frontend/src/app/(auth)/signup/page.tsx b/frontend/src/app/(auth)/signup/page.tsx index 17dc762..884e90b 100644 --- a/frontend/src/app/(auth)/signup/page.tsx +++ b/frontend/src/app/(auth)/signup/page.tsx @@ -1,52 +1,7 @@ -"use client" +'use client'; -import Link from "next/link"; -import { cn } from "@/lib/utils"; -import { buttonVariants } from "@/components/ui/button"; -import { Icons } from "@/components/icons"; -import { ChevronLeftIcon } from "@radix-ui/react-icons"; -import { SignUpForm } from "@/features/auth/components/sign-up-form"; -import LegalTerms from "@/features/auth/components/legal-terms"; +import { SignUpForm } from '@/features/auth/components/sign-up-form'; export default function SignUpPage() { - - return ( -
- - - <> - Back - - - -
-
- -

- Create an account -

-

- Enter your name, email and password to signup -

-
- - - -

- - Already have an account? Sign In - -

- - - -
-
- ); + return ; } diff --git a/frontend/src/app/(dashboard)/(page)/p/[pageId]/page.tsx b/frontend/src/app/(dashboard)/(page)/p/[pageId]/page.tsx index d2cf8c1..9db64e5 100644 --- a/frontend/src/app/(dashboard)/(page)/p/[pageId]/page.tsx +++ b/frontend/src/app/(dashboard)/(page)/p/[pageId]/page.tsx @@ -12,7 +12,7 @@ export default function Page() { return (
- +
); } diff --git a/frontend/src/app/(dashboard)/home/page.tsx b/frontend/src/app/(dashboard)/home/page.tsx index ef79bfd..a7f6874 100644 --- a/frontend/src/app/(dashboard)/home/page.tsx +++ b/frontend/src/app/(dashboard)/home/page.tsx @@ -1,9 +1,9 @@ -"use client"; +'use client'; -import { useAtom } from "jotai"; -import { currentUserAtom } from "@/features/user/atoms/current-user-atom"; +import { useAtom } from 'jotai'; +import { currentUserAtom } from '@/features/user/atoms/current-user-atom'; -export default function Home() { +export default function HomeB() { const [currentUser] = useAtom(currentUserAtom); return ( diff --git a/frontend/src/app/(dashboard)/layout.tsx b/frontend/src/app/(dashboard)/layout.tsx index d59615d..941c2a9 100644 --- a/frontend/src/app/(dashboard)/layout.tsx +++ b/frontend/src/app/(dashboard)/layout.tsx @@ -1,9 +1,9 @@ -"use client" +'use client'; -import dynamic from "next/dynamic"; -import { UserProvider } from "@/features/user/user-provider"; +import dynamic from 'next/dynamic'; +import { UserProvider } from '@/features/user/user-provider'; -const Shell = dynamic(() => import("./shell"), { +const Shell = dynamic(() => import('./shell'), { ssr: false, }); @@ -14,11 +14,7 @@ export default function DashboardLayout({ children }: { return ( -
-
- {children} -
-
+ {children}
); diff --git a/frontend/src/app/(dashboard)/settings/account/page.tsx b/frontend/src/app/(dashboard)/settings/account/page.tsx deleted file mode 100644 index caf06aa..0000000 --- a/frontend/src/app/(dashboard)/settings/account/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client'; - -import AccountNameForm from '@/features/user/components/account-name-form'; -import ChangePassword from "@/features/user/components/change-password"; -import ChangeEmail from "@/features/user/components/change-email"; -import { Separator } from "@/components/ui/separator"; -import React from "react"; - -export default function Home() { - - return ( - <> - - - - - - - - - - ); -} diff --git a/frontend/src/app/(dashboard)/settings/layout.tsx b/frontend/src/app/(dashboard)/settings/layout.tsx deleted file mode 100644 index 99e1c5c..0000000 --- a/frontend/src/app/(dashboard)/settings/layout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { ReactNode } from 'react'; - -export default function SettingsLayout({ children }: { children: ReactNode }) { - return ( - <> - {children} - - ); -} diff --git a/frontend/src/app/(dashboard)/settings/page.tsx b/frontend/src/app/(dashboard)/settings/page.tsx deleted file mode 100644 index 2c7e396..0000000 --- a/frontend/src/app/(dashboard)/settings/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -'use client'; - -import { useRouter } from 'next/navigation'; -import { useEffect } from 'react'; - -export default function Home() { - const router = useRouter(); - - useEffect(() => { - router.push('/settings/account'); - }, [router]); - - return <>; -} diff --git a/frontend/src/app/(dashboard)/settings/workspace/members/page.tsx b/frontend/src/app/(dashboard)/settings/workspace/members/page.tsx deleted file mode 100644 index 80c350a..0000000 --- a/frontend/src/app/(dashboard)/settings/workspace/members/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -"use client"; - -import { Separator } from "@/components/ui/separator"; -import WorkspaceInviteSection from "@/features/workspace/components/workspace-invite-section"; -import React from "react"; -import WorkspaceInviteDialog from "@/features/workspace/components/workspace-invite-dialog"; - -const WorkspaceMembersTable = React.lazy(() => import('@/features/workspace/components/workspace-members-table')); - -export default function WorkspaceMembers() { - return ( - <> - - - - -
-

Members

- - - - - -
- - ); -} diff --git a/frontend/src/app/(dashboard)/settings/workspace/page.tsx b/frontend/src/app/(dashboard)/settings/workspace/page.tsx deleted file mode 100644 index 790e6ad..0000000 --- a/frontend/src/app/(dashboard)/settings/workspace/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -'use client'; - -import WorkspaceNameForm from "@/features/workspace/components/workspace-name-form"; - - -export default function Home() { - - return (); -} diff --git a/frontend/src/app/(dashboard)/shell.tsx b/frontend/src/app/(dashboard)/shell.tsx index 84eb57e..1404919 100644 --- a/frontend/src/app/(dashboard)/shell.tsx +++ b/frontend/src/app/(dashboard)/shell.tsx @@ -1,23 +1,54 @@ 'use client'; -import Sidebar from '@/components/sidebar/sidebar'; -import TopBar from '@/components/sidebar/topbar'; +import { desktopSidebarAtom } from '@/components/navbar/atoms/sidebar-atom'; +import { useToggleSidebar } from '@/components/navbar/hooks/use-toggle-sidebar'; +import { Navbar } from '@/components/navbar/navbar'; +import { AppShell, Burger, Group } from '@mantine/core'; +import { useDisclosure } from '@mantine/hooks'; +import { useAtom } from 'jotai'; export default function Shell({ children }: { children: React.ReactNode }) { + const [mobileOpened, { toggle: toggleMobile }] = useDisclosure(); + const [desktopOpened] = useAtom(desktopSidebarAtom); + const toggleDesktop = useToggleSidebar(desktopSidebarAtom); + + return ( -
- + + + + + -
- + Header -
- {children} -
-
-
+ + + + + + + + {children} + ); } diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css deleted file mode 100644 index 0ca07ba..0000000 --- a/frontend/src/app/globals.css +++ /dev/null @@ -1,76 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - :root { - --background: 0 0% 100%; - --foreground: 240 10% 3.9%; - - --card: 0 0% 100%; - --card-foreground: 240 10% 3.9%; - - --popover: 0 0% 100%; - --popover-foreground: 240 10% 3.9%; - - --primary: 240 5.9% 10%; - --primary-foreground: 0 0% 98%; - - --secondary: 240 4.8% 95.9%; - --secondary-foreground: 240 5.9% 10%; - - --muted: 240 4.8% 95.9%; - --muted-foreground: 240 3.8% 46.1%; - - --accent: 240 4.8% 95.9%; - --accent-foreground: 240 5.9% 10%; - - --destructive: 0 62.8% 50.6%; - --destructive-foreground: 0 0% 98%; - - --border: 240 5.9% 90%; - --input: 240 5.9% 90%; - --ring: 240 10% 3.9%; - - --radius: 0.5rem; - } - - .dark { - --background: 0 0% 10%; - --foreground: 0 0% 85%; - - --card: 0 0% 10%; - --card-foreground: 0 0% 85%; - - --popover: 0 0% 10%; - --popover-foreground: 0 0% 85%; - - --primary: 0 0% 98%; - --primary-foreground: 240 5.9% 10%; - - --secondary: 240 3.7% 15.9%; - --secondary-foreground: 0 0% 85%; - - --muted: 240 3.7% 15.9%; - --muted-foreground: 240 5% 64.9%; - - --accent: 240 3.7% 15.9%; - --accent-foreground: 0 0% 85%; - - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 0% 98%; - - --border: 240 3.7% 15.9%; - --input: 240 3.7% 15.9%; - --ring: 240 4.9% 83.9%; - } -} - -@layer base { - * { - @apply border-border; - } - body { - @apply bg-background text-foreground; - } -} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 3d54eaa..3eb5508 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,12 +1,9 @@ -import './globals.css' -import type { Metadata } from 'next' -import { Inter } from 'next/font/google' -import { cn } from "@/lib/utils"; -import { ThemeProvider } from "@/components/providers/theme-provider"; -import { TanstackProvider } from "@/components/providers/tanstack-provider"; -import CustomToaster from "@/components/ui/custom-toaster"; - -const inter = Inter({ subsets: ['latin'] }) +import '@mantine/core/styles.css'; +import type { Metadata } from 'next'; +import { TanstackProvider } from '@/components/providers/tanstack-provider'; +import CustomToaster from '@/components/ui/custom-toaster'; +import { theme } from '@/app/theme'; +import { ColorSchemeScript, MantineProvider } from '@mantine/core'; export const metadata: Metadata = { title: 'Create Next App', @@ -16,25 +13,26 @@ export const metadata: Metadata = { initialScale: 1, maximumScale: 1, }, -} +}; export default function RootLayout({ children, }: { - children: React.ReactNode + children: React.ReactNode; }) { - return ( - - - - {children} - - - - + + + + + + + {children} + + + + - ) - + ); } diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 07e3637..d10c2ec 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,18 +1,5 @@ -import {ThemeToggle} from "@/components/theme-toggle"; +import { Welcome } from '@/components/welcome/welcome'; export default function Home() { - return ( -
-
-

- Get started by editing  - src/app/page.tsx -

-
- -
-
- -
- ) + return ; } diff --git a/frontend/src/app/theme.ts b/frontend/src/app/theme.ts new file mode 100644 index 0000000..63df4d8 --- /dev/null +++ b/frontend/src/app/theme.ts @@ -0,0 +1,7 @@ +'use client'; + +import { createTheme } from '@mantine/core'; + +export const theme = createTheme({ + +}); diff --git a/frontend/src/components/sidebar/atoms/sidebar-atom.ts b/frontend/src/components/navbar/atoms/sidebar-atom.ts similarity index 58% rename from frontend/src/components/sidebar/atoms/sidebar-atom.ts rename to frontend/src/components/navbar/atoms/sidebar-atom.ts index a5d6f5d..77386c0 100644 --- a/frontend/src/components/sidebar/atoms/sidebar-atom.ts +++ b/frontend/src/components/navbar/atoms/sidebar-atom.ts @@ -1,5 +1,3 @@ import { atomWithWebStorage } from "@/lib/jotai-helper"; -import { atom } from "jotai"; -export const desktopSidebarAtom = atomWithWebStorage('showSidebar',true); -export const mobileSidebarAtom = atom(false); +export const desktopSidebarAtom = atomWithWebStorage('showSidebar',true); \ No newline at end of file diff --git a/frontend/src/components/sidebar/hooks/use-toggle-sidebar.ts b/frontend/src/components/navbar/hooks/use-toggle-sidebar.ts similarity index 74% rename from frontend/src/components/sidebar/hooks/use-toggle-sidebar.ts rename to frontend/src/components/navbar/hooks/use-toggle-sidebar.ts index 5dbe3ba..c951ce2 100644 --- a/frontend/src/components/sidebar/hooks/use-toggle-sidebar.ts +++ b/frontend/src/components/navbar/hooks/use-toggle-sidebar.ts @@ -1,6 +1,6 @@ import { useAtom } from "jotai"; -export function useToggleSidebar(sidebarAtom) { +export function useToggleSidebar(sidebarAtom: any) { const [sidebarState, setSidebarState] = useAtom(sidebarAtom); return () => { setSidebarState(!sidebarState); diff --git a/frontend/src/components/navbar/navbar.module.css b/frontend/src/components/navbar/navbar.module.css new file mode 100644 index 0000000..312ecbe --- /dev/null +++ b/frontend/src/components/navbar/navbar.module.css @@ -0,0 +1,89 @@ +.navbar { + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); + height: 100%; + width: rem(300px); + padding: var(--mantine-spacing-md); + padding-top: 0; + display: flex; + flex-direction: column; + border-right: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); +} + +.section { + margin-left: calc(var(--mantine-spacing-md) * -1); + margin-right: calc(var(--mantine-spacing-md) * -1); + margin-bottom: var(--mantine-spacing-md); + + &:not(:last-of-type) { + border-bottom: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); + } +} + +.searchCode { + font-weight: 700; + font-size: rem(10px); + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-7)); + border: rem(1px) solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-7)); +} + +.menuItems { + padding-left: calc(var(--mantine-spacing-md) - var(--mantine-spacing-xs)); + padding-right: calc(var(--mantine-spacing-md) - var(--mantine-spacing-xs)); + padding-bottom: var(--mantine-spacing-md); +} + +.menu { + display: flex; + align-items: center; + width: 100%; + font-size: var(--mantine-font-size-sm); + padding: rem(8px) var(--mantine-spacing-xs); + border-radius: var(--mantine-radius-sm); + font-weight: 500; + color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0)); + + & + :hover { + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); + color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0)); + } +} + +.menuItemInner { + display: flex; + align-items: center; + flex: 1; +} + +.menuItemIcon { + margin-right: var(--mantine-spacing-sm); + color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-2)); +} + +.pages { + padding-left: calc(var(--mantine-spacing-md) - rem(6px)); + padding-right: calc(var(--mantine-spacing-md) - rem(6px)); + padding-bottom: var(--mantine-spacing-md); +} + +.pagesHeader { + padding-left: calc(var(--mantine-spacing-md) + rem(2px)); + padding-right: var(--mantine-spacing-md); + margin-bottom: rem(5px); +} + +.pageLink { + display: block; + padding: rem(8px) var(--mantine-spacing-xs); + text-decoration: none; + border-radius: var(--mantine-radius-sm); + font-size: var(--mantine-font-size-xs); + color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0)); + line-height: 1; + font-weight: 500; + + &:hover { + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); + color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0)); + } +} diff --git a/frontend/src/components/navbar/navbar.tsx b/frontend/src/components/navbar/navbar.tsx new file mode 100644 index 0000000..0e4cb3a --- /dev/null +++ b/frontend/src/components/navbar/navbar.tsx @@ -0,0 +1,118 @@ +import { + UnstyledButton, + Text, + Group, + ActionIcon, + Tooltip, + rem, +} from '@mantine/core'; +import { + IconSearch, + IconPlus, + IconSettings, + IconFilePlus, +} from '@tabler/icons-react'; + +import classes from './navbar.module.css'; +import { UserButton } from './user-button'; +import React from 'react'; +import { useAtom } from 'jotai'; +import { settingsModalAtom } from '@/features/settings/modal/atoms/settings-modal-atom'; +import SettingsModal from '@/features/settings/modal/settings-modal'; + +interface PrimaryMenuItem { + icon: React.ElementType; + label: string; + onClick?: () => void; +} + +interface PageItem { + emoji: string; + label: string; +} + +const primaryMenu: PrimaryMenuItem[] = [ + { icon: IconSearch, label: 'Search' }, + { icon: IconSettings, label: 'Settings' }, + { icon: IconFilePlus, label: 'New Page' }, +]; + +const pages: PageItem[] = [ + { emoji: '👍', label: 'Sales' }, + { emoji: '🚚', label: 'Deliveries' }, + { emoji: '💸', label: 'Discounts' }, + { emoji: '💰', label: 'Profits' }, + { emoji: '✨', label: 'Reports' }, + { emoji: '🛒', label: 'Orders' }, + { emoji: '📅', label: 'Events' }, + { emoji: '🙈', label: 'Debts' }, + { emoji: '💁‍♀️', label: 'Customers' }, +]; + +export function Navbar() { + const [, setSettingsModalOpen] = useAtom(settingsModalAtom); + + const handleMenuItemClick = (label: string) => { + if (label === 'Settings') { + setSettingsModalOpen(true); + } + }; + + const primaryMenuItems = primaryMenu.map((menuItem) => ( + handleMenuItemClick(menuItem.label)} + > +
+ + {menuItem.label} +
+
+ )); + + const pageLinks = pages.map((page) => ( + event.preventDefault()} + key={page.label} + className={classes.pageLink} + > + + {page.emoji} + {' '} + {page.label} + + )); + + return ( + <> + + + + + ); +} diff --git a/frontend/src/components/navbar/user-button.module.css b/frontend/src/components/navbar/user-button.module.css new file mode 100644 index 0000000..8b33814 --- /dev/null +++ b/frontend/src/components/navbar/user-button.module.css @@ -0,0 +1,10 @@ +.user { + display: block; + width: 100%; + padding: var(--mantine-spacing-md); + color: light-dark(var(--mantine-color-black), var(--mantine-color-dark-0)); + + @mixin hover { + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-8)); + } + } \ No newline at end of file diff --git a/frontend/src/components/navbar/user-button.tsx b/frontend/src/components/navbar/user-button.tsx new file mode 100644 index 0000000..1785148 --- /dev/null +++ b/frontend/src/components/navbar/user-button.tsx @@ -0,0 +1,28 @@ +import { UnstyledButton, Group, Avatar, Text, rem } from '@mantine/core'; +import { IconChevronRight } from '@tabler/icons-react'; +import classes from './user-button.module.css'; + +export function UserButton() { + return ( + + + + +
+ + Harriette Spoonlicker + + + + hspoonlicker@outlook.com + +
+ + +
+
+ ); +} diff --git a/frontend/src/components/providers/tanstack-provider.tsx b/frontend/src/components/providers/tanstack-provider.tsx index 5a01ac8..9a4a172 100644 --- a/frontend/src/components/providers/tanstack-provider.tsx +++ b/frontend/src/components/providers/tanstack-provider.tsx @@ -1,4 +1,4 @@ -'use client' +'use client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import React from 'react'; @@ -7,9 +7,9 @@ const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnMount: false, - refetchOnWindowFocus: false - } - } + refetchOnWindowFocus: false, + }, + }, }); export function TanstackProvider({ children }: React.PropsWithChildren) { diff --git a/frontend/src/components/providers/theme-provider.tsx b/frontend/src/components/providers/theme-provider.tsx deleted file mode 100644 index 9866cb1..0000000 --- a/frontend/src/components/providers/theme-provider.tsx +++ /dev/null @@ -1,15 +0,0 @@ -"use client" - -import * as React from "react" -import { ThemeProvider as NextThemesProvider } from "next-themes" -import { ThemeProviderProps } from "next-themes/dist/types" - -import { TooltipProvider } from "@/components/ui/tooltip" - -export function ThemeProvider({ children, ...props }: ThemeProviderProps) { - return ( - - {children} - - ) -} diff --git a/frontend/src/components/sidebar/navigation/navigation-items.tsx b/frontend/src/components/sidebar/navigation/navigation-items.tsx deleted file mode 100644 index 8e4d18a..0000000 --- a/frontend/src/components/sidebar/navigation/navigation-items.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { ReactNode } from 'react'; -import { - IconHome, - IconSearch, - IconSettings, - IconFilePlus, -} from '@tabler/icons-react'; -import NavigationLink from "@/components/sidebar/navigation/navigation-link"; -import ButtonWithIcon from "@/components/ui/button-with-icon"; - -export type NavigationMenuType = { - label: string; - path: string; - icon: ReactNode; - target?: string, - onClick?: React.MouseEventHandler; -}; - -export const navigationMenu: NavigationMenuType[] = [ - { - label: 'Home', - path: '', - icon: , - target: '/home', - }, - { - label: 'Search', - path: '', - icon: , - }, - { - label: 'Settings', - path: '', - icon: , - target: '/settings/account' - }, - { - label: 'New Page', - path: '', - icon: , - }, -]; - -export const renderMenuItem = (menu, index) => { - if (menu.target) { - return ( - - {menu.label} - - ); - } - - return ( - - {menu.label} - - ); -}; diff --git a/frontend/src/components/sidebar/navigation/navigation-link.tsx b/frontend/src/components/sidebar/navigation/navigation-link.tsx deleted file mode 100644 index d04ef56..0000000 --- a/frontend/src/components/sidebar/navigation/navigation-link.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ReactNode } from "react"; -import { buttonVariants } from "@/components/ui/button"; -import Link from "next/link"; -import { cn } from "@/lib/utils"; - -interface NavigationLinkProps { - children: ReactNode, - href: string; - icon?: ReactNode; - variant?: "default" | "ghost" | "outline"; - className?: string; -} - -export default function NavigationLink({ children, href, icon, variant = "ghost", className }: NavigationLinkProps) { - return ( - - {icon && - {icon} - } - - {children} - - - ); -} diff --git a/frontend/src/components/sidebar/navigation/navigation.tsx b/frontend/src/components/sidebar/navigation/navigation.tsx deleted file mode 100644 index 1e5323d..0000000 --- a/frontend/src/components/sidebar/navigation/navigation.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { SidebarSection } from "@/components/sidebar/sidebar-section"; -import { navigationMenu, renderMenuItem } from "@/components/sidebar/navigation/navigation-items"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import NavigationLink from "@/components/sidebar/navigation/navigation-link"; -import { IconFileText } from "@tabler/icons-react"; - -import React from "react"; - -export default function Navigation() { - return ( -
- - -
- ); -} - -function PrimaryNavigation() { - return ( - - {navigationMenu.map(renderMenuItem)} - - ); -} - -function SecondaryNavigationArea() { - return ( - -
- } - > - Welcome page - -
-
- ); -} diff --git a/frontend/src/components/sidebar/sidebar-section.tsx b/frontend/src/components/sidebar/sidebar-section.tsx deleted file mode 100644 index 3c1cb4d..0000000 --- a/frontend/src/components/sidebar/sidebar-section.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, { ReactNode } from "react"; -import { cn } from "@/lib/utils"; - -interface SidebarSectionProps { - className?: string; - children: ReactNode -} - -export function SidebarSection({className, children}: SidebarSectionProps) { - return ( -
- {children} -
- ) -} diff --git a/frontend/src/components/sidebar/sidebar-toggle-button.tsx b/frontend/src/components/sidebar/sidebar-toggle-button.tsx deleted file mode 100644 index a9cc510..0000000 --- a/frontend/src/components/sidebar/sidebar-toggle-button.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import { useIsMobile } from '@/hooks/use-is-mobile'; -import { - desktopSidebarAtom, - mobileSidebarAtom, -} from '@/components/sidebar/atoms/sidebar-atom'; -import { useToggleSidebar } from './hooks/use-toggle-sidebar'; -import ButtonWithIcon from '../ui/button-with-icon'; -import { - IconLayoutSidebarLeftCollapse, - IconLayoutSidebarRightCollapse, -} from '@tabler/icons-react'; -import { useAtom } from 'jotai'; -import { cn } from '@/lib/utils'; - -interface SidebarToggleButtonProps { - className?: string; -} - -export default function SidebarToggleButton({ - className, -}: SidebarToggleButtonProps) { - const isMobile = useIsMobile(); - const sidebarStateAtom = isMobile ? mobileSidebarAtom : desktopSidebarAtom; - - const [isSidebarOpen] = useAtom(sidebarStateAtom); - const toggleSidebar = useToggleSidebar(sidebarStateAtom); - - const SidebarIcon = isSidebarOpen - ? IconLayoutSidebarLeftCollapse - : IconLayoutSidebarRightCollapse; - - return ( - } - variant={'ghost'} - onClick={toggleSidebar} - /> - ); -} - -export function MobileSidebarToggle({ isSidebarOpen }) { - return ( - - ); -} diff --git a/frontend/src/components/sidebar/sidebar.tsx b/frontend/src/components/sidebar/sidebar.tsx deleted file mode 100644 index 7e0562f..0000000 --- a/frontend/src/components/sidebar/sidebar.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useIsMobile } from "@/hooks/use-is-mobile"; -import { useAtom } from "jotai"; -import { - desktopSidebarAtom, - mobileSidebarAtom, -} from "@/components/sidebar/atoms/sidebar-atom"; -import { MobileSidebarToggle } from "./sidebar-toggle-button"; -import SettingsNav from "@/features/settings/nav/settings-nav"; -import { usePathname } from "next/navigation"; -import React, { useEffect } from "react"; -import Navigation from "@/components/sidebar/navigation/navigation"; - -export default function Sidebar() { - const isMobile = useIsMobile(); - const pathname = usePathname(); - const [isSidebarOpen, setIsSidebarOpen] = useAtom(isMobile ? mobileSidebarAtom : desktopSidebarAtom); - const isSettings = pathname.startsWith("/settings"); - - const mobileClass = "fixed top-0 left-0 h-screen z-50 bg-background"; - const sidebarWidth = isSidebarOpen ? "w-[270px]" : "w-[0px]"; - - const closeSidebar = () => { - setIsSidebarOpen(false); - }; - - useEffect(() => { - if (isMobile) { - setIsSidebarOpen(false); - } - }, [pathname, isMobile, setIsSidebarOpen]); - - return ( - <> - {isMobile && isSidebarOpen && ( -
-
- )} - - - - ); -} diff --git a/frontend/src/components/sidebar/topbar.tsx b/frontend/src/components/sidebar/topbar.tsx deleted file mode 100644 index f1b4561..0000000 --- a/frontend/src/components/sidebar/topbar.tsx +++ /dev/null @@ -1,21 +0,0 @@ -'use client'; - -import { useIsMobile } from '@/hooks/use-is-mobile'; -import SidebarToggleButton from './sidebar-toggle-button'; - -export default function TopBar() { - const isMobile = useIsMobile(); - - return ( -
-
-
-
- {!isMobile && } -
- -
-
-
- ); -} diff --git a/frontend/src/components/theme-toggle.tsx b/frontend/src/components/theme-toggle.tsx index a7e0cad..1b803ea 100644 --- a/frontend/src/components/theme-toggle.tsx +++ b/frontend/src/components/theme-toggle.tsx @@ -1,23 +1,15 @@ -"use client" +'use client'; -import * as React from "react" -import { MoonIcon, SunIcon } from "@radix-ui/react-icons" -import { useTheme } from "next-themes" - -import { Button } from "@/components/ui/button" +import { Button, Group, useMantineColorScheme } from '@mantine/core'; export function ThemeToggle() { - const { setTheme, theme } = useTheme() + const { setColorScheme } = useMantineColorScheme(); return ( - - ) + + + + + + ); } diff --git a/frontend/src/components/ui/badge.tsx b/frontend/src/components/ui/badge.tsx deleted file mode 100644 index e87d62b..0000000 --- a/frontend/src/components/ui/badge.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const badgeVariants = cva( - "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", - { - variants: { - variant: { - default: - "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80", - secondary: - "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", - destructive: - "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80", - outline: "text-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) - -export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} - -function Badge({ className, variant, ...props }: BadgeProps) { - return ( -
- ) -} - -export { Badge, badgeVariants } diff --git a/frontend/src/components/ui/button-with-icon.tsx b/frontend/src/components/ui/button-with-icon.tsx deleted file mode 100644 index 685a3d4..0000000 --- a/frontend/src/components/ui/button-with-icon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React, { forwardRef, ReactNode } from 'react'; -import { Button } from '@/components/ui/button'; - -interface ButtonIconProps { - icon: ReactNode; - children?: ReactNode; -} - -type Props = ButtonIconProps & React.ComponentPropsWithoutRef; - -const ButtonWithIcon = forwardRef( - ({ icon, children, ...rest }, ref) => { - return ( - - ); - } -); - -ButtonWithIcon.displayName = 'ButtonWithIcon'; - -export default ButtonWithIcon; diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx deleted file mode 100644 index 28d1e4b..0000000 --- a/frontend/src/components/ui/button.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const buttonVariants = cva( - "whitespace-nowrap inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", - { - variants: { - variant: { - default: - "bg-primary text-primary-foreground shadow hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", - outline: - "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8", - icon: "h-7 w-7", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) - -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean -} - -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" - return ( - - ) - } -) -Button.displayName = "Button" - -export { Button, buttonVariants } diff --git a/frontend/src/components/ui/card.tsx b/frontend/src/components/ui/card.tsx deleted file mode 100644 index 77e9fb7..0000000 --- a/frontend/src/components/ui/card.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -Card.displayName = "Card" - -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardHeader.displayName = "CardHeader" - -const CardTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardTitle.displayName = "CardTitle" - -const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardDescription.displayName = "CardDescription" - -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardContent.displayName = "CardContent" - -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardFooter.displayName = "CardFooter" - -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/frontend/src/components/ui/command.tsx b/frontend/src/components/ui/command.tsx deleted file mode 100644 index 6f4a5eb..0000000 --- a/frontend/src/components/ui/command.tsx +++ /dev/null @@ -1,155 +0,0 @@ -"use client" - -import * as React from "react" -import { DialogProps } from "@radix-ui/react-dialog" -import { MagnifyingGlassIcon } from "@radix-ui/react-icons" -import { Command as CommandPrimitive } from "cmdk" - -import { cn } from "@/lib/utils" -import { Dialog, DialogContent } from "@/components/ui/dialog" - -const Command = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -Command.displayName = CommandPrimitive.displayName - -interface CommandDialogProps extends DialogProps {} - -const CommandDialog = ({ children, ...props }: CommandDialogProps) => { - return ( - - - - {children} - - - - ) -} - -const CommandInput = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( -
- - -
-)) - -CommandInput.displayName = CommandPrimitive.Input.displayName - -const CommandList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) - -CommandList.displayName = CommandPrimitive.List.displayName - -const CommandEmpty = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->((props, ref) => ( - -)) - -CommandEmpty.displayName = CommandPrimitive.Empty.displayName - -const CommandGroup = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) - -CommandGroup.displayName = CommandPrimitive.Group.displayName - -const CommandSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -CommandSeparator.displayName = CommandPrimitive.Separator.displayName - -const CommandItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) - -CommandItem.displayName = CommandPrimitive.Item.displayName - -const CommandShortcut = ({ - className, - ...props -}: React.HTMLAttributes) => { - return ( - - ) -} -CommandShortcut.displayName = "CommandShortcut" - -export { - Command, - CommandDialog, - CommandInput, - CommandList, - CommandEmpty, - CommandGroup, - CommandItem, - CommandShortcut, - CommandSeparator, -} diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx deleted file mode 100644 index d6d08ff..0000000 --- a/frontend/src/components/ui/dialog.tsx +++ /dev/null @@ -1,123 +0,0 @@ -"use client" - -import * as React from "react" -import * as DialogPrimitive from "@radix-ui/react-dialog" -import { Cross2Icon } from "@radix-ui/react-icons" - -import { cn } from "@/lib/utils" - -const Dialog = DialogPrimitive.Root - -const DialogTrigger = DialogPrimitive.Trigger - -const DialogPortal = ({ - className, - ...props -}: DialogPrimitive.DialogPortalProps) => ( - -) -DialogPortal.displayName = DialogPrimitive.Portal.displayName - -const DialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName - -const DialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)) -DialogContent.displayName = DialogPrimitive.Content.displayName - -const DialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogHeader.displayName = "DialogHeader" - -const DialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogFooter.displayName = "DialogFooter" - -const DialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogTitle.displayName = DialogPrimitive.Title.displayName - -const DialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogDescription.displayName = DialogPrimitive.Description.displayName - -export { - Dialog, - DialogTrigger, - DialogContent, - DialogHeader, - DialogFooter, - DialogTitle, - DialogDescription, -} diff --git a/frontend/src/components/ui/form.tsx b/frontend/src/components/ui/form.tsx deleted file mode 100644 index 3eae0c7..0000000 --- a/frontend/src/components/ui/form.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import * as React from "react" -import * as LabelPrimitive from "@radix-ui/react-label" -import { Slot } from "@radix-ui/react-slot" -import { - Controller, - ControllerProps, - FieldPath, - FieldValues, - FormProvider, - useFormContext, -} from "react-hook-form" - -import { cn } from "@/lib/utils" -import { Label } from "@/components/ui/label" - -const Form = FormProvider - -type FormFieldContextValue< - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath -> = { - name: TName -} - -const FormFieldContext = React.createContext( - {} as FormFieldContextValue -) - -const FormField = < - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath ->({ - ...props -}: ControllerProps) => { - return ( - - - - ) -} - -const useFormField = () => { - const fieldContext = React.useContext(FormFieldContext) - const itemContext = React.useContext(FormItemContext) - const { getFieldState, formState } = useFormContext() - - const fieldState = getFieldState(fieldContext.name, formState) - - if (!fieldContext) { - throw new Error("useFormField should be used within ") - } - - const { id } = itemContext - - return { - id, - name: fieldContext.name, - formItemId: `${id}-form-item`, - formDescriptionId: `${id}-form-item-description`, - formMessageId: `${id}-form-item-message`, - ...fieldState, - } -} - -type FormItemContextValue = { - id: string -} - -const FormItemContext = React.createContext( - {} as FormItemContextValue -) - -const FormItem = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => { - const id = React.useId() - - return ( - -
- - ) -}) -FormItem.displayName = "FormItem" - -const FormLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { - const { error, formItemId } = useFormField() - - return ( -