mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-10 11:47:43 +02:00
[Haik]: and so it begins
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
.color-button-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.color-button-img {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.color-button-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.color-button {
|
||||
background-color: rgba(255, 255, 255, 0);
|
||||
color: black;
|
||||
border: none;
|
||||
font-size: 1.45rem;
|
||||
font-weight: bold; /* Changed from 900 to bold */
|
||||
font-family: 'Consolas', monospace;
|
||||
cursor: pointer;
|
||||
border-radius: 400px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.color-button:hover {
|
||||
background-color: #9292926c;
|
||||
}
|
||||
|
||||
.color-button:active {
|
||||
background-color: #929292ce;
|
||||
}
|
||||
|
||||
.color-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.color-button-container p {
|
||||
color: #D9D9D9;
|
||||
font-family: 'Consolas', monospace;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import axios from 'axios';
|
||||
import pushImg from '../../assets/color-reset.png'; // Adjust the path according to your project structure
|
||||
import './ColorReset.css'; // Import the CSS file
|
||||
|
||||
const ColorReset = ({ projectStructure, setProjectStructure }) => {
|
||||
const pushStructure = async () => {
|
||||
try {
|
||||
console.log("Resetting colors");
|
||||
const response = await axios.post('http://127.0.0.1:6969/reset_color');
|
||||
console.log('Project structure:', response.data);
|
||||
setProjectStructure(response.data);
|
||||
} catch (error) {
|
||||
console.error('Error pushing project structure:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="color-button-container">
|
||||
<div className="color-button-content">
|
||||
<button className="color-button" onClick={pushStructure}>
|
||||
<img src={pushImg} alt="Project Structure" className="color-button-img" />
|
||||
</button>
|
||||
<p>Wipe colors</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorReset;
|
||||
@@ -0,0 +1,129 @@
|
||||
/* EmojiPicker.css */
|
||||
|
||||
.picker-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.picker-button {
|
||||
font-size: 1.5rem;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
|
||||
}
|
||||
|
||||
.emoji-popup {
|
||||
position: absolute;
|
||||
top: 2.5rem;
|
||||
left: 0;
|
||||
width: fit-content;
|
||||
padding: 10px;
|
||||
border: 7px solid #cccccc46;
|
||||
border-radius: 35px;
|
||||
background-color: #181818ef;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.folder-section {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
height: fit-content;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.folder-item {
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
background-color: #00000000;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.folder-item:hover {
|
||||
background-color: #ffffff35;
|
||||
}
|
||||
|
||||
.folder-item.active {
|
||||
background-color: #ffffff15; /* Active color for the selected folder */
|
||||
}
|
||||
|
||||
.folder-item.active:hover {
|
||||
background-color: #ffffff35; /* Active color for the selected folder */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.emoji-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
gap: 10px;
|
||||
height: 260px;
|
||||
width: 330px;
|
||||
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
|
||||
}
|
||||
|
||||
.emoji-item {
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
height: fit-content;
|
||||
border-radius: 5px;
|
||||
font-size: 1.5rem;
|
||||
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
|
||||
}
|
||||
|
||||
.emoji-item:hover {
|
||||
background-color: #ffffff35;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.pagination button {
|
||||
background-color: #00000000;
|
||||
border: 0;
|
||||
gap: 0;
|
||||
width: 18px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 0 16px;
|
||||
border-radius: 50px;
|
||||
color: #ffffff;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.pagination button img {
|
||||
height: 100px;
|
||||
width: 30px;
|
||||
object-fit: cover;
|
||||
|
||||
}
|
||||
|
||||
.pagination button:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.pagination button:hover {
|
||||
background-color: #ffffff15;
|
||||
}
|
||||
|
||||
.selected-emoji-display {
|
||||
margin-top: 20px;
|
||||
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { emojiList } from '../../assets/emojis';
|
||||
import PrevPage from '../../assets/prev-page.png';
|
||||
import NextPage from '../../assets/next-page.png';
|
||||
import './EmojiPicker.css'; // Import CSS file
|
||||
|
||||
const EMOJIS_PER_PAGE = 30;
|
||||
|
||||
const EmojiPicker = ({ defaultEmoji, handleEmojiChange }) => {
|
||||
const folderNames = Object.keys(emojiList); // Get all folder names
|
||||
const firstFolder = folderNames[0]; // Get the first folder name
|
||||
const [showPicker, setShowPicker] = useState(false);
|
||||
const [selectedEmoji, setSelectedEmoji] = useState(defaultEmoji || "😀"); // Initialize with the default emoji from props or fallback to smiley
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const [currentFolder, setCurrentFolder] = useState(firstFolder); // Initialize with first folder
|
||||
|
||||
// When defaultEmoji changes (e.g., from backend data), update selectedEmoji
|
||||
useEffect(() => {
|
||||
if (defaultEmoji) {
|
||||
setSelectedEmoji(defaultEmoji);
|
||||
}
|
||||
}, [defaultEmoji]);
|
||||
|
||||
// Handle folder click
|
||||
const handleFolderClick = (folderName) => {
|
||||
setCurrentFolder(folderName); // Set the current folder
|
||||
setCurrentPage(0); // Reset page to 0 when switching folders
|
||||
};
|
||||
|
||||
// Get the emojis for the selected folder
|
||||
const emojis = currentFolder ? emojiList[currentFolder] : [];
|
||||
const totalPages = Math.ceil(emojis.length / EMOJIS_PER_PAGE);
|
||||
const currentEmojis = emojis.slice(
|
||||
currentPage * EMOJIS_PER_PAGE,
|
||||
(currentPage + 1) * EMOJIS_PER_PAGE
|
||||
);
|
||||
|
||||
const handleEmojiClick = (emoji) => {
|
||||
setSelectedEmoji(emoji);
|
||||
setShowPicker(false); // Close the picker when an emoji is selected
|
||||
handleEmojiChange(emoji); // Call the parent handler with the selected emoji
|
||||
};
|
||||
|
||||
const togglePicker = () => {
|
||||
setShowPicker((prev) => !prev); // Toggle the picker visibility
|
||||
};
|
||||
|
||||
const goToNextFolder = () => {
|
||||
const currentIndex = folderNames.indexOf(currentFolder);
|
||||
const nextFolderIndex = currentIndex + 1;
|
||||
if (nextFolderIndex < folderNames.length) {
|
||||
setCurrentFolder(folderNames[nextFolderIndex]);
|
||||
setCurrentPage(0); // Reset to the first page of the next folder
|
||||
}
|
||||
};
|
||||
|
||||
const goToPreviousFolder = () => {
|
||||
const currentIndex = folderNames.indexOf(currentFolder);
|
||||
const previousFolderIndex = currentIndex - 1;
|
||||
if (previousFolderIndex >= 0) {
|
||||
const previousFolder = folderNames[previousFolderIndex];
|
||||
setCurrentFolder(previousFolder);
|
||||
const lastPageOfPreviousFolder = Math.ceil(emojiList[previousFolder].length / EMOJIS_PER_PAGE) - 1;
|
||||
setCurrentPage(lastPageOfPreviousFolder); // Set to the last page of the previous folder
|
||||
}
|
||||
};
|
||||
|
||||
const goToNextPage = () => {
|
||||
if (currentPage < totalPages - 1) {
|
||||
setCurrentPage(currentPage + 1);
|
||||
} else {
|
||||
goToNextFolder();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPreviousPage = () => {
|
||||
if (currentPage > 0) {
|
||||
setCurrentPage(currentPage - 1);
|
||||
} else {
|
||||
goToPreviousFolder();
|
||||
}
|
||||
};
|
||||
|
||||
const isLastFolder = currentFolder === folderNames[folderNames.length - 1];
|
||||
const isLastPageOfLastFolder = isLastFolder && currentPage === totalPages - 1;
|
||||
const isFirstFolder = currentFolder === folderNames[0];
|
||||
const isFirstPageOfFirstFolder = isFirstFolder && currentPage === 0;
|
||||
|
||||
return (
|
||||
<div className="picker-wrapper">
|
||||
{/* The emoji picker icon that changes when an emoji is selected */}
|
||||
<button onClick={togglePicker} className="picker-button">
|
||||
{selectedEmoji}
|
||||
</button>
|
||||
|
||||
{/* Hoverable emoji picker */}
|
||||
{showPicker && (
|
||||
<div className="emoji-popup">
|
||||
<div className="emoji-section">
|
||||
<div className="pagination">
|
||||
<button onClick={goToPreviousPage} disabled={isFirstPageOfFirstFolder}>
|
||||
<img src={PrevPage} alt="Previous Page" />
|
||||
</button>
|
||||
<div className="emoji-grid">
|
||||
{currentEmojis.map((emoji, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="emoji-item"
|
||||
onClick={() => handleEmojiClick(emoji)}
|
||||
>
|
||||
{emoji}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={goToNextPage}
|
||||
disabled={isLastPageOfLastFolder}
|
||||
>
|
||||
<img src={NextPage} alt="Next Page" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="folder-section">
|
||||
{folderNames.map((folderName, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`folder-item ${folderName === currentFolder ? 'active' : ''}`}
|
||||
onClick={() => handleFolderClick(folderName)}
|
||||
>
|
||||
{emojiList[folderName][0]}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmojiPicker;
|
||||
@@ -0,0 +1,49 @@
|
||||
.pull-button-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 40vw;
|
||||
}
|
||||
|
||||
.pull-button-img {
|
||||
margin-right: 20px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.pull-button-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.pull-button {
|
||||
background-color: #A3FFA9;
|
||||
color: black;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
font-size: 1.45rem;
|
||||
font-weight: bold; /* Changed from 900 to bold */
|
||||
font-family: 'Consolas', monospace;
|
||||
cursor: pointer;
|
||||
margin: 20px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.pull-button:hover {
|
||||
background-color: #84d488;
|
||||
}
|
||||
|
||||
.pull-button:active {
|
||||
background-color: #65a568;
|
||||
}
|
||||
|
||||
.pull-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.pull-button-container p {
|
||||
color: #A3FFA9;
|
||||
font-family: 'Consolas', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import { Button } from '@mui/material';
|
||||
import axios from 'axios';
|
||||
import pullImg from '../../assets/pull.png'; // Adjust the path according to your project structure
|
||||
import './PullButton.css';
|
||||
|
||||
|
||||
const PullButton = ({ setProjectStructure }) => {
|
||||
const pullStructure = async () => {
|
||||
try {
|
||||
const response = await axios.get('http://127.0.0.1:6969/pull_structure');
|
||||
console.log('Project structure:', response.data);
|
||||
setProjectStructure(response.data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching project structure:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="pull-button-container">
|
||||
<img src={pullImg} alt="Project Structure" className="pull-button-img" />
|
||||
<div className="pull-button-content">
|
||||
<button className="pull-button" onClick={pullStructure}>
|
||||
Pull
|
||||
</button>
|
||||
<p>Pull debugger config from backend</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PullButton;
|
||||
@@ -0,0 +1,50 @@
|
||||
.push-button-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 40vw;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.push-button-img {
|
||||
margin-left: 20px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.push-button-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.push-button {
|
||||
background-color: #FFA3A4;
|
||||
color: black;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
font-size: 1.45rem;
|
||||
font-weight: bold; /* Changed from 900 to bold */
|
||||
font-family: 'Consolas', monospace;
|
||||
cursor: pointer;
|
||||
margin: 20px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.push-button:hover {
|
||||
background-color: #cc8182;
|
||||
}
|
||||
|
||||
.push-button:active {
|
||||
background-color: #a86768;
|
||||
}
|
||||
|
||||
.push-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.push-button-container p {
|
||||
color: #FFA3A4;
|
||||
font-family: 'Consolas', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import axios from 'axios';
|
||||
import pushImg from '../../assets/push.png'; // Adjust the path according to your project structure
|
||||
import './PushButton.css'; // Import the CSS file
|
||||
|
||||
const PushButton = ({ projectStructure, setProjectStructure }) => {
|
||||
const pushStructure = async () => {
|
||||
try {
|
||||
console.log("Pushing project structure to backend: ", projectStructure);
|
||||
const response = await axios.post('http://127.0.0.1:6969/push_structure', {
|
||||
projectStructure // Include the projectStructure in the POST request body
|
||||
});
|
||||
console.log('Project structure pushed:', response.data);
|
||||
setProjectStructure(response.data);
|
||||
} catch (error) {
|
||||
console.error('Error pushing project structure:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="push-button-container">
|
||||
<div className="push-button-content">
|
||||
<button className="push-button" onClick={pushStructure}>
|
||||
Push
|
||||
</button>
|
||||
<p>Push debugger config to backend</p>
|
||||
</div>
|
||||
<img src={pushImg} alt="Project Structure" className="push-button-img" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PushButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
.sync-section-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100vw;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
gap: 0
|
||||
}
|
||||
|
||||
.sync-section-container > div {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import PullButton from '../pull-button/PullButton';
|
||||
import PushButton from '../push-button/PushButton';
|
||||
import ColorReset from '../color-reset/ColorReset';
|
||||
import './SyncSection.css'; // Import the CSS file
|
||||
|
||||
const SyncSection = ({ projectStructure, setProjectStructure }) => {
|
||||
return (
|
||||
<div className="sync-section-container">
|
||||
<PullButton setProjectStructure={setProjectStructure} />
|
||||
<ColorReset setProjectStructure={setProjectStructure} />
|
||||
<PushButton projectStructure={projectStructure} setProjectStructure={setProjectStructure} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SyncSection;
|
||||
@@ -0,0 +1,7 @@
|
||||
.tree-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import TreeNode from '../tree_node/TreeNode';
|
||||
import './Tree.css';
|
||||
|
||||
const Tree = ({ projectStructure, expanded, handleExpandClick, handleCheckboxChange, handleColorChange, handleEmojiChange}) => {
|
||||
const renderTree = (node, parentId = '') => {
|
||||
const nodeId = parentId ? `${parentId}/${node.name}` : node.name;
|
||||
|
||||
return (
|
||||
<TreeNode
|
||||
key={nodeId}
|
||||
node={node}
|
||||
nodeId={nodeId}
|
||||
expanded={expanded}
|
||||
handleExpandClick={handleExpandClick}
|
||||
handleCheckboxChange={handleCheckboxChange}
|
||||
handleColorChange={handleColorChange}
|
||||
handleEmojiChange={handleEmojiChange}
|
||||
renderTree={renderTree}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
if (!Array.isArray(projectStructure)) return null; // Ensure projectStructure is an array
|
||||
|
||||
return (
|
||||
<div className='tree-container'>
|
||||
{projectStructure.map((node) => renderTree(node))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tree;
|
||||
@@ -0,0 +1,88 @@
|
||||
.tree-node {
|
||||
border: 1px solid #ccc;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
background-color: #181818;
|
||||
}
|
||||
|
||||
.tree-node-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tree-node-content-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.expand-button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
padding: 0; /* Ensure no padding around the button */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.expand-button img {
|
||||
width: 16px; /* Adjust the width as needed */
|
||||
height: 16px; /* Adjust the height as needed */
|
||||
max-width: 100%; /* Ensure it doesn't exceed button size */
|
||||
max-height: 100%; /* Ensure it doesn't exceed button size */
|
||||
}
|
||||
|
||||
.tree-node-text {
|
||||
margin-left: 10px;
|
||||
font-size: 1.45rem;
|
||||
font-weight: 600;
|
||||
font-family: 'Consolas', monospace; /* Specify fallback font */
|
||||
color: #ffffff; /* Adjust text color to ensure it's visible on the dark background */
|
||||
}
|
||||
|
||||
.tree-node-children {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tree-node-content-secondary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.color-picker-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.color-picker-icon {
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
background-size: 100% 100%; /* Ensure the background color scales to fit */
|
||||
background-clip: content-box;
|
||||
background-color: transparent; /* Ensure the background is transparent */
|
||||
-webkit-mask: url('../../assets/color-picker.png') center no-repeat;
|
||||
mask: url('../../assets/color-picker.png') center no-repeat;
|
||||
-webkit-mask-size: 20px; /* Adjust this value to fit your icon */
|
||||
mask-size: 20px; /* Adjust this value to fit your icon */
|
||||
}
|
||||
|
||||
.color-picker-icon img {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import './TreeNode.css';
|
||||
import React from 'react';
|
||||
import plusIcon from '../../assets/collapsed.png';
|
||||
import minusIcon from '../../assets/expanded.png';
|
||||
import colorIcon from '../../assets/color-picker.png'; // Import your custom color icon
|
||||
import EmojiPicker from '../emoji-picker/EmojiPicker';
|
||||
|
||||
const TreeNode = ({ node, nodeId, expanded, handleExpandClick, handleCheckboxChange, handleColorChange, handleEmojiChange, renderTree }) => (
|
||||
<div className="tree-node">
|
||||
<div className="tree-node-content">
|
||||
<div className="tree-node-content-main">
|
||||
{node.children && node.children.length > 0 && (
|
||||
<button className="expand-button" onClick={() => handleExpandClick(nodeId)}>
|
||||
<img src={expanded[nodeId] ? minusIcon : plusIcon} alt="Expand/Collapse Icon" />
|
||||
</button>
|
||||
)}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={node.is_toggled}
|
||||
onChange={(e) => handleCheckboxChange(nodeId, e.target.checked)}
|
||||
/>
|
||||
{/* Pass node.emoji along with handleEmojiChange */}
|
||||
<EmojiPicker
|
||||
defaultEmoji={node.emoji}
|
||||
handleEmojiChange={(emoji) => handleEmojiChange(nodeId, emoji)}
|
||||
/>
|
||||
<span className="tree-node-text" style={{ color: node.color || '#000000' }}>{node.name}</span>
|
||||
</div>
|
||||
<div className="tree-node-content-secondary">
|
||||
<div className="color-picker-wrapper">
|
||||
<input
|
||||
type="color"
|
||||
value={node.color || '#000000'}
|
||||
onChange={(e) => handleColorChange(nodeId, e.target.value)}
|
||||
style={{ display: 'none' }} // Hide the default color input
|
||||
id={`color-picker-${nodeId}`}
|
||||
/>
|
||||
<label htmlFor={`color-picker-${nodeId}`} className="color-picker-icon" style={{ backgroundColor: node.color || '#000000' }}>
|
||||
<img src={colorIcon} alt="Color Picker Icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{node.children && expanded[nodeId] && (
|
||||
<div className="tree-node-children">
|
||||
{node.children.map((childNode) => renderTree(childNode, nodeId))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default TreeNode;
|
||||
Reference in New Issue
Block a user