feat(mui): migrate Login (auth shell + 2FA) onto MUI kit; drop login.css
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,6 @@ import "./datepicker.css";
|
||||
import "./filemanager.css";
|
||||
import "./pagination.css";
|
||||
import "./responsive.css";
|
||||
import "./login.css";
|
||||
import "./dashboard.css";
|
||||
import "./attendance.css";
|
||||
import "./plan.css";
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
/* ============================================================================
|
||||
Login Page
|
||||
============================================================================ */
|
||||
|
||||
.admin-login {
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
max-height: 100vh;
|
||||
max-height: 100dvh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
background: var(--bg-primary);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.admin-login .bg-orb {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(80px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.admin-login .bg-orb-1 {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
background: var(--orb-color-1);
|
||||
top: 10%;
|
||||
left: 20%;
|
||||
animation: float 20s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.admin-login .bg-orb-2 {
|
||||
width: 320px;
|
||||
height: 320px;
|
||||
background: var(--orb-color-2);
|
||||
bottom: 20%;
|
||||
right: 15%;
|
||||
animation: float 25s ease-in-out infinite reverse;
|
||||
}
|
||||
|
||||
.admin-login-theme-btn {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
padding: 0;
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid var(--glass-border);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
transition: var(--transition);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.admin-login-theme-btn:hover {
|
||||
background: var(--glass-bg-solid);
|
||||
color: var(--text-primary);
|
||||
border-color: var(--border-color-hover);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.admin-login-card {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
max-height: calc(100vh - 2rem);
|
||||
max-height: calc(100dvh - 2rem);
|
||||
padding: 2rem;
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: var(--border-radius-lg);
|
||||
box-shadow: var(--glass-shadow);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.admin-login-card {
|
||||
padding: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-login-header {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.admin-login-logo {
|
||||
height: 48px;
|
||||
width: auto;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.admin-login-2fa-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent-light);
|
||||
color: var(--accent-color);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.admin-login-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
font-family: var(--font-heading);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.admin-login-subtitle {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.admin-back-link {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
font-size: 0.875rem;
|
||||
transition: var(--transition);
|
||||
margin-top: 1.5rem;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.admin-back-link:hover {
|
||||
color: var(--text-primary);
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useState, useEffect, useRef, useCallback } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import { useAlert } from "../context/AlertContext";
|
||||
import { useTheme } from "../../context/ThemeContext";
|
||||
@@ -8,7 +12,7 @@ import {
|
||||
shouldShowSessionExpiredAlert,
|
||||
shouldShowLogoutAlert,
|
||||
} from "../utils/api";
|
||||
import FormField from "../components/FormField";
|
||||
import { TextField, Button, CheckboxField, Field } from "../ui";
|
||||
|
||||
export default function Login() {
|
||||
const { login, verify2FA, isAuthenticated, loading: authLoading } = useAuth();
|
||||
@@ -132,11 +136,17 @@ export default function Login() {
|
||||
|
||||
if (authLoading) {
|
||||
return (
|
||||
<div className="admin-login">
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
</div>
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: ["100vh", "100dvh"],
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
bgcolor: "var(--bg-primary)",
|
||||
}}
|
||||
>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -144,32 +154,115 @@ export default function Login() {
|
||||
return <Navigate to="/" replace />;
|
||||
}
|
||||
|
||||
// Shared glass card sx (replaces .admin-login-card)
|
||||
const cardSx = {
|
||||
width: "100%",
|
||||
maxWidth: 420,
|
||||
maxHeight: "calc(100dvh - 2rem)",
|
||||
p: { xs: 4, sm: 5 },
|
||||
background: "var(--glass-bg)",
|
||||
backdropFilter: "blur(20px)",
|
||||
border: "1px solid var(--glass-border)",
|
||||
borderRadius: "var(--border-radius-lg)",
|
||||
boxShadow: "var(--glass-shadow)",
|
||||
position: "relative" as const,
|
||||
zIndex: 1,
|
||||
overflowY: "auto" as const,
|
||||
};
|
||||
|
||||
// Framer entrance + shake choreography for the card panels (unchanged)
|
||||
const cardMotion = {
|
||||
initial: { opacity: 0, y: 30 },
|
||||
animate: shake
|
||||
? { opacity: 1, y: 0, x: [0, -12, 12, -8, 8, -4, 4, 0] }
|
||||
: { opacity: 1, y: 0 },
|
||||
exit: { opacity: 0, y: -20 },
|
||||
transition: shake
|
||||
? { x: { duration: 0.5, ease: "easeOut" as const } }
|
||||
: { duration: 0.3 },
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className="admin-login"
|
||||
<Box
|
||||
component={motion.div}
|
||||
initial={{ opacity: 0, scale: 0.98 }}
|
||||
animate={
|
||||
animatingOut
|
||||
? { scale: 1.5, opacity: 0, filter: "blur(12px)" }
|
||||
: { scale: 1, opacity: 1, filter: "none" }
|
||||
}
|
||||
transition={
|
||||
animatingOut
|
||||
? { duration: 0.25, ease: [0.4, 0, 0.2, 1] }
|
||||
: { duration: 0.25, ease: [0.4, 0, 0.2, 1] }
|
||||
}
|
||||
transition={{ duration: 0.25, ease: [0.4, 0, 0.2, 1] }}
|
||||
sx={{
|
||||
minHeight: ["100vh", "100dvh"],
|
||||
maxHeight: ["100vh", "100dvh"],
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
p: 2,
|
||||
background: "var(--bg-primary)",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
>
|
||||
<div className="bg-orb bg-orb-1" />
|
||||
<div className="bg-orb bg-orb-2" />
|
||||
{/* Animated background orbs (replaces .bg-orb) */}
|
||||
<Box
|
||||
aria-hidden
|
||||
sx={{
|
||||
position: "absolute",
|
||||
borderRadius: "50%",
|
||||
filter: "blur(80px)",
|
||||
pointerEvents: "none",
|
||||
width: 400,
|
||||
height: 400,
|
||||
background: "var(--orb-color-1)",
|
||||
top: "10%",
|
||||
left: "20%",
|
||||
animation: "float 20s ease-in-out infinite",
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
aria-hidden
|
||||
sx={{
|
||||
position: "absolute",
|
||||
borderRadius: "50%",
|
||||
filter: "blur(80px)",
|
||||
pointerEvents: "none",
|
||||
width: 320,
|
||||
height: 320,
|
||||
background: "var(--orb-color-2)",
|
||||
bottom: "20%",
|
||||
right: "15%",
|
||||
animation: "float 25s ease-in-out infinite reverse",
|
||||
}}
|
||||
/>
|
||||
|
||||
<button
|
||||
{/* Theme toggle (replaces .admin-login-theme-btn) */}
|
||||
<IconButton
|
||||
onClick={toggleTheme}
|
||||
className="admin-login-theme-btn"
|
||||
title={theme === "dark" ? "Světlý režim" : "Tmavý režim"}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "1rem",
|
||||
right: "1rem",
|
||||
width: 44,
|
||||
height: 44,
|
||||
background: "var(--glass-bg)",
|
||||
backdropFilter: "blur(10px)",
|
||||
border: "1px solid var(--glass-border)",
|
||||
color: "var(--text-secondary)",
|
||||
overflow: "hidden",
|
||||
zIndex: 10,
|
||||
transition: "var(--transition)",
|
||||
"&:hover": {
|
||||
background: "var(--glass-bg-solid)",
|
||||
color: "var(--text-primary)",
|
||||
borderColor: "var(--border-color-hover)",
|
||||
transform: "scale(1.05)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className={`admin-theme-icon ${theme === "light" ? "visible" : ""}`}
|
||||
>
|
||||
{theme === "light" ? (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
@@ -181,10 +274,7 @@ export default function Login() {
|
||||
<circle cx="12" cy="12" r="5" />
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" />
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
className={`admin-theme-icon ${theme === "dark" ? "visible" : ""}`}
|
||||
>
|
||||
) : (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
@@ -195,122 +285,114 @@ export default function Login() {
|
||||
>
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
</IconButton>
|
||||
|
||||
<AnimatePresence mode="wait">
|
||||
{!show2FA ? (
|
||||
<motion.div
|
||||
key="login"
|
||||
className="admin-login-card"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={
|
||||
shake
|
||||
? { opacity: 1, y: 0, x: [0, -12, 12, -8, 8, -4, 4, 0] }
|
||||
: { opacity: 1, y: 0 }
|
||||
}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
transition={
|
||||
shake
|
||||
? { x: { duration: 0.5, ease: "easeOut" } }
|
||||
: { duration: 0.3 }
|
||||
}
|
||||
>
|
||||
<div className="admin-login-header">
|
||||
<img
|
||||
<Box key="login" component={motion.div} {...cardMotion} sx={cardSx}>
|
||||
<Box sx={{ textAlign: "center", mb: 4 }}>
|
||||
<Box
|
||||
component="img"
|
||||
src={
|
||||
theme === "dark"
|
||||
? "/api/admin/company-settings/logo?variant=dark"
|
||||
: "/api/admin/company-settings/logo?variant=light"
|
||||
}
|
||||
alt="Logo"
|
||||
className="admin-login-logo"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src =
|
||||
theme === "dark"
|
||||
? "/images/logo-dark.png"
|
||||
: "/images/logo-light.png";
|
||||
}}
|
||||
sx={{ height: 48, width: "auto", mb: 2 }}
|
||||
/>
|
||||
<h1 className="admin-login-title">Interní systém</h1>
|
||||
<p className="admin-login-subtitle">Přihlaste se ke svému účtu</p>
|
||||
</div>
|
||||
<Typography
|
||||
variant="h1"
|
||||
sx={{
|
||||
fontSize: "1.5rem",
|
||||
fontWeight: 700,
|
||||
color: "var(--text-primary)",
|
||||
fontFamily: "var(--font-heading)",
|
||||
mb: 1,
|
||||
}}
|
||||
>
|
||||
Interní systém
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{ color: "var(--text-secondary)", fontSize: "0.95rem" }}
|
||||
>
|
||||
Přihlaste se ke svému účtu
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<form onSubmit={handleSubmit} className="admin-form">
|
||||
<FormField label="Uživatelské jméno nebo e-mail">
|
||||
<input
|
||||
<Box component="form" onSubmit={handleSubmit}>
|
||||
<Field label="Uživatelské jméno nebo e-mail">
|
||||
<TextField
|
||||
id="username"
|
||||
type="text"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
required
|
||||
autoComplete="username"
|
||||
className="admin-form-input"
|
||||
placeholder="Zadejte uživatelské jméno"
|
||||
/>
|
||||
</FormField>
|
||||
</Field>
|
||||
|
||||
<FormField label="Heslo">
|
||||
<input
|
||||
<Field label="Heslo">
|
||||
<TextField
|
||||
id="password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
autoComplete="current-password"
|
||||
className="admin-form-input"
|
||||
placeholder="Zadejte heslo"
|
||||
/>
|
||||
</FormField>
|
||||
</Field>
|
||||
|
||||
<label className="admin-form-checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
<Box sx={{ mb: 2 }}>
|
||||
<CheckboxField
|
||||
label="Zapamatovat si mě"
|
||||
checked={remember}
|
||||
onChange={(e) => setRemember(e.target.checked)}
|
||||
onChange={setRemember}
|
||||
/>
|
||||
<span>Zapamatovat si mě</span>
|
||||
</label>
|
||||
</Box>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="admin-btn admin-btn-primary"
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Button type="submit" disabled={loading} fullWidth>
|
||||
{loading ? (
|
||||
<>
|
||||
<div
|
||||
className="admin-spinner"
|
||||
style={{ width: 20, height: 20, borderWidth: 2 }}
|
||||
<CircularProgress
|
||||
size={20}
|
||||
thickness={5}
|
||||
color="inherit"
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
Přihlašování...
|
||||
</>
|
||||
) : (
|
||||
"Přihlásit se"
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
</motion.div>
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<motion.div
|
||||
key="2fa"
|
||||
className="admin-login-card"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={
|
||||
shake
|
||||
? { opacity: 1, y: 0, x: [0, -12, 12, -8, 8, -4, 4, 0] }
|
||||
: { opacity: 1, y: 0 }
|
||||
}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
transition={
|
||||
shake
|
||||
? { x: { duration: 0.5, ease: "easeOut" } }
|
||||
: { duration: 0.3 }
|
||||
}
|
||||
>
|
||||
<div className="admin-login-header">
|
||||
<div className="admin-login-2fa-icon">
|
||||
<Box key="2fa" component={motion.div} {...cardMotion} sx={cardSx}>
|
||||
<Box sx={{ textAlign: "center", mb: 4 }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: "50%",
|
||||
background: "var(--accent-light)",
|
||||
color: "var(--accent-color)",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
@@ -322,26 +404,34 @@ export default function Login() {
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="admin-login-title">Dvoufaktorové ověření</h1>
|
||||
<p className="admin-login-subtitle">
|
||||
</Box>
|
||||
<Typography
|
||||
variant="h1"
|
||||
sx={{
|
||||
fontSize: "1.5rem",
|
||||
fontWeight: 700,
|
||||
color: "var(--text-primary)",
|
||||
fontFamily: "var(--font-heading)",
|
||||
mb: 1,
|
||||
}}
|
||||
>
|
||||
Dvoufaktorové ověření
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{ color: "var(--text-secondary)", fontSize: "0.95rem" }}
|
||||
>
|
||||
{useBackupCode
|
||||
? "Zadejte jeden ze záložních kódů"
|
||||
: "Zadejte 6místný kód z autentizační aplikace"}
|
||||
</p>
|
||||
</div>
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<form onSubmit={handle2FASubmit} className="admin-form">
|
||||
<FormField
|
||||
label={useBackupCode ? "Záložní kód" : "Ověřovací kód"}
|
||||
>
|
||||
<input
|
||||
ref={totpInputRef}
|
||||
<Box component="form" onSubmit={handle2FASubmit}>
|
||||
<Field label={useBackupCode ? "Záložní kód" : "Ověřovací kód"}>
|
||||
<TextField
|
||||
inputRef={totpInputRef}
|
||||
id="totp-code"
|
||||
type="text"
|
||||
inputMode={useBackupCode ? "text" : "numeric"}
|
||||
pattern={useBackupCode ? undefined : "[0-9]*"}
|
||||
maxLength={useBackupCode ? 8 : 6}
|
||||
value={totpCode}
|
||||
onChange={(e) => {
|
||||
const val = useBackupCode
|
||||
@@ -351,80 +441,93 @@ export default function Login() {
|
||||
}}
|
||||
required
|
||||
autoComplete="one-time-code"
|
||||
className="admin-form-input"
|
||||
placeholder={useBackupCode ? "XXXXXXXX" : "000000"}
|
||||
style={
|
||||
useBackupCode
|
||||
? {}
|
||||
: {
|
||||
textAlign: "center",
|
||||
fontSize: "1.5rem",
|
||||
letterSpacing: "0.5rem",
|
||||
fontFamily: "monospace",
|
||||
}
|
||||
}
|
||||
slotProps={{
|
||||
htmlInput: {
|
||||
inputMode: useBackupCode ? "text" : "numeric",
|
||||
pattern: useBackupCode ? undefined : "[0-9]*",
|
||||
maxLength: useBackupCode ? 8 : 6,
|
||||
style: useBackupCode
|
||||
? {}
|
||||
: {
|
||||
textAlign: "center",
|
||||
fontSize: "1.5rem",
|
||||
letterSpacing: "0.5rem",
|
||||
fontFamily: "monospace",
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</FormField>
|
||||
</Field>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="admin-btn admin-btn-primary"
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Button type="submit" disabled={loading} fullWidth>
|
||||
{loading ? (
|
||||
<>
|
||||
<div
|
||||
className="admin-spinner"
|
||||
style={{ width: 20, height: 20, borderWidth: 2 }}
|
||||
<CircularProgress
|
||||
size={20}
|
||||
thickness={5}
|
||||
color="inherit"
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
Ověřování...
|
||||
</>
|
||||
) : (
|
||||
"Ověřit"
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<div
|
||||
style={{
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "0.5rem",
|
||||
marginTop: "0.5rem",
|
||||
gap: 1,
|
||||
mt: 1,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
<Button
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
setUseBackupCode(!useBackupCode);
|
||||
setTotpCode("");
|
||||
}}
|
||||
className="admin-back-link"
|
||||
style={{
|
||||
border: "none",
|
||||
background: "none",
|
||||
cursor: "pointer",
|
||||
sx={{
|
||||
color: "var(--text-secondary)",
|
||||
fontSize: "0.875rem",
|
||||
fontWeight: 400,
|
||||
textTransform: "none",
|
||||
"&:hover": {
|
||||
color: "var(--text-primary)",
|
||||
textDecoration: "underline",
|
||||
background: "transparent",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{useBackupCode
|
||||
? "Použít autentizační aplikaci"
|
||||
: "Použít záložní kód"}
|
||||
</button>
|
||||
<button
|
||||
</Button>
|
||||
<Button
|
||||
variant="text"
|
||||
onClick={handleBack}
|
||||
className="admin-back-link"
|
||||
style={{
|
||||
border: "none",
|
||||
background: "none",
|
||||
cursor: "pointer",
|
||||
sx={{
|
||||
color: "var(--text-secondary)",
|
||||
fontSize: "0.875rem",
|
||||
fontWeight: 400,
|
||||
textTransform: "none",
|
||||
"&:hover": {
|
||||
color: "var(--text-primary)",
|
||||
textDecoration: "underline",
|
||||
background: "transparent",
|
||||
},
|
||||
}}
|
||||
>
|
||||
← Zpět na přihlášení
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user