diff --git a/src/app/globals.css b/src/app/globals.css index 607cc9a..8dc99a6 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -64,6 +64,7 @@ body { @apply block; } +/* Tooltips */ [data-tooltip] { @apply relative z-10; } @@ -81,7 +82,24 @@ body { @apply opacity-100 scale-100; } -/* Scrollbar */ +/* Fallback Tooltips */ +[data-tooltip-span] { + @apply relative; +} + +[data-tooltip-span] > .tooltip { + @apply absolute left-1/2 top-full mt-2 px-2 py-1 bg-orange-400 border border-orange-400 rounded-md text-sm text-white whitespace-nowrap select-none pointer-events-none shadow-md opacity-0 scale-75 transition-all duration-200 ease-out origin-top -translate-x-1/2 z-[999999]; +} + +[data-tooltip-span] > .tooltip::before { + @apply content-[''] absolute left-1/2 -translate-x-1/2 -top-2 border-4 border-transparent border-b-orange-400; +} + +[data-tooltip-span]:hover > .tooltip { + @apply opacity-100 scale-100; +} + +/* Scrollbars */ /* Firefox */ * { scrollbar-color: #ff8903 transparent; diff --git a/src/app/mii/[id]/page.tsx b/src/app/mii/[id]/page.tsx index 28bdfef..1cfd177 100644 --- a/src/app/mii/[id]/page.tsx +++ b/src/app/mii/[id]/page.tsx @@ -149,8 +149,59 @@ export default async function MiiPage({ params }: Props) { )} + {/* Mii Platform */} +
+
+ Platform +
+
+ +
+
+ {mii.platform === "THREE_DS" ? "3DS" : "Switch"} +
+ +
+ +
+ +
+ +
+
+ {/* Mii Gender */} -
+
+
+ Gender +
+
+ +
+
+ {mii.gender === "MALE" ? "Male" : "Female"} +
+
+ rawTags + ? rawTags + .split(",") + .map((tag) => tag.trim()) + .filter((tag) => tag.length > 0) + : [], + [rawTags] + ); + + const [filterCount, setFilterCount] = useState(tags.length); + + // Filter menu button handler + const handleClick = () => { + if (!isOpen) { + setIsOpen(true); + // slight delay to trigger animation + setTimeout(() => setIsVisible(true), 10); + } else { + setIsVisible(false); + setTimeout(() => { + setIsOpen(false); + }, 200); + } + }; + + // Count all active filters + useEffect(() => { + let count = tags.length; + if (platform) count++; + if (gender) count++; + + setFilterCount(count); + }, [tags, platform, gender]); + + return ( +
+ + + {isOpen && ( +
+ {/* Arrow */} +
+ + + +
+
+ Platform +
+
+ + +
+
+ Gender +
+
+ +
+ )} +
+ ); +} diff --git a/src/components/mii-list/gender-select.tsx b/src/components/mii-list/gender-select.tsx index 25997cf..0b7eb56 100644 --- a/src/components/mii-list/gender-select.tsx +++ b/src/components/mii-list/gender-select.tsx @@ -29,24 +29,28 @@ export default function GenderSelect() { }; return ( -
+
diff --git a/src/components/mii-list/index.tsx b/src/components/mii-list/index.tsx index 9a98733..7c363a9 100644 --- a/src/components/mii-list/index.tsx +++ b/src/components/mii-list/index.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; -import { MiiGender, Prisma } from "@prisma/client"; +import { MiiGender, MiiPlatform, Prisma } from "@prisma/client"; import { Icon } from "@iconify/react"; import { z } from "zod"; @@ -10,8 +10,7 @@ import { querySchema } from "@/lib/schemas"; import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; -import GenderSelect from "./gender-select"; -import TagFilter from "./tag-filter"; +import FilterMenu from "./filter-menu"; import SortSelect from "./sort-select"; import Carousel from "../carousel"; import LikeButton from "../like-button"; @@ -36,6 +35,7 @@ const searchSchema = z.object({ .map((tag) => tag.trim()) .filter((tag) => tag.length > 0) ), + platform: z.enum(MiiPlatform, { error: "Platform must be either 'THREE_DS', or 'SWITCH'" }).optional(), gender: z.enum(MiiGender, { error: "Gender must be either 'MALE', or 'FEMALE'" }).optional(), // todo: incorporate tagsSchema // Pages @@ -60,7 +60,7 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro const parsed = searchSchema.safeParse(searchParams); if (!parsed.success) return

{parsed.error.issues[0].message}

; - const { q: query, sort, tags, gender, page = 1, limit = 24, seed } = parsed.data; + const { q: query, sort, tags, platform, gender, page = 1, limit = 24, seed } = parsed.data; // My Likes page let miiIdsLiked: number[] | undefined = undefined; @@ -82,6 +82,8 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro }), // Tag filtering ...(tags && tags.length > 0 && { tags: { hasEvery: tags } }), + // Platform + ...(platform && { platform: { equals: platform } }), // Gender ...(gender && { gender: { equals: gender } }), // Profiles @@ -99,6 +101,7 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro }, }, }), + platform: true, name: true, imageCount: true, tags: true, @@ -201,9 +204,8 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro )}
-
- - +
+
diff --git a/src/components/mii-list/platform-select.tsx b/src/components/mii-list/platform-select.tsx new file mode 100644 index 0000000..8915d8e --- /dev/null +++ b/src/components/mii-list/platform-select.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { useRouter, useSearchParams } from "next/navigation"; +import { useState, useTransition } from "react"; +import { Icon } from "@iconify/react"; +import { MiiPlatform } from "@prisma/client"; + +export default function PlatformSelect() { + const router = useRouter(); + const searchParams = useSearchParams(); + const [, startTransition] = useTransition(); + + const [selected, setSelected] = useState((searchParams.get("platform") as MiiPlatform) ?? null); + + const handleClick = (platform: MiiPlatform) => { + const filter = selected === platform ? null : platform; + setSelected(filter); + + const params = new URLSearchParams(searchParams); + if (filter) { + params.set("platform", filter); + } else { + params.delete("platform"); + } + + startTransition(() => { + router.push(`?${params.toString()}`); + }); + }; + + return ( +
+ + + +
+ ); +}