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";
|
"use client";
|
||||||
|
|
||||||
|
import Image from "next/image";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import useEmblaCarousel from "embla-carousel-react";
|
import useEmblaCarousel from "embla-carousel-react";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
|
|
@ -30,7 +31,7 @@ export default function Carousel({ images, className }: Props) {
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{images.map((src, index) => (
|
{images.map((src, index) => (
|
||||||
<div key={index} className="flex-[0_0_100%]">
|
<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>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ interface Props {
|
||||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
// for use on profiles
|
// for use on profiles
|
||||||
userId?: number;
|
userId?: number;
|
||||||
where?: Record<string, any>;
|
where?: Record<string, object>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function MiiList({ searchParams, userId, where }: Props) {
|
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 ImageList from "./submit/image-list";
|
||||||
import QrUpload from "./submit/qr-upload";
|
import QrUpload from "./submit/qr-upload";
|
||||||
import QrScanner from "./submit/qr-scanner";
|
import QrScanner from "./submit/qr-scanner";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
export default function SubmitForm() {
|
export default function SubmitForm() {
|
||||||
const [files, setFiles] = useState<FileWithPath[]>([]);
|
const [files, setFiles] = useState<FileWithPath[]>([]);
|
||||||
|
|
@ -114,7 +115,7 @@ export default function SubmitForm() {
|
||||||
generatedCode.make();
|
generatedCode.make();
|
||||||
|
|
||||||
setGeneratedQrCodeUrl(generatedCode.createDataURL());
|
setGeneratedQrCodeUrl(generatedCode.createDataURL());
|
||||||
} catch (error) {
|
} catch {
|
||||||
setError("Failed to get and/or generate Mii images");
|
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="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">
|
<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>}
|
{!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>
|
||||||
<div className="relative flex justify-center items-center size-32 aspect-square bg-orange-100 rounded-xl border-2 border-amber-500">
|
<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>}
|
{!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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Image from "next/image";
|
||||||
import { FileWithPath } from "react-dropzone";
|
import { FileWithPath } from "react-dropzone";
|
||||||
import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd";
|
import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
|
|
@ -37,7 +38,7 @@ export default function ImageList({ files, setFiles }: Props) {
|
||||||
{...provided.draggableProps}
|
{...provided.draggableProps}
|
||||||
className="w-full p-4 rounded-xl bg-orange-100 border-2 border-amber-500 flex gap-2 shadow-md my-1"
|
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)}
|
src={URL.createObjectURL(file)}
|
||||||
alt={file.name}
|
alt={file.name}
|
||||||
className="aspect-[3/2] object-contain w-24 rounded-md bg-orange-300 border-2 border-orange-400"
|
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);
|
setSelectedDeviceId(videoDevices[0].deviceId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [isOpen]);
|
}, [isOpen, selectedDeviceId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isOpen && !permissionGranted) return;
|
if (!isOpen && !permissionGranted) return;
|
||||||
requestRef.current = requestAnimationFrame(scanQRCode);
|
requestRef.current = requestAnimationFrame(scanQRCode);
|
||||||
}, [permissionGranted]);
|
}, [isOpen, permissionGranted, scanQRCode]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ interface Props {
|
||||||
export default function QrUpload({ setQrBytesRaw }: Props) {
|
export default function QrUpload({ setQrBytesRaw }: Props) {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
|
|
||||||
const onDrop = useCallback((acceptedFiles: FileWithPath[]) => {
|
const onDrop = useCallback(
|
||||||
|
(acceptedFiles: FileWithPath[]) => {
|
||||||
acceptedFiles.forEach((file) => {
|
acceptedFiles.forEach((file) => {
|
||||||
// Scan QR code
|
// Scan QR code
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|
@ -39,7 +40,9 @@ export default function QrUpload({ setQrBytesRaw }: Props) {
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
});
|
});
|
||||||
}, []);
|
},
|
||||||
|
[setQrBytesRaw]
|
||||||
|
);
|
||||||
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
const { getRootProps, getInputProps } = useDropzone({
|
||||||
onDrop,
|
onDrop,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState, KeyboardEvent } from "react";
|
import React, { useState } from "react";
|
||||||
import { useCombobox, useMultipleSelection } from "downshift";
|
import { useCombobox } from "downshift";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -135,7 +135,7 @@ export default function TagSelector({ tags, setTags }: Props) {
|
||||||
setInputValue("");
|
setInputValue("");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Add "{inputValue}"
|
Add "{inputValue}"
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ export default async function MiiPage({ params }: Props) {
|
||||||
key={index}
|
key={index}
|
||||||
src={src}
|
src={src}
|
||||||
width={256}
|
width={256}
|
||||||
height={1}
|
height={170}
|
||||||
alt="mii screenshots"
|
alt="mii screenshots"
|
||||||
className="rounded-xl bg-zinc-300 border-2 border-zinc-300 shadow-md aspect-[3/2] h-full object-contain"
|
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");
|
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} />;
|
return <MiiList searchParams={searchParams} />;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,8 @@ export default function PrivacyPage() {
|
||||||
<section>
|
<section>
|
||||||
<p className="mb-2">
|
<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
|
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,
|
deleted at any time by going to your profile page, clicking the settings icon, and clicking the 'Delete Account' button. Upon
|
||||||
your data will be promptly removed from our servers.
|
clicking, your data will be promptly removed from our servers.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export default async function SearchPage({ searchParams }: Props) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-lg">
|
<p className="text-lg">
|
||||||
Search results for "<span className="font-bold">{query}</span>"
|
Search results for "<span className="font-bold">{query}</span>"
|
||||||
</p>
|
</p>
|
||||||
<MiiList
|
<MiiList
|
||||||
searchParams={searchParams}
|
searchParams={searchParams}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export default function PrivacyPage() {
|
||||||
<a href="/privacy" className="text-blue-700">
|
<a href="/privacy" className="text-blue-700">
|
||||||
Privacy Policy
|
Privacy Policy
|
||||||
</a>{" "}
|
</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">
|
<a href="mailto:hello@trafficlunar.net" className="text-blue-700">
|
||||||
hello@trafficlunar.net
|
hello@trafficlunar.net
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -70,8 +70,8 @@ export default function PrivacyPage() {
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<p className="mb-2">
|
<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
|
This service is provided "as is" and without any warranties. We are not responsible for any user-generated content or the
|
||||||
users on the site. You use the site at your own risk.
|
actions of users on the site. You use the site at your own risk.
|
||||||
</p>
|
</p>
|
||||||
<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
|
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>
|
<section>
|
||||||
<p className="mb-2">
|
<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
|
This site is not affiliated with, endorsed by, or associated with Nintendo in any way. "Mii" and all related character designs
|
||||||
trademarks of Nintendo Co., Ltd.
|
are trademarks of Nintendo Co., Ltd.
|
||||||
</p>
|
</p>
|
||||||
<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
|
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_DIMENSIONS = 1024;
|
||||||
const MAX_IMAGE_SIZE = 1024 * 1024; // 1 MB
|
const MAX_IMAGE_SIZE = 1024 * 1024; // 1 MB
|
||||||
|
|
||||||
const THRESHOLD = 0.5;
|
// const THRESHOLD = 0.5;
|
||||||
|
|
||||||
// tf.enableProdMode();
|
// tf.enableProdMode();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export function convertQrCode(bytes: Uint8Array): { mii: Mii; tomodachiLifeMii:
|
||||||
let decrypted: Uint8Array<ArrayBufferLike> = new Uint8Array();
|
let decrypted: Uint8Array<ArrayBufferLike> = new Uint8Array();
|
||||||
try {
|
try {
|
||||||
decrypted = AES_CCM.decrypt(content, MII_DECRYPTION_KEY, nonceWithZeros, undefined, 16);
|
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");
|
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 };
|
return { mii, tomodachiLifeMii };
|
||||||
} catch (error) {
|
} catch {
|
||||||
throw new Error("Mii data is not valid");
|
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 { DefaultSession } from "next-auth";
|
||||||
import { User as PrismaUser } from "@prisma/client";
|
|
||||||
|
|
||||||
declare module "next-auth" {
|
declare module "next-auth" {
|
||||||
interface Session {
|
interface Session {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue