From f438d0339967d81796f9355420bace928df496ee Mon Sep 17 00:00:00 2001 From: dvelo <52332868+DeveloLongScript@users.noreply.github.com> Date: Sat, 15 Feb 2025 17:18:58 -0600 Subject: [PATCH] feat: add topbar and fix versioning --- apps/www/src/app/(main)/layout.tsx | 78 ++++ apps/www/src/app/(main)/page.tsx | 16 + apps/www/src/app/layout.tsx | 51 +++ apps/www/src/app/not-found.tsx | 12 + .../www/src/components/feat/navbar/navbar.tsx | 24 ++ .../feat/server-list/server-list.tsx | 4 + apps/www/src/components/icon.tsx | 357 ++++++++++++++++++ apps/www/src/components/ui/github.tsx | 20 + apps/www/src/components/util/is-script.tsx | 11 + apps/www/src/components/util/link.tsx | 109 ++++++ apps/www/src/components/util/not-found.tsx | 20 + apps/www/src/config/version.tsx | 44 ++- 12 files changed, 723 insertions(+), 23 deletions(-) create mode 100644 apps/www/src/app/(main)/layout.tsx create mode 100644 apps/www/src/app/(main)/page.tsx create mode 100644 apps/www/src/app/layout.tsx create mode 100644 apps/www/src/app/not-found.tsx create mode 100644 apps/www/src/components/feat/navbar/navbar.tsx create mode 100644 apps/www/src/components/feat/server-list/server-list.tsx create mode 100644 apps/www/src/components/icon.tsx create mode 100644 apps/www/src/components/ui/github.tsx create mode 100644 apps/www/src/components/util/is-script.tsx create mode 100644 apps/www/src/components/util/link.tsx create mode 100644 apps/www/src/components/util/not-found.tsx diff --git a/apps/www/src/app/(main)/layout.tsx b/apps/www/src/app/(main)/layout.tsx new file mode 100644 index 0000000..cd23220 --- /dev/null +++ b/apps/www/src/app/(main)/layout.tsx @@ -0,0 +1,78 @@ +/* + * MHSF, Minehut Server List + * All external content is rather licensed under the ECA Agreement + * located here: https://mhsf.app/docs/legal/external-content-agreement + * + * All code under MHSF is licensed under the MIT License + * by open source contributors + * + * Copyright (c) 2024 dvelo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +"use client"; +import "../globals.css"; +import { useSearchParams } from "next/navigation"; +import { Inter } from "next/font/google"; +import { Placeholder } from "@/components/ui/placeholder"; +import { X } from "lucide-react"; +import { IsScript } from "@/components/util/is-script"; +import { Button } from "@/components/ui/button"; +import { ClerkProvider } from "@clerk/nextjs"; +import Link from "next/link"; +import { NavBar } from "@/components/feat/navbar/navbar"; + +const inter = Inter({ subsets: ["latin"] }); + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + const searchParams = useSearchParams(); + const search = searchParams?.get("theme") || "light"; + + return ( + + + + + + +
{children}
+
+ + +
+ ); +} diff --git a/apps/www/src/app/(main)/page.tsx b/apps/www/src/app/(main)/page.tsx new file mode 100644 index 0000000..9c50722 --- /dev/null +++ b/apps/www/src/app/(main)/page.tsx @@ -0,0 +1,16 @@ +import { ServerList } from "@/components/feat/server-list/server-list"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + applicationName: "MHSF", + title: "Server list · MHSF", + description: "View all servers on Minehut using the MHSF server list.", +}; + +export default function ServerListPage() { + return ( +
+ +
+ ); +} diff --git a/apps/www/src/app/layout.tsx b/apps/www/src/app/layout.tsx new file mode 100644 index 0000000..0cb2762 --- /dev/null +++ b/apps/www/src/app/layout.tsx @@ -0,0 +1,51 @@ +/* + * MHSF, Minehut Server List + * All external content is rather licensed under the ECA Agreement + * located here: https://mhsf.app/docs/legal/external-content-agreement + * + * All code under MHSF is licensed under the MIT License + * by open source contributors + * + * Copyright (c) 2024 dvelo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +"use client"; +import "./globals.css"; +import { useSearchParams } from "next/navigation"; +import { Inter } from "next/font/google"; + +const inter = Inter({ subsets: ["latin"] }); + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + const searchParams = useSearchParams(); + const search = searchParams?.get("theme") || "light"; + + return ( + + {children} + + ); +} diff --git a/apps/www/src/app/not-found.tsx b/apps/www/src/app/not-found.tsx new file mode 100644 index 0000000..7ad6a74 --- /dev/null +++ b/apps/www/src/app/not-found.tsx @@ -0,0 +1,12 @@ +import { NotFoundComponent } from "@/components/util/not-found"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + applicationName: "MHSF", + title: "Page not found · MHSF", + description: "Couldn't find the page that was requested.", +}; + +export default function NotFoundPage() { + return ; +} diff --git a/apps/www/src/components/feat/navbar/navbar.tsx b/apps/www/src/components/feat/navbar/navbar.tsx new file mode 100644 index 0000000..46faed7 --- /dev/null +++ b/apps/www/src/components/feat/navbar/navbar.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { BrandingColorfulIcon } from "@/components/Icon"; +import { version } from "@/config/version"; +import { cn } from "@/lib/utils"; + +export function NavBar() { + return ( +
+
+ + + MHSF + v{version} + +
+
+ ); +} diff --git a/apps/www/src/components/feat/server-list/server-list.tsx b/apps/www/src/components/feat/server-list/server-list.tsx new file mode 100644 index 0000000..e2bbb25 --- /dev/null +++ b/apps/www/src/components/feat/server-list/server-list.tsx @@ -0,0 +1,4 @@ +"use client"; +export function ServerList() { + return
Server List
; +} diff --git a/apps/www/src/components/icon.tsx b/apps/www/src/components/icon.tsx new file mode 100644 index 0000000..fc93891 --- /dev/null +++ b/apps/www/src/components/icon.tsx @@ -0,0 +1,357 @@ +/* + * MHSF, Minehut Server List + * All external content is rather licensed under the ECA Agreement + * located here: https://list.mlnehut.com/docs/legal/external-content-agreement + * + * All code under MHSF is licensed under the MIT License + * by open source contributors + * + * Copyright (c) 2024 dvelo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +"use client"; +import { useTheme } from "next-themes"; +import type { SVGProps } from "react"; + +/** + * Returns a colorful version of the branding icon. + * + * The stored SVG file is at `/public/svg/icon-cf.svg` + * + * @param props The props for the SVG element. + * @returns A JSX element representing the colorful branding icon. + */ +export function BrandingColorfulIcon(props: SVGProps) { + return ( + + + + + + + + + + + + + + + + ); +} +/** + * Returns the optional Pride icon + * + * The stored SVG file is at `/public/svg/icon-p.svg` + * + * @param {SVGProps} props The props for the SVG element. + * @returns A JSX element representing the branding icon. + */ +export function BrandingPrideIcon(props: SVGProps) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} + +/** + * Returns the branding icon based on the current theme. + * + * If the theme is dark, the branding icon is a dark version of the logo. + * If the theme is light, the branding icon is a light version of the logo. + * + * The stored SVG file is at `/public/svg/icon-gl.svg` or `/public/svg/icon-gd.svg` + * + * @param {SVGProps} props The props for the SVG element. + * + * @returns A JSX element representing the branding icon. + */ +export function BrandingGenericIcon(props: SVGProps) { + const { resolvedTheme } = useTheme(); + + if (resolvedTheme == "dark") { + return ( + + + + + + + + + + + + + + + ); + } else { + return ( + + + + + + + + + + + + + + + ); + } +} + +export function BadgeOfAffiliation(props: SVGProps) { + return ( + + + + + + + + + + + ); +} + +export const Discord = (props: SVGProps) => ( + + + +); diff --git a/apps/www/src/components/ui/github.tsx b/apps/www/src/components/ui/github.tsx new file mode 100644 index 0000000..8dca926 --- /dev/null +++ b/apps/www/src/components/ui/github.tsx @@ -0,0 +1,20 @@ +import { useTheme } from "next-themes"; +import type { SVGProps } from "react"; +const Github = (props: SVGProps) => { + const { resolvedTheme } = useTheme(); + + return ( + + + + ); +}; +export default Github; diff --git a/apps/www/src/components/util/is-script.tsx b/apps/www/src/components/util/is-script.tsx new file mode 100644 index 0000000..1ac7636 --- /dev/null +++ b/apps/www/src/components/util/is-script.tsx @@ -0,0 +1,11 @@ +"use client"; + +import { useEffect, useState } from "react"; + +export function IsScript({ children }: { children: React.ReactNode }) { + const [mounted, setMounted] = useState(false); + + useEffect(() => setMounted(true)); + + return mounted && children; +} diff --git a/apps/www/src/components/util/link.tsx b/apps/www/src/components/util/link.tsx new file mode 100644 index 0000000..8b869d3 --- /dev/null +++ b/apps/www/src/components/util/link.tsx @@ -0,0 +1,109 @@ +/* + * MHSF, Minehut Server List + * All external content is rather licensed under the ECA Agreement + * located here: https://list.mlnehut.com/docs/legal/external-content-agreement + * + * All code under MHSF is licensed under the MIT License + * by open source contributors + * + * Copyright (c) 2024 dvelo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +import type { ReactNode } from "react"; +import { default as NextLink } from "next/link"; +import { Book, ExternalLink, NotebookText } from "lucide-react"; + +export default function A({ + children, + alt, +}: { + children: string; + alt: string | ReactNode; +}) { + return ( + + {(children || "").startsWith("Docs:") && ( + + )} + {(children || "").startsWith("Wiki:") && ( + + )} + {alt} + {(children || "").startsWith("https") && ( + + )} + + ); +} + +export function ALegacy({ + children, + href, +}: { + children?: string | ReactNode; + href?: string; +}) { + return ( + + {(href || "").startsWith("Docs:") && ( + + )} + {(href || "").startsWith("Wiki:") && ( + + )} + {children} + {(href || "").startsWith("https") && ( + + )} + + ); +} + +export const pageFind = (text: string) => { + if (text.startsWith("Docs:")) { + return "/docs/" + text.substring(5).toLowerCase(); + } + if (text === "Special:Root") return "/"; + if (text === "Special:Preferences") return "/account/settings"; + if (text === "Special:AccountOptions") return "/account/settings/options"; + if (text.startsWith("Server:") && text.endsWith("/Customization")) + return "/server/" + text.substring(7, text.length - 14) + "/customization"; + if (text === "Special:ClerkConvertionPage") return process.env.NEXT_PUBLIC_CLERK_SWITCH_DOMAIN; + if (text.startsWith("Server:")) return "/server/" + text.substring(7); + if (text.startsWith("Wiki:")) + return "https://minehut.wiki.gg/wiki/" + text.substring(5); + if (text.startsWith("GitHub:")) + return "https://github.com/" + text.substring(7); + if (text === "Special:GitHub") + return "https://github.com/DeveloLongScript/MHSF"; + if (text.startsWith("Special:GitHub/")) + return "https://github.com/DeveloLongScript/MHSF/" + text.substring(15); + return text; +}; diff --git a/apps/www/src/components/util/not-found.tsx b/apps/www/src/components/util/not-found.tsx new file mode 100644 index 0000000..eb3921c --- /dev/null +++ b/apps/www/src/components/util/not-found.tsx @@ -0,0 +1,20 @@ +import { X } from "lucide-react"; +import { Placeholder } from "../ui/placeholder"; +import Link from "next/link"; +import { Button } from "../ui/button"; + +export function NotFoundComponent() { + return ( +
+ } + title="We couldn't find that page" + description="The page you were trying to go to either doesn't exist ever or has been removed previously." + > + + + + +
+ ); +} diff --git a/apps/www/src/config/version.tsx b/apps/www/src/config/version.tsx index 4f66f5d..db096ff 100644 --- a/apps/www/src/config/version.tsx +++ b/apps/www/src/config/version.tsx @@ -29,7 +29,7 @@ */ "use client"; -import A from "@/components/misc/Link"; +import A from "@/components/util/link"; import { Button } from "@/components/ui/button"; import Github from "@/components/ui/github"; import Link from "next/link"; @@ -67,35 +67,33 @@ const FeatureList = ({ ); }; -export const version = "1.8.0"; +export const version = "2.0"; export const changelog: { name: string; id: string; changelog: ReactNode }[] = [ - { - id: "tnjageringae231nfnajrekgra", - name: "v1.8.0", - changelog: ( - - Version 1.8.0 (February 14th 2025, {"<3 happy valentines"}) - - } - /> - ), - }, + { + id: "tnjageringae231nfnajrekgra", + name: "v1.8.0", + changelog: ( + + Version 1.8.0 (February 14th 2025, {"<3 happy valentines"}) + + } + /> + ), + }, { id: "tj4ijg09aern9eargjjuauerr", name: "v1.7.5", changelog: ( Version 1.7.5 (January 29th 2025)