feat(dashboard): setting up layout
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
</div>
|
||||
<div className="bg-muted/50 min-h-screen flex-1 rounded-xl md:min-h-min" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@basango/ui/components/breadcrumb";
|
||||
import { Separator } from "@basango/ui/components/separator";
|
||||
import { SidebarInset, SidebarProvider, SidebarTrigger } from "@basango/ui/components/sidebar";
|
||||
|
||||
import { AppSidebar } from "@/components/sidebar/app-sidebar";
|
||||
import { HydrateClient } from "@/trpc/server";
|
||||
|
||||
export default async function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<HydrateClient>
|
||||
<SidebarProvider>
|
||||
<AppSidebar />
|
||||
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
|
||||
<div className="flex items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<Separator className="mr-2 data-[orientation=vertical]:h-4" orientation="vertical" />
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem className="hidden md:block">
|
||||
<BreadcrumbLink href="#">Building Your Application</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator className="hidden md:block" />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</header>
|
||||
{children}
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
</HydrateClient>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
</div>
|
||||
<div className="bg-muted/50 min-h-screen flex-1 rounded-xl md:min-h-min" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { GalleryVerticalEnd } from "lucide-react";
|
||||
|
||||
import { LoginForm } from "@/components/forms/login-form";
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<div className="grid min-h-svh lg:grid-cols-2">
|
||||
<div className="flex flex-col gap-4 p-6 md:p-10">
|
||||
<div className="flex justify-center gap-2 md:justify-start">
|
||||
<a className="flex items-center gap-2 font-medium" href="#">
|
||||
<div className="bg-primary text-primary-foreground flex size-6 items-center justify-center rounded-md">
|
||||
<GalleryVerticalEnd className="size-4" />
|
||||
</div>
|
||||
Acme Inc.
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex flex-1 items-center justify-center">
|
||||
<div className="w-full max-w-xs">
|
||||
<LoginForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-muted relative hidden lg:block">
|
||||
<img
|
||||
alt="verification placeholder"
|
||||
className="absolute inset-0 h-full w-full object-cover dark:brightness-[0.2] dark:grayscale"
|
||||
src="/placeholder.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@basango/ui/components/button";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function ErrorPage({ reset }: { reset: () => void }) {
|
||||
return (
|
||||
<div className="h-[calc(100vh-200px)] w-full">
|
||||
<div className="mt-8 flex flex-col items-center justify-center h-full">
|
||||
<div className="flex justify-between items-center flex-col mt-8 text-center mb-8">
|
||||
<h2 className="font-medium mb-4">Something went wrong</h2>
|
||||
<p className="text-sm text-[#878787]">
|
||||
An unexpected error has occurred. Please try again
|
||||
<br /> or contact support if the issue persists.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-4">
|
||||
<Button onClick={() => reset()} variant="outline">
|
||||
Try again
|
||||
</Button>
|
||||
|
||||
<Link href="/account/support">
|
||||
<Button>Contact us</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "@basango/ui/globals.css";
|
||||
|
||||
import { Toaster } from "@basango/ui/components/sonner";
|
||||
import { NuqsAdapter } from "nuqs/adapters/next/app";
|
||||
|
||||
import { Providers } from "./providers";
|
||||
|
||||
const geistSans = Geist({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-geist-sans",
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-geist-mono",
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
description: "Basango : The intelligent news curation platform.",
|
||||
metadataBase: new URL("https://dashboard.basango.com"),
|
||||
title: "Basango | AI-powered news curation dashboard",
|
||||
};
|
||||
|
||||
export const viewport = {
|
||||
initialScale: 1,
|
||||
maximumScale: 1,
|
||||
themeColor: [
|
||||
{ media: "(prefers-color-scheme: light)" },
|
||||
{ media: "(prefers-color-scheme: dark)" },
|
||||
],
|
||||
userScalable: false,
|
||||
width: "device-width",
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
params,
|
||||
children,
|
||||
}: Readonly<{
|
||||
params: Promise<{ locale: string }>;
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const { locale } = await params;
|
||||
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
||||
<NuqsAdapter>
|
||||
<Providers locale={locale}>{children}</Providers>
|
||||
<Toaster />
|
||||
</NuqsAdapter>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="h-screen flex flex-col items-center justify-center text-center text-sm text-[#606060]">
|
||||
<h2 className="text-xl font-semibold mb-2">Not Found</h2>
|
||||
<p className="mb-4">Could not find requested resource</p>
|
||||
<Link className="underline" href="/">
|
||||
Return Home
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { I18nProviderClient } from "@/locales/client";
|
||||
import { TRPCReactProvider } from "@/trpc/client";
|
||||
|
||||
type ProviderProps = {
|
||||
locale: string;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export function Providers({ locale, children }: ProviderProps) {
|
||||
return (
|
||||
<TRPCReactProvider>
|
||||
<I18nProviderClient locale={locale}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
disableTransitionOnChange
|
||||
enableColorScheme
|
||||
enableSystem
|
||||
>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</I18nProviderClient>
|
||||
</TRPCReactProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user