Refactor app by modularizing components and extracting utilities.
The changes split large features into smaller, reusable components like `AdminPanel`, `LoginPage`, `TopBar`, `PasswordModal`, and `ChipModal`. Utility functions such as `cycleTag` and `chipStorage` were extracted for better organization. This improves the code's readability, maintainability, and scalability.
This commit is contained in:
84
frontend/src/styles/hooks/useHpGlobalStyles.js
Normal file
84
frontend/src/styles/hooks/useHpGlobalStyles.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import { useEffect } from "react";
|
||||
import { stylesTokens } from "../theme";
|
||||
|
||||
export function useHpGlobalStyles() {
|
||||
// Google Fonts
|
||||
useEffect(() => {
|
||||
if (document.getElementById("hp-fonts")) return;
|
||||
|
||||
const pre1 = document.createElement("link");
|
||||
pre1.id = "hp-fonts-pre1";
|
||||
pre1.rel = "preconnect";
|
||||
pre1.href = "https://fonts.googleapis.com";
|
||||
|
||||
const pre2 = document.createElement("link");
|
||||
pre2.id = "hp-fonts-pre2";
|
||||
pre2.rel = "preconnect";
|
||||
pre2.href = "https://fonts.gstatic.com";
|
||||
pre2.crossOrigin = "anonymous";
|
||||
|
||||
const link = document.createElement("link");
|
||||
link.id = "hp-fonts";
|
||||
link.rel = "stylesheet";
|
||||
link.href =
|
||||
"https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@700;900&family=IM+Fell+English:ital,wght@0,400;0,700;1,400&display=swap";
|
||||
|
||||
document.head.appendChild(pre1);
|
||||
document.head.appendChild(pre2);
|
||||
document.head.appendChild(link);
|
||||
}, []);
|
||||
|
||||
// Keyframes
|
||||
useEffect(() => {
|
||||
if (document.getElementById("hp-anim-style")) return;
|
||||
const style = document.createElement("style");
|
||||
style.id = "hp-anim-style";
|
||||
style.innerHTML = `
|
||||
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||||
@keyframes popIn { from { opacity: 0; transform: translateY(8px) scale(0.985); } to { opacity: 1; transform: translateY(0) scale(1); } }
|
||||
@keyframes rowPulse { 0%{ transform: scale(1); } 50%{ transform: scale(1.01); } 100%{ transform: scale(1); } }
|
||||
@keyframes candleGlow {
|
||||
0% { opacity: .55; transform: translateY(0px) scale(1); filter: blur(16px); }
|
||||
35% { opacity: .85; transform: translateY(-2px) scale(1.02); filter: blur(18px); }
|
||||
70% { opacity: .62; transform: translateY(1px) scale(1.01); filter: blur(17px); }
|
||||
100% { opacity: .55; transform: translateY(0px) scale(1); filter: blur(16px); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}, []);
|
||||
|
||||
// html/body reset
|
||||
useEffect(() => {
|
||||
document.documentElement.style.height = "100%";
|
||||
document.body.style.height = "100%";
|
||||
document.documentElement.style.margin = "0";
|
||||
document.body.style.margin = "0";
|
||||
document.documentElement.style.padding = "0";
|
||||
document.body.style.padding = "0";
|
||||
}, []);
|
||||
|
||||
// Global CSS
|
||||
useEffect(() => {
|
||||
if (document.getElementById("hp-global-style")) return;
|
||||
const style = document.createElement("style");
|
||||
style.id = "hp-global-style";
|
||||
style.innerHTML = `
|
||||
html, body {
|
||||
overscroll-behavior-y: none;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background: ${stylesTokens.pageBg};
|
||||
color: ${stylesTokens.textMain};
|
||||
}
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
#root { background: transparent; }
|
||||
* { -webkit-tap-highlight-color: transparent; }
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}, []);
|
||||
}
|
||||
490
frontend/src/styles/styles.js
Normal file
490
frontend/src/styles/styles.js
Normal file
@@ -0,0 +1,490 @@
|
||||
import { stylesTokens } from "./theme";
|
||||
|
||||
export const styles = {
|
||||
page: {
|
||||
minHeight: "100dvh",
|
||||
background: "transparent",
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
},
|
||||
|
||||
shell: {
|
||||
fontFamily: '"IM Fell English", system-ui',
|
||||
padding: 16,
|
||||
maxWidth: 680,
|
||||
margin: "0 auto",
|
||||
},
|
||||
|
||||
topBar: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
padding: 12,
|
||||
borderRadius: 16,
|
||||
background: stylesTokens.panelBg,
|
||||
border: `1px solid ${stylesTokens.panelBorder}`,
|
||||
boxShadow: "0 12px 30px rgba(0,0,0,0.45)",
|
||||
backdropFilter: "blur(6px)",
|
||||
},
|
||||
|
||||
card: {
|
||||
borderRadius: 18,
|
||||
overflow: "hidden",
|
||||
border: `1px solid ${stylesTokens.panelBorder}`,
|
||||
background: "rgba(18, 18, 20, 0.50)",
|
||||
boxShadow: "0 18px 40px rgba(0,0,0,0.50), inset 0 1px 0 rgba(255,255,255,0.06)",
|
||||
},
|
||||
|
||||
cardBody: {
|
||||
padding: 12,
|
||||
display: "flex",
|
||||
gap: 10,
|
||||
alignItems: "center",
|
||||
},
|
||||
|
||||
sectionHeader: {
|
||||
padding: "11px 14px",
|
||||
fontWeight: 1000,
|
||||
fontFamily: '"Cinzel Decorative", "IM Fell English", system-ui',
|
||||
letterSpacing: 1.0,
|
||||
color: stylesTokens.textGold,
|
||||
background: "linear-gradient(180deg, rgba(32,32,36,0.92), rgba(14,14,16,0.92))",
|
||||
borderBottom: `1px solid ${stylesTokens.goldLine}`,
|
||||
textTransform: "uppercase",
|
||||
textShadow: "0 1px 0 rgba(0,0,0,0.6)",
|
||||
},
|
||||
|
||||
row: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 54px 68px",
|
||||
gap: 10,
|
||||
padding: "12px 14px",
|
||||
alignItems: "center",
|
||||
borderBottom: "1px solid rgba(233,216,166,0.08)",
|
||||
borderLeft: "4px solid rgba(0,0,0,0)",
|
||||
},
|
||||
|
||||
name: {
|
||||
cursor: "pointer",
|
||||
userSelect: "none",
|
||||
fontWeight: 800,
|
||||
letterSpacing: 0.2,
|
||||
color: stylesTokens.textMain,
|
||||
},
|
||||
|
||||
statusCell: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
|
||||
statusBadge: {
|
||||
width: 34,
|
||||
height: 34,
|
||||
display: "inline-flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
borderRadius: 999,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
fontWeight: 1100,
|
||||
fontSize: 16,
|
||||
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.06)",
|
||||
},
|
||||
|
||||
tagBtn: {
|
||||
padding: "8px 0",
|
||||
fontWeight: 1000,
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(255,255,255,0.06)",
|
||||
color: stylesTokens.textGold,
|
||||
cursor: "pointer",
|
||||
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.06)",
|
||||
},
|
||||
|
||||
helpBtn: {
|
||||
padding: "10px 12px",
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(255,255,255,0.06)",
|
||||
color: stylesTokens.textGold,
|
||||
fontWeight: 1000,
|
||||
cursor: "pointer",
|
||||
whiteSpace: "nowrap",
|
||||
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.06)",
|
||||
},
|
||||
|
||||
input: {
|
||||
width: "100%",
|
||||
padding: 10,
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(10,10,12,0.55)",
|
||||
color: stylesTokens.textMain,
|
||||
outline: "none",
|
||||
fontSize: 16,
|
||||
},
|
||||
|
||||
primaryBtn: {
|
||||
padding: "10px 12px",
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.28)`,
|
||||
background: "linear-gradient(180deg, rgba(233,216,166,0.24), rgba(233,216,166,0.10))",
|
||||
color: stylesTokens.textGold,
|
||||
fontWeight: 1000,
|
||||
cursor: "pointer",
|
||||
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.08)",
|
||||
},
|
||||
|
||||
secondaryBtn: {
|
||||
padding: "10px 12px",
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
color: stylesTokens.textMain,
|
||||
fontWeight: 900,
|
||||
cursor: "pointer",
|
||||
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.06)",
|
||||
},
|
||||
|
||||
// Admin
|
||||
adminWrap: {
|
||||
marginTop: 14,
|
||||
padding: 12,
|
||||
borderRadius: 16,
|
||||
border: `1px solid rgba(233,216,166,0.14)`,
|
||||
background: "rgba(18, 18, 20, 0.40)",
|
||||
boxShadow: "0 12px 30px rgba(0,0,0,0.45)",
|
||||
backdropFilter: "blur(6px)",
|
||||
},
|
||||
adminTop: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: 10,
|
||||
},
|
||||
adminTitle: {
|
||||
fontWeight: 1000,
|
||||
color: stylesTokens.textGold,
|
||||
},
|
||||
userRow: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 80px 90px",
|
||||
gap: 8,
|
||||
padding: 10,
|
||||
borderRadius: 12,
|
||||
background: "rgba(255,255,255,0.06)",
|
||||
border: `1px solid rgba(233,216,166,0.10)`,
|
||||
},
|
||||
|
||||
// Modal
|
||||
modalOverlay: {
|
||||
position: "fixed",
|
||||
inset: 0,
|
||||
background: "rgba(0,0,0,0.65)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: 16,
|
||||
zIndex: 9999,
|
||||
animation: "fadeIn 160ms ease-out",
|
||||
},
|
||||
modalCard: {
|
||||
width: "100%",
|
||||
maxWidth: 560,
|
||||
borderRadius: 18,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "linear-gradient(180deg, rgba(20,20,24,0.92), rgba(12,12,14,0.86))",
|
||||
boxShadow: "0 18px 55px rgba(0,0,0,0.70)",
|
||||
padding: 14,
|
||||
backdropFilter: "blur(6px)",
|
||||
animation: "popIn 160ms ease-out",
|
||||
color: stylesTokens.textMain,
|
||||
},
|
||||
modalHeader: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
},
|
||||
modalCloseBtn: {
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(255,255,255,0.06)",
|
||||
color: stylesTokens.textGold,
|
||||
fontWeight: 1000,
|
||||
cursor: "pointer",
|
||||
lineHeight: "38px",
|
||||
textAlign: "center",
|
||||
},
|
||||
|
||||
// Help
|
||||
helpBody: {
|
||||
marginTop: 10,
|
||||
paddingTop: 4,
|
||||
maxHeight: "70vh",
|
||||
overflow: "auto",
|
||||
},
|
||||
helpSectionTitle: {
|
||||
fontWeight: 1000,
|
||||
color: stylesTokens.textGold,
|
||||
marginTop: 10,
|
||||
marginBottom: 6,
|
||||
},
|
||||
helpText: {
|
||||
color: stylesTokens.textMain,
|
||||
opacity: 0.92,
|
||||
lineHeight: 1.35,
|
||||
},
|
||||
helpList: {
|
||||
marginTop: 10,
|
||||
display: "grid",
|
||||
gap: 8,
|
||||
},
|
||||
helpListRow: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "42px 1fr",
|
||||
gap: 10,
|
||||
alignItems: "center",
|
||||
color: stylesTokens.textMain,
|
||||
},
|
||||
helpBadge: {
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
fontWeight: 1100,
|
||||
fontSize: 18,
|
||||
},
|
||||
helpMiniTag: {
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(255,255,255,0.06)",
|
||||
color: stylesTokens.textGold,
|
||||
fontWeight: 1100,
|
||||
},
|
||||
helpDivider: {
|
||||
margin: "14px 0",
|
||||
height: 1,
|
||||
background: "rgba(233,216,166,0.12)",
|
||||
},
|
||||
|
||||
// Login
|
||||
loginPage: {
|
||||
minHeight: "100dvh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
padding: 20,
|
||||
background: "transparent",
|
||||
zIndex: 1,
|
||||
},
|
||||
loginCard: {
|
||||
width: "100%",
|
||||
maxWidth: 420,
|
||||
padding: 26,
|
||||
borderRadius: 22,
|
||||
position: "relative",
|
||||
zIndex: 2,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(18, 18, 20, 0.55)",
|
||||
boxShadow: "0 18px 60px rgba(0,0,0,0.70)",
|
||||
backdropFilter: "blur(8px)",
|
||||
animation: "popIn 240ms ease-out",
|
||||
color: stylesTokens.textMain,
|
||||
},
|
||||
loginTitle: {
|
||||
fontFamily: '"Cinzel Decorative", "IM Fell English", system-ui',
|
||||
fontWeight: 1000,
|
||||
fontSize: 26,
|
||||
color: stylesTokens.textGold,
|
||||
textAlign: "center",
|
||||
letterSpacing: 0.6,
|
||||
},
|
||||
loginSubtitle: {
|
||||
marginTop: 6,
|
||||
textAlign: "center",
|
||||
color: stylesTokens.textMain,
|
||||
opacity: 0.9,
|
||||
fontSize: 15,
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
loginFieldWrap: {
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
},
|
||||
loginInput: {
|
||||
width: "100%",
|
||||
padding: 10,
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(10,10,12,0.60)",
|
||||
color: stylesTokens.textMain,
|
||||
outline: "none",
|
||||
fontSize: 16,
|
||||
},
|
||||
loginBtn: {
|
||||
padding: "12px 14px",
|
||||
borderRadius: 14,
|
||||
border: `1px solid rgba(233,216,166,0.28)`,
|
||||
background: "linear-gradient(180deg, rgba(233,216,166,0.24), rgba(233,216,166,0.10))",
|
||||
color: stylesTokens.textGold,
|
||||
fontWeight: 1000,
|
||||
fontSize: 16,
|
||||
cursor: "pointer",
|
||||
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.08)",
|
||||
},
|
||||
loginHint: {
|
||||
marginTop: 18,
|
||||
fontSize: 13,
|
||||
opacity: 0.78,
|
||||
textAlign: "center",
|
||||
color: stylesTokens.textDim,
|
||||
lineHeight: 1.35,
|
||||
},
|
||||
|
||||
candleGlowLayer: {
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
pointerEvents: "none",
|
||||
background: `
|
||||
radial-gradient(circle at 20% 25%, rgba(255, 200, 120, 0.16), rgba(0,0,0,0) 40%),
|
||||
radial-gradient(circle at 80% 30%, rgba(255, 210, 140, 0.12), rgba(0,0,0,0) 42%),
|
||||
radial-gradient(circle at 55% 75%, rgba(255, 180, 100, 0.08), rgba(0,0,0,0) 45%)
|
||||
`,
|
||||
animation: "candleGlow 3.8s ease-in-out infinite",
|
||||
mixBlendMode: "multiply",
|
||||
},
|
||||
|
||||
inputRow: {
|
||||
display: "flex",
|
||||
alignItems: "stretch",
|
||||
width: "100%",
|
||||
},
|
||||
inputInRow: {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
borderRadius: "12px 0 0 12px",
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(10,10,12,0.60)",
|
||||
color: stylesTokens.textMain,
|
||||
outline: "none",
|
||||
minWidth: 0,
|
||||
fontSize: 16,
|
||||
},
|
||||
pwToggleBtn: {
|
||||
width: 48,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: "0 12px 12px 0",
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
borderLeft: "none",
|
||||
background: "rgba(255,255,255,0.06)",
|
||||
color: stylesTokens.textGold,
|
||||
cursor: "pointer",
|
||||
fontWeight: 900,
|
||||
padding: 0,
|
||||
},
|
||||
|
||||
// Background
|
||||
bgFixed: {
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100vw",
|
||||
height: "100dvh",
|
||||
zIndex: -1,
|
||||
pointerEvents: "none",
|
||||
transform: "translateZ(0)",
|
||||
backfaceVisibility: "hidden",
|
||||
willChange: "transform",
|
||||
},
|
||||
|
||||
bgMap: {
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
backgroundImage: 'url("/bg/marauders-map-blur.jpg")',
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
filter: "saturate(0.9) contrast(1.05) brightness(0.55)",
|
||||
},
|
||||
|
||||
chipGrid: {
|
||||
marginTop: 12,
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(5, minmax(0, 1fr))",
|
||||
gap: 8,
|
||||
},
|
||||
|
||||
chipBtn: {
|
||||
padding: "10px 14px",
|
||||
borderRadius: 12,
|
||||
border: "1px solid rgba(233,216,166,0.18)",
|
||||
background: "rgba(255,255,255,0.06)",
|
||||
color: stylesTokens.textGold,
|
||||
fontWeight: 1000,
|
||||
cursor: "pointer",
|
||||
minWidth: 64,
|
||||
},
|
||||
|
||||
userBtn: {
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
padding: "10px 12px",
|
||||
borderRadius: 12,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "rgba(255,255,255,0.05)",
|
||||
color: stylesTokens.textMain,
|
||||
fontWeight: 900,
|
||||
cursor: "pointer",
|
||||
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.06)",
|
||||
maxWidth: 180,
|
||||
},
|
||||
|
||||
userDropdown: {
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
top: "calc(100% + 8px)",
|
||||
minWidth: 220,
|
||||
borderRadius: 14,
|
||||
border: `1px solid rgba(233,216,166,0.18)`,
|
||||
background: "linear-gradient(180deg, rgba(20,20,24,0.96), rgba(12,12,14,0.92))",
|
||||
boxShadow: "0 18px 55px rgba(0,0,0,0.70)",
|
||||
overflow: "hidden",
|
||||
zIndex: 10000,
|
||||
backdropFilter: "blur(8px)",
|
||||
},
|
||||
|
||||
userDropdownItem: {
|
||||
width: "100%",
|
||||
textAlign: "left",
|
||||
padding: "10px 12px",
|
||||
border: "none",
|
||||
background: "transparent",
|
||||
color: stylesTokens.textMain,
|
||||
fontWeight: 900,
|
||||
cursor: "pointer",
|
||||
},
|
||||
|
||||
userDropdownDivider: {
|
||||
height: 1,
|
||||
background: "rgba(233,216,166,0.12)",
|
||||
},
|
||||
};
|
||||
11
frontend/src/styles/theme.js
Normal file
11
frontend/src/styles/theme.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export const stylesTokens = {
|
||||
pageBg: "#0b0b0c",
|
||||
panelBg: "rgba(20, 20, 22, 0.55)",
|
||||
panelBorder: "rgba(233, 216, 166, 0.14)",
|
||||
|
||||
textMain: "rgba(245, 239, 220, 0.92)",
|
||||
textDim: "rgba(233, 216, 166, 0.70)",
|
||||
textGold: "#e9d8a6",
|
||||
|
||||
goldLine: "rgba(233, 216, 166, 0.18)",
|
||||
};
|
||||
Reference in New Issue
Block a user