fix: build errors
This commit is contained in:
parent
4a65994d35
commit
516923905d
15 changed files with 65 additions and 57 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 "{inputValue}"
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 'Delete Account' button. Upon
|
||||
clicking, your data will be promptly removed from our servers.
|
||||
</p>
|
||||
</section>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -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 "<span className="font-bold">{query}</span>"
|
||||
</p>
|
||||
<MiiList
|
||||
searchParams={searchParams}
|
||||
|
|
|
|||
|
|
@ -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 "Data Deletion") 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 "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.
|
||||
</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. "Mii" 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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
3
src/types.d.ts
vendored
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue