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( +
+
+ {children} +
+
, + document.body, + ); +} \ No newline at end of file