This commit is contained in:
parent
27b4eb38ea
commit
87edf0e3e3
1
package-lock.json
generated
1
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"@radix-ui/react-popover": "^1.0.7",
|
"@radix-ui/react-popover": "^1.0.7",
|
||||||
"@radix-ui/react-separator": "^1.0.3",
|
"@radix-ui/react-separator": "^1.0.3",
|
||||||
"@radix-ui/react-slider": "^1.1.2",
|
"@radix-ui/react-slider": "^1.1.2",
|
||||||
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
"@radix-ui/react-tooltip": "^1.0.7",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"@sentry/nextjs": "^7.74.1",
|
"@sentry/nextjs": "^7.74.1",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"@radix-ui/react-popover": "^1.0.7",
|
"@radix-ui/react-popover": "^1.0.7",
|
||||||
"@radix-ui/react-separator": "^1.0.3",
|
"@radix-ui/react-separator": "^1.0.3",
|
||||||
"@radix-ui/react-slider": "^1.1.2",
|
"@radix-ui/react-slider": "^1.1.2",
|
||||||
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
"@radix-ui/react-tooltip": "^1.0.7",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"@sentry/nextjs": "^7.74.1",
|
"@sentry/nextjs": "^7.74.1",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
|
@ -57,7 +57,10 @@ export default async function Analytics() {
|
|||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Container>
|
<Container>
|
||||||
<Card className="flex flex-col items-center justify-center">
|
<Card
|
||||||
|
outerClassName="mt-2"
|
||||||
|
className="flex flex-col items-center justify-center"
|
||||||
|
>
|
||||||
<h1 className="text-center text-3xl font-bold">Analytics</h1>
|
<h1 className="text-center text-3xl font-bold">Analytics</h1>
|
||||||
<p className="text-center">
|
<p className="text-center">
|
||||||
Scoresaber metrics and statistics over the last 30 days.
|
Scoresaber metrics and statistics over the last 30 days.
|
||||||
|
@ -21,7 +21,7 @@ export default async function Analytics() {
|
|||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Container>
|
<Container>
|
||||||
<Card>
|
<Card outerClassName="mt-2">
|
||||||
<h1 className="mb-1 text-3xl font-bold">Credits</h1>
|
<h1 className="mb-1 text-3xl font-bold">Credits</h1>
|
||||||
<p className="mb-8 text-gray-300">
|
<p className="mb-8 text-gray-300">
|
||||||
This website is made possible because of the following:
|
This website is made possible because of the following:
|
||||||
|
@ -5,64 +5,47 @@
|
|||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 224 71.4% 4.1%;
|
--foreground: 240 10% 3.9%;
|
||||||
|
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
--card-foreground: 224 71.4% 4.1%;
|
--card-foreground: 240 10% 3.9%;
|
||||||
|
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
--popover-foreground: 224 71.4% 4.1%;
|
--popover-foreground: 240 10% 3.9%;
|
||||||
|
--primary: 262.1 83.3% 57.8%;
|
||||||
--primary: 220.9 39.3% 11%;
|
--primary-foreground: 355.7 100% 97.3%;
|
||||||
--primary-foreground: 210 20% 98%;
|
--secondary: 240 4.8% 95.9%;
|
||||||
|
--secondary-foreground: 240 5.9% 10%;
|
||||||
--secondary: 220 14.3% 95.9%;
|
--muted: 240 4.8% 95.9%;
|
||||||
--secondary-foreground: 220.9 39.3% 11%;
|
--muted-foreground: 240 3.8% 46.1%;
|
||||||
|
--accent: 240 4.8% 95.9%;
|
||||||
--muted: 220 14.3% 95.9%;
|
--accent-foreground: 240 5.9% 10%;
|
||||||
--muted-foreground: 220 8.9% 46.1%;
|
|
||||||
|
|
||||||
--accent: 220 14.3% 95.9%;
|
|
||||||
--accent-foreground: 220.9 39.3% 11%;
|
|
||||||
|
|
||||||
--destructive: 0 84.2% 60.2%;
|
--destructive: 0 84.2% 60.2%;
|
||||||
--destructive-foreground: 210 20% 98%;
|
--destructive-foreground: 0 0% 98%;
|
||||||
|
--border: 240 5.9% 90%;
|
||||||
--border: 220 13% 91%;
|
--input: 240 5.9% 90%;
|
||||||
--input: 220 13% 91%;
|
--ring: 262.1 83.3% 57.8%;
|
||||||
--ring: 224 71.4% 4.1%;
|
|
||||||
|
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--background: 224 71.4% 4.1%;
|
--background: 20 14.3% 4.1%;
|
||||||
--foreground: 210 20% 98%;
|
--foreground: 0 0% 95%;
|
||||||
|
--card: 24 9.8% 10%;
|
||||||
--card: 224 71.4% 4.1%;
|
--card-foreground: 0 0% 95%;
|
||||||
--card-foreground: 210 20% 98%;
|
--popover: 0 0% 9%;
|
||||||
|
--popover-foreground: 0 0% 95%;
|
||||||
--popover: 224 71.4% 4.1%;
|
--primary: 262.1 83.3% 57.8%;
|
||||||
--popover-foreground: 210 20% 98%;
|
--primary-foreground: 144.9 80.4% 10%;
|
||||||
|
--secondary: 240 3.7% 15.9%;
|
||||||
--primary: 210 20% 98%;
|
--secondary-foreground: 0 0% 98%;
|
||||||
--primary-foreground: 220.9 39.3% 11%;
|
--muted: 0 0% 15%;
|
||||||
|
--muted-foreground: 240 5% 64.9%;
|
||||||
--secondary: 215 27.9% 16.9%;
|
--accent: 12 6.5% 15.1%;
|
||||||
--secondary-foreground: 210 20% 98%;
|
--accent-foreground: 0 0% 98%;
|
||||||
|
|
||||||
--muted: 215 27.9% 16.9%;
|
|
||||||
--muted-foreground: 217.9 10.6% 64.9%;
|
|
||||||
|
|
||||||
--accent: 215 27.9% 16.9%;
|
|
||||||
--accent-foreground: 210 20% 98%;
|
|
||||||
|
|
||||||
--destructive: 0 62.8% 30.6%;
|
--destructive: 0 62.8% 30.6%;
|
||||||
--destructive-foreground: 210 20% 98%;
|
--destructive-foreground: 0 85.7% 97.3%;
|
||||||
|
--border: 240 3.7% 15.9%;
|
||||||
--border: 215 27.9% 16.9%;
|
--input: 240 3.7% 15.9%;
|
||||||
--input: 215 27.9% 16.9%;
|
--ring: 262.1 83.3% 57.8%;
|
||||||
--ring: 216 12.2% 83.9%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export default async function Analytics() {
|
|||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Container>
|
<Container>
|
||||||
<Card>
|
<Card outerClassName="mt-2">
|
||||||
<h1 className="mb-1 text-3xl font-bold">Privacy</h1>
|
<h1 className="mb-1 text-3xl font-bold">Privacy</h1>
|
||||||
<p className="mb-8 text-gray-300">
|
<p className="mb-8 text-gray-300">
|
||||||
This site does not collect personal data. All of the data stored is
|
This site does not collect personal data. All of the data stored is
|
||||||
|
@ -13,7 +13,10 @@ export default function Home() {
|
|||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Container>
|
<Container>
|
||||||
<Card className="flex flex-col items-center justify-center">
|
<Card
|
||||||
|
outerClassName="mt-2"
|
||||||
|
className="flex flex-col items-center justify-center"
|
||||||
|
>
|
||||||
<UnknownAvatar />
|
<UnknownAvatar />
|
||||||
|
|
||||||
<p className="text-xl">Stranger</p>
|
<p className="text-xl">Stranger</p>
|
||||||
|
@ -3,13 +3,20 @@ import clsx from "clsx";
|
|||||||
|
|
||||||
type CardProps = {
|
type CardProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
outerClassName?: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Card({ className, children }: CardProps) {
|
export default function Card({
|
||||||
|
className,
|
||||||
|
outerClassName,
|
||||||
|
children,
|
||||||
|
}: CardProps) {
|
||||||
return (
|
return (
|
||||||
<CardBase className="mt-2">
|
<CardBase className={outerClassName}>
|
||||||
<CardContent className={clsx(className, "mt-2")}>{children}</CardContent>
|
<CardContent className={clsx(className, "pb-4 pt-2")}>
|
||||||
|
{children}
|
||||||
|
</CardContent>
|
||||||
</CardBase>
|
</CardBase>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ssrSettings } from "@/ssrSettings";
|
import { ssrSettings } from "@/ssrSettings";
|
||||||
import { isProduction } from "@/utils/utils";
|
import { isProduction } from "@/utils/utils";
|
||||||
|
import Card from "./Card";
|
||||||
|
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{
|
{
|
||||||
@ -19,8 +20,8 @@ const buildId = process.env.NEXT_PUBLIC_BUILD_ID
|
|||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
<footer>
|
<footer className="p-3">
|
||||||
<div className="bg-background m-3 flex flex-col items-center justify-center gap-1 rounded-md p-3">
|
<Card className="mb-2 mt-2 flex flex-col items-center justify-center gap-1 !pb-1 !pt-0">
|
||||||
<div className="flex flex-row gap-3">
|
<div className="flex flex-row gap-3">
|
||||||
<a
|
<a
|
||||||
className="transform-gpu transition-all hover:text-blue-500"
|
className="transform-gpu transition-all hover:text-blue-500"
|
||||||
@ -48,7 +49,7 @@ export default function Footer() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-sm text-gray-400">Build ID: {buildId}</div>
|
<div className="text-sm text-gray-400">Build ID: {buildId}</div>
|
||||||
</div>
|
</Card>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ export default function GlobalRanking({ page, country }: GlobalRankingProps) {
|
|||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Container>
|
<Container>
|
||||||
<Card className="mt-2">
|
<Card outerClassName="mt-2" className="mt-2">
|
||||||
{pageInfo.loading ? (
|
{pageInfo.loading ? (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
|
@ -9,24 +9,24 @@ import {
|
|||||||
UserIcon,
|
UserIcon,
|
||||||
} from "@heroicons/react/20/solid";
|
} from "@heroicons/react/20/solid";
|
||||||
import { GlobeAltIcon } from "@heroicons/react/24/outline";
|
import { GlobeAltIcon } from "@heroicons/react/24/outline";
|
||||||
|
import Link from "next/link";
|
||||||
import Avatar from "./Avatar";
|
import Avatar from "./Avatar";
|
||||||
import Button from "./Button";
|
|
||||||
import { Card } from "./ui/card";
|
import { Card } from "./ui/card";
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
||||||
|
|
||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
text: string;
|
text: string;
|
||||||
icon?: JSX.Element;
|
icon?: JSX.Element;
|
||||||
href?: string;
|
href?: string;
|
||||||
ariaLabel: string;
|
ariaLabel: string;
|
||||||
children?: React.ReactNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function NavbarButton({ text, icon, href, ariaLabel, children }: ButtonProps) {
|
function NavbarButton({ text, icon, href, ariaLabel }: ButtonProps) {
|
||||||
return (
|
return (
|
||||||
<div className="group">
|
<div className="group">
|
||||||
<a
|
<a
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
className="flex h-full w-fit transform-gpu items-center justify-center gap-1 rounded-md p-3 transition-all hover:cursor-pointer hover:bg-blue-500"
|
className="flex h-full w-fit transform-gpu items-center justify-center gap-1 rounded-md p-[10px] transition-all hover:cursor-pointer hover:bg-blue-500"
|
||||||
href={href}
|
href={href}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
@ -34,12 +34,6 @@ function NavbarButton({ text, icon, href, ariaLabel, children }: ButtonProps) {
|
|||||||
<p className="hidden md:block">{text}</p>
|
<p className="hidden md:block">{text}</p>
|
||||||
</>
|
</>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{children && (
|
|
||||||
<div className="absolute z-20 hidden divide-y rounded-md bg-gray-600 opacity-[0.98] shadow-sm group-hover:flex">
|
|
||||||
<div className="p-2">{children}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -65,42 +59,42 @@ export default function Navbar() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<NavbarButton
|
<Popover>
|
||||||
ariaLabel="View your friends"
|
<PopoverTrigger>
|
||||||
text="Friends"
|
<NavbarButton
|
||||||
icon={<UserIcon height={20} width={20} />}
|
ariaLabel="View your friends"
|
||||||
href="/search"
|
text="Friends"
|
||||||
>
|
icon={<UserIcon height={20} width={20} />}
|
||||||
{settingsStore?.friends.length == 0 ? (
|
/>
|
||||||
<p className="text-sm font-bold">No friends, add someone!</p>
|
</PopoverTrigger>
|
||||||
) : (
|
<PopoverContent className="p-2">
|
||||||
settingsStore?.friends.map((friend) => {
|
{settingsStore?.friends.length == 0 ? (
|
||||||
return (
|
<p className="text-sm font-bold">No friends, add someone!</p>
|
||||||
<Button
|
) : (
|
||||||
key={friend.id}
|
settingsStore?.friends.map((friend) => {
|
||||||
className="mt-2"
|
return (
|
||||||
color="bg-gray-500"
|
<Link
|
||||||
text={friend.name}
|
key={friend.id}
|
||||||
url={`/player/${friend.id}/top/1`}
|
href={`/player/${friend.id}/top/1`}
|
||||||
icon={
|
className="w-full"
|
||||||
<Avatar
|
>
|
||||||
url={friend.profilePicture}
|
<div className="flex transform-gpu gap-2 rounded-md p-2 text-left transition-all hover:bg-background">
|
||||||
label={`${friend.name}'s avatar`}
|
<Avatar
|
||||||
size={20}
|
url={friend.profilePicture}
|
||||||
/>
|
label="Friend avatar"
|
||||||
}
|
size={48}
|
||||||
/>
|
/>
|
||||||
);
|
<div>
|
||||||
})
|
<p className="text-sm text-gray-400">#{friend.rank}</p>
|
||||||
)}
|
<p>{friend.name}</p>
|
||||||
|
</div>
|
||||||
<Button
|
</div>
|
||||||
className="mt-2"
|
</Link>
|
||||||
text="Search"
|
);
|
||||||
url="/search"
|
})
|
||||||
icon={<MagnifyingGlassIcon height={20} width={20} />}
|
)}
|
||||||
/>
|
</PopoverContent>
|
||||||
</NavbarButton>
|
</Popover>
|
||||||
<NavbarButton
|
<NavbarButton
|
||||||
ariaLabel="View the global ranking"
|
ariaLabel="View the global ranking"
|
||||||
text="Ranking"
|
text="Ranking"
|
||||||
|
@ -111,7 +111,7 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) {
|
|||||||
const scoreStats = playerData.scoreStats;
|
const scoreStats = playerData.scoreStats;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="mt-2">
|
<Card outerClassName="mt-2" className="mt-2">
|
||||||
{/* Player Info */}
|
{/* Player Info */}
|
||||||
<div className="flex flex-col items-center gap-3 md:flex-row md:items-start">
|
<div className="flex flex-col items-center gap-3 md:flex-row md:items-start">
|
||||||
<div className="min-w-fit">
|
<div className="min-w-fit">
|
||||||
|
@ -67,7 +67,7 @@ export default function PlayerPage({ id, sort, page }: PlayerPageProps) {
|
|||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Container>
|
<Container>
|
||||||
<Card className="mt-2">
|
<Card outerClassName="mt-2" className="mt-2">
|
||||||
<div className="p-3 text-center">
|
<div className="p-3 text-center">
|
||||||
<div role="status">
|
<div role="status">
|
||||||
<div className="flex flex-col items-center justify-center gap-2">
|
<div className="flex flex-col items-center justify-center gap-2">
|
||||||
@ -90,7 +90,7 @@ export default function PlayerPage({ id, sort, page }: PlayerPageProps) {
|
|||||||
<Container>
|
<Container>
|
||||||
<PlayerInfo playerData={playerData} />
|
<PlayerInfo playerData={playerData} />
|
||||||
{/* Chart */}
|
{/* Chart */}
|
||||||
<Card className="mt-2">
|
<Card outerClassName="mt-2">
|
||||||
{/* Badges */}
|
{/* Badges */}
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -97,9 +97,9 @@ export default function Scores({ playerData, page, sortType }: ScoresProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="mt-2 w-full items-center md:flex-col">
|
<Card outerClassName="mt-2" className="w-full items-center md:flex-col">
|
||||||
{/* Sort */}
|
{/* Sort */}
|
||||||
<div className="m-4 w-full text-sm">
|
<div className="mb-2 mt-1 w-full text-sm">
|
||||||
<div className="flex justify-center gap-2">
|
<div className="flex justify-center gap-2">
|
||||||
{Object.values(SortTypes).map((sortType) => {
|
{Object.values(SortTypes).map((sortType) => {
|
||||||
return (
|
return (
|
||||||
|
56
src/components/ui/button.tsx
Normal file
56
src/components/ui/button.tsx
Normal file
@ -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 "@/utils/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<HTMLButtonElement>,
|
||||||
|
VariantProps<typeof buttonVariants> {
|
||||||
|
asChild?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
|
const Comp = asChild ? Slot : "button"
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Button.displayName = "Button"
|
||||||
|
|
||||||
|
export { Button, buttonVariants }
|
@ -22,7 +22,7 @@ module.exports = {
|
|||||||
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
|
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
|
||||||
},
|
},
|
||||||
backgroundColor: {
|
backgroundColor: {
|
||||||
"pp-blue": "#5763c9",
|
"pp-blue": "hsl(var(--primary))",
|
||||||
},
|
},
|
||||||
textColor: {
|
textColor: {
|
||||||
"pp-blue": "#9fa8f3",
|
"pp-blue": "#9fa8f3",
|
||||||
|
Loading…
Reference in New Issue
Block a user