From b761dcbcea9849d5d545da4b686a391f2d96aca4 Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Mon, 20 Nov 2023 23:30:11 +0900 Subject: [PATCH] [WIP] Feat/frontend/profile (#67) * [frontend] Add skeleton with shadcn - `npx shadcn-ui@latest add skeleton` * [frontend] Add a separator with shadcn - `npx shadcn-ui@latest add separator` * [frontend] Add profile pages * [frontend] Fix navbar --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- frontend/app/profile/account/page.tsx | 3 ++ frontend/app/profile/appearance/page.tsx | 3 ++ frontend/app/profile/display/page.tsx | 3 ++ frontend/app/profile/layout.tsx | 54 ++++++++++++++++++++ frontend/app/profile/notifications/page.tsx | 3 ++ frontend/app/profile/page.tsx | 48 ++++++++++++++++++ frontend/app/ui/layout/stack.tsx | 55 +++++++++++++++++++++ frontend/app/ui/nav.tsx | 55 +++++++++++---------- frontend/app/ui/sidebar-nav.tsx | 44 +++++++++++++++++ frontend/components/ui/separator.tsx | 31 ++++++++++++ frontend/components/ui/skeleton.tsx | 15 ++++++ frontend/package-lock.json | 32 +++++++++++- frontend/package.json | 1 + 13 files changed, 321 insertions(+), 26 deletions(-) create mode 100644 frontend/app/profile/account/page.tsx create mode 100644 frontend/app/profile/appearance/page.tsx create mode 100644 frontend/app/profile/display/page.tsx create mode 100644 frontend/app/profile/layout.tsx create mode 100644 frontend/app/profile/notifications/page.tsx create mode 100644 frontend/app/profile/page.tsx create mode 100644 frontend/app/ui/layout/stack.tsx create mode 100644 frontend/app/ui/sidebar-nav.tsx create mode 100644 frontend/components/ui/separator.tsx create mode 100644 frontend/components/ui/skeleton.tsx diff --git a/frontend/app/profile/account/page.tsx b/frontend/app/profile/account/page.tsx new file mode 100644 index 00000000..e025bc6c --- /dev/null +++ b/frontend/app/profile/account/page.tsx @@ -0,0 +1,3 @@ +export default function AccountPage() { + return
Account Page
; +} diff --git a/frontend/app/profile/appearance/page.tsx b/frontend/app/profile/appearance/page.tsx new file mode 100644 index 00000000..a8a5b219 --- /dev/null +++ b/frontend/app/profile/appearance/page.tsx @@ -0,0 +1,3 @@ +export default function AppearancePage() { + return
Appearance Page
; +} diff --git a/frontend/app/profile/display/page.tsx b/frontend/app/profile/display/page.tsx new file mode 100644 index 00000000..64e09cc4 --- /dev/null +++ b/frontend/app/profile/display/page.tsx @@ -0,0 +1,3 @@ +export default function DisplayPage() { + return
Display Page
; +} diff --git a/frontend/app/profile/layout.tsx b/frontend/app/profile/layout.tsx new file mode 100644 index 00000000..aba695ee --- /dev/null +++ b/frontend/app/profile/layout.tsx @@ -0,0 +1,54 @@ +import { Separator } from "@/components/ui/separator"; +import { SidebarNav } from "@/app/ui/sidebar-nav"; + +const sidebarNavItems = [ + { + title: "Profile", + href: "/profile", + }, + { + title: "Account", + href: "/profile/account", + }, + { + title: "Appearance", + href: "/profile/appearance", + }, + { + title: "Notifications", + href: "/profile/notifications", + }, + { + title: "Display", + href: "/profile/display", + }, +]; + +interface SettingsLayoutProps { + children: React.ReactNode; +} + +export default function SettingsLayout({ children }: SettingsLayoutProps) { + return ( + <> +
+
Can't be displayed.
+
+
+
+

Settings

+

+ Manage your account settings and set e-mail preferences. +

+
+ +
+ +
{children}
+
+
+ + ); +} diff --git a/frontend/app/profile/notifications/page.tsx b/frontend/app/profile/notifications/page.tsx new file mode 100644 index 00000000..1b527372 --- /dev/null +++ b/frontend/app/profile/notifications/page.tsx @@ -0,0 +1,3 @@ +export default function NotificationsPage() { + return
Notifications Page
; +} diff --git a/frontend/app/profile/page.tsx b/frontend/app/profile/page.tsx new file mode 100644 index 00000000..91287065 --- /dev/null +++ b/frontend/app/profile/page.tsx @@ -0,0 +1,48 @@ +import { Skeleton } from "@/components/ui/skeleton"; +import { Separator } from "@/components/ui/separator"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Stack } from "@/app/ui/layout/stack"; + +function AvatarSkeleton() { + return ; +} + +type ProfileItemProps = { + title: string; + value: string; +}; + +function ProfileItem({ title, value }: ProfileItemProps) { + return ( + +
{title}:
+ +
+ ); +} + +export default function ProfilePage() { + // Menu: min 100px + // Profile : the rest + return ( + <> +
+
+ + +
Profile
+ +
+ + + + +
+
+
+ + ); +} diff --git a/frontend/app/ui/layout/stack.tsx b/frontend/app/ui/layout/stack.tsx new file mode 100644 index 00000000..408cd34f --- /dev/null +++ b/frontend/app/ui/layout/stack.tsx @@ -0,0 +1,55 @@ +import { cn } from "@/lib/utils"; + +const gaps = { + 0: "gap-0", + 1: "gap-1", + 2: "gap-2", + 3: "gap-3", + 4: "gap-4", + 5: "gap-5", + 6: "gap-6", + 7: "gap-7", + 8: "gap-8", + 9: "gap-9", + 10: "gap-10", + 11: "gap-11", + 12: "gap-12", + 14: "gap-14", + 16: "gap-16", + 20: "gap-20", + 24: "gap-24", + 28: "gap-28", + 32: "gap-32", + 36: "gap-36", + 40: "gap-40", + 44: "gap-44", + 48: "gap-48", + 52: "gap-52", + 56: "gap-56", + 60: "gap-60", + 64: "gap-64", + 72: "gap-72", + 80: "gap-80", + 96: "gap-96", +}; + +type StackProps = { + className?: string; + spacing?: keyof typeof gaps; + children: React.ReactNode; +}; + +export function Stack({ className, spacing = 1, children }: StackProps) { + return ( +
+ {children} +
+ ); +} + +// center +export function HStack({ className, spacing = 1, children }: StackProps) { + return ( +
{children}
+ ); +} diff --git a/frontend/app/ui/nav.tsx b/frontend/app/ui/nav.tsx index 9038a325..736881a8 100644 --- a/frontend/app/ui/nav.tsx +++ b/frontend/app/ui/nav.tsx @@ -1,37 +1,42 @@ -import Image from "next/image"; import { ModeToggle } from "@/components/toggle-mode"; import { Button } from "@/components/ui/button"; import Link from "next/link"; import { signOut } from "@/app/lib/actions"; +import { isLoggedIn } from "@/app/lib/session"; -export default function Nav() { +function AuthorizedMenu() { + return ( +
  • + User List + ChatRoom List +
    + +
    + +
  • + ); +} + +function UnauthorizedMenu() { + return ( +
  • + Sign Up + Log In + +
  • + ); +} + +export default async function Nav() { + const isAuthorized = await isLoggedIn(); return (
    diff --git a/frontend/app/ui/sidebar-nav.tsx b/frontend/app/ui/sidebar-nav.tsx new file mode 100644 index 00000000..d2bed874 --- /dev/null +++ b/frontend/app/ui/sidebar-nav.tsx @@ -0,0 +1,44 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; + +interface SidebarNavProps extends React.HTMLAttributes { + items: { + href: string; + title: string; + }[]; +} + +export function SidebarNav({ className, items, ...props }: SidebarNavProps) { + const pathname = usePathname(); + + return ( + + ); +} diff --git a/frontend/components/ui/separator.tsx b/frontend/components/ui/separator.tsx new file mode 100644 index 00000000..9ac3b95f --- /dev/null +++ b/frontend/components/ui/separator.tsx @@ -0,0 +1,31 @@ +"use client"; + +import * as React from "react"; +import * as SeparatorPrimitive from "@radix-ui/react-separator"; + +import { cn } from "@/lib/utils"; + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref, + ) => ( + + ), +); +Separator.displayName = SeparatorPrimitive.Root.displayName; + +export { Separator }; diff --git a/frontend/components/ui/skeleton.tsx b/frontend/components/ui/skeleton.tsx new file mode 100644 index 00000000..2cdf440d --- /dev/null +++ b/frontend/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/lib/utils"; + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
    + ); +} + +export { Skeleton }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1b6c8020..1567a952 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,6 +11,7 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "class-variance-authority": "^0.7.0", @@ -23,12 +24,14 @@ "react-dom": "^18", "socket.io-client": "^4.7.2", "tailwind-merge": "^1.14.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "uuid": "^9.0.1" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/uuid": "^9.0.7", "autoprefixer": "^10", "eslint": "^8", "eslint-config-next": "14.0.2", @@ -858,6 +861,15 @@ "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1" + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz", + "integrity": "sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", @@ -1129,6 +1141,12 @@ "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==", "devOptional": true }, + "node_modules/@types/uuid": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", + "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==", + "dev": true + }, "node_modules/@typescript-eslint/parser": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", @@ -5083,6 +5101,18 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 503b7c36..7deae2d6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "class-variance-authority": "^0.7.0",