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; buttonSize?: string;
/** /**
* The gap between items in degrees. If not provided, items are evenly spaced * The gap between items in degrees (for radial layout) or pixels (for vertical layout).
* around the circle. * If not provided, items are evenly spaced around the circle (radial) or use 8px gap (vertical).
*/ */
gap?: number; gap?: number;
/** /**
@@ -35,6 +35,11 @@ interface RadialMenuProps {
* If true, rotates the text so its baseline runs parallel to the radial line. * If true, rotates the text so its baseline runs parallel to the radial line.
*/ */
rotateText?: boolean; rotateText?: boolean;
/**
* Layout mode: "radial" (circular) or "vertical" (stacked list to the right).
* Defaults to "radial".
*/
layout?: "radial" | "vertical";
} }
const proportionalAngle = ( const proportionalAngle = (
@@ -76,6 +81,7 @@ export function RadialMenu({
gap, gap,
startAt, startAt,
rotateText, rotateText,
layout = "radial",
}: RadialMenuProps) { }: RadialMenuProps) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [calculatedRadius, setCalculatedRadius] = useState<number>(100); const [calculatedRadius, setCalculatedRadius] = useState<number>(100);
@@ -137,13 +143,72 @@ export function RadialMenu({
</div> </div>
{visibleItems.map((item, index) => { {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 = const angle =
gap !== undefined gap !== undefined
? gappedAngle(index, gap, startAt) ? gappedAngle(index, gap, startAt)
: proportionalAngle(index, visibleItems.length, startAt); : proportionalAngle(index, visibleItems.length, startAt);
const x = Math.cos(angle) * parseFloat(radiusValue); const x = Math.cos(angle) * parseFloat(radiusValue);
const y = Math.sin(angle) * parseFloat(radiusValue); const y = Math.sin(angle) * parseFloat(radiusValue);
const isEnabled = item.enabled !== false;
// calculate text offset along the radial line // calculate text offset along the radial line
const textDistance = 0.375 * numRadius; const textDistance = 0.375 * numRadius;
@@ -170,8 +235,8 @@ export function RadialMenu({
disabled={!isEnabled} 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" 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={{ style={{
width: buttonSize ?? "40px", width: btnSize,
height: buttonSize ?? "40px", height: btnSize,
transform: isOpen transform: isOpen
? `translate(-50%, -50%) translate(${x}px, ${y}px) scale(1)` ? `translate(-50%, -50%) translate(${x}px, ${y}px) scale(1)`
: "translate(-50%, -50%) translate(0, 0) scale(0)", : "translate(-50%, -50%) translate(0, 0) scale(0)",

View File

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