Fix workflow add menu layout to use vertical stacking (#4568)

This commit is contained in:
Celal Zamanoglu
2026-01-28 19:53:37 +03:00
committed by GitHub
parent f9d249ccef
commit 39a926d526
2 changed files with 71 additions and 5 deletions

View File

@@ -18,8 +18,8 @@ interface RadialMenuProps {
*/
buttonSize?: string;
/**
* The gap between items in degrees. If not provided, items are evenly spaced
* around the circle.
* The gap between items in degrees (for radial layout) or pixels (for vertical layout).
* If not provided, items are evenly spaced around the circle (radial) or use 8px gap (vertical).
*/
gap?: number;
/**
@@ -35,6 +35,11 @@ interface RadialMenuProps {
* If true, rotates the text so its baseline runs parallel to the radial line.
*/
rotateText?: boolean;
/**
* Layout mode: "radial" (circular) or "vertical" (stacked list to the right).
* Defaults to "radial".
*/
layout?: "radial" | "vertical";
}
const proportionalAngle = (
@@ -76,6 +81,7 @@ export function RadialMenu({
gap,
startAt,
rotateText,
layout = "radial",
}: RadialMenuProps) {
const [isOpen, setIsOpen] = useState(false);
const [calculatedRadius, setCalculatedRadius] = useState<number>(100);
@@ -137,13 +143,72 @@ export function RadialMenu({
</div>
{visibleItems.map((item, index) => {
const isEnabled = item.enabled !== false;
const btnSize = buttonSize ?? "40px";
const btnSizeNum = parseFloat(btnSize);
if (layout === "vertical") {
// Vertical layout: stack items to the right of center
const verticalGap = gap ?? 8;
const xOffset = numRadius;
// Center the stack vertically around the middle item
const totalHeight =
visibleItems.length * btnSizeNum +
(visibleItems.length - 1) * verticalGap;
const startY = -totalHeight / 2 + btnSizeNum / 2;
const yOffset = startY + index * (btnSizeNum + verticalGap);
return (
<div
key={item.id}
onClick={() => {
if (isEnabled) {
item.onClick();
setIsOpen(false);
}
}}
className="absolute left-1/2 top-1/2 z-30 flex cursor-pointer items-center gap-2 transition-all duration-300 ease-out"
style={{
transform: isOpen
? `translate(0%, -50%) translate(${xOffset}px, ${yOffset}px) scale(1)`
: `translate(0%, -50%) translate(0, 0) scale(0)`,
opacity: isOpen ? (isEnabled ? 1 : 0.5) : 0,
pointerEvents: isOpen ? (isEnabled ? "auto" : "none") : "none",
transitionDelay: isOpen ? `${index * 50}ms` : "0ms",
}}
>
<button
disabled={!isEnabled}
className="flex items-center justify-center rounded-full bg-white shadow-lg hover:bg-gray-50 disabled:cursor-not-allowed"
style={{
width: btnSize,
height: btnSize,
}}
>
<div className="text-gray-700">{item.icon}</div>
</button>
{item.text && (
<span
className="whitespace-nowrap rounded bg-white px-2 py-1 text-xs text-gray-700 shadow-md"
style={{
opacity: isEnabled ? 1 : 0.5,
cursor: isEnabled ? "pointer" : "not-allowed",
}}
>
{item.text}
</span>
)}
</div>
);
}
// Radial layout (default)
const angle =
gap !== undefined
? gappedAngle(index, gap, startAt)
: proportionalAngle(index, visibleItems.length, startAt);
const x = Math.cos(angle) * parseFloat(radiusValue);
const y = Math.sin(angle) * parseFloat(radiusValue);
const isEnabled = item.enabled !== false;
// calculate text offset along the radial line
const textDistance = 0.375 * numRadius;
@@ -170,8 +235,8 @@ export function RadialMenu({
disabled={!isEnabled}
className="absolute left-1/2 top-1/2 z-30 flex items-center justify-center rounded-full bg-white shadow-lg transition-all duration-300 ease-out hover:bg-gray-50 disabled:cursor-not-allowed"
style={{
width: buttonSize ?? "40px",
height: buttonSize ?? "40px",
width: btnSize,
height: btnSize,
transform: isOpen
? `translate(-50%, -50%) translate(${x}px, ${y}px) scale(1)`
: "translate(-50%, -50%) translate(0, 0) scale(0)",

View File

@@ -97,6 +97,7 @@ function WorkflowAddMenu({
startAt={startAt}
gap={gap}
rotateText={rotateText}
layout="vertical"
>
{children}
</RadialMenu>