diff --git a/Frontend/.eslintrc.json b/Frontend/.eslintrc.json index bffb357..0e81f9b 100644 --- a/Frontend/.eslintrc.json +++ b/Frontend/.eslintrc.json @@ -1,3 +1,3 @@ { "extends": "next/core-web-vitals" -} +} \ No newline at end of file diff --git a/Frontend/.gitignore b/Frontend/.gitignore index 80ee040..673aee7 100644 --- a/Frontend/.gitignore +++ b/Frontend/.gitignore @@ -1,6 +1,8 @@ node_modules -.next/ +.idea/ .fleet/ .vscode/ +.VSCodeCounter/ +.next/ .env*.local next-env.d.ts \ No newline at end of file diff --git a/Frontend/bun.lockb b/Frontend/bun.lockb index 7d3b1b6..f56dc23 100644 Binary files a/Frontend/bun.lockb and b/Frontend/bun.lockb differ diff --git a/Frontend/config.json b/Frontend/config.json index 8357055..9048b32 100644 --- a/Frontend/config.json +++ b/Frontend/config.json @@ -49,5 +49,17 @@ "image": "/media/featured/server.jpg", "href": "/server" } - ] + ], + "footerLinks": { + "Utilities": { + "Player Query": "/player", + "Server Query": "/server", + "Mojang Status": "/mojang" + }, + "Resources": { + "Source Code": "https://github.com/Rainnny7/RESTfulMC", + "Wiki": "https://git.rainnny.club/Rainnny/RESTfulMC/wiki", + "SwaggerUI": "https://api.restfulmc.cc/swagger-ui.html" + } + } } diff --git a/Frontend/package.json b/Frontend/package.json index e0d4415..f9caee9 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -41,7 +41,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", - "eslint": "^9.0.0", + "eslint": "8.57.0", "eslint-config-next": "14.2.2", "postcss": "^8", "sleep-promise": "^9.1.0", diff --git a/Frontend/src/app/(pages)/docs/page.tsx b/Frontend/src/app/(pages)/docs/page.tsx index 93d9fcf..6d2afea 100644 --- a/Frontend/src/app/(pages)/docs/page.tsx +++ b/Frontend/src/app/(pages)/docs/page.tsx @@ -18,7 +18,7 @@ export const metadata: Metadata = { * @returns the page jsx */ const DocsPage = (): ReactElement => ( -
+
{/* Creeper */} diff --git a/Frontend/src/app/(pages)/mojang/page.tsx b/Frontend/src/app/(pages)/mojang/page.tsx index 80c0b5f..87009b1 100644 --- a/Frontend/src/app/(pages)/mojang/page.tsx +++ b/Frontend/src/app/(pages)/mojang/page.tsx @@ -4,9 +4,9 @@ import { Metadata } from "next"; import Link from "next/link"; import { ReactElement } from "react"; import { + getMojangServerStatus, MojangServerStatus, MojangServerStatusResponse, - getMojangServerStatus, } from "restfulmc-lib"; /** diff --git a/Frontend/src/app/(pages)/page.tsx b/Frontend/src/app/(pages)/page.tsx index 3fe7911..a3dba86 100644 --- a/Frontend/src/app/(pages)/page.tsx +++ b/Frontend/src/app/(pages)/page.tsx @@ -1,8 +1,8 @@ -import Background from "@/components/landing/background"; import FeaturedContent from "@/components/landing/featured-content"; import Hero from "@/components/landing/hero"; import StatisticCounters from "@/components/landing/statistic-counters"; import { ReactElement } from "react"; +import HeroBackground from "../components/landing/background"; /** * The landing page. @@ -13,7 +13,7 @@ const LandingPage = (): ReactElement => (
{/* Hero */}
- +
diff --git a/Frontend/src/app/(pages)/server/[[...slug]]/page.tsx b/Frontend/src/app/(pages)/server/[[...slug]]/page.tsx index cb3bc8c..1ed4f0a 100644 --- a/Frontend/src/app/(pages)/server/[[...slug]]/page.tsx +++ b/Frontend/src/app/(pages)/server/[[...slug]]/page.tsx @@ -12,9 +12,9 @@ import { ReactElement } from "react"; import { CachedBedrockMinecraftServer, CachedJavaMinecraftServer, - ServerPlatform, getMinecraftServer, type RestfulMCAPIError, + ServerPlatform, } from "restfulmc-lib"; /** diff --git a/Frontend/src/app/components/footer.tsx b/Frontend/src/app/components/footer.tsx index f5ee589..af585cc 100644 --- a/Frontend/src/app/components/footer.tsx +++ b/Frontend/src/app/components/footer.tsx @@ -1,4 +1,86 @@ +import Image from "next/image"; +import Link from "next/link"; import { ReactElement } from "react"; +import config from "@/config"; +import { minecrafter } from "@/font/fonts"; +import { cn } from "@/lib/utils"; +import { FooterLinks } from "@/types/config"; -const Footer = (): ReactElement =>
FOOTER
; +const Footer = (): ReactElement => ( +
+
+ {/* Branding */} +
+ {/* Logo & Site Name */} +
+ Site Logo + +

+ {config.siteName} +

+
+ + {/* Disclaimer */} +

+ Not affiliated with Mojang or Microsoft. +

+
+ + {/* Links */} +
+ {Object.keys(config.footerLinks).map( + (header: string, groupIndex: number): ReactElement => ( +
+ {/* Header */} +

+ {header} +

+ + {/* Links */} +
+ {Object.entries( + (config.footerLinks as FooterLinks)[header] + ).map( + ( + [name, url]: [string, string], + linkIndex: number + ): ReactElement => ( + + {name} + + ) + )} +
+
+ ) + )} +
+
+
+); export default Footer; diff --git a/Frontend/src/app/components/github-star-button.tsx b/Frontend/src/app/components/github-star-button.tsx index 68fa770..5eb6ab6 100644 --- a/Frontend/src/app/components/github-star-button.tsx +++ b/Frontend/src/app/components/github-star-button.tsx @@ -33,7 +33,6 @@ const GitHubStarButton = (): ReactElement => { ); const json: any = await response.json(); // Get the JSON response setStars(json.stargazers_count); // Set the stars - console.log("fetch stars"); }; if (stars === undefined) { fetchStars(); // Fetch the stars diff --git a/Frontend/src/app/components/landing/background.tsx b/Frontend/src/app/components/landing/background.tsx index e638bc2..dbafa9d 100644 --- a/Frontend/src/app/components/landing/background.tsx +++ b/Frontend/src/app/components/landing/background.tsx @@ -2,11 +2,11 @@ import { ReactElement } from "react"; import { cn } from "../../lib/utils"; /** - * The background component. + * The background hero component. * * @returns the background jsx */ -const Background = (): ReactElement => ( +const HeroBackground = (): ReactElement => (
( )} /> ); -export default Background; +export default HeroBackground; diff --git a/Frontend/src/app/components/landing/statistic-counters.tsx b/Frontend/src/app/components/landing/statistic-counters.tsx index 633ea73..a2c0c83 100644 --- a/Frontend/src/app/components/landing/statistic-counters.tsx +++ b/Frontend/src/app/components/landing/statistic-counters.tsx @@ -7,7 +7,7 @@ import { ReactElement } from "react"; * @returns the counters jsx */ const StatisticCounters = (): ReactElement => ( -
+
diff --git a/Frontend/src/app/components/ui/badge.tsx b/Frontend/src/app/components/ui/badge.tsx index f99cedf..5990b73 100644 --- a/Frontend/src/app/components/ui/badge.tsx +++ b/Frontend/src/app/components/ui/badge.tsx @@ -1,36 +1,36 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/app/lib/utils" +import { cn } from "@/app/lib/utils"; const badgeVariants = cva( - "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", - { - variants: { - variant: { - default: - "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", - secondary: - "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", - destructive: - "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", - outline: "text-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} + extends React.HTMLAttributes, + VariantProps {} function Badge({ className, variant, ...props }: BadgeProps) { - return ( -
- ) + return ( +
+ ); } -export { Badge, badgeVariants } +export { Badge, badgeVariants }; diff --git a/Frontend/src/app/components/ui/button.tsx b/Frontend/src/app/components/ui/button.tsx index f705f1b..dc76d90 100644 --- a/Frontend/src/app/components/ui/button.tsx +++ b/Frontend/src/app/components/ui/button.tsx @@ -1,56 +1,57 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +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" +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", - }, - } -) + "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 + 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" + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + } +); +Button.displayName = "Button"; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/Frontend/src/app/components/ui/context-menu.tsx b/Frontend/src/app/components/ui/context-menu.tsx index 2bd9c6b..a7812cc 100644 --- a/Frontend/src/app/components/ui/context-menu.tsx +++ b/Frontend/src/app/components/ui/context-menu.tsx @@ -1,200 +1,200 @@ -"use client" +"use client"; -import * as React from "react" -import * as ContextMenuPrimitive from "@radix-ui/react-context-menu" -import { Check, ChevronRight, Circle } from "lucide-react" +import * as React from "react"; +import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"; +import { Check, ChevronRight, Circle } from "lucide-react"; -import { cn } from "@/app/lib/utils" +import { cn } from "@/app/lib/utils"; -const ContextMenu = ContextMenuPrimitive.Root +const ContextMenu = ContextMenuPrimitive.Root; -const ContextMenuTrigger = ContextMenuPrimitive.Trigger +const ContextMenuTrigger = ContextMenuPrimitive.Trigger; -const ContextMenuGroup = ContextMenuPrimitive.Group +const ContextMenuGroup = ContextMenuPrimitive.Group; -const ContextMenuPortal = ContextMenuPrimitive.Portal +const ContextMenuPortal = ContextMenuPrimitive.Portal; -const ContextMenuSub = ContextMenuPrimitive.Sub +const ContextMenuSub = ContextMenuPrimitive.Sub; -const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup +const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup; const ContextMenuSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } >(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)) -ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName + + {children} + + +)); +ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName; const ContextMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName + +)); +ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName; const ContextMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - - -)) -ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName + + + +)); +ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName; const ContextMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } >(({ className, inset, ...props }, ref) => ( - -)) -ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName + +)); +ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName; const ContextMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)) + + + + + + + {children} + +)); ContextMenuCheckboxItem.displayName = - ContextMenuPrimitive.CheckboxItem.displayName + ContextMenuPrimitive.CheckboxItem.displayName; const ContextMenuRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)) -ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName + + + + + + + {children} + +)); +ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName; const ContextMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } >(({ className, inset, ...props }, ref) => ( - -)) -ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName + +)); +ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName; const ContextMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName + +)); +ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName; const ContextMenuShortcut = ({ - className, - ...props + className, + ...props }: React.HTMLAttributes) => { - return ( - - ) -} -ContextMenuShortcut.displayName = "ContextMenuShortcut" + return ( + + ); +}; +ContextMenuShortcut.displayName = "ContextMenuShortcut"; export { - ContextMenu, - ContextMenuTrigger, - ContextMenuContent, - ContextMenuItem, - ContextMenuCheckboxItem, - ContextMenuRadioItem, - ContextMenuLabel, - ContextMenuSeparator, - ContextMenuShortcut, - ContextMenuGroup, - ContextMenuPortal, - ContextMenuSub, - ContextMenuSubContent, - ContextMenuSubTrigger, - ContextMenuRadioGroup, -} + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, + ContextMenuItem, + ContextMenuCheckboxItem, + ContextMenuRadioItem, + ContextMenuLabel, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuGroup, + ContextMenuPortal, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuRadioGroup, +}; diff --git a/Frontend/src/app/components/ui/label.tsx b/Frontend/src/app/components/ui/label.tsx index a992f60..dbb2d78 100644 --- a/Frontend/src/app/components/ui/label.tsx +++ b/Frontend/src/app/components/ui/label.tsx @@ -7,19 +7,19 @@ import * as React from "react"; import { cn } from "@/app/lib/utils"; const labelVariants = cva( - "text-sm font-medium text-zinc-300 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" + "text-sm font-medium text-zinc-300 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" ); const Label = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps >(({ className, ...props }, ref) => ( - + )); Label.displayName = LabelPrimitive.Root.displayName; diff --git a/Frontend/src/app/components/ui/select.tsx b/Frontend/src/app/components/ui/select.tsx index abdae28..5329a24 100644 --- a/Frontend/src/app/components/ui/select.tsx +++ b/Frontend/src/app/components/ui/select.tsx @@ -1,160 +1,160 @@ -"use client" +"use client"; -import * as React from "react" -import * as SelectPrimitive from "@radix-ui/react-select" -import { Check, ChevronDown, ChevronUp } from "lucide-react" +import * as React from "react"; +import * as SelectPrimitive from "@radix-ui/react-select"; +import { Check, ChevronDown, ChevronUp } from "lucide-react"; -import { cn } from "@/app/lib/utils" +import { cn } from "@/app/lib/utils"; -const Select = SelectPrimitive.Root +const Select = SelectPrimitive.Root; -const SelectGroup = SelectPrimitive.Group +const SelectGroup = SelectPrimitive.Group; -const SelectValue = SelectPrimitive.Value +const SelectValue = SelectPrimitive.Value; const SelectTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - span]:line-clamp-1 transition-all transform-gpu", - className - )} - {...props} - > - {children} - - - - -)) -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + span]:line-clamp-1 transition-all transform-gpu", + className + )} + {...props} + > + {children} + + + + +)); +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; const SelectScrollUpButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - - -)) -SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + + + +)); +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; const SelectScrollDownButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - - -)) + + + +)); SelectScrollDownButton.displayName = - SelectPrimitive.ScrollDownButton.displayName + SelectPrimitive.ScrollDownButton.displayName; const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, position = "popper", ...props }, ref) => ( - - - - - {children} - - - - -)) -SelectContent.displayName = SelectPrimitive.Content.displayName + + + + + {children} + + + + +)); +SelectContent.displayName = SelectPrimitive.Content.displayName; const SelectLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -SelectLabel.displayName = SelectPrimitive.Label.displayName + +)); +SelectLabel.displayName = SelectPrimitive.Label.displayName; const SelectItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - - - - - + + + + + + - {children} - -)) -SelectItem.displayName = SelectPrimitive.Item.displayName + {children} + +)); +SelectItem.displayName = SelectPrimitive.Item.displayName; const SelectSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +)); +SelectSeparator.displayName = SelectPrimitive.Separator.displayName; export { - Select, - SelectGroup, - SelectValue, - SelectTrigger, - SelectContent, - SelectLabel, - SelectItem, - SelectSeparator, - SelectScrollUpButton, - SelectScrollDownButton, -} + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +}; diff --git a/Frontend/src/app/components/ui/skeleton.tsx b/Frontend/src/app/components/ui/skeleton.tsx index cebdb00..e8cde28 100644 --- a/Frontend/src/app/components/ui/skeleton.tsx +++ b/Frontend/src/app/components/ui/skeleton.tsx @@ -1,15 +1,15 @@ -import { cn } from "@/app/lib/utils" +import { cn } from "@/app/lib/utils"; function Skeleton({ - className, - ...props + className, + ...props }: React.HTMLAttributes) { - return ( -
- ) + return ( +
+ ); } -export { Skeleton } +export { Skeleton }; diff --git a/Frontend/src/app/components/ui/sonner.tsx b/Frontend/src/app/components/ui/sonner.tsx index 452f4d9..d8dc1cc 100644 --- a/Frontend/src/app/components/ui/sonner.tsx +++ b/Frontend/src/app/components/ui/sonner.tsx @@ -1,31 +1,30 @@ -"use client" +"use client"; -import { useTheme } from "next-themes" -import { Toaster as Sonner } from "sonner" +import { useTheme } from "next-themes"; +import { Toaster as Sonner } from "sonner"; -type ToasterProps = React.ComponentProps +type ToasterProps = React.ComponentProps; const Toaster = ({ ...props }: ToasterProps) => { - const { theme = "system" } = useTheme() + const { theme = "system" } = useTheme(); - return ( - - ) -} + return ( + + ); +}; -export { Toaster } +export { Toaster }; diff --git a/Frontend/src/app/components/ui/toast.tsx b/Frontend/src/app/components/ui/toast.tsx index c7fb656..a32532a 100644 --- a/Frontend/src/app/components/ui/toast.tsx +++ b/Frontend/src/app/components/ui/toast.tsx @@ -1,122 +1,129 @@ -"use client" +"use client"; -import * as ToastPrimitives from "@radix-ui/react-toast" -import { cva, type VariantProps } from "class-variance-authority" -import { X } from "lucide-react" -import * as React from "react" +import * as ToastPrimitives from "@radix-ui/react-toast"; +import { cva, type VariantProps } from "class-variance-authority"; +import { X } from "lucide-react"; +import * as React from "react"; -import { cn } from "@/app/lib/utils" +import { cn } from "@/app/lib/utils"; -const ToastProvider = ToastPrimitives.Provider +const ToastProvider = ToastPrimitives.Provider; const ToastViewport = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ToastViewport.displayName = ToastPrimitives.Viewport.displayName + +)); +ToastViewport.displayName = ToastPrimitives.Viewport.displayName; const toastVariants = cva( - "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", - { - variants: { - variant: { - default: "border bg-muted text-foreground", - destructive: - "destructive group border-destructive bg-destructive text-destructive-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) + "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", + { + variants: { + variant: { + default: "border bg-muted text-foreground", + destructive: + "destructive group border-destructive bg-destructive text-destructive-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); const Toast = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps >(({ className, variant, ...props }, ref) => { - return ( - - ) -}) -Toast.displayName = ToastPrimitives.Root.displayName + return ( + + ); +}); +Toast.displayName = ToastPrimitives.Root.displayName; const ToastAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ToastAction.displayName = ToastPrimitives.Action.displayName + +)); +ToastAction.displayName = ToastPrimitives.Action.displayName; const ToastClose = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - - -)) -ToastClose.displayName = ToastPrimitives.Close.displayName + + + +)); +ToastClose.displayName = ToastPrimitives.Close.displayName; const ToastTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ToastTitle.displayName = ToastPrimitives.Title.displayName + +)); +ToastTitle.displayName = ToastPrimitives.Title.displayName; const ToastDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ToastDescription.displayName = ToastPrimitives.Description.displayName + +)); +ToastDescription.displayName = ToastPrimitives.Description.displayName; -type ToastProps = React.ComponentPropsWithoutRef +type ToastProps = React.ComponentPropsWithoutRef; -type ToastActionElement = React.ReactElement +type ToastActionElement = React.ReactElement; export { - Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, type ToastActionElement, type ToastProps -} - + Toast, + ToastAction, + ToastClose, + ToastDescription, + ToastProvider, + ToastTitle, + ToastViewport, + type ToastActionElement, + type ToastProps, +}; diff --git a/Frontend/src/app/components/ui/toaster.tsx b/Frontend/src/app/components/ui/toaster.tsx index a451808..dd88327 100644 --- a/Frontend/src/app/components/ui/toaster.tsx +++ b/Frontend/src/app/components/ui/toaster.tsx @@ -1,35 +1,43 @@ -"use client" +"use client"; import { - Toast, - ToastClose, - ToastDescription, - ToastProvider, - ToastTitle, - ToastViewport, -} from "@/app/components/ui/toast" -import { useToast } from "@/app/components/ui/use-toast" + Toast, + ToastClose, + ToastDescription, + ToastProvider, + ToastTitle, + ToastViewport, +} from "@/app/components/ui/toast"; +import { useToast } from "@/app/components/ui/use-toast"; export function Toaster() { - const { toasts } = useToast() + const { toasts } = useToast(); - return ( - - {toasts.map(function ({ id, title, description, action, ...props }) { - return ( - -
- {title && {title}} - {description && ( - {description} - )} -
- {action} - -
- ) - })} - -
- ) + return ( + + {toasts.map(function ({ + id, + title, + description, + action, + ...props + }) { + return ( + +
+ {title && {title}} + {description && ( + + {description} + + )} +
+ {action} + +
+ ); + })} + +
+ ); } diff --git a/Frontend/src/app/components/ui/tooltip.tsx b/Frontend/src/app/components/ui/tooltip.tsx index 1a6c803..7853f95 100644 --- a/Frontend/src/app/components/ui/tooltip.tsx +++ b/Frontend/src/app/components/ui/tooltip.tsx @@ -1,30 +1,30 @@ -"use client" +"use client"; -import * as React from "react" -import * as TooltipPrimitive from "@radix-ui/react-tooltip" +import * as React from "react"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; -import { cn } from "@/app/lib/utils" +import { cn } from "@/app/lib/utils"; -const TooltipProvider = TooltipPrimitive.Provider +const TooltipProvider = TooltipPrimitive.Provider; -const Tooltip = TooltipPrimitive.Root +const Tooltip = TooltipPrimitive.Root; -const TooltipTrigger = TooltipPrimitive.Trigger +const TooltipTrigger = TooltipPrimitive.Trigger; const TooltipContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( - -)) -TooltipContent.displayName = TooltipPrimitive.Content.displayName + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/Frontend/src/app/components/ui/use-toast.ts b/Frontend/src/app/components/ui/use-toast.ts index b21985b..63b356e 100644 --- a/Frontend/src/app/components/ui/use-toast.ts +++ b/Frontend/src/app/components/ui/use-toast.ts @@ -1,194 +1,192 @@ -"use client" +"use client"; // Inspired by react-hot-toast library -import * as React from "react" +import * as React from "react"; -import type { - ToastActionElement, - ToastProps, -} from "@/app/components/ui/toast" +import type { ToastActionElement, ToastProps } from "@/app/components/ui/toast"; -const TOAST_LIMIT = 1 -const TOAST_REMOVE_DELAY = 1000000 +const TOAST_LIMIT = 1; +const TOAST_REMOVE_DELAY = 1000000; type ToasterToast = ToastProps & { - id: string - title?: React.ReactNode - description?: React.ReactNode - action?: ToastActionElement -} + id: string; + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; +}; const actionTypes = { - ADD_TOAST: "ADD_TOAST", - UPDATE_TOAST: "UPDATE_TOAST", - DISMISS_TOAST: "DISMISS_TOAST", - REMOVE_TOAST: "REMOVE_TOAST", -} as const + ADD_TOAST: "ADD_TOAST", + UPDATE_TOAST: "UPDATE_TOAST", + DISMISS_TOAST: "DISMISS_TOAST", + REMOVE_TOAST: "REMOVE_TOAST", +} as const; -let count = 0 +let count = 0; function genId() { - count = (count + 1) % Number.MAX_SAFE_INTEGER - return count.toString() + count = (count + 1) % Number.MAX_SAFE_INTEGER; + return count.toString(); } -type ActionType = typeof actionTypes +type ActionType = typeof actionTypes; type Action = - | { - type: ActionType["ADD_TOAST"] - toast: ToasterToast - } - | { - type: ActionType["UPDATE_TOAST"] - toast: Partial - } - | { - type: ActionType["DISMISS_TOAST"] - toastId?: ToasterToast["id"] - } - | { - type: ActionType["REMOVE_TOAST"] - toastId?: ToasterToast["id"] - } + | { + type: ActionType["ADD_TOAST"]; + toast: ToasterToast; + } + | { + type: ActionType["UPDATE_TOAST"]; + toast: Partial; + } + | { + type: ActionType["DISMISS_TOAST"]; + toastId?: ToasterToast["id"]; + } + | { + type: ActionType["REMOVE_TOAST"]; + toastId?: ToasterToast["id"]; + }; interface State { - toasts: ToasterToast[] + toasts: ToasterToast[]; } -const toastTimeouts = new Map>() +const toastTimeouts = new Map>(); const addToRemoveQueue = (toastId: string) => { - if (toastTimeouts.has(toastId)) { - return - } + if (toastTimeouts.has(toastId)) { + return; + } - const timeout = setTimeout(() => { - toastTimeouts.delete(toastId) - dispatch({ - type: "REMOVE_TOAST", - toastId: toastId, - }) - }, TOAST_REMOVE_DELAY) + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId); + dispatch({ + type: "REMOVE_TOAST", + toastId: toastId, + }); + }, TOAST_REMOVE_DELAY); - toastTimeouts.set(toastId, timeout) -} + toastTimeouts.set(toastId, timeout); +}; export const reducer = (state: State, action: Action): State => { - switch (action.type) { - case "ADD_TOAST": - return { - ...state, - toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - } + switch (action.type) { + case "ADD_TOAST": + return { + ...state, + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), + }; - case "UPDATE_TOAST": - return { - ...state, - toasts: state.toasts.map((t) => - t.id === action.toast.id ? { ...t, ...action.toast } : t - ), - } + case "UPDATE_TOAST": + return { + ...state, + toasts: state.toasts.map((t) => + t.id === action.toast.id ? { ...t, ...action.toast } : t + ), + }; - case "DISMISS_TOAST": { - const { toastId } = action + case "DISMISS_TOAST": { + const { toastId } = action; - // ! Side effects ! - This could be extracted into a dismissToast() action, - // but I'll keep it here for simplicity - if (toastId) { - addToRemoveQueue(toastId) - } else { - state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id) - }) - } + // ! Side effects ! - This could be extracted into a dismissToast() action, + // but I'll keep it here for simplicity + if (toastId) { + addToRemoveQueue(toastId); + } else { + state.toasts.forEach((toast) => { + addToRemoveQueue(toast.id); + }); + } - return { - ...state, - toasts: state.toasts.map((t) => - t.id === toastId || toastId === undefined - ? { - ...t, - open: false, - } - : t - ), - } - } - case "REMOVE_TOAST": - if (action.toastId === undefined) { - return { - ...state, - toasts: [], + return { + ...state, + toasts: state.toasts.map((t) => + t.id === toastId || toastId === undefined + ? { + ...t, + open: false, + } + : t + ), + }; } - } - return { - ...state, - toasts: state.toasts.filter((t) => t.id !== action.toastId), - } - } -} + case "REMOVE_TOAST": + if (action.toastId === undefined) { + return { + ...state, + toasts: [], + }; + } + return { + ...state, + toasts: state.toasts.filter((t) => t.id !== action.toastId), + }; + } +}; -const listeners: Array<(state: State) => void> = [] +const listeners: Array<(state: State) => void> = []; -let memoryState: State = { toasts: [] } +let memoryState: State = { toasts: [] }; function dispatch(action: Action) { - memoryState = reducer(memoryState, action) - listeners.forEach((listener) => { - listener(memoryState) - }) + memoryState = reducer(memoryState, action); + listeners.forEach((listener) => { + listener(memoryState); + }); } -type Toast = Omit +type Toast = Omit; function toast({ ...props }: Toast) { - const id = genId() + const id = genId(); + + const update = (props: ToasterToast) => + dispatch({ + type: "UPDATE_TOAST", + toast: { ...props, id }, + }); + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); - const update = (props: ToasterToast) => dispatch({ - type: "UPDATE_TOAST", - toast: { ...props, id }, - }) - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + type: "ADD_TOAST", + toast: { + ...props, + id, + open: true, + onOpenChange: (open) => { + if (!open) dismiss(); + }, + }, + }); - dispatch({ - type: "ADD_TOAST", - toast: { - ...props, - id, - open: true, - onOpenChange: (open) => { - if (!open) dismiss() - }, - }, - }) - - return { - id: id, - dismiss, - update, - } + return { + id: id, + dismiss, + update, + }; } function useToast() { - const [state, setState] = React.useState(memoryState) + const [state, setState] = React.useState(memoryState); - React.useEffect(() => { - listeners.push(setState) - return () => { - const index = listeners.indexOf(setState) - if (index > -1) { - listeners.splice(index, 1) - } - } - }, [state]) + React.useEffect(() => { + listeners.push(setState); + return () => { + const index = listeners.indexOf(setState); + if (index > -1) { + listeners.splice(index, 1); + } + }; + }, [state]); - return { - ...state, - toast, - dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), - } + return { + ...state, + toast, + dismiss: (toastId?: string) => + dispatch({ type: "DISMISS_TOAST", toastId }), + }; } -export { useToast, toast } +export { useToast, toast }; diff --git a/Frontend/src/app/config.ts b/Frontend/src/app/config.ts index c282611..2a4af07 100644 --- a/Frontend/src/app/config.ts +++ b/Frontend/src/app/config.ts @@ -2,4 +2,5 @@ * The configuration for this app. */ import config from "@/configJson"; + export default config; diff --git a/Frontend/src/app/layout.tsx b/Frontend/src/app/layout.tsx index 44ab237..c258a06 100644 --- a/Frontend/src/app/layout.tsx +++ b/Frontend/src/app/layout.tsx @@ -1,14 +1,15 @@ +import Footer from "@/components/footer"; import Navbar from "@/components/navbar"; -import { Toaster } from "@/components/ui/sonner" +import { Toaster } from "@/components/ui/sonner"; import { TooltipProvider } from "@/components/ui/tooltip"; import config from "@/config"; import { notoSans } from "@/font/fonts"; import { cn } from "@/lib/utils"; -import ThemeProvider from "@/provider/theme-provider"; import type { Metadata, Viewport } from "next"; import PlausibleProvider from "next-plausible"; import { ReactElement, ReactNode } from "react"; import "./globals.css"; +import ThemeProvider from "@/provider/theme-provider"; /** * Site metadata & viewport. @@ -44,7 +45,7 @@ const RootLayout = ({ {children} - {/*