Commit 0c0bcb97 authored by Mahmoud Aglan's avatar Mahmoud Aglan

paswe 0

parent a1d2298a
This diff is collapsed.
......@@ -4,15 +4,15 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="theme-color" content="#0A0A14" />
<meta name="theme-color" content="#071120" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<title>EL3AB - العب</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;900&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=Cairo:wght@600;700;900&display=swap" rel="stylesheet" />
</head>
<body class="bg-background text-text-primary font-cairo antialiased overflow-x-hidden">
<body class="bg-background text-text-primary antialiased overflow-x-hidden">
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
......
import { motion, AnimatePresence } from 'framer-motion'
import { Gift, Coins, Flame, Sparkles } from 'lucide-react'
import { Gift, Coins, Flame } from 'lucide-react'
import { Button } from './ui/Button'
interface DailyRewardModalProps {
......@@ -20,60 +20,45 @@ export function DailyRewardModal({ open, streak, reward, loading, onClaim, onClo
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
onClick={onClose}
>
<motion.div
className="w-full max-w-[340px] rounded-3xl bg-surface-1 border-3 border-border p-7 flex flex-col items-center gap-5 relative overflow-hidden"
initial={{ scale: 0.8, opacity: 0 }}
className="w-full max-w-[340px] rounded-[var(--radius-hero)] bg-surface-1 border border-border p-6 flex flex-col items-center gap-5"
style={{ boxShadow: 'var(--shadow-3)' }}
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.8, opacity: 0 }}
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
exit={{ scale: 0.9, opacity: 0 }}
transition={{ duration: 0.2 }}
onClick={(e) => e.stopPropagation()}
>
<div className="absolute top-0 left-0 w-full h-32 bg-gradient-to-b from-gold/8 to-transparent" />
<motion.div
className="w-20 h-20 rounded-full bg-gradient-to-br from-gold/20 to-gold/5 border-3 border-gold/50 flex items-center justify-center relative"
animate={{ rotate: [0, 5, -5, 0] }}
transition={{ duration: 3, repeat: Infinity }}
>
<Gift size={36} className="text-gold" />
<motion.div
className="absolute -top-1 -right-1"
animate={{ scale: [1, 1.3, 1], opacity: [1, 0.6, 1] }}
transition={{ duration: 1.5, repeat: Infinity }}
>
<Sparkles size={16} className="text-gold" />
</motion.div>
</motion.div>
<div className="w-16 h-16 rounded-[var(--radius-large)] bg-gold/10 border border-gold/30 flex items-center justify-center">
<Gift size={32} className="text-gold" />
</div>
<div className="text-center z-10">
<h3 className="text-xl font-black text-text-primary">المكافأة اليومية</h3>
<div className="text-center">
<h3 className="text-xl font-bold text-text-primary">المكافأة اليومية</h3>
<p className="text-sm text-text-muted mt-1">ادخل كل يوم واحصل على مكافآت اكثر</p>
</div>
<div className="flex items-center gap-3 bg-surface-2 rounded-2xl px-5 py-3 border border-border">
<Flame size={20} className="text-coral" />
<span className="text-sm font-bold text-text-secondary">سلسلة:</span>
<span className="text-lg font-black text-coral">{streak}</span>
<div className="flex items-center gap-3 bg-surface-2 rounded-[var(--radius-standard)] px-4 py-3 border border-border">
<Flame size={18} className="text-coral" />
<span className="text-sm font-medium text-text-secondary">سلسلة:</span>
<span className="text-lg font-bold text-coral">{streak}</span>
<span className="text-sm text-text-muted">يوم</span>
</div>
<motion.div
className="flex items-center gap-3 bg-gold/10 rounded-2xl px-6 py-4 border border-gold/30"
animate={{ scale: [1, 1.02, 1] }}
transition={{ duration: 2, repeat: Infinity }}
>
<Coins size={28} className="text-gold" />
<span className="text-3xl font-black text-gold">+{reward}</span>
</motion.div>
<div className="flex items-center gap-3 bg-gold/10 rounded-[var(--radius-standard)] px-5 py-4 border border-gold/20">
<Coins size={24} className="text-gold" />
<span className="text-2xl font-bold text-gold">+{reward}</span>
</div>
<Button
variant="gold"
size="lg"
onClick={onClaim}
loading={loading}
className="w-[80%] mx-auto"
className="w-full"
>
استلم المكافأة
</Button>
......
......@@ -10,121 +10,46 @@ const NAV_ITEMS = [
{ path: '/profile', icon: User, label: 'حسابي' },
]
const CENTER_INDEX = 2
export function BottomNav() {
const location = useLocation()
const navigate = useNavigate()
return (
<nav className="fixed bottom-0 left-0 right-0 z-50 px-4 pb-3 pt-1">
<div className="app-container !p-0">
{/* Decorative corner accents */}
<div className="relative">
{/* Left L-accent */}
<div className="absolute -top-1 left-1 w-3 h-3 border-t-2 border-l-2 border-gold/40 rounded-tl-sm pointer-events-none" />
{/* Right L-accent */}
<div className="absolute -top-1 right-1 w-3 h-3 border-t-2 border-r-2 border-gold/40 rounded-tr-sm pointer-events-none" />
{/* Main bar */}
<div className="game-panel border-4 border-border bg-surface-2 shadow-[0_8px_32px_rgba(0,0,0,0.6),0_2px_8px_rgba(0,0,0,0.4)]">
<div className="flex items-center justify-around px-2 py-2 relative">
{NAV_ITEMS.map((item, index) => {
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-surface-1 border-t border-border">
<div className="flex items-center justify-around px-4 py-2 max-w-[480px] mx-auto">
{NAV_ITEMS.map((item) => {
const isActive = location.pathname === item.path
const isCenter = index === CENTER_INDEX
const Icon = item.icon
return (
<motion.button
key={item.path}
onClick={() => navigate(item.path)}
className="relative flex flex-col items-center gap-0.5 px-2 py-1"
whileTap={{ scale: 0.8 }}
>
{/* Slot background */}
<div
className={`relative flex items-center justify-center rounded-xl transition-colors duration-200 ${
isCenter ? 'w-12 h-12' : 'w-10 h-10'
} ${
isActive
? 'bg-gold/15'
: 'bg-surface-3/60'
} ${
isCenter ? 'border-2 border-gold/20' : 'border border-border/50'
}`}
className="relative flex flex-col items-center gap-1 py-1 min-w-[44px] min-h-[44px] justify-center"
whileTap={{ scale: 0.9 }}
transition={{ duration: 0.15 }}
>
{/* Hex outline for center item */}
{isCenter && (
<div
className="absolute inset-0 border border-gold/15"
style={{
clipPath: 'polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)',
}}
/>
)}
<motion.div
animate={
isActive
? { y: -14, scale: 1.15 }
: { y: 0, scale: 1 }
}
transition={{ type: 'spring', stiffness: 400, damping: 22 }}
>
{/* Glowing badge behind active icon */}
{isActive && (
<motion.div
className="absolute inset-0 -m-2 rounded-full bg-gold/20 blur-sm"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.2 }}
/>
)}
<Icon
size={isCenter ? 24 : 20}
className={
isActive
? 'text-gold drop-shadow-[0_0_6px_rgba(255,200,60,0.6)]'
: 'text-text-muted'
}
strokeWidth={isActive ? 2.8 : 2}
size={22}
className={isActive ? 'text-gold' : 'text-text-muted'}
strokeWidth={isActive ? 2.5 : 2}
/>
</motion.div>
</div>
{/* Label: shows when active */}
<motion.span
className="text-[9px] font-bold text-gold"
initial={false}
animate={{
opacity: isActive ? 1 : 0,
y: isActive ? 0 : 4,
}}
transition={{ duration: 0.2 }}
<span
className={`text-[11px] font-semibold ${isActive ? 'text-gold' : 'text-text-muted'}`}
>
{item.label}
</motion.span>
{/* Active glow indicator */}
</span>
{isActive && (
<motion.div
className="absolute -bottom-1 w-5 h-[3px] rounded-full bg-gold"
className="absolute -bottom-2 w-6 h-[3px] rounded-full bg-gold"
layoutId="nav-indicator"
style={{ boxShadow: '0 0 8px rgba(255, 200, 60, 0.7)' }}
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
transition={{ duration: 0.2 }}
/>
)}
</motion.button>
)
})}
</div>
</div>
{/* Bottom L-accents */}
<div className="absolute -bottom-1 left-1 w-3 h-3 border-b-2 border-l-2 border-gold/40 rounded-bl-sm pointer-events-none" />
<div className="absolute -bottom-1 right-1 w-3 h-3 border-b-2 border-r-2 border-gold/40 rounded-br-sm pointer-events-none" />
</div>
</div>
</nav>
)
}
import { motion } from 'framer-motion'
const particles = [
{ x: '12%', delay: 0, duration: 4.5 },
{ x: '28%', delay: 1.2, duration: 5.2 },
{ x: '45%', delay: 0.5, duration: 3.8 },
{ x: '62%', delay: 2.1, duration: 4.8 },
{ x: '78%', delay: 0.8, duration: 5.5 },
{ x: '88%', delay: 1.6, duration: 4.2 },
{ x: '35%', delay: 2.8, duration: 5.0 },
]
function generateRayLines() {
const lines = []
for (let i = 0; i < 12; i++) {
const angle = (i * 30 * Math.PI) / 180
const x2 = 50 + 45 * Math.cos(angle)
const y2 = 50 + 45 * Math.sin(angle)
lines.push(
<line
key={i}
x1="50"
y1="50"
x2={x2}
y2={y2}
stroke="rgba(255, 200, 60, 0.04)"
strokeWidth="0.5"
/>
)
}
return lines
}
export function DecorativeBackground() {
return (
<div className="fixed inset-0 pointer-events-none z-0 overflow-hidden">
{/* Arena gradient base */}
<div className="absolute inset-0 bg-arena" />
{/* Rotating ray pattern */}
<motion.div
className="absolute inset-0 flex items-center justify-center"
animate={{ rotate: 360 }}
transition={{
duration: 90,
repeat: Infinity,
ease: 'linear',
}}
>
<svg
viewBox="0 0 100 100"
className="w-[140vmax] h-[140vmax] opacity-60"
xmlns="http://www.w3.org/2000/svg"
>
{generateRayLines()}
</svg>
</motion.div>
{/* Floating gold particles */}
{particles.map((particle, i) => (
<motion.div
key={i}
className="absolute w-1 h-1 rounded-full bg-gold/30"
<div className="fixed inset-0 pointer-events-none z-0">
<div
className="absolute inset-0"
style={{
left: particle.x,
top: '80%',
}}
animate={{
y: [0, -window.innerHeight * 0.7, -window.innerHeight],
opacity: [0, 0.8, 0],
}}
transition={{
duration: particle.duration,
repeat: Infinity,
delay: particle.delay,
ease: 'linear',
background: 'radial-gradient(ellipse at 50% 0%, rgba(23, 37, 60, 0.5) 0%, transparent 60%)',
}}
/>
))}
</div>
)
}
......@@ -2,7 +2,6 @@ import { motion } from 'framer-motion'
import { Bell, Coins, Gem } from 'lucide-react'
import { useNotificationStore } from '../../stores/notificationStore'
import { useAuthStore } from '../../stores/authStore'
import { GoldCrown } from '../icons/GoldCrown'
import { useNavigate } from 'react-router-dom'
export function Header() {
......@@ -11,102 +10,57 @@ export function Header() {
const navigate = useNavigate()
return (
<header className="sticky top-0 z-50 px-4 pt-3 pb-2">
<div className="app-container !p-0">
{/* HUD Bar with diagonal bottom edge */}
<div
className="game-panel relative border-4 border-border bg-surface-2"
style={{
clipPath: 'polygon(0 0, 100% 0, 100% 85%, 98% 100%, 2% 100%, 0% 85%)',
}}
>
<div className="flex items-center justify-between px-4 py-2.5">
{/* Logo section (right side in RTL) */}
<div className="flex items-center gap-2.5">
{/* Shield-shaped container */}
<div
className="relative flex items-center justify-center w-11 h-11 bg-surface-3 border-2 border-gold/40"
style={{
clipPath: 'polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)',
}}
>
<GoldCrown size={22} animate={false} />
</div>
<span
className="text-lg font-black text-gold tracking-widest"
style={{
textShadow: '0 2px 4px rgba(0,0,0,0.5), 0 0 12px rgba(255,200,60,0.3)',
}}
>
<header className="sticky top-0 z-50 bg-surface-1/95 backdrop-blur-sm border-b border-border">
<div className="app-container flex items-center justify-between h-14">
{/* Logo */}
<div className="flex items-center gap-2">
<span className="text-lg font-bold text-gold tracking-wide">
EL3AB
</span>
</div>
{/* Center: Level indicator */}
{profile && (
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
<div className="w-8 h-8 rounded-full bg-surface-3 border-2 border-gold/50 flex items-center justify-center shadow-[0_0_8px_rgba(255,200,60,0.2)]">
<span className="text-[11px] font-black text-gold">
<div className="flex items-center justify-center w-7 h-7 rounded-full bg-surface-2 border border-border">
<span className="text-[11px] font-bold text-gold">
{profile.level || 1}
</span>
</div>
</div>
)}
</div>
{/* Resources section (left side in RTL) */}
<div className="flex items-center gap-2">
{/* Resources + Bell */}
<div className="flex items-center gap-3">
{profile && (
<>
{/* Coins capsule */}
<motion.div
className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-gold/10 border-2 border-gold/40 shadow-[inset_0_0_8px_rgba(255,200,60,0.15)]"
whileTap={{ scale: 0.9 }}
>
<div className="flex items-center gap-1.5 px-3 py-1.5 rounded-[var(--radius-tiny)] bg-surface-2 border border-border">
<Coins size={14} className="text-gold" />
<span className="text-xs font-black text-gold">{profile.coins}</span>
</motion.div>
<span className="text-xs font-semibold text-text-primary">{profile.coins}</span>
</div>
{/* Gems capsule */}
{profile.gems > 0 && (
<motion.div
className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-purple/10 border-2 border-purple/40 shadow-[inset_0_0_8px_rgba(180,77,255,0.15)]"
whileTap={{ scale: 0.9 }}
>
<div className="flex items-center gap-1.5 px-3 py-1.5 rounded-[var(--radius-tiny)] bg-surface-2 border border-border">
<Gem size={12} className="text-purple" />
<span className="text-xs font-black text-purple">{profile.gems}</span>
</motion.div>
<span className="text-xs font-semibold text-text-primary">{profile.gems}</span>
</div>
)}
</>
)}
{/* Bell: hexagonal button */}
<motion.button
className="relative flex items-center justify-center w-10 h-10 bg-surface-3 border-2 border-border"
style={{
clipPath: 'polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)',
}}
className="relative flex items-center justify-center w-10 h-10 rounded-[var(--radius-tiny)] bg-surface-2 border border-border"
onClick={() => navigate('/notifications')}
whileTap={{ scale: 0.85 }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.9 }}
transition={{ duration: 0.15 }}
>
<Bell size={16} className="text-text-secondary" />
<Bell size={18} className="text-text-secondary" />
{unreadCount > 0 && (
<motion.div
className="absolute -top-1 -right-1 w-5 h-5 rounded-full bg-coral border-2 border-surface-2 flex items-center justify-center animate-pulse-glow"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: 'spring', stiffness: 500, damping: 15 }}
>
<span className="text-[9px] font-black text-white">
<div className="absolute -top-1 -right-1 w-5 h-5 rounded-full bg-coral flex items-center justify-center">
<span className="text-[10px] font-bold text-white">
{unreadCount > 9 ? '9+' : unreadCount}
</span>
</motion.div>
</div>
)}
</motion.button>
</div>
</div>
</div>
</div>
</header>
)
}
......@@ -9,11 +9,11 @@ interface PageTransitionProps {
export function PageTransition({ children, className = '' }: PageTransitionProps) {
return (
<motion.div
className={`app-container py-8 flex flex-col gap-7 ${className}`}
initial={{ opacity: 0, y: 24, scale: 0.97 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -16, scale: 0.98 }}
transition={{ type: 'spring', stiffness: 300, damping: 28 }}
className={`app-container py-6 pb-24 ${className}`}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
>
{children}
</motion.div>
......
......@@ -5,7 +5,7 @@ import { Loader2 } from 'lucide-react'
interface ButtonProps {
children: ReactNode
onClick?: () => void
variant?: 'gold' | 'ghost' | 'coral' | 'cyan' | 'purple'
variant?: 'gold' | 'ghost' | 'blue' | 'cyan' | 'danger'
size?: 'sm' | 'md' | 'lg'
disabled?: boolean
loading?: boolean
......@@ -13,18 +13,18 @@ interface ButtonProps {
type?: 'button' | 'submit'
}
const variants = {
gold: 'bg-gradient-to-b from-gold-light to-gold text-background font-black shadow-lg shadow-gold/30 border-b-4 border-gold-muted',
ghost: 'bg-surface-2 border-2 border-border text-text-primary font-bold hover:border-gold/50 hover:bg-surface-3',
coral: 'bg-gradient-to-b from-[#FF7070] to-coral text-white font-black shadow-lg shadow-coral/25 border-b-4 border-[#B83A3A]',
cyan: 'bg-gradient-to-b from-[#33FFE5] to-cyan text-background font-black shadow-lg shadow-cyan/25 border-b-4 border-[#009E8E]',
purple: 'bg-gradient-to-b from-[#CC70FF] to-purple text-white font-black shadow-lg shadow-purple/25 border-b-4 border-[#6B3D8F]',
const variantStyles = {
gold: 'btn-gold',
blue: 'btn-blue',
cyan: 'btn-cyan',
ghost: 'btn-ghost',
danger: 'btn-danger',
}
const sizes = {
sm: 'px-5 py-2 text-sm rounded-xl gap-2 min-w-[90px]',
md: 'px-7 py-3 text-base rounded-2xl gap-2.5 min-w-[120px]',
lg: 'px-10 py-4 text-lg rounded-2xl gap-3 min-w-[160px]',
const sizeStyles = {
sm: 'px-4 py-2 text-sm min-h-[36px]',
md: 'px-6 py-3 text-base min-h-[44px]',
lg: 'px-8 py-4 text-lg min-h-[52px]',
}
export function Button({
......@@ -42,10 +42,9 @@ export function Button({
type={type}
onClick={onClick}
disabled={disabled || loading}
className={`inline-flex items-center justify-center transition-all uppercase tracking-wide ${variants[variant]} ${sizes[size]} ${disabled ? 'opacity-50 cursor-not-allowed saturate-50' : ''} ${className}`}
whileTap={!disabled ? { scale: 0.92, y: 2 } : undefined}
whileHover={!disabled ? { scale: 1.03 } : undefined}
transition={{ type: 'spring', stiffness: 600, damping: 20 }}
className={`btn ${variantStyles[variant]} ${sizeStyles[size]} ${disabled ? 'opacity-50 cursor-not-allowed' : ''} ${className}`}
whileTap={!disabled ? { scale: 0.96, y: 2 } : undefined}
transition={{ duration: 0.15 }}
>
{loading && <Loader2 size={18} className="animate-spin" />}
{children}
......
......@@ -4,27 +4,20 @@ import type { ReactNode } from 'react'
interface CardProps {
children: ReactNode
className?: string
glow?: boolean
onClick?: () => void
variant?: 'default' | 'gold' | 'elevated'
variant?: 'default' | 'elevated'
}
export function Card({ children, className = '', glow = false, onClick, variant = 'default' }: CardProps) {
const base = 'rounded-2xl p-5 border-3 transition-all'
const variantStyles = {
default: `bg-surface-1 border-border ${glow ? 'border-gold shadow-[0_0_20px_rgba(255,200,60,0.2)]' : ''}`,
gold: 'bg-gradient-to-br from-surface-2 to-surface-1 border-gold/60 shadow-[0_0_16px_rgba(255,200,60,0.15)]',
elevated: 'bg-surface-2 border-border shadow-xl shadow-black/40',
}
export function Card({ children, className = '', onClick, variant = 'default' }: CardProps) {
const base = variant === 'elevated' ? 'card card-elevated' : 'card'
return (
<motion.div
className={`${base} ${variantStyles[variant]} ${onClick ? 'cursor-pointer' : ''} ${className}`}
whileHover={onClick ? { y: -4, scale: 1.01, boxShadow: '0 12px 32px rgba(0,0,0,0.5)' } : undefined}
whileTap={onClick ? { scale: 0.97 } : undefined}
className={`${base} ${onClick ? 'cursor-pointer' : ''} ${className}`}
whileHover={onClick ? { y: -2 } : undefined}
whileTap={onClick ? { scale: 0.98 } : undefined}
onClick={onClick}
transition={{ type: 'spring', stiffness: 400, damping: 22 }}
transition={{ duration: 0.15 }}
>
{children}
</motion.div>
......
......@@ -4,8 +4,7 @@ import type { ReactNode } from 'react'
interface GamePanelProps {
children: ReactNode
className?: string
variant?: 'default' | 'gold' | 'legendary' | 'recessed'
rivets?: boolean
variant?: 'default' | 'elevated'
onClick?: () => void
}
......@@ -13,52 +12,21 @@ export function GamePanel({
children,
className = '',
variant = 'default',
rivets = false,
onClick,
}: GamePanelProps) {
const baseClass = variant === 'recessed' ? 'game-panel-recessed' : 'game-panel'
const goldClass = variant === 'gold' || variant === 'legendary' ? 'game-panel-gold' : ''
const styles = variant === 'elevated'
? 'bg-surface-2 border border-border-strong shadow-[var(--shadow-2)]'
: 'bg-surface-1 border border-border shadow-[var(--shadow-1)]'
return (
<motion.div
className={`${baseClass} ${goldClass} p-5 relative overflow-hidden ${onClick ? 'cursor-pointer' : ''} ${className}`}
whileHover={onClick ? { y: -4, scale: 1.01 } : undefined}
whileTap={onClick ? { scale: 0.97 } : undefined}
className={`rounded-[var(--radius-large)] p-4 md:p-6 relative ${styles} ${onClick ? 'cursor-pointer' : ''} ${className}`}
whileHover={onClick ? { y: -2 } : undefined}
whileTap={onClick ? { scale: 0.98 } : undefined}
onClick={onClick}
transition={{ type: 'spring', stiffness: 400, damping: 22 }}
transition={{ duration: 0.15 }}
>
{/* Legendary shimmer overlay */}
{variant === 'legendary' && (
<motion.div
className="absolute inset-0 pointer-events-none"
style={{
background:
'linear-gradient(105deg, transparent 40%, rgba(255, 200, 60, 0.12) 45%, rgba(255, 200, 60, 0.2) 50%, rgba(255, 200, 60, 0.12) 55%, transparent 60%)',
}}
animate={{
x: ['-100%', '200%'],
}}
transition={{
duration: 3,
repeat: Infinity,
ease: 'easeInOut',
repeatDelay: 1.5,
}}
/>
)}
{/* Rivets at 4 corners */}
{rivets && (
<>
<span className="absolute top-3 left-3 w-[6px] h-[6px] rounded-full bg-surface-3 shadow-[inset_0_1px_2px_rgba(0,0,0,0.6),0_1px_0_rgba(255,255,255,0.05)]" />
<span className="absolute top-3 right-3 w-[6px] h-[6px] rounded-full bg-surface-3 shadow-[inset_0_1px_2px_rgba(0,0,0,0.6),0_1px_0_rgba(255,255,255,0.05)]" />
<span className="absolute bottom-3 left-3 w-[6px] h-[6px] rounded-full bg-surface-3 shadow-[inset_0_1px_2px_rgba(0,0,0,0.6),0_1px_0_rgba(255,255,255,0.05)]" />
<span className="absolute bottom-3 right-3 w-[6px] h-[6px] rounded-full bg-surface-3 shadow-[inset_0_1px_2px_rgba(0,0,0,0.6),0_1px_0_rgba(255,255,255,0.05)]" />
</>
)}
{/* Content */}
<div className="relative z-10">{children}</div>
{children}
</motion.div>
)
}
interface GameProgressBarProps {
value: number
max: number
color?: 'gold' | 'cyan' | 'green' | 'purple'
color?: 'gold' | 'cyan' | 'green' | 'blue'
showLabel?: boolean
}
const fillColorClass: Record<string, string> = {
gold: 'progress-game-fill',
cyan: 'progress-game-fill progress-game-fill-cyan',
green: 'progress-game-fill progress-game-fill-green',
purple: 'progress-game-fill progress-game-fill-purple',
const fillColors: Record<string, string> = {
gold: 'bg-gold',
cyan: 'bg-cyan',
green: 'bg-green',
blue: 'bg-royal-blue',
}
export function GameProgressBar({
......@@ -22,25 +22,15 @@ export function GameProgressBar({
return (
<div className="w-full">
<div className="progress-game relative">
{/* Fill bar */}
<div className="h-3 rounded-[var(--radius-tiny)] bg-surface-3 overflow-hidden">
<div
className={`${fillColorClass[color]} relative`}
className={`h-full rounded-[var(--radius-tiny)] ${fillColors[color]} transition-all duration-300`}
style={{ width: `${percentage}%` }}
>
{/* Segmented overlay */}
<div
className="absolute inset-0 opacity-20"
style={{
background:
'repeating-linear-gradient(90deg, transparent 0px, transparent 8px, rgba(0,0,0,0.3) 8px, rgba(0,0,0,0.3) 10px)',
}}
/>
</div>
</div>
{showLabel && (
<div className="flex justify-between mt-1">
<span className="text-xs text-text-muted font-bold">{value}</span>
<span className="text-xs text-text-muted font-medium">{value}</span>
<span className="text-xs text-text-muted">{max}</span>
</div>
)}
......
......@@ -3,66 +3,14 @@ import type { ComponentType } from 'react'
interface RibbonHeaderProps {
text: string
icon?: ComponentType<{ size?: number; className?: string }>
color?: 'gold' | 'cyan' | 'purple' | 'coral'
size?: 'sm' | 'md'
className?: string
}
const colorStyles = {
gold: {
gradient: 'linear-gradient(135deg, #FFC83D 0%, #C9972E 100%)',
border: 'rgba(255, 200, 60, 0.6)',
text: '#1a1a2e',
},
cyan: {
gradient: 'linear-gradient(135deg, #00E5CC 0%, #009E8C 100%)',
border: 'rgba(0, 229, 204, 0.6)',
text: '#0a1a1a',
},
purple: {
gradient: 'linear-gradient(135deg, #B44DFF 0%, #7B2EBF 100%)',
border: 'rgba(180, 77, 255, 0.6)',
text: '#ffffff',
},
coral: {
gradient: 'linear-gradient(135deg, #FF5252 0%, #BF2E2E 100%)',
border: 'rgba(255, 82, 82, 0.6)',
text: '#ffffff',
},
}
const sizeStyles = {
sm: {
padding: '6px 24px',
fontSize: '0.8rem',
iconSize: 14,
},
md: {
padding: '10px 36px',
fontSize: '0.95rem',
iconSize: 18,
},
}
export function RibbonHeader({ text, icon: Icon, color = 'gold', size = 'md' }: RibbonHeaderProps) {
const colors = colorStyles[color]
const sizes = sizeStyles[size]
export function RibbonHeader({ text, icon: Icon, className = '' }: RibbonHeaderProps) {
return (
<div className="flex justify-center w-full">
<div
className="ribbon-banner inline-flex items-center gap-2 font-bold"
style={{
background: colors.gradient,
color: colors.text,
padding: sizes.padding,
fontSize: sizes.fontSize,
borderBottom: `3px solid ${colors.border}`,
boxShadow: `0 4px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2)`,
}}
>
{Icon && <Icon size={sizes.iconSize} className="flex-shrink-0" />}
<span>{text}</span>
</div>
<div className={`flex items-center gap-2 mb-4 ${className}`}>
{Icon && <Icon size={20} className="text-gold" />}
<h2 className="text-lg font-bold text-text-primary">{text}</h2>
</div>
)
}
......@@ -2,9 +2,8 @@ import type { ReactNode } from 'react'
interface ShieldBadgeProps {
children: ReactNode
size?: 'sm' | 'md' | 'lg' | 'xl'
color?: 'gold' | 'cyan' | 'purple' | 'coral' | 'default'
glow?: boolean
size?: 'sm' | 'md' | 'lg'
color?: 'gold' | 'cyan' | 'blue' | 'default'
className?: string
}
......@@ -12,72 +11,26 @@ const sizeMap = {
sm: 'w-10 h-10',
md: 'w-14 h-14',
lg: 'w-20 h-20',
xl: 'w-28 h-28',
}
const colorMap = {
default: {
bg: 'bg-surface-2',
ring: 'rgba(61, 69, 112, 0.8)',
glow: 'none',
},
gold: {
bg: 'bg-gradient-to-br from-[#FFC83D] to-[#C9972E]',
ring: 'rgba(255, 200, 60, 0.8)',
glow: '0 0 20px rgba(255, 200, 60, 0.4)',
},
cyan: {
bg: 'bg-gradient-to-br from-[#00E5CC] to-[#009E8C]',
ring: 'rgba(0, 229, 204, 0.8)',
glow: '0 0 20px rgba(0, 229, 204, 0.4)',
},
purple: {
bg: 'bg-gradient-to-br from-[#B44DFF] to-[#7B2EBF]',
ring: 'rgba(180, 77, 255, 0.8)',
glow: '0 0 20px rgba(180, 77, 255, 0.4)',
},
coral: {
bg: 'bg-gradient-to-br from-[#FF5252] to-[#BF2E2E]',
ring: 'rgba(255, 82, 82, 0.8)',
glow: '0 0 20px rgba(255, 82, 82, 0.4)',
},
default: 'bg-surface-2 border-border',
gold: 'bg-surface-2 border-gold/40',
cyan: 'bg-surface-2 border-cyan/40',
blue: 'bg-surface-2 border-royal-blue/40',
}
export function ShieldBadge({
children,
size = 'md',
color = 'default',
glow = false,
className = '',
}: ShieldBadgeProps) {
const sizeClass = sizeMap[size]
const colorConfig = colorMap[color]
return (
<div
className={`relative inline-flex items-center justify-center ${sizeClass} ${className}`}
style={{
boxShadow: glow ? colorConfig.glow : 'none',
}}
className={`inline-flex items-center justify-center rounded-[var(--radius-standard)] border-2 ${sizeMap[size]} ${colorMap[color]} ${className}`}
>
{/* Outer ring */}
<div
className="absolute inset-0 clip-shield"
style={{
background: colorConfig.ring,
}}
/>
{/* Inner shield body */}
<div
className={`absolute clip-shield ${colorConfig.bg} flex items-center justify-center`}
style={{
inset: '3px',
}}
/>
{/* Content */}
<div className="relative z-10 flex items-center justify-center text-white font-bold">
{children}
</div>
</div>
)
}
This diff is collapsed.
......@@ -86,7 +86,7 @@ export function BotSelectPage() {
>
<motion.div
onClick={() => setSelectedBot(bot.id)}
className={`game-panel !p-4 flex items-center gap-4 relative overflow-hidden cursor-pointer transition-all ${
className={`card !p-4 flex items-center gap-4 relative overflow-hidden cursor-pointer transition-all ${
isSelected ? '!border-[#FFC83D]' : ''
}`}
style={{
......@@ -192,7 +192,7 @@ export function BotSelectPage() {
<motion.button
onClick={startGame}
whileTap={{ scale: 0.95 }}
className="btn-3d w-[80%] py-4 rounded-2xl bg-gradient-to-b from-[#FFC83D] to-[#E5A800] text-background text-lg font-black flex items-center justify-center gap-2"
className="w-[80%] py-4 rounded-2xl bg-gradient-to-b from-[#FFC83D] to-[#E5A800] text-background text-lg font-black flex items-center justify-center gap-2"
style={{ boxShadow: '0 6px 0 #B8860B, 0 8px 20px rgba(255,200,61,0.3)' }}
>
<Swords size={20} />
......
......@@ -128,7 +128,7 @@ export function FriendsPage() {
const alreadySent = sentIds.has(result.id)
return (
<motion.div key={result.id} variants={item}>
<div className="game-panel !p-3.5 flex items-center gap-3">
<div className="card !p-3.5 flex items-center gap-3">
<div className="w-10 h-10 flex items-center justify-center shrink-0"
style={{ clipPath: 'polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)' }}
>
......@@ -152,7 +152,7 @@ export function FriendsPage() {
<motion.button
whileTap={{ scale: 0.9 }}
onClick={() => handleSendRequest(result.id)}
className="btn-3d px-4 py-2 rounded-xl bg-[#FFC83D] text-background text-xs font-black"
className="px-4 py-2 rounded-xl bg-[#FFC83D] text-background text-xs font-black"
>
اضافة
</motion.button>
......@@ -180,7 +180,7 @@ export function FriendsPage() {
</h2>
<div className="flex flex-col gap-2.5">
{pendingReceived.map((req) => (
<div key={req.id} className="game-panel-gold !p-3.5 flex items-center gap-3">
<div key={req.id} className="card !p-3.5 flex items-center gap-3">
<div className="w-11 h-11 flex items-center justify-center shrink-0"
style={{ clipPath: 'polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)' }}
>
......@@ -202,14 +202,14 @@ export function FriendsPage() {
<motion.button
whileTap={{ scale: 0.85 }}
onClick={() => acceptRequest(req.id)}
className="btn-3d px-3.5 py-2 rounded-xl bg-[#00E5CC] text-background text-xs font-black"
className="px-3.5 py-2 rounded-xl bg-[#00E5CC] text-background text-xs font-black"
>
قبول
</motion.button>
<motion.button
whileTap={{ scale: 0.85 }}
onClick={() => rejectRequest(req.id)}
className="btn-3d px-3.5 py-2 rounded-xl bg-[#FF5252] text-white text-xs font-black"
className="px-3.5 py-2 rounded-xl bg-[#FF5252] text-white text-xs font-black"
>
رفض
</motion.button>
......@@ -229,7 +229,7 @@ export function FriendsPage() {
</h2>
<div className="flex flex-col gap-2.5">
{onlineFriends.map((friend) => (
<div key={friend.id} className="game-panel !p-3 flex items-center gap-3 relative overflow-hidden">
<div key={friend.id} className="card !p-3 flex items-center gap-3 relative overflow-hidden">
{/* Green accent stripe */}
<div className="absolute right-0 top-0 bottom-0 w-[4px] bg-[#4ADE80] rounded-r-full" />
......@@ -283,7 +283,7 @@ export function FriendsPage() {
</h2>
<div className="flex flex-col gap-2.5">
{offlineFriends.map((friend) => (
<div key={friend.id} className="game-panel !p-3 flex items-center gap-3 opacity-60 relative overflow-hidden">
<div key={friend.id} className="card !p-3 flex items-center gap-3 opacity-60 relative overflow-hidden">
{/* Gray accent stripe */}
<div className="absolute right-0 top-0 bottom-0 w-[4px] bg-text-muted/30 rounded-r-full" />
......
......@@ -423,7 +423,7 @@ function MultiplayerGameView({ matchId }: { matchId: string }) {
{/* Action buttons */}
<div className="flex items-center gap-4 mt-5">
<Button
variant="coral"
variant="danger"
size="md"
onClick={resign}
disabled={gameOver}
......@@ -913,7 +913,7 @@ function BotGameView({ botId }: { botId: string | undefined }) {
{/* Action buttons */}
<div className="flex items-center gap-4 mt-5">
<Button
variant="coral"
variant="danger"
size="md"
onClick={() => { setGameOver(true); setResult('استسلام'); playSound('lose') }}
>
......
This diff is collapsed.
......@@ -178,9 +178,9 @@ export function MatchmakingPage() {
جاري البحث عن خصم
</motion.h2>
{/* Timer in a game-panel mini-bar */}
{/* Timer in a card mini-bar */}
<motion.div
className="mt-4 game-panel !py-2 !px-6 inline-flex items-center justify-center"
className="mt-4 card !py-2 !px-6 inline-flex items-center justify-center"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.4 }}
......@@ -217,7 +217,7 @@ export function MatchmakingPage() {
<motion.button
whileTap={{ scale: 0.93 }}
onClick={handleCancel}
className="btn-3d px-8 py-3 rounded-xl bg-surface-2 border-3 border-border text-text-muted text-sm font-black"
className="px-8 py-3 rounded-xl bg-surface-2 border-3 border-border text-text-muted text-sm font-black"
style={{ boxShadow: '0 4px 0 rgba(0,0,0,0.3)' }}
>
الغاء
......
This diff is collapsed.
......@@ -25,7 +25,7 @@ export function SettingsPage() {
<div className="flex flex-col gap-3">
{/* Sound toggle */}
<div className="game-panel !p-4 flex items-center justify-between">
<div className="card !p-4 flex items-center justify-between">
<div className="flex items-center gap-3">
{soundEnabled ? (
<div className="w-10 h-10 rounded-xl bg-[#00E5CC]/15 border-2 border-[#00E5CC]/30 flex items-center justify-center">
......@@ -63,7 +63,7 @@ export function SettingsPage() {
</div>
{/* Report bug */}
<div className="game-panel !p-4 flex items-center gap-3">
<div className="card !p-4 flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-[#B44DFF]/15 border-2 border-[#B44DFF]/30 flex items-center justify-center">
<Bug size={18} className="text-[#B44DFF]" />
</div>
......@@ -74,7 +74,7 @@ export function SettingsPage() {
</div>
{/* Version info - recessed panel */}
<div className="game-panel !p-4 flex items-center gap-3"
<div className="card !p-4 flex items-center gap-3"
style={{ boxShadow: 'inset 0 3px 8px rgba(0,0,0,0.3), inset 0 1px 2px rgba(0,0,0,0.2)' }}
>
<div className="w-10 h-10 rounded-xl bg-[#FFC83D]/15 border-2 border-[#FFC83D]/30 flex items-center justify-center">
......@@ -92,7 +92,7 @@ export function SettingsPage() {
<motion.button
whileTap={{ scale: 0.93 }}
onClick={handleLogout}
className="btn-3d flex items-center justify-center gap-2.5 w-[70%] px-6 py-3.5 rounded-2xl bg-[#FF5252] text-white font-black text-sm"
className="flex items-center justify-center gap-2.5 w-[70%] px-6 py-3.5 rounded-2xl bg-[#FF5252] text-white font-black text-sm"
>
<LogOut size={16} />
<span>تسجيل الخروج</span>
......
......@@ -242,7 +242,7 @@ export function ShopPage() {
onClick={() => !purchasing && setSelectedItem(null)}
>
<motion.div
className="w-full max-w-[340px] game-panel !p-0 flex flex-col items-center relative overflow-hidden"
className="w-full max-w-[340px] card !p-0 flex flex-col items-center relative overflow-hidden"
initial={{ scale: 0.7, opacity: 0, rotate: -3 }}
animate={{ scale: 1, opacity: 1, rotate: 0 }}
exit={{ scale: 0.7, opacity: 0, rotate: 3 }}
......@@ -333,7 +333,7 @@ export function ShopPage() {
whileTap={{ scale: 0.93 }}
onClick={handleEquip}
disabled={purchasing}
className="btn-3d w-full py-3 rounded-xl bg-[#00E5CC] text-background text-sm font-black disabled:opacity-50"
className="w-full py-3 rounded-xl bg-[#00E5CC] text-background text-sm font-black disabled:opacity-50"
>
{purchasing ? 'جاري...' : 'تفعيل'}
</motion.button>
......@@ -365,7 +365,7 @@ export function ShopPage() {
? (profile?.gems || 0) < (selectedItem.price_gems || 0)
: (profile?.coins || 0) < (selectedItem.price_coins || 0))
}
className="btn-3d w-full py-3 rounded-xl bg-gradient-to-b from-[#FFC83D] to-[#E5A800] text-background text-sm font-black disabled:opacity-50 disabled:grayscale"
className="w-full py-3 rounded-xl bg-gradient-to-b from-[#FFC83D] to-[#E5A800] text-background text-sm font-black disabled:opacity-50 disabled:grayscale"
>
{purchasing ? 'جاري...' : 'شراء'}
</motion.button>
......
......@@ -84,7 +84,7 @@ export function TournamentsPage() {
{loading ? (
<div className="flex flex-col gap-4">
{[1, 2, 3].map((i) => (
<div key={i} className="game-panel animate-pulse !p-5">
<div key={i} className="card animate-pulse !p-5">
<div className="w-36 h-5 rounded bg-surface-3 mb-3" />
<div className="w-24 h-3 rounded bg-surface-3" />
</div>
......@@ -122,7 +122,7 @@ export function TournamentsPage() {
exit={{ opacity: 0, y: -16 }}
transition={{ type: 'spring', stiffness: 400, damping: 24, delay: i * 0.06 }}
>
<div className="game-panel relative overflow-hidden !p-5">
<div className="card relative overflow-hidden !p-5">
{/* Status ribbon - diagonal corner badge */}
<div
className="absolute top-0 left-0 w-28 h-7 flex items-center justify-center"
......@@ -207,7 +207,7 @@ export function TournamentsPage() {
<motion.button
whileTap={{ scale: 0.93 }}
onClick={() => unregister(t.id)}
className="btn-3d px-3.5 py-2 rounded-xl bg-[#FF5252] text-white text-xs font-black"
className="px-3.5 py-2 rounded-xl bg-[#FF5252] text-white text-xs font-black"
>
إلغاء
</motion.button>
......@@ -216,7 +216,7 @@ export function TournamentsPage() {
<motion.button
whileTap={{ scale: 0.93 }}
onClick={() => register(t.id)}
className="btn-3d w-[75%] py-3 rounded-xl bg-gradient-to-b from-[#FFC83D] to-[#E5A800] text-background text-sm font-black"
className="w-[75%] py-3 rounded-xl bg-gradient-to-b from-[#FFC83D] to-[#E5A800] text-background text-sm font-black"
>
سجل الان
</motion.button>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment