fix: build errors

This commit is contained in:
trafficlunar 2025-04-09 13:49:09 +01:00
parent 4a65994d35
commit 516923905d
15 changed files with 65 additions and 57 deletions

View file

@ -1,5 +1,6 @@
"use client";
import Image from "next/image";
import { useCallback, useEffect, useState } from "react";
import useEmblaCarousel from "embla-carousel-react";
import { Icon } from "@iconify/react";
@ -30,7 +31,7 @@ export default function Carousel({ images, className }: Props) {
<div className="flex">
{images.map((src, index) => (
<div key={index} className="flex-[0_0_100%]">
<img src={src} alt="" className="w-full h-auto aspect-[3/2] object-contain" />
<Image src={src} alt="mii image" width={480} height={320} className="w-full h-auto aspect-[3/2] object-contain" />
</div>
))}
</div>

View file

@ -11,7 +11,7 @@ interface Props {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
// for use on profiles
userId?: number;
where?: Record<string, any>;
where?: Record<string, object>;
}
export default async function MiiList({ searchParams, userId, where }: Props) {

View file

@ -17,6 +17,7 @@ import TagSelector from "./submit/tag-selector";
import ImageList from "./submit/image-list";
import QrUpload from "./submit/qr-upload";
import QrScanner from "./submit/qr-scanner";
import Image from "next/image";
export default function SubmitForm() {
const [files, setFiles] = useState<FileWithPath[]>([]);
@ -114,7 +115,7 @@ export default function SubmitForm() {
generatedCode.make();
setGeneratedQrCodeUrl(generatedCode.createDataURL());
} catch (error) {
} catch {
setError("Failed to get and/or generate Mii images");
}
};
@ -128,11 +129,23 @@ export default function SubmitForm() {
<div className="flex justify-center gap-2">
<div className="relative flex justify-center items-center size-32 aspect-square bg-orange-100 rounded-xl border-2 border-amber-500">
{!studioUrl && <span className="absolute text-center font-light">Mii</span>}
<img src={studioUrl} alt="Nintendo Studio URL" className="size-full rounded-xl text-[0px]" />
<Image
src={studioUrl ?? "/missing.webp"}
width={128}
height={128}
alt="Nintendo Studio URL"
className="size-full rounded-xl text-[0px]"
/>
</div>
<div className="relative flex justify-center items-center size-32 aspect-square bg-orange-100 rounded-xl border-2 border-amber-500">
{!generatedQrCodeUrl && <span className="absolute text-center font-light">QR Code</span>}
<img src={generatedQrCodeUrl} alt="Generated QR Code" className="size-full rounded-xl text-[0px]" />
<Image
src={generatedQrCodeUrl ?? "/missing.webp"}
width={128}
height={128}
alt="Generated QR Code"
className="size-full rounded-xl text-[0px]"
/>
</div>
</div>

View file

@ -1,3 +1,4 @@
import Image from "next/image";
import { FileWithPath } from "react-dropzone";
import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd";
import { Icon } from "@iconify/react";
@ -37,7 +38,7 @@ export default function ImageList({ files, setFiles }: Props) {
{...provided.draggableProps}
className="w-full p-4 rounded-xl bg-orange-100 border-2 border-amber-500 flex gap-2 shadow-md my-1"
>
<img
<Image
src={URL.createObjectURL(file)}
alt={file.name}
className="aspect-[3/2] object-contain w-24 rounded-md bg-orange-300 border-2 border-orange-400"

View file

@ -97,12 +97,12 @@ export default function QrScanner({ isOpen, setIsOpen, setQrBytesRaw }: Props) {
setSelectedDeviceId(videoDevices[0].deviceId);
}
});
}, [isOpen]);
}, [isOpen, selectedDeviceId]);
useEffect(() => {
if (!isOpen && !permissionGranted) return;
requestRef.current = requestAnimationFrame(scanQRCode);
}, [permissionGranted]);
}, [isOpen, permissionGranted, scanQRCode]);
if (!isOpen) return null;

View file

@ -12,34 +12,37 @@ interface Props {
export default function QrUpload({ setQrBytesRaw }: Props) {
const canvasRef = useRef<HTMLCanvasElement>(null);
const onDrop = useCallback((acceptedFiles: FileWithPath[]) => {
acceptedFiles.forEach((file) => {
// Scan QR code
const reader = new FileReader();
reader.onload = async (event) => {
const image = new Image();
image.onload = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const onDrop = useCallback(
(acceptedFiles: FileWithPath[]) => {
acceptedFiles.forEach((file) => {
// Scan QR code
const reader = new FileReader();
reader.onload = async (event) => {
const image = new Image();
image.onload = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
const imageData = ctx.getImageData(0, 0, image.width, image.height);
const code = jsQR(imageData.data, image.width, image.height);
if (!code) return;
const imageData = ctx.getImageData(0, 0, image.width, image.height);
const code = jsQR(imageData.data, image.width, image.height);
if (!code) return;
setQrBytesRaw(code.binaryData!);
setQrBytesRaw(code.binaryData!);
};
image.src = event.target!.result as string;
};
image.src = event.target!.result as string;
};
reader.readAsDataURL(file);
});
}, []);
reader.readAsDataURL(file);
});
},
[setQrBytesRaw]
);
const { getRootProps, getInputProps } = useDropzone({
onDrop,

View file

@ -1,7 +1,7 @@
"use client";
import React, { useState, KeyboardEvent } from "react";
import { useCombobox, useMultipleSelection } from "downshift";
import React, { useState } from "react";
import { useCombobox } from "downshift";
import { Icon } from "@iconify/react";
interface Props {
@ -135,7 +135,7 @@ export default function TagSelector({ tags, setTags }: Props) {
setInputValue("");
}}
>
Add "{inputValue}"
Add &quot;{inputValue}&quot;
</li>
)}
</ul>

View file

@ -112,7 +112,7 @@ export default async function MiiPage({ params }: Props) {
key={index}
src={src}
width={256}
height={1}
height={170}
alt="mii screenshots"
className="rounded-xl bg-zinc-300 border-2 border-zinc-300 shadow-md aspect-[3/2] h-full object-contain"
/>

View file

@ -9,14 +9,5 @@ export default async function Page({ searchParams }: { searchParams: Promise<{ [
redirect("/create-username");
}
// await prisma.mii.create({
// data: {
// userId: 1,
// name: "Himmel",
// pictures: ["https://placehold.co/600x400", "/missing.webp"],
// tags: ["Anime", "Osaka"],
// },
// });
return <MiiList searchParams={searchParams} />;
}

View file

@ -89,8 +89,8 @@ export default function PrivacyPage() {
<section>
<p className="mb-2">
Your data, including your Miis, will be retained for as long as you have an account on the site. You may request that your data be
deleted at any time by going to your profile page, clicking the settings icon, and clicking the 'Delete Account' button. Upon clicking,
your data will be promptly removed from our servers.
deleted at any time by going to your profile page, clicking the settings icon, and clicking the &apos;Delete Account&apos; button. Upon
clicking, your data will be promptly removed from our servers.
</p>
</section>
</li>

View file

@ -25,7 +25,7 @@ export default async function SearchPage({ searchParams }: Props) {
return (
<div>
<p className="text-lg">
Search results for "<span className="font-bold">{query}</span>"
Search results for &quot;<span className="font-bold">{query}</span>&quot;
</p>
<MiiList
searchParams={searchParams}

View file

@ -51,7 +51,7 @@ export default function PrivacyPage() {
<a href="/privacy" className="text-blue-700">
Privacy Policy
</a>{" "}
(see "Data Deletion") or email me at{" "}
(see &quot;Data Deletion&quot;) or email me at{" "}
<a href="mailto:hello@trafficlunar.net" className="text-blue-700">
hello@trafficlunar.net
</a>
@ -70,8 +70,8 @@ export default function PrivacyPage() {
<section>
<p className="mb-2">
This service is provided "as is" and without any warranties. We are not responsible for any user-generated content or the actions of
users on the site. You use the site at your own risk.
This service is provided &quot;as is&quot; and without any warranties. We are not responsible for any user-generated content or the
actions of users on the site. You use the site at your own risk.
</p>
<p>
We do not guarantee continuous or secure access to the service and are not liable for any damages resulting from interruptions, loss of
@ -109,8 +109,8 @@ export default function PrivacyPage() {
<section>
<p className="mb-2">
This site is not affiliated with, endorsed by, or associated with Nintendo in any way. "Mii" and all related character designs are
trademarks of Nintendo Co., Ltd.
This site is not affiliated with, endorsed by, or associated with Nintendo in any way. &quot;Mii&quot; and all related character designs
are trademarks of Nintendo Co., Ltd.
</p>
<p>
All Mii-related content is shared by users under the assumption that it does not violate any third-party rights. If you believe your

View file

@ -6,7 +6,7 @@ const MIN_IMAGE_DIMENSIONS = 128;
const MAX_IMAGE_DIMENSIONS = 1024;
const MAX_IMAGE_SIZE = 1024 * 1024; // 1 MB
const THRESHOLD = 0.5;
// const THRESHOLD = 0.5;
// tf.enableProdMode();

View file

@ -15,7 +15,7 @@ export function convertQrCode(bytes: Uint8Array): { mii: Mii; tomodachiLifeMii:
let decrypted: Uint8Array<ArrayBufferLike> = new Uint8Array();
try {
decrypted = AES_CCM.decrypt(content, MII_DECRYPTION_KEY, nonceWithZeros, undefined, 16);
} catch (error) {
} catch {
throw new Error("Failed to decrypt QR code. It may be invalid or corrupted");
}
@ -40,7 +40,7 @@ export function convertQrCode(bytes: Uint8Array): { mii: Mii; tomodachiLifeMii:
}
return { mii, tomodachiLifeMii };
} catch (error) {
} catch {
throw new Error("Mii data is not valid");
}
}

3
src/types.d.ts vendored
View file

@ -1,5 +1,4 @@
import { DefaultSession, User } from "next-auth";
import { User as PrismaUser } from "@prisma/client";
import { DefaultSession } from "next-auth";
declare module "next-auth" {
interface Session {