feat(dashboard): setting up layout

This commit is contained in:
2025-11-12 16:51:59 +02:00
parent b8b2a15ee9
commit a3f46b6b38
61 changed files with 2957 additions and 123 deletions
@@ -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>
);
}
+30
View File
@@ -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>
);
}