diff --git a/vite-frontend/src/pages/node.tsx b/vite-frontend/src/pages/node.tsx index b98733d..2613dc1 100644 --- a/vite-frontend/src/pages/node.tsx +++ b/vite-frontend/src/pages/node.tsx @@ -375,6 +375,41 @@ export default function NodePage() { Record >({}); + const [infoPopoverPlacement, setInfoPopoverPlacement] = useState< + Record + >({}); + + const updateInfoPopoverPlacement = useCallback( + (nodeId: number, triggerElement: HTMLElement | null) => { + if (!triggerElement) { + return; + } + + const rect = triggerElement.getBoundingClientRect(); + const cardElement = triggerElement.closest("[data-node-card='true']"); + const cardRect = + cardElement instanceof HTMLElement + ? cardElement.getBoundingClientRect() + : null; + const estimatedPanelWidth = 288; + const containerPadding = 16; + const availableLeftSpace = cardRect + ? rect.left - cardRect.left + : rect.left; + const nextPlacement: "left" | "bottom" = + availableLeftSpace >= estimatedPanelWidth + containerPadding + ? "left" + : "bottom"; + + setInfoPopoverPlacement((prev) => + prev[nodeId] === nextPlacement + ? prev + : { ...prev, [nodeId]: nextPlacement }, + ); + }, + [], + ); + const handleNodeOffline = useCallback((nodeId: number) => { setNodeList((prev) => prev.map((node) => { @@ -1710,10 +1745,12 @@ export default function NodePage() { !node.expiryReminderDismissed, ); const hasInfoTrigger = hasRemark || hasExpiryInfo; + const infoCount = Number(hasExpiryInfo) + Number(hasRemark); + const infoPlacement = infoPopoverPlacement[node.id] ?? "left"; return ( - {(listeners, attributes) => ( + {(listeners) => (
+
+ +
{selectMode && (
-
-
- -
+
+ {hasInfoTrigger && ( +
+ +
+
+ {hasExpiryInfo && ( +
+
+
+ 到期提醒 +
+ +
+
+ + {expiryMeta.label} + +
+
+ {formatNodeRenewalTime( + expiryMeta.nextDueTime, + )} +
+
+ )} + + {hasRemark && ( +
+
+ 备注 +
+
+ {node.remark?.trim()} +
+
+ )} +
+
+
+ )}
@@ -2114,60 +2248,6 @@ export default function NodePage() { )} - {hasInfoTrigger && ( -
- {hasExpiryInfo && ( -
-
-
- 到期提醒 -
- -
-
- - {expiryMeta.label} - -
-
- {formatNodeRenewalTime( - expiryMeta.nextDueTime, - )} -
-
- )} - - {hasRemark && ( -
-
- 备注 -
-
- {node.remark?.trim()} -
-
- )} -
- )} -
{/* 操作按钮 */}