diff --git a/Frontend/README.md b/Frontend/README.md index 986524d..b544e2c 100644 --- a/Frontend/README.md +++ b/Frontend/README.md @@ -1 +1 @@ -# Frontend +# RESTfulMC Frontend \ No newline at end of file diff --git a/Frontend/bun.lockb b/Frontend/bun.lockb index 1505dec..fc03632 100644 Binary files a/Frontend/bun.lockb and b/Frontend/bun.lockb differ diff --git a/Frontend/components.json b/Frontend/components.json new file mode 100644 index 0000000..44d4078 --- /dev/null +++ b/Frontend/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/app/globals.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/app/components", + "utils": "@/app/lib/utils" + } +} diff --git a/Frontend/config.json b/Frontend/config.json new file mode 100644 index 0000000..f2ff49e --- /dev/null +++ b/Frontend/config.json @@ -0,0 +1,37 @@ +{ + "siteName": "RESTfulMC", + "siteUrl": "http://localhost:3000", + "analyticsDomain": "mc.rainnny.club", + "metadata": { + "title": { + "default": "RESTfulMC", + "template": "%s 🞄 RESTfulMC" + }, + "description": "A simple, yet useful RESTful API for Minecraft utilizing Springboot.", + "keywords": [ + "java", + "minecraft", + "json", + "rest-api", + "restful", + "bedrock", + "springboot" + ], + "icons": [ + { + "rel": "icon", + "type": "image/png", + "sizes": "32x32", + "url": "/media/logo.webp" + } + ] + }, + "viewport": { + "themeColor": "minecraft-green-1" + }, + "navbarLinks": { + "Player": "/player", + "Server": "/player", + "Mojang": "/mojang" + } +} diff --git a/Frontend/package.json b/Frontend/package.json index 1cb7d23..8db2c28 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -1,28 +1,38 @@ { - "name": "restfulmc-frontend", - "version": "1.0.0", - "author": "Braydon (Rainnny) ", - "description": "A simple, yet useful RESTful API for Minecraft utilizing Springboot.", - "homepage": "https://mc.rainnny.club", - "scripts": { - "dev": "next dev --turbo", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "react": "^18", - "react-dom": "^18", - "next": "14.2.1" - }, - "devDependencies": { - "typescript": "^5", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "postcss": "^8", - "tailwindcss": "^3.4.1", - "eslint": "^8", - "eslint-config-next": "14.2.1" - } + "name": "restfulmc-frontend", + "version": "1.0.0", + "author": "Braydon (Rainnny) ", + "description": "A simple, yet useful RESTful API for Minecraft utilizing Springboot.", + "homepage": "https://mc.rainnny.club", + "scripts": { + "dev": "next dev --turbo", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-tooltip": "^1.0.7", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "lucide-react": "^0.368.0", + "next": "14.2.1", + "next-plausible": "^3.12.0", + "next-themes": "^0.3.0", + "react": "^18", + "react-dom": "^18", + "restfulmc-lib": "^1.0.7", + "tailwind-merge": "^2.2.2", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "typescript": "^5", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "postcss": "^8", + "tailwindcss": "^3.4.1", + "eslint": "^8", + "eslint-config-next": "14.2.1" + } } diff --git a/Frontend/public/media/logo.webp b/Frontend/public/media/logo.webp new file mode 100644 index 0000000..885ff60 Binary files /dev/null and b/Frontend/public/media/logo.webp differ diff --git a/Frontend/src/app/(pages)/layout.tsx b/Frontend/src/app/(pages)/layout.tsx new file mode 100644 index 0000000..eca52ea --- /dev/null +++ b/Frontend/src/app/(pages)/layout.tsx @@ -0,0 +1,55 @@ +import Navbar from "@/components/navbar"; +import { TooltipProvider } from "@/components/ui/tooltip"; +import config from "@/config"; +import ThemeProvider from "@/provider/theme-provider"; +import type { Metadata, Viewport } from "next"; +import PlausibleProvider from "next-plausible"; +import { Noto_Sans } from "next/font/google"; +import "../globals.css"; + +/** + * Site metadata & viewport. + */ +export const metadata: Metadata = config.metadata; +export const viewport: Viewport = config.viewport; + +/** + * The default Minecraft font to use. + */ +const notoSans = Noto_Sans({ subsets: ["latin"] }); + +/** + * The root layout for this site. + * + * @param children the children of this layout + * @returns the layout jsx + */ +const RootLayout = ({ + children, +}: Readonly<{ + children: React.ReactNode; +}>): JSX.Element => { + const analyticsDomain: string | undefined = config.analyticsDomain; + return ( + + + {analyticsDomain && ( + + )} + + + + + + {children} + + + + + ); +}; +export default RootLayout; diff --git a/Frontend/src/app/(pages)/page.tsx b/Frontend/src/app/(pages)/page.tsx index 5bf9429..29b254b 100644 --- a/Frontend/src/app/(pages)/page.tsx +++ b/Frontend/src/app/(pages)/page.tsx @@ -1,2 +1,11 @@ -const HomePage = (): JSX.Element =>
Hello World
; +/** + * The home page of the site. + * + * @returns the home page jsx + */ +const HomePage = (): JSX.Element => ( +
+ Hello World +
+); export default HomePage; diff --git a/Frontend/src/app/components/navbar.tsx b/Frontend/src/app/components/navbar.tsx new file mode 100644 index 0000000..2a18092 --- /dev/null +++ b/Frontend/src/app/components/navbar.tsx @@ -0,0 +1,41 @@ +import config from "@/config"; +import localFont from "next/font/local"; +import Link from "next/link"; + +/** + * The title font to use to brand the site. + */ +const minecrafter = localFont({ + src: "../font/Minecrafter.ttf", +}); + +/** + * The navbar for the site. + * + * @returns the navbar jsx + */ +const Navbar = () => ( + +); +export default Navbar; diff --git a/Frontend/src/app/components/ui/button.tsx b/Frontend/src/app/components/ui/button.tsx new file mode 100644 index 0000000..f705f1b --- /dev/null +++ b/Frontend/src/app/components/ui/button.tsx @@ -0,0 +1,56 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/app/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/Frontend/src/app/components/ui/tooltip.tsx b/Frontend/src/app/components/ui/tooltip.tsx new file mode 100644 index 0000000..1a6c803 --- /dev/null +++ b/Frontend/src/app/components/ui/tooltip.tsx @@ -0,0 +1,30 @@ +"use client" + +import * as React from "react" +import * as TooltipPrimitive from "@radix-ui/react-tooltip" + +import { cn } from "@/app/lib/utils" + +const TooltipProvider = TooltipPrimitive.Provider + +const Tooltip = TooltipPrimitive.Root + +const TooltipTrigger = TooltipPrimitive.Trigger + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)) +TooltipContent.displayName = TooltipPrimitive.Content.displayName + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } diff --git a/Frontend/src/app/config.ts b/Frontend/src/app/config.ts new file mode 100644 index 0000000..1600248 --- /dev/null +++ b/Frontend/src/app/config.ts @@ -0,0 +1,7 @@ +import { Config } from "@/types/config"; + +/** + * The configuration for this app. + */ +const config: Config = require("@/configJson"); +export default config; diff --git a/Frontend/src/app/font/Minecrafter.ttf b/Frontend/src/app/font/Minecrafter.ttf new file mode 100644 index 0000000..c1be72b Binary files /dev/null and b/Frontend/src/app/font/Minecrafter.ttf differ diff --git a/Frontend/src/app/globals.css b/Frontend/src/app/globals.css index bd6213e..382b4cc 100644 --- a/Frontend/src/app/globals.css +++ b/Frontend/src/app/globals.css @@ -1,3 +1,53 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +@layer base { + :root { + --background: 30 5% 9%; + --foreground: 0 0% 98%; + + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + + --radius: 0.5rem; + + /* Navbar */ + --navbar-background: 0 0% 7%; + + /* Minecraft Colors */ + --minecraft-green-1: 104 51% 43%; + } +} + +@layer base { + * { + @apply border-border; + } + + body { + @apply bg-background text-foreground; + } +} diff --git a/Frontend/src/app/layout.tsx b/Frontend/src/app/layout.tsx deleted file mode 100644 index ce4ab81..0000000 --- a/Frontend/src/app/layout.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { Metadata } from "next"; -import { Inter } from "next/font/google"; -import "./globals.css"; - -const inter = Inter({ subsets: ["latin"] }); - -export const metadata: Metadata = { - title: "RESTfulMC", - description: - "A simple, yet useful RESTful API for Minecraft utilizing Springboot.", -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - {children} - - ); -} diff --git a/Frontend/src/app/lib/utils.ts b/Frontend/src/app/lib/utils.ts new file mode 100644 index 0000000..3200be2 --- /dev/null +++ b/Frontend/src/app/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/Frontend/src/app/provider/theme-provider.tsx b/Frontend/src/app/provider/theme-provider.tsx new file mode 100644 index 0000000..de48665 --- /dev/null +++ b/Frontend/src/app/provider/theme-provider.tsx @@ -0,0 +1,12 @@ +"use client"; + +import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { type ThemeProviderProps } from "next-themes/dist/types"; + +/** + * The provider of themes!! + */ +const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => ( + {children} +); +export default ThemeProvider; diff --git a/Frontend/src/app/types/config.d.ts b/Frontend/src/app/types/config.d.ts new file mode 100644 index 0000000..a24d120 --- /dev/null +++ b/Frontend/src/app/types/config.d.ts @@ -0,0 +1,42 @@ +import { Metadata, Viewport } from "next"; + +/** + * Options for configuration. + */ +interface Config { + /** + * The name of this site. + */ + siteName: string; + + /** + * The URL of this site. + */ + siteUrl: string; + + /** + * The optional domain to track analytics on. + */ + analyticsDomain: string | undefined; + + /** + * The metadata of this site. + */ + metadata: Metadata; + + /** + * The viewport of this site. + */ + viewport: Viewport; + + /** + * Links to display on the navbar. + *

+ * The key is the name of the + * link, and the value is the URL. + *

+ */ + navbarLinks: { + [name: string]: string; + }; +} diff --git a/Frontend/tailwind.config.ts b/Frontend/tailwind.config.ts index 2838159..c96165d 100644 --- a/Frontend/tailwind.config.ts +++ b/Frontend/tailwind.config.ts @@ -1,16 +1,79 @@ import type { Config } from "tailwindcss"; +const { fontFamily } = require("tailwindcss/defaultTheme"); -const config: Config = { - content: ["./src/app/**/*.{js,ts,jsx,tsx,mdx}"], +const config = { + darkMode: ["class"], + content: ["./src/app/**/*.{ts,tsx}"], theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, extend: { - backgroundImage: { - "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", - "gradient-conic": - "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + + // Custom Colors + "navbar-background": "hsl(var(--navbar-background))", + "minecraft-green-1": "hsl(var(--minecraft-green-1))", + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", }, }, }, - plugins: [], -}; + plugins: [require("tailwindcss-animate")], +} satisfies Config; + export default config; diff --git a/Frontend/tsconfig.json b/Frontend/tsconfig.json index 31dc15d..bce7d9a 100644 --- a/Frontend/tsconfig.json +++ b/Frontend/tsconfig.json @@ -19,7 +19,13 @@ ], "paths": { "@/*": ["./src/*"], - "@/lib/*": ["./src/lib/*"] + "@/config": ["./src/app/config.ts"], + "@/components/*": ["./src/app/components/*"], + "@/provider/*": ["./src/app/provider/*"], + "@/font/*": ["./src/app/font/*"], + "@/types/*": ["./src/app/types/*"], + "@/lib/*": ["./src/app/lib/*"], + "@/configJson": ["./config.json"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],