add account frontend elements w/ sample
All checks were successful
Build and Push Docker Image / build_and_push (push) Successful in 6m11s

This commit is contained in:
Aidan 2025-01-25 20:23:27 -05:00
parent 1ac3dd8e28
commit a8f4de04b4
11 changed files with 300 additions and 4 deletions

View File

@ -0,0 +1,106 @@
"use client"
import { useState } from "react"
import { Flex, Text, Card, Progress, Grid, Box } from "@radix-ui/themes"
import { Mail, GitBranch, Music, Key, CheckCircle, XCircle } from "lucide-react"
import Sidebar from "../../components/account/Sidebar"
export default function Dashboard() {
const [diskUsage, setDiskUsage] = useState(75)
return (
<Flex>
<Sidebar />
<Flex direction="column" className="flex-1 p-8">
<Text size="8" weight="bold" className="mb-6">
Dashboard
</Text>
<Grid columns="2" gap="4">
<Card className="p-6">
<Text size="6" weight="bold" className="mb-4">
Disk Usage
</Text>
<Flex direction="column" gap="2" className="mt-8">
<Progress value={diskUsage} />
<Text>{diskUsage}% of 100GB used</Text>
</Flex>
</Card>
<Card className="p-6">
<Text size="6" weight="bold" className="mb-4">
Account Security
</Text>
<Flex direction="column" gap="2" className="mt-3">
<Flex align="center" gap="2">
<CheckCircle className="text-green-500" />
<Text>Spam Protection</Text>
</Flex>
<Flex align="center" gap="2">
<XCircle className="text-red-500" />
<Text>Two-Factor Authentication</Text>
</Flex>
</Flex>
</Card>
<Card className="p-6">
<Text size="6" weight="bold" className="mb-4">
Services
</Text>
<Grid columns="2" gap="4" className="mt-4">
<Flex align="center" gap="2">
<Mail className="text-blue-500" />
<Text>Mail</Text>
</Flex>
<Flex align="center" gap="2">
<GitBranch className="text-purple-500" />
<Text>Git</Text>
</Flex>
<Flex align="center" gap="2">
<Music className="text-green-500" />
<Text>Music</Text>
</Flex>
<Flex align="center" gap="2">
<Key className="text-yellow-500" />
<Text>Password Manager</Text>
</Flex>
</Grid>
</Card>
<Card className="p-6">
<Text size="6" weight="bold" className="mb-4">
Linked Accounts
</Text>
<Flex direction="column" gap="2" className="mt-6">
<Flex align="center" gap="2">
<Box className="w-4 h-4 rounded-full bg-green-500" />
<Text>p0ntus mail</Text>
</Flex>
<Flex align="center" gap="2">
<Box className="w-4 h-4 rounded-full bg-green-500" />
<Text>LibreCloud Git</Text>
</Flex>
</Flex>
</Card>
<Card className="p-6">
<Text size="6" weight="bold" className="mb-4">
LibreCloud Git
</Text>
<Flex align="center" gap="4" className="mt-4">
<Box className="w-16 h-16 rounded-full bg-gray-700 flex items-center justify-center">
</Box>
<Flex direction="column" gap="1">
<Text size="5" weight="bold">
username
</Text>
<Text>12 repositories</Text>
</Flex>
</Flex>
</Card>
</Grid>
</Flex>
</Flex>
)
}

15
app/account/layout.tsx Normal file
View File

@ -0,0 +1,15 @@
import { Theme } from "@radix-ui/themes"
import "@radix-ui/themes/styles.css"
export default function AccountLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<Theme appearance="dark" accentColor="blue" grayColor="slate">
<div className="min-h-screen bg-gray-900">{children}</div>
</Theme>
)
}

View File

@ -0,0 +1,60 @@
"use client"
import Link from "next/link"
import { useState } from "react"
import { TextField, Button, Flex, Text, Card } from "@radix-ui/themes"
import { Mail, Lock } from "lucide-react"
export default function Login() {
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
}
return (
<Flex className="h-screen" align="center" justify="center">
<Card className="w-full max-w-md p-6">
<form onSubmit={handleSubmit}>
<Text size="5" weight="bold">
Log in to your account
</Text>
<Flex direction="column" gap="4" className="mt-6">
<TextField.Root
placeholder="Email"
type="email"
value={email}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
required
>
<TextField.Slot>
<Mail height="16" width="16" />
</TextField.Slot>
</TextField.Root>
<TextField.Root
placeholder="Password"
type="password"
value={password}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)}
className="mb-3"
required
>
<TextField.Slot>
<Lock height="16" width="16" />
</TextField.Slot>
</TextField.Root>
<Button color="gray" variant="outline" type="submit" highContrast>Log in</Button>
<Link
href="https://user.pontusmail.org/admin/user/signup"
className="text-sm underline text-center"
>
I don&apos;t have an account
</Link>
</Flex>
</form>
</Card>
</Flex>
)
}

View File

@ -0,0 +1,25 @@
"use client"
import { useEffect } from "react"
import { Flex, Text, Spinner } from "@radix-ui/themes"
import { useRouter } from "next/navigation"
export default function Logout() {
const router = useRouter()
useEffect(() => {
const timer = setTimeout(() => {
router.push("/account/login")
}, 5000)
return () => clearTimeout(timer)
}, [router])
return (
<Flex direction="column" justify="center" align="center" className="h-screen" gap="4">
<Spinner size="3" />
<Text size="5">Logging out...</Text>
</Flex>
)
}

View File

@ -0,0 +1,38 @@
"use client"
import { useState } from "react"
import { Flex, Text, Switch, Button } from "@radix-ui/themes"
import Sidebar from "../../components/account/Sidebar"
export default function Settings() {
const [darkMode, setDarkMode] = useState(true)
const [notifications, setNotifications] = useState(true)
return (
<Flex>
<Sidebar />
<Flex direction="column" className="flex-1 p-8">
<Text size="8" weight="bold" className="mb-6">
Settings
</Text>
<Flex direction="column" gap="4" className="mt-4" style={{ maxWidth: "500px" }}>
<Flex justify="between" align="center">
<Text size="4">Dark Mode</Text>
<Switch checked={darkMode} onCheckedChange={setDarkMode} />
</Flex>
<Flex justify="between" align="center" className="mb-4">
<Text size="4">Enable Notifications</Text>
<Switch checked={notifications} onCheckedChange={setNotifications} />
</Flex>
<Flex justify="center" gap="4" align="center">
<Button>Save Changes</Button>
<Button color="gray" variant="outline" highContrast>
Go Back
</Button>
</Flex>
</Flex>
</Flex>
</Flex>
)
}

View File

@ -2,7 +2,7 @@
import { useState } from "react"
import Link from "next/link"
import { Menu, X, Server, Home } from "lucide-react"
import { Menu, X, Server, Home, User } from "lucide-react"
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false)
@ -19,17 +19,23 @@ const Navbar = () => {
<div className="hidden md:block">
<div className="ml-10 flex items-center space-x-4">
<Link
href="#"
href="/"
className="flex items-center text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
>
<Home className="mr-2 h-5 w-5" /> Home
</Link>
<Link
href="#services"
href="/#services"
className="flex items-center text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
>
<Server className="mr-2 h-5 w-5" /> Services
</Link>
<Link
href="/account"
className="flex items-center text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
>
<User className="mr-2 h-5 w-5" /> My Account
</Link>
</div>
</div>
<div className="md:hidden">
@ -64,6 +70,12 @@ const Navbar = () => {
>
<Server className="mr-2 h-5 w-5" /> Services
</Link>
<Link
href="/account"
className="flex items-center text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium"
>
<User className="mr-2 h-5 w-5" /> My Account
</Link>
</div>
</div>
)}

View File

@ -0,0 +1,38 @@
import Link from "next/link"
import { Cog, LogOut, Gauge } from "lucide-react"
import { Flex, Card } from "@radix-ui/themes"
import { usePathname } from "next/navigation"
const Sidebar = () => {
const pathname = usePathname()
const navItems = [
{ href: "/account/dashboard", icon: Gauge, label: "Dashboard" },
{ href: "/account/settings", icon: Cog, label: "Settings" },
{ href: "/account/logout", icon: LogOut, label: "Logout" },
]
return (
<Card className="w-64 h-screen bg-gray-800 p-4">
<Flex direction="column" gap="2">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`
flex items-center px-4 py-2 rounded-md text-white
transition-colors duration-200
${pathname === item.href ? "bg-blue-600 hover:bg-blue-700" : "hover:bg-gray-700"}
`}
>
<item.icon className="w-5 h-5 mr-3" />
<span className="text-sm font-medium">{item.label}</span>
</Link>
))}
</Flex>
</Card>
)
}
export default Sidebar

View File

@ -69,4 +69,4 @@ body {
body {
@apply bg-background text-foreground;
}
}
}

View File

@ -3,6 +3,7 @@ import type { Metadata } from "next"
import Head from "next/head"
import { Inter } from "next/font/google"
import Navbar from "../app/components/Navbar"
import "@radix-ui/themes/styles.css";
const inter = Inter({ subsets: ["latin"] })

BIN
bun.lockb

Binary file not shown.

View File

@ -10,6 +10,7 @@
},
"dependencies": {
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/themes": "^3.2.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.474.0",