dev #4
@@ -2,7 +2,19 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { api } from "../api/client";
|
import { api } from "../api/client";
|
||||||
import { styles } from "../styles/styles";
|
import { styles } from "../styles/styles";
|
||||||
import { stylesTokens } from "../styles/theme";
|
import { stylesTokens } from "../styles/theme";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
|
||||||
|
const prev = document.body.style.overflow;
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.body.style.overflow = prev;
|
||||||
|
};
|
||||||
|
}, [open]);
|
||||||
export default function AdminPanel() {
|
export default function AdminPanel() {
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
|
|
||||||
@@ -112,7 +124,8 @@ export default function AdminPanel() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{open && (
|
{open &&
|
||||||
|
createPortal(
|
||||||
<div style={styles.modalOverlay} onMouseDown={closeModal}>
|
<div style={styles.modalOverlay} onMouseDown={closeModal}>
|
||||||
<div style={styles.modalCard} onMouseDown={(e) => e.stopPropagation()}>
|
<div style={styles.modalCard} onMouseDown={(e) => e.stopPropagation()}>
|
||||||
<div style={styles.modalHeader}>
|
<div style={styles.modalHeader}>
|
||||||
@@ -175,8 +188,10 @@ export default function AdminPanel() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>,
|
||||||
)}
|
document.body
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
40
frontend/src/components/ModalPortal.jsx
Normal file
40
frontend/src/components/ModalPortal.jsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
import { styles } from "../styles/styles";
|
||||||
|
|
||||||
|
export default function ModalPortal({ open, onClose, children }) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
|
||||||
|
const onKeyDown = (e) => {
|
||||||
|
if (e.key === "Escape") onClose?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scroll der Seite sperren
|
||||||
|
const prev = document.body.style.overflow;
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
|
||||||
|
window.addEventListener("keydown", onKeyDown);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("keydown", onKeyDown);
|
||||||
|
document.body.style.overflow = prev;
|
||||||
|
};
|
||||||
|
}, [open, onClose]);
|
||||||
|
|
||||||
|
if (!open) return null;
|
||||||
|
|
||||||
|
return createPortal(
|
||||||
|
<div
|
||||||
|
style={styles.modalOverlay}
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
// Klick außerhalb schließt
|
||||||
|
if (e.target === e.currentTarget) onClose?.();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={styles.modalCard} onMouseDown={(e) => e.stopPropagation()}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
document.body
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -188,32 +188,29 @@ export const styles = {
|
|||||||
// Modal
|
// Modal
|
||||||
modalOverlay: {
|
modalOverlay: {
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
inset: 0,
|
top: 0,
|
||||||
background: "rgba(0,0,0,0.78)", // stärker abdunkeln
|
left: 0,
|
||||||
backdropFilter: "blur(6px)", // Hintergrund weich (macht viel aus)
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
width: "100vw",
|
||||||
|
height: "100vh",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
padding: 16,
|
padding: 16,
|
||||||
zIndex: 9999,
|
zIndex: 2147483647, // wirklich ganz oben
|
||||||
animation: "fadeIn 160ms ease-out",
|
background: "rgba(0,0,0,0.72)",
|
||||||
overflowY: "auto", // falls Viewport zu klein
|
overflowY: "auto",
|
||||||
},
|
},
|
||||||
|
|
||||||
modalCard: {
|
modalCard: {
|
||||||
width: "100%",
|
width: "min(560px, 100%)",
|
||||||
maxWidth: 560,
|
|
||||||
borderRadius: 18,
|
borderRadius: 18,
|
||||||
border: `1px solid rgba(233,216,166,0.18)`,
|
border: `1px solid rgba(233,216,166,0.18)`,
|
||||||
background: "linear-gradient(180deg, rgba(20,20,24,0.95), rgba(12,12,14,0.92))",
|
background: "rgba(12,12,14,0.96)",
|
||||||
boxShadow: "0 18px 55px rgba(0,0,0,0.70)",
|
boxShadow: "0 18px 55px rgba(0,0,0,0.70)",
|
||||||
padding: 14,
|
padding: 14,
|
||||||
backdropFilter: "blur(8px)",
|
maxHeight: "calc(100vh - 32px)",
|
||||||
animation: "popIn 160ms ease-out",
|
|
||||||
color: stylesTokens.textMain,
|
|
||||||
|
|
||||||
// neu: damit es nie “kaputt” aussieht
|
|
||||||
maxHeight: "calc(100dvh - 32px)",
|
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
},
|
},
|
||||||
modalHeader: {
|
modalHeader: {
|
||||||
|
|||||||
Reference in New Issue
Block a user