Compare commits

..

2 commits

Author SHA1 Message Date
Landon & Emma
a4f92f1605
Merge 282a1d3938 into af7f1380bc 2026-04-24 14:42:41 -04:00
Landon & Emma
282a1d3938 Fixed theme issues 2026-04-24 14:42:30 -04:00
7 changed files with 94 additions and 166 deletions

View file

@ -43,14 +43,14 @@ export default function Header() {
<Link <Link
to={`${import.meta.env.VITE_API_URL}/random`} to={`${import.meta.env.VITE_API_URL}/random`}
aria-label="Go to Random Link" aria-label="Go to Random Link"
className="pill button p-0! h-full aspect-square" className="pill button p-0! h-full aspect-square dark:bg-orange-300 dark:border-orange-400"
data-tooltip="Go to a Random Mii" data-tooltip="Go to a Random Mii"
> >
<Icon icon="mdi:dice-3" fontSize={28} /> <Icon icon="mdi:dice-3" fontSize={28} />
</Link> </Link>
</li> </li>
<li> <li>
<Link to={"/submit"} className="pill button h-full"> <Link to={"/submit"} className="pill button h-full dark:bg-orange-300 dark:border-orange-400">
Submit Submit
</Link> </Link>
</li> </li>
@ -60,7 +60,7 @@ export default function Header() {
<ThemeToggle size="md" /> <ThemeToggle size="md" />
</li> </li>
<li> <li>
<Link to={"/login"} className="pill button h-full"> <Link to={"/login"} className="pill button h-full dark:bg-orange-300 dark:border-orange-400">
Login Login
</Link> </Link>
</li> </li>
@ -71,7 +71,7 @@ export default function Header() {
<Link <Link
to={`/profile/${$session?.user?.id}`} to={`/profile/${$session?.user?.id}`}
aria-label="Go to profile" aria-label="Go to profile"
className="pill button gap-2! p-0! h-full max-w-64" className="pill button gap-2! p-0! h-full max-w-64 dark:bg-orange-300 dark:border-orange-400"
data-tooltip="Your Profile" data-tooltip="Your Profile"
> >
<img <img
@ -95,7 +95,7 @@ export default function Header() {
<Link <Link
to={`${import.meta.env.VITE_API_URL}/api/auth/signout`} to={`${import.meta.env.VITE_API_URL}/api/auth/signout`}
aria-label="Log Out" aria-label="Log Out"
className="pill button p-2! aspect-square h-full" className="pill button p-2! aspect-square h-full dark:bg-orange-300 dark:border-orange-400"
data-tooltip="Log Out" data-tooltip="Log Out"
> >
<Icon icon="ic:round-logout" fontSize={24} /> <Icon icon="ic:round-logout" fontSize={24} />

View file

@ -1,5 +1,4 @@
import { useState, useEffect } from "react"; import { useState } from "react";
import { useStore } from "@nanostores/react";
import { userNameSchema } from "@tomodachi-share/shared/schemas"; import { userNameSchema } from "@tomodachi-share/shared/schemas";
@ -8,8 +7,6 @@ import SubmitDialogButton from "./submit-dialog-button";
import DeleteAccount from "./delete-account"; import DeleteAccount from "./delete-account";
import z from "zod"; import z from "zod";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { session } from "../../session";
import { type Theme, applyTheme } from "../../lib/theme";
interface Props { interface Props {
currentDescription: string | null | undefined; currentDescription: string | null | undefined;
@ -17,22 +14,12 @@ interface Props {
export default function ProfileSettings({ currentDescription }: Props) { export default function ProfileSettings({ currentDescription }: Props) {
const navigate = useNavigate(); const navigate = useNavigate();
const $session = useStore(session);
const [description, setDescription] = useState(currentDescription); const [description, setDescription] = useState(currentDescription);
const [name, setName] = useState(""); const [name, setName] = useState("");
const [selectedTheme, setSelectedTheme] = useState<Theme>("SYSTEM");
const [themeSaveError, setThemeSaveError] = useState<string | undefined>(undefined);
const [descriptionChangeError, setDescriptionChangeError] = useState<string | undefined>(undefined); const [descriptionChangeError, setDescriptionChangeError] = useState<string | undefined>(undefined);
const [nameChangeError, setNameChangeError] = useState<string | undefined>(undefined); const [nameChangeError, setNameChangeError] = useState<string | undefined>(undefined);
// Initialize theme from session when it loads
useEffect(() => {
if ($session?.user?.theme) {
setSelectedTheme($session.user.theme);
}
}, [$session?.user?.theme]);
const handleSubmitDescriptionChange = async (close: () => void) => { const handleSubmitDescriptionChange = async (close: () => void) => {
const parsed = z.string().trim().max(256).safeParse(description); const parsed = z.string().trim().max(256).safeParse(description);
if (!parsed.success) { if (!parsed.success) {
@ -81,31 +68,11 @@ export default function ProfileSettings({ currentDescription }: Props) {
navigate(0); navigate(0);
}; };
const handleThemeSave = async (close: () => void) => {
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/auth/theme`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ theme: selectedTheme }),
credentials: "include",
});
if (!response.ok) {
const { error } = await response.json();
setThemeSaveError(error);
return;
}
// Apply the theme immediately
applyTheme(selectedTheme);
close();
navigate(0);
};
return ( return (
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-4 dark:bg-slate-900 dark:border-slate-700"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-4 dark:bg-slate-900 dark:border-slate-700">
<div> <div>
<h2 className="text-2xl font-bold dark:text-slate-100">Settings</h2> <h2 className="text-2xl font-bold dark:text-slate-100">Settings</h2>
<p className="text-sm text-zinc-500 dark:text-slate-400">Update your account info, username, and site-wide theme.</p> <p className="text-sm text-zinc-500 dark:text-slate-400">Update your account info and username.</p>
</div> </div>
{/* Separator */} {/* Separator */}
@ -172,39 +139,6 @@ export default function ProfileSettings({ currentDescription }: Props) {
</div> </div>
</div> </div>
{/* Separator - Personalization */}
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium my-1 dark:text-slate-400">
<hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Personalization</span>
<hr className="grow border-zinc-300 dark:border-slate-600" />
</div>
{/* Theme Selection */}
<div className="grid grid-cols-5 gap-4 max-lg:grid-cols-1">
<div className="col-span-3">
<label className="font-semibold dark:text-slate-100">Site Theme</label>
<p className="text-sm text-zinc-500 dark:text-slate-400">Choose your preferred color theme for the site</p>
</div>
<div className="flex justify-end gap-1 h-min col-span-2">
<select
className="pill input flex-1 rounded-xl! cursor-pointer"
value={selectedTheme}
onChange={(e) => setSelectedTheme(e.target.value as Theme)}
>
<option value="LIGHT">Light</option>
<option value="DARK">Dark</option>
<option value="SYSTEM">System</option>
</select>
<SubmitDialogButton
title="Confirm Theme Change"
description="Are you sure you want to save this theme preference to your account?"
error={themeSaveError}
onSubmit={handleThemeSave}
/>
</div>
</div>
{/* Separator - Danger Zone */} {/* Separator - Danger Zone */}
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium my-1 dark:text-slate-400"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium my-1 dark:text-slate-400">
<hr className="grow border-zinc-300 dark:border-slate-600" /> <hr className="grow border-zinc-300 dark:border-slate-600" />

View file

@ -31,14 +31,8 @@ export default function ThemeToggle({ size = "md", className = "" }: ThemeToggle
const getIcon = () => { const getIcon = () => {
if (theme === "DARK") return <Icon icon="mdi:moon" fontSize={iconSizes[size]} />; if (theme === "DARK") return <Icon icon="mdi:moon" fontSize={iconSizes[size]} />;
if (theme === "LIGHT") return <Icon icon="mdi:white-balance-sunny" fontSize={iconSizes[size]} />; if (theme === "LIGHT") return <Icon icon="mdi:white-balance-sunny" fontSize={iconSizes[size]} />;
// SYSTEM or undefined - show both // SYSTEM or undefined - show computer/monitor icon
return ( return <Icon icon="mdi:monitor" fontSize={iconSizes[size]} />;
<div className="flex items-center">
<Icon icon="mdi:white-balance-sunny" fontSize={iconSizes[size] - 4} />
<span className="mx-0.5 text-xs">/</span>
<Icon icon="mdi:moon" fontSize={iconSizes[size] - 4} />
</div>
);
}; };
const getTooltip = () => { const getTooltip = () => {

View file

@ -9,7 +9,7 @@ export default function IndexPage() {
<h1 className="sr-only"> <h1 className="sr-only">
{searchParams.get("tags") ? `Miis tagged with '${searchParams.get("tags")}' - TomodachiShare` : "TomodachiShare - index mii list"} {searchParams.get("tags") ? `Miis tagged with '${searchParams.get("tags")}' - TomodachiShare` : "TomodachiShare - index mii list"}
</h1> </h1>
<p className="text-center mb-4">We're currently going through some major code changes therefore some features won't work.</p> <p className="text-center mb-4 dark:text-slate-300">We're currently going through some major code changes therefore some features won't work.</p>
<MiiList /> <MiiList />
</> </>
); );

View file

@ -12,13 +12,13 @@ export default function LoginPage() {
return ( return (
<div className="grow flex items-center justify-center"> <div className="grow flex items-center justify-center">
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg px-10 py-12 max-w-md text-center"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg px-10 py-12 max-w-md text-center dark:bg-slate-800 dark:border-slate-600">
<h1 className="text-3xl font-bold mb-4">Welcome to TomodachiShare!</h1> <h1 className="text-3xl font-bold mb-4 dark:text-slate-100">Welcome to TomodachiShare!</h1>
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-8"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-8 dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Choose your login method</span> <span>Choose your login method</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
@ -48,13 +48,13 @@ export default function LoginPage() {
</Link> </Link>
</div> </div>
<p className="mt-8 text-xs text-zinc-400"> <p className="mt-8 text-xs text-zinc-400 dark:text-slate-500">
By signing up, you agree to the{" "} By signing up, you agree to the{" "}
<Link to="/terms-of-service" className="underline hover:text-zinc-600"> <Link to="/terms-of-service" className="underline hover:text-zinc-600 dark:hover:text-slate-300">
Terms of Service Terms of Service
</Link>{" "} </Link>{" "}
and{" "} and{" "}
<Link to="/privacy" className="underline hover:text-zinc-600"> <Link to="/privacy" className="underline hover:text-zinc-600 dark:hover:text-slate-300">
Privacy Policy Privacy Policy
</Link> </Link>
. .

View file

@ -92,7 +92,7 @@ export default function MiiPage() {
</div> </div>
)} )}
{mii.in_queue && ( {mii.in_queue && (
<div className="bg-zinc-50 border-2 border-zinc-400 rounded-2xl shadow-lg p-4 flex items-start gap-3 text-zinc-600"> <div className="bg-zinc-50 border-2 border-zinc-400 rounded-2xl shadow-lg p-4 flex items-start gap-3 text-zinc-600 dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300">
<Icon icon="material-symbols:timer" className="text-2xl shrink-0" /> <Icon icon="material-symbols:timer" className="text-2xl shrink-0" />
<p className="font-medium"> <p className="font-medium">
This Mii is waiting to be manually reviewed and is hidden from the main page. The review could take between a few hours and a few days. This Mii is waiting to be manually reviewed and is hidden from the main page. The review could take between a few hours and a few days.
@ -102,9 +102,9 @@ export default function MiiPage() {
</div> </div>
)} )}
<div className="relative grid grid-cols-3 gap-4 max-md:grid-cols-1"> <div className="relative grid grid-cols-3 gap-4 max-md:grid-cols-1">
<div className="bg-amber-50 rounded-3xl border-2 border-amber-500 shadow-lg p-4 h-min flex flex-col items-center max-w-md w-full max-md:place-self-center max-md:row-start-2"> <div className="bg-amber-50 rounded-3xl border-2 border-amber-500 shadow-lg p-4 h-min flex flex-col items-center max-w-md w-full max-md:place-self-center max-md:row-start-2 dark:bg-slate-800 dark:border-slate-600">
{/* Mii Image */} {/* Mii Image */}
<div className="bg-linear-to-b from-amber-100 to-amber-200 overflow-hidden rounded-xl w-full mb-4 flex justify-center"> <div className="bg-linear-to-b from-amber-100 to-amber-200 overflow-hidden rounded-xl w-full mb-4 flex justify-center dark:from-slate-700 dark:to-slate-800">
<ImageViewer <ImageViewer
src={`${API_URL}/mii/${mii.id}/image?type=mii`} src={`${API_URL}/mii/${mii.id}/image?type=mii`}
alt="mii headshot" alt="mii headshot"
@ -115,13 +115,13 @@ export default function MiiPage() {
</div> </div>
{/* QR Code */} {/* QR Code */}
{mii.platform === "THREE_DS" ? ( {mii.platform === "THREE_DS" ? (
<div className="bg-amber-200 overflow-hidden rounded-xl w-full mb-4 flex justify-center p-2"> <div className="bg-amber-200 overflow-hidden rounded-xl w-full mb-4 flex justify-center p-2 dark:bg-slate-700">
<ImageViewer <ImageViewer
src={`${API_URL}/mii/${mii.id}/image?type=qr-code`} src={`${API_URL}/mii/${mii.id}/image?type=qr-code`}
alt="mii qr code" alt="mii qr code"
width={128} width={128}
height={128} height={128}
className="border-2 border-amber-300 rounded-lg hover:brightness-90 transition-all" className="border-2 border-amber-300 rounded-lg hover:brightness-90 transition-all dark:border-slate-600"
/> />
</div> </div>
) : ( ) : (
@ -133,11 +133,11 @@ export default function MiiPage() {
className="rounded-lg hover:brightness-90 mb-4 transition-all" className="rounded-lg hover:brightness-90 mb-4 transition-all"
/> />
)} )}
<hr className="w-full border-t-2 border-t-amber-400" /> <hr className="w-full border-t-2 border-t-amber-400 dark:border-t-slate-600" />
{/* Mii Info */} {/* Mii Info */}
{mii.platform === "THREE_DS" && ( {mii.platform === "THREE_DS" && (
<ul className="text-sm w-full p-2 *:flex *:justify-between *:items-center *:my-1"> <ul className="text-sm w-full p-2 *:flex *:justify-between *:items-center *:my-1 dark:text-slate-300">
<li> <li>
Name:{" "} Name:{" "}
<span className="text-right font-medium"> <span className="text-right font-medium">
@ -154,10 +154,10 @@ export default function MiiPage() {
)} )}
{/* Mii Platform */} {/* Mii Platform */}
<div className={`flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 w-full ${mii.platform !== "THREE_DS" && "mt-2"}`}> <div className={`flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 w-full ${mii.platform !== "THREE_DS" && "mt-2"} dark:text-slate-400`}>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Platform</span> <span>Platform</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div data-tooltip-span title={mii.platform} className="grid grid-cols-2 gap-2 mb-2"> <div data-tooltip-span title={mii.platform} className="grid grid-cols-2 gap-2 mb-2">
@ -171,7 +171,7 @@ export default function MiiPage() {
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-3xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-3xl border-2 shadow-sm ${
mii.platform === "THREE_DS" ? "bg-sky-100 border-sky-400" : "bg-white border-gray-300" mii.platform === "THREE_DS" ? "bg-sky-100 border-sky-400" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="cib:nintendo-3ds" className="text-sky-500" /> <Icon icon="cib:nintendo-3ds" className="text-sky-500" />
@ -179,7 +179,7 @@ export default function MiiPage() {
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-3xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-3xl border-2 shadow-sm ${
mii.platform === "SWITCH" ? "bg-red-100 border-red-400" : "bg-white border-gray-300" mii.platform === "SWITCH" ? "bg-red-100 border-red-400" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="cib:nintendo-switch" className="text-red-400" /> <Icon icon="cib:nintendo-switch" className="text-red-400" />
@ -187,10 +187,10 @@ export default function MiiPage() {
</div> </div>
{/* Mii Gender */} {/* Mii Gender */}
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 w-full"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 w-full dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Gender</span> <span>Gender</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div data-tooltip-span title={mii.gender ?? "NULL"} className="flex gap-1"> <div data-tooltip-span title={mii.gender ?? "NULL"} className="flex gap-1">
@ -208,7 +208,7 @@ export default function MiiPage() {
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${
mii.gender === "MALE" ? "bg-blue-100 border-blue-400" : "bg-white border-gray-300" mii.gender === "MALE" ? "bg-blue-100 border-blue-400" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="foundation:male" className="text-blue-400" /> <Icon icon="foundation:male" className="text-blue-400" />
@ -216,7 +216,7 @@ export default function MiiPage() {
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${
mii.gender === "FEMALE" ? "bg-pink-100 border-pink-400" : "bg-white border-gray-300" mii.gender === "FEMALE" ? "bg-pink-100 border-pink-400" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="foundation:female" className="text-pink-400" /> <Icon icon="foundation:female" className="text-pink-400" />
@ -225,7 +225,7 @@ export default function MiiPage() {
{mii.platform !== "THREE_DS" && ( {mii.platform !== "THREE_DS" && (
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${
mii.gender === "NONBINARY" ? "bg-purple-100 border-purple-400" : "bg-white border-gray-300" mii.gender === "NONBINARY" ? "bg-purple-100 border-purple-400" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="mdi:gender-non-binary" className="text-purple-400" /> <Icon icon="mdi:gender-non-binary" className="text-purple-400" />
@ -236,10 +236,10 @@ export default function MiiPage() {
{/* Makeup */} {/* Makeup */}
{mii.platform === "SWITCH" && ( {mii.platform === "SWITCH" && (
<> <>
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 mt-2 w-full"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 mt-2 w-full dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Makeup</span> <span>Makeup</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div data-tooltip-span title={mii.makeup ?? "NULL"} className="flex gap-1"> <div data-tooltip-span title={mii.makeup ?? "NULL"} className="flex gap-1">
@ -259,7 +259,7 @@ export default function MiiPage() {
{/* Full Makeup */} {/* Full Makeup */}
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${
mii.makeup === "FULL" ? "bg-pink-100 border-pink-400" : "bg-white border-gray-300" mii.makeup === "FULL" ? "bg-pink-100 border-pink-400" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="mdi:palette" className="text-pink-400" /> <Icon icon="mdi:palette" className="text-pink-400" />
@ -268,7 +268,7 @@ export default function MiiPage() {
{/* Partial Makeup */} {/* Partial Makeup */}
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${
mii.makeup === "PARTIAL" ? "bg-purple-100 border-purple-400" : "bg-white border-gray-300" mii.makeup === "PARTIAL" ? "bg-purple-100 border-purple-400" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="mdi:lipstick" className="text-purple-400" /> <Icon icon="mdi:lipstick" className="text-purple-400" />
@ -277,10 +277,10 @@ export default function MiiPage() {
{/* No Makeup */} {/* No Makeup */}
<div <div
className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${ className={`rounded-xl flex justify-center items-center size-13 text-5xl border-2 shadow-sm ${
mii.makeup === "NONE" ? "bg-gray-200 border-gray-400" : "bg-white border-gray-300" mii.makeup === "NONE" ? "bg-gray-200 border-gray-400 dark:bg-gray-600 dark:border-gray-700" : "bg-white border-gray-300 dark:bg-slate-800 dark:border-slate-600"
}`} }`}
> >
<Icon icon="codex:cross" className="text-gray-400" /> <Icon icon="codex:cross" className="text-gray-400 dark:text-gray-200" />
</div> </div>
</div> </div>
</> </>
@ -289,10 +289,10 @@ export default function MiiPage() {
<div className="col-span-2 flex flex-col gap-4 max-md:col-span-1"> <div className="col-span-2 flex flex-col gap-4 max-md:col-span-1">
{/* Information */} {/* Information */}
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-1"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-1 dark:bg-slate-800 dark:border-slate-600">
<div className="flex justify-between items-start"> <div className="flex justify-between items-start">
{/* Submission name */} {/* Submission name */}
<h1 className="text-4xl font-extrabold wrap-break-word whitespace-break-spaces text-amber-700 flex-1 min-w-0">{mii.name}</h1> <h1 className="text-4xl font-extrabold wrap-break-word whitespace-break-spaces text-amber-700 flex-1 min-w-0 dark:text-amber-500">{mii.name}</h1>
{/* Like button */} {/* Like button */}
<LikeButton likes={mii.likeCount ?? 0} miiId={mii.id} isLiked={isLiked} big /> <LikeButton likes={mii.likeCount ?? 0} miiId={mii.id} isLiked={isLiked} big />
</div> </div>
@ -306,11 +306,11 @@ export default function MiiPage() {
</div> </div>
{/* Author and Created date */} {/* Author and Created date */}
<div className="mt-2"> <div className="mt-2 dark:text-slate-300">
<Link to={`/profile/${mii.userId}`} className="text-lg wrap-break-word"> <Link to={`/profile/${mii.userId}`} className="text-lg wrap-break-word dark:text-slate-200">
By <span className="font-bold">{mii.user.name}</span> By <span className="font-bold">{mii.user.name}</span>
</Link> </Link>
<h4 className="text-sm"> <h4 className="text-sm dark:text-slate-400">
Created:{" "} Created:{" "}
{new Date(mii.createdAt).toLocaleString("en-GB", { {new Date(mii.createdAt).toLocaleString("en-GB", {
day: "2-digit", day: "2-digit",
@ -330,7 +330,7 @@ export default function MiiPage() {
</div> </div>
{/* Buttons */} {/* Buttons */}
<div className="flex gap-3 w-fit bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 text-3xl text-orange-400 max-md:place-self-center *:size-12 *:flex *:flex-col *:items-center *:gap-1 **:transition-discrete **:duration-150 *:hover:brightness-75 *:hover:scale-[1.08] *:[&_span]:text-xs"> <div className="flex gap-3 w-fit bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 text-3xl text-orange-400 max-md:place-self-center dark:bg-slate-800 dark:border-slate-600 *:size-12 *:flex *:flex-col *:items-center *:gap-1 **:transition-discrete **:duration-150 *:hover:brightness-75 *:hover:scale-[1.08] *:[&_span]:text-xs">
<AuthorButtons mii={mii} /> <AuthorButtons mii={mii} />
<ShareMiiButton miiId={mii.id} /> <ShareMiiButton miiId={mii.id} />
@ -343,8 +343,8 @@ export default function MiiPage() {
{/* Instructions */} {/* Instructions */}
{mii.platform === "SWITCH" && ( {mii.platform === "SWITCH" && (
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-3 max-h-96 overflow-y-auto"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-3 max-h-96 overflow-y-auto dark:bg-slate-800 dark:border-slate-600">
<h2 className="text-xl font-semibold text-amber-700 flex items-center gap-2"> <h2 className="text-xl font-semibold text-amber-700 flex items-center gap-2 dark:text-amber-500">
<Icon icon="fa7-solid:list" /> <Icon icon="fa7-solid:list" />
Instructions Instructions
</h2> </h2>

View file

@ -173,7 +173,7 @@ export default function SubmitPage() {
return ( return (
<div className="flex justify-center gap-4 w-full max-lg:flex-col max-lg:items-center"> <div className="flex justify-center gap-4 w-full max-lg:flex-col max-lg:items-center">
<div className="flex justify-center"> <div className="flex justify-center">
<div className="w-75 h-min flex flex-col bg-zinc-50 rounded-3xl border-2 border-zinc-300 shadow-lg p-3"> <div className="w-75 h-min flex flex-col bg-zinc-50 rounded-3xl border-2 border-zinc-300 shadow-lg p-3 dark:bg-slate-800 dark:border-slate-600">
<Carousel <Carousel
images={[ images={[
miiPortraitUri ?? "/loading.svg", miiPortraitUri ?? "/loading.svg",
@ -183,7 +183,7 @@ export default function SubmitPage() {
/> />
<div className="p-4 flex flex-col gap-1 h-full"> <div className="p-4 flex flex-col gap-1 h-full">
<h1 className="font-bold text-2xl line-clamp-1" title={name}> <h1 className="font-bold text-2xl line-clamp-1 dark:text-slate-100" title={name}>
{name || "Mii name"} {name || "Mii name"}
</h1> </h1>
<div id="tags" className="flex flex-wrap gap-1"> <div id="tags" className="flex flex-wrap gap-1">
@ -206,19 +206,19 @@ export default function SubmitPage() {
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-2 w-full"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-2 w-full">
<div> <div>
<h2 className="text-2xl font-bold">Submit your Mii</h2> <h2 className="text-2xl font-bold">Submit your Mii</h2>
<p className="text-sm text-zinc-500">Share your creation for others to see.</p> <p className="text-sm text-zinc-500 dark:text-slate-400">Share your creation for others to see.</p>
</div> </div>
{/* Separator */} {/* Separator */}
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium my-1"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium my-1 dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Info</span> <span>Info</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
{/* Platform select */} {/* Platform select */}
<div className="w-full grid grid-cols-3 items-center"> <div className="w-full grid grid-cols-3 items-center">
<label htmlFor="name" className="font-semibold"> <label htmlFor="name" className="font-semibold dark:text-slate-100">
Platform Platform
</label> </label>
<div className="relative col-span-2 grid grid-cols-2 bg-orange-300 border-2 border-orange-400 rounded-4xl shadow-md inset-shadow-sm/10"> <div className="relative col-span-2 grid grid-cols-2 bg-orange-300 border-2 border-orange-400 rounded-4xl shadow-md inset-shadow-sm/10">
@ -258,7 +258,7 @@ export default function SubmitPage() {
{/* Name */} {/* Name */}
<div className="w-full grid grid-cols-3 items-center"> <div className="w-full grid grid-cols-3 items-center">
<label htmlFor="name" className="font-semibold"> <label htmlFor="name" className="font-semibold dark:text-slate-100">
Name Name
</label> </label>
<input <input
@ -274,7 +274,7 @@ export default function SubmitPage() {
</div> </div>
<div className="w-full grid grid-cols-3 items-center"> <div className="w-full grid grid-cols-3 items-center">
<label htmlFor="tags" className="font-semibold"> <label htmlFor="tags" className="font-semibold dark:text-slate-100">
Tags Tags
</label> </label>
<TagSelector tags={tags} setTags={setTags} showTagLimit /> <TagSelector tags={tags} setTags={setTags} showTagLimit />
@ -282,7 +282,7 @@ export default function SubmitPage() {
{/* Description */} {/* Description */}
<div className="w-full grid grid-cols-3 items-start"> <div className="w-full grid grid-cols-3 items-start">
<label htmlFor="description" className="font-semibold py-2"> <label htmlFor="description" className="font-semibold py-2 dark:text-slate-100">
Description Description
</label> </label>
<textarea <textarea
@ -298,7 +298,7 @@ export default function SubmitPage() {
{/* Gender (switch only) */} {/* Gender (switch only) */}
<div className={`w-full grid grid-cols-3 items-start z-20 ${platform === "SWITCH" ? "" : "hidden"}`}> <div className={`w-full grid grid-cols-3 items-start z-20 ${platform === "SWITCH" ? "" : "hidden"}`}>
<label htmlFor="gender" className="font-semibold py-2"> <label htmlFor="gender" className="font-semibold py-2 dark:text-slate-100">
Gender Gender
</label> </label>
<div className="col-span-2 flex gap-1"> <div className="col-span-2 flex gap-1">
@ -308,7 +308,7 @@ export default function SubmitPage() {
aria-label="Filter for Male Miis" aria-label="Filter for Male Miis"
data-tooltip="Male" data-tooltip="Male"
className={`cursor-pointer rounded-xl flex justify-center items-center size-11 text-4xl border-2 transition-all after:bg-blue-400! after:border-blue-400! before:border-b-blue-400! ${ className={`cursor-pointer rounded-xl flex justify-center items-center size-11 text-4xl border-2 transition-all after:bg-blue-400! after:border-blue-400! before:border-b-blue-400! ${
gender === "MALE" ? "bg-blue-100 border-blue-400 shadow-md" : "bg-white border-gray-300 hover:border-gray-400" gender === "MALE" ? "bg-blue-100 border-blue-400 shadow-md" : "bg-white border-gray-300 hover:border-gray-400 dark:bg-slate-800 dark:border-slate-600 dark:hover:border-slate-500"
}`} }`}
> >
<Icon icon="foundation:male" className="text-blue-400" /> <Icon icon="foundation:male" className="text-blue-400" />
@ -320,7 +320,7 @@ export default function SubmitPage() {
aria-label="Filter for Female Miis" aria-label="Filter for Female Miis"
data-tooltip="Female" data-tooltip="Female"
className={`cursor-pointer rounded-xl flex justify-center items-center size-11 text-4xl border-2 transition-all after:bg-pink-400! after:border-pink-400! before:border-b-pink-400! ${ className={`cursor-pointer rounded-xl flex justify-center items-center size-11 text-4xl border-2 transition-all after:bg-pink-400! after:border-pink-400! before:border-b-pink-400! ${
gender === "FEMALE" ? "bg-pink-100 border-pink-400 shadow-md" : "bg-white border-gray-300 hover:border-gray-400" gender === "FEMALE" ? "bg-pink-100 border-pink-400 shadow-md" : "bg-white border-gray-300 hover:border-gray-400 dark:bg-slate-800 dark:border-slate-600 dark:hover:border-slate-500"
}`} }`}
> >
<Icon icon="foundation:female" className="text-pink-400" /> <Icon icon="foundation:female" className="text-pink-400" />
@ -332,7 +332,7 @@ export default function SubmitPage() {
aria-label="Filter for Nonbinary Miis" aria-label="Filter for Nonbinary Miis"
data-tooltip="Nonbinary" data-tooltip="Nonbinary"
className={`cursor-pointer rounded-xl flex justify-center items-center size-11 text-4xl border-2 transition-all after:bg-purple-400! after:border-purple-400! before:border-b-purple-400! ${ className={`cursor-pointer rounded-xl flex justify-center items-center size-11 text-4xl border-2 transition-all after:bg-purple-400! after:border-purple-400! before:border-b-purple-400! ${
gender === "NONBINARY" ? "bg-purple-100 border-purple-400 shadow-md" : "bg-white border-gray-300 hover:border-gray-400" gender === "NONBINARY" ? "bg-purple-100 border-purple-400 shadow-md" : "bg-white border-gray-300 hover:border-gray-400 dark:bg-slate-800 dark:border-slate-600 dark:hover:border-slate-500"
}`} }`}
> >
<Icon icon="mdi:gender-non-binary" className="text-purple-400" /> <Icon icon="mdi:gender-non-binary" className="text-purple-400" />
@ -342,7 +342,7 @@ export default function SubmitPage() {
{/* Makeup (switch only) */} {/* Makeup (switch only) */}
<div className={`w-full grid grid-cols-3 items-start ${platform === "SWITCH" ? "" : "hidden"}`}> <div className={`w-full grid grid-cols-3 items-start ${platform === "SWITCH" ? "" : "hidden"}`}>
<label className="font-semibold py-2">Face Paint</label> <label className="font-semibold py-2 dark:text-slate-100">Face Paint</label>
<div className="col-span-2 flex flex-col gap-1.5"> <div className="col-span-2 flex flex-col gap-1.5">
{[ {[
@ -355,11 +355,11 @@ export default function SubmitPage() {
type="button" type="button"
onClick={() => setMakeup(value as MiiMakeup)} onClick={() => setMakeup(value as MiiMakeup)}
className={`cursor-pointer rounded-xl text-left px-3 py-2 border-2 transition-all ${ className={`cursor-pointer rounded-xl text-left px-3 py-2 border-2 transition-all ${
makeup === value ? `bg-${color}-100 border-${color}-400 shadow-md` : "bg-white border-gray-300 hover:border-gray-400" makeup === value ? `bg-${color}-100 border-${color}-400 shadow-md` : "bg-white border-gray-300 hover:border-gray-400 dark:bg-slate-800 dark:border-slate-600 dark:hover:border-slate-500"
}`} }`}
> >
<div className={`font-medium text-sm ${makeup === value ? `text-${color}-500` : "text-gray-500"}`}>{label}</div> <div className={`font-medium text-sm ${makeup === value ? `text-${color}-500` : "text-gray-500 dark:text-slate-400"}`}>{label}</div>
<div className="text-xs text-gray-500 mt-0.5">{desc}</div> <div className="text-xs text-gray-500 mt-0.5 dark:text-slate-500">{desc}</div>
</button> </button>
))} ))}
</div> </div>
@ -368,10 +368,10 @@ export default function SubmitPage() {
{/* (Switch Only) Mii Screenshots */} {/* (Switch Only) Mii Screenshots */}
<div className={`${platform === "SWITCH" ? "" : "hidden"}`}> <div className={`${platform === "SWITCH" ? "" : "hidden"}`}>
{/* Separator */} {/* Separator */}
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2 dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Mii Screenshots</span> <span>Mii Screenshots</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div className="flex flex-col items-center gap-4 w-full"> <div className="flex flex-col items-center gap-4 w-full">
@ -379,7 +379,7 @@ export default function SubmitPage() {
<div className="flex flex-col items-center gap-2 w-full"> <div className="flex flex-col items-center gap-2 w-full">
<div className="flex items-center gap-2 self-start"> <div className="flex items-center gap-2 self-start">
<span className="bg-orange-400 text-white text-xs font-bold rounded-full size-5 flex items-center justify-center shrink-0">1</span> <span className="bg-orange-400 text-white text-xs font-bold rounded-full size-5 flex items-center justify-center shrink-0">1</span>
<span className="text-sm font-semibold text-zinc-600">Portrait screenshot</span> <span className="text-sm font-semibold text-zinc-600 dark:text-slate-300">Portrait screenshot</span>
</div> </div>
<div className="flex gap-3 w-full items-start max-sm:flex-col max-sm:items-center"> <div className="flex gap-3 w-full items-start max-sm:flex-col max-sm:items-center">
<div data-tooltip="Your screenshot should look like this"> <div data-tooltip="Your screenshot should look like this">
@ -388,7 +388,7 @@ export default function SubmitPage() {
alt="Example portrait screenshot" alt="Example portrait screenshot"
width={80} width={80}
height={80} height={80}
className="size-20 object-cover rounded-xl border-2 border-orange-300 shrink-0 opacity-70" className="size-20 object-cover rounded-xl border-2 border-orange-300 shrink-0 opacity-70 dark:border-slate-600"
/> />
</div> </div>
<SwitchFileUpload text="a screenshot of your Mii here" image={miiPortraitUri} setImage={setMiiPortraitUri} forceCrop /> <SwitchFileUpload text="a screenshot of your Mii here" image={miiPortraitUri} setImage={setMiiPortraitUri} forceCrop />
@ -399,8 +399,8 @@ export default function SubmitPage() {
<div className="flex flex-col items-center gap-2 w-full"> <div className="flex flex-col items-center gap-2 w-full">
<div className="flex items-center gap-2 self-start"> <div className="flex items-center gap-2 self-start">
<span className="bg-orange-400 text-white text-xs font-bold rounded-full size-5 flex items-center justify-center shrink-0">2</span> <span className="bg-orange-400 text-white text-xs font-bold rounded-full size-5 flex items-center justify-center shrink-0">2</span>
<span className="text-sm font-semibold text-zinc-600"> <span className="text-sm font-semibold text-zinc-600 dark:text-slate-300">
Features screenshot <span className="text-orange-500">(the features panel - see example)</span> Features screenshot <span className="text-orange-500 dark:text-orange-400">(the features panel - see example)</span>
</span> </span>
</div> </div>
<div className="flex gap-3 w-full items-start max-sm:flex-col max-sm:items-center"> <div className="flex gap-3 w-full items-start max-sm:flex-col max-sm:items-center">
@ -410,7 +410,7 @@ export default function SubmitPage() {
alt="Example features screenshot showing the parts panel" alt="Example features screenshot showing the parts panel"
width={80} width={80}
height={80} height={80}
className="size-20 object-cover rounded-xl border-2 border-orange-300 shrink-0 opacity-70" className="size-20 object-cover rounded-xl border-2 border-orange-300 shrink-0 opacity-70 dark:border-slate-600"
/> />
</div> </div>
<SwitchFileUpload text="a screenshot of your Mii's features here" image={miiFeaturesUri} setImage={setMiiFeaturesUri} /> <SwitchFileUpload text="a screenshot of your Mii's features here" image={miiFeaturesUri} setImage={setMiiFeaturesUri} />
@ -420,20 +420,20 @@ export default function SubmitPage() {
<SwitchSubmitTutorialButton /> <SwitchSubmitTutorialButton />
</div> </div>
<p className="text-xs text-zinc-400 text-center mt-2">A tutorial on how to screenshot the features is above.</p> <p className="text-xs text-zinc-400 text-center mt-2 dark:text-slate-500">A tutorial on how to screenshot the features is above.</p>
</div> </div>
{/* (3DS only) QR code scanning */} {/* (3DS only) QR code scanning */}
<div className={`${platform === "THREE_DS" ? "" : "hidden"}`}> <div className={`${platform === "THREE_DS" ? "" : "hidden"}`}>
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2 dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>QR Code</span> <span>QR Code</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<QrUpload setQrBytesRaw={setQrBytesRaw} /> <QrUpload setQrBytesRaw={setQrBytesRaw} />
<span>or</span> <span className="dark:text-slate-300">or</span>
<button type="button" aria-label="Use your camera" onClick={() => setIsQrScannerOpen(true)} className="pill button gap-2"> <button type="button" aria-label="Use your camera" onClick={() => setIsQrScannerOpen(true)} className="pill button gap-2">
<Icon icon="mdi:camera" fontSize={20} /> <Icon icon="mdi:camera" fontSize={20} />
@ -443,22 +443,22 @@ export default function SubmitPage() {
<Camera isOpen={isQrScannerOpen} setIsOpen={setIsQrScannerOpen} setQrBytesRaw={setQrBytesRaw} /> <Camera isOpen={isQrScannerOpen} setIsOpen={setIsQrScannerOpen} setQrBytesRaw={setQrBytesRaw} />
<ThreeDsScanTutorialButton /> <ThreeDsScanTutorialButton />
<span className="text-xs text-zinc-400">For emulators, aes_keys.txt is required.</span> <span className="text-xs text-zinc-400 dark:text-slate-500">For emulators, aes_keys.txt is required.</span>
</div> </div>
</div> </div>
{/* (Switch only) Mii instructions */} {/* (Switch only) Mii instructions */}
<div className={`${platform === "SWITCH" ? "" : "hidden"}`}> <div className={`${platform === "SWITCH" ? "" : "hidden"}`}>
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2 dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Mii Instructions</span> <span>Mii Instructions</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
{/* YouTube */} {/* YouTube */}
<div className="w-full grid grid-cols-3 items-center"> <div className="w-full grid grid-cols-3 items-center">
<label htmlFor="youtube" className="font-semibold"> <label htmlFor="youtube" className="font-semibold dark:text-slate-100">
YouTube Video YouTube Video
</label> </label>
<input <input
@ -479,34 +479,34 @@ export default function SubmitPage() {
<MiiEditor instructions={instructions} /> <MiiEditor instructions={instructions} />
<SwitchSubmitTutorialButton /> <SwitchSubmitTutorialButton />
<span className="text-xs text-zinc-400 text-center px-32 max-sm:px-8"> <span className="text-xs text-zinc-400 text-center px-32 max-sm:px-8 dark:text-slate-500">
Mii editor may be inaccurate. Instructions are REALLY recommended, but you do not have to add every instruction. Mii editor may be inaccurate. Instructions are REALLY recommended, but you do not have to add every instruction.
</span> </span>
</div> </div>
</div> </div>
{/* Custom images selector */} {/* Custom images selector */}
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-6 mb-2"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-6 mb-2 dark:text-slate-400">
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
<span>Custom images</span> <span>Custom images</span>
<hr className="grow border-zinc-300" /> <hr className="grow border-zinc-300 dark:border-slate-600" />
</div> </div>
<div className="max-w-md w-full self-center flex flex-col items-center"> <div className="max-w-md w-full self-center flex flex-col items-center">
<Dropzone onDrop={handleDrop}> <Dropzone onDrop={handleDrop}>
<p className="text-center text-sm"> <p className="text-center text-sm dark:text-slate-300">
Drag and drop your images here Drag and drop your images here
<br /> <br />
or click to open or click to open
</p> </p>
</Dropzone> </Dropzone>
<span className="text-xs text-zinc-400 mt-2">Animated images currently not supported.</span> <span className="text-xs text-zinc-400 mt-2 dark:text-slate-500">Animated images currently not supported.</span>
</div> </div>
<ImageList files={files} setFiles={setFiles} /> <ImageList files={files} setFiles={setFiles} />
<hr className="border-zinc-300 my-2" /> <hr className="border-zinc-300 my-2 dark:border-slate-600" />
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
{error && <span className="text-red-400 font-bold">Error: {error}</span>} {error && <span className="text-red-400 font-bold">Error: {error}</span>}