+
+ Case File · {c.hackathonName}
+
+
Register
-
+
Welcome Hacker! {" "}
Please fill out the form below to complete your
registration for {c.hackathonName}.
-
+
Psttt... Running into a issue? Please let us know on{" "}
-
+
Discord
!
@@ -55,32 +66,5 @@ export default async function Page() {
);
}
- return (
-
-
- {c.hackathonName}
-
- Registration
-
-
-
- Registration Is Currently Closed
-
-
- If you believe this is a mistake or have any questions, feel
- free to reach out to us at {c.issueEmail}!
-
-
-
-
Return Home
-
-
- Already registered?
-
- Sign-in.
-
-
-
-
- );
+ return ( );
}
diff --git a/apps/web/src/app/rsvp/page.tsx b/apps/web/src/app/rsvp/page.tsx
index 31632a650..0510ae86d 100644
--- a/apps/web/src/app/rsvp/page.tsx
+++ b/apps/web/src/app/rsvp/page.tsx
@@ -7,20 +7,11 @@ import { eq } from "db/drizzle";
import { userCommonData } from "db/schema";
import ClientToast from "@/components/shared/ClientToast";
import { SignedOut, RedirectToSignIn } from "@clerk/nextjs";
-import {
- parseRedisBoolean,
- parseRedisNumber,
- redisGet,
-} from "@/lib/utils/server/redis";
import Link from "next/link";
import { Button } from "@/components/shadcn/ui/button";
import { getUser } from "db/functions";
-export default async function RsvpPage({
- searchParams,
-}: {
- searchParams?: { [key: string]: string | string[] | undefined };
-}) {
+export default async function RsvpPage() {
const { userId } = await auth();
if (!userId) {
@@ -42,22 +33,12 @@ export default async function RsvpPage({
return redirect("/i/approval");
}
- const rsvpEnabled = parseRedisBoolean(
- (await redisGet("config:registration:allowRSVPs")) as
- | string
- | boolean
- | null
- | undefined,
- true,
- );
+ const rsvpEnabled = c.rsvpAvailable;
let isRsvpPossible = false;
- if (rsvpEnabled === true) {
- const rsvpLimit = parseRedisNumber(
- await redisGet("config:registration:maxRSVPs"),
- c.rsvpDefaultLimit,
- );
+ if (rsvpEnabled) {
+ const rsvpLimit = c.rsvpLimit;
const rsvpUserCount = await db
.select({ count: count() })
diff --git a/apps/web/src/app/sign-up/[[...sign-up]]/page.tsx b/apps/web/src/app/sign-up/[[...sign-up]]/page.tsx
index eea682138..c09385469 100644
--- a/apps/web/src/app/sign-up/[[...sign-up]]/page.tsx
+++ b/apps/web/src/app/sign-up/[[...sign-up]]/page.tsx
@@ -1,16 +1,11 @@
import { SignUp } from "@clerk/nextjs";
-import { redisMGet } from "@/lib/utils/server/redis";
-import { parseRedisBoolean } from "@/lib/utils/server/redis";
import c from "config";
-import { Button } from "@/components/shadcn/ui/button";
-import Link from "next/link";
+import RegisterClosed from "@/components/registration/RegistretionClosed";;
export default async function Page() {
- const [defaultRegistrationEnabled]: (string | null)[] = await redisMGet(
- "config:registration:registrationEnabled",
- );
+ const registrationEnabled = c.registrationAvailable;
- if (parseRedisBoolean(defaultRegistrationEnabled, true) === true) {
+ if (registrationEnabled) {
return (
@@ -18,32 +13,5 @@ export default async function Page() {
);
}
- return (
-
-
- {c.hackathonName}
-
- Registration
-
-
-
- Registration Is Currently Closed
-
-
- If you believe this is a mistake or have any questions, feel
- free to reach out to us at {c.issueEmail}!
-
-
-
-
Return Home
-
-
- Already registered?{" "}
-
- Sign-in.
-
-
-
-
- );
+ return ( );
}
diff --git a/apps/web/src/components/admin/toggles/NavItemsManager.tsx b/apps/web/src/components/admin/toggles/NavItemsManager.tsx
deleted file mode 100644
index 237590d6e..000000000
--- a/apps/web/src/components/admin/toggles/NavItemsManager.tsx
+++ /dev/null
@@ -1,317 +0,0 @@
-"use client";
-
-import type { NavItemToggleType } from "@/validators/shared/navitemtoggle";
-import {
- Table,
- TableBody,
- TableCaption,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from "@/components/shadcn/ui/table";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
- DialogTrigger,
-} from "@/components/shadcn/ui/dialog";
-import { Button } from "@/components/shadcn/ui/button";
-import { Input } from "@/components/shadcn/ui/input";
-import { Label } from "@/components/shadcn/ui/label";
-import { Plus, Loader2 } from "lucide-react";
-import { useState } from "react";
-import { useAction, useOptimisticAction } from "next-safe-action/hooks";
-import {
- setItem,
- removeItem,
- toggleItem,
- editItem,
-} from "@/actions/admin/modify-nav-item";
-import { toast } from "sonner";
-import Link from "next/link";
-import { Switch } from "@/components/shadcn/ui/switch";
-
-interface NavItemsManagerProps {
- navItems: NavItemToggleType[];
-}
-
-export function NavItemsManager({ navItems }: NavItemsManagerProps) {
- const { execute, result, status } = useAction(removeItem, {
- onSuccess: () => {
- toast.dismiss();
- toast.success("NavItem deleted successfully!");
- },
- onError: () => {
- toast.dismiss();
- toast.error("Error deleting NavItem");
- },
- });
-
- return (
-
-
- {/* A list of your recent invoices. */}
- {/* TODO: FIX MASSIVE BUG WHERE IF ENCODED IS DIFFERENT IT WILL ALL BREAK */}
-
-
- Name
- Link
- Enabled
- Options
-
-
-
- {navItems.map((item) => (
-
-
- {item.name}
-
-
-
- {item.url}
-
-
-
- {/* didToggle(item.name, checked)}
- /> */}
-
-
-
-
- {
- toast.dismiss();
- toast.loading("Deleting NavItem...");
- execute(item.name);
- }}
- >
- Delete
-
-
-
- ))}
-
-
-
- );
-}
-
-function ToggleSwitch({
- itemStatus,
- name,
-}: {
- itemStatus: boolean;
- name: string;
-}) {
- const initialData = { itemStatus }; // Initial data matching the shape of toggleItem's return type
-
- const { execute, optimisticState } = useOptimisticAction(toggleItem, {
- currentState: initialData,
- updateFn: (state, { statusToSet }) => {
- return { itemStatus: statusToSet };
- },
- onError: () => {
- toast.error("Error toggling NavItem");
- },
- });
-
- return (
-
- execute({ name, statusToSet: checked })
- }
- />
- );
-}
-
-export function AddNavItemDialog() {
- const [name, setName] = useState(null);
- const [url, setUrl] = useState(null);
- const [open, setOpen] = useState(false);
-
- const {
- execute,
- result,
- status: createStatus,
- } = useAction(setItem, {
- onSuccess: () => {
- console.log("Success");
- setOpen(false);
- toast.success("NavItem created successfully!");
- },
- onError: () => {
- toast.error("Error creating NavItem");
- },
- });
-
- const isLoading = createStatus === "executing";
-
- return (
-
-
-
-
- Add Item
-
-
-
-
- New Item
-
- Create a item to show in the non-dashboard navbar
-
-
-
-
- {
- console.log("Running Action");
- if (!name || !url)
- return alert("Please fill out all fields.");
-
- execute({ name, url });
- }}
- >
- {isLoading && (
-
- )}
- Create
-
-
-
-
- );
-}
-
-interface EditNavItemDialogProps {
- existingName: string;
- existingUrl: string;
- existingEnabled: boolean;
-}
-
-function EditNavItemDialog({
- existingName,
- existingUrl,
- existingEnabled,
-}: EditNavItemDialogProps) {
- const [name, setName] = useState(existingName);
- const [url, setUrl] = useState(existingUrl);
- const [open, setOpen] = useState(false);
-
- const { execute, status: editStatus } = useAction(editItem, {
- onSuccess: () => {
- console.log("Success");
- setOpen(false);
- toast.success("NavItem edited successfully!");
- },
- onError: () => {
- toast.error("Error editing NavItem");
- },
- });
- const isLoading = editStatus === "executing";
-
- return (
-
-
- Edit Item
-
-
-
- Edit Item
-
- Edit an existing item shown in the non-dashboard navbar
-
-
-
-
- {
- console.log("Running Action");
- if (!name || !url)
- return alert("Please fill out all fields.");
-
- execute({
- enabled: existingEnabled,
- existingName,
- name,
- url,
- });
- }}
- >
- {isLoading && (
-
- )}
- Update
-
-
-
-
- );
-}
diff --git a/apps/web/src/components/admin/toggles/RegistrationSettings.tsx b/apps/web/src/components/admin/toggles/RegistrationSettings.tsx
deleted file mode 100644
index 116aa1f36..000000000
--- a/apps/web/src/components/admin/toggles/RegistrationSettings.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-"use client";
-
-import { Button } from "@/components/shadcn/ui/button";
-import { Input } from "@/components/shadcn/ui/input";
-import { Label } from "@/components/shadcn/ui/label";
-import { Switch } from "@/components/shadcn/ui/switch";
-import { useOptimisticAction } from "next-safe-action/hooks";
-import { toast } from "sonner";
-import {
- toggleRegistrationEnabled,
- toggleRegistrationMessageEnabled,
- toggleRSVPs,
- setRSVPLimit,
-} from "@/actions/admin/registration-actions";
-import { UpdateItemWithConfirmation } from "./UpdateItemWithConfirmation";
-
-interface RegistrationTogglesProps {
- defaultRegistrationEnabled: boolean;
- defaultRSVPsEnabled: boolean;
- defaultRSVPLimit: number;
-}
-
-export function RegistrationToggles({
- defaultRegistrationEnabled,
- defaultRSVPsEnabled,
- defaultRSVPLimit,
-}: RegistrationTogglesProps) {
- const {
- execute: executeToggleRSVPs,
- optimisticState: toggleRSVPsOptimisticData,
- } = useOptimisticAction(toggleRSVPs, {
- currentState: { success: true, statusSet: defaultRSVPsEnabled },
- updateFn: (state, { enabled }) => {
- return { statusSet: enabled, success: true };
- },
- });
-
- const {
- execute: executeToggleRegistrationEnabled,
- optimisticState: ToggleRegistrationEnabledOptimisticData,
- } = useOptimisticAction(toggleRegistrationEnabled, {
- currentState: { success: true, statusSet: defaultRegistrationEnabled },
- updateFn: (state, { enabled }) => {
- return { statusSet: enabled, success: true };
- },
- });
-
- const {
- execute: executeSetRSVPLimit,
- optimisticState: SetRSVPLimitOptimisticData,
- } = useOptimisticAction(setRSVPLimit, {
- currentState: { success: true, statusSet: defaultRSVPLimit },
- updateFn: (state, { rsvpLimit }) => {
- return { statusSet: rsvpLimit, success: true };
- },
- });
-
- return (
- <>
-
-
Registration
-
-
-
New Registrations
-
{
- toast.success(
- `Registration ${checked ? "enabled" : "disabled"} successfully!`,
- );
- executeToggleRegistrationEnabled({
- enabled: checked,
- });
- }}
- />
-
-
-
-
-
RSVPs
-
-
-
Allow RSVPs
-
{
- toast.success(
- `RSVPs ${checked ? "enabled" : "disabled"} successfully!`,
- );
- executeToggleRSVPs({ enabled: checked });
- }}
- />
-
-
-
RSVP Limit
-
{
- toast.success(
- `Hacker RSVP limit successfully changed to ${newLimit}!`,
- );
- executeSetRSVPLimit({ rsvpLimit: newLimit });
- }}
- />
-
-
-
- >
- );
-}
diff --git a/apps/web/src/components/admin/toggles/ToggleItem.tsx b/apps/web/src/components/admin/toggles/ToggleItem.tsx
deleted file mode 100644
index 0c57d9e58..000000000
--- a/apps/web/src/components/admin/toggles/ToggleItem.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-"use client";
-
-import Link from "next/link";
-import { usePathname } from "next/navigation";
-
-interface ToggleItemProps {
- name: string;
- path: string;
-}
-
-export default function ToggleItem({ name, path }: ToggleItemProps) {
- const currPath = usePathname();
- return (
-
-
-
- );
-}
diff --git a/apps/web/src/components/admin/toggles/UpdateItemWithConfirmation.tsx b/apps/web/src/components/admin/toggles/UpdateItemWithConfirmation.tsx
deleted file mode 100644
index dc35d3eab..000000000
--- a/apps/web/src/components/admin/toggles/UpdateItemWithConfirmation.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { useState } from "react";
-import { Input } from "@/components/shadcn/ui/input";
-import { Button } from "@/components/shadcn/ui/button";
-
-interface UpdateItemWithConfirmationBaseProps {
- defaultValue: T;
- enabled: boolean;
- onSubmit: (value: T) => void;
-}
-
-type UpdateItemWithConfirmationProps =
- | ({ type: "string" } & UpdateItemWithConfirmationBaseProps)
- | ({ type: "number" } & UpdateItemWithConfirmationBaseProps);
-
-export function UpdateItemWithConfirmation({
- type,
- defaultValue,
- onSubmit,
- enabled,
-}: UpdateItemWithConfirmationProps) {
- const [valueUpdated, setValueUpdated] = useState(false);
- const [value, setValue] = useState(defaultValue.toString());
-
- return (
-
- {
- // Ignore the change if the value is a non numeric character.
- if (type === "number" && /[^0-9]/.test(updated)) {
- setValue(value);
- return;
- }
-
- setValue(updated);
-
- /* Avoid allowing the user to update the default value to itself.
- * Also disallow the user from sending a zero length input. */
- setValueUpdated(
- updated !== defaultValue.toString() &&
- updated.length !== 0,
- );
- }}
- />
- {
- if (type === "number") {
- onSubmit(parseInt(value));
- } else {
- onSubmit(value);
- }
-
- setValueUpdated(false);
- }}
- >
- Apply
-
-
- );
-}
diff --git a/apps/web/src/components/dash/overview/ClientBubbles.tsx b/apps/web/src/components/dash/overview/ClientBubbles.tsx
index 8551b01ba..bd7f64564 100644
--- a/apps/web/src/components/dash/overview/ClientBubbles.tsx
+++ b/apps/web/src/components/dash/overview/ClientBubbles.tsx
@@ -1,8 +1,17 @@
"use client";
-import { useState } from "react";
import { useTimer } from "react-timer-hook";
-import { Badge } from "@/components/shadcn/ui/badge";
+import { Manuale, Shadows_Into_Light } from "next/font/google";
+import Pin from "@/components/landing/Pin";
+
+const manuale = Manuale({
+ subsets: ["latin"],
+ display: "swap",
+});
+const shadow = Shadows_Into_Light({
+ subsets: ["latin"],
+ weight: "400",
+});
interface CountdownProps {
title: string;
@@ -13,51 +22,66 @@ export function Countdown({ title, date }: CountdownProps) {
const { seconds, minutes, hours, days } = useTimer({
expiryTimestamp: date,
});
+ function DossierPins() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+ }
return (
-
-
-
-
+
+
+
+
+
- {days}
+ {String(days).padStart(2, "0")}
Days
-
+
- {hours}
+ {String(hours).padStart(2, "0")}
Hours
-
+
- {minutes}
+ {String(minutes).padStart(2, "0")}
Minutes
-
+
- {seconds}
+ {String(seconds).padStart(2, "0")}
Seconds
-
);
-}
+}
\ No newline at end of file
diff --git a/apps/web/src/components/dash/overview/ServerBubbles.tsx b/apps/web/src/components/dash/overview/ServerBubbles.tsx
index e01e995b7..a7b400ece 100644
--- a/apps/web/src/components/dash/overview/ServerBubbles.tsx
+++ b/apps/web/src/components/dash/overview/ServerBubbles.tsx
@@ -1,67 +1,244 @@
-import { Button } from "@/components/shadcn/ui/button";
import Link from "next/link";
+import Image from "next/image";
import c from "config";
import { format } from "date-fns";
-import GradientHero from "./GradientHero";
import QRCode from "react-qr-code";
+import { Manuale, Shadows_Into_Light } from "next/font/google";
+import { Mail } from "lucide-react";
+import Pin from "@/components/landing/Pin";
+
+const manuale = Manuale({
+ subsets: ["latin"],
+ display: "swap",
+});
+
+const shadow = Shadows_Into_Light({
+ subsets: ["latin"],
+ weight: "400",
+});
export function Questions() {
+ function DossierPins() {
+ return (
+ <>
+
+
+
+ >
+ );
+ }
return (
-
+
+
+
-
Have a question?
-
+
Have a question?
+
We're here to help! Feel free to reach out to us via email
or on Discord.
-
-
-
Discord
+
+
+
-
- Email
+
+
);
}
-export function TitleBubble() {
+function QR({ qrPayload}: { qrPayload: string; qrSize?: string }) {
+ return (
+ <>
+
Quick QR
+
+
+
+
+ Click / Tap To Open Event Pass
+
+ >
+ );
+}
+
+function TicketInfo({ className, firstName }: { className?: string; firstName: string }) {
return (
-
-
-
-
+
+
+
{c.hackathonName}
-
- {`${format(c.startDate, "h:mma, MMM d, yyyy")}`} @{" "}
- {c.prettyLocation}
-
+
+ 24 hours, one mission: the perfect hack
+
+
+
+
+
+
Event
+
{c.hackathonName}
+
+
+
Date
+
{format(c.startDate, "MM-dd-yy")}
+
+
+
Location
+
Downtown campus | SP1 | SP2
+
+
+
Pass No.
+
RH-10-2026
+
+
+
+
+
+
+
Welcome to the crew, {firstName}
+
+
+ );
+}
+
+export function QRTiteleHorizintalTicket({ qrPayload, firstName }: { qrPayload: string; firstName: string }) {
+ function DossierPins() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+ }
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+
+export function QRTiteleVerticalTicket({ qrPayload, firstName }: { qrPayload: string; firstName: string }) {
+ function DossierPins() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+ }
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export function TitleTicket({ firstName }: { firstName: string }) {
+ function DossierPins() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
);
}
export function QuickQR({ qrPayload }: { qrPayload: string }) {
+ function DossierPins() {
+ return (
+ <>
+
+
+ >
+ );
+ }
return (
-
- Quick QR
-
-
+
+
+
+
+
-
- Click / Tap To Open Event Pass
-
+
);
}
diff --git a/apps/web/src/components/landing/About.tsx b/apps/web/src/components/landing/About.tsx
index 407df687b..dc57cff1f 100644
--- a/apps/web/src/components/landing/About.tsx
+++ b/apps/web/src/components/landing/About.tsx
@@ -1,29 +1,189 @@
-import Balancer from "react-wrap-balancer";
-import Image from "next/image";
-import D1 from "../../../public/img/landing/d1.svg";
-import D2 from "../../../public/img/landing/d2.svg";
-import D3 from "../../../public/img/landing/d3.svg";
-import D4 from "../../../public/img/landing/d4.svg";
-import Dino_Coding from "../../../public/img/landing/dinos_coding.png";
+"use client";
+import { Manuale, Shadows_Into_Light } from "next/font/google";
+import { motion } from "motion/react";
+import Pin from "./Pin";
+
+const manuale = Manuale({
+ subsets: ["latin"],
+ display: "swap",
+});
+const shadow = Shadows_Into_Light({
+ subsets: ["latin"],
+ weight: "400",
+});
+
+function DossierPins() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
+
export default function About() {
- const d1_stylesheet = {
- width: "25rem",
- height: "auto",
- sm: "width: 30rem",
- };
return (
-
-
-
- About Section
-
-
- Introduce the hackathon and its purpose! Make it sound
- enticing
-
+
+
+
+
+
+
+
+
+
+
+
+
+ What is RowdyHacks?
+
+
+
+
+ RowdyHacks is UTSA's annual hackathon, hosted by
+ the Association for Computing Machinery (ACM) at
+ UTSA.
+
+ It's a weekend-long event where students, tech
+ enthusiasts, and creative minds from all
+ backgrounds come together to collaborate,
+ innovate, and build real-world projects in 24
+ hours.
+
+
+
+
+
+ {/* ===== Desktop ===== */}
+
+
+
+
+
+
+
+
+
+ What is RowdyHacks?
+
+
+
+
+ RowdyHacks is UTSA's annual hackathon,
+ hosted by the Association for Computing
+ Machinery (ACM) at UTSA.
+
+ It's a weekend-long event where students,
+ tech enthusiasts, and creative minds from
+ all backgrounds come together to
+ collaborate, innovate, and build real-world
+ projects in 24 hours.
+
+
+
+
+
+
+
+
+
+
+
+ Whether you’ve a seasoned hackathon vet or
+ you’re just getting started, you’ll feel
+ right at home at RowdyHacks. Come hang out,
+ try something new, team up with others, and
+ bring your ideas to life. There’s plenty of
+ room to explore, learn as you go, and get
+ help when you need it. You don’t need to be
+ an expert, just curious and ready to build.
+ By the end, you’ll have something real to
+ show for it, and a few new friends along the
+ way.
+
+
+
+
+
+
+
);
diff --git a/apps/web/src/components/landing/CreatedWithHackkit.tsx b/apps/web/src/components/landing/CreatedWithHackkit.tsx
index 553ded28e..076120a94 100644
--- a/apps/web/src/components/landing/CreatedWithHackkit.tsx
+++ b/apps/web/src/components/landing/CreatedWithHackkit.tsx
@@ -1,18 +1,26 @@
import Image from "next/image";
import Link from "next/link";
+
+import { Shadows_Into_Light } from "next/font/google";
+
+const shadowsIntoLight = Shadows_Into_Light({
+ weight: "400",
+ subsets: ["latin"],
+});
+
export default function CreatedWithHackkit() {
return (
-
-
+ {/*
-
+ /> */}
+
Created with HackKit
diff --git a/apps/web/src/components/landing/Footer.tsx b/apps/web/src/components/landing/Footer.tsx
index 2e801f2ee..e8613a10f 100644
--- a/apps/web/src/components/landing/Footer.tsx
+++ b/apps/web/src/components/landing/Footer.tsx
@@ -1,32 +1,79 @@
"use client";
-import { type FunctionComponent, useState } from "react";
import Image from "next/image";
+import FooterLinks, { footerSections } from "./FooterLinks";
+
+import { Shadows_Into_Light } from "next/font/google";
import Link from "next/link";
-import { Instagram, Facebook, Twitter, Github, Disc } from "lucide-react";
-import Discord from "../../../public/img/landing/discord_icon.svg";
-import CreatedWithHackkit from "@/components/landing/CreatedWithHackkit";
+import { Facebook, Github, Instagram, Twitter } from "lucide-react";
+import CreatedWithHackkit from "./CreatedWithHackkit";
-interface Props {
- className?: string;
-}
+const shadowsIntoLight = Shadows_Into_Light({
+ weight: "400",
+ subsets: ["latin"],
+});
export default function Footer() {
- const [showResources, setShowResources] = useState(false);
- const [showLinks, setShowLinks] = useState(false);
- const [showHackathons, setShowHackathons] = useState(false);
-
return (
-
-
-
- {" "}
- Your Footer Here
-
-
-
+
+
+
+
+
+
+ {/* links, resources, other hackatons */}
+
+ {footerSections.map((section) => (
+
+ ))}
+
+
+ {/* icons */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Made with </> & ♥ @ RowdyHacks
+ © RowdyHacks & Association of Computing Machinery
+ at UTSA 2026. All Rights Reserved.
+
-
+
);
}
diff --git a/apps/web/src/components/landing/FooterLinks.tsx b/apps/web/src/components/landing/FooterLinks.tsx
new file mode 100644
index 000000000..82d56610e
--- /dev/null
+++ b/apps/web/src/components/landing/FooterLinks.tsx
@@ -0,0 +1,104 @@
+"use client";
+
+import {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuItem,
+ DropdownMenuContent,
+} from "../shadcn/ui/dropdown-menu";
+import Link from "next/link";
+
+import { Shadows_Into_Light } from "next/font/google";
+
+const shadowsIntoLight = Shadows_Into_Light({
+ weight: "400",
+ subsets: ["latin"],
+});
+
+const resources = [
+ { name: "Register", link: "/auth" },
+ { name: "FAQ", link: "/faq" },
+ { name: "Code of Conduct", link: "https://mlh.io/code-of-conduct" },
+ { name: "Contact Us", link: "/contact" },
+ { name: "ACM-W", link: "https://acmutsa.org/suborg_acmw/" },
+ { name: "ACM UTSA", link: "https://acmutsa.org/" },
+] as const;
+
+const links = [
+ { name: "Open Source", link: "https://github.com/acmutsa/rowdyHacksXI" },
+] as const;
+
+const hackathons = [
+ { name: "CodeQuantum", link: "https://cqhacks.org/" },
+ { name: "RowdyDatathon", link: "https://rowdydatathon.org/" },
+ { name: "TAMUhack", link: "https://tamuhack.com/" },
+ { name: "WEHack", link: "https://wehackutd.com/" },
+ { name: "HackUTD", link: "https://hackutd.co/" },
+ { name: "HackTX", link: "https://hacktx.com/" },
+ { name: "HackUNT", link: "https://unthackathon.com/#/" },
+ { name: "HackUTA", link: "https://hackuta.org/" },
+ { name: "Hacklahoma", link: "https://hacklahoma.org/" },
+] as const;
+
+export default function FooterLinks({
+ title,
+ data,
+}: {
+ title: string;
+ data: Readonly<{ name: string; link: string }[]>;
+}) {
+ return (
+ <>
+ {/* mobile */}
+
+
+
+
+ {title}
+
+
+
+ {data.map(({ name, link }, idx) => (
+
+
+ {name}
+
+
+ ))}
+
+
+
+
+ {/* desktop */}
+
+
+ {title}
+
+ {data.map(({ link, name }, idx) => (
+
+
+ {name}
+
+
+ ))}
+
+ >
+ );
+}
+
+export const footerSections = [
+ { title: "Resources", data: resources },
+ { title: "Links", data: links },
+ { title: "Other Hackathons", data: hackathons },
+] as const;
diff --git a/apps/web/src/components/landing/Hero.tsx b/apps/web/src/components/landing/Hero.tsx
index 59d5c7da8..0f2243df0 100644
--- a/apps/web/src/components/landing/Hero.tsx
+++ b/apps/web/src/components/landing/Hero.tsx
@@ -1,56 +1,185 @@
-import Image from "next/image";
-import Link from "next/link";
-import { Button } from "../shadcn/ui/button";
+"use client";
+
+import { Manuale, Shadows_Into_Light } from "next/font/google";
+import { motion } from "motion/react";
+import Pin from "@/components/landing/Pin";
+
+const line1 = "Heist";
+const line2 = "starts at 9:00";
+
+const shadows = Shadows_Into_Light({
+ subsets: ["latin"],
+ variable: "--font-shadows",
+ weight: "400",
+});
+const manuale = Manuale({
+ subsets: ["latin"],
+ weight: "500",
+});
+
+function DossierPins() {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+}
export default function Hero() {
return (
-
-
-
-
-
-
-
-
-
-
-
- Hack
-
- Kit
-
-
+ <>
+
+
+
+
+
+
+ {/* top-secret: animated pop-in (moved from commented code) */}
+
+
+
+
+
+
-
- Feature-packed Hackathon managment software{" "}
- that just works .
-
+
+
+
+
+
+
+
+ {/* Heist / starts at 9:00: per-character fade-up (moved from commented code) */}
+
+
+ {line1.split("").map((char, i) => (
+
+ {char}
+
+ ))}
+
+
+ {line2.split("").map((char, i) => (
+
+ {char}
+
+ ))}
+
+
+
+
+
+
+
+ Help Wanted
+
+
+
+
+
+ Register
+
+
+
+
+
+ Mentors
+
+
+
+
+
+ Judges
+
+
+
+
+
+ Volunteers
+
-
-
-
-
- GitHub
-
-
-
-
- Docs
-
-
-
-
- Channel Log
-
-
-
-
-
-
+
+ >
);
}
diff --git a/apps/web/src/components/landing/LandingThread.tsx b/apps/web/src/components/landing/LandingThread.tsx
new file mode 100644
index 000000000..6ab1a71e4
--- /dev/null
+++ b/apps/web/src/components/landing/LandingThread.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import { useEffect } from "react";
+import { mountLandingThread } from "@/lib/utils/client/thread";
+
+export default function LandingThread() {
+ useEffect(() => mountLandingThread(), []);
+ return null;
+}
diff --git a/apps/web/src/components/landing/MLHBadge.tsx b/apps/web/src/components/landing/MLHBadge.tsx
index 7c0e49c6d..874c4d2d7 100644
--- a/apps/web/src/components/landing/MLHBadge.tsx
+++ b/apps/web/src/components/landing/MLHBadge.tsx
@@ -4,11 +4,13 @@ import Image from "next/image";
export default function MLHBadge() {
return (
<>
-
+
@@ -22,24 +24,6 @@ export default function MLHBadge() {
/>
-
-
-
-
-
>
);
}
diff --git a/apps/web/src/components/landing/Map.tsx b/apps/web/src/components/landing/Map.tsx
new file mode 100644
index 000000000..df8734a0d
--- /dev/null
+++ b/apps/web/src/components/landing/Map.tsx
@@ -0,0 +1,284 @@
+"use client";
+import Image from "next/image";
+import { useRef } from "react";
+import { Shadows_Into_Light } from "next/font/google";
+import Pin from "@/components/landing/Pin";
+import { findPosition } from "@/hooks/findPosition";
+import { motion } from "motion/react";
+
+const line1 = "CONNECTED?";
+const line2_1 = "UTSA";
+const line2_2 = "Main Campus";
+const line3_1 = "UTSA";
+const line3_2 = "San Pedro 1";
+const line3_3 = "(Place of action)";
+
+const shadowsIntoLight = Shadows_Into_Light({
+ weight: "400",
+ subsets: ["latin"],
+ variable: "--font-shadows",
+});
+
+export default function Map() {
+ const mapContainerRef = useRef
(null);
+ const mapImgRef = useRef(null);
+ const mainCampusCardRef = useRef(null);
+ const mainCampusImgRef = useRef(null);
+ const sp1CardRef = useRef(null);
+ const sp1CampusImgRef = useRef(null);
+
+ const sp1PinStyle = findPosition(
+ mapContainerRef,
+ mapImgRef,
+ { x: 0.54, y: 0.75 },
+ 20,
+ );
+ const sp1TextStyle = findPosition(
+ mapContainerRef,
+ mapImgRef,
+ { x: 0.46, y: 0.82 },
+ 10,
+ );
+ const sp1CircleStyle = findPosition(
+ mapContainerRef,
+ mapImgRef,
+ { x: 0.54, y: 0.77 },
+ 10,
+ );
+ const sp1CardTextStyle = findPosition(
+ sp1CardRef,
+ sp1CampusImgRef,
+ { x: 0.3, y: 0.87 },
+ 20,
+ );
+
+ const mainCampusPinStyle = findPosition(
+ mapContainerRef,
+ mapImgRef,
+ { x: 0.31, y: 0.22 },
+ 20,
+ );
+ const mainCampusTextStyle = findPosition(
+ mapContainerRef,
+ mapImgRef,
+ { x: 0.3, y: 0.29 },
+ 10,
+ );
+ const mainCampusCircleStyle = findPosition(
+ mapContainerRef,
+ mapImgRef,
+ { x: 0.31, y: 0.24 },
+ 10,
+ );
+ const mainCampusCardTextStyle = findPosition(
+ mainCampusCardRef,
+ mainCampusImgRef,
+ { x: 0.4, y: 0.87 },
+ 20,
+ );
+
+ const connectedStyle = findPosition(
+ mapContainerRef,
+ mapImgRef,
+ { x: 0.48, y: 0.5 },
+ 10,
+ );
+
+ return (
+
+
+
+ {/* Pictures */}
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/landing/PartnerCard.tsx b/apps/web/src/components/landing/PartnerCard.tsx
index 436873b92..32a70c657 100644
--- a/apps/web/src/components/landing/PartnerCard.tsx
+++ b/apps/web/src/components/landing/PartnerCard.tsx
@@ -1,6 +1,8 @@
import React from "react";
import Link from "next/link";
import Image from "next/image";
+import { Manuale } from "next/font/google";
+import Pin from "./Pin";
type Partner = {
name: string;
@@ -9,78 +11,60 @@ type Partner = {
tier: string;
};
-type colorMap = {
- key: string;
- value: string;
-};
-
-// const tierBorderMap = {
-// [Tier.Title]: "w-[15rem] sm:w-72 md:w-72 lg:w-80 2xl:w-[19rem]",
-// [Tier.Gold]: "w-[12.75rem] sm:w-[14.75rem] md:w-[16rem] lg:w-72 2xl:w-[19rem]",
-// [Tier.Silver]: "w-[11rem] sm:w-52 md:w-60 lg:w-[16rem] 2xl:w-[17rem] ",
-// [Tier.Bronze]: "w-32 sm:w-40 md:w-[12rem] lg:w-[14rem] 2xl:w-[16rem]",
-// [Tier.Rowdy_Partner]: "w-[7rem] sm:w-32 md:w-40 lg:w-[11rem] 2xl:w-[13rem]",
-// [Tier.In_Kind_Partner]: "w-[6rem] sm:w-[7rem] md:w-32 lg:w-40 2xl:w-52",
-// };
-
-const tierColorMap: { [key: string]: string } = {
- ["Title Sponsor"]: "text-purple-500",
- ["Gold Sponsor"]: "text-yellow-600",
- ["Silver Sponsor"]: "text-gray-400",
- ["Bronze Sponsor"]: "text-amber-800",
- ["Rowdy Partner"]: "text-blue-500",
- ["Rowdy In-Kind"]: "text-red-500",
-};
+const manuale = Manuale({
+ weight: ["300", "400", "500", "600", "700", "800"],
+ subsets: ["latin"],
+ variable: "--font-manuale",
+});
function PartnerCard({
partner,
is_title,
+ index,
}: {
partner: Partner;
is_title: boolean;
+ index: number;
}) {
- const text: string = is_title
- ? "text-2xl sm:text-3xl xl:text-4xl 2xl:text-[3rem]"
- : "text-md sm:text-lg lg:text-xl xl:text-2xl 2xl:text-3xl";
-
- const height: string = is_title
- ? "h-[15rem] sm:h-[15rem] md:h-[16rem] lg:h-[20rem] xl:h-[20rem] 2xl:h-[22rem]"
- : "h-[9rem] sm:h-[11rem] md:h-[11rem] lg:h-[12rem] xl:h-[14rem] 2xl:h-[17rem]";
- const image: string = is_title
- ? "w-[17rem] sm:w-[17rem] md:w-[18rem] xl:w-[20rem] 2xl:w-[24rem]"
- : "w-[8rem] sm:w-[10rem] md:w-[14rem] lg:w-48 xl:w-[16rem]";
-
+ const padding: string[] = [
+ "pl-[15vh] pt-[0vh] pb-[2vh] lg:pt-[0vh] xl:pt-[5vh] xl:pb-[0vh] 2xl:pl-[3vh] 2xl:pt-[7vh] 2xl:pb-[0vh]",
+ "pl-[1vh] pr-[30vw] pt-[0vh] pb-[2vh] lg:pt-[0vh] lg:pr-[2vw] xl:pt-[2vh] xl:pr-[2vw] 2xl:pl-[0vw] 2xl:pr-[0vw] ",
+ "pl-[1vh] pr-[30vw] pt-[0vh] pb-[0vh] md:pr-[2vw] lg:pr-[30vw] xl:pr-[40vw] xl:pt-[0vh] xl:pb-[2vh] 2xl:pr-[0vw] 2xl:pb-[7vh]",
+ "pl-[1vh] pt-[5vh] pb-[0vh] md:pt-[15vh] lg:pt-[5vh] lg:pb-[0vh] lg:pb-[4vh] xl:pr-[3vw] xl:pt-[0vh] xl:pb-[6vh] 2xl:pl-[0vw] 2xl:pr-[0vw]",
+ "pl-[1vh] pt-[0vh] pb-[6vh] md:pr-[4vw] lg:pt-[0vh] lg:pb-[5vh] lg:pr-[4vw] xl:pr-[4vw] xl:pt-[6vh] xl:pb-[0vh] 2xl:pr-[33vw]",
+ "pl-[1vh] pt-[0vh] pb-[4vh] xl:pt-[5vh] 2xl:pb-[0vh] 2xl:pt-[7vh]",
+ "pl-[1vh] pb-[2vh]",
+ ];
return (
-
-
+
+
+
+
+ {partner.logo ? (
+
+ ) : (
+
+ Logo
+
+ )}
+
+
+
+
-
- {partner?.name}
-
-
- {partner?.tier}
-
);
}
diff --git a/apps/web/src/components/landing/Partners.tsx b/apps/web/src/components/landing/Partners.tsx
index 9b8bb203b..6136b5981 100644
--- a/apps/web/src/components/landing/Partners.tsx
+++ b/apps/web/src/components/landing/Partners.tsx
@@ -1,6 +1,19 @@
import partnerData from "./partners.json";
import PartnerCard from "./PartnerCard";
import Image from "next/image";
+import { Manuale, Shadows_Into_Light } from "next/font/google";
+import Pin from "./Pin";
+
+const shadowsIntoLight = Shadows_Into_Light({
+ weight: "400",
+ subsets: ["latin"],
+ variable: "--font-shadows",
+});
+
+const manuale = Manuale({
+ subsets: ["latin"],
+ display: "swap",
+});
type Partner = {
name: string;
@@ -9,41 +22,88 @@ type Partner = {
tier: string;
};
-export default async function Partners() {
- // Christian Walker: Aware of weird bug from 1280px to 1286 px where background dissapears
- const marathon: Partner = {
- name: "Marathon",
- logo: "marathon_logo.svg",
- url: "https://www.marathonpetroleum.com/",
- tier: "Title Sponsor",
- };
+function DossierPins() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
+
+export default async function Partners() {
return (
-
-
-
- Partners Sections
-
-
- {
- "See the Partners Component inside components/landing/Partners for an example"
- }
-
+
);
}
diff --git a/apps/web/src/components/landing/Person.tsx b/apps/web/src/components/landing/Person.tsx
index 83e976af1..5075fdc35 100644
--- a/apps/web/src/components/landing/Person.tsx
+++ b/apps/web/src/components/landing/Person.tsx
@@ -1,9 +1,9 @@
export type Person = {
- fname: string; //picture file name must match name with .png
+ fname: string;
lname: string;
imgLink: string;
- role: string;
- linkedin: string;
- website: string;
- github: string;
+ linkedin?: string;
+ note?: string;
+ top?:string
+ left?:string
};
diff --git a/apps/web/src/components/landing/Pin.tsx b/apps/web/src/components/landing/Pin.tsx
new file mode 100644
index 000000000..0fa7ec210
--- /dev/null
+++ b/apps/web/src/components/landing/Pin.tsx
@@ -0,0 +1,30 @@
+import Image from "next/image";
+
+export default function Pin({
+ name = "/img/assets/silver-pin.svg",
+ size = 25,
+ className = "",
+ no_thread = false,
+ no_img = false,
+}: {
+ name?: string;
+ size?: number;
+ className?: string;
+ no_thread?: boolean;
+ no_img?: boolean;
+ maxSize?: number;
+}) {
+ return (
+
+ {!no_img && (
+
+
+
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/landing/TeamMember.tsx b/apps/web/src/components/landing/TeamMember.tsx
deleted file mode 100644
index 870d8eeb8..000000000
--- a/apps/web/src/components/landing/TeamMember.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-"use client";
-
-import { Person } from "./Person";
-import {
- Card,
- CardContent,
- CardDescription,
- CardFooter,
- CardHeader,
- CardTitle,
-} from "../shadcn/ui/card";
-import { Oswald } from "next/font/google";
-import Image from "next/image";
-import { useState } from "react";
-const oswald = Oswald({
- variable: "--font-oswald",
- subsets: ["latin"],
-});
-
-// Using the raw svg tag is inefficient. Will need to change later
-function LinkedIn({ fillColor }: { fillColor: string }) {
- return (
-
-
-
- );
-}
-
-function Website({ fillColor }: { fillColor: string }) {
- return (
-
-
-
- );
-}
-
-function Github({ fillColor }: { fillColor: string }) {
- return (
-
-
-
- );
-}
-
-export default function TeamMember({ person }: { person: Person }) {
- // Edit the max width and height and then set the height to auto in the styling
-
- const [src, setSrc] = useState(person.imgLink);
- const [styling, setStyling] = useState(
- "max-w-[110px] md:max-w-[140px] lg:max-w-[160px] 2xl:max-w-[200px] h-auto rounded-lg",
- );
-
- const FallBackStyling =
- "max-w-[105px] md:max-w-[132px] lg:max-w-[150px] xl:max-w-[151px] 2xl:max-w-[188px] rounded-lg";
-
- return (
-
-
-
-
- {`${person.fname}\u00A0${person.lname}`}
-
-
-
- {person.role}
-
-
-
-
- {/* This also needs to be fixed */}
- {
- setSrc("/img/logo/hackkit.svg");
- setStyling(FallBackStyling);
- }}
- />
-
-
-
-
-
-
- );
-}
diff --git a/apps/web/src/components/landing/WorkWithUs.tsx b/apps/web/src/components/landing/WorkWithUs.tsx
index 842c6e243..ccfc3cdb2 100644
--- a/apps/web/src/components/landing/WorkWithUs.tsx
+++ b/apps/web/src/components/landing/WorkWithUs.tsx
@@ -1,13 +1,263 @@
+"use client";
+
+import Image from "next/image";
+import { useEffect, useState } from "react";
+import { Shadows_Into_Light } from "next/font/google";
+import { Person } from "./Person";
+import teamData from "./team.json";
+import Link from "next/link";
+import { Linkedin } from "lucide-react";
+import { motion } from "motion/react";
+import Pin from "./Pin";
+
+const people: Person[] = teamData.team;
+
+const shadowsIntoLight = Shadows_Into_Light({
+ weight: "400",
+ subsets: ["latin"],
+ variable: "--font-shadows",
+});
+
+function srcFor(p: Person) {
+ return p.imgLink && p.imgLink.length > 0 ? p.imgLink : `/${p.fname}.png`;
+}
+
+// Polaroid signature:
+function Polaroid({
+ person,
+ slotIndex,
+}: {
+ person: Person;
+ slotIndex: number;
+}) {
+ const [front, setFront] = useState(person);
+ const [back, setBack] = useState(person);
+ const [showFront, setShowFront] = useState(true);
+ const [roration] = useState(() => Math.random() * 10 - 3);
+
+ useEffect(() => {
+ if (showFront && person !== front) {
+ setBack(person);
+ setShowFront(false);
+ } else if (!showFront && person !== back) {
+ setFront(person);
+ setShowFront(true);
+ }
+ }, [person, front, back, showFront]);
+
+ return (
+
+
+ {/* photo */}
+
+
+
+
+
+ {/* name + linkedin in a row */}
+
+ {/* name crossfade */}
+
+
+ {front.fname} {front.lname}
+
+
+ {back.fname} {back.lname}
+
+
+
+ {/* icon crossfade — its own relative box keeps it in the row */}
+
+ {front.linkedin && (
+
+
+
+ )}
+ {back.linkedin && (
+
+
+
+ )}
+
+
+
+ {(() => {
+ const active = showFront ? front : back;
+ if (!active.note) return null;
+ return (
+
+
+ {active.note.split("").map((char, i) => (
+
+ {char === " " ? "\u00A0" : char}
+
+ ))}
+
+
+ );
+ })()}
+
+ );
+}
+
+function DossierPins() {
+ return (
+ <>
+
+
+
+ >
+ );
+}
+
export default function WorkWithUs() {
+ const [index, setIndex] = useState(0);
+ const len = people.length || 1;
+
+ const [step, setStep] = useState(3);
+
+ useEffect(() => {
+ const lg = window.matchMedia("(min-width: 1024px)"); // lg
+ const md = window.matchMedia("(min-width: 768px)"); // md
+ const sm = window.matchMedia("(min-width: 640px)"); // sm
+
+ const update = () => {
+ if (lg.matches) setStep(5);
+ else if (md.matches) setStep(4);
+ else if (sm.matches) setStep(3);
+ else setStep(2);
+ };
+
+ update();
+ lg.addEventListener("change", update);
+ md.addEventListener("change", update);
+ sm.addEventListener("change", update);
+ return () => {
+ lg.removeEventListener("change", update);
+ md.removeEventListener("change", update);
+ sm.removeEventListener("change", update);
+ };
+ }, []);
+
+ const move = (delta: number) => setIndex((i) => (i + delta + len) % len);
+ const slots = [0, 1, 2, 3, 4];
+
return (
-
-
- Work With Us Section
-
-
- Incentivize companies to monetarily support and other students
- to volunteer to help out!{" "}
-
+
+
+
+
+ {/* carousel row */}
+
+
move(-step)}
+ className={`${shadowsIntoLight.className} text-[7vw] transition-transform hover:scale-110 active:scale-95`}
+ >
+ {"\u2039"}
+
+
+ {slots.map((slot) => {
+ const person_id = (index + slot) % len;
+ const person = people[person_id];
+ const visibility =
+ slot < 2
+ ? "flex"
+ : slot === 2
+ ? "hidden sm:flex"
+ : slot === 3
+ ? "hidden md:flex"
+ : "hidden lg:flex";
+ return (
+
+ );
+ })}
+
+
move(step)}
+ className={`${shadowsIntoLight.className} text-[7vw] transition-transform hover:scale-110 active:scale-95`}
+ >
+ {"\u203A"}
+
+
+
);
}
diff --git a/apps/web/src/components/landing/faq.json b/apps/web/src/components/landing/faq.json
new file mode 100644
index 000000000..4a2fdac3d
--- /dev/null
+++ b/apps/web/src/components/landing/faq.json
@@ -0,0 +1,28 @@
+{
+ "faq": [
+ {
+ "question": "Who can attend?",
+ "answer": "All students can sign up to be a hacker. Regardless of your experience, education, or background, as long as you are excited about learning, building, and having fun, we'd love for you to attend."
+ },
+ {
+ "question": "When is the deadline to apply?",
+ "answer": "The deadline for registration is , at 23:59."
+ },
+ {
+ "question": "How much experience do I need?",
+ "answer": "Absolutely zero! We want you here because you have a passion for creating, not because you're the most experienced hacker on the block. We'll have lots of resources including workshops and a bunch of mentors to help beginners get started. There'll also be plenty of people to learn from and help out!"
+ },
+ {
+ "question": "How much does it cost?",
+ "answer": "Nothing. Nada. Zilch. It's completely free for all accepted hackers. To make it even better, we'll be giving out a ton of swag to every hacker, and prizes to our winners."
+ },
+ {
+ "question": "What should I bring?",
+ "answer": "Please bring a valid ID in addition to anything that would help you with creating your hack or making you comfortable. A laptop, charger, mouse, keyboard, hardware, light jacket, and any hygienic products should be helpful. Don't bring anything you wouldn't bring on an airplane."
+ },
+ {
+ "question": "How do teams work?",
+ "answer": "Teams are limited to 1-4 hackers. If you have a team in mind, make sure all members submit an application before the deadline. If you don't have a team and would like to be a part of one, no worries! We'll have a dedicated time for team formation after the opening ceremony."
+ }
+ ]
+}
diff --git a/apps/web/src/components/landing/faq.tsx b/apps/web/src/components/landing/faq.tsx
new file mode 100644
index 000000000..8d1090502
--- /dev/null
+++ b/apps/web/src/components/landing/faq.tsx
@@ -0,0 +1,167 @@
+"use client";
+import { Manuale } from "next/font/google";
+import faqData from "./faq.json";
+import { motion } from "motion/react";
+import Pin from "./Pin";
+
+const manuale = Manuale({
+ subsets: ["latin"],
+ display: "swap",
+});
+
+type Faq = { question: string; answer: string };
+
+const LEFT_COUNT = 4;
+const allFaqs = faqData.faq as Faq[];
+const leftFaqs = allFaqs.slice(0, LEFT_COUNT);
+const rightFaqs = allFaqs.slice(LEFT_COUNT);
+
+function DossierPins() {
+ return (
+ <>
+
+
+
+ >
+ );
+}
+
+function PaperBg() {
+ return (
+
+ );
+}
+
+function FaqHeader() {
+ return (
+
+
+
+ FAQ
+
+
+ );
+}
+
+function ClassifiedStamp({
+ wrapperClassName = "relative flex justify-end pr-[5%] pb-[5%]",
+}: {
+ wrapperClassName?: string;
+}) {
+ return (
+
+
+
+ );
+}
+
+function FaqItem({ item }: { item: Faq }) {
+ return (
+
+
+
+ {item.question}
+
+
+
+
+ {item.answer}
+
+
+ );
+}
+
+/* ---------- Page ---------- */
+
+export default function FAQ() {
+ return (
+
+
+
+ {/* ===== Desktop & Tablet ===== */}
+
+ {/* Left paper */}
+
+
+
+
+ {leftFaqs.map((item, index) => (
+
+ ))}
+
+
+
+ {/* Right paper */}
+
+
+
+
+ {rightFaqs.map((item, index) => (
+
+ ))}
+
+
+
+
+ {/* ===== Mobile ===== */}
+
+
+
+
+
+
+
+
+
+ {allFaqs.map((item, index) => (
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/landing/partners.json b/apps/web/src/components/landing/partners.json
index fc654015b..17ec4b4b7 100644
--- a/apps/web/src/components/landing/partners.json
+++ b/apps/web/src/components/landing/partners.json
@@ -1,142 +1,28 @@
{
"partners": [
{
- "name": "Cymanii",
- "logo": "CyManII_Logo.svg",
- "url": "https://cymanii.org/",
- "tier": "Gold Sponsor"
- },
- {
- "name": "UTSA DS Dept.",
- "logo": "UTSADS.svg",
- "url": "https://sds.utsa.edu/",
- "tier": "Gold Sponsor"
- },
- {
- "name": "Swivel",
- "logo": "swivel_logo.svg",
- "url": "https://www.getswivel.io/",
- "tier": "Silver Sponsor"
- },
- {
- "name": "UTSA CS Dept.",
- "logo": "UTSA_CS.svg",
- "url": "https://sciences.utsa.edu/computer-science/",
- "tier": "Silver Sponsor"
- },
- {
- "name": "Frost Bank",
- "logo": "FrostBank.svg",
- "url": "https://www.frostbank.com/",
- "tier": "Silver Sponsor"
- },
- {
- "name": "Valero",
- "logo": "ValeroLogo.svg",
- "url": "https://www.valero.com/",
- "tier": "Silver Sponsor"
- },
- {
- "name": "Google",
- "logo": "Google_Icon.svg",
- "url": "https://about.google/",
- "tier": "Bronze Sponsor"
- },
- {
- "name": "Paycom",
- "logo": "PaycomLogo.svg",
- "url": "https://www.paycom.com/",
- "tier": "Bronze Sponsor"
+ "name": "H-E-B",
+ "logo": "HEB.svg",
+ "url": "https://www.heb.com/",
+ "tier": "title"
},
{
"name": "Dell",
- "logo": "Dell_Tech_Logo.svg",
+ "logo": "dell.svg",
"url": "https://www.dell.com/",
- "tier": "Bronze Sponsor"
- },
- {
- "name": "S + S",
- "logo": "Students_and_Startups.svg",
- "url": "https://studentsstartups.com/",
- "tier": "Bronze Sponsor"
- },
- {
- "name": "AFCS",
- "logo": "AFCSLogo.svg",
- "url": "https://afciviliancareers.com/",
- "tier": "Bronze Sponsor"
- },
- {
- "name": "Accenture",
- "logo": "Accenture-logo.svg",
- "url": "https://www.accenture.com/",
- "tier": "Rowdy Partner"
- },
- {
- "name": "UTSA COE",
- "logo": "UTSA_COE.svg",
- "url": "https://klesse.utsa.edu/",
- "tier": "Rowdy Partner"
- },
- {
- "name": "UTSA Tech Store",
- "logo": "rowdy_tech_logo.svg",
- "url": "https://campustechnologystore.com/campustechnologystore/",
- "tier": "Rowdy Partner"
- },
- {
- "name": "TD Synnex",
- "logo": "TD_Synnex_logo.svg",
- "url": "https://www.tdsynnex.com/",
- "tier": "Rowdy Partner"
- },
- {
- "name": "Wolfram Alpha",
- "logo": "wolfram_logo.svg",
- "url": "https://www.wolframalpha.com/",
- "tier": "Rowdy Partner"
- },
- {
- "name": "CodePath",
- "logo": "Codepath_logo.svg",
- "url": "https://www.codepath.org/",
- "tier": "Rowdy Partner"
+ "tier": "golden"
},
{
- "name": "ACM",
- "logo": "ACM_logo.svg",
- "url": "https://www.acm.org/",
- "tier": "Rowdy Partner"
- },
- {
- "name": "Artea",
- "logo": "Artea_logo.svg",
- "url": "https://www.drinkartea.com/",
- "tier": "Rowdy In-Kind"
- },
- {
- "name": "Pho Thien An",
- "logo": "Pho_logo.svg",
- "url": "https://www.phothienan.com/",
- "tier": "Rowdy In-Kind"
- },
- {
- "name": "Bunz Burgers",
- "logo": "Bunz_logo.svg",
- "url": "https://www.tastybunz.com/",
- "tier": "Rowdy In-Kind"
- },
- {
- "name": "H-E-B",
- "logo": "HEB.svg",
- "url": "https://www.heb.com/",
- "tier": "Rowdy In-Kind"
+ "name": "Apple",
+ "logo": "apple.svg",
+ "url": "https://www.apple.com/",
+ "tier": "silver"
},
{
- "name": "Six Flags",
- "logo": "Six_Flags_logo.svg",
- "url": "https://www.sixflags.com/fiestatexas",
- "tier": "Rowdy In-Kind"
+ "name": "google",
+ "logo": "google.svg",
+ "url": "https://www.google.com/",
+ "tier": "bronze"
}
]
}
diff --git a/apps/web/src/components/landing/team.json b/apps/web/src/components/landing/team.json
new file mode 100644
index 000000000..86a9e9760
--- /dev/null
+++ b/apps/web/src/components/landing/team.json
@@ -0,0 +1,202 @@
+{
+ "team": [
+ {
+ "fname": "Evelynn",
+ "lname": "Donaldson",
+ "imgLink": "/img/assets/team/Evelynn Donaldson.webp",
+ "linkedin": "https://www.linkedin.com/in/evelynn-donaldson-191a00290/"
+ },
+ {
+ "fname": "Alekzander",
+ "lname": "Brysch",
+ "imgLink": "/img/assets/team/Alekzander Brysch.webp",
+ "linkedin": "https://www.linkedin.com/in/zander-brysch/",
+ "note": "Director?",
+ "top": "87%",
+ "left": "10%"
+ },
+ {
+ "fname": "Paula",
+ "lname": "Com",
+ "imgLink": "/img/assets/team/Paula Com.webp",
+ "linkedin": "https://www.linkedin.com/in/paula-com-morales/"
+ },
+ {
+ "fname": "Tri",
+ "lname": "Nguyen",
+ "imgLink": "/img/assets/team/Tri Nguyen.webp",
+ "linkedin": "https://www.linkedin.com/in/tri-nguyen2/"
+ },
+ {
+ "fname": "Rufat",
+ "lname": "Niftaliyev",
+ "imgLink": "/img/assets/team/Rufat Niftaliyev.webp",
+ "linkedin": "https://www.linkedin.com/in/rufat-niftaliyev/" ,
+ "note": "Lead?",
+ "top": "87%",
+ "left": "50%"
+ },
+ {
+ "fname": "Cayden",
+ "lname": "Hutcheson",
+ "imgLink": "/img/assets/team/Cayden Hutcheson.webp",
+ "linkedin": "https://www.linkedin.com/in/cayden-hutcheson110/",
+ "note": "Director?",
+ "top": "8%",
+ "left": "15%"
+ },
+ {
+ "fname": "Ash",
+ "lname": "Hernandez",
+ "imgLink": "/img/assets/team/Ash Hernandez.webp",
+ "linkedin": "https://www.linkedin.com/in/ashley-hernandez-sanchez-b76312333/"
+ },
+ {
+ "fname": "Maryna",
+ "lname": "Korolova",
+ "imgLink": "/img/assets/team/Maryna Korolova.webp",
+ "linkedin": "https://www.linkedin.com/in/marynakorolova",
+ "note": "Lead?",
+ "top": "83%",
+ "left": "50%"
+ },
+ {
+ "fname": "Shaun",
+ "lname": "Philippe",
+ "imgLink": "/img/assets/team/Shaun Philippe.webp",
+ "linkedin": "https://www.linkedin.com/in/shaun-ph/"
+ },
+ {
+ "fname": "Josie",
+ "lname": "Sauceda",
+ "imgLink": "/img/assets/team/Josie Sauceda.webp",
+ "linkedin": "https://www.linkedin.com/in/josie-sauceda/"
+ },
+ {
+ "fname": "Miguel",
+ "lname": "Oseguera",
+ "imgLink": "/img/assets/team/Miguel Oseguera.webp",
+ "linkedin": "https://www.linkedin.com/in/miguel-oseguera-0b5306281/",
+ "note": "Lead?",
+ "top": "8%",
+ "left": "8%"
+ },
+ {
+ "fname": "Blessy",
+ "lname": "Kalluri",
+ "imgLink": "/img/assets/team/Blessy Kalluri.webp",
+ "linkedin": "https://www.linkedin.com/in/blessykalluri/"
+ },
+ {
+ "fname": "Camille",
+ "lname": "Hart",
+ "imgLink": "/img/assets/team/Camille Hart.webp",
+ "linkedin": "https://www.linkedin.com/in/camille-louise-rivera/"
+ },
+ {
+ "fname": "Anh",
+ "lname": "Doan",
+ "imgLink": "/img/assets/team/Anh Doan.webp",
+ "linkedin": "https://www.linkedin.com/in/minh-anh-doan-600b94291/",
+ "note": "Lead?",
+ "top": "85%",
+ "left": "6%"
+ },
+ {
+ "fname": "Abrar",
+ "lname": "Ahmed",
+ "imgLink": "/img/assets/team/Abrar Ahmed.webp",
+ "linkedin": "https://www.linkedin.com/in/abrar-ahmed1/"
+ },
+ {
+ "fname": "Diego",
+ "lname": "Medina",
+ "imgLink": "/img/assets/team/Diego Medina.webp",
+ "linkedin": "https://www.linkedin.com/in/diegomedina12/",
+ "note": "Lead?",
+ "top": "85%",
+ "left": "39%"
+ },
+ {
+ "fname": "Dyshana",
+ "lname": "Torres Rivera",
+ "imgLink": "/img/assets/team/Dyshana Torres Rivera.webp",
+ "linkedin": "https://www.linkedin.com/in/dyshana-torres/"
+ },
+ {
+ "fname": "Elisa",
+ "lname": "Moran",
+ "imgLink": "/img/assets/team/Elisa Moran.webp",
+ "linkedin": "https://www.linkedin.com/in/elisa-moran-a6aa2b29a/"
+ },
+ {
+ "fname": "Eric",
+ "lname": "Lee",
+ "imgLink": "/img/assets/team/Eric Lee.webp",
+ "linkedin": "https://www.linkedin.com/in/eric-lee-sunghyun/",
+ "note": "Lead?",
+ "top": "9%",
+ "left": "7%"
+ },
+ {
+ "fname": "Francisco",
+ "lname": "Epinoza",
+ "imgLink": "/img/assets/team/Francisco Epinoza.webp",
+ "linkedin": "https://www.linkedin.com/in/francisco0-espinoza7/"
+ },
+ {
+ "fname": "Layla",
+ "lname": "Mendiola",
+ "imgLink": "/img/assets/team/Layla Mendiola.webp",
+ "linkedin": "https://www.linkedin.com/in/layla-mendiola-144013381/"
+ },
+ {
+ "fname": "Martin",
+ "lname": "Llano",
+ "imgLink": "/img/assets/team/Martin Llano.webp",
+ "linkedin": "https://www.linkedin.com/in/martin-llano-b10239291/"
+ },
+ {
+ "fname": "Reese",
+ "lname": "Sylvester",
+ "imgLink": "/img/assets/team/Reese Sylvester.webp",
+ "linkedin": "" ,
+ "note": "Lead?",
+ "top": "10%",
+ "left": "13%"
+ },
+ {
+ "fname": "Anam",
+ "lname": "Sultana",
+ "imgLink": "/img/assets/team/Anam Sultana.webp",
+ "linkedin": "https://www.linkedin.com/in/anam-sult/"
+ },
+ {
+ "fname": "Savanah",
+ "lname": "Schaefer",
+ "imgLink": "/img/assets/team/Savanah Schaefer.webp",
+ "linkedin": "https://www.linkedin.com/in/savanahsch/",
+ "note": "Lead?",
+ "top": "86%",
+ "left": "10%"
+ },
+ {
+ "fname": "Scherly",
+ "lname": "Ramirez",
+ "imgLink": "/img/assets/team/Scherly Ramirez.webp",
+ "linkedin": "https://www.linkedin.com/in/scherly-ramirez-miranda-189623388/"
+ },
+ {
+ "fname": "Tochi",
+ "lname": "Kalu",
+ "imgLink": "/img/assets/team/Tochi Kalu.webp",
+ "linkedin": ""
+ },
+ {
+ "fname": "Victoria",
+ "lname": "Rivas",
+ "imgLink": "/img/assets/team/Victoria Rivas.webp",
+ "linkedin": ""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/web/src/components/registration/FormGroupWrapper.tsx b/apps/web/src/components/registration/FormGroupWrapper.tsx
index 1c9867feb..86a91947f 100644
--- a/apps/web/src/components/registration/FormGroupWrapper.tsx
+++ b/apps/web/src/components/registration/FormGroupWrapper.tsx
@@ -8,8 +8,8 @@ export default function FormGroupWrapper({
title,
}: FormGroupWrapperProps) {
return (
-
-
+
+
{title}
{children}
diff --git a/apps/web/src/components/registration/RegisterForm.tsx b/apps/web/src/components/registration/RegisterForm.tsx
index 85abd141b..c435097c2 100644
--- a/apps/web/src/components/registration/RegisterForm.tsx
+++ b/apps/web/src/components/registration/RegisterForm.tsx
@@ -82,6 +82,12 @@ import {
decodeBase64AsFile,
} from "@/lib/utils/shared/files";
import { useDebouncedCallback } from "use-debounce";
+import { Manuale } from "next/font/google";
+
+const manuale = Manuale({
+ subsets: ["latin"],
+ display: "swap",
+});
export default function RegisterForm({
defaultEmail,
@@ -361,14 +367,14 @@ export default function RegisterForm({
isLoading={isLoading}
/>
) : (
-