Admin Dashboard hinzugefügt: Modernes Dashboard für Administratoren mit Statistiken, Verwaltungsmodulen und Schnellzugriffen
This commit is contained in:
@@ -2,6 +2,7 @@ import { Navigate, Route, Routes } from "react-router-dom";
|
|||||||
import { SessionProvider, useSession } from "./lib/session";
|
import { SessionProvider, useSession } from "./lib/session";
|
||||||
import AppShell from "./layout/AppShell";
|
import AppShell from "./layout/AppShell";
|
||||||
import HomePage from "./pages/HomePage";
|
import HomePage from "./pages/HomePage";
|
||||||
|
import AdminDashboardPage from "./pages/AdminDashboardPage";
|
||||||
import LoginPage from "./pages/LoginPage";
|
import LoginPage from "./pages/LoginPage";
|
||||||
import SampleRegistrationPage from "./pages/SampleRegistrationPage";
|
import SampleRegistrationPage from "./pages/SampleRegistrationPage";
|
||||||
import AnamnesisPage from "./pages/AnamnesisPage";
|
import AnamnesisPage from "./pages/AnamnesisPage";
|
||||||
@@ -30,7 +31,8 @@ function ProtectedRoutes() {
|
|||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<AppShell />}>
|
<Route element={<AppShell />}>
|
||||||
<Route path="/home" element={<HomePage />} />
|
<Route path="/home" element={isAdmin ? <AdminDashboardPage /> : <HomePage />} />
|
||||||
|
<Route path="/admin/dashboard" element={<AdminDashboardPage />} />
|
||||||
<Route path="/samples/new" element={<SampleRegistrationPage />} />
|
<Route path="/samples/new" element={<SampleRegistrationPage />} />
|
||||||
<Route path="/samples/:sampleId/registration" element={<SampleRegistrationPage />} />
|
<Route path="/samples/:sampleId/registration" element={<SampleRegistrationPage />} />
|
||||||
<Route path="/samples/:sampleId/anamnesis" element={<AnamnesisPage />} />
|
<Route path="/samples/:sampleId/anamnesis" element={<AnamnesisPage />} />
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useSession } from "../lib/session";
|
|||||||
|
|
||||||
const PAGE_TITLES: Record<string, string> = {
|
const PAGE_TITLES: Record<string, string> = {
|
||||||
"/home": "Startseite",
|
"/home": "Startseite",
|
||||||
|
"/admin/dashboard": "Admin Dashboard",
|
||||||
"/samples/new": "Neuanlage einer Probe",
|
"/samples/new": "Neuanlage einer Probe",
|
||||||
"/portal": "MUH-Portal",
|
"/portal": "MUH-Portal",
|
||||||
"/report-template": "Bericht",
|
"/report-template": "Bericht",
|
||||||
@@ -62,12 +63,65 @@ export default function AppShell() {
|
|||||||
|
|
||||||
<nav className="sidebar__nav">
|
<nav className="sidebar__nav">
|
||||||
{user?.role === "ADMIN" ? (
|
{user?.role === "ADMIN" ? (
|
||||||
<NavLink
|
<>
|
||||||
to="/portal"
|
<NavLink
|
||||||
className={({ isActive }) => `nav-link ${isActive ? "is-active" : ""}`}
|
to="/admin/dashboard"
|
||||||
>
|
className={({ isActive }) => `nav-link ${isActive ? "is-active" : ""}`}
|
||||||
Benutzerverwaltung
|
>
|
||||||
</NavLink>
|
Dashboard
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to="/samples/new" className={({ isActive }) => `nav-link ${isActive ? "is-active" : ""}`}>
|
||||||
|
Neue Probe
|
||||||
|
</NavLink>
|
||||||
|
|
||||||
|
<div className="nav-group">
|
||||||
|
<div className="nav-group__label">Verwaltung</div>
|
||||||
|
<div className="nav-subnav">
|
||||||
|
<div className="nav-subgroup">
|
||||||
|
<div className="nav-subgroup__label">Vorlagen</div>
|
||||||
|
<div className="nav-subnav nav-subnav--nested">
|
||||||
|
<NavLink to="/report-template" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Bericht
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NavLink to="/admin/landwirte" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Landwirte
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to="/admin/medikamente" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Medikamente
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to="/admin/erreger" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Erreger
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to="/admin/antibiogramm" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Antibiogramm
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to="/admin/benutzer" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Benutzer
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="nav-group">
|
||||||
|
<div className="nav-group__label">Suche</div>
|
||||||
|
<div className="nav-subnav">
|
||||||
|
<NavLink to="/search/landwirt" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Landwirt
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to="/search/probe" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Probe
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to="/search/kalendar" className={({ isActive }) => `nav-sublink ${isActive ? "is-active" : ""}`}>
|
||||||
|
Kalendar
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NavLink to="/portal" className={({ isActive }) => `nav-link ${isActive ? "is-active" : ""}`}>
|
||||||
|
Portal
|
||||||
|
</NavLink>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<NavLink to="/home" className={({ isActive }) => `nav-link ${isActive ? "is-active" : ""}`}>
|
<NavLink to="/home" className={({ isActive }) => `nav-link ${isActive ? "is-active" : ""}`}>
|
||||||
|
|||||||
192
frontend/src/pages/AdminDashboardPage.tsx
Normal file
192
frontend/src/pages/AdminDashboardPage.tsx
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { apiGet } from "../lib/api";
|
||||||
|
import type { DashboardOverview } from "../lib/types";
|
||||||
|
|
||||||
|
interface AdminStats {
|
||||||
|
totalSamples: number;
|
||||||
|
openSamples: number;
|
||||||
|
completedToday: number;
|
||||||
|
nextSampleNumber: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AdminDashboardPage() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [stats, setStats] = useState<AdminStats | null>(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function loadStats() {
|
||||||
|
try {
|
||||||
|
const dashboard = await apiGet<DashboardOverview>("/dashboard");
|
||||||
|
setStats({
|
||||||
|
totalSamples: dashboard.nextSampleNumber - 1,
|
||||||
|
openSamples: dashboard.openSamples,
|
||||||
|
completedToday: dashboard.completedToday,
|
||||||
|
nextSampleNumber: dashboard.nextSampleNumber,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadStats();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const adminModules = [
|
||||||
|
{
|
||||||
|
title: "Landwirte",
|
||||||
|
description: "Verwaltung der Landwirte und Betriebe",
|
||||||
|
icon: "👨🌾",
|
||||||
|
route: "/admin/landwirte",
|
||||||
|
color: "#4a7c59",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Benutzer",
|
||||||
|
description: "Benutzerverwaltung und Berechtigungen",
|
||||||
|
icon: "👥",
|
||||||
|
route: "/admin/benutzer",
|
||||||
|
color: "#5b7ba8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Medikamente",
|
||||||
|
description: "Verwaltung der Medikamentenkataloge",
|
||||||
|
icon: "💊",
|
||||||
|
route: "/admin/medikamente",
|
||||||
|
color: "#8b5a7c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Erreger",
|
||||||
|
description: "Verwaltung der Erreger und Kürzel",
|
||||||
|
icon: "🦠",
|
||||||
|
route: "/admin/erreger",
|
||||||
|
color: "#7c5a5a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Antibiogramm",
|
||||||
|
description: "Verwaltung der Antibiotika-Kataloge",
|
||||||
|
icon: "📊",
|
||||||
|
route: "/admin/antibiogramm",
|
||||||
|
color: "#5a7c7c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Berichtsvorlage",
|
||||||
|
description: "Gestaltung der PDF-Berichtsvorlagen",
|
||||||
|
icon: "📄",
|
||||||
|
route: "/report-template",
|
||||||
|
color: "#7c7c5a",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="page-stack">
|
||||||
|
{/* Header Bereich */}
|
||||||
|
<section className="hero-card admin-hero">
|
||||||
|
<div>
|
||||||
|
<p className="eyebrow">Administration</p>
|
||||||
|
<h3>Administrator Dashboard</h3>
|
||||||
|
<p className="muted-text">
|
||||||
|
Verwalten Sie Landwirte, Benutzer, Medikamente, Erreger und Systemeinstellungen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Statistik-Karten */}
|
||||||
|
<section className="metrics-grid admin-metrics">
|
||||||
|
<article className="metric-card metric-card--primary">
|
||||||
|
<span className="metric-card__label">Nächste Probennummer</span>
|
||||||
|
<strong className="metric-card__value--large">
|
||||||
|
{loading ? "..." : stats?.nextSampleNumber}
|
||||||
|
</strong>
|
||||||
|
</article>
|
||||||
|
<article className="metric-card">
|
||||||
|
<span className="metric-card__label">Offene Proben</span>
|
||||||
|
<strong>{loading ? "..." : stats?.openSamples}</strong>
|
||||||
|
</article>
|
||||||
|
<article className="metric-card">
|
||||||
|
<span className="metric-card__label">Heute abgeschlossen</span>
|
||||||
|
<strong>{loading ? "..." : stats?.completedToday}</strong>
|
||||||
|
</article>
|
||||||
|
<article className="metric-card">
|
||||||
|
<span className="metric-card__label">Gesamtproben</span>
|
||||||
|
<strong>{loading ? "..." : stats?.totalSamples}</strong>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Admin Module Grid */}
|
||||||
|
<section className="admin-modules-section">
|
||||||
|
<div className="section-card__header">
|
||||||
|
<div>
|
||||||
|
<p className="eyebrow">Verwaltung</p>
|
||||||
|
<h3>Verwaltungsmodule</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="admin-modules-grid">
|
||||||
|
{adminModules.map((module) => (
|
||||||
|
<button
|
||||||
|
key={module.route}
|
||||||
|
type="button"
|
||||||
|
className="admin-module-card"
|
||||||
|
onClick={() => navigate(module.route)}
|
||||||
|
style={{ "--module-color": module.color } as React.CSSProperties}
|
||||||
|
>
|
||||||
|
<span className="admin-module-card__icon">{module.icon}</span>
|
||||||
|
<div className="admin-module-card__content">
|
||||||
|
<strong>{module.title}</strong>
|
||||||
|
<span className="muted-text">{module.description}</span>
|
||||||
|
</div>
|
||||||
|
<span className="admin-module-card__arrow">→</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Schnellzugriffe */}
|
||||||
|
<section className="quick-actions-section">
|
||||||
|
<div className="section-card">
|
||||||
|
<div className="section-card__header">
|
||||||
|
<div>
|
||||||
|
<p className="eyebrow">Schnellzugriff</p>
|
||||||
|
<h3>Häufige Aktionen</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="quick-actions-grid">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="quick-action-button"
|
||||||
|
onClick={() => navigate("/samples/new")}
|
||||||
|
>
|
||||||
|
<span>➕</span>
|
||||||
|
<span>Neue Probe anlegen</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="quick-action-button"
|
||||||
|
onClick={() => navigate("/search/probe")}
|
||||||
|
>
|
||||||
|
<span>🔍</span>
|
||||||
|
<span>Probe suchen</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="quick-action-button"
|
||||||
|
onClick={() => navigate("/portal")}
|
||||||
|
>
|
||||||
|
<span>📧</span>
|
||||||
|
<span>Portal & Berichte</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="quick-action-button"
|
||||||
|
onClick={() => navigate("/search/landwirt")}
|
||||||
|
>
|
||||||
|
<span>👤</span>
|
||||||
|
<span>Landwirt suchen</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { FormEvent, useState } from "react";
|
import { FormEvent, useState } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import { apiPost } from "../lib/api";
|
import { apiPost } from "../lib/api";
|
||||||
import { useSession } from "../lib/session";
|
import { useSession } from "../lib/session";
|
||||||
import type { SessionResponse } from "../lib/types";
|
import type { SessionResponse } from "../lib/types";
|
||||||
@@ -28,6 +29,7 @@ export default function LoginPage() {
|
|||||||
});
|
});
|
||||||
const [feedback, setFeedback] = useState<FeedbackState>(null);
|
const [feedback, setFeedback] = useState<FeedbackState>(null);
|
||||||
const { setSession } = useSession();
|
const { setSession } = useSession();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
function unlockLoginInputs() {
|
function unlockLoginInputs() {
|
||||||
setLoginInputsUnlocked(true);
|
setLoginInputsUnlocked(true);
|
||||||
@@ -50,6 +52,8 @@ export default function LoginPage() {
|
|||||||
password,
|
password,
|
||||||
});
|
});
|
||||||
setSession(response);
|
setSession(response);
|
||||||
|
// Admin zum Dashboard, Kunden zur Startseite
|
||||||
|
navigate(response.user.role === "ADMIN" ? "/admin/dashboard" : "/home");
|
||||||
} catch (loginError) {
|
} catch (loginError) {
|
||||||
setFeedback({ type: "error", text: (loginError as Error).message });
|
setFeedback({ type: "error", text: (loginError as Error).message });
|
||||||
}
|
}
|
||||||
@@ -88,6 +92,8 @@ export default function LoginPage() {
|
|||||||
text: `Registrierung erfolgreich. Willkommen ${response.user.companyName ?? response.user.displayName}.`,
|
text: `Registrierung erfolgreich. Willkommen ${response.user.companyName ?? response.user.displayName}.`,
|
||||||
});
|
});
|
||||||
setSession(response);
|
setSession(response);
|
||||||
|
// Admin zum Dashboard, Kunden zur Startseite
|
||||||
|
navigate(response.user.role === "ADMIN" ? "/admin/dashboard" : "/home");
|
||||||
} catch (registrationError) {
|
} catch (registrationError) {
|
||||||
setFeedback({ type: "error", text: (registrationError as Error).message });
|
setFeedback({ type: "error", text: (registrationError as Error).message });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1088,6 +1088,162 @@ a {
|
|||||||
min-height: 88px;
|
min-height: 88px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Admin Dashboard Styles */
|
||||||
|
.admin-hero {
|
||||||
|
background: linear-gradient(135deg, rgba(90, 123, 168, 0.15) 0%, rgba(74, 124, 89, 0.1) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-metrics {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.admin-metrics {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.admin-metrics {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card--primary {
|
||||||
|
background: linear-gradient(135deg, rgba(90, 123, 168, 0.25) 0%, rgba(90, 123, 168, 0.1) 100%);
|
||||||
|
border-color: rgba(90, 123, 168, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card__value--large {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
background: linear-gradient(135deg, var(--text) 0%, #5b7ba8 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-modules-section {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-modules-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.admin-modules-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.admin-modules-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
border-radius: var(--radius-xl);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
text-align: left;
|
||||||
|
border-left: 4px solid var(--module-color, #5b7ba8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card__icon {
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card__content strong {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card__content .muted-text {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card__arrow {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--muted);
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-module-card:hover .admin-module-card__arrow {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-actions-section {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-actions-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.quick-actions-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.quick-actions-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-action-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-action-button:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-action-button span:first-child {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.dialog-backdrop {
|
.dialog-backdrop {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user