feat: implement new dashboard design

This commit is contained in:
shadcn 2022-11-04 16:55:31 +04:00
parent ae7cb2f01a
commit f21f4b2855
11 changed files with 47 additions and 59 deletions

View file

@ -1,10 +1,11 @@
import { headers } from "next/headers"
import { notFound } from "next/navigation"
import Link from "next/link"
import { getSession } from "@/lib/session"
import { DashboardBranding } from "@/components/dashboard-branding"
import { DashboardNav } from "@/components/dashboard-nav"
import { UserAccountNav } from "@/components/user-account-nav"
import { notFound } from "next/navigation"
import { Icons } from "@/components/icons"
interface DashboardLayoutProps {
children?: React.ReactNode
@ -30,25 +31,28 @@ export default async function DashboardLayout({
}
return (
<>
<div className="flex h-screen overflow-hidden">
<aside className="hidden w-14 flex-col border-r border-slate-100 bg-slate-50 py-4 md:flex lg:w-56 lg:flex-shrink-0 lg:px-4">
<div className="flex flex-1 flex-col space-y-4">
<DashboardBranding />
<DashboardNav />
</div>
<UserAccountNav
user={{
name: user.name,
image: user.image,
email: user.email,
}}
/>
<div className="mx-auto flex h-screen max-w-[1440px] flex-col space-y-6 overflow-hidden px-6">
<header className="flex h-[64px] items-center justify-between pl-2">
<Link href="/" className="flex items-center space-x-2">
<Icons.logo />
<span className="text-lg font-bold">Taxonomy</span>
</Link>
<UserAccountNav
user={{
name: user.name,
image: user.image,
email: user.email,
}}
/>
</header>
<div className="grid grid-cols-[200px_1fr] gap-12">
<aside className="flex w-[200px] flex-col">
<DashboardNav />
</aside>
<main className="flex w-0 flex-1 flex-col overflow-hidden px-12 py-10">
<main className="flex w-full flex-1 flex-col overflow-hidden">
{children}
</main>
</div>
</>
</div>
)
}

View file

@ -1,4 +1,5 @@
import { headers } from "next/headers"
import { User } from "@prisma/client"
import { db } from "@/lib/db"
import { getSession } from "@/lib/session"
@ -8,14 +9,10 @@ import { DashboardShell } from "@/components/dashboard-shell"
import { PostItem } from "@/components/post-item"
import { EmptyPlaceholder } from "@/components/empty-placeholder"
export const dynamic = "force-dynamic"
async function getPosts() {
const session = await getSession(headers().get("cookie"))
async function getPostsForUser(userId: User["id"]) {
return await db.post.findMany({
where: {
authorId: session?.user.id,
authorId: userId,
},
select: {
id: true,
@ -30,7 +27,8 @@ async function getPosts() {
}
export default async function DashboardPage() {
const posts = await getPosts()
const session = await getSession(headers().get("cookie"))
const posts = await getPostsForUser(session?.user.id)
return (
<DashboardShell>

View file

@ -4,7 +4,7 @@ import { EmptyPlaceholder } from "@/components/empty-placeholder"
export default function NotFound() {
return (
<EmptyPlaceholder>
<EmptyPlaceholder className="mx-auto max-w-[800px]">
<EmptyPlaceholder.Icon name="warning" />
<EmptyPlaceholder.Title>Uh oh! Not Found</EmptyPlaceholder.Title>
<EmptyPlaceholder.Description>

View file

@ -1,12 +1,16 @@
import { notFound } from "next/navigation"
import { headers } from "next/headers"
import { Post, User } from "@prisma/client"
import { Editor } from "@/components/editor"
import { db } from "@/lib/db"
import { getSession } from "@/lib/session"
async function getPost(postId: string) {
async function getPostForUser(postId: Post["id"], userId: User["id"]) {
return await db.post.findFirst({
where: {
id: postId,
authorId: userId,
},
})
}
@ -16,7 +20,8 @@ interface EditorPageProps {
}
export default async function EditorPage({ params }: EditorPageProps) {
const post = await getPost(params.postId)
const session = await getSession(headers().get("cookie"))
const post = await getPostForUser(params.postId, session?.user.id)
if (!post) {
notFound()

View file

@ -1,10 +0,0 @@
import { Icons } from "./icons"
export function DashboardBranding() {
return (
<header className="flex items-center space-x-2 px-3">
<Icons.logo />
<span className="font-bold">Taxonomy</span>
</header>
)
}

View file

@ -12,10 +12,10 @@ export function DashboardHeader({
return (
<div className="flex justify-between px-2">
<div className="grid gap-1">
<h1 className="text-xl font-bold tracking-wide text-black">
<h1 className="text-2xl font-bold tracking-wide text-slate-900">
{heading}
</h1>
{text && <p className="text-sm text-neutral-500">{text}</p>}
{text && <p className="text-neutral-500">{text}</p>}
</div>
{children}
</div>

View file

@ -42,7 +42,7 @@ export function DashboardNav() {
const path = usePathname()
return (
<nav className="grid items-start gap-1">
<nav className="grid items-start gap-2">
{navigationItems.map((navigationItem, index) => (
<Link
key={index}
@ -50,7 +50,7 @@ export function DashboardNav() {
>
<span
className={clsx(
"group flex items-center rounded-md px-3 py-2 text-sm font-medium text-slate-600 hover:bg-slate-100",
"group flex items-center rounded-md px-3 py-2 text-sm font-medium text-slate-800 hover:bg-slate-100",
path === navigationItem.href ? "bg-slate-200" : "transparent",
navigationItem.disabled && "cursor-not-allowed opacity-50"
)}

View file

@ -1,7 +1,6 @@
import * as AvatarPrimitive from "@radix-ui/react-avatar"
import { cn } from "@/lib/utils"
import Image, { ImageProps } from "next/image"
type AvatarProps = AvatarPrimitive.AvatarProps
@ -9,7 +8,7 @@ export function Avatar({ className, ...props }: AvatarProps) {
return (
<AvatarPrimitive.Root
className={cn(
"flex h-[48px] w-[48px] items-center justify-center overflow-hidden rounded-full bg-slate-100",
"flex h-[32px] w-[32px] items-center justify-center overflow-hidden rounded-full bg-slate-100",
className
)}
{...props}

View file

@ -29,7 +29,7 @@ DropdownMenu.Content = React.forwardRef<
ref={ref}
align="end"
className={cn(
"overflow-hidden rounded-md bg-white shadow-md animate-in slide-in-from-top-1 md:w-32",
"overflow-hidden rounded-md border border-slate-50 bg-white shadow-md animate-in slide-in-from-top-1 md:w-32",
className
)}
{...props}

View file

@ -2,11 +2,10 @@
import { User } from "next-auth"
import { signOut } from "next-auth/react"
import Link from "next/link"
import { DropdownMenu } from "@/components/ui/dropdown"
import { Icons } from "@/components/icons"
import { UserAvatar } from "./user-avatar"
import Link from "next/link"
import { UserAvatar } from "@/components/user-avatar"
interface UserAccountNavProps extends React.HTMLAttributes<HTMLDivElement> {
user: Pick<User, "name" | "image" | "email">
@ -15,20 +14,13 @@ interface UserAccountNavProps extends React.HTMLAttributes<HTMLDivElement> {
export function UserAccountNav({ user }: UserAccountNavProps) {
return (
<DropdownMenu>
<DropdownMenu.Trigger className="flex items-center gap-2 overflow-hidden rounded-md border bg-white p-2 px-2 hover:bg-slate-100 focus:ring-2 focus:ring-brand-900 focus:ring-offset-2 focus-visible:outline-none">
<DropdownMenu.Trigger className="flex items-center gap-2 overflow-hidden focus:ring-2 focus:ring-brand-900 focus:ring-offset-2 focus-visible:outline-none">
<UserAvatar user={{ name: user.name, image: user.image }} />
<div className="flex flex-1 flex-col items-start">
{user.name && <p className="text-sm font-medium">{user.name}</p>}
<p className="rounded-md bg-brand px-2 py-[2px] text-[10px] uppercase text-white">
Pro
</p>
</div>
<Icons.ellipsis className="h-4 w-4" />
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content className="md:w-[240px]" align="start">
<DropdownMenu.Content className="mt-2 md:w-[240px]" align="end">
<div className="flex items-center justify-start gap-2 p-4">
<div className="flex flex-col leading-none">
<div className="flex flex-col space-y-1 leading-none">
{user.name && <p className="font-medium">{user.name}</p>}
{user.email && (
<p className="w-[200px] truncate text-sm text-slate-600">

View file

@ -14,7 +14,7 @@ export function UserAvatar({ user, ...props }: UserAvatarProps) {
<Avatar.Image alt="Picture" src={user.image} />
<Avatar.Fallback>
<span className="sr-only">{user.name}</span>
<Icons.user className="h-6 w-6" />
<Icons.user className="h-4 w-4" />
</Avatar.Fallback>
</Avatar>
)