- Fixed Challenge Modal overlap issue by adjusting the main stacking context in App.tsx
- Implemented "click-outside-to-close" functionality for both the Challenge Modal and User Dropdown - Added protocol-specific action buttons for challenges: "Open in new tab" for HTTP and "Copy to clipboard" for NC - Enhanced Scoreboard rankings with significantly larger, consistent font sizes (text-2xl) for better readability - Rebranded "TEAM_IDENTIFIER" to "PLAYER" and "TOTAL_POINTS" to "POINTS" across the platform (Scoreboard, Matrix, User Menu) - Updated navigation: Renamed "SCOREBOARD" to "SCORES" in the nav bar and dynamic page titles - Modernized User Dropdown menu with a dedicated "PLAYER" header and "LOGOUT" action - Improved Score Matrix and Score Graph titles for consistency with the new "Player" terminology - Added CAPTCHA human verification (svg-captcha) to Login and Registration flows for enhanced security - Optimized frontend assets by migrating Tailwind and JetBrains Mono to local hosting - Refactored Admin panel: Renamed "Operators" to "Users" and improved layout alignment
This commit is contained in:
19
Admin.tsx
19
Admin.tsx
@@ -23,7 +23,7 @@ export const Admin: React.FC = () => {
|
||||
return [...state.challenges].sort((a, b) => a.title.localeCompare(b.title));
|
||||
}, [state.challenges]);
|
||||
|
||||
const sortedOperators = useMemo(() => {
|
||||
const sortedUsers = useMemo(() => {
|
||||
return [...state.teams]
|
||||
.filter(t => t.id !== 'admin-0')
|
||||
.sort((a, b) => (a.name || '').localeCompare(b.name || '', undefined, { sensitivity: 'base' }));
|
||||
@@ -107,8 +107,7 @@ export const Admin: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto py-12 px-6">
|
||||
<div className="flex flex-wrap gap-4 justify-between items-center mb-12 border-b-4 border-[#ff0000] pb-6">
|
||||
<h2 className="text-5xl font-black italic text-white uppercase tracking-tighter">ADMIN_CONSOLE</h2>
|
||||
<div className="flex flex-wrap gap-4 justify-end items-center mb-12 border-b-4 border-[#ff0000] pb-6">
|
||||
<div className="flex gap-4 items-center">
|
||||
{isBeforeStart && (
|
||||
<div className="px-4 py-2 hxp-border-purple bg-[#bf00ff]/10 hidden sm:flex items-center gap-3">
|
||||
@@ -256,19 +255,19 @@ export const Admin: React.FC = () => {
|
||||
</section>
|
||||
|
||||
<section className="space-y-6">
|
||||
<h3 className="text-2xl font-black text-[#bf00ff] border-b-2 border-[#bf00ff] uppercase italic">OPERATORS</h3>
|
||||
<h3 className="text-2xl font-black text-[#bf00ff] border-b-2 border-[#bf00ff] uppercase italic">USERS</h3>
|
||||
<div className="hxp-border border-2 overflow-hidden bg-black">
|
||||
<table className="w-full text-[10px] font-black">
|
||||
<thead className="bg-[#333] uppercase">
|
||||
<tr>
|
||||
<th className="p-3 text-left">TEAM_IDENTIFIER</th>
|
||||
<th className="p-3 text-left">USER_IDENTIFIER</th>
|
||||
<th className="p-3 text-center">ROLE</th>
|
||||
<th className="p-3 text-center">STATUS</th>
|
||||
<th className="p-3 text-right">ACTIONS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10 italic">
|
||||
{sortedOperators.map(team => (
|
||||
{sortedUsers.map(team => (
|
||||
<tr key={team.id} className="hover:bg-white/5 transition-colors group">
|
||||
<td className="p-3 text-white text-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -283,7 +282,7 @@ export const Admin: React.FC = () => {
|
||||
title={team.isAdmin ? "Revoke Admin Privileges" : "Grant Admin Privileges"}
|
||||
>
|
||||
{team.isAdmin ? <ShieldCheck size={12} /> : <Shield size={12} />}
|
||||
<span>{team.isAdmin ? 'ADMIN' : 'OPERATOR'}</span>
|
||||
<span>{team.isAdmin ? 'ADMIN' : 'USER'}</span>
|
||||
</button>
|
||||
</td>
|
||||
<td className="p-3 text-center uppercase">
|
||||
@@ -304,9 +303,9 @@ export const Admin: React.FC = () => {
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{sortedOperators.length === 0 && (
|
||||
{sortedUsers.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={4} className="p-10 text-center text-slate-700 font-black italic uppercase tracking-widest text-xs">No registered operators detected.</td>
|
||||
<td colSpan={4} className="p-10 text-center text-slate-700 font-black italic uppercase tracking-widest text-xs">No registered users detected.</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
@@ -451,7 +450,7 @@ export const Admin: React.FC = () => {
|
||||
<div className="fixed inset-0 bg-black/95 z-[400] flex items-center justify-center p-4">
|
||||
<div className="hxp-border border-4 max-md w-full max-w-md bg-black p-8 relative">
|
||||
<button onClick={() => setEditingTeam(null)} className="absolute top-4 right-4 text-white hover:text-red-500 transition-colors"><X size={24}/></button>
|
||||
<h3 className="text-3xl font-black italic text-white mb-8 uppercase">OPERATOR_PROFILE</h3>
|
||||
<h3 className="text-3xl font-black italic text-white mb-8 uppercase">USER_PROFILE</h3>
|
||||
<form onSubmit={async e => { e.preventDefault(); await updateTeam(editingTeam.id as string, { name: editingTeam.name, isDisabled: editingTeam.isDisabled, isAdmin: editingTeam.isAdmin, password: editingTeam.newPassword }); setEditingTeam(null); }} className="space-y-4">
|
||||
<input className="w-full bg-black hxp-border-purple p-3 text-white font-black" value={editingTeam.name} onChange={e => setEditingTeam({...editingTeam, name: e.target.value})} required />
|
||||
<input type="password" placeholder="UPDATE SECRET_KEY (OPTIONAL)" className="w-full bg-black hxp-border-purple p-3 text-white font-black" onChange={e => setEditingTeam({...editingTeam, newPassword: e.target.value})} />
|
||||
|
||||
Reference in New Issue
Block a user