new footer
All checks were successful
Deploy Website / docker (ubuntu-latest) (push) Successful in 3m0s

This commit is contained in:
Rainnny7 2024-10-29 17:39:32 -04:00
parent 803edb4fd5
commit cd8bbeff5d
5 changed files with 186 additions and 72 deletions

@ -1,5 +1,4 @@
import "./globals.css"; import "./globals.css";
import Footer from "@/components/footer";
import { PreloadResources } from "@/components/preload-resources"; import { PreloadResources } from "@/components/preload-resources";
import { QueryProvider } from "@/components/providers/query-provider"; import { QueryProvider } from "@/components/providers/query-provider";
import { ThemeProvider } from "@/components/providers/theme-provider"; import { ThemeProvider } from "@/components/providers/theme-provider";
@ -14,6 +13,8 @@ import { Colors } from "@/common/colors";
import OfflineNetwork from "@/components/offline-network"; import OfflineNetwork from "@/components/offline-network";
import Script from "next/script"; import Script from "next/script";
import { ApiHealth } from "@/components/api/api-health"; import { ApiHealth } from "@/components/api/api-health";
import Footer from "@/components/footer";
import { getBuildInformation } from "@/common/website-utils";
const siteFont = localFont({ const siteFont = localFont({
src: "./fonts/JetBrainsMono.ttf", src: "./fonts/JetBrainsMono.ttf",
@ -66,6 +67,7 @@ export default function RootLayout({
}: Readonly<{ }: Readonly<{
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
const { buildId, buildTimeShort } = getBuildInformation();
return ( return (
<html lang="en"> <html lang="en">
<body className={`${siteFont.className} antialiased w-full h-full`}> <body className={`${siteFont.className} antialiased w-full h-full`}>
@ -84,7 +86,8 @@ export default function RootLayout({
<div className="mt-3 z-[1] m-auto flex flex-col flex-grow items-center w-full md:max-w-[1600px]"> <div className="mt-3 z-[1] m-auto flex flex-col flex-grow items-center w-full md:max-w-[1600px]">
{children} {children}
</div> </div>
<Footer /> {/*<Footer />*/}
<Footer buildId={buildId} buildTimeShort={buildTimeShort} />
</main> </main>
</QueryProvider> </QueryProvider>
</ThemeProvider> </ThemeProvider>

@ -1,78 +1,176 @@
import { getBuildInformation } from "@/common/website-utils"; "use client";
import Link from "next/link";
type NavbarItem = { import Link from "next/link";
import { ExternalLink } from "lucide-react";
import { cn } from "@/common/utils";
import { ReactElement } from "react";
import { SiGithub, SiX } from "react-icons/si";
import { usePathname } from "next/navigation";
type FooterLink = {
/**
* The name of this link.
*/
name: string; name: string;
link: string;
openInNewTab?: boolean; /**
* The href for this link.
*/
href: string;
/**
* The optional name to show
* when the screen size is small.
*/
shortName?: string;
}; };
const items: NavbarItem[] = [ type SocialLinkType = {
/**
* The name of this social link.
*/
name: string;
/**
* The logo for this social link.
*/
logo: ReactElement;
/**
* The href for this social link.
*/
href: string;
};
const links: {
[category: string]: FooterLink[];
} = {
Resources: [
{ {
name: "Home", name: "Swagger Docs",
link: "/", shortName: "Swagger",
href: "/swagger",
}, },
{ {
name: "Source", name: "Source Code",
link: "https://git.fascinated.cc/Fascinated/scoresaber-reloadedv3", shortName: "Source",
openInNewTab: true, href: "https://git.fascinated.cc/Fascinated/scoresaber-reloadedv3",
}, },
{ {
name: "Twitter", name: "System Status",
link: "https://x.com/ssr_reloaded", shortName: "Status",
openInNewTab: true, href: "https://status.fascinated.cc/status/scoresaber-reloaded",
},
{
name: "Discord",
link: "https://discord.gg/kmNfWGA4A8",
openInNewTab: true,
},
{
name: "Status",
link: "https://status.fascinated.cc/status/scoresaber-reloaded",
openInNewTab: true,
},
{
name: "Swagger",
link: "/swagger",
openInNewTab: true,
}, },
],
App: [
{ {
name: "Score Feed", name: "Score Feed",
link: "/scores/live", href: "/scores/live",
openInNewTab: false,
}, },
{ {
name: "Top Scores", name: "Top Scores",
link: "/scores/top/weekly", href: "/scores/top/weekly",
openInNewTab: false, },
],
};
const socialLinks: SocialLinkType[] = [
{
name: "Twitter",
logo: <SiX className="size-5 lg:size-6" />,
href: "https://x.com/ssr_reloaded",
},
{
name: "Discord",
logo: <img className="size-6 lg:size-7" src="/assets/logos/discord.svg" />,
href: "https://discord.gg/kmNfWGA4A8",
},
{
name: "GitHub",
logo: <SiGithub className="size-5 lg:size-6" />,
href: "https://git.fascinated.cc/Fascinated/scoresaber-reloadedv3",
}, },
]; ];
export default function Footer() { export default function Footer({ buildId, buildTimeShort }: { buildId: string; buildTimeShort: string | undefined }) {
const { buildId, buildTime, buildTimeShort } = getBuildInformation(); const isHome: boolean = usePathname() === "/";
return ( return (
<div className="flex items-center w-full flex-col gap-1 mt-6"> <footer
<div className="flex items-center gap-2 text-input text-sm"> className={cn(
<p>Build: {buildId}</p> "px-10 min-h-80 py-5 flex flex-col gap-10 lg:gap-0 justify-between border-t border-muted select-none",
<p className="hidden md:block">({buildTime})</p> isHome ? "bg-[#121212]" : "mt-5 bg-[#121212]/60"
<p className="none md:hidden">({buildTimeShort})</p> )}
>
{/* Top Section */}
<div className="flex justify-center">
{/* Branding & Social Links */}
<div className="w-full max-w-screen-2xl flex flex-col gap-7 lg:flex-row justify-between items-center lg:items-start">
<div className="flex flex-col gap-5">
{/* Branding */}
<div className="flex flex-col gap-2 text-center items-center lg:text-left lg:items-start">
<Link
className="flex gap-3 items-center hover:opacity-75 transition-all transform-gpu"
href="/"
draggable={false}
>
<img className="size-9" src="/assets/logos/scoresaber.png" alt="Scoresaber Logo" />
<h1 className="text-xl font-bold text-pp">ScoreSaber Reloaded</h1>
</Link>
<p className="max-w-md text-sm opacity-85">
ScoreSaber Reloaded is a new way to view your scores and get more stats about you and your plays
</p>
</div> </div>
<div className="w-full flex flex-wrap items-center justify-center bg-secondary/95 divide-x divide-input text-sm py-2">
{items.map((item, index) => { {/* Social Links */}
<div className="flex gap-4 justify-center lg:justify-start items-center">
{socialLinks.map(link => (
<Link
key={link.name}
className="hover:opacity-75 transition-all transform-gpu"
href={link.href}
target="_blank"
draggable={false}
>
{link.logo}
</Link>
))}
</div>
</div>
{/* Links */}
<div className="flex gap-20 md:gap-32 transition-all transform-gpu">
{Object.entries(links).map(([title, links]) => (
<div key={title} className="flex flex-col gap-0.5">
<h1 className="pb-1 text-lg font-semibold text-ssr">{title}</h1>
{links.map(link => {
const external: boolean = !link.href.startsWith("/");
return ( return (
<Link <Link
key={index} key={link.name}
className="px-2 text-ssr hover:brightness-[66%] transition-all transform-gpu" className="flex gap-2 items-center hover:opacity-75 transition-all transform-gpu"
href={item.link} href={link.href}
target={item.openInNewTab ? "_blank" : undefined} target={external ? "_blank" : undefined}
draggable={false}
> >
{item.name} <span className={cn("hidden sm:flex", !link.shortName && "flex")}>{link.name}</span>
{link.shortName && <span className="flex sm:hidden">{link.shortName}</span>}
{external && <ExternalLink className="w-3.5 h-3.5" />}
</Link> </Link>
); );
})} })}
</div> </div>
))}
</div> </div>
</div>
</div>
{/* Bottom Section */}
<div className="flex justify-center">
{/* Build Info */}
<p className="text-sm opacity-50">
Build {buildId} ({buildTimeShort})
</p>
</div>
</footer>
); );
} }

@ -1,4 +1,5 @@
import { UsersRound } from "lucide-react"; import { UsersRound } from "lucide-react";
import { cn } from "@/common/utils";
export default function Friends() { export default function Friends() {
return ( return (
@ -15,7 +16,13 @@ export default function Friends() {
</div> </div>
{/* Content */} {/* Content */}
<div className="max-w-[900px]"> <div
className={cn(
"relative",
"before:absolute before:-left-36 before:-top-28 before:size-[32rem] before:bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] before:from-purple-600 before:rounded-full before:blur-3xl before:opacity-30 before:z-[1]"
)}
>
<div className={cn("relative max-w-[900px] z-20")}>
<img <img
className="w-full h-full rounded-2xl border border-ssr/20" className="w-full h-full rounded-2xl border border-ssr/20"
src="/assets/home/friends.png" src="/assets/home/friends.png"
@ -24,5 +31,6 @@ export default function Friends() {
/> />
</div> </div>
</div> </div>
</div>
); );
} }

@ -52,7 +52,7 @@ function Title() {
ScoreSaber Reloaded ScoreSaber Reloaded
</h1> </h1>
<p className="max-w-sm md:max-w-xl md:text-lg opacity-85"> <p className="max-w-sm md:max-w-xl md:text-lg opacity-85">
Scoresaber Reloaded is a new way to view your scores and get more stats about your and your plays ScoreSaber Reloaded is a new way to view your scores and get more stats about you and your plays
</p> </p>
</> </>
); );
@ -66,7 +66,7 @@ function Buttons() {
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.35, duration: 0.7, ease: "easeOut" }} transition={{ delay: 0.35, duration: 0.7, ease: "easeOut" }}
> >
<Link href="https://discord.gg/kmNfWGA4A8" target="_blank"> <Link href="/search" target="_blank">
<Button className="max-w-52 flex gap-2.5 bg-pp hover:bg-pp/85 text-white text-base"> <Button className="max-w-52 flex gap-2.5 bg-pp hover:bg-pp/85 text-white text-base">
<UserSearch className="size-6" /> <UserSearch className="size-6" />
<span>Player Search</span> <span>Player Search</span>

@ -1,5 +1,5 @@
import { ChartNoAxesCombined, Database, Flame } from "lucide-react"; import { ChartNoAxesCombined, Database, Flame } from "lucide-react";
import { getRandomInteger } from "@/common/utils"; import { cn, getRandomInteger } from "@/common/utils";
import { GlobeAmericasIcon } from "@heroicons/react/24/solid"; import { GlobeAmericasIcon } from "@heroicons/react/24/solid";
import { Difficulty, getDifficulty, getRandomDifficulty } from "@/common/song-utils"; import { Difficulty, getDifficulty, getRandomDifficulty } from "@/common/song-utils";
import { AnimatedList } from "@/components/ui/animated-list"; import { AnimatedList } from "@/components/ui/animated-list";
@ -47,7 +47,12 @@ scores = Array.from({ length: 32 }, () => scores).flat();
export default function RealtimeScores() { export default function RealtimeScores() {
return ( return (
<div className="px-5 -mt-20 flex flex-col lg:flex-row-reverse gap-10 select-none"> <div
className={cn(
"relative px-5 -mt-20 flex flex-col lg:flex-row-reverse gap-10 select-none",
"before:absolute before:-left-40 before:-bottom-36 before:size-[28rem] before:bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] before:from-yellow-600 before:rounded-full before:blur-3xl before:opacity-30"
)}
>
{/* Header */} {/* Header */}
<div className="flex flex-col gap-2.5 text-right items-end"> <div className="flex flex-col gap-2.5 text-right items-end">
<div className="flex flex-row-reverse gap-3 items-center text-yellow-400"> <div className="flex flex-row-reverse gap-3 items-center text-yellow-400">