diff --git a/src/App.tsx b/src/App.tsx index 87e3ee7..70ae375 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,36 +1,22 @@ +import { DndContext, DragEndEvent } from '@dnd-kit/core'; import { useRef } from 'react'; import { useShallow } from 'zustand/shallow'; import './App.scss'; import { TierImage } from './components/Image'; -import { Tier, TierProps } from './components/Tier'; +import { Tier } from './components/Tier'; +import { TierModal } from './components/TierModal'; import useStore from './store'; -const default_tier_levels: TierProps[] = [ - { - name: 'S', - color: 'green', - textColor: 'black', - }, - { - name: 'A', - color: 'yellow', - textColor: 'black', - }, - { - name: 'B', - color: 'red', - textColor: 'black', - }, -]; - interface tierImage { name: string; url: string; category: string; } -function App() { - const [images, addTierImage] = useStore(useShallow(state => [state.images, state.addTierImage])); +const App = () => { + const [images, addTierImage, tierLevels, editTierImage] = useStore( + useShallow(state => [state.images, state.addTierImage, state.tierLevels, state.editTierImage]), + ); const uploadBtn = useRef(null); @@ -39,7 +25,7 @@ function App() { }; const getRandomCategoryName = () => { - const categoryNames = default_tier_levels.flatMap(category => category.name); + const categoryNames = tierLevels.flatMap(category => category.name); return categoryNames[Math.floor(Math.random() * categoryNames.length)]; }; @@ -49,10 +35,18 @@ function App() { }); }; + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + if (active.data.current && over && over.data.current) { + const image: tierImage = active.data.current.image; + editTierImage(image, over.data.current.name); + } + }; + return ( - <> +
- {default_tier_levels.map(tier_level => ( + {tierLevels.map(tier_level => (
- + +
); -} +}; export default App; diff --git a/src/components/Image.tsx b/src/components/Image.tsx index c744dc6..ca07694 100644 --- a/src/components/Image.tsx +++ b/src/components/Image.tsx @@ -1,20 +1,27 @@ import { useDraggable } from '@dnd-kit/core'; -import { tierImage } from '../store'; +import { useEffect } from 'react'; +import { tierImage } from '../dto/tier'; +import useStore from '../store'; import './Image.scss'; interface ImageProps { image: tierImage; - onDragStart?: () => void; } export const TierImage = ({ image }: ImageProps) => { - const { attributes, listeners, setNodeRef, transform } = useDraggable({ + const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({ id: `draggable:${image.name}`, + data: { image }, }); + const setModalOpen = useStore(state => state.setTierLevelModalOpen); const style = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, + zIndex: 99999, } : undefined; + useEffect(() => { + setModalOpen(isDragging); + }, [isDragging, setModalOpen]); return (
{ let color_code = ''; @@ -21,14 +22,17 @@ export const Tier = ({ color, name, textColor }: TierProps) => { color_code = '#ffeaa7'; break; default: - color_code = '#6c5ce7'; + color_code = color; } switch (textColor) { case 'white': text_color_code = '#dfe6e9'; break; - default: + case 'black': text_color_code = '#2d3436'; + break; + default: + text_color_code = textColor; } return ( diff --git a/src/components/TierModal.tsx b/src/components/TierModal.tsx new file mode 100644 index 0000000..3447e2b --- /dev/null +++ b/src/components/TierModal.tsx @@ -0,0 +1,19 @@ +import { useShallow } from 'zustand/shallow'; +import useStore from '../store'; +import { TierModalCategory } from './TierModalCategory'; + +export const TierModal = () => { + const [modalOpen, tierLevels] = useStore(useShallow(state => [state.tierLevelsModalOpen, state.tierLevels])); + + return ( +
+ {tierLevels.map(tier_level => ( + + ))} +
+ ); +}; diff --git a/src/components/TierModalCategory.tsx b/src/components/TierModalCategory.tsx new file mode 100644 index 0000000..7326bca --- /dev/null +++ b/src/components/TierModalCategory.tsx @@ -0,0 +1,67 @@ +import { useDroppable } from '@dnd-kit/core'; +import { useEffect } from 'react'; + +interface TierModalCategoryProps { + color: string; + textColor: string; + name: string; +} + +export const TierModalCategory = ({ color, textColor, name }: TierModalCategoryProps) => { + const { setNodeRef, isOver } = useDroppable({ + id: 'droppable:' + name, + data: { name }, + }); + const getColorCode = (color: string) => { + let color_code = ''; + // TODO: color on hover + switch (color) { + case 'green': + color_code = isOver ? '#55efc4' : '#00b894'; + break; + case 'red': + color_code = isOver ? '#d63031' : '#ff7675'; + break; + case 'yellow': + color_code = isOver ? '#fdcb6e' : '#ffeaa7'; + break; + default: + color_code = color; + } + return color_code; + }; + const getTextColorCode = (textColor: string) => { + let text_color_code = ''; + switch (textColor) { + case 'white': + text_color_code = '#dfe6e9'; + break; + case 'black': + text_color_code = '#2d3436'; + break; + default: + text_color_code = textColor; + } + return text_color_code; + }; + + useEffect(() => { + console.log(isOver); + }, [isOver]); + + const style = { + backgroundColor: getColorCode(color), + color: getTextColorCode(textColor), + }; + + return ( +
+ {name} +
+ ); +}; diff --git a/src/dto/tier.ts b/src/dto/tier.ts new file mode 100644 index 0000000..a2c5428 --- /dev/null +++ b/src/dto/tier.ts @@ -0,0 +1,5 @@ +export interface tierImage { + name: string; + url: string; + category: string; +} diff --git a/src/store.ts b/src/store.ts index ecc77d0..37ec246 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,17 +1,19 @@ import { create } from 'zustand'; import { devtools } from 'zustand/middleware'; - -export interface tierImage { - name: string; - url: string; - category: string; -} +import { TierProps } from './components/Tier'; +import { tierImage } from './dto/tier'; +import { generateTierLevel } from './tools/genarators'; interface tierStore { images: tierImage[]; addTierImage: (image: tierImage) => void; editTierImage: (image: tierImage, tier: string) => void; removeTierImage: (image: tierImage) => void; + tierLevelsModalOpen: boolean; + setTierLevelModalOpen: (open: boolean) => void; + tierLevels: TierProps[]; + addTierLevel: (name: string, color: string, textColor: string) => void; + editTierLevelName: (id: string, name: string) => void; } const useStore = create( @@ -20,11 +22,27 @@ const useStore = create( images: [] as tierImage[], addTierImage: (image: tierImage) => set(state => ({ images: [...state.images, image] })), editTierImage: (image: tierImage, tier: string) => - set(state => ({ images: state.images.map(i => (i.name === image.name ? { ...i, category: tier } : i)) })), + set(state => ({ + images: + image.category === tier + ? state.images + : state.images.map(i => (i.name === image.name ? { ...i, category: tier } : i)), + })), removeTierImage: (image: tierImage) => { URL.revokeObjectURL(image.url); set(state => ({ images: state.images.filter(i => i.name !== image.name) })); }, + tierLevelsModalOpen: false, + setTierLevelModalOpen: (open: boolean) => set({ tierLevelsModalOpen: open }), + tierLevels: [ + generateTierLevel('S', 'green', 'black'), + generateTierLevel('A', 'yellow', 'black'), + generateTierLevel('B', 'red', 'black'), + ] as TierProps[], + addTierLevel: (name: string, color: string, textColor: string) => + set(state => ({ tierLevels: [...state.tierLevels, generateTierLevel(name, color, textColor)] })), + editTierLevelName: (id: string, name: string) => + set(state => ({ tierLevels: state.tierLevels.map(t => (t.id === id ? { ...t, name } : t)) })), }), { name: 'tierStore' }, ), diff --git a/src/tools/genarators.ts b/src/tools/genarators.ts new file mode 100644 index 0000000..d9c4a80 --- /dev/null +++ b/src/tools/genarators.ts @@ -0,0 +1,10 @@ +import { TierProps } from '../components/Tier'; + +export const generateTierLevel = (name: string, color: string, textColor: string): TierProps => { + return { + name, + color, + textColor, + id: crypto.randomUUID(), + }; +};