[Haik]: and so it begins

This commit is contained in:
haikdc
2026-03-13 12:09:25 -07:00
commit 23621306a1
190 changed files with 51641 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
.app-container {
display: flex;
flex-direction: column;
width: 90vw;
height: 100%;
padding-left: 5vw;
padding-right: 5vw;
padding-bottom: 5vh;
align-items: center;
}
.app-header {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 10vh;
font-family: 'Consolas', monospace;
font-size: 3.45rem;
font-weight: bold; /* Changed from 900 to bold */
color: #d8d8d8;
text-align: center;
margin-bottom: 2vh;
margin-top: 2vh;
}
+223
View File
@@ -0,0 +1,223 @@
import React, { useState } from 'react';
import { Container } from '@mui/material';
// import PullButton from './components/pull-button/PullButton'; // Import the FetchButton component
import SyncSection from './components/sync-section/SyncSection'; // Import the FetchButton component
import Tree from './components/tree/Tree'; // Import the Tree component
import './App.css';
const App = () => {
const [projectStructure, setProjectStructure] = useState(null);
const [expanded, setExpanded] = useState({});
const handleExpandClick = (id) => {
setExpanded((prevExpanded) => ({ ...prevExpanded, [id]: !prevExpanded[id] }));
};
const handleCheckboxChange = (nodeId, checked) => {
console.log("Handle checkbox change on node: ", nodeId, " with checked: ", checked); // Log the checkbox change
const updateNode = (nodes, pathParts, checked, forceCheck = false) => {
return nodes.map((node) => {
if (node.name === pathParts[0]) {
// Check if the node should be force-checked due to a child being checked
const shouldCheck = checked || forceCheck;
if (pathParts.length === 1) {
console.log("Node found: ", node.name, " With current checked: ", node.is_toggled);
return { ...node, is_toggled: shouldCheck, children: updateChildren(node.children, shouldCheck) };
}
// Recursively update children
if (node.children) {
const updatedChildren = updateNode(node.children, pathParts.slice(1), checked, shouldCheck);
return { ...node, is_toggled: shouldCheck, children: updatedChildren };
}
return { ...node, is_toggled: shouldCheck };
}
return node;
});
};
// Function to update the state of child nodes
const updateChildren = (children, checked) => {
if (!children) return [];
return children.map((child) => ({
...child,
is_toggled: checked,
children: updateChildren(child.children, checked)
}));
};
setProjectStructure((prevStructure) => {
if (!prevStructure) return prevStructure;
const pathParts = nodeId.split('/');
const updatedStructure = updateNode(prevStructure, pathParts, checked);
return updatedStructure;
});
};
const handleEmojiChange = (nodeId, emoji) => {
console.log("Handle emoji change on node: ", nodeId, " with emoji: ", emoji);
// Function to recursively propagate the emoji to all children but not update the ancestors
const propagateEmojiToChildren = (node) => {
if (!node.children) return node; // If no children, return the node as is
const updatedChildren = node.children.map((child) => ({
...child,
emoji, // Set the new emoji to the child node
children: propagateEmojiToChildren(child).children, // Recursively propagate to deeper children
}));
return { ...node, children: updatedChildren }; // Update the node's children but not the node itself
};
const updateNode = (nodes, pathParts, emoji) => {
return nodes.map((node) => {
if (node.name === pathParts[0]) {
// Update the emoji of the node itself if this is the target node
let updatedNode = { ...node };
if (pathParts.length === 1) {
// This is the target node, update its emoji
updatedNode.emoji = emoji;
}
// If this node has children and we haven't reached the target node yet
if (node.children && pathParts.length > 1) {
const updatedChildren = updateNode(node.children, pathParts.slice(1), emoji);
updatedNode = { ...updatedNode, children: updatedChildren };
}
// If we've reached the target node, propagate the emoji to its children
if (pathParts.length === 1 && node.children) {
updatedNode.children = propagateEmojiToChildren(node).children;
}
return updatedNode;
}
return node; // No match, return the node as is
});
};
setProjectStructure((prevStructure) => {
if (!prevStructure) return prevStructure;
const pathParts = nodeId.split('/');
const updatedStructure = updateNode(prevStructure, pathParts, emoji);
return updatedStructure;
});
};
const defaultColor = '#ff0000'; // Define the default color
const handleColorChange = (nodeId, color) => {
console.log("Handle color change on node: ", nodeId, " with color: ", color); // Log the color change
const amount = 50; // Define the amount to lighten the color
const updateNode = (nodes, pathParts, color, isOriginalParent = false) => {
console.log("HIT updateNode with color: ", color); // Log the color
return nodes.map((node) => {
if (node.name === pathParts[0]) {
let name = node.name;
let newColor = node.color;
let is_toggled = node.is_toggled;
let set_manually = node.set_manually;
// If the node is the target node
if (pathParts.length === 1) {
console.log("Node found: ", node.name, " With current color: ", node.color);
console.log("Setting color to: ", color);
console.log("Is original parent: ", isOriginalParent, " Set manually: ", set_manually);
if (isOriginalParent) {
set_manually = true;
}
newColor = color;
}
if (node.children) {
// Update children nodes
const updatedChildren = updateNode(node.children, pathParts.slice(1), color, isOriginalParent);
// Check and propagate the color to children if needed
const propagatedChildren = updatedChildren.map((child) => {
console.log("Checking child: ", child.name);
console.log("Child set manually: ", child.set_manually);
if (!child.set_manually) {
console.log("Propagating color to child: ", child.name);
const newPath = [...pathParts.slice(1), child.name];
return updateNode([child], newPath, lightenColor(color, amount), false)[0];
}
return child;
});
console.log("RETURN 1 node: ", node.name, " with color: ", newColor);
return {
...node,
name: name,
color: newColor,
is_toggled: is_toggled,
set_manually: set_manually,
children: propagatedChildren
};
}
console.log("RETURN 2 node: ", node.name, " with color: ", newColor);
return { ...node, name: name, color: newColor, is_toggled, set_manually};
}
return node;
});
};
// Helper function to lighten a color (example implementation)
const lightenColor = (color, amount = 50) => {
if (!color || typeof color !== 'string' || !color.startsWith('#') || color.length !== 7) {
throw new Error('Invalid color format. Expected format is #RRGGBB. But got: ' + color);
}
const colorInt = parseInt(color.slice(1), 16);
const r = Math.min(255, (colorInt >> 16) + amount);
const g = Math.min(255, ((colorInt >> 8) & 0x00FF) + amount);
const b = Math.min(255, (colorInt & 0x0000FF) + amount);
const newColorInt = (r << 16) + (g << 8) + b;
// Corrected console.log statement
console.log(`Old color: ${color}, New color: #${newColorInt.toString(16).padStart(6, '0')}`); // Log the old and new color
return `#${newColorInt.toString(16).padStart(6, '0')}`;
};
setProjectStructure((prevStructure) => {
if (!prevStructure) return prevStructure;
const pathParts = nodeId.split('/');
const updatedStructure = updateNode(prevStructure, pathParts, color, true);
console.log('Updated structure:', updatedStructure);
return updatedStructure;
});
};
return (
<div className='app-container'>
<div className='app-header'>
Cluster Labs Debugger v0
</div>
{/* <PullButton setProjectStructure={setProjectStructure} /> */}
{/* <SyncSection setProjectStructure={setProjectStructure} /> */}
<SyncSection projectStructure={projectStructure} setProjectStructure={setProjectStructure} />
<Tree
projectStructure={projectStructure}
expanded={expanded}
handleExpandClick={handleExpandClick}
handleCheckboxChange={handleCheckboxChange}
handleColorChange={handleColorChange}
handleEmojiChange={handleEmojiChange}
/>
</div>
);
};
export default App;
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

+128
View File
@@ -0,0 +1,128 @@
// Description: List of emojis for the debugger
export const emojiList = {
"R": [
'👽','👾','🤖','🦠','🚀','🛸',
],
"S": [
'😀','😃','😄','😁','😆','😅','🤣','😂','🙂','🙃','😉','😊',
'😇','🥰','😍','🤩','😘','😗','☺','😚','😙','😋','😛','😜',
'🤪','😝','🤑','🤗','🤭','🤫','🤔','🤐','🤨','😐',
'😑','😶','😏','😒','🙄','😬','🤥',
'😌','😔','😪','🤤','😴','😷','🤒','🤕','🤢','🤮','🤧',
'🥵','🥶','🥴','😵','🤯','🤠','🥳','😎','🤓','🧐',
'😕','😟','🙁','☹','😮','😯','😲','😳','🥺','😦','😧',
'😨','😰','😥','😢','😭','😱','😖','😣','😞','😓','😩','😫',
'🥱','😤','😡','😠','🤬','😈','👿','💀','☠','💩','🤡','👹',
'👺','👻','👋','🤚','🖐','✋','🖖','👌','🤏','✌','🤞','🤟','🤘','🤙','👈','👉',
'👆','🖕','👇','☝','👍','👎','✊','👊','🤛','🤜','👏','🙌','👐','🤲','🤝','🙏','✍','💅','🤳',
'💪','🦾','🦿','🦵','🦶','👂','🦻','👃','🧠','🦷','🦴','👀','👁',
'👅','👄','👶','🧒','👦','👧','🧑','👱','👨','🧔','👨‍🦰',
'👨‍🦱','👨‍🦳','👨‍🦲','👩','👩‍🦰','👩‍🦱','👩‍🦳','👩‍🦲','👱‍♀️',
'👱‍♂️','🧓','👴','👵','🙍','🙍‍♂️','🙍‍♀️','🙎','🙎‍♂️','🙎‍♀️','🙅','🙅‍♂️','🙅‍♀️','🙆','🙆‍♂️',
'🙆‍♀️','💁','💁‍♂️','💁‍♀️','🙋','🙋‍♂️','🙋‍♀️','🧏','🧏‍♂️','🧏‍♀️','🙇','🙇‍♂️','🙇‍♀️','🤦','🤦‍♂️',
'🤦‍♀️','🤷','🤷‍♂️','🤷‍♀️','👨‍⚕️','👩‍⚕️','👨‍🎓','👩‍🎓','👨‍🏫','👩‍🏫',
'👨‍⚖️','👩‍⚖️','👨‍🌾','👩‍🌾','👨‍🍳','👩‍🍳','👨‍🔧','👩‍🔧','👨‍🏭','👩‍🏭',
'👨‍💼','👩‍💼',,'👨‍🔬','👩‍🔬','👨‍💻','👩‍💻','👨‍🎤','👩‍🎤','👨‍🎨',
'👩‍🎨','👨‍✈️','👩‍✈️','👨‍🚀','👩‍🚀','👨‍🚒','👩‍🚒','👮','👮‍♂️','👮‍♀️','🕵','🕵️‍♂️',
'🕵️‍♀️','💂','💂‍♂️','💂‍♀️','👷','👷‍♂️','👷‍♀️','🤴','👸','👳','👳‍♂️','👳‍♀️','👲','🧕','🤵',
'👰','🤰','🤱','👼','🎅',
'🤶','🦸','🦸‍♂️','🦸‍♀️','🦹','🦹‍♂️','🦹‍♀️','🧙','🧙‍♂️','🧙‍♀️','🧚','🧚‍♂️','🧚‍♀️','🧛',
'🧛‍♂️','🧛‍♀️','🧜','🧜‍♂️','🧜‍♀️','🧝','🧝‍♂️','🧝‍♀️','🧞','🧞‍♂️','🧞‍♀️','🧟','🧟‍♂️','🧟‍♀️','💆',
'💆‍♂️','💆‍♀️','💇','💇‍♂️','💇‍♀️','🚶','🚶‍♂️','🚶‍♀️','🧍','🧍‍♂️','🧍‍♀️','🧎',
'🧎‍♂️','🧎‍♀️','👨‍🦯','👩‍🦯',
'👨‍🦼','👩‍🦼','👨‍🦽','👩‍🦽','🏃',
'🏃‍♂️','🏃‍♀️','💃','🕺','🕴','👯','👯‍♂️','👯‍♀️','🧖','🧖‍♂️','🧖‍♀️','🧗',
'🧗‍♂️','🧗‍♀️','🤺','🏇','⛷','🏂','🏌','🏌️‍♂️','🏌️‍♀️','🏄','🏄‍♂️','🏄‍♀️','🚣','🚣‍♂️','🚣‍♀️','🏊',
'🏊‍♂️','🏊‍♀️','⛹','⛹️‍♂️','⛹️‍♀️','🏋','🏋️‍♂️','🏋️‍♀️','🚴','🚴‍♂️','🚴‍♀️','🚵','🚵‍♂️','🚵‍♀️','🤸','🤸‍♂️',
'🤸‍♀️','🤼','🤼‍♂️','🤼‍♀️','🤽','🤽‍♂️','🤽‍♀️','🤾','🤾‍♂️','🤾‍♀️','🤹','🤹‍♂️','🤹‍♀️','🧘','🧘‍♂️','🧘‍♀️',
'🛀','🛌','🗣','👤','👥','👪','👣','🦰','🦱','🦳','🦲',
],
"A": [
'🐕','🦮','🐕‍🦺','🐩','🐺','🦊','🦝','🐱','😺','😸','😹','😻','😼','😽','🙀','😿','😾','🙈','🙉','🙊','🐵','🐒','🦍','🦧',
'🐈','🦁','🐯','🐅','🐆','🐴','🐎','🦄','🦓','🦌',
'🐮','🐂','🐃','🐄','🐷','🐖','🐗','🐽','🐏','🐑','🐐','🐪','🐫','🦙',
'🦒','🐘','🦏','🦛','🐭','🐁','🐀','🐹','🐰','🐇','🐿','🦔','🦇',
'🐻','🐨','🐼','🦥','🦦','🦨','🦘','🦡','🐾','🦃','🐔','🐓','🐣',
'🐤','🐥','🐦','🐧','🕊','🦅','🦆','🦢','🦉','🦩','🦚','🦜',
'🐸','🐊','🐢','🦎','🐍','🐲','🐉','🦕','🦖','🐳','🐋','🐬','🐟',
'🐠','🐡','🦈','🐙','🐚','🐌','🦋','🐛','🐜','🐝','🐞','🦗','🕷',
'🕸','🦂','🦟','🍇','🍈',
'🛎','💐','🌸','💮','🏵','🌹','🥀','🌺','🌻','🌼','🌷',
'🌱','🌲','🌳','🌴','🌵','🌾','🌿','☘','🍀','🍁','🍂','🍃','🍄','🎃','🎄','🎋','🎍',
],
"F": [
'🍉','🍊','🍋','🍌','🍍','🥭','🍎','🍏','🍐','🍑','🍒','🍓','🥝','🍅',
'🥥','🥑','🍆','🥔','🥕','🌽','🌶','🥒','🥬','🥦','🧄','🧅','🥜','🌰',
'🍞','🥐','🥖','🥨','🥯','🥞','🧇','🧀','🍖','🍗','🥩','🥓','🍔','🍟','🍕',
'🌭','🥪','🌮','🌯','🥙','🧆','🥚','🍳','🥘','🍲','🥣','🥗','🍿','🧈','🧂','🥫',
'🍱','🍘','🍙','🍚','🍛','🍜','🍝','🍠','🍢','🍣','🍤','🍥','🥮','🍡','🥟','🥠','🥡',
'🦀','🦞','🦐','🦑','🦪','🍦','🍧','🍨','🍩','🍪','🎂','🍰','🧁','🥧','🍫','🍬','🍭','🍮',
'🍯','🍼','🥛','☕','🍵','🍶','🍾','🍷','🍸','🍹','🍺','🍻','🥂','🥃','🥤','🧃',
'🧉','🧊','🥢','🍽','🍴','🥄','🔪',
],
"G": [
'⚽','⚾','🥎','🏀','🏐','🏈','🏉','🎾','🥏',
'🎳','🏏','🏑','🏒','🥍','🏓','🏸','🥊','🥋','🥅','⛳','⛸','🎣','🤿','🎽','🎿','🛷','🥌',
'♟','🃏','🀄','🎴','🎭','🖼','🎨','🧵','🎖','🏆','🏅','🥇','🥈','🥉',
'🎯','🪀','🪁','🔫','🎱','🔮','🎮','🕹','🎰','🎲','🧩','🧸','♠','♥','♦','♣',
],
"W": [
'🌍','🌎','🌏','🌐','🗺','🗾','🧭','🏔','⛰','🌋',
'🗻','🏕','🏖','🏜','🏝','🏞','🏟','🏛','🏗','🧱','🏘','🏚','🏠','🏡','🏢','🏣','🏤',
'🏥','🏦','🏨','🏩','🏪','🏫','🏬','🏭','🏯','🏰','💒','🗼','🗽','⛪','🕌','🛕','🕍','⛩',
'🕋','⛲','⛺','🌁','🌃','🏙','🌄','🌅','🌆','🌇','🌉','♨','🎠','🎡','🎢','💈','🎪','🚂',
'🚃','🚄','🚅','🚆','🚇','🚈','🚉','🚊','🚝','🚞','🚋','🚌','🚍','🚎','🚐','🚑','🚒','🚓',
'🚔','🚕','🚖','🚗','🚘','🚙','🚚','🚛','🚜','🏎','🏍','🛵','🦽','🦼','🛺','🚲','🛴','🛹',
'🚏','🛣','🛤','🛢','⛽','🚨','🚥','🚦','🛑','🚧','⚓','⛵','🛶','🚤','🛳','⛴','🛥',
'🚢','✈','🛩','🛫','🛬','🪂','💺','🚁','🚟','🚠','🚡','🛰','🧳','🎎','🎏','🎐','🎑','🧧','🎀','🎁',
'🎗','🎟','🎫','🏺',
],
"T": [
'⌛','⏳','⌚',
'⏰','⏱','⏲','🕰','🕛','🕧','🕐','🕜','🕑','🕝','🕒','🕞','🕓','🕟','🕔','🕠','🕕','🕡',
'🕖','🕢','🕗','🕣','🕘','🕤','🕙','🕥','🕚','🕦','🌑','🌒','🌓','🌔','🌕','🌖','🌗','🌘',
'🌙','🌚','🌛','🌜','🌡','☀','🌝','🌞','🪐','⭐','🌟','🌠','🌌','☁','⛅','⛈','🌤','🌥','🌦',
'🌧','🌨','🌩','🌪','🌫','🌬','🌀','🌈','🌂','☂','☔','⛱','⚡','❄','☃','⛄','☄','🔥','💧','🌊',
'🎆','🎇','🧨','✨','🎈','🎉','🎊',
],
"X": [
'💻','🖥','🖨','⌨','🖱','🖲','💽','💾','💿','📀','🧮','🎥','🎞','📽',
'🎬','📺','📷','📸','📹','📼','🔍','🔎','🕯','💡','🔦',
'🎙','🎚','🎛','🎤','🎧','📻','🎷','🎸',
'🎹','🎺','🎻','🪕','🥁','📱','📲','☎','📞','📟','📠','🔋',
'🔌','🏮','🪔','📔','📕','💌',
'📖','📗','📘','📙','📚','📓','📒','📃','📜','📄','📰','🗞','📑','🔖','🏷',
'💰','💴','💵','💶','💷','💸','💳','🧾','💹','✉','📧','📨','📩','📤',
'📥','📦','📫','📪','📬','📭','📮','🗳','✏','✒','🖋','🖊','🖌','🖍','📝',
'💼','📁','📂','🗂','📅','📆','🗒','🗓','📇','📈','📉','📊','📋','📌','📍',
'📎','🖇','📏','📐','✂','🗃','🗄','🗑','🔒','🔓','🔏','🔐','🔑','🗝','🔨','🪓',
'⛏','⚒','🛠','🗡','⚔','💣','🏹','🛡','🔧','🔩','⚙','🗜','⚖','🦯',
'🔗','⛓','🧰','🧲','⚗','🧪','🧫','🧬','🔬','🔭','📡','💉','🩸',
'💊','🩹','🩺','🚪','🛏','🛋','🪑','🚽','🚿','🛁','🪒',
'🧴','🧷','🧹','🧺','🧻','🧼','🧽','🧯','🛒','🚬','⚰','⚱','🧿',
],
"O": [
'💘','💝','💖','💗','💓','💞','💕','💟','❣','💔',
'❤','🧡','💛','💚','💙','💜','🤎','🖤','🤍',
'💋','💯','💢','💥','💫','💦','💨','🕳','💬','👁️‍🗨️','🗨',
'🗯','💭','💤','🧶','👓','🕶','🥽','🥼','🦺','👔','👕','👖','🧣','🧤','🧥',
'🧦','👗','👘','🥻','🩱','🩲','🩳','👙','👚','👛','👜','👝','🛍',
'🎒','👞','👟','🥾','🥿','👠','👡','🩰','👢','👑','👒','🎩',
'🎓','🧢','⛑','📿','💄','💍','💎','🔇','🔈','🔉','🔊','📢','📣',
'📯','🔔','🔕','🎼','🎵','🎶',
'🗿','🏧','🚮','🚰','♿','🚹','🚺','🚻','🚼','🚾','🛂','🛃','🛄',
'🛅','⚠','🚸','⛔','🚫','🚳','🚭','🚯','🚱','🚷','📵','🔞','☢','☣','⬆','↗',
'➡','↘','⬇','↙','⬅','↖','↕','↔','↩','↪','⤴','⤵','🔃','🔄','🔙','🔚','🔛','🔜',
'🔝','🛐','⚛','🕉','✡','☸','☯','✝','☦','☪','☮','🕎','🔯','♈','♉','♊',
'♋','♌','♍','♎','♏','♐','♑','♒','♓','⛎','🔀','🔁','🔂','▶','⏩','⏭',
'⏯','◀','⏪','⏮','🔼','⏫','🔽','⏬','⏸','⏹','⏺','⏏','🎦','🔅','🔆','📶',
'📳','📴','♀','♂','⚧','✖','','','➗','♾','‼','⁉','❓','❔','❕','❗','〰',
'💱','💲','⚕','♻','⚜','🔱','📛','🔰','⭕','✅','☑','✔','❌','❎','➰','➿','〽','✳',
'✴','❇','©','®','™','#️⃣','*️⃣','0️⃣','1️⃣','2️⃣','3️⃣','4️⃣','5️⃣','6️⃣','7️⃣','8️⃣','9️⃣',
'🔟','🔠','🔡','🔢','🔣','🔤','🅰','🆎','🅱','🆑','🆒','🆓','','🆔','Ⓜ','🆕','🆖',
'🅾','🆗','🅿','🆘','🆙','🆚','🈁','🈂','🈷','🈶','🈯','🉐','🈹','🈚','🈲','🉑','🈸',
'🈴','🈳','㊗','㊙','🈺','🈵','🔴','🟠','🟡','🟢','🔵','🟣','🟤','⚫','⚪','🟥',
'🟧','🟨','🟩','🟦','🟪','🟫','⬛','⬜','◼','◻','◾','◽','▪','▫','🔶','🔷','🔸','🔹',
'🔺','🔻','💠','🔘','🔳','🔲','🏁','🚩','🎌','🏴','🏳','🏳️‍⚧️','🏴‍☠️',
],
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@@ -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;
+14
View File
@@ -0,0 +1,14 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #242121;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
+9
View File
@@ -0,0 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
ReactDOM.render(
<App />,
document.getElementById('root')
);