This commit is contained in:
2023-12-20 17:29:59 +08:00
parent 1bf86099d8
commit ec316824b7
8 changed files with 139 additions and 134 deletions

BIN
public/icon/model1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
public/icon/model2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,12 +1,13 @@
import { useState } from "react"; import { useState } from "react";
import { AddIcon } from "@chakra-ui/icons"; import { AddIcon, DeleteIcon } from "@chakra-ui/icons";
import { import {
Button, Button,
Modal, Modal,
ModalBody, ModalBody,
ModalContent, ModalContent,
ModalOverlay, ModalOverlay,
Image Image,
IconButton
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { pickFile } from "@/lib/upload"; import { pickFile } from "@/lib/upload";
import useModelStore, { StickerType } from "@/store/useModelStore"; import useModelStore, { StickerType } from "@/store/useModelStore";
@ -30,10 +31,13 @@ const LogoPanel = () => {
setActiveDecal(decal.id) setActiveDecal(decal.id)
}} }}
key={decal.id} key={decal.id}
className={`mb-2 flex h-12 w-full cursor-pointer items-center justify-between rounded bg-white px-2 shadow ${decal.id === activeDecal ? "border-2 border-green-100" : "" className={`mb-2 flex h-12 w-full cursor-pointer items-center justify-between rounded bg-white px-2 shadow ${decal.id === activeDecal ? "border-2 border-green-100 bg-blue-200" : ""
}`} }`}
> >
<Image className={"w-12 h-12 object-contain"} src={decal.url} /> <Image className={"w-12 h-12 object-contain"} src={decal.url} />
<IconButton icon={<DeleteIcon />} aria-label={""} colorScheme="red" size={"xs"} onClick={() => {
setDecals(decals.filter(el => el.id !== decal.id))
}} />
</li> </li>
))} ))}
</ul> </ul>

View File

@ -26,13 +26,12 @@ const RightPanel = () => {
onClick={() => { onClick={() => {
setActiveModel(index); setActiveModel(index);
}} }}
className={`${ className={`${activeModel === index ? "border-2 border-green-300" : ""
activeModel === index ? "border-2 border-green-300" : "" } flex aspect-square items-center justify-center overflow-hidden rounded-xl bg-blue-100`}
} flex aspect-square items-center justify-center overflow-hidden rounded-xl bg-blue-100`}
> >
<img <img
className="h-full w-full object-cover" className="h-full w-full object-cover"
src={models[activeModel].icon} src={models[index].icon}
/> />
</div> </div>
))} ))}

View File

@ -1,11 +1,11 @@
import useModelStore, { StickerType } from "@/store/useModelStore"; import useModelStore, { StickerType } from "@/store/useModelStore";
import { AddIcon, DeleteIcon, EditIcon } from "@chakra-ui/icons"; import { AddIcon, DeleteIcon, EditIcon } from "@chakra-ui/icons";
import { import {
Button, Button,
FormControl, FormControl,
FormLabel, FormLabel,
IconButton, IconButton,
Input, Input,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useState } from "react"; import { useState } from "react";
import { fabric } from "fabric"; import { fabric } from "fabric";
@ -13,125 +13,126 @@ import { Vector3 } from "three";
import { v4 } from "uuid"; import { v4 } from "uuid";
const TextLabelPanel = () => { const TextLabelPanel = () => {
const decals = useModelStore((state) => state.decals); const decals = useModelStore((state) => state.decals);
const setDecals = useModelStore((state) => state.setDecals); const setDecals = useModelStore((state) => state.setDecals);
const setActiveDecal = useModelStore((state) => state.setActiveDecal); const setActiveDecal = useModelStore((state) => state.setActiveDecal);
const activeDecal = useModelStore((state) => state.activeDecal); const activeDecal = useModelStore((state) => state.activeDecal);
const [editing, setEditing] = useState(false); const [editing, setEditing] = useState(false);
const [text, setText] = useState(""); const [text, setText] = useState("");
const [color, setColor] = useState("#ffffff"); const [color, setColor] = useState("#ffffff");
return ( return (
<> <>
{editing ? ( {editing ? (
<div className={"rounded bg-white p-4"}> <div className={"rounded bg-white p-4"}>
<h2 className="font-bold"></h2> <h2 className="font-bold"></h2>
<FormControl> <FormControl>
<FormLabel></FormLabel> <FormLabel></FormLabel>
<Input <Input
value={text} value={text}
onInput={(ev) => { onInput={(ev) => {
setText(() => (ev.target as HTMLInputElement).value); setText(() => (ev.target as HTMLInputElement).value);
}} }}
/> />
</FormControl> </FormControl>
<FormControl> <FormControl>
<FormLabel></FormLabel> <FormLabel></FormLabel>
<Input <Input
type="color" type="color"
value={color} value={color}
onInput={(ev) => { onInput={(ev) => {
setColor(() => (ev.target as HTMLInputElement).value); setColor(() => (ev.target as HTMLInputElement).value);
}} }}
/> />
</FormControl> </FormControl>
<div className={"mt-2 flex justify-center"}> <div className={"mt-2 flex justify-center"}>
<Button <Button
colorScheme="messenger" colorScheme="messenger"
size={"sm"} size={"sm"}
onClick={() => { onClick={() => {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
const fabricText = new fabric.Text(text, { const fabricText = new fabric.Text(text, {
fill: color, fill: color,
}); // fontFamily: 'sans-serif'
const fabricCanvas = new fabric.Canvas(canvas, { });
width: fabricText.width, const fabricCanvas = new fabric.Canvas(canvas, {
height: fabricText.height, width: fabricText.width,
}); height: fabricText.height,
});
fabricCanvas.add(fabricText); fabricCanvas.add(fabricText);
const id = v4(); const id = v4();
setActiveDecal(id); setActiveDecal(id);
setDecals([ setDecals([
...decals, ...decals,
{ {
id, id,
postion: new Vector3(0, 0, 0), postion: new Vector3(0, 0, 0),
text, text,
url: fabricCanvas.toDataURL(), url: fabricCanvas.toDataURL(),
type: StickerType.text, type: StickerType.text,
}, },
]); ]);
setText(() => ""); setText(() => "");
setColor(() => "#ffffff"); setColor(() => "#ffffff");
setEditing(() => false); setEditing(() => false);
}} }}
> >
</Button> </Button>
</div> </div>
</div>
) : (
<ul>
{decals
.filter((el) => el.type === StickerType.text)
.map((text) => (
<li
onClick={() => {
setActiveDecal(text.id);
}}
key={text.id}
className={`mt-2 flex h-12 w-full cursor-pointer items-center justify-between rounded bg-white px-2 shadow ${
activeDecal === text.id ? "border-2 border-green-100" : ""
}`}
>
<span>{text.text}</span>
<div className={"right"}>
<IconButton
onClick={(ev) => {
ev.stopPropagation();
}}
size={"xs"}
icon={<EditIcon />}
aria-label={""}
/>
<IconButton
className={"ml-1"}
onClick={(ev) => {
ev.stopPropagation();
}}
size={"xs"}
icon={<DeleteIcon />}
aria-label={""}
/>
</div> </div>
</li> ) : (
))} <ul>
</ul> {decals
)} .filter((el) => el.type === StickerType.text)
<div className="mt-4 flex justify-center"> .map((text) => (
<Button <li
colorScheme="messenger" onClick={() => {
onClick={() => { setActiveDecal(text.id);
// setOpen(() => true) }}
setEditing(() => true); key={text.id}
}} className={`mb-2 flex h-12 w-full cursor-pointer items-center justify-between rounded bg-white px-2 shadow ${activeDecal === text.id ? "border-2 border-green-100 bg-blue-200" : ""
leftIcon={<AddIcon />} }`}
> >
<span>{text.text}</span>
</Button> <div className={"right"}>
</div> <IconButton
</> onClick={(ev) => {
); ev.stopPropagation();
}}
size={"xs"}
icon={<EditIcon />}
aria-label={""}
/>
<IconButton
className={"ml-1"}
onClick={(ev) => {
ev.stopPropagation();
setDecals(decals.filter(el => el.id !== text.id))
}}
size={"xs"}
icon={<DeleteIcon />}
aria-label={""}
colorScheme="red"
/>
</div>
</li>
))}
</ul>
)}
<div className="mt-4 flex justify-center">
<Button
colorScheme="messenger"
onClick={() => {
setEditing(() => true);
}}
leftIcon={<AddIcon />}
>
</Button>
</div>
</>
);
}; };
export default TextLabelPanel; export default TextLabelPanel;

View File

@ -53,7 +53,6 @@ const CapModel = () => {
y / models[activeModel].scale, y / models[activeModel].scale,
z / models[activeModel].scale, z / models[activeModel].scale,
); );
console.log(pos);
setDecalPositon(activeDecal, pos); setDecalPositon(activeDecal, pos);
} }
}} }}
@ -76,7 +75,6 @@ const CapModel = () => {
) : ( ) : (
<meshStandardMaterial color="gray" /> <meshStandardMaterial color="gray" />
)} )}
</mesh> </mesh>
); );
} }

View File

@ -2,7 +2,7 @@ export const models = [
{ {
name: "版型1", name: "版型1",
path: "/models/baseball_cap_3d.glb", path: "/models/baseball_cap_3d.glb",
icon: "/icon/baseball_cap_3d.png", icon: "/icon/model1.jpg",
scale: 18, scale: 18,
mesh: [ mesh: [
{ {
@ -49,7 +49,7 @@ export const models = [
}, },
{ {
name: "版型2", name: "版型2",
icon: "/icon/baseball_cap_3d_logo.png", icon: "/icon/model2.jpg",
path: "/models/baseball_cap.glb", path: "/models/baseball_cap.glb",
scale: 0.02, scale: 0.02,
mesh: [ mesh: [

View File

@ -1,10 +1,13 @@
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc"; import react from "@vitejs/plugin-react-swc";
import {fileURLToPath, URL} from 'node:url' import { fileURLToPath, URL } from 'node:url'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
server: {
host: true
},
resolve: { resolve: {
alias: { alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)) "@": fileURLToPath(new URL("./src", import.meta.url))