edca8f84cd
- Hozzáadva react-toastify a notifyWarning használatához - Javítva a CardEditor fejléc hogy helyesen jelenítse meg az új kártya típusát - Javítva a CardsList 'szerkesztés folyamatban' rész hogy QUESTION/JOKER/LUCK értékeket használjon - Implementálva az automatikus nem megfelelő típusú kártyák törlése új kártya mentésekor - Hozzáadva hibakezelés a kártya mentési logikához - Joker típus címke változtatva 'Szórakozás'-ról 'Joker'-re - Joker kártya szín változtatva citromsárgára (#FFD700) - Docker watch mode volume konfiguráció javítása a hot reload-hoz
221 lines
10 KiB
React
221 lines
10 KiB
React
// src/components/DeckCreator/DeckHeader.jsx
|
||
// Deck alapadatok szerkesztése és mentés
|
||
|
||
import React, { useState, useRef, useEffect } from "react"
|
||
import { FaSave, FaArrowLeft, FaGlobe, FaLock, FaQuestionCircle, FaDice, FaLaughBeam } from "react-icons/fa"
|
||
|
||
const deckTypes = [
|
||
{ value: "QUESTION", label: "Kérdés", icon: FaQuestionCircle, color: "var(--color-question)" },
|
||
{ value: "LUCK", label: "Szerencse", icon: FaDice, color: "var(--color-luck)" },
|
||
{ value: "JOKER", label: "Joker", icon: FaLaughBeam, color: "var(--color-fun)" }
|
||
]
|
||
|
||
const privacyOptions = [
|
||
{ value: "private", label: "Privát", icon: FaLock },
|
||
{ value: "public", label: "Publikus", icon: FaGlobe }
|
||
]
|
||
|
||
export default function DeckHeader({ deck, onUpdate, onSave, onBack }) {
|
||
const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState(false);
|
||
const [isPrivacyDropdownOpen, setIsPrivacyDropdownOpen] = useState(false);
|
||
const typeDropdownRef = useRef(null);
|
||
const privacyDropdownRef = useRef(null);
|
||
|
||
const currentDeckType = deckTypes.find(type => type.value === deck.type) || deckTypes[0]
|
||
const currentPrivacy = privacyOptions.find(option => option.value === deck.privacy) || privacyOptions[0]
|
||
|
||
useEffect(() => {
|
||
function handleClickOutside(event) {
|
||
if (typeDropdownRef.current && !typeDropdownRef.current.contains(event.target)) {
|
||
setIsTypeDropdownOpen(false);
|
||
}
|
||
if (privacyDropdownRef.current && !privacyDropdownRef.current.contains(event.target)) {
|
||
setIsPrivacyDropdownOpen(false);
|
||
}
|
||
}
|
||
|
||
document.addEventListener('mousedown', handleClickOutside);
|
||
return () => {
|
||
document.removeEventListener('mousedown', handleClickOutside);
|
||
};
|
||
}, []);
|
||
|
||
const handleInputChange = (field, value) => {
|
||
onUpdate({ [field]: value })
|
||
}
|
||
|
||
// Remove unused card count variables
|
||
|
||
return (
|
||
<div className="bg-[color:var(--color-surface)] border-b border-[color:var(--color-surface-selected)] px-6 py-4">
|
||
{/* Top Row - Title and Actions */}
|
||
<div className="flex items-center justify-between mb-4">
|
||
<div className="flex items-center gap-4">
|
||
<button
|
||
onClick={onBack}
|
||
className="flex items-center gap-2 px-4 py-2 rounded-xl bg-[color:var(--color-background)] hover:bg-[color:var(--color-surface-selected)] text-[color:var(--color-text)] transition-all duration-200"
|
||
>
|
||
<FaArrowLeft />
|
||
Vissza
|
||
</button>
|
||
|
||
<h1 className="text-2xl font-bold text-[color:var(--color-text)]">
|
||
📝 Pakli Szerkesztés
|
||
</h1>
|
||
</div>
|
||
|
||
<button
|
||
onClick={onSave}
|
||
className="flex items-center gap-2 px-6 py-2 rounded-xl bg-[color:var(--color-success)] hover:bg-[color:var(--color-success)]/80 text-[color:var(--color-text-inverse)] font-semibold transition-all duration-200 hover:scale-105 shadow-lg"
|
||
>
|
||
<FaSave />
|
||
Mentés
|
||
</button>
|
||
</div>
|
||
|
||
{/* Main Content Row */}
|
||
<div className="space-y-4">
|
||
{/* Two Column Layout */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
{/* Deck Name - Takes up 2 columns */}
|
||
<div className="md:col-span-2">
|
||
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||
📦 Pakli neve
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={deck.name}
|
||
onChange={(e) => handleInputChange('name', e.target.value)}
|
||
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200"
|
||
placeholder="Add meg a pakli nevét..."
|
||
/>
|
||
</div>
|
||
|
||
{/* Empty space for visual balance */}
|
||
<div className="hidden md:block"></div>
|
||
</div>
|
||
|
||
{/* Type, Privacy and Description Row */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
{/* Deck Type */}
|
||
<div>
|
||
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||
🎯 Típus
|
||
</label>
|
||
<div className="relative">
|
||
<button
|
||
type="button"
|
||
onClick={() => setIsTypeDropdownOpen(!isTypeDropdownOpen)}
|
||
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200 flex items-center"
|
||
style={{
|
||
paddingLeft: "2.5rem"
|
||
}}
|
||
>
|
||
<div className="absolute left-4 top-1/2 -translate-y-1/2">
|
||
{React.createElement(currentDeckType.icon, {
|
||
style: { color: currentDeckType.color }
|
||
})}
|
||
</div>
|
||
{currentDeckType.label}
|
||
<div className="absolute right-4 top-1/2 -translate-y-1/2">
|
||
<svg className={`w-4 h-4 text-[color:var(--color-text-muted)] transform transition-transform ${isTypeDropdownOpen ? 'rotate-180' : ''}`} viewBox="0 0 20 20" fill="currentColor">
|
||
<path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
|
||
</svg>
|
||
</div>
|
||
</button>
|
||
|
||
{isTypeDropdownOpen && (
|
||
<div
|
||
className="absolute z-10 w-full mt-1 bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] rounded-xl shadow-lg overflow-hidden"
|
||
ref={typeDropdownRef}
|
||
>
|
||
{deckTypes.map(type => (
|
||
<button
|
||
key={type.value}
|
||
onClick={() => {
|
||
handleInputChange('type', type.value);
|
||
setIsTypeDropdownOpen(false);
|
||
}}
|
||
className={`w-full px-4 py-2 flex items-center gap-3 hover:bg-[color:var(--color-surface-selected)] transition-colors text-[color:var(--color-text)] ${deck.type === type.value ? 'bg-[color:var(--color-surface-selected)]' : ''}`}
|
||
>
|
||
{React.createElement(type.icon, {
|
||
style: { color: type.color }
|
||
})}
|
||
<span>{type.label}</span>
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Privacy */}
|
||
<div>
|
||
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||
👁️ Láthatóság
|
||
</label>
|
||
<div className="relative">
|
||
<button
|
||
type="button"
|
||
onClick={() => setIsPrivacyDropdownOpen(!isPrivacyDropdownOpen)}
|
||
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200 flex items-center"
|
||
style={{
|
||
paddingLeft: "2.5rem"
|
||
}}
|
||
>
|
||
<div className="absolute left-4 top-1/2 -translate-y-1/2">
|
||
{React.createElement(currentPrivacy.icon, {
|
||
className: "text-[color:var(--color-text)]"
|
||
})}
|
||
</div>
|
||
{currentPrivacy.label}
|
||
<div className="absolute right-4 top-1/2 -translate-y-1/2">
|
||
<svg className={`w-4 h-4 text-[color:var(--color-text-muted)] transform transition-transform ${isPrivacyDropdownOpen ? 'rotate-180' : ''}`} viewBox="0 0 20 20" fill="currentColor">
|
||
<path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
|
||
</svg>
|
||
</div>
|
||
</button>
|
||
|
||
{isPrivacyDropdownOpen && (
|
||
<div
|
||
className="absolute z-10 w-full mt-1 bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] rounded-xl shadow-lg overflow-hidden"
|
||
ref={privacyDropdownRef}
|
||
>
|
||
{privacyOptions.map(option => (
|
||
<button
|
||
key={option.value}
|
||
onClick={() => {
|
||
handleInputChange('privacy', option.value);
|
||
setIsPrivacyDropdownOpen(false);
|
||
}}
|
||
className={`w-full px-4 py-2 flex items-center gap-3 hover:bg-[color:var(--color-surface-selected)] transition-colors text-[color:var(--color-text)] ${deck.privacy === option.value ? 'bg-[color:var(--color-surface-selected)]' : ''}`}
|
||
>
|
||
{React.createElement(option.icon, {
|
||
className: "text-[color:var(--color-text)]"
|
||
})}
|
||
<span>{option.label}</span>
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Description */}
|
||
<div>
|
||
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||
📝 Leírás
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={deck.description}
|
||
onChange={(e) => handleInputChange('description', e.target.value)}
|
||
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200"
|
||
placeholder="Rövid leírás..."
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
} |