update styles and icons

This commit is contained in:
Torben Haack 2024-10-11 21:24:19 +02:00
parent 16beeb94a6
commit 6f4ce01645
9 changed files with 138 additions and 100 deletions

View File

@ -2,76 +2,60 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@layer base { @layer base {
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 0 0% 3.9%; --foreground: 222.2 84% 4.9%;
--card: 0 0% 100%; --card: 0 0% 100%;
--card-foreground: 0 0% 3.9%; --card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%; --popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%; --popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary: 0 0% 9%; --primary-foreground: 210 40% 98%;
--primary-foreground: 0 0% 98%; --secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--secondary: 0 0% 96.1%; --muted: 210 40% 96.1%;
--secondary-foreground: 0 0% 9%; --muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--muted: 0 0% 90.1%; --accent-foreground: 222.2 47.4% 11.2%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%; --destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%; --destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--border: 0 0% 89.8%; --input: 214.3 31.8% 91.4%;
--input: 0 0% 89.8%; --ring: 221.2 83.2% 53.3%;
--ring: 0 0% 3.9%; --radius: 0.75rem;
--chart-1: 12 76% 61%;
--radius: 0.5rem; --chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
} }
.dark { .dark {
--background: 0 0% 3.9%; --background: 222.2 84% 4.9%;
--foreground: 0 0% 98%; --foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card: 0 0% 3.9%; --card-foreground: 210 40% 98%;
--card-foreground: 0 0% 98%; --popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--popover: 0 0% 3.9%; --primary: 217.2 91.2% 59.8%;
--popover-foreground: 0 0% 98%; --primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--primary: 0 0% 98%; --secondary-foreground: 210 40% 98%;
--primary-foreground: 0 0% 9%; --muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--secondary: 0 0% 14.9%; --accent: 217.2 32.6% 17.5%;
--secondary-foreground: 0 0% 98%; --accent-foreground: 210 40% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%; --destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%; --destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--border: 0 0% 14.9%; --input: 217.2 32.6% 17.5%;
--input: 0 0% 14.9%; --ring: 224.3 76.3% 48%;
--ring: 0 0% 83.1%; --chart-1: 220 70% 50%;
} --chart-2: 160 60% 45%;
} --chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
@layer base { --chart-5: 340 75% 55%;
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
} }
} }

View File

@ -24,7 +24,7 @@ export default function RootLayout(props: RootLayoutProps) {
return ( return (
<html lang="de" suppressHydrationWarning> <html lang="de" suppressHydrationWarning>
<head /> <head />
<body className={"min-h-dvh bg-muted font-sans antialiased"}> <body className={"min-h-dvh bg-neutral-200 font-sans antialiased"}>
<Header /> <Header />
<main className="flex-grow max-w-screen-2xl w-full mx-auto flex flex-col p-8 gap-4 text-foreground"> <main className="flex-grow max-w-screen-2xl w-full mx-auto flex flex-col p-8 gap-4 text-foreground">
{children} {children}

View File

@ -1,11 +1,12 @@
import { columns } from "@/app/my/jobs/columns"; import { columns } from "@/app/my/jobs/columns";
import { JobsTable } from "@/app/my/jobs/data-table"; import { JobsTable } from "@/app/my/jobs/data-table";
import { DynamicPrinterCards } from "@/components/dynamic-printer-cards"; import { DynamicPrinterCards } from "@/components/dynamic-printer-cards";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { validateRequest } from "@/server/auth"; import { validateRequest } from "@/server/auth";
import { db } from "@/server/db"; import { db } from "@/server/db";
import { printJobs } from "@/server/db/schema"; import { printJobs } from "@/server/db/schema";
import { desc, eq } from "drizzle-orm"; import { desc, eq } from "drizzle-orm";
import { BoxesIcon, NewspaperIcon } from "lucide-react";
import type { Metadata } from "next"; import type { Metadata } from "next";
export const metadata: Metadata = { export const metadata: Metadata = {
@ -43,8 +44,10 @@ export default async function HomePage() {
{/* NEEDS TO BE FIXED FOR A NEW / EMPTY USER {isLoggedIn && <PersonalizedCards />} */} {/* NEEDS TO BE FIXED FOR A NEW / EMPTY USER {isLoggedIn && <PersonalizedCards />} */}
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Druckerbelegung</CardTitle> <CardTitle className="flex flex-row items-center gap-x-1">
<CardDescription>({printers.length} Verfügbar)</CardDescription> <BoxesIcon className="w-5 h-5" />
<span className="text-lg">Druckerbelegung</span>
</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"> <CardContent className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
<DynamicPrinterCards user={user} /> <DynamicPrinterCards user={user} />
@ -53,8 +56,10 @@ export default async function HomePage() {
{userIsLoggedIn && ( {userIsLoggedIn && (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Druckaufträge</CardTitle> <CardTitle className="flex flex-row items-center gap-x-1">
<CardDescription>Deine aktuellen Druckaufträge</CardDescription> <NewspaperIcon className="w-5 h-5" />
<span className="text-lg">Druckaufträge</span>
</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<JobsTable columns={columns} data={jobs} /> <JobsTable columns={columns} data={jobs} />

View File

@ -34,7 +34,7 @@ export function PrinterReserveForm(props: PrinterReserveFormProps) {
const { userId, printerId, isDialog } = props; const { userId, printerId, isDialog } = props;
const router = useRouter(); const router = useRouter();
const { toast } = useToast(); const { toast } = useToast();
const [lock, setLocked] = useState(false); const [isLocked, setLocked] = useState(false);
const form = useForm<z.infer<typeof formSchema>>({ const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema), resolver: zodResolver(formSchema),
@ -46,8 +46,11 @@ export function PrinterReserveForm(props: PrinterReserveFormProps) {
}); });
async function onSubmit(values: z.infer<typeof formSchema>) { async function onSubmit(values: z.infer<typeof formSchema>) {
if (!lock) { if (!isLocked) {
setLocked(true); setLocked(true);
setTimeout(() => {
setLocked(false);
}, 1000 * 5);
} else { } else {
toast({ toast({
description: "Bitte warte ein wenig, bevor du eine weitere Reservierung tätigst...", description: "Bitte warte ein wenig, bevor du eine weitere Reservierung tätigst...",

View File

@ -1,7 +1,7 @@
import { HeaderNavigation } from "@/components/header/navigation"; import { HeaderNavigation } from "@/components/header/navigation";
import { LoginButton } from "@/components/login-button";
import { LogoutButton } from "@/components/logout-button"; import { LogoutButton } from "@/components/logout-button";
import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@ -13,7 +13,7 @@ import {
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { validateRequest } from "@/server/auth"; import { validateRequest } from "@/server/auth";
import { UserRole, hasRole } from "@/server/auth/permissions"; import { UserRole, hasRole } from "@/server/auth/permissions";
import { ScanFaceIcon, StickerIcon, UserIcon, WrenchIcon } from "lucide-react"; import { StickerIcon, UserIcon, WrenchIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { If, Then } from "react-if"; import { If, Then } from "react-if";
@ -78,14 +78,7 @@ export async function Header() {
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
)} )}
{user == null && ( {user == null && <LoginButton />}
<Button variant={"ghost"} className="gap-2 flex items-center" asChild>
<Link href="/auth/login">
<ScanFaceIcon className="w-4 h-4" />
<span>Anmelden</span>
</Link>
</Button>
)}
</div> </div>
</header> </header>
); );

View File

@ -1,10 +1,12 @@
"use client"; "use client";
import { cn } from "@/utils/styles"; import { cn } from "@/utils/styles";
import { ContactRoundIcon, LayersIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
interface Site { interface Site {
name: string; name: string;
icon: JSX.Element;
path: string; path: string;
} }
@ -12,7 +14,8 @@ export function HeaderNavigation() {
const pathname = usePathname(); const pathname = usePathname();
const sites: Site[] = [ const sites: Site[] = [
{ {
name: "Mein Dashboard", name: "Dashboard",
icon: <LayersIcon className="w-4 h-4" />,
path: "/", path: "/",
}, },
/* { /* {
@ -21,6 +24,7 @@ export function HeaderNavigation() {
}, */ }, */
{ {
name: "Mein Profil", name: "Mein Profil",
icon: <ContactRoundIcon className="w-4 h-4" />,
path: "/my/profile", path: "/my/profile",
}, },
]; ];
@ -31,12 +35,13 @@ export function HeaderNavigation() {
<Link <Link
key={site.path} key={site.path}
href={site.path} href={site.path}
className={cn("transition-colors hover:text-neutral-50", { className={cn("transition-colors hover:text-neutral-50 flex items-center gap-x-1", {
"text-neutral-50": pathname === site.path, "text-primary-foreground font-semibold": pathname === site.path,
"text-neutral-500": pathname !== site.path, "text-neutral-500": pathname !== site.path,
})} })}
> >
{site.name} {site.icon}
<span>{site.name}</span>
</Link> </Link>
))} ))}
</nav> </nav>

View File

@ -0,0 +1,37 @@
"use client";
import { Button } from "@/components/ui/button";
import { useToast } from "@/components/ui/use-toast";
import { ScanFaceIcon } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
export function LoginButton() {
const { toast } = useToast();
const [isLocked, setLocked] = useState(false);
function onClick() {
if (!isLocked) {
toast({
description: "Du wirst angemeldet...",
});
// Prevent multiple clicks because of login delay...
setLocked(true);
setTimeout(() => {
setLocked(false);
}, 1000 * 5);
}
toast({
description: "Bitte warte einen Moment...",
});
}
return (
<Button onClick={onClick} variant={"ghost"} className="gap-2 flex items-center" asChild disabled={isLocked}>
<Link href="/auth/login">
<ScanFaceIcon className="w-4 h-4" />
<span>Anmelden</span>
</Link>
</Button>
);
}

View File

@ -1,12 +1,21 @@
"use client"; "use client";
import { useToast } from "@/components/ui/use-toast";
import { logout } from "@/server/actions/authentication/logout"; import { logout } from "@/server/actions/authentication/logout";
import { LogOutIcon } from "lucide-react"; import { LogOutIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
export function LogoutButton() { export function LogoutButton() {
const { toast } = useToast();
function onClick() {
toast({
description: "Du wirst nun abgemeldet...",
});
logout();
}
return ( return (
<Link href="/" onClick={() => logout()} className="flex items-center gap-2"> <Link href="/" onClick={onClick} className="flex items-center gap-2">
<LogOutIcon className="w-4 h-4" /> <LogOutIcon className="w-4 h-4" />
<span>Abmelden</span> <span>Abmelden</span>
</Link> </Link>

View File

@ -33,7 +33,8 @@ export function PrinterCard(props: PrinterCardProps) {
"opacity-50 select-none cursor-not-allowed": status === PrinterStatus.OUT_OF_ORDER, "opacity-50 select-none cursor-not-allowed": status === PrinterStatus.OUT_OF_ORDER,
})} })}
> >
<CardHeader className="flex flex-row justify-between"> <CardHeader>
<div className="flex flex-row items-start justify-between">
<div> <div>
<CardTitle>{printer.name}</CardTitle> <CardTitle>{printer.name}</CardTitle>
<CardDescription>{printer.description}</CardDescription> <CardDescription>{printer.description}</CardDescription>
@ -50,6 +51,7 @@ export function PrinterCard(props: PrinterCardProps) {
<Else>{translatePrinterStatus(status)}</Else> <Else>{translatePrinterStatus(status)}</Else>
</If> </If>
</Badge> </Badge>
</div>
</CardHeader> </CardHeader>
<CardContent className="flex justify-end"> <CardContent className="flex justify-end">
<If condition={status === PrinterStatus.IDLE && userIsLoggedIn && !hasRole(user, UserRole.GUEST)}> <If condition={status === PrinterStatus.IDLE && userIsLoggedIn && !hasRole(user, UserRole.GUEST)}>