From 977b750476487a73085c450759b6baa46d2a4c41 Mon Sep 17 00:00:00 2001 From: Artur AGH Date: Tue, 19 Dec 2023 09:36:29 +0100 Subject: [PATCH] styling test version --- src/components/layout/layout.tsx | 15 +- .../layout/sidebar/image-gallery.tsx | 35 +---- .../sidebar/image-gallery/image-gallery.tsx | 146 ++++++++++++++++++ .../sidebar/image-input/image-input.tsx | 36 +++++ src/components/layout/sidebar/layers.tsx | 67 -------- .../layout/sidebar/layers/layers.tsx | 48 ++++++ src/components/layout/sidebar/sidebar.tsx | 73 +++++++-- .../stage-settings/stage-background.tsx | 28 ++++ .../sidebar/stage-settings/stage-size.tsx | 42 +++++ src/components/layout/sidebar/text-input.tsx | 11 +- .../layout/sidebar/text-input/text-input.tsx | 45 ++++++ src/components/ui/tabs.tsx | 30 ++-- 12 files changed, 439 insertions(+), 137 deletions(-) create mode 100644 src/components/layout/sidebar/image-gallery/image-gallery.tsx create mode 100644 src/components/layout/sidebar/image-input/image-input.tsx delete mode 100644 src/components/layout/sidebar/layers.tsx create mode 100644 src/components/layout/sidebar/layers/layers.tsx create mode 100644 src/components/layout/sidebar/stage-settings/stage-background.tsx create mode 100644 src/components/layout/sidebar/stage-settings/stage-size.tsx create mode 100644 src/components/layout/sidebar/text-input/text-input.tsx diff --git a/src/components/layout/layout.tsx b/src/components/layout/layout.tsx index 5763b00..8f7b55f 100644 --- a/src/components/layout/layout.tsx +++ b/src/components/layout/layout.tsx @@ -3,7 +3,9 @@ import React from "react"; import { Sidebar } from "@/components/layout/sidebar/sidebar"; import Header from "@/components/layout/header/Header"; import { Separator } from "@/components/ui/separator"; -import { Tabs } from "@/components/ui/tabs"; +import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/button"; +import { PlusCircledIcon } from "@radix-ui/react-icons"; type Props = { children: ReactNode; @@ -11,14 +13,17 @@ type Props = { export const Layout = ({ children }: Props) => { return ( -
+
-
-
+
+
{children}
-
+
diff --git a/src/components/layout/sidebar/image-gallery.tsx b/src/components/layout/sidebar/image-gallery.tsx index c340900..5cbcbfa 100644 --- a/src/components/layout/sidebar/image-gallery.tsx +++ b/src/components/layout/sidebar/image-gallery.tsx @@ -101,40 +101,7 @@ export const ImageGallery = () => { - - - - Template - - - setQuery(e.target.value)} - /> - -
- {photos?.map((p, i) => ( -
- {"image"} -
- ))} -
-
-
+ ); }; diff --git a/src/components/layout/sidebar/image-gallery/image-gallery.tsx b/src/components/layout/sidebar/image-gallery/image-gallery.tsx new file mode 100644 index 0000000..0ca4a32 --- /dev/null +++ b/src/components/layout/sidebar/image-gallery/image-gallery.tsx @@ -0,0 +1,146 @@ +import React, { + ChangeEvent, + type ElementRef, + useEffect, + useRef, + useState, +} from "react"; +import { Card, CardHeader, CardTitle } from "@/components/ui/card"; +import axios from "axios"; +import * as process from "process"; +import Image from "next/image"; +import { Input } from "@/components/ui/input"; +import { addImage } from "@/store/app.slice"; + +type Props = { + open: boolean; +}; + +export const ImageGallery = ({ open }: Props) => { + const [query, setQuery] = useState(""); + const [page, setPage] = useState(1); + const [isLoading, setIsLoading] = useState(false); + + const [photos, setPhotos] = useState([]); + + const scrollAreaRef = useRef>(null); + + const mainUrl = "https://api.unsplash.com/photos"; + const searchUrl = "https://api.unsplash.com/search/photos"; + const clientID = `?client_id=${process.env.NEXT_PUBLIC_ACCESS_KEY}`; + + useEffect(() => { + fetchImages(); + }, [query, page]); + + const fetchImages = async () => { + setIsLoading(true); + let url; + const urlPage = `&page=${page}`; + const urlQuery = `&query=${query}`; + + if (query) { + url = `${searchUrl}${clientID}${urlPage}${urlQuery}`; + console.log(url); + } else { + url = `${mainUrl}${clientID}${urlPage}`; + } + + try { + const { data } = await axios.get(url); + + setPhotos((oldPhotos) => { + if (query && page === 1) { + return data.results; + } else if (query) { + return [...oldPhotos, ...data.results]; + } else { + console.log(data); + return [...oldPhotos, ...data]; + } + }); + setIsLoading(false); + } catch (error) { + console.log(error); + setIsLoading(false); + } + }; + + useEffect(() => { + const ref = scrollAreaRef.current; + const handler = () => { + if (scrollAreaRef.current) { + console.log( + scrollAreaRef.current.clientHeight + scrollAreaRef.current.scrollTop, + scrollAreaRef.current.scrollHeight - 2, + ); + } + if ( + isLoading || + !scrollAreaRef.current || + scrollAreaRef.current.clientHeight + scrollAreaRef.current.scrollTop < + scrollAreaRef.current.scrollHeight - 2 + ) { + return; + } + + setPage((oldPage) => { + return oldPage + 1; + }); + }; + const handleImageUploaded = () => { + if (!file) return; + const img = document.createElement("img"); + const imageUrl = URL.createObjectURL(file); + img.onload = () => { + dispatch(addImage({ imageUrl, width: img.width, height: img.height })); + img.remove(); + }; + img.src = imageUrl; + img.style.cssText = "display: none;"; + document.body.appendChild(img); + }; + scrollAreaRef.current?.addEventListener("scroll", handler); + return () => ref?.removeEventListener("scroll", handler); + }, [isLoading, open]); + + const handleImageAdd = (e) => { + console.log(e.target); + }; + + return ( + + + Template + + + setQuery(e.target.value)} + /> + +
+ {photos?.map((p, i) => ( +
handleImageAdd(e)} + className="rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary" + > + {"image"} +
+ ))} +
+
+ ); +}; diff --git a/src/components/layout/sidebar/image-input/image-input.tsx b/src/components/layout/sidebar/image-input/image-input.tsx new file mode 100644 index 0000000..543ec86 --- /dev/null +++ b/src/components/layout/sidebar/image-input/image-input.tsx @@ -0,0 +1,36 @@ +import React, { type ChangeEvent } from "react"; +import { addImage } from "@/store/app.slice"; +import { useAppDispatch } from "@/hooks"; +import { + Card, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; + +export default function ImageInput() { + const dispatch = useAppDispatch(); + + const handleImageUploaded = (e: ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + const img = document.createElement("img"); + const imageUrl = URL.createObjectURL(file); + img.onload = () => { + dispatch(addImage({ imageUrl, width: img.width, height: img.height })); + img.remove(); + }; + img.src = imageUrl; + img.style.cssText = "display: none;"; + document.body.appendChild(img); + }; + return ( + + + + Téléchargez votre image et ajoutez-la à votre étiquette. + + + ); +} diff --git a/src/components/layout/sidebar/layers.tsx b/src/components/layout/sidebar/layers.tsx deleted file mode 100644 index 1bad938..0000000 --- a/src/components/layout/sidebar/layers.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from "react"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { RxStack } from "react-icons/rx"; -import { useAppDispatch, useAppSelector } from "@/hooks"; -import { selectItem, setStageItems } from "@/store/app.slice"; -import { closestCenter, DndContext, type DragEndEvent } from "@dnd-kit/core"; -import { - arrayMove, - SortableContext, - verticalListSortingStrategy, -} from "@dnd-kit/sortable"; -import LayerItem from "@/components/layer-item"; - -export const Layers = () => { - const dispatch = useAppDispatch(); - const currentStep = useAppSelector((state) => state.app.currentStep); - const items = useAppSelector( - (state) => state.app.history[currentStep]?.items, - ); - if (!items) return; - const handleDragEnd = (e: DragEndEvent) => { - const { active, over } = e; - const oldIndex = items.findIndex((item) => item.id === active.id); - const newIndex = items.findIndex((item) => item.id === over?.id); - const result = arrayMove(items, oldIndex, newIndex); - dispatch(setStageItems(result)); - dispatch(selectItem(active.id)); - }; - - return ( - - - - - - - - Layers - - - - - {items.map((item) => ( - - ))} - - - - - - - ); -}; diff --git a/src/components/layout/sidebar/layers/layers.tsx b/src/components/layout/sidebar/layers/layers.tsx new file mode 100644 index 0000000..40177e2 --- /dev/null +++ b/src/components/layout/sidebar/layers/layers.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { useAppDispatch, useAppSelector } from "@/hooks"; +import { selectItem, setStageItems } from "@/store/app.slice"; +import { closestCenter, DndContext, type DragEndEvent } from "@dnd-kit/core"; +import { + arrayMove, + SortableContext, + verticalListSortingStrategy, +} from "@dnd-kit/sortable"; +import LayerItem from "@/components/layer-item"; + +export const Layers = () => { + const dispatch = useAppDispatch(); + const currentStep = useAppSelector((state) => state.app.currentStep); + const items = useAppSelector( + (state) => state.app.history[currentStep]?.items, + ); + if (!items) return; + const handleDragEnd = (e: DragEndEvent) => { + const { active, over } = e; + const oldIndex = items.findIndex((item) => item.id === active.id); + const newIndex = items.findIndex((item) => item.id === over?.id); + const result = arrayMove(items, oldIndex, newIndex); + dispatch(setStageItems(result)); + dispatch(selectItem(active.id)); + }; + + return ( + + + Layers + + + + + {items.map((item) => ( + + ))} + + + + + ); +}; diff --git a/src/components/layout/sidebar/sidebar.tsx b/src/components/layout/sidebar/sidebar.tsx index d3e3c69..7c15e4e 100644 --- a/src/components/layout/sidebar/sidebar.tsx +++ b/src/components/layout/sidebar/sidebar.tsx @@ -1,21 +1,64 @@ -import { TextInput } from "@/components/layout/sidebar/text-input"; -import ImageInput from "@/components/layout/sidebar/image-input"; -import SizeSelect from "@/components/layout/sidebar/size-select"; -import { BackgroundSelect } from "@/components/layout/sidebar/background-select"; -import { Layers } from "@/components/layout/sidebar/layers"; -import { SelectTemplate } from "@/components/layout/sidebar/select-template"; -import { ImageGallery } from "@/components/layout/sidebar/image-gallery"; +import TextInput from "@/components/layout/sidebar/text-input/text-input"; +import ImageInput from "@/components/layout/sidebar/image-input/image-input"; +import { Layers } from "@/components/layout/sidebar/layers/layers"; +import { ImageGallery } from "@/components/layout/sidebar/image-gallery/image-gallery"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import React, { useState } from "react"; +import { LuLayoutTemplate } from "react-icons/lu"; +import { + GearIcon, + ImageIcon, + LayersIcon, + TextIcon, +} from "@radix-ui/react-icons"; +import { StageSize } from "@/components/layout/sidebar/stage-settings/stage-size"; +import { StageBackground } from "@/components/layout/sidebar/stage-settings/stage-background"; export function Sidebar() { + const [openGallery, setOpenGallery] = useState(false); + return ( -
- - - - - - - +
+ + + + + + + + + + + + setOpenGallery(true)} + open={openGallery} + onOpenChange={setOpenGallery} + value="gallery" + > + + + + + + + + + + + + + + + + + + + + + + +
); } diff --git a/src/components/layout/sidebar/stage-settings/stage-background.tsx b/src/components/layout/sidebar/stage-settings/stage-background.tsx new file mode 100644 index 0000000..e7a595f --- /dev/null +++ b/src/components/layout/sidebar/stage-settings/stage-background.tsx @@ -0,0 +1,28 @@ +import React, { useState } from "react"; +import { Label } from "@/components/ui/label"; +import { useAppDispatch, useAppSelector } from "@/hooks"; +import { selectBackground } from "@/store/app.slice"; + +export const StageBackground = () => { + const dispatch = useAppDispatch(); + const bgColor = useAppSelector((state) => state.app.backgroundColor); + + const handleBackgroundSelect = (color: string) => { + dispatch(selectBackground(color)); + }; + return ( +
+ +
+ ); +}; diff --git a/src/components/layout/sidebar/stage-settings/stage-size.tsx b/src/components/layout/sidebar/stage-settings/stage-size.tsx new file mode 100644 index 0000000..0b82d90 --- /dev/null +++ b/src/components/layout/sidebar/stage-settings/stage-size.tsx @@ -0,0 +1,42 @@ +import React, { useState } from "react"; +import { Card, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { useAppDispatch } from "@/hooks"; +import { updateStage } from "@/store/app.slice"; + +export const StageSize = () => { + const dispatch = useAppDispatch(); + + const handleStageSizeSelect = ( + width: number | undefined, + height: number | undefined, + ) => { + dispatch(updateStage({ width, height })); + }; + return ( + + + {`Sélectionnez la taille d'étiquette`} + + +
+ + + +
+ + {/**/} + {/* */} + {/* */} + {/**/} +
+ ); +}; diff --git a/src/components/layout/sidebar/text-input.tsx b/src/components/layout/sidebar/text-input.tsx index 873c75d..734875a 100644 --- a/src/components/layout/sidebar/text-input.tsx +++ b/src/components/layout/sidebar/text-input.tsx @@ -8,7 +8,13 @@ import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; import { addText } from "@/store/app.slice"; import { useAppDispatch } from "@/hooks"; -import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { RxText } from "react-icons/rx"; export function TextInput() { @@ -51,6 +57,9 @@ export function TextInput() { + + Téléchargez votre image et ajoutez-la à votre étiquette. + diff --git a/src/components/layout/sidebar/text-input/text-input.tsx b/src/components/layout/sidebar/text-input/text-input.tsx new file mode 100644 index 0000000..4d62c51 --- /dev/null +++ b/src/components/layout/sidebar/text-input/text-input.tsx @@ -0,0 +1,45 @@ +import React, { type ChangeEvent, useState } from "react"; +import { + Card, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Textarea } from "@/components/ui/textarea"; +import { Button } from "@/components/ui/button"; +import { addText } from "@/store/app.slice"; +import { useAppDispatch } from "@/hooks"; + +export default function TextInput() { + const dispatch = useAppDispatch(); + const [inputText, setInputText] = useState(""); + const handleTextAdd = () => { + dispatch(addText({ initialValue: inputText })); + }; + const handleInputChange = (e: ChangeEvent) => { + setInputText(e.target.value); + }; + return ( + + + Text + +