Add context menu icons and styles for improved UI interaction

This commit is contained in:
Nalvazhuthi
2025-08-12 11:05:48 +05:30
parent c71b25c407
commit 3576a65aeb
5 changed files with 348 additions and 155 deletions

View File

@@ -160,3 +160,153 @@ export function RenameIcon() {
</svg> </svg>
); );
} }
export function FocusIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.31999 1.56H9.89999C10.0325 1.56 10.14 1.66745 10.14 1.8V4.14M10.14 7.5V9.9C10.14 10.0325 10.0325 10.14 9.89999 10.14H7.31999M4.55999 10.14H1.91999C1.78744 10.14 1.67999 10.0325 1.67999 9.9V7.5M1.67999 4.14V1.8C1.67999 1.66745 1.78744 1.56 1.91999 1.56H4.55999" stroke="white" stroke-linecap="round" />
<circle cx="6.00005" cy="5.87999" r="1.7" stroke="white" />
</svg>
);
}
export function TransformIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_55_63)">
<path d="M3 0.75C2.40326 0.75 1.83097 0.987053 1.40901 1.40901C0.987053 1.83097 0.75 2.40326 0.75 3C0.75 3.59674 0.987053 4.16903 1.40901 4.59099C1.83097 5.01295 2.40326 5.25 3 5.25C3.24134 5.24937 3.481 5.20991 3.7098 5.13314L3.28805 4.71141L4.79632 3.20316L4.94545 3.05402L5.22342 3.33199C5.24047 3.22214 5.24935 3.11117 5.25 3C5.25 2.40326 5.01295 1.83097 4.59099 1.40901C4.16903 0.987053 3.59674 0.75 3 0.75ZM4.94545 3.65062L3.88467 4.71141L5.92336 6.75L5.37333 7.30001L8.07427 7.84017L7.53403 5.13923L6.98405 5.68922L4.94545 3.65062ZM8.28647 6.75L8.61202 8.37797L6.75 8.00555V11.25H11.25V6.75H8.28645H8.28647Z" fill="#FCFDFD" />
</g>
<defs>
<clipPath id="clip0_55_63">
<rect width="12" height="12" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function DublicateIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_190)">
<path d="M9 1.5H2C1.72386 1.5 1.5 1.72386 1.5 2V9C1.5 9.27615 1.27614 9.5 1 9.5C0.72386 9.5 0.5 9.27615 0.5 9V2C0.5 1.17158 1.17158 0.5 2 0.5H9C9.27615 0.5 9.5 0.72386 9.5 1C9.5 1.27614 9.27615 1.5 9 1.5Z" fill="white" />
<path d="M6.5 5.5C6.5 5.22385 6.72385 5 7 5C7.27615 5 7.5 5.22385 7.5 5.5V6.5H8.5C8.77615 6.5 9 6.72385 9 7C9 7.27615 8.77615 7.5 8.5 7.5H7.5V8.5C7.5 8.77615 7.27615 9 7 9C6.72385 9 6.5 8.77615 6.5 8.5V7.5H5.5C5.22385 7.5 5 7.27615 5 7C5 6.72385 5.22385 6.5 5.5 6.5H6.5V5.5Z" fill="white" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 2.5C10.8285 2.5 11.5 3.17158 11.5 4V10C11.5 10.8285 10.8285 11.5 10 11.5H4C3.17158 11.5 2.5 10.8285 2.5 10V4C2.5 3.17158 3.17158 2.5 4 2.5H10ZM10 3.5C10.2761 3.5 10.5 3.72386 10.5 4V10C10.5 10.2761 10.2761 10.5 10 10.5H4C3.72386 10.5 3.5 10.2761 3.5 10V4C3.5 3.72386 3.72386 3.5 4 3.5H10Z" fill="white" />
</g>
<defs>
<clipPath id="clip0_1_190">
<rect width="12" height="12" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function CopyIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_197)">
<path d="M4.375 1.5H8.875C9.22018 1.5 9.5 1.77982 9.5 2.125V5.07422C9.25749 5.02497 9.00651 5 8.75 5C6.67893 5 5 6.67893 5 8.75C5 8.91951 5.01426 9.08616 5.03613 9.25H4.375C4.02982 9.25 3.75 8.97018 3.75 8.625V2.125C3.75 1.77982 4.02982 1.5 4.375 1.5Z" stroke="white" />
<path d="M7.02181 10.8891C5.8404 9.93469 5.6564 8.20324 6.61085 7.02182C7.56529 5.84041 9.29675 5.65641 10.4782 6.61086C11.6596 7.5653 11.8436 9.29676 10.8891 10.4782C9.93468 11.6596 8.20322 11.8436 7.02181 10.8891ZM7.53035 9.63652C7.55951 9.73588 7.64818 9.80729 7.7514 9.81511L7.79716 9.81441L7.84067 9.80562C7.94019 9.77642 8.01223 9.68724 8.01987 9.58381L8.01932 9.53942L7.89568 8.38246L9.76272 9.88956L9.80012 9.91475C9.89114 9.96447 10.0045 9.95243 10.083 9.88469L10.1143 9.8522L10.1395 9.8148C10.1892 9.72378 10.1772 9.61043 10.1094 9.53189L10.0769 9.50062L8.20913 7.99291L9.36823 7.86974L9.41174 7.86095C9.52542 7.82759 9.60327 7.71674 9.59039 7.59475C9.57742 7.47272 9.47859 7.38002 9.36039 7.37128L9.3154 7.37259L7.5357 7.5631L7.50592 7.57044L7.46405 7.58808L7.42779 7.61277L7.40435 7.63401L7.37612 7.66895L7.36028 7.69633L7.35134 7.71672L7.33894 7.75692L7.33456 7.781L7.33441 7.81227L7.52217 9.59225L7.53035 9.63652Z" fill="white" />
</g>
<defs>
<clipPath id="clip0_1_197">
<rect width="12" height="12" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function PasteIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_207)">
<path d="M4.375 1.5H8.875C9.22018 1.5 9.5 1.77982 9.5 2.125V5.07422C9.25749 5.02497 9.00651 5 8.75 5C6.67893 5 5 6.67893 5 8.75C5 8.91951 5.01426 9.08616 5.03613 9.25H4.375C4.02982 9.25 3.75 8.97018 3.75 8.625V2.125C3.75 1.77982 4.02982 1.5 4.375 1.5Z" stroke="white" />
<path d="M10.4408 6.58164C11.6383 7.51587 11.8516 9.24395 10.9174 10.4414C9.9832 11.6389 8.25512 11.8523 7.05765 10.918C5.86019 9.98382 5.64679 8.25574 6.58102 7.05828C7.51524 5.86081 9.24332 5.64742 10.4408 6.58164ZM9.95361 7.84272C9.92276 7.74387 9.83289 7.67398 9.72956 7.66791L9.68382 7.66939L9.64046 7.67892C9.54146 7.7098 9.47094 7.8002 9.46506 7.90374L9.46636 7.94811L9.60965 9.10281L7.71726 7.62766L7.67944 7.60311C7.58759 7.55494 7.47446 7.56891 7.39709 7.63798L7.36637 7.67099L7.34182 7.70881C7.29366 7.80066 7.30763 7.91379 7.37669 7.99117L7.4097 8.02188L9.30286 9.49763L8.14603 9.64048L8.10268 9.65001C7.98957 9.6853 7.91362 9.79746 7.92858 9.91921C7.94362 10.041 8.044 10.132 8.16233 10.1387L8.2073 10.1367L9.9835 9.91593L10.0131 9.90809L10.0547 9.88974L10.0906 9.86444L10.1136 9.8428L10.1413 9.80739L10.1566 9.77974L10.1652 9.7592L10.1769 9.71879L10.1809 9.69464L10.1805 9.66338L9.96254 7.88684L9.95361 7.84272Z" fill="white" />
</g>
<defs>
<clipPath id="clip0_1_207">
<rect width="12" height="12" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function ModifiersIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 4.5V3.23607C2 3.08082 2.03615 2.92771 2.10558 2.78886L2.5 2H5L5.5 3H10.5C10.7761 3 11 3.22386 11 3.5V4.5V9C11 9.5523 10.5523 10 10 10H9" stroke="white" stroke-linecap="round" stroke-linejoin="round" />
<path d="M8.61805 4.5H1.15458C0.824894 4.5 0.585449 4.81349 0.672199 5.13155L1.79898 9.2631C1.91764 9.6982 2.3128 10 2.76375 10H9.84535C10.175 10 10.4145 9.6865 10.3277 9.36845L9.10045 4.86844C9.0411 4.65091 8.84355 4.5 8.61805 4.5Z" stroke="white" />
</svg>
);
}
export function DeleteIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_241)">
<path d="M4.70588 5.32353V9.02941M7.17647 5.32353V9.02941M9.64706 2.85294V10.2647C9.64706 10.947 9.09402 11.5 8.41177 11.5H3.47059C2.78835 11.5 2.23529 10.947 2.23529 10.2647V2.85294M1 2.85294H10.8824M7.79412 2.85294V2.23529C7.79412 1.55306 7.24108 1 6.55882 1H5.32353C4.6413 1 4.08824 1.55306 4.08824 2.23529V2.85294" stroke="white" stroke-linecap="round" stroke-linejoin="round" />
</g>
<defs>
<clipPath id="clip0_1_241">
<rect width="12" height="12" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function MoveIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_241)">
<path d="M4.70588 5.32353V9.02941M7.17647 5.32353V9.02941M9.64706 2.85294V10.2647C9.64706 10.947 9.09402 11.5 8.41177 11.5H3.47059C2.78835 11.5 2.23529 10.947 2.23529 10.2647V2.85294M1 2.85294H10.8824M7.79412 2.85294V2.23529C7.79412 1.55306 7.24108 1 6.55882 1H5.32353C4.6413 1 4.08824 1.55306 4.08824 2.23529V2.85294" stroke="white" stroke-linecap="round" stroke-linejoin="round" />
</g>
<defs>
<clipPath id="clip0_1_241">
<rect width="12" height="12" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function RotateIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.99998 1.31111H4.7251L3.88539 0.471406L4.3568 0L6.00124 1.64444L4.37502 3.27067L3.90361 2.79927L4.72511 1.97777H3.99998C2.89541 1.97777 1.99998 2.87321 1.99998 3.97777H1.33331C1.33331 2.50501 2.52722 1.31111 3.99998 1.31111ZM3.99998 5.33333C3.99998 4.59696 4.59693 4 5.33331 4H10.6667C11.4031 4 12 4.59696 12 5.33333V10.6667C12 11.4031 11.4031 12 10.6667 12H5.33331C4.59693 12 3.99998 11.4031 3.99998 10.6667V5.33333ZM5.33331 4.66667H10.6667C11.0349 4.66667 11.3333 4.96514 11.3333 5.33333V10.6667C11.3333 11.0349 11.0349 11.3333 10.6667 11.3333H5.33331C4.96513 11.3333 4.66664 11.0349 4.66664 10.6667V5.33333C4.66664 4.96514 4.96513 4.66667 5.33331 4.66667Z" fill="#FCFDFD" />
</svg>
);
}
export function GroupIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.99998 1.31111H4.7251L3.88539 0.471406L4.3568 0L6.00124 1.64444L4.37502 3.27067L3.90361 2.79927L4.72511 1.97777H3.99998C2.89541 1.97777 1.99998 2.87321 1.99998 3.97777H1.33331C1.33331 2.50501 2.52722 1.31111 3.99998 1.31111ZM3.99998 5.33333C3.99998 4.59696 4.59693 4 5.33331 4H10.6667C11.4031 4 12 4.59696 12 5.33333V10.6667C12 11.4031 11.4031 12 10.6667 12H5.33331C4.59693 12 3.99998 11.4031 3.99998 10.6667V5.33333ZM5.33331 4.66667H10.6667C11.0349 4.66667 11.3333 4.96514 11.3333 5.33333V10.6667C11.3333 11.0349 11.0349 11.3333 10.6667 11.3333H5.33331C4.96513 11.3333 4.66664 11.0349 4.66664 10.6667V5.33333C4.66664 4.96514 4.96513 4.66667 5.33331 4.66667Z" fill="#FCFDFD" />
</svg>
);
}
export function ArrayIcon() {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1.09998" y="0.5" width="1.66667" height="5.66667" rx="0.5" stroke="white" />
<rect x="5.09998" y="3.16797" width="1.66667" height="5.66667" rx="0.5" stroke="white" />
<rect x="9.09998" y="5.83203" width="1.66667" height="5.66667" rx="0.5" stroke="white" />
</svg>
);
}
export function SubMenuIcon() {
return (
<svg width="4" height="6" viewBox="0 0 4 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 6V0L4 3L0.5 6Z" fill="white" />
</svg>
);
}

View File

@@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import { ArrayIcon, CopyIcon, DeleteIcon, DublicateIcon, FlipXAxisIcon, FlipZAxisIcon, FocusIcon, GroupIcon, ModifiersIcon, MoveIcon, PasteIcon, RenameIcon, RotateIcon, SubMenuIcon, TransformIcon } from "../../icons/ContextMenuIcons";
type ContextMenuProps = { type ContextMenuProps = {
visibility: { visibility: {
@@ -45,161 +46,140 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
onArray, onArray,
onDelete, onDelete,
}) => { }) => {
const styles: { [key: string]: React.CSSProperties } = {
contextMenu: {
position: "absolute",
top: 0,
left: 0,
backgroundColor: "#2c2c2c",
borderRadius: "6px",
padding: "8px",
color: "white",
fontFamily: "sans-serif",
fontSize: "14px",
boxShadow: "0 0 8px rgba(0,0,0,0.4)",
zIndex: 1000,
},
menuItem: {
margin: "4px 0",
},
button: {
background: "none",
border: "none",
color: "inherit",
display: "flex",
justifyContent: "space-between",
width: "180px",
padding: "4px 8px",
cursor: "pointer",
},
submenu: {
marginLeft: "10px",
marginTop: "4px",
backgroundColor: "#3a3a3a",
borderRadius: "4px",
padding: "4px",
},
shortcut: {
opacity: 0.6,
},
};
return ( return (
<div style={styles.contextMenu}> <div className="context-menu">
<div> {visibility.rename && (
{visibility.rename && ( <div className="menuItem">
<div style={styles.menuItem}> <button className="button" onClick={onRename}>
<button style={styles.button} onClick={onRename}> <div className="icon"><RenameIcon /></div>
<span>Rename</span> <span>Rename</span>
<span style={styles.shortcut}>F2</span> </button>
</button> <span className="shortcut">F2</span>
</div>
)}
{visibility.focus && (
<div className="menuItem">
<button className="button" onClick={onFocus}>
<div className="icon"><FocusIcon /></div>
<span>Focus</span>
</button>
<span className="shortcut">F</span>
</div>
)}
{visibility.flipX && (
<div className="menuItem">
<button className="button" onClick={onFlipX}>
<div className="icon"><FlipXAxisIcon /></div>
<span>Flip to X axis</span>
</button>
</div>
)}
{visibility.flipZ && (
<div className="menuItem">
<button className="button" onClick={onFlipZ}>
<div className="icon"><FlipZAxisIcon /></div>
<span>Flip to Z axis</span>
</button>
</div>
)}
{(visibility.move || visibility.rotate) && (
<div className="menuItem">
<button className="button">
<div className="icon"><TransformIcon /></div>
<span>Transform</span>
</button>
<div className="more"><SubMenuIcon /></div>
<div className="submenu">
{visibility.move && (
<div className="menuItem">
<button className="button" onClick={onMove}>
<div className="icon"><MoveIcon /></div>
<span>Move</span>
</button>
<span className="shortcut">G</span>
</div>
)}
{visibility.rotate && (
<div className="menuItem">
<button className="button" onClick={onRotate}>
<div className="icon"><RotateIcon /></div>
<span>Rotate</span>
</button>
<span className="shortcut">R</span>
</div>
)}
</div> </div>
)} </div>
{visibility.focus && ( )}
<div style={styles.menuItem}> {visibility.duplicate && (
<button style={styles.button} onClick={onFocus}> <div className="menuItem">
<span>Focus</span> <button className="button" onClick={onDuplicate}>
<span style={styles.shortcut}>F</span> <div className="icon"><DublicateIcon /></div>
</button> <span>Duplicate</span>
</button>
<span className="shortcut">Ctrl + D</span>
</div>
)}
{visibility.copy && (
<div className="menuItem">
<button className="button" onClick={onCopy}>
<div className="icon"><CopyIcon /></div>
<span>Copy Objects</span>
</button>
<span className="shortcut">Ctrl + C</span>
</div>
)}
{visibility.paste && (
<div className="menuItem">
<button className="button" onClick={onPaste}>
<div className="icon"><PasteIcon /></div>
<span>Paste Objects</span>
</button>
<span className="shortcut">Ctrl + V</span>
</div>
)}
{visibility.modifier && (
<div className="menuItem">
<div className="icon"><ModifiersIcon /></div>
<button className="button">Modifiers</button>
</div>
)}
{(visibility.group || visibility.array) && (
<div className="menuItem">
<button className="button">Group / Array</button>
<div className="submenu">
{visibility.group && (
<div className="menuItem">
<button className="button" onClick={onGroup}>
<GroupIcon />
<span>Group</span>
</button>
<span className="shortcut">Ctrl + G</span>
</div>
)}
{visibility.array && (
<div className="menuItem">
<button className="button" onClick={onArray}>
<div className="icon"><ArrayIcon /></div>
<span>Array</span>
</button>
</div>
)}
</div> </div>
)} </div>
{visibility.flipX && ( )}
<div style={styles.menuItem}> {visibility.delete && (
<button style={styles.button} onClick={onFlipX}> <div className="menuItem">
Flip to X axis <button className="button" onClick={onDelete}>
</button> <div className="icon"><DeleteIcon /></div>
</div> <span>Delete</span>
)} </button>
{visibility.flipZ && ( <span className="shortcut">X</span>
<div style={styles.menuItem}> </div>
<button style={styles.button} onClick={onFlipZ}> )}
Flip to Z axis
</button>
</div>
)}
{(visibility.move || visibility.rotate) && (
<div style={styles.menuItem}>
<button style={styles.button}>Transform</button>
<div style={styles.submenu}>
{visibility.move && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onMove}>
<span>Move</span>
<span style={styles.shortcut}>G</span>
</button>
</div>
)}
{visibility.rotate && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onRotate}>
<span>Rotate</span>
<span style={styles.shortcut}>R</span>
</button>
</div>
)}
</div>
</div>
)}
{visibility.duplicate && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onDuplicate}>
<span>Duplicate</span>
<span style={styles.shortcut}>Ctrl + D</span>
</button>
</div>
)}
{visibility.copy && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onCopy}>
<span>Copy Objects</span>
<span style={styles.shortcut}>Ctrl + C</span>
</button>
</div>
)}
{visibility.paste && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onPaste}>
<span>Paste Objects</span>
<span style={styles.shortcut}>Ctrl + V</span>
</button>
</div>
)}
{visibility.modifier && (
<div style={styles.menuItem}>
<button style={styles.button}>Modifiers</button>
</div>
)}
{(visibility.group || visibility.array) && (
<div style={styles.menuItem}>
<button style={styles.button}>Group / Array</button>
<div style={styles.submenu}>
{visibility.group && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onGroup}>
<span>Group</span>
<span style={styles.shortcut}>Ctrl + G</span>
</button>
</div>
)}
{visibility.array && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onArray}>
Array
</button>
</div>
)}
</div>
</div>
)}
{visibility.delete && (
<div style={styles.menuItem}>
<button style={styles.button} onClick={onDelete}>
<span>Delete</span>
<span style={styles.shortcut}>X</span>
</button>
</div>
)}
</div>
</div> </div>
); );
}; };

View File

@@ -202,10 +202,10 @@ const UserAuth: React.FC = () => {
</div> </div>
{!isSignIn && ( {!isSignIn && (
<div className="policy-checkbox"> <div className="policy-checkbox">
<input type="checkbox" name="" id="" required /> <input type="checkbox" id="tos" required />
<div className="label"> <label htmlFor="tos" className="label">
I have read and agree to the terms of service I have read and agree to the terms of service
</div> </label>
</div> </div>
)} )}
<button id="form-submit" type="submit" className="continue-button"> <button id="form-submit" type="submit" className="continue-button">

View File

@@ -0,0 +1,62 @@
@use "../../abstracts/variables" as *;
@use "../../abstracts/mixins" as *;
.context-menu {
position: absolute;
top: 0;
left: 0;
background: var(--background-color);
backdrop-filter: blur(50px);
color: var(--text-button-color);
box-shadow: var(--box-shadow-light);
border-radius: 6px;
z-index: 1000;
min-width: 200px;
padding: 4px;
display: flex;
flex-direction: column;
gap: 2px;
.menuItem {
position: relative;
display: flex;
justify-content: space-between;
padding: 6px 8px;
border-radius: 10px;
cursor: pointer;
.submenu {
display: none;
min-width: 178px;
position: absolute;
top: 0;
left: 100%; // place directly beside
background: var(--background-color);
backdrop-filter: blur(50px);
color: var(--text-button-color);
box-shadow: var(--box-shadow-light);
padding: 4px;
border-radius: 6px;
z-index: 1000;
}
.button {
display: flex;
gap: 6px;
}
// Keep submenu open while hovering parent OR submenu
&:hover .submenu,
.submenu:hover {
display: block;
}
&:hover {
background-color: var(--background-color-button);
}
}
}

View File

@@ -27,6 +27,7 @@
@use "components/simulation/analysis"; @use "components/simulation/analysis";
@use "components/logs/logs"; @use "components/logs/logs";
@use "components/footer/footer.scss"; @use "components/footer/footer.scss";
@use "components/contextMenu/contextMenu";
// layout // layout
@use "layout/loading"; @use "layout/loading";