Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

/**
* Merge and deduplicate Tailwind classes without style conflicts
*
* @param inputs - Class names to merge
* @returns A string of class names, merged and deduplicated
*/
export function cn(...inputs: Array<ClassValue>) {
return twMerge(clsx(inputs));
}

/**
* Size breakpoints in pixels based on Tailwind CSS defaults.
*
* https://tailwindcss.com/docs/responsive-design
*/
export const breakpointPixels = {
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
"2xl": 1536,
} as const;
141 changes: 79 additions & 62 deletions src/routes/_home.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { SiFacebook } from "@icons-pack/react-simple-icons";
import { useViewportSize } from "@mantine/hooks";
import { FolderOpen, Mail, MapPin } from "lucide-react";
import { motion } from "motion/react";
import { Link, NavLink, Outlet, type To } from "react-router";
import { type Sponsor, getSponsors } from "~/api/sponsor";
import { Button, buttonVariants } from "~/components/ui/button";
import { buttonVariants } from "~/components/ui/button";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "~/components/ui/drawer";
import "~/home.css";
import { breakpointPixels, cn } from "~/lib/utils";
import { navRoutes } from "~/routes";

// biome-ignore lint/style/noDefaultExport: Route Modules require default export https://reactrouter.com/start/framework/route-module
Expand All @@ -30,23 +33,31 @@ export default function Layout() {
}

function AppHeader() {
const { width } = useViewportSize();
const isMobile = width < breakpointPixels.md;

return (
<div className="sticky top-2 z-50">
<div className="flex w-full flex-wrap justify-center lg:px-4">
<div className="mr-12 flex w-fit items-center gap-1 rounded-full bg-[#ccecf6] bg-opacity-40 px-1.5 shadow-md backdrop-blur dark:bg-black dark:bg-opacity-40">
<img
src="/images/vektor-logo-circle.svg"
alt="vektorprogrammet logo"
width={32}
height={32}
/>
<NavTabs routes={navRoutes} />
</div>
</div>
<div className="absolute top-0 right-2 hidden rounded-full md:flex">
<LoginButtons />
</div>
<MobileMenu routes={navRoutes} />
{isMobile ? (
<MobileMenu routes={navRoutes} />
) : (
<>
<div className="flex w-full flex-wrap justify-center lg:px-4">
<div className="mr-12 flex w-fit items-center gap-1 rounded-full bg-[#ccecf6] bg-opacity-40 px-1.5 shadow-md backdrop-blur dark:bg-black dark:bg-opacity-40">
<img
src="/images/vektor-logo-circle.svg"
alt="vektorprogrammet logo"
width={32}
height={32}
/>
<NavTabs routes={navRoutes} />
</div>
</div>
<div className="absolute top-0 right-2 flex rounded-full">
<LoginButtons />
</div>
</>
)}
</div>
);
}
Expand Down Expand Up @@ -109,53 +120,59 @@ const MobileMenu = ({
routes,
}: { routes: Array<{ name: string; path: To }> }) => {
return (
<div className="md:hidden">
<Drawer>
<DrawerTrigger>
<div className="fixed top-12 right-0 flex rounded-l-full bg-[rgba(0,0,0,0.8)] p-1 pr-2">
<Button
variant="outline"
className="rounded-full bg-vektor-bg p-0"
size="icon"
>
<Avatar className="h-full w-full rounded-full">
<AvatarImage src="/images/team/IT-Tor.png" />
<AvatarFallback>{"Tor"}</AvatarFallback>
</Avatar>
</Button>
</div>
</DrawerTrigger>
<DrawerContent>
<DrawerHeader />
<DrawerDescription>
<div className="flex items-start justify-between p-6">
<ul className="flex w-full flex-col items-start gap-4 text-center">
{routes.map((route) => (
<li key={route.name}>
<Link
className="text-lg dark:text-white"
reloadDocument
to={route.path}
prefetch="render"
>
{route.name}
</Link>
</li>
))}
</ul>
<div className="flex w-fit justify-center">
<LoginButtons />
</div>
</div>
<Drawer>
<DrawerTrigger>
<div className="fixed top-12 right-0 flex rounded-l-full bg-black/80 p-1 pr-2">
<Avatar
className={cn(
"h-full w-full rounded-full bg-vektor-bg p-0",
buttonVariants({
variant: "outline",
size: "icon",
className: "rounded-full",
}),
)}
>
<AvatarImage src="/images/team/IT-Tor.png" />
<AvatarFallback>{"Tor"}</AvatarFallback>
</Avatar>
</div>
</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>{"Navigasjonsmeny"}</DrawerTitle>
<DrawerDescription hidden={true}>
{"Meny for å navigere til hovedsider på nettsiden"}
</DrawerDescription>
<DrawerFooter>
<DrawerClose>
<Button variant="outline">{"Close"}</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
</div>
</DrawerHeader>

<div className="flex items-start justify-between p-6">
<ul className="flex w-full flex-col items-start gap-4 text-center">
{routes.map((route) => (
<li key={route.name}>
<Link
className="text-lg dark:text-white"
reloadDocument
to={route.path}
prefetch="render"
>
{route.name}
</Link>
</li>
))}
</ul>
<div className="flex w-fit justify-center">
<LoginButtons />
</div>
</div>

<DrawerFooter>
<DrawerClose className={buttonVariants({ variant: "outline" })}>
{"Close"}
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
};

Expand Down