Compare commits
2 Commits
f0c9a9e4cc
...
6c08789555
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c08789555 | ||
|
|
7dbd044859 |
@@ -69,18 +69,64 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
|
||||
return (
|
||||
<section className="relative w-full min-h-screen flex flex-col items-center overflow-hidden pt-24 pb-16">
|
||||
<div className="relative z-10 w-full max-w-6xl mx-auto px-8 py-16">
|
||||
<h1 className="text-4xl font-gaming font-black mb-8 text-center">
|
||||
<div className="relative z-10 w-full max-w-6xl mx-auto px-4 sm:px-8 py-16">
|
||||
<h1 className="text-2xl sm:text-4xl font-gaming font-black mb-8 text-center break-words">
|
||||
<span className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent">
|
||||
ADMIN
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
{/* Navigation Tabs */}
|
||||
<div className="flex gap-4 mb-8 justify-center">
|
||||
<div className="mb-8">
|
||||
{/* Mobile: Grid layout */}
|
||||
<div className="grid grid-cols-2 sm:hidden gap-2">
|
||||
<button
|
||||
onClick={() => setActiveSection("preferences")}
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${
|
||||
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
||||
activeSection === "preferences"
|
||||
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
}`}
|
||||
>
|
||||
Préférences
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection("users")}
|
||||
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
||||
activeSection === "users"
|
||||
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
}`}
|
||||
>
|
||||
Utilisateurs
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection("events")}
|
||||
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
||||
activeSection === "events"
|
||||
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
}`}
|
||||
>
|
||||
Événements
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection("feedbacks")}
|
||||
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
||||
activeSection === "feedbacks"
|
||||
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
}`}
|
||||
>
|
||||
Feedbacks
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Desktop: Horizontal tabs */}
|
||||
<div className="hidden sm:flex gap-4 justify-center">
|
||||
<button
|
||||
onClick={() => setActiveSection("preferences")}
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition whitespace-nowrap ${
|
||||
activeSection === "preferences"
|
||||
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
@@ -90,7 +136,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection("users")}
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition whitespace-nowrap ${
|
||||
activeSection === "users"
|
||||
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
@@ -100,7 +146,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection("events")}
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition whitespace-nowrap ${
|
||||
activeSection === "events"
|
||||
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
@@ -110,7 +156,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection("feedbacks")}
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${
|
||||
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition whitespace-nowrap ${
|
||||
activeSection === "feedbacks"
|
||||
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold"
|
||||
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
||||
@@ -119,27 +165,28 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
Feedbacks
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{activeSection === "preferences" && (
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
||||
<h2 className="text-xl sm:text-2xl font-gaming font-bold mb-6 text-pixel-gold break-words">
|
||||
Préférences UI Globales
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="bg-black/60 border border-pixel-gold/20 rounded p-4">
|
||||
<div className="flex justify-between items-start mb-4">
|
||||
<div>
|
||||
<h3 className="text-pixel-gold font-bold text-lg">
|
||||
<div className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4">
|
||||
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3 mb-4">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-pixel-gold font-bold text-base sm:text-lg break-words">
|
||||
Images de fond du site
|
||||
</h3>
|
||||
<p className="text-gray-400 text-sm">
|
||||
<p className="text-gray-400 text-xs sm:text-sm">
|
||||
Ces préférences s'appliquent à tous les utilisateurs
|
||||
</p>
|
||||
</div>
|
||||
{!isEditing && (
|
||||
<button
|
||||
onClick={handleEdit}
|
||||
className="px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition"
|
||||
className="px-3 sm:px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition whitespace-nowrap flex-shrink-0"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
@@ -178,7 +225,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
}
|
||||
label="Background Leaderboard"
|
||||
/>
|
||||
<div className="flex gap-2 pt-4">
|
||||
<div className="flex flex-col sm:flex-row gap-2 pt-4">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
className="px-4 py-2 border border-green-500/50 bg-green-900/20 text-green-400 uppercase text-xs tracking-widest rounded hover:bg-green-900/30 transition"
|
||||
@@ -195,70 +242,76 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-pixel-gold font-bold min-w-[120px]">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
|
||||
Home:
|
||||
</span>
|
||||
{preferences?.homeBackground ? (
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
|
||||
<img
|
||||
src={preferences.homeBackground}
|
||||
alt="Home background"
|
||||
className="w-20 h-12 object-cover rounded border border-pixel-gold/30"
|
||||
className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
|
||||
onError={(e) => {
|
||||
e.currentTarget.src = "/got-2.jpg";
|
||||
}}
|
||||
/>
|
||||
<span className="text-xs text-gray-400 truncate max-w-xs">
|
||||
<span className="text-xs text-gray-400 truncate min-w-0">
|
||||
{preferences.homeBackground}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-gray-400">Par défaut</span>
|
||||
<span className="text-gray-400 text-sm sm:text-base">
|
||||
Par défaut
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-pixel-gold font-bold min-w-[120px]">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
|
||||
Events:
|
||||
</span>
|
||||
{preferences?.eventsBackground ? (
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
|
||||
<img
|
||||
src={preferences.eventsBackground}
|
||||
alt="Events background"
|
||||
className="w-20 h-12 object-cover rounded border border-pixel-gold/30"
|
||||
className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
|
||||
onError={(e) => {
|
||||
e.currentTarget.src = "/got-2.jpg";
|
||||
}}
|
||||
/>
|
||||
<span className="text-xs text-gray-400 truncate max-w-xs">
|
||||
<span className="text-xs text-gray-400 truncate min-w-0">
|
||||
{preferences.eventsBackground}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-gray-400">Par défaut</span>
|
||||
<span className="text-gray-400 text-sm sm:text-base">
|
||||
Par défaut
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-pixel-gold font-bold min-w-[120px]">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
|
||||
Leaderboard:
|
||||
</span>
|
||||
{preferences?.leaderboardBackground ? (
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
|
||||
<img
|
||||
src={preferences.leaderboardBackground}
|
||||
alt="Leaderboard background"
|
||||
className="w-20 h-12 object-cover rounded border border-pixel-gold/30"
|
||||
className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
|
||||
onError={(e) => {
|
||||
e.currentTarget.src = "/got-2.jpg";
|
||||
}}
|
||||
/>
|
||||
<span className="text-xs text-gray-400 truncate max-w-xs">
|
||||
<span className="text-xs text-gray-400 truncate min-w-0">
|
||||
{preferences.leaderboardBackground}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-gray-400">Par défaut</span>
|
||||
<span className="text-gray-400 text-sm sm:text-base">
|
||||
Par défaut
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -269,7 +322,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
)}
|
||||
|
||||
{activeSection === "users" && (
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm">
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Utilisateurs
|
||||
</h2>
|
||||
@@ -278,7 +331,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
)}
|
||||
|
||||
{activeSection === "events" && (
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm">
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Événements
|
||||
</h2>
|
||||
@@ -287,7 +340,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
||||
)}
|
||||
|
||||
{activeSection === "feedbacks" && (
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm">
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Feedbacks
|
||||
</h2>
|
||||
|
||||
@@ -213,14 +213,14 @@ export default function EventManagement() {
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-xl font-gaming font-bold text-pixel-gold">
|
||||
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4">
|
||||
<h3 className="text-lg sm:text-xl font-gaming font-bold text-pixel-gold break-words">
|
||||
Événements ({events.length})
|
||||
</h3>
|
||||
{!isCreating && !editingEvent && (
|
||||
<button
|
||||
onClick={handleCreate}
|
||||
className="px-4 py-2 border border-green-500/50 bg-green-900/20 text-green-400 uppercase text-xs tracking-widest rounded hover:bg-green-900/30 transition"
|
||||
className="px-3 sm:px-4 py-2 border border-green-500/50 bg-green-900/20 text-green-400 uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-green-900/30 transition whitespace-nowrap flex-shrink-0"
|
||||
>
|
||||
+ Nouvel événement
|
||||
</button>
|
||||
@@ -228,24 +228,28 @@ export default function EventManagement() {
|
||||
</div>
|
||||
|
||||
{(isCreating || editingEvent) && (
|
||||
<div className="bg-black/60 border border-pixel-gold/20 rounded p-4 mb-4">
|
||||
<h4 className="text-pixel-gold font-bold mb-4">
|
||||
<div className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4 mb-4">
|
||||
<h4 className="text-pixel-gold font-bold mb-4 text-base sm:text-lg break-words">
|
||||
{isCreating ? "Créer un événement" : "Modifier l'événement"}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">Date</label>
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1">
|
||||
Date
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
value={formData.date}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, date: e.target.value })
|
||||
}
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">Nom</label>
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1">
|
||||
Nom
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.name}
|
||||
@@ -253,11 +257,11 @@ export default function EventManagement() {
|
||||
setFormData({ ...formData, name: e.target.value })
|
||||
}
|
||||
placeholder="Nom de l'événement"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1">
|
||||
Description
|
||||
</label>
|
||||
<textarea
|
||||
@@ -267,12 +271,14 @@ export default function EventManagement() {
|
||||
}
|
||||
placeholder="Description de l'événement"
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">Type</label>
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1">
|
||||
Type
|
||||
</label>
|
||||
<select
|
||||
value={formData.type}
|
||||
onChange={(e) =>
|
||||
@@ -281,7 +287,7 @@ export default function EventManagement() {
|
||||
type: e.target.value as Event["type"],
|
||||
})
|
||||
}
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
|
||||
>
|
||||
{eventTypes.map((type) => (
|
||||
<option key={type} value={type}>
|
||||
@@ -291,9 +297,9 @@ export default function EventManagement() {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1">
|
||||
Salle
|
||||
</label>
|
||||
<input
|
||||
@@ -303,11 +309,11 @@ export default function EventManagement() {
|
||||
setFormData({ ...formData, room: e.target.value })
|
||||
}
|
||||
placeholder="Ex: Nautilus"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1">
|
||||
Heure
|
||||
</label>
|
||||
<input
|
||||
@@ -317,11 +323,11 @@ export default function EventManagement() {
|
||||
setFormData({ ...formData, time: e.target.value })
|
||||
}
|
||||
placeholder="Ex: 11h-12h"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1">
|
||||
Places max
|
||||
</label>
|
||||
<input
|
||||
@@ -336,11 +342,11 @@ export default function EventManagement() {
|
||||
})
|
||||
}
|
||||
placeholder="Ex: 25"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
@@ -368,19 +374,19 @@ export default function EventManagement() {
|
||||
{events.map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
className="bg-black/60 border border-pixel-gold/20 rounded p-4"
|
||||
className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4"
|
||||
>
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<h4 className="text-pixel-gold font-bold text-lg">
|
||||
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex flex-wrap items-center gap-2 sm:gap-3 mb-2">
|
||||
<h4 className="text-pixel-gold font-bold text-base sm:text-lg break-words">
|
||||
{event.name}
|
||||
</h4>
|
||||
<span className="px-2 py-1 bg-pixel-gold/20 border border-pixel-gold/50 text-pixel-gold text-xs uppercase rounded">
|
||||
<span className="px-2 py-1 bg-pixel-gold/20 border border-pixel-gold/50 text-pixel-gold text-[10px] sm:text-xs uppercase rounded whitespace-nowrap flex-shrink-0">
|
||||
{getEventTypeLabel(event.type)}
|
||||
</span>
|
||||
<span
|
||||
className={`px-2 py-1 text-xs uppercase rounded ${(() => {
|
||||
className={`px-2 py-1 text-[10px] sm:text-xs uppercase rounded whitespace-nowrap flex-shrink-0 ${(() => {
|
||||
const status = calculateEventStatus(event.date);
|
||||
return status === "UPCOMING"
|
||||
? "bg-green-900/50 border border-green-500/50 text-green-400"
|
||||
@@ -392,45 +398,45 @@ export default function EventManagement() {
|
||||
{getStatusLabel(calculateEventStatus(event.date))}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-gray-400 text-sm mb-2">
|
||||
<p className="text-gray-400 text-xs sm:text-sm mb-2 break-words">
|
||||
{event.description}
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center gap-4 mt-2">
|
||||
<p className="text-gray-500 text-xs">
|
||||
<div className="flex flex-wrap items-center gap-2 sm:gap-4 mt-2">
|
||||
<p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
|
||||
Date: {new Date(event.date).toLocaleDateString("fr-FR")}
|
||||
</p>
|
||||
{event.room && (
|
||||
<p className="text-gray-500 text-xs">
|
||||
<p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
|
||||
📍 Salle: {event.room}
|
||||
</p>
|
||||
)}
|
||||
{event.time && (
|
||||
<p className="text-gray-500 text-xs">
|
||||
<p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
|
||||
🕐 Heure: {event.time}
|
||||
</p>
|
||||
)}
|
||||
{event.maxPlaces && (
|
||||
<p className="text-gray-500 text-xs">
|
||||
<p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
|
||||
👥 Places: {event.maxPlaces}
|
||||
</p>
|
||||
)}
|
||||
<span className="px-2 py-1 bg-blue-900/30 border border-blue-500/50 text-blue-400 text-xs rounded">
|
||||
<span className="px-2 py-1 bg-blue-900/30 border border-blue-500/50 text-blue-400 text-[10px] sm:text-xs rounded whitespace-nowrap flex-shrink-0">
|
||||
{event.registrationsCount || 0} inscrit
|
||||
{event.registrationsCount !== 1 ? "s" : ""}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{!isCreating && !editingEvent && (
|
||||
<div className="flex gap-2 ml-4">
|
||||
<div className="flex gap-2 sm:ml-4 flex-shrink-0">
|
||||
<button
|
||||
onClick={() => handleEdit(event)}
|
||||
className="px-3 py-1 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition whitespace-nowrap"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDelete(event.id)}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-xs tracking-widest rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-red-900/30 transition whitespace-nowrap"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
|
||||
@@ -74,18 +74,20 @@ export default function FeedbackManagement() {
|
||||
|
||||
const renderStars = (rating: number) => {
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-0.5 sm:gap-1">
|
||||
{[1, 2, 3, 4, 5].map((star) => (
|
||||
<span
|
||||
key={star}
|
||||
className={`text-lg ${
|
||||
className={`text-sm sm:text-lg ${
|
||||
star <= rating ? "text-pixel-gold" : "text-gray-600"
|
||||
}`}
|
||||
>
|
||||
★
|
||||
</span>
|
||||
))}
|
||||
<span className="text-gray-400 text-sm ml-2">({rating}/5)</span>
|
||||
<span className="text-gray-400 text-xs sm:text-sm ml-1 sm:ml-2">
|
||||
({rating}/5)
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -96,25 +98,25 @@ export default function FeedbackManagement() {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-8">
|
||||
<p className="text-gray-400 text-center">Chargement...</p>
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-4 sm:p-8">
|
||||
<p className="text-gray-400 text-center text-sm">Chargement...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-4 sm:space-y-6">
|
||||
{/* Statistiques par événement */}
|
||||
{statistics.length > 0 && (
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-6">
|
||||
<h3 className="text-pixel-gold font-bold text-lg mb-4">
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-3 sm:p-6">
|
||||
<h3 className="text-pixel-gold font-bold text-base sm:text-lg mb-4 break-words">
|
||||
Statistiques par événement
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4">
|
||||
{statistics.map((stat) => (
|
||||
<div
|
||||
key={stat.eventId}
|
||||
className={`bg-black/40 border rounded p-4 cursor-pointer transition ${
|
||||
className={`bg-black/40 border rounded p-3 sm:p-4 cursor-pointer transition ${
|
||||
selectedEvent === stat.eventId
|
||||
? "border-pixel-gold bg-pixel-gold/10"
|
||||
: "border-pixel-gold/30 hover:border-pixel-gold/50"
|
||||
@@ -125,21 +127,21 @@ export default function FeedbackManagement() {
|
||||
)
|
||||
}
|
||||
>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<h4 className="text-white font-semibold text-sm">
|
||||
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-2 mb-2">
|
||||
<h4 className="text-white font-semibold text-xs sm:text-sm break-words">
|
||||
{stat.eventName}
|
||||
</h4>
|
||||
<span className="text-pixel-gold text-xs uppercase">
|
||||
<span className="text-pixel-gold text-[10px] sm:text-xs uppercase whitespace-nowrap flex-shrink-0">
|
||||
{stat.eventType && getEventTypeLabel(stat.eventType)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
{renderStars(Math.round(stat.averageRating))}
|
||||
</div>
|
||||
<div className="text-gray-400 text-xs">
|
||||
<div className="text-gray-400 text-[10px] sm:text-xs">
|
||||
Moyenne: {stat.averageRating.toFixed(2)}/5
|
||||
</div>
|
||||
<div className="text-gray-400 text-xs">
|
||||
<div className="text-gray-400 text-[10px] sm:text-xs">
|
||||
{stat.feedbackCount} feedback
|
||||
{stat.feedbackCount > 1 ? "s" : ""}
|
||||
</div>
|
||||
@@ -149,7 +151,7 @@ export default function FeedbackManagement() {
|
||||
{selectedEvent && (
|
||||
<button
|
||||
onClick={() => setSelectedEvent(null)}
|
||||
className="mt-4 text-pixel-gold text-sm hover:text-orange-400 transition"
|
||||
className="mt-4 text-pixel-gold text-xs sm:text-sm hover:text-orange-400 transition"
|
||||
>
|
||||
Voir tous les feedbacks
|
||||
</button>
|
||||
@@ -158,8 +160,8 @@ export default function FeedbackManagement() {
|
||||
)}
|
||||
|
||||
{/* Liste des feedbacks */}
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-6">
|
||||
<h3 className="text-pixel-gold font-bold text-lg mb-4">
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-3 sm:p-6">
|
||||
<h3 className="text-pixel-gold font-bold text-base sm:text-lg mb-4 break-words">
|
||||
{selectedEvent
|
||||
? `Feedbacks pour: ${
|
||||
statistics.find((s) => s.eventId === selectedEvent)?.eventName
|
||||
@@ -168,36 +170,36 @@ export default function FeedbackManagement() {
|
||||
</h3>
|
||||
|
||||
{error && (
|
||||
<div className="bg-red-900/50 border border-red-500/50 text-red-400 px-4 py-3 rounded text-sm mb-4">
|
||||
<div className="bg-red-900/50 border border-red-500/50 text-red-400 px-3 sm:px-4 py-2 sm:py-3 rounded text-xs sm:text-sm mb-4">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filteredFeedbacks.length === 0 ? (
|
||||
<p className="text-gray-400 text-center py-8">
|
||||
<p className="text-gray-400 text-center py-8 text-sm">
|
||||
Aucun feedback pour le moment
|
||||
</p>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-3 sm:space-y-4">
|
||||
{filteredFeedbacks.map((feedback) => (
|
||||
<div
|
||||
key={feedback.id}
|
||||
className="bg-black/40 border border-pixel-gold/20 rounded p-4"
|
||||
className="bg-black/40 border border-pixel-gold/20 rounded p-3 sm:p-4"
|
||||
>
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<h4 className="text-white font-semibold">
|
||||
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-3">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3 mb-2">
|
||||
<h4 className="text-white font-semibold text-sm sm:text-base break-words">
|
||||
{feedback.user.username}
|
||||
</h4>
|
||||
<span className="text-gray-500 text-xs">
|
||||
<span className="text-gray-500 text-[10px] sm:text-xs break-all">
|
||||
{feedback.user.email}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-pixel-gold text-sm font-semibold mb-2">
|
||||
<div className="text-pixel-gold text-xs sm:text-sm font-semibold mb-2 break-words">
|
||||
{feedback.event.name}
|
||||
</div>
|
||||
<div className="text-gray-500 text-xs mb-2">
|
||||
<div className="text-gray-500 text-[10px] sm:text-xs mb-2">
|
||||
{new Date(feedback.createdAt).toLocaleDateString(
|
||||
"fr-FR",
|
||||
{
|
||||
@@ -210,11 +212,13 @@ export default function FeedbackManagement() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div>{renderStars(feedback.rating)}</div>
|
||||
<div className="flex-shrink-0">
|
||||
{renderStars(feedback.rating)}
|
||||
</div>
|
||||
</div>
|
||||
{feedback.comment && (
|
||||
<div className="mt-3 pt-3 border-t border-pixel-gold/20">
|
||||
<p className="text-gray-300 text-sm whitespace-pre-wrap">
|
||||
<p className="text-gray-300 text-xs sm:text-sm whitespace-pre-wrap break-words">
|
||||
{feedback.comment}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -2,34 +2,9 @@
|
||||
|
||||
import { useBackgroundImage } from "@/hooks/usePreferences";
|
||||
import Link from "next/link";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
|
||||
export default function HeroSection() {
|
||||
const backgroundImage = useBackgroundImage("home", "/got-2.jpg");
|
||||
const titleRef = useRef<HTMLSpanElement>(null);
|
||||
const [mousePosition, setMousePosition] = useState({ x: 50, y: 50 });
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
if (titleRef.current) {
|
||||
const rect = titleRef.current.getBoundingClientRect();
|
||||
const x = ((e.clientX - rect.left) / rect.width) * 100;
|
||||
const y = ((e.clientY - rect.top) / rect.height) * 100;
|
||||
setMousePosition({
|
||||
x: Math.max(0, Math.min(100, x)),
|
||||
y: Math.max(0, Math.min(100, y)),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("mousemove", handleMouseMove);
|
||||
return () => window.removeEventListener("mousemove", handleMouseMove);
|
||||
}, []);
|
||||
|
||||
// Calculer la position du gradient basée sur la souris avec plus d'amplitude
|
||||
const gradientPosition = mousePosition.x;
|
||||
const glowIntensity = 12 + mousePosition.x / 5;
|
||||
const glowOpacity = 0.4 + mousePosition.y / 250;
|
||||
|
||||
return (
|
||||
<section className="relative w-full min-h-screen flex flex-col items-center justify-center overflow-hidden pt-24">
|
||||
@@ -45,49 +20,24 @@ export default function HeroSection() {
|
||||
</div>
|
||||
|
||||
{/* Hero Content */}
|
||||
<div className="relative z-10 w-full max-w-5xl xl:max-w-6xl mx-auto px-8 py-16 text-center flex flex-col items-center">
|
||||
<div className="relative z-10 w-full max-w-5xl xl:max-w-6xl mx-auto px-4 sm:px-8 py-16 text-center flex flex-col items-center">
|
||||
{/* Game Title */}
|
||||
<div className="w-full flex justify-center mb-4">
|
||||
<h1 className="text-6xl md:text-8xl lg:text-9xl xl:text-9xl font-gaming font-black tracking-tight relative">
|
||||
<div className="w-full flex justify-center mb-4 overflow-hidden">
|
||||
<h1 className="text-4xl sm:text-5xl md:text-8xl lg:text-9xl xl:text-9xl font-gaming font-black tracking-tight relative break-words">
|
||||
<span
|
||||
ref={titleRef}
|
||||
className="title-animated inline-block relative z-10"
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(90deg, #daa520 0%, #ffa500 ${Math.max(
|
||||
10,
|
||||
gradientPosition - 20
|
||||
)}%, #ff8c00 ${gradientPosition}%, #ffa500 ${Math.min(
|
||||
90,
|
||||
gradientPosition + 20
|
||||
)}%, #daa520 100%)`,
|
||||
backgroundImage: `linear-gradient(90deg, #daa520 0%, #ffa500 30%, #ff8c00 50%, #ffa500 70%, #daa520 100%)`,
|
||||
backgroundSize: "200% auto",
|
||||
WebkitBackgroundClip: "text",
|
||||
WebkitTextFillColor: "transparent",
|
||||
backgroundClip: "text",
|
||||
color: "transparent",
|
||||
transition: "background-image 0.15s ease-out",
|
||||
filter: `drop-shadow(0 0 ${glowIntensity}px rgba(255, 140, 0, ${glowOpacity}))`,
|
||||
filter: `drop-shadow(0 0 12px rgba(255, 140, 0, 0.4))`,
|
||||
}}
|
||||
>
|
||||
GAME.OF.TECH
|
||||
</span>
|
||||
{/* Glow effect qui suit la souris */}
|
||||
<span
|
||||
className="absolute inset-0 pointer-events-none"
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(90deg, transparent 0%, rgba(255, 140, 0, 0.3) ${gradientPosition}%, transparent 100%)`,
|
||||
WebkitBackgroundClip: "text",
|
||||
WebkitTextFillColor: "transparent",
|
||||
backgroundClip: "text",
|
||||
filter: `blur(${10 + mousePosition.x / 20}px)`,
|
||||
opacity: 0.5,
|
||||
zIndex: 0,
|
||||
transition: "all 0.15s ease-out",
|
||||
}}
|
||||
aria-hidden="true"
|
||||
>
|
||||
GAME.OF.TECH
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -76,13 +76,15 @@ export default function ImageSelector({
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<label className="block text-sm text-gray-300 mb-1">{label}</label>
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-1 break-words">
|
||||
{label}
|
||||
</label>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4">
|
||||
{/* Colonne gauche - Image */}
|
||||
<div className="flex-shrink-0">
|
||||
<div className="flex-shrink-0 flex justify-center sm:justify-start">
|
||||
{value ? (
|
||||
<div className="relative w-48 h-32 border border-pixel-gold/30 rounded overflow-hidden bg-black/60">
|
||||
<div className="relative w-full sm:w-48 h-40 sm:h-32 border border-pixel-gold/30 rounded overflow-hidden bg-black/60">
|
||||
<img
|
||||
src={value}
|
||||
alt="Preview"
|
||||
@@ -99,34 +101,34 @@ export default function ImageSelector({
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-48 h-32 border border-pixel-gold/30 rounded bg-black/60 flex items-center justify-center">
|
||||
<div className="w-full sm:w-48 h-40 sm:h-32 border border-pixel-gold/30 rounded bg-black/60 flex items-center justify-center">
|
||||
<span className="text-xs text-gray-500">Aucune</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Colonne droite - Contrôles */}
|
||||
<div className="flex-1 space-y-3">
|
||||
<div className="flex-1 space-y-3 min-w-0">
|
||||
{/* Input URL */}
|
||||
<div className="flex gap-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={urlInput}
|
||||
onChange={(e) => setUrlInput(e.target.value)}
|
||||
onKeyPress={(e) => e.key === "Enter" && handleUrlSubmit()}
|
||||
placeholder="https://example.com/image.jpg ou /image.jpg"
|
||||
className="flex-1 px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
className="flex-1 px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm min-w-0"
|
||||
/>
|
||||
<button
|
||||
onClick={handleUrlSubmit}
|
||||
className="px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition"
|
||||
className="px-3 sm:px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition whitespace-nowrap flex-shrink-0"
|
||||
>
|
||||
URL
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Upload depuis le disque */}
|
||||
<div className="flex gap-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
@@ -137,7 +139,7 @@ export default function ImageSelector({
|
||||
/>
|
||||
<label
|
||||
htmlFor={`file-${label}`}
|
||||
className={`flex-1 px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition text-center cursor-pointer ${
|
||||
className={`flex-1 px-3 sm:px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition text-center cursor-pointer ${
|
||||
uploading ? "opacity-50 cursor-not-allowed" : ""
|
||||
}`}
|
||||
>
|
||||
@@ -145,22 +147,26 @@ export default function ImageSelector({
|
||||
</label>
|
||||
<button
|
||||
onClick={() => setShowGallery(!showGallery)}
|
||||
className="px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition"
|
||||
className="px-3 sm:px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition whitespace-nowrap"
|
||||
>
|
||||
{showGallery ? "Masquer" : "Galerie"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Chemin de l'image */}
|
||||
{value && <p className="text-xs text-gray-400 truncate">{value}</p>}
|
||||
{value && (
|
||||
<p className="text-xs text-gray-400 truncate break-all">{value}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Galerie d'images */}
|
||||
{showGallery && (
|
||||
<div className="mt-4 p-4 bg-black/40 border border-pixel-gold/20 rounded">
|
||||
<h4 className="text-sm text-gray-300 mb-3">Images disponibles</h4>
|
||||
<div className="grid grid-cols-3 md:grid-cols-4 gap-3 max-h-64 overflow-y-auto">
|
||||
<div className="mt-4 p-3 sm:p-4 bg-black/40 border border-pixel-gold/20 rounded">
|
||||
<h4 className="text-xs sm:text-sm text-gray-300 mb-3">
|
||||
Images disponibles
|
||||
</h4>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 sm:gap-3 max-h-64 overflow-y-auto">
|
||||
{availableImages.length === 0 ? (
|
||||
<div className="col-span-full text-center text-gray-400 text-sm py-4">
|
||||
Aucune image disponible
|
||||
|
||||
@@ -45,10 +45,10 @@ export default function LeaderboardSection({
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10 w-full max-w-6xl mx-auto px-8 py-16">
|
||||
<div className="relative z-10 w-full max-w-6xl mx-auto px-4 sm:px-8 py-16">
|
||||
{/* Title Section */}
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="text-5xl md:text-7xl font-gaming font-black mb-4 tracking-tight">
|
||||
<div className="text-center mb-12 overflow-hidden">
|
||||
<h1 className="text-3xl sm:text-4xl md:text-7xl font-gaming font-black mb-4 tracking-tight break-words">
|
||||
<span
|
||||
className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent"
|
||||
style={{
|
||||
@@ -66,11 +66,11 @@ export default function LeaderboardSection({
|
||||
</div>
|
||||
|
||||
{/* Leaderboard Table */}
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg backdrop-blur-sm">
|
||||
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg backdrop-blur-sm overflow-x-auto">
|
||||
{/* Header */}
|
||||
<div className="bg-gray-900/80 border-b border-pixel-gold/30 grid grid-cols-12 gap-4 p-4 font-bold text-xs uppercase tracking-widest text-gray-300">
|
||||
<div className="col-span-1 text-center">Rank</div>
|
||||
<div className="col-span-6">Player</div>
|
||||
<div className="bg-gray-900/80 border-b border-pixel-gold/30 grid grid-cols-12 gap-2 sm:gap-4 p-2 sm:p-4 font-bold text-[10px] sm:text-xs uppercase tracking-widest text-gray-300">
|
||||
<div className="col-span-2 sm:col-span-1 text-center">Rank</div>
|
||||
<div className="col-span-5 sm:col-span-6">Player</div>
|
||||
<div className="col-span-3 text-right">Score</div>
|
||||
<div className="col-span-2 text-right">Level</div>
|
||||
</div>
|
||||
@@ -80,16 +80,16 @@ export default function LeaderboardSection({
|
||||
{leaderboard.map((entry) => (
|
||||
<div
|
||||
key={entry.rank}
|
||||
className={`grid grid-cols-12 gap-4 p-4 hover:bg-gray-900/50 transition relative ${
|
||||
className={`grid grid-cols-12 gap-2 sm:gap-4 p-2 sm:p-4 hover:bg-gray-900/50 transition relative ${
|
||||
entry.rank <= 3
|
||||
? "bg-gradient-to-r from-pixel-gold/10 via-pixel-gold/5 to-transparent"
|
||||
: "bg-black/40"
|
||||
}`}
|
||||
>
|
||||
{/* Rank */}
|
||||
<div className="col-span-1 flex items-center justify-center">
|
||||
<div className="col-span-2 sm:col-span-1 flex items-center justify-center">
|
||||
<span
|
||||
className={`inline-flex items-center justify-center w-10 h-10 rounded-full font-bold text-sm ${
|
||||
className={`inline-flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 rounded-full font-bold text-xs sm:text-sm ${
|
||||
entry.rank === 1
|
||||
? "bg-gradient-to-br from-pixel-gold to-orange-500 text-black shadow-lg shadow-pixel-gold/50"
|
||||
: entry.rank === 2
|
||||
@@ -104,9 +104,9 @@ export default function LeaderboardSection({
|
||||
</div>
|
||||
|
||||
{/* Player */}
|
||||
<div className="col-span-6 flex items-center gap-3">
|
||||
<div className="col-span-5 sm:col-span-6 flex items-center gap-2 sm:gap-3 min-w-0">
|
||||
{entry.avatar ? (
|
||||
<div className="w-10 h-10 rounded-full border border-pixel-gold/30 overflow-hidden">
|
||||
<div className="w-8 h-8 sm:w-10 sm:h-10 rounded-full border border-pixel-gold/30 overflow-hidden flex-shrink-0">
|
||||
<img
|
||||
src={entry.avatar}
|
||||
alt={entry.username}
|
||||
@@ -114,18 +114,18 @@ export default function LeaderboardSection({
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-gray-800 to-gray-900 border border-pixel-gold/30 flex items-center justify-center">
|
||||
<span className="text-pixel-gold text-xs font-bold">
|
||||
<div className="w-8 h-8 sm:w-10 sm:h-10 rounded-full bg-gradient-to-br from-gray-800 to-gray-900 border border-pixel-gold/30 flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-pixel-gold text-[10px] sm:text-xs font-bold">
|
||||
{entry.username.charAt(0).toUpperCase()}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer hover:opacity-80 transition"
|
||||
className="flex items-center gap-1 sm:gap-2 cursor-pointer hover:opacity-80 transition min-w-0"
|
||||
onClick={() => setSelectedEntry(entry)}
|
||||
>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
className={`font-bold text-xs sm:text-sm truncate ${
|
||||
entry.rank <= 3 ? "text-pixel-gold" : "text-white"
|
||||
}`}
|
||||
>
|
||||
@@ -153,14 +153,14 @@ export default function LeaderboardSection({
|
||||
|
||||
{/* Score */}
|
||||
<div className="col-span-3 flex items-center justify-end">
|
||||
<span className="font-mono text-gray-300">
|
||||
<span className="font-mono text-gray-300 text-xs sm:text-sm">
|
||||
{formatScore(entry.score)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Level */}
|
||||
<div className="col-span-2 flex items-center justify-end">
|
||||
<span className="font-bold text-gray-400">
|
||||
<span className="font-bold text-gray-400 text-xs sm:text-sm">
|
||||
Lv.{entry.level}
|
||||
</span>
|
||||
</div>
|
||||
@@ -190,10 +190,10 @@ export default function LeaderboardSection({
|
||||
className="bg-black border-2 border-pixel-gold/70 rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-8">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-3xl font-bold text-pixel-gold uppercase tracking-wider">
|
||||
<h2 className="text-xl sm:text-3xl font-bold text-pixel-gold uppercase tracking-wider break-words">
|
||||
{selectedEntry.username}
|
||||
</h2>
|
||||
<button
|
||||
@@ -205,9 +205,9 @@ export default function LeaderboardSection({
|
||||
</div>
|
||||
|
||||
{/* Avatar and Class */}
|
||||
<div className="flex items-center gap-6 mb-6">
|
||||
<div className="flex items-center gap-4 sm:gap-6 mb-6">
|
||||
{selectedEntry.avatar ? (
|
||||
<div className="w-24 h-24 rounded-full border-4 border-pixel-gold/50 overflow-hidden">
|
||||
<div className="w-16 h-16 sm:w-24 sm:h-24 rounded-full border-2 sm:border-4 border-pixel-gold/50 overflow-hidden flex-shrink-0">
|
||||
<img
|
||||
src={selectedEntry.avatar}
|
||||
alt={selectedEntry.username}
|
||||
@@ -215,8 +215,8 @@ export default function LeaderboardSection({
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-24 h-24 rounded-full border-4 border-pixel-gold/50 bg-gray-900 flex items-center justify-center">
|
||||
<span className="text-pixel-gold text-4xl font-bold">
|
||||
<div className="w-16 h-16 sm:w-24 sm:h-24 rounded-full border-2 sm:border-4 border-pixel-gold/50 bg-gray-900 flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-pixel-gold text-2xl sm:text-4xl font-bold">
|
||||
{selectedEntry.username.charAt(0).toUpperCase()}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { useSession, signOut } from "next-auth/react";
|
||||
import { useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import PlayerStats from "./PlayerStats";
|
||||
|
||||
interface UserData {
|
||||
@@ -24,29 +26,37 @@ export default function Navigation({
|
||||
initialIsAdmin,
|
||||
}: NavigationProps) {
|
||||
const { data: session } = useSession();
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
// Ne pas afficher le profil sur les pages login/register
|
||||
const isAuthPage = pathname === "/login" || pathname === "/register";
|
||||
|
||||
// Utiliser initialUserData pour déterminer l'état de connexion pendant l'hydratation
|
||||
// Cela évite le clignottement au reload
|
||||
const isAuthenticated = initialUserData !== null || session !== null;
|
||||
// Vérifier explicitement que initialUserData n'est pas undefined
|
||||
const isAuthenticated =
|
||||
(initialUserData !== undefined && initialUserData !== null) ||
|
||||
session !== null;
|
||||
const isAdmin = initialIsAdmin ?? session?.user?.role === "ADMIN";
|
||||
|
||||
return (
|
||||
<nav className="w-full fixed top-0 left-0 z-50 px-8 py-3 bg-black/80 backdrop-blur-sm border-b border-gray-800/30">
|
||||
<nav className="w-full fixed top-0 left-0 z-50 px-4 sm:px-8 py-3 bg-black/80 backdrop-blur-sm border-b border-gray-800/30">
|
||||
<div className="max-w-7xl mx-auto flex items-center justify-between">
|
||||
{/* Logo - Left */}
|
||||
<div className="flex flex-col">
|
||||
<div className="text-white text-xl font-gaming font-bold tracking-tight">
|
||||
<div className="text-white text-lg sm:text-xl font-gaming font-bold tracking-tight">
|
||||
GAME.OF.TECH
|
||||
</div>
|
||||
<div className="text-pixel-gold text-xs font-gaming-subtitle font-semibold flex items-center gap-1 tracking-wide">
|
||||
<div className="text-pixel-gold text-[10px] sm:text-xs font-gaming-subtitle font-semibold flex items-center gap-1 tracking-wide">
|
||||
<span>✦</span>
|
||||
<span>Peaksys</span>
|
||||
<span>✦</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Navigation Links - Center */}
|
||||
<div className="flex items-center gap-6">
|
||||
{/* Navigation Links - Center (Desktop) */}
|
||||
<div className="hidden md:flex items-center gap-6">
|
||||
<Link
|
||||
href="/"
|
||||
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest"
|
||||
@@ -76,17 +86,23 @@ export default function Navigation({
|
||||
</div>
|
||||
|
||||
{/* Right Side */}
|
||||
<div className="flex items-center gap-4">
|
||||
{isAuthenticated ? (
|
||||
<>
|
||||
<div className="flex items-center gap-2 sm:gap-4">
|
||||
{/* PlayerStats - Hidden on mobile */}
|
||||
{isAuthenticated && !isAuthPage && (
|
||||
<div className="hidden lg:block">
|
||||
<PlayerStats initialUserData={initialUserData} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Desktop Auth Buttons */}
|
||||
<div className="hidden md:flex items-center gap-4">
|
||||
{isAuthenticated ? (
|
||||
<button
|
||||
onClick={() => signOut()}
|
||||
className="text-gray-400 hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest"
|
||||
>
|
||||
Déconnexion
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link
|
||||
@@ -104,7 +120,111 @@ export default function Navigation({
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<button
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
className="md:hidden text-white hover:text-pixel-gold transition p-2"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
{isMenuOpen ? (
|
||||
<path d="M6 18L18 6M6 6l12 12" />
|
||||
) : (
|
||||
<path d="M4 6h16M4 12h16M4 18h16" />
|
||||
)}
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
{isMenuOpen && (
|
||||
<div className="md:hidden absolute top-full left-0 w-full bg-black/95 backdrop-blur-sm border-b border-gray-800/30">
|
||||
<div className="px-4 py-4 flex flex-col gap-4">
|
||||
{/* Mobile Navigation Links */}
|
||||
<div className="flex flex-col gap-3">
|
||||
<Link
|
||||
href="/"
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
|
||||
>
|
||||
HOME
|
||||
</Link>
|
||||
<Link
|
||||
href="/events"
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
|
||||
>
|
||||
EVENTS
|
||||
</Link>
|
||||
<Link
|
||||
href="/leaderboard"
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
|
||||
>
|
||||
LEADERBOARD
|
||||
</Link>
|
||||
{isAdmin && (
|
||||
<Link
|
||||
href="/admin"
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
className="text-pixel-gold hover:text-orange-400 transition text-xs font-normal uppercase tracking-widest py-2"
|
||||
>
|
||||
ADMIN
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Mobile PlayerStats */}
|
||||
{isAuthenticated && !isAuthPage && (
|
||||
<div className="lg:hidden pt-2 border-t border-gray-800/30">
|
||||
<PlayerStats initialUserData={initialUserData} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Mobile Auth Buttons */}
|
||||
<div className="flex flex-col gap-3 pt-2 border-t border-gray-800/30">
|
||||
{isAuthenticated ? (
|
||||
<button
|
||||
onClick={() => {
|
||||
signOut();
|
||||
setIsMenuOpen(false);
|
||||
}}
|
||||
className="text-gray-400 hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest text-left py-2"
|
||||
>
|
||||
Déconnexion
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<Link
|
||||
href="/login"
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
|
||||
>
|
||||
Connexion
|
||||
</Link>
|
||||
<Link
|
||||
href="/register"
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
className="px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 hover:border-pixel-gold transition text-center"
|
||||
>
|
||||
Inscription
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ export default function PlayerStats({ initialUserData }: PlayerStatsProps) {
|
||||
</Link>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="flex flex-col gap-1.5 min-w-[200px]">
|
||||
<div className="flex flex-col gap-1.5 min-w-[180px] sm:min-w-[200px]">
|
||||
{/* Username & Level */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
|
||||
@@ -174,12 +174,12 @@ export default function UserManagement() {
|
||||
return (
|
||||
<div
|
||||
key={user.id}
|
||||
className="bg-black/60 border border-pixel-gold/20 rounded p-3"
|
||||
className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4"
|
||||
>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<div className="flex gap-3 items-center flex-1 min-w-0">
|
||||
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-2">
|
||||
<div className="flex gap-2 sm:gap-3 items-center flex-1 min-w-0">
|
||||
{/* Avatar */}
|
||||
<div className="w-10 h-10 rounded-full border-2 border-pixel-gold/50 overflow-hidden bg-black/60 flex-shrink-0">
|
||||
<div className="w-8 h-8 sm:w-10 sm:h-10 rounded-full border-2 border-pixel-gold/50 overflow-hidden bg-black/60 flex-shrink-0">
|
||||
{user.avatar ? (
|
||||
<img
|
||||
src={user.avatar}
|
||||
@@ -194,7 +194,7 @@ export default function UserManagement() {
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
className={`w-full h-full flex items-center justify-center text-pixel-gold text-sm font-bold ${
|
||||
className={`w-full h-full flex items-center justify-center text-pixel-gold text-xs sm:text-sm font-bold ${
|
||||
user.avatar ? "hidden" : ""
|
||||
}`}
|
||||
>
|
||||
@@ -202,18 +202,18 @@ export default function UserManagement() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<h3 className="text-pixel-gold font-bold text-base">
|
||||
<div className="flex items-center gap-1.5 sm:gap-2 flex-wrap">
|
||||
<h3 className="text-pixel-gold font-bold text-sm sm:text-base break-words">
|
||||
{user.username}
|
||||
</h3>
|
||||
<span className="text-xs text-gray-500">
|
||||
<span className="text-[10px] sm:text-xs text-gray-500 whitespace-nowrap">
|
||||
Niveau {user.level}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">
|
||||
<span className="text-[10px] sm:text-xs text-gray-500 whitespace-nowrap">
|
||||
Score: {formatNumber(user.score)}
|
||||
</span>
|
||||
<span
|
||||
className={`text-xs ${
|
||||
className={`text-[10px] sm:text-xs whitespace-nowrap ${
|
||||
user.role === "ADMIN"
|
||||
? "text-pixel-gold"
|
||||
: "text-gray-500"
|
||||
@@ -222,23 +222,23 @@ export default function UserManagement() {
|
||||
{user.role}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-gray-400 text-xs truncate">
|
||||
<p className="text-gray-400 text-[10px] sm:text-xs truncate">
|
||||
{user.email}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{!isEditing && (
|
||||
<div className="flex gap-2 flex-shrink-0 ml-2">
|
||||
<div className="flex gap-2 flex-shrink-0 sm:ml-2">
|
||||
<button
|
||||
onClick={() => handleEdit(user)}
|
||||
className="px-3 py-1.5 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition"
|
||||
className="px-2 sm:px-3 py-1.5 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition whitespace-nowrap"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDelete(user.id)}
|
||||
disabled={deletingUserId === user.id}
|
||||
className="px-3 py-1.5 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-xs tracking-widest rounded hover:bg-red-900/30 transition disabled:opacity-50"
|
||||
className="px-2 sm:px-3 py-1.5 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-red-900/30 transition disabled:opacity-50 whitespace-nowrap"
|
||||
>
|
||||
{deletingUserId === user.id
|
||||
? "Suppression..."
|
||||
@@ -253,14 +253,14 @@ export default function UserManagement() {
|
||||
{/* HP Section */}
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<label className="text-sm text-gray-300">
|
||||
<label className="text-xs sm:text-sm text-gray-300">
|
||||
Points de Vie (HP)
|
||||
</label>
|
||||
<span className="text-xs text-gray-400">
|
||||
<span className="text-[10px] sm:text-xs text-gray-400">
|
||||
{previewHp} / {user.maxHp}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex gap-1 sm:gap-2 flex-wrap">
|
||||
<button
|
||||
onClick={() =>
|
||||
setEditingUser({
|
||||
@@ -268,7 +268,7 @@ export default function UserManagement() {
|
||||
hpDelta: editingUser.hpDelta - 100,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
|
||||
>
|
||||
-100
|
||||
</button>
|
||||
@@ -279,7 +279,7 @@ export default function UserManagement() {
|
||||
hpDelta: editingUser.hpDelta - 10,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
|
||||
>
|
||||
-10
|
||||
</button>
|
||||
@@ -292,7 +292,7 @@ export default function UserManagement() {
|
||||
hpDelta: parseInt(e.target.value) || 0,
|
||||
})
|
||||
}
|
||||
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center"
|
||||
className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
|
||||
/>
|
||||
<button
|
||||
onClick={() =>
|
||||
@@ -301,7 +301,7 @@ export default function UserManagement() {
|
||||
hpDelta: editingUser.hpDelta + 10,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
|
||||
>
|
||||
+10
|
||||
</button>
|
||||
@@ -312,7 +312,7 @@ export default function UserManagement() {
|
||||
hpDelta: editingUser.hpDelta + 100,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
|
||||
>
|
||||
+100
|
||||
</button>
|
||||
@@ -333,14 +333,14 @@ export default function UserManagement() {
|
||||
{/* XP Section */}
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<label className="text-sm text-gray-300">
|
||||
<label className="text-xs sm:text-sm text-gray-300">
|
||||
Expérience (XP)
|
||||
</label>
|
||||
<span className="text-xs text-gray-400">
|
||||
<span className="text-[10px] sm:text-xs text-gray-400">
|
||||
{formatNumber(previewXp)} / {formatNumber(user.maxXp)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex gap-1 sm:gap-2 flex-wrap">
|
||||
<button
|
||||
onClick={() =>
|
||||
setEditingUser({
|
||||
@@ -348,7 +348,7 @@ export default function UserManagement() {
|
||||
xpDelta: editingUser.xpDelta - 1000,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
|
||||
>
|
||||
-1000
|
||||
</button>
|
||||
@@ -359,7 +359,7 @@ export default function UserManagement() {
|
||||
xpDelta: editingUser.xpDelta - 100,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
|
||||
>
|
||||
-100
|
||||
</button>
|
||||
@@ -372,7 +372,7 @@ export default function UserManagement() {
|
||||
xpDelta: parseInt(e.target.value) || 0,
|
||||
})
|
||||
}
|
||||
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center"
|
||||
className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
|
||||
/>
|
||||
<button
|
||||
onClick={() =>
|
||||
@@ -381,7 +381,7 @@ export default function UserManagement() {
|
||||
xpDelta: editingUser.xpDelta + 100,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
|
||||
>
|
||||
+100
|
||||
</button>
|
||||
@@ -392,7 +392,7 @@ export default function UserManagement() {
|
||||
xpDelta: editingUser.xpDelta + 1000,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
|
||||
>
|
||||
+1000
|
||||
</button>
|
||||
@@ -412,10 +412,10 @@ export default function UserManagement() {
|
||||
|
||||
{/* Score Section */}
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-2">
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-2">
|
||||
Score
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex gap-1 sm:gap-2 flex-wrap">
|
||||
<button
|
||||
onClick={() =>
|
||||
setEditingUser({
|
||||
@@ -423,7 +423,7 @@ export default function UserManagement() {
|
||||
score: (editingUser.score || 0) - 1000,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
|
||||
>
|
||||
-1000
|
||||
</button>
|
||||
@@ -434,7 +434,7 @@ export default function UserManagement() {
|
||||
score: (editingUser.score || 0) - 100,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
|
||||
>
|
||||
-100
|
||||
</button>
|
||||
@@ -447,7 +447,7 @@ export default function UserManagement() {
|
||||
score: parseInt(e.target.value) || 0,
|
||||
})
|
||||
}
|
||||
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center"
|
||||
className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
|
||||
/>
|
||||
<button
|
||||
onClick={() =>
|
||||
@@ -456,7 +456,7 @@ export default function UserManagement() {
|
||||
score: (editingUser.score || 0) + 100,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
|
||||
>
|
||||
+100
|
||||
</button>
|
||||
@@ -467,7 +467,7 @@ export default function UserManagement() {
|
||||
score: (editingUser.score || 0) + 1000,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
|
||||
>
|
||||
+1000
|
||||
</button>
|
||||
@@ -476,10 +476,10 @@ export default function UserManagement() {
|
||||
|
||||
{/* Level Section */}
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-2">
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-2">
|
||||
Niveau
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex gap-1 sm:gap-2">
|
||||
<button
|
||||
onClick={() =>
|
||||
setEditingUser({
|
||||
@@ -487,7 +487,7 @@ export default function UserManagement() {
|
||||
level: Math.max(1, (editingUser.level || 1) - 1),
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
|
||||
>
|
||||
-1
|
||||
</button>
|
||||
@@ -501,7 +501,7 @@ export default function UserManagement() {
|
||||
level: Math.max(1, parseInt(e.target.value) || 1),
|
||||
})
|
||||
}
|
||||
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center"
|
||||
className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
|
||||
/>
|
||||
<button
|
||||
onClick={() =>
|
||||
@@ -510,7 +510,7 @@ export default function UserManagement() {
|
||||
level: (editingUser.level || 1) + 1,
|
||||
})
|
||||
}
|
||||
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition"
|
||||
className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
|
||||
>
|
||||
+1
|
||||
</button>
|
||||
@@ -519,7 +519,7 @@ export default function UserManagement() {
|
||||
|
||||
{/* Role Section */}
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-2">
|
||||
<label className="block text-xs sm:text-sm text-gray-300 mb-2">
|
||||
Rôle
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
@@ -530,7 +530,7 @@ export default function UserManagement() {
|
||||
role: "USER",
|
||||
})
|
||||
}
|
||||
className={`flex-1 px-4 py-2 border rounded text-xs uppercase tracking-widest transition ${
|
||||
className={`flex-1 px-3 sm:px-4 py-2 border rounded text-[10px] sm:text-xs uppercase tracking-widest transition ${
|
||||
editingUser.role === "USER"
|
||||
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold"
|
||||
: "border-gray-600/50 bg-gray-900/20 text-gray-400 hover:bg-gray-900/30"
|
||||
@@ -545,7 +545,7 @@ export default function UserManagement() {
|
||||
role: "ADMIN",
|
||||
})
|
||||
}
|
||||
className={`flex-1 px-4 py-2 border rounded text-xs uppercase tracking-widest transition ${
|
||||
className={`flex-1 px-3 sm:px-4 py-2 border rounded text-[10px] sm:text-xs uppercase tracking-widest transition ${
|
||||
editingUser.role === "ADMIN"
|
||||
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold"
|
||||
: "border-gray-600/50 bg-gray-900/20 text-gray-400 hover:bg-gray-900/30"
|
||||
@@ -556,7 +556,7 @@ export default function UserManagement() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 pt-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2 pt-2">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
@@ -573,7 +573,7 @@ export default function UserManagement() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex gap-4 text-xs">
|
||||
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4 text-[10px] sm:text-xs">
|
||||
<div className="flex-1">
|
||||
<div className="flex justify-between items-center mb-0.5">
|
||||
<span className="text-gray-400">HP</span>
|
||||
|
||||
Reference in New Issue
Block a user