diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index a11777c..0000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/index.html b/public/index.html index aa069f2..ba11b5c 100644 --- a/public/index.html +++ b/public/index.html @@ -2,42 +2,16 @@ - + - - - - - - React App + Dynamic Tier List
- diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..786e1a7 --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a..0000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/logo512.png b/public/logo512.png deleted file mode 100644 index a4e47a6..0000000 Binary files a/public/logo512.png and /dev/null differ diff --git a/public/manifest.json b/public/manifest.json deleted file mode 100644 index 080d6c7..0000000 --- a/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e05..0000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.tsx b/src/App.tsx index d8f392a..c809dde 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,21 +1,8 @@ -// src/App.tsx -import React, {useState} from 'react'; import './index.css'; import TierList from './components/TierList'; import ImageHolder from './components/ImageHolder'; -import Modal from './components/Modal'; const App = () => { - const [modalOpen, setModalOpen] = useState(true); - - const openModal = () => { - setModalOpen(true); - }; - - const closeModal = () => { - setModalOpen(false); - }; - return (
diff --git a/src/components/ImageHolder.tsx b/src/components/ImageHolder.tsx index e252a54..8929e37 100644 --- a/src/components/ImageHolder.tsx +++ b/src/components/ImageHolder.tsx @@ -1,106 +1,110 @@ -import React, { useState, useEffect } from 'react'; -import { ReactSortable } from 'react-sortablejs'; +import { useState, useEffect } from "react"; +import { ReactSortable } from "react-sortablejs"; interface ImageItem { - id: number; - url: string; + id: number; + url: string; } const ImageHolder = () => { - const [images, setImages] = useState([]); + const [images, setImages] = useState([]); - const handleDrop = (event: DragEvent) => { - event.preventDefault(); - if (event.dataTransfer == null) return; - if ( - event.dataTransfer.getData('application/x-tier') !== "true" - ) { - if (event.dataTransfer.files.length > 0){ - const files = Array.from(event.dataTransfer.files) - files.forEach(file => { - if (!file.type.startsWith('image/')) return - const reader = new FileReader(); - reader.onload = function(event) { - if(event.target == null) return - const imageData = event.target.result; - setImages(prevImages => [ - ...prevImages, - { id: new Date().getTime() + Math.floor(Math.random() * 1000), url: imageData as string}, - ]); - } - reader.readAsDataURL(file); - }); - } - } - }; + const handleDrop = (event: DragEvent) => { + event.preventDefault(); + if (event.dataTransfer == null) return; + if (event.dataTransfer.getData("application/x-tier") !== "true") { + if (event.dataTransfer.files.length > 0) { + const files = Array.from(event.dataTransfer.files); + files.forEach((file) => { + if (!file.type.startsWith("image/")) return; + const reader = new FileReader(); + reader.onload = function (event) { + if (event.target == null) return; + const imageData = event.target.result; + setImages((prevImages) => [ + ...prevImages, + { + id: new Date().getTime() + Math.floor(Math.random() * 1000), + url: imageData as string + } + ]); + }; + reader.readAsDataURL(file); + }); + } + } + }; - const dragStart = (event: DragEvent) =>{ - if(event.dataTransfer == null) return - event.dataTransfer.setData('application/x-tier', 'true'); - } + const dragStart = (event: DragEvent) => { + if (event.dataTransfer == null) return; + event.dataTransfer.setData("application/x-tier", "true"); + }; - useEffect(() => { - const handlePaste = (event: ClipboardEvent) => { - const items = event.clipboardData?.items; - if (items) { - for (let i = 0; i < items.length; i++) { - const item = items[i]; - if (item.type.indexOf('image') !== -1) { - const blob = item.getAsFile(); - if (blob) { - const imageUrl = URL.createObjectURL(blob); - setImages(prevImages => [ - ...prevImages, - { id: new Date().getTime(), url: imageUrl }, - ]); - } - } - } - } - }; + useEffect(() => { + const handlePaste = (event: ClipboardEvent) => { + const items = event.clipboardData?.items; + if (items) { + for (let i = 0; i < items.length; i++) { + const item = items[i]; + if (item.type.indexOf("image") !== -1) { + const blob = item.getAsFile(); + if (blob) { + const imageUrl = URL.createObjectURL(blob); + setImages((prevImages) => [ + ...prevImages, + { id: new Date().getTime(), url: imageUrl } + ]); + } + } + } + } + }; - // Attach paste event listener - document.addEventListener('paste', handlePaste); + document.addEventListener("paste", handlePaste); - const dragOver = (event: DragEvent) => { - event.preventDefault(); - }; + const dragOver = (event: DragEvent) => { + event.preventDefault(); + }; - const drop = (event: DragEvent) => { - event.preventDefault(); - handleDrop(event); - }; + const drop = (event: DragEvent) => { + event.preventDefault(); + handleDrop(event); + }; - // Attach global dragover and drop event listeners - document.addEventListener('dragstart', dragStart); - document.addEventListener('dragover', dragOver); - document.addEventListener('drop', drop); + document.addEventListener("dragstart", dragStart); + document.addEventListener("dragover", dragOver); + document.addEventListener("drop", drop); + + return () => { + document.removeEventListener("paste", handlePaste); + document.removeEventListener("dragover", dragOver); + document.removeEventListener("drop", drop); + }; + }, []); - // Clean up the event listeners on unmount - return () => { - document.removeEventListener('paste', handlePaste); - document.removeEventListener('dragover', dragOver); - document.removeEventListener('drop', drop); - }; - }, []); - - return ( - - {images.length === 0 ? ( -

Drag & Drop or Copy and Paste images in here!
If this is your first time using this you can right click tiers to edit them and drag them about, clicking the plus will add more tiers

- ) : - images.map((image) => ( - - ))} -
- ); + return ( + + {images.length === 0 ? ( +

+ Drag & Drop or Copy and Paste images in here! +
+ If this is your first time using this you can right click tiers to + edit them and drag them about, clicking the plus will add more tiers +

+ ) : ( + images.map((image) => ( + + )) + )} +
+ ); }; export default ImageHolder; diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 9da123e..e8352a1 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -1,89 +1,106 @@ -import React, { useState, ChangeEvent, FormEvent } from 'react'; -import { SketchPicker } from 'react-color'; +import React, { useState, ChangeEvent, FormEvent } from "react"; +import { SketchPicker } from "react-color"; interface ModalProps { - isOpen: boolean; - onClose: () => void; - onAddTier: (color: string, name: string) => void; + isOpen: boolean; + onClose: () => void; + onAddTier: (color: string, name: string) => void; } const Modal: React.FC = ({ isOpen, onClose, onAddTier }) => { - const [name, setName] = useState(''); - const [color, setColor] = useState(''); + const [name, setName] = useState(""); + const [color, setColor] = useState(""); - const handleNameChange = (event: ChangeEvent) => { - setName(event.target.value); - }; + const handleNameChange = (event: ChangeEvent) => { + setName(event.target.value); + }; - const handleColorChange = (newColor: any) => { - setColor(newColor.hex); - }; + const handleColorChange = (newColor: any) => { + setColor(newColor.hex); + }; - const handleSubmit = (event: FormEvent) => { - event.preventDefault(); - // Call the onAddTier function with the new tier's data - onAddTier(color, name); - onClose(); - }; + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + // Call the onAddTier function with the new tier's data + onAddTier(color, name); + onClose(); + }; - const handleClick = (event: React.MouseEvent) => { - const target = event.target as HTMLElement - if(target.id == "modal-bg") onClose(); - } + const handleClick = (event: React.MouseEvent) => { + const target = event.target as HTMLElement; + if (target.id === "modal-bg") onClose(); + }; - if (!isOpen) { - return null; - } + if (!isOpen) { + return null; + } - return ( - - ); + return ( + + ); }; export default Modal; diff --git a/src/components/Tier.tsx b/src/components/Tier.tsx index 1f74764..28aa41f 100644 --- a/src/components/Tier.tsx +++ b/src/components/Tier.tsx @@ -1,144 +1,154 @@ -import React, { useState, useEffect, useRef } from 'react'; -import { ReactSortable } from 'react-sortablejs'; -import { SketchPicker } from 'react-color'; +import React, { useState, useEffect, useRef } from "react"; +import { ReactSortable } from "react-sortablejs"; +import { SketchPicker } from "react-color"; interface ImageItem { - id: number; - url: string; + id: number; + url: string; } interface TierProps { - color: string; - name: string; - onDelete: () => void; + color: string; + name: string; + onDelete: () => void; } const Tier: React.FC = ({ color, name, onDelete }) => { - const [images, setImages] = useState([]); - const [editedColor, setEditedColor] = useState(color); - const [editedName, setEditedName] = useState(name); - const [isContextMenuOpen, setIsContextMenuOpen] = useState(false); - const [contextMenuPosition, setContextMenuPosition] = useState({ left: 0, top: 0 }); - - const contextMenuRef = useRef(null); - - useEffect(() => { - setEditedColor(color); - }, [color]); - - useEffect(() => { - setEditedName(name); - }, [name]); - - useEffect(() => { - const handleOutsideClick = (e: MouseEvent) => { - if ( - isContextMenuOpen && - contextMenuRef.current && - !contextMenuRef.current.contains(e.target as Node) - ) { - handleCloseContextMenu(); - } - }; - - window.addEventListener('click', handleOutsideClick); - - return () => { - window.removeEventListener('click', handleOutsideClick); - }; - }, [isContextMenuOpen]); - - const handleColorChange = (newColor: any) => { - setEditedColor(newColor.hex); - }; - - const handleNameChange = (event: React.ChangeEvent) => { - setEditedName(event.target.value); - }; - - const handleContextMenu = (e: React.MouseEvent) => { - e.preventDefault(); - setIsContextMenuOpen(true); - setContextMenuPosition({ left: e.clientX, top: e.clientY }); - }; - - const handleCloseContextMenu = () => { - setIsContextMenuOpen(false); - }; - - const handleDeleteTier = () => { - onDelete(); - handleCloseContextMenu(); - }; - - return ( -
-
-

- {editedName} -

-
- - {images.map((image) => ( - - ))} - - - {isContextMenuOpen && ( -
-
- - -
-
- - -
-
- - Delete Tier - -
-
- )} -
- ); + const [images, setImages] = useState([]); + const [editedColor, setEditedColor] = useState(color); + const [editedName, setEditedName] = useState(name); + const [isContextMenuOpen, setIsContextMenuOpen] = useState(false); + const [contextMenuPosition, setContextMenuPosition] = useState({ + left: 0, + top: 0 + }); + + const contextMenuRef = useRef(null); + + useEffect(() => { + setEditedColor(color); + }, [color]); + + useEffect(() => { + setEditedName(name); + }, [name]); + + useEffect(() => { + const handleOutsideClick = (e: MouseEvent) => { + if ( + isContextMenuOpen && + contextMenuRef.current && + !contextMenuRef.current.contains(e.target as Node) + ) { + handleCloseContextMenu(); + } + }; + + window.addEventListener("click", handleOutsideClick); + + return () => { + window.removeEventListener("click", handleOutsideClick); + }; + }, [isContextMenuOpen]); + + const handleColorChange = (newColor: any) => { + setEditedColor(newColor.hex); + }; + + const handleNameChange = (event: React.ChangeEvent) => { + setEditedName(event.target.value); + }; + + const handleContextMenu = (e: React.MouseEvent) => { + e.preventDefault(); + setIsContextMenuOpen(true); + setContextMenuPosition({ left: e.clientX, top: e.clientY }); + }; + + const handleCloseContextMenu = () => { + setIsContextMenuOpen(false); + }; + + const handleDeleteTier = () => { + onDelete(); + handleCloseContextMenu(); + }; + + return ( +
+
+

+ {editedName} +

+
+ + {images.map((image) => ( + + ))} + + + {isContextMenuOpen && ( +
+
+ + +
+
+ + +
+
+ + Delete Tier + +
+
+ )} +
+ ); }; export default Tier; diff --git a/src/components/TierList.tsx b/src/components/TierList.tsx index fe6bab6..5b0598b 100644 --- a/src/components/TierList.tsx +++ b/src/components/TierList.tsx @@ -1,59 +1,61 @@ -import React, { useState } from 'react'; -import Tier from './Tier'; -import Modal from './Modal'; -import { ReactSortable } from "react-sortablejs" +import { useState } from "react"; +import Tier from "./Tier"; +import Modal from "./Modal"; +import { ReactSortable } from "react-sortablejs"; const TierList = () => { - const [tiers, setTiers] = useState([ - { color: '#FF7F7F', id: 'S' }, - { color: '#FFBF7F', id: 'A' }, - { color: '#FFDF80', id: 'B' }, - { color: '#FFFF7F', id: 'C' }, - { color: '#BFFF7F', id: 'D' }, - ]); - - const addTier = (color: string, id: string) => { - const newTier = { color, id }; - setTiers((prevTiers) => [...prevTiers, newTier]); - }; - - const deleteTier = (index: number) => { - const updatedTiers = tiers.filter((_, i) => i !== index); - setTiers(updatedTiers); - }; - - const [isModalOpen, setIsModalOpen] = useState(false); - - const openModal = () => { - setIsModalOpen(true); - }; - - const closeModal = () => { - setIsModalOpen(false); - }; - - return ( - <> - - {tiers.map((tier, index) => ( - deleteTier(index)} - /> - ))} - - - - - ); + const [tiers, setTiers] = useState([ + { color: "#FF7F7F", id: "S" }, + { color: "#FFBF7F", id: "A" }, + { color: "#FFDF80", id: "B" }, + { color: "#FFFF7F", id: "C" }, + { color: "#BFFF7F", id: "D" } + ]); + + const addTier = (color: string, id: string) => { + const newTier = { color, id }; + setTiers((prevTiers) => [...prevTiers, newTier]); + }; + + const deleteTier = (index: number) => { + const updatedTiers = tiers.filter((_, i) => i !== index); + setTiers(updatedTiers); + }; + + const [isModalOpen, setIsModalOpen] = useState(false); + + const openModal = () => { + setIsModalOpen(true); + }; + + const closeModal = () => { + setIsModalOpen(false); + }; + + return ( + <> + + {tiers.map((tier, index) => ( + deleteTier(index)} + /> + ))} + + + + + ); }; export default TierList; diff --git a/src/index.css b/src/index.css index eb2dc1e..bd6213e 100644 --- a/src/index.css +++ b/src/index.css @@ -1,27 +1,3 @@ @tailwind base; @tailwind components; -@tailwind utilities; - -.red{ - background-color: #FF7F7F -} - -.orange{ - background-color: #FFBF7F -} - -.gold{ - background-color: #FFDF80 -} - -.yellow{ - background-color: #FFFF7F -} - -.lime{ - background-color: #BFFF7F -} - -.green{ - background-color: #7FFF7F -} +@tailwind utilities; \ No newline at end of file diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file