Skip to content
Merged
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
60 changes: 60 additions & 0 deletions app/components/hero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use client";
import Image from "next/image";
import Stars from "./stars";

export default function Hero() {
return (
<section
className="relative min-h-screen bg-gradient-to-b from-[#050014] via-[#04002A] to-[#050032] text-white overflow-hidden"
style={{
background: ``,
}}
>
<div className="absolute bottom-0 left-1/2 transform -translate-x-1/2 w-[120vw] h-[50vh] z-0">
<div
className="absolute inset-0 blur-3xl scale-150 opacity-70"
style={{
background:
"radial-gradient(ellipse 50% 110% at center bottom, rgba(255, 177, 94, 1) 40%, rgba(242, 88, 204, 0.9) 70%, rgba(231, 105, 199, 0.4) 85%, transparent 100%)",
pointerEvents: "none",
}}
/>
</div>
<Stars speed={1000} />
<div className="absolute top-1/3 left-0 right-0 transform -translate-y-1/2 z-10">
<div className="flex items-center justify-center space-x-4 px-4">
{/* Logo */}
<Image src="/logo.svg" alt="HackUTD Logo" width={120} height={120} />

{/* Text Section */}
<div className="font-['CeraPro']">
<p className="text-md font-medium text-white ml-1">We are</p>
<h1 className="text-[6rem] font-bold leading-none">
<span className="text-white">Hack</span>
<span className="bg-gradient-to-r from-pink-500 to-orange-400 text-transparent bg-clip-text">
UTD
</span>
</h1>
<p className="text-sm font-medium text-white mr-1 text-right">
North America&apos;s Largest 24-hour Hackathon
</p>
</div>
</div>
</div>
<div className="absolute bottom-0 left-0 right-0 z-10 flex flex-col">
<div className="relative w-full">
<div className="relative">
<Image
src="/dallas_skyline.svg"
alt="Dallas Skyline"
width={1920}
height={400}
className="w-full h-auto object-cover scale-130"
/>
</div>
<div className="bg-black h-20 w-full -mt-9"></div>
</div>
</div>
</section>
);
}
250 changes: 250 additions & 0 deletions app/components/navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
"use client";

import React from "react";

import Link from "next/link";
import Image from "next/image";
import { Menu, type LucideIcon } from "lucide-react";
import { useState } from "react";

function cn(...classes: (string | undefined | null | false)[]): string {
return classes.filter(Boolean).join(" ");
}

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
asChild?: boolean;
variant?: "default" | "outline";
size?: "default" | "icon";
children: React.ReactNode;
}

function Button({
asChild,
variant = "default",
size = "default",
className,
children,
...props
}: ButtonProps) {
const baseClasses =
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background";

const variants = {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
outline: "border border-input hover:bg-accent hover:text-accent-foreground",
};

const sizes = {
default: "h-10 py-2 px-4",
icon: "h-10 w-10",
};

const classes = cn(baseClasses, variants[variant], sizes[size], className);

if (asChild && React.isValidElement(children)) {
return React.cloneElement(children, {
className: classes,
...(children.props as any),
});
}

return (
<button className={classes} {...props}>
{children}
</button>
);
}

function MobileSheet({
children,
trigger,
}: {
children: React.ReactNode;
trigger: React.ReactNode;
}) {
const [isOpen, setIsOpen] = useState(false);

return (
<>
<div onClick={() => setIsOpen(true)}>{trigger}</div>

{isOpen && (
<>
{/* Backdrop */}
<div
className="fixed inset-0 z-50 bg-black/50"
onClick={() => setIsOpen(false)}
/>

{/* Sheet */}
<div className="fixed right-0 top-0 z-50 h-full w-64 liquid-glass border-l border-gray-800 flex flex-col">
{children}
</div>
</>
)}
</>
);
}

export interface NavLink {
href: string;
label: string;
icon?: LucideIcon;
}

export interface NavbarProps {
/** Brand logo source */
logoSrc?: string;
/** Brand name */
brandName: string;
/** Navigation links */
links: NavLink[];
/** CTA button text */
ctaText?: string;
/** CTA button href */
ctaHref?: string;
/** Custom logo width (default: 20) */
logoWidth?: number;
/** Custom logo height (default: 20) */
logoHeight?: number;
/** Custom container max width (default: max-w-4xl) */
containerMaxWidth?: string;
}

export function Navbar({
logoSrc,
brandName,
links,
ctaText = "Get Started",
ctaHref = "#contact",
logoWidth = 20,
logoHeight = 20,
containerMaxWidth = "max-w-4xl",
}: NavbarProps) {
return (
<header className="sticky top-0 z-50 p-4 font-['CeraPro']">
<div className={`container mx-auto ${containerMaxWidth}`}>
<div className="flex h-14 items-center justify-between px-6 liquid-glass-header rounded-full">
{/* Brand Logo */}
<Link href="/" className="flex items-center gap-1.5">
{logoSrc && (
<Image
src={logoSrc || "/placeholder.svg"}
alt={`${brandName} logo`}
width={logoWidth}
height={logoHeight}
className={`h-${Math.ceil(logoHeight / 4)} w-${Math.ceil(
logoWidth / 4
)}`}
/>
)}
<span className="font-semibold tracking-wide text-white">
{brandName}
</span>
</Link>

{/* Desktop Nav */}
<nav className="hidden items-center gap-6 text-sm text-gray-300 md:flex">
{links.map((link) => (
<a
key={link.href}
href={link.href}
onClick={(e) => {
e.preventDefault();
const target = document.querySelector(link.href);
if (target) {
const yOffset = -80; // adjust for fixed navbar height
const y =
target.getBoundingClientRect().top +
window.scrollY +
yOffset;
window.scrollTo({ top: y, behavior: "smooth" });
}
}}
className="hover:text-purple-300 transition-colors cursor-pointer"
>
{link.label}
</a>
))}
</nav>

{/* Desktop CTA */}
<div className="hidden md:flex">
<Button
asChild
className="bg-[#FF65BB] text-white font-medium rounded-lg px-6 py-2.5
hover:bg-[#FF4DAA] hover:shadow-md hover:scale-[1.02]
transition-all"
>
<Link href={ctaHref}>{ctaText}</Link>
</Button>
</div>

{/* Mobile Nav */}
<div className="md:hidden">
<MobileSheet
trigger={
<Button
variant="outline"
size="icon"
className="border-gray-700 bg-gray-900/80 text-gray-200 hover:bg-gray-800"
>
<Menu className="h-5 w-5" />
<span className="sr-only">Open menu</span>
</Button>
}
>
{/* Brand Header */}
<div className="flex items-center gap-1.5 px-4 py-4 border-b border-gray-800">
{logoSrc && (
<Image
src={logoSrc || "/placeholder.svg"}
alt={`${brandName} logo`}
width={24}
height={24}
className="h-6 w-6"
/>
)}
<span className="font-semibold tracking-wide text-white text-lg">
{brandName}
</span>
</div>

{/* Nav Links */}
<nav className="flex flex-col gap-1 mt-2 text-gray-200">
{links.map((link) => (
<Link
key={link.href}
href={link.href}
className="flex items-center gap-3 px-4 py-3 hover:bg-gray-900 hover:text-purple-300 transition-colors"
>
{link.icon && (
<span className="inline-flex items-center justify-center w-5 h-5 text-gray-400">
<link.icon className="h-4 w-4" />
</span>
)}
<span className="text-sm">{link.label}</span>
</Link>
))}
</nav>

{/* CTA Button at Bottom */}
<div className="mt-auto border-t border-gray-800 p-4">
<Button
asChild
className="w-full bg-lime-400 text-black font-medium rounded-lg px-6 py-2.5
hover:bg-lime-300 hover:shadow-md hover:scale-[1.02]
transition-all"
>
<Link href={ctaHref}>{ctaText}</Link>
</Button>
</div>
</MobileSheet>
</div>
</div>
</div>
</header>
);
}

export default Navbar;
Loading