mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-05-13 05:07:46 +00:00
Compare commits
2 commits
a0d06b5251
...
a4f92f1605
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4f92f1605 | ||
|
|
282a1d3938 |
7 changed files with 94 additions and 166 deletions
|
|
@ -43,14 +43,14 @@ export default function Header() {
|
|||
<Link
|
||||
to={`${import.meta.env.VITE_API_URL}/random`}
|
||||
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"
|
||||
>
|
||||
<Icon icon="mdi:dice-3" fontSize={28} />
|
||||
</Link>
|
||||
</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
|
||||
</Link>
|
||||
</li>
|
||||
|
|
@ -60,7 +60,7 @@ export default function Header() {
|
|||
<ThemeToggle size="md" />
|
||||
</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
|
||||
</Link>
|
||||
</li>
|
||||
|
|
@ -71,7 +71,7 @@ export default function Header() {
|
|||
<Link
|
||||
to={`/profile/${$session?.user?.id}`}
|
||||
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"
|
||||
>
|
||||
<img
|
||||
|
|
@ -95,7 +95,7 @@ export default function Header() {
|
|||
<Link
|
||||
to={`${import.meta.env.VITE_API_URL}/api/auth/signout`}
|
||||
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"
|
||||
>
|
||||
<Icon icon="ic:round-logout" fontSize={24} />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useState, useEffect } from "react";
|
||||
import { useStore } from "@nanostores/react";
|
||||
import { useState } from "react";
|
||||
|
||||
import { userNameSchema } from "@tomodachi-share/shared/schemas";
|
||||
|
||||
|
|
@ -8,8 +7,6 @@ import SubmitDialogButton from "./submit-dialog-button";
|
|||
import DeleteAccount from "./delete-account";
|
||||
import z from "zod";
|
||||
import { useNavigate } from "react-router";
|
||||
import { session } from "../../session";
|
||||
import { type Theme, applyTheme } from "../../lib/theme";
|
||||
|
||||
interface Props {
|
||||
currentDescription: string | null | undefined;
|
||||
|
|
@ -17,22 +14,12 @@ interface Props {
|
|||
|
||||
export default function ProfileSettings({ currentDescription }: Props) {
|
||||
const navigate = useNavigate();
|
||||
const $session = useStore(session);
|
||||
const [description, setDescription] = useState(currentDescription);
|
||||
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 [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 parsed = z.string().trim().max(256).safeParse(description);
|
||||
if (!parsed.success) {
|
||||
|
|
@ -81,31 +68,11 @@ export default function ProfileSettings({ currentDescription }: Props) {
|
|||
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 (
|
||||
<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>
|
||||
<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>
|
||||
|
||||
{/* Separator */}
|
||||
|
|
@ -172,39 +139,6 @@ export default function ProfileSettings({ currentDescription }: Props) {
|
|||
</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 */}
|
||||
<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" />
|
||||
|
|
|
|||
|
|
@ -31,14 +31,8 @@ export default function ThemeToggle({ size = "md", className = "" }: ThemeToggle
|
|||
const getIcon = () => {
|
||||
if (theme === "DARK") return <Icon icon="mdi:moon" fontSize={iconSizes[size]} />;
|
||||
if (theme === "LIGHT") return <Icon icon="mdi:white-balance-sunny" fontSize={iconSizes[size]} />;
|
||||
// SYSTEM or undefined - show both
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
// SYSTEM or undefined - show computer/monitor icon
|
||||
return <Icon icon="mdi:monitor" fontSize={iconSizes[size]} />;
|
||||
};
|
||||
|
||||
const getTooltip = () => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export default function IndexPage() {
|
|||
<h1 className="sr-only">
|
||||
{searchParams.get("tags") ? `Miis tagged with '${searchParams.get("tags")}' - TomodachiShare` : "TomodachiShare - index mii list"}
|
||||
</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 />
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ export default function LoginPage() {
|
|||
|
||||
return (
|
||||
<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">
|
||||
<h1 className="text-3xl font-bold mb-4">Welcome to TomodachiShare!</h1>
|
||||
<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 dark:text-slate-100">Welcome to TomodachiShare!</h1>
|
||||
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-8">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>Choose your login method</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
|
|
@ -48,13 +48,13 @@ export default function LoginPage() {
|
|||
</Link>
|
||||
</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{" "}
|
||||
<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
|
||||
</Link>{" "}
|
||||
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
|
||||
</Link>
|
||||
.
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export default function MiiPage() {
|
|||
</div>
|
||||
)}
|
||||
{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" />
|
||||
<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.
|
||||
|
|
@ -102,9 +102,9 @@ export default function MiiPage() {
|
|||
</div>
|
||||
)}
|
||||
<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 */}
|
||||
<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
|
||||
src={`${API_URL}/mii/${mii.id}/image?type=mii`}
|
||||
alt="mii headshot"
|
||||
|
|
@ -115,13 +115,13 @@ export default function MiiPage() {
|
|||
</div>
|
||||
{/* QR Code */}
|
||||
{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
|
||||
src={`${API_URL}/mii/${mii.id}/image?type=qr-code`}
|
||||
alt="mii qr code"
|
||||
width={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>
|
||||
) : (
|
||||
|
|
@ -133,11 +133,11 @@ export default function MiiPage() {
|
|||
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.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>
|
||||
Name:{" "}
|
||||
<span className="text-right font-medium">
|
||||
|
|
@ -154,10 +154,10 @@ export default function MiiPage() {
|
|||
)}
|
||||
|
||||
{/* 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"}`}>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>Platform</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<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
|
||||
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" />
|
||||
|
|
@ -179,7 +179,7 @@ export default function MiiPage() {
|
|||
|
||||
<div
|
||||
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" />
|
||||
|
|
@ -187,10 +187,10 @@ export default function MiiPage() {
|
|||
</div>
|
||||
|
||||
{/* Mii Gender */}
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 w-full">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>Gender</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<div data-tooltip-span title={mii.gender ?? "NULL"} className="flex gap-1">
|
||||
|
|
@ -208,7 +208,7 @@ export default function MiiPage() {
|
|||
|
||||
<div
|
||||
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" />
|
||||
|
|
@ -216,7 +216,7 @@ export default function MiiPage() {
|
|||
|
||||
<div
|
||||
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" />
|
||||
|
|
@ -225,7 +225,7 @@ export default function MiiPage() {
|
|||
{mii.platform !== "THREE_DS" && (
|
||||
<div
|
||||
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" />
|
||||
|
|
@ -236,10 +236,10 @@ export default function MiiPage() {
|
|||
{/* Makeup */}
|
||||
{mii.platform === "SWITCH" && (
|
||||
<>
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mb-2 mt-2 w-full">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>Makeup</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<div data-tooltip-span title={mii.makeup ?? "NULL"} className="flex gap-1">
|
||||
|
|
@ -259,7 +259,7 @@ export default function MiiPage() {
|
|||
{/* Full Makeup */}
|
||||
<div
|
||||
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" />
|
||||
|
|
@ -268,7 +268,7 @@ export default function MiiPage() {
|
|||
{/* Partial Makeup */}
|
||||
<div
|
||||
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" />
|
||||
|
|
@ -277,10 +277,10 @@ export default function MiiPage() {
|
|||
{/* No Makeup */}
|
||||
<div
|
||||
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>
|
||||
</>
|
||||
|
|
@ -289,10 +289,10 @@ export default function MiiPage() {
|
|||
|
||||
<div className="col-span-2 flex flex-col gap-4 max-md:col-span-1">
|
||||
{/* 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">
|
||||
{/* 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 */}
|
||||
<LikeButton likes={mii.likeCount ?? 0} miiId={mii.id} isLiked={isLiked} big />
|
||||
</div>
|
||||
|
|
@ -306,11 +306,11 @@ export default function MiiPage() {
|
|||
</div>
|
||||
|
||||
{/* Author and Created date */}
|
||||
<div className="mt-2">
|
||||
<Link to={`/profile/${mii.userId}`} className="text-lg wrap-break-word">
|
||||
<div className="mt-2 dark:text-slate-300">
|
||||
<Link to={`/profile/${mii.userId}`} className="text-lg wrap-break-word dark:text-slate-200">
|
||||
By <span className="font-bold">{mii.user.name}</span>
|
||||
</Link>
|
||||
<h4 className="text-sm">
|
||||
<h4 className="text-sm dark:text-slate-400">
|
||||
Created:{" "}
|
||||
{new Date(mii.createdAt).toLocaleString("en-GB", {
|
||||
day: "2-digit",
|
||||
|
|
@ -330,7 +330,7 @@ export default function MiiPage() {
|
|||
</div>
|
||||
|
||||
{/* 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} />
|
||||
|
||||
<ShareMiiButton miiId={mii.id} />
|
||||
|
|
@ -343,8 +343,8 @@ export default function MiiPage() {
|
|||
|
||||
{/* Instructions */}
|
||||
{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">
|
||||
<h2 className="text-xl font-semibold text-amber-700 flex items-center gap-2">
|
||||
<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 dark:text-amber-500">
|
||||
<Icon icon="fa7-solid:list" />
|
||||
Instructions
|
||||
</h2>
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ export default function SubmitPage() {
|
|||
return (
|
||||
<div className="flex justify-center gap-4 w-full max-lg:flex-col max-lg:items-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
|
||||
images={[
|
||||
miiPortraitUri ?? "/loading.svg",
|
||||
|
|
@ -183,7 +183,7 @@ export default function SubmitPage() {
|
|||
/>
|
||||
|
||||
<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"}
|
||||
</h1>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
{/* Separator */}
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium my-1">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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>Info</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
{/* Platform select */}
|
||||
<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
|
||||
</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">
|
||||
|
|
@ -258,7 +258,7 @@ export default function SubmitPage() {
|
|||
|
||||
{/* Name */}
|
||||
<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
|
||||
</label>
|
||||
<input
|
||||
|
|
@ -274,7 +274,7 @@ export default function SubmitPage() {
|
|||
</div>
|
||||
|
||||
<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
|
||||
</label>
|
||||
<TagSelector tags={tags} setTags={setTags} showTagLimit />
|
||||
|
|
@ -282,7 +282,7 @@ export default function SubmitPage() {
|
|||
|
||||
{/* Description */}
|
||||
<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
|
||||
</label>
|
||||
<textarea
|
||||
|
|
@ -298,7 +298,7 @@ export default function SubmitPage() {
|
|||
|
||||
{/* Gender (switch only) */}
|
||||
<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
|
||||
</label>
|
||||
<div className="col-span-2 flex gap-1">
|
||||
|
|
@ -308,7 +308,7 @@ export default function SubmitPage() {
|
|||
aria-label="Filter for Male Miis"
|
||||
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! ${
|
||||
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" />
|
||||
|
|
@ -320,7 +320,7 @@ export default function SubmitPage() {
|
|||
aria-label="Filter for Female Miis"
|
||||
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! ${
|
||||
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" />
|
||||
|
|
@ -332,7 +332,7 @@ export default function SubmitPage() {
|
|||
aria-label="Filter for Nonbinary Miis"
|
||||
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! ${
|
||||
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" />
|
||||
|
|
@ -342,7 +342,7 @@ export default function SubmitPage() {
|
|||
|
||||
{/* Makeup (switch only) */}
|
||||
<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">
|
||||
{[
|
||||
|
|
@ -355,11 +355,11 @@ export default function SubmitPage() {
|
|||
type="button"
|
||||
onClick={() => setMakeup(value as MiiMakeup)}
|
||||
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="text-xs text-gray-500 mt-0.5">{desc}</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 dark:text-slate-500">{desc}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -368,10 +368,10 @@ export default function SubmitPage() {
|
|||
{/* (Switch Only) Mii Screenshots */}
|
||||
<div className={`${platform === "SWITCH" ? "" : "hidden"}`}>
|
||||
{/* Separator */}
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>Mii Screenshots</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<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 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="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 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">
|
||||
|
|
@ -388,7 +388,7 @@ export default function SubmitPage() {
|
|||
alt="Example portrait screenshot"
|
||||
width={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>
|
||||
<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 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="text-sm font-semibold text-zinc-600">
|
||||
Features screenshot <span className="text-orange-500">(the features panel - see example)</span>
|
||||
<span className="text-sm font-semibold text-zinc-600 dark:text-slate-300">
|
||||
Features screenshot <span className="text-orange-500 dark:text-orange-400">(the features panel - see example)</span>
|
||||
</span>
|
||||
</div>
|
||||
<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"
|
||||
width={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>
|
||||
<SwitchFileUpload text="a screenshot of your Mii's features here" image={miiFeaturesUri} setImage={setMiiFeaturesUri} />
|
||||
|
|
@ -420,20 +420,20 @@ export default function SubmitPage() {
|
|||
<SwitchSubmitTutorialButton />
|
||||
</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>
|
||||
|
||||
{/* (3DS only) QR code scanning */}
|
||||
<div className={`${platform === "THREE_DS" ? "" : "hidden"}`}>
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>QR Code</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<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">
|
||||
<Icon icon="mdi:camera" fontSize={20} />
|
||||
|
|
@ -443,22 +443,22 @@ export default function SubmitPage() {
|
|||
<Camera isOpen={isQrScannerOpen} setIsOpen={setIsQrScannerOpen} setQrBytesRaw={setQrBytesRaw} />
|
||||
<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>
|
||||
|
||||
{/* (Switch only) Mii instructions */}
|
||||
<div className={`${platform === "SWITCH" ? "" : "hidden"}`}>
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>Mii Instructions</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
{/* YouTube */}
|
||||
<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
|
||||
</label>
|
||||
<input
|
||||
|
|
@ -479,34 +479,34 @@ export default function SubmitPage() {
|
|||
|
||||
<MiiEditor instructions={instructions} />
|
||||
<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.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Custom images selector */}
|
||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-6 mb-2">
|
||||
<hr className="grow border-zinc-300" />
|
||||
<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 dark:border-slate-600" />
|
||||
<span>Custom images</span>
|
||||
<hr className="grow border-zinc-300" />
|
||||
<hr className="grow border-zinc-300 dark:border-slate-600" />
|
||||
</div>
|
||||
|
||||
<div className="max-w-md w-full self-center flex flex-col items-center">
|
||||
<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
|
||||
<br />
|
||||
or click to open
|
||||
</p>
|
||||
</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>
|
||||
|
||||
<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">
|
||||
{error && <span className="text-red-400 font-bold">Error: {error}</span>}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue