오늘의 목표

수행 내역

import React, { useState } from 'react';
import ReactGridLayout from 'react-grid-layout';
import './MyPage.scss';

const initialLayout = [
    { i: 'BED', x: 0, y: 0, w: 1, h: 1 },
    { i: 'dark-magician', x: 1, y: 0, w: 1, h: 1 },
    { i: 'kuriboh', x: 2, y: 0, w: 1, h: 1 },
    { i: 'spell-caster', x: 3, y: 0, w: 1, h: 1 },
    { i: 'summoned-skull', x: 0, y: 1, w: 1, h: 1 },
];

const MyPage = () => {
    const [layout, setLayout] = useState(initialLayout);

    const [newItemCounter, setNewItemCounter] = useState(0);

    const onDrop = (currentLayout, droppedItemProps) => {
        setNewItemCounter((prevCounter) => {
            const newId = `new-item-${prevCounter}`;
            const newItem = {
                i: newId,
                x: droppedItemProps.x,
                y: droppedItemProps.y,
                w: 1,
                h: 1,
            };
            setLayout((prevLayout) => [...prevLayout, newItem]);

            console.log(newItem);
            return prevCounter + 1;
        });

        console.log('레이아웃', layout);
        console.log('아이템', droppedItemProps);
        setNewItemCounter((prevCounter) => prevCounter + 1);
    };

    const renderGridItems = () => {
        return layout.map((item) => {
            const isNewItem = item.i.startsWith('new-item');
            const itemText = isNewItem
                ? `New Item ${item.i.split('-').pop()}`
                : item.i.replace(/-/g, ' ').toUpperCase();

            return (
                <div className={isNewItem ? 'new-grid-item' : item.i} key={item.i}>
                    <div className='grid-item-text'>{itemText}</div>
                </div>
            );
        });
    };

    return (
        <div id='MyPage'>
            <div className='user-info-area'>
                <div className='profile-photo'>
                    <img id='user-profile-photo' src='' alt='' />
                </div>
                <div className='user-introduction'>
                    <textarea></textarea>
                </div>
            </div>
            <div className='blog-area'>
                <div className='floating-droppables-ui'>
                    <div
                        className='droppable-element'
                        draggable={true}
                        unselectable='on'
                        onDragStart={(e) => e.dataTransfer.setData('text/plain', '')}
                    >
                        Drag Element1
                    </div>
                    <div
                        className='droppable-element'
                        draggable={true}
                        unselectable='on'
                        onDragStart={(e) => e.dataTransfer.setData('text/plain', '')}
                    >
                        Drag Element2
                    </div>
                    <div
                        className='droppable-element'
                        draggable={true}
                        unselectable='on'
                        onDragStart={(e) => e.dataTransfer.setData('text/plain', '')}
                    >
                        Drag Element3
                    </div>
                </div>
                <ReactGridLayout
                    layout={layout}
                    cols={5}
                    rowHeight={170}
                    width={900}
                    onDrop={onDrop}
                    isDroppable={true}
                    compactType={'vertical'}
                >
                    {renderGridItems()}
                </ReactGridLayout>
            </div>
        </div>
    );
};

export default MyPage;
#MyPage {
    position: relative;
    display: flex;
    gap: 30px;

    .user-info-area {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 40px;
        padding-top: 60px;
        flex: 0.3;

        .profile-photo {
            width: 250px;
            height: 250px;
            border-radius: 50%;
            background-color: bisque;
        }

        .user-introduction {
            width: 100%;

            textarea {
                width: 100%;
                height: 150px;
            }
        }
    }

    .blog-area {
        flex: 1;

        .react-grid-layout {
            position: relative;
            transition: height 200ms ease;
            background-color: azure;
            margin: 0 auto;
            overflow: hidden;

            .react-grid-item {
                cursor: pointer;
                transition: all 200ms ease;
                background-color: #9ee7e7;
                transition-property: left, top, width, height;
                border-radius: 10px;

                a {
                    display: block;
                    width: 100%;
                    height: 100%;
                }

                img {
                    pointer-events: none;
                    user-select: none;
                }

                &.cssTransforms {
                    transition-property: transform, width, height;
                }

                &.resizing {
                    transition: none;
                    z-index: 1;
                    will-change: width, height;
                }

                &.react-draggable-dragging {
                    transition: none;
                    z-index: 3;
                    will-change: transform;
                }

                &.dropping {
                    visibility: hidden;
                }

                &.react-grid-placeholder {
                    border: 3px dashed #c80cf7;
                    opacity: 0.2;
                    transition-duration: 100ms;
                    z-index: 2;
                    user-select: none;
                    -webkit-user-select: none;
                    -moz-user-select: none;
                    -ms-user-select: none;
                    -o-user-select: none;
                    &.placeholder-resizing {
                        transition: none;
                    }
                }

                > .react-resizable-handle {
                    position: absolute;
                    width: 20px;
                    height: 20px;

                    &::after {
                        content: '';
                        position: absolute;
                        right: 6px;
                        bottom: 6px;
                        width: 5px;
                        height: 5px;
                        border-right: 2px solid #00000066;
                        border-bottom: 2px solid #00000066;
                    }

                    &.react-resizable-handle-sw {
                        bottom: 0;
                        left: 0;
                        cursor: sw-resize;
                        transform: rotate(90deg);
                    }

                    &.react-resizable-handle-se {
                        bottom: 0;
                        right: 0;
                        cursor: se-resize;
                    }

                    &.react-resizable-handle-nw {
                        top: 0;
                        left: 0;
                        cursor: nw-resize;
                        transform: rotate(180deg);
                    }

                    &.react-resizable-handle-ne {
                        top: 0;
                        right: 0;
                        cursor: ne-resize;
                        transform: rotate(270deg);
                    }

                    &.react-resizable-handle-w,
                    &.react-resizable-handle-e {
                        top: 50%;
                        margin-top: -10px;
                        cursor: ew-resize;
                    }

                    &.react-resizable-handle-w {
                        left: 0;
                        transform: rotate(135deg);
                    }

                    &.react-resizable-handle-e {
                        right: 0;
                        transform: rotate(315deg);
                    }

                    &.react-resizable-handle-n,
                    &.react-resizable-handle-s {
                        left: 50%;
                        margin-left: -10px;
                        cursor: ns-resize;
                    }

                    &.react-resizable-handle-n {
                        top: 0;
                        transform: rotate(225deg);
                    }

                    &.react-resizable-handle-s {
                        bottom: 0;
                        transform: rotate(45deg);
                    }
                }
            }
        }
    }

    .floating-droppables-ui {
        position: fixed;
        bottom: 5%;
        left: 50%;
        margin-left: -150px;
        display: flex;
        justify-content: space-between;
        width: 300px;
        height: 50px;
        z-index: 5;
        background-color: pink;

        .droppable-element {
            width: 80px;
            height: 50px;
            text-align: center;
            border-radius: 10px;
            background-color: #9ee7e7;
        }
    }

    .react-resizable-hide {
        > .react-resizable-handle {
            display: none;
        }
    }
}

문제 및 이슈

참고자료

지원요청

내일 계획