basic UI for selecting and editing
This commit is contained in:
parent
939539611f
commit
97cdb093a5
@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import useThrottle from "../hooks/useThrottle";
|
import useThrottle from "../hooks/useThrottle";
|
||||||
|
import EditPopup from "./select-and-edit/EditPopup";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
code: string;
|
code: string;
|
||||||
@ -13,9 +14,70 @@ function Preview({ code, device }: Props) {
|
|||||||
// Don't update code more often than every 200ms.
|
// Don't update code more often than every 200ms.
|
||||||
const throttledCode = useThrottle(code, 200);
|
const throttledCode = useThrottle(code, 200);
|
||||||
|
|
||||||
|
const [selectedElement, setSelectedElement] = useState<HTMLElement | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
|
const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 });
|
||||||
|
const [editText, setEditText] = useState("");
|
||||||
|
|
||||||
|
console.log(selectedElement);
|
||||||
|
|
||||||
|
function updateHighlight(targetElement: HTMLElement) {
|
||||||
|
setSelectedElement((prev) => {
|
||||||
|
// Remove style from previous element
|
||||||
|
if (prev) {
|
||||||
|
prev.style.outline = "";
|
||||||
|
prev.style.backgroundColor = "";
|
||||||
|
}
|
||||||
|
// Add style to new element
|
||||||
|
targetElement.style.outline = "2px dashed #1846db";
|
||||||
|
targetElement.style.backgroundColor = "#bfcbf5";
|
||||||
|
return targetElement;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(event: MouseEvent) {
|
||||||
|
const { clientX, clientY } = event;
|
||||||
|
|
||||||
|
// Prevent default to avoid issues like label clicks triggering textareas, etc.
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const targetElement = event.target as HTMLElement;
|
||||||
|
|
||||||
|
// Return if no target element
|
||||||
|
if (!targetElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Highlight the selected element
|
||||||
|
updateHighlight(targetElement);
|
||||||
|
|
||||||
|
// Show popup at click position
|
||||||
|
setPopupVisible(false);
|
||||||
|
setPopupPosition({ x: clientX, y: clientY });
|
||||||
|
setPopupVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEditSubmit() {
|
||||||
|
if (selectedElement) {
|
||||||
|
selectedElement.innerText = editText;
|
||||||
|
}
|
||||||
|
setPopupVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (iframeRef.current) {
|
const iframe = iframeRef.current;
|
||||||
iframeRef.current.srcdoc = throttledCode;
|
if (iframe) {
|
||||||
|
iframe.srcdoc = throttledCode;
|
||||||
|
|
||||||
|
// Related to
|
||||||
|
iframe.addEventListener("load", function () {
|
||||||
|
iframe.contentWindow?.document.body.addEventListener(
|
||||||
|
"click",
|
||||||
|
handleClick
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [throttledCode]);
|
}, [throttledCode]);
|
||||||
|
|
||||||
@ -34,6 +96,15 @@ function Preview({ code, device }: Props) {
|
|||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
></iframe>
|
></iframe>
|
||||||
|
<EditPopup
|
||||||
|
{...{
|
||||||
|
popupVisible,
|
||||||
|
popupPosition,
|
||||||
|
editText,
|
||||||
|
setEditText,
|
||||||
|
handleEditSubmit,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
52
frontend/src/components/select-and-edit/EditPopup.tsx
Normal file
52
frontend/src/components/select-and-edit/EditPopup.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React, { useEffect, useRef } from "react";
|
||||||
|
import { Textarea } from "../ui/textarea";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
|
||||||
|
interface EditPopupProps {
|
||||||
|
popupVisible: boolean;
|
||||||
|
popupPosition: { x: number; y: number };
|
||||||
|
editText: string;
|
||||||
|
setEditText: (text: string) => void;
|
||||||
|
handleEditSubmit: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditPopup: React.FC<EditPopupProps> = ({
|
||||||
|
popupVisible,
|
||||||
|
popupPosition,
|
||||||
|
editText,
|
||||||
|
setEditText,
|
||||||
|
handleEditSubmit,
|
||||||
|
}) => {
|
||||||
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (popupVisible && textareaRef.current) {
|
||||||
|
textareaRef.current.focus();
|
||||||
|
}
|
||||||
|
}, [popupVisible]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (!popupVisible) {
|
||||||
|
// setEditText("");
|
||||||
|
// }
|
||||||
|
// }, [popupVisible, setEditText]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="absolute bg-white p-4 border border-gray-300 rounded shadow-lg"
|
||||||
|
style={{ top: popupPosition.y, left: popupPosition.x }}
|
||||||
|
>
|
||||||
|
<Textarea
|
||||||
|
ref={textareaRef}
|
||||||
|
value={editText}
|
||||||
|
onChange={(e) => setEditText(e.target.value)}
|
||||||
|
placeholder="Edit text"
|
||||||
|
/>
|
||||||
|
<Button onClick={handleEditSubmit} className="mt-2">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditPopup;
|
||||||
Loading…
Reference in New Issue
Block a user