adding canvas size button to sidebar - without fonctionality

This commit is contained in:
Artur AGH
2023-10-31 11:38:01 +01:00
parent 46d0d98886
commit 53e8e16191
7 changed files with 161 additions and 23 deletions

View File

@@ -0,0 +1,25 @@
import React from "react";
import { Button } from "@/components/ui/button";
import { deleteShape } from "@/store/app.slice";
import { useAppDispatch } from "@/hooks";
import { BsTrash3 } from "react-icons/bs";
type Props = {
selectedItemId: string;
};
export const DeleteShapeButton = ({ selectedItemId }: Props) => {
const dispatch = useAppDispatch();
const deleteTextHandler = (selectedItemId: string) => {
dispatch(deleteShape(selectedItemId));
};
return (
<Button
variant="destructive"
color="cyan"
onClick={() => deleteTextHandler(selectedItemId)}
>
<BsTrash3 />
</Button>
);
};

View File

@@ -1,5 +1,32 @@
import React from "react";
import { DeleteShapeButton } from "@/components/delete-shape-button";
import { Button } from "@/components/ui/button";
import { TbFlipHorizontal, TbFlipVertical } from "react-icons/tb";
import { Toggle } from "@/components/ui/toggle";
import { useAppDispatch } from "@/hooks";
import { updateImage } from "@/store/app.slice";
export function ImageToolbar() {
return <div>Image toolbar</div>;
export function ImageToolbar({ selectedItemId, currentImage }) {
const dispatch = useAppDispatch();
const flipImageVerticaly = (selectedItemId) => {
dispatch(
updateImage({
id: selectedItemId,
}),
);
};
const flipImageHorizontaly = () => {
console.log("Horizontal Flip");
};
return (
<>
<Toggle onClick={flipImageVerticaly}>
<TbFlipVertical />
</Toggle>
<Toggle>
<TbFlipHorizontal onClick={flipImageHorizontaly} />
</Toggle>
</>
);
}

View File

@@ -3,10 +3,12 @@ import ImageInput from "@/components/layout/sidebar/image-input";
import { SelectTemplate } from "@/components/layout/sidebar/select-template";
import { Button } from "@/components/ui/button";
import { useAppDispatch } from "@/hooks";
import SizeSelect from "@/components/layout/sidebar/size-select";
export function Sidebar() {
return (
<div className="flex h-full w-20 flex-col gap-2 p-2">
<SizeSelect />
<TextInput />
<ImageInput />
<SelectTemplate />

View File

@@ -0,0 +1,54 @@
import React, { useState } from "react";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { PiTextT } from "react-icons/pi";
import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Textarea } from "@/components/ui/textarea";
import { addText } from "@/store/app.slice";
import { SlSizeFullscreen } from "react-icons/sl";
const SizeSelect = () => {
const [open, setOpen] = useState(false);
const handleSizeSelect = () => {
setOpen(false);
};
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
onClick={() => setOpen(true)}
variant="secondary"
className="text-xl"
>
<SlSizeFullscreen />
</Button>
</PopoverTrigger>
<PopoverContent side="right" className="mt-4">
<Card className="p-3">
<CardHeader>
<CardTitle>Sélectionnez la taille d'étiquette</CardTitle>
</CardHeader>
<div className="flex flex-col gap-2">
<Button>Petit Format</Button>
<Button>Moyen Format</Button>
<Button>Grand Format</Button>
</div>
<CardFooter className="mt-8 justify-between">
<Button variant="ghost" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button onClick={handleSizeSelect}>Submit</Button>
</CardFooter>
</Card>
</PopoverContent>
</Popover>
);
};
export default SizeSelect;

View File

@@ -9,6 +9,7 @@ import { type TransformableTextProps } from "@/components/transformable-text";
import { Button } from "@/components/ui/button";
import { useAppDispatch } from "@/hooks";
import { deleteShape } from "@/store/app.slice";
import { DeleteShapeButton } from "@/components/delete-shape-button";
type Props = {
selectedItemId: string;
@@ -22,9 +23,6 @@ export const TextToolbar = ({
}: Props) => {
const dispatch = useAppDispatch();
if (!currentText) return null;
const deleteTextHandler = (selectedItemId) => {
dispatch(deleteShape(selectedItemId));
};
return (
<>
@@ -53,9 +51,6 @@ export const TextToolbar = ({
currentText={currentText}
selectedItemId={selectedItemId}
/>
<Button onClick={() => deleteTextHandler(selectedItemId)}>
Delete Text
</Button>
</>
);
};

View File

@@ -3,6 +3,10 @@ import { ImageToolbar } from "@/components/image-toolbar";
import { TextToolbar } from "@/components/text-toolbar";
import { useAppDispatch, useAppSelector } from "@/hooks";
import { updateText } from "@/store/app.slice";
import { BsTrash3 } from "react-icons/bs";
import { Button } from "@/components/ui/button";
import { DeleteShapeButton } from "@/components/delete-shape-button";
import { Separator } from "@/components/ui/separator";
export const Toolbar = () => {
const dispatch = useAppDispatch();
@@ -27,7 +31,6 @@ export const Toolbar = () => {
return (
<div className=" flex h-[5rem] w-full gap-6 border border-t-0 bg-white p-[1rem]">
{currentImage && <ImageToolbar />}
{currentText && (
<TextToolbar
currentText={currentText}
@@ -35,6 +38,16 @@ export const Toolbar = () => {
onTextColorChange={handleTextColorChange}
/>
)}
{currentImage && (
<ImageToolbar
currentImage={currentImage}
selectedItemId={selectedItemId}
/>
)}
<Separator orientation="vertical" />
<DeleteShapeButton selectedItemId={selectedItemId} />
</div>
);
};

View File

@@ -3,10 +3,10 @@ import type { TransformableTextProps } from "@/components/transformable-text";
import type { PayloadAction } from "@reduxjs/toolkit";
import type { ChangeEvent } from "react";
import { createSlice } from "@reduxjs/toolkit";
import { createSlice, current } from "@reduxjs/toolkit";
import { v1 } from "uuid";
import type { TextConfig } from "konva/lib/shapes/Text";
import { RootState } from "./store";
import type { ImageConfig } from "konva/lib/shapes/Image";
const initialState = {
selectedItemId: null as string | null,
@@ -22,26 +22,30 @@ const defaultTextConfig = {
fontFamily: "Roboto",
};
const defaultImageConfig = {};
export const appSlice = createSlice({
name: "app",
initialState,
reducers: {
addText: (state, action: PayloadAction<{ initialValue: string }>) => {
const textId = v1();
state.texts.push({
text: action.payload.initialValue,
id: textId,
...defaultTextConfig,
});
console.log(current(state.texts));
},
addImage: (state, action: PayloadAction<ChangeEvent<HTMLInputElement>>) => {
const file = action.payload.target.files?.[0];
if (!file) return;
const imageId = v1();
const imageUrl = URL.createObjectURL(file);
state.images.push({ imageUrl, id: imageId });
},
addText: (state, action: PayloadAction<{ initialValue: string }>) => {
const textId = v1();
console.log(state);
state.texts.push({
text: action.payload.initialValue,
id: textId,
...defaultTextConfig,
});
console.log(current(state.images));
},
selectItem: (state, action: PayloadAction<string>) => {
@@ -54,7 +58,7 @@ export const appSlice = createSlice({
updateText: (
state,
action: PayloadAction<{ id: string } & Partial<TextConfig>>,
action: PayloadAction<{ id: string } & Partial<TransformableTextProps>>,
) => {
const textToUpdateIndex = state.texts.findIndex(
(t) => t.id === action.payload.id,
@@ -69,11 +73,28 @@ export const appSlice = createSlice({
};
},
updateImage: (
state,
action: PayloadAction<{ id: string } & Partial<TransformableImageProps>>,
) => {
const imageToUpdateIndex = state.images.findIndex(
(img) => img.id === action.payload.id,
);
const imageToUpdate = state.images[imageToUpdateIndex];
if (!imageToUpdate) return;
state.images[imageToUpdateIndex] = {
...imageToUpdate,
...action.payload,
};
},
deleteShape: (state, action: PayloadAction<string>) => {
console.log(state.texts);
return {
...state,
texts: state.texts.filter((shape) => shape.id !== action.payload),
images: state.images.filter((shape) => shape.id !== action.payload),
};
},
},
@@ -85,5 +106,6 @@ export const {
selectItem,
deselectItem,
updateText,
updateImage,
deleteShape,
} = appSlice.actions;