diff --git a/frontend/src/components/kubernetes/ResourceVisualEditor.tsx b/frontend/src/components/kubernetes/ResourceVisualEditor.tsx
index 2eb3c49..5aeac79 100644
--- a/frontend/src/components/kubernetes/ResourceVisualEditor.tsx
+++ b/frontend/src/components/kubernetes/ResourceVisualEditor.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect, useCallback } from 'react';
import { X, Save, Loader2, Plus, Trash2, FileText, Network, Shield, Database, ChevronRight} from 'lucide-react';
import { Button } from '@/components/ui/button';
+import { ModalOverlay } from '@/components/ui/modal-overlay';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
@@ -132,8 +133,11 @@ export function ResourceVisualEditor({ clusterCode, namespace, resource, name, o
const MetaIcon = meta.icon;
return (
-
-
e.stopPropagation()}>
+
+ e.stopPropagation()}
+ >
{/* Header */}
@@ -206,7 +210,7 @@ export function ResourceVisualEditor({ clusterCode, namespace, resource, name, o
)}
-
+
);
}
diff --git a/frontend/src/components/kubernetes/YamlImportDialog.tsx b/frontend/src/components/kubernetes/YamlImportDialog.tsx
index c21a930..60a5d84 100644
--- a/frontend/src/components/kubernetes/YamlImportDialog.tsx
+++ b/frontend/src/components/kubernetes/YamlImportDialog.tsx
@@ -2,6 +2,7 @@
import { useState } from 'react';
import { X, Upload, Loader2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
+import { ModalOverlay } from '@/components/ui/modal-overlay';
import { useToast } from '@/hooks/use-toast';
import { kubernetesApi } from '@/api';
import CodeMirror from '@uiw/react-codemirror';
@@ -36,7 +37,7 @@ export function YamlImportDialog({ clusterCode, onClose, onApplied }: YamlImport
};
return (
-
+
e.stopPropagation()}
@@ -71,6 +72,6 @@ export function YamlImportDialog({ clusterCode, onClose, onApplied }: YamlImport
-
+
);
}
\ No newline at end of file
diff --git a/frontend/src/components/kubernetes/YamlViewer.tsx b/frontend/src/components/kubernetes/YamlViewer.tsx
index 7ca8740..2c1a570 100644
--- a/frontend/src/components/kubernetes/YamlViewer.tsx
+++ b/frontend/src/components/kubernetes/YamlViewer.tsx
@@ -4,6 +4,7 @@
import { useState, useEffect, useMemo} from 'react';
import { X, Copy, Check, Save, Loader2, Sparkles} from 'lucide-react';
import { Button } from '@/components/ui/button';
+import { ModalOverlay } from '@/components/ui/modal-overlay';
import { useToast } from '@/hooks/use-toast';
import { kubernetesApi } from '@/api';
import { cleanYAML } from './k8s-yaml-utils';
@@ -186,10 +187,13 @@ export function YamlViewer({ clusterCode, namespace, resource, name, onClose, on
);
}
- // 弹窗模式(原有行为)
+ // 弹窗模式 — Portal 到 body,避免 PageTransition transform 导致偏移 // Logan.Li
return (
-
-
e.stopPropagation()}>
+
+ e.stopPropagation()}
+ >
{/* Header */}
@@ -260,6 +264,6 @@ export function YamlViewer({ clusterCode, namespace, resource, name, onClose, on
)}
-
+
);
}
diff --git a/frontend/src/components/ui/modal-overlay.tsx b/frontend/src/components/ui/modal-overlay.tsx
new file mode 100644
index 0000000..46de437
--- /dev/null
+++ b/frontend/src/components/ui/modal-overlay.tsx
@@ -0,0 +1,24 @@
+// ModalOverlay — Portal 到 body,避免父级 transform 导致 fixed 弹框偏移 // Logan.Li
+import { createPortal } from 'react-dom';
+
+interface ModalOverlayProps {
+ onClose: () => void;
+ children: React.ReactNode;
+ /** 遮罩 z-index,默认高于 Sidebar/Header */
+ zIndex?: number;
+}
+
+export function ModalOverlay({ onClose, children, zIndex = 100 }: ModalOverlayProps) {
+ return createPortal(
+
,
+ document.body,
+ );
+}
\ No newline at end of file