Paradox Simulation

728x90
반응형

살다보면 스티커 메모처럼 위젯을 구현하고 싶을때가 온다.. 나만그럴수도있고

 

그럼 이 위젯을 어떻게 만들어야할까?

 

우선 GridLayout에서 만들것이므로

 

NewGrid.js

import React, { useState } from "react";
import ResizableWidget from "./ResizableWidget";
import "./NewGrid.css";

const Grid = () => {
  const [widgets, setWidgets] = useState([
    { id: "1", text: "Widget 1" },
    { id: "2", text: "Widget 2" },
    { id: "3", text: "Widget 3" },
  ]);

  const handleRemoveWidget = (widgetId) => {
    setWidgets((prevWidgets) =>
      prevWidgets.filter((widget) => widget.id !== widgetId)
    );
  };

  const handleAddWidget = () => {
    const newWidget = {
      id: `${widgets.length + 1}`,
      text: `Widget ${widgets.length + 1}`,
    };
    setWidgets((prevWidgets) => [...prevWidgets, newWidget]);
  };

  return (
    <div className="grid-container">
      <button className="add-button" onClick={handleAddWidget}>
        +
      </button>
      {widgets.map((widget) => (
        <ResizableWidget
          key={widget.id}
          id={widget.id}
          text={widget.text}
          onRemove={() => handleRemoveWidget(widget.id)}
        />
      ))}
    </div>
  );
};

export default Grid;

 

NewGrid.css

.resizable-widget {
    border: 1px solid #ccc;
    border-radius: 6px;
  }
  
  .widget-header {
    background-color: #ccc;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
    padding: 0.5rem;
  }
  
  .widget-content {
    padding: 0.5rem;
  }
  
  .widget-footer {
    display: flex;
    justify-content: flex-end;
    padding: 0.5rem;
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: rgba(255, 255, 255, 0.7);
  }
  
  .remove-button {
    background-color: transparent;
    border: none;
    cursor: pointer;
    font-size: 1rem;
    margin-left: 0.5rem;
  }
  
  .add-button {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 1rem;
    position: absolute;
    z-index: 10;
    padding: 0.5rem;
    border: none;
    border-top-right-radius: 5px;
    background-color: #ccc;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    transition: transform 0.2s ease-in-out;
  }
  
  .add-button:hover {
    transform: scale(1.1);
  }
  
  .grid-container {
    position: relative;
  }
  
  .layout {
    position: relative;
    height: 100%;
  }
  
  @media (max-width: 768px) {
    .layout {
      margin-left: -10px;
    }
  }
  
  @media (max-width: 576px) {
    .layout {
      margin-left: -8px;
    }
  }
  
  .rounded-widget {
    border-radius: 10px;
    overflow: hidden;
  }
  
  .resizable-widget textarea {
    width: 100%;
    height: 100%;
    resize: none;
    border: none;
  }

 

ResizableWidget.js

import React, { useState, useRef } from "react";
import { ResizableBox } from "react-resizable";
import Draggable from "react-draggable";
import "./ResizableWidget.css";

const ResizableWidget = ({ id, text, onRemove }) => {
  const [widgetText, setWidgetText] = useState(text);
  const textareaRef = useRef(null);

  const handleTextChange = (event) => {
    setWidgetText(event.target.value);
  };

  return (
    <Draggable handle=".widget-header">
      <ResizableBox
        className="resizable-widget"
        width={200}
        height={200}
        minConstraints={[100, 100]}
        handle={
          <div className="resize-handle">
            <span className="icon"></span>
          </div>
        }
        onResize={(event, { size }) => {
          if (textareaRef.current) {
            textareaRef.current.style.width = `${size.width}px`;
            textareaRef.current.style.height = `${size.height - 60}px`;
          }
        }}
      >
        <div>
          <div className="widget-header">
            Widget {id}
            <button className="remove-button" onClick={onRemove}>
              삭제
            </button>
          </div>
          <div className="widget-content">
            <textarea
              ref={textareaRef}
              style={{ width: "100%", height: "calc(100% - 60px)" }}
              value={widgetText}
              onChange={handleTextChange}
            />
          </div>
        </div>
      </ResizableBox>
    </Draggable>
  );
};

export default ResizableWidget;

 

ResizableWidget.css

.resizable-widget {
    position: relative;
    background-color: #fff;
    border-radius: 10px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    overflow: hidden;
    margin: 10px;
  }
  
  .widget-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.5rem;
    font-weight: bold;
    background-color: #2196f3;
    color: #fff;
  }
  
  .remove-button {
    background-color: transparent;
    border: none;
    cursor: pointer;
    font-size: 1rem;
    margin-left: 0.5rem;
  }
  
  .widget-content {
    padding: 0.5rem;
  }
  
  .resize-handle {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 24px;
    height: 24px;
    border-top: 4px solid rgba(0, 0, 0, 0.1);
    border-right: 4px solid rgba(0, 0, 0, 0.1);
    background-color: #f1f1f1;
    cursor: nwse-resize;
  }
  
  .resize-handle .icon {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 8px;
    height: 8px;
    border-left: 2px solid #333;
    border-bottom: 2px solid #333;
  }
  
  .widget-footer {
    display: flex;
    justify-content: flex-end;
    padding: 0.5rem;
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: rgba(255, 255, 255, 0.7);
  }
  
  .widget-footer button {
    background-color: transparent;
    border: none;
    cursor: pointer;
    font-size: 1rem;
    margin-left: 0.5rem;
    margin-right: 0.5rem;
    transition: transform 0.2s ease-in-out;
  }

  .widget-content {
    padding: 8px;
    background-color: #f0f0f0;
    border: 1px solid #ccc;
    overflow: auto;
  }
  
  
  .widget-footer button:hover {
    transform: scale(1.1);
  }
  
  .dummy-button {
    padding: 0.5rem 1rem;
    border-radius: 5px;
    border: none;
    background-color: #e0e0e0;
    color: #333;
    font-weight: bold;
    text-transform: uppercase;
    transition: background-color 0.2s ease-in-out;
  }
  
  .dummy-button:hover {
    background-color: #bdbdbd;
  }

 

 

이렇게 구성해놓고 실행해보면 다음과 같이 나온다.

 

 

이런식으로 길게 늘려서 쓸수도있고,

 

삭제를 누르게 되면 삭제가 된다.

 

없애버린 위젯은 옆에 + 버튼을 누르면 생성이 되고, 안에 글자도 쓸 수 있다.

 

 

또한 위젯은 자유롭게 이동도 가능하다!

 

css더 수정하고 하면 좀 좋은 구도의 스티커 메모가 생길거같다.

728x90
반응형
250x250
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band