Initial import
This commit is contained in:
commit
f964f4167b
5
app/.firebaserc
Normal file
5
app/.firebaserc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "gamehus"
|
||||
}
|
||||
}
|
||||
69
app/.gitignore
vendored
Normal file
69
app/.gitignore
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
firebase-debug.log*
|
||||
firebase-debug.*.log*
|
||||
|
||||
# Firebase cache
|
||||
.firebase/
|
||||
|
||||
# Firebase config
|
||||
|
||||
# Uncomment this if you'd like others to create their own Firebase project.
|
||||
# For a team working on the same Firebase project(s), it is recommended to leave
|
||||
# it commented so all members can deploy to the same project(s) in .firebaserc.
|
||||
# .firebaserc
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# dataconnect generated files
|
||||
.dataconnect
|
||||
10
app/firebase.json
Normal file
10
app/firebase.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"hosting": {
|
||||
"public": "public",
|
||||
"ignore": [
|
||||
"firebase.json",
|
||||
"**/.*",
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
33
app/public/404.html
Normal file
33
app/public/404.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Page Not Found</title>
|
||||
|
||||
<style media="screen">
|
||||
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
|
||||
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px 16px; border-radius: 3px; }
|
||||
#message h3 { color: #888; font-weight: normal; font-size: 16px; margin: 16px 0 12px; }
|
||||
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
|
||||
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
|
||||
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
|
||||
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
|
||||
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
|
||||
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
|
||||
@media (max-width: 600px) {
|
||||
body, #message { margin-top: 0; background: white; box-shadow: none; }
|
||||
body { border-top: 16px solid #ffa100; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="message">
|
||||
<h2>404</h2>
|
||||
<h1>Page Not Found</h1>
|
||||
<p>The specified file was not found on this website. Please check the URL for mistakes and try again.</p>
|
||||
<h3>Why am I seeing this?</h3>
|
||||
<p>This page was generated by the Firebase Command-Line Interface. To modify it, edit the <code>404.html</code> file in your project's configured <code>public</code> directory.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
135
app/public/chat.html
Normal file
135
app/public/chat.html
Normal file
@ -0,0 +1,135 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GAMEHUS — الدردشة</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-page="chat" class="auth-guard">
|
||||
|
||||
<div class="app-shell">
|
||||
<header id="topbar" class="topbar"></header>
|
||||
<div class="app-body">
|
||||
<aside id="sidebar" class="sidebar"></aside>
|
||||
<main class="content-area">
|
||||
|
||||
<!-- 2-column layout: rooms list + chat area -->
|
||||
<div style="display:flex;height:100%;overflow:hidden;">
|
||||
|
||||
<!-- Rooms column -->
|
||||
<div style="width:200px;background:var(--bg-surface);border-left:1px solid var(--border-gold);display:flex;flex-direction:column;flex-shrink:0;">
|
||||
<div style="padding:14px 12px 8px;border-bottom:1px solid var(--border-dim);">
|
||||
<div style="font-size:0.7rem;font-weight:800;letter-spacing:2px;color:var(--gold-dim);text-transform:uppercase;">الغرف</div>
|
||||
</div>
|
||||
<div style="overflow-y:auto;flex:1;padding:8px;">
|
||||
${[
|
||||
{id:'general', icon:'🌍', name:'العامة', users:284, active:true},
|
||||
{id:'billiards',icon:'🎱', name:'البلياردو', users:156},
|
||||
{id:'chess', icon:'♟️', name:'الشطرنج', users:98},
|
||||
{id:'vip', icon:'👑', name:'VIP فقط', users:34, vip:true},
|
||||
{id:'help', icon:'❓', name:'المساعدة', users:22},
|
||||
{id:'welcome', icon:'👋', name:'الترحيب', users:67},
|
||||
].map(r=>`
|
||||
<div onclick="switchRoom(this,'${r.id}')" style="display:flex;align-items:center;justify-content:space-between;padding:9px 10px;border-radius:9px;cursor:pointer;margin-bottom:2px;background:${r.active?'rgba(212,160,23,0.1)':'transparent'};border:1px solid ${r.active?'var(--border-gold)':'transparent'};transition:all 0.2s;" onmouseover="if(!this.classList.contains('r-active'))this.style.background='rgba(255,255,255,0.04)'" onmouseout="if(!this.classList.contains('r-active'))this.style.background='transparent'" class="${r.active?'r-active':''}">
|
||||
<div style="display:flex;align-items:center;gap:7px;">
|
||||
<span style="font-size:0.9rem;">${r.icon}</span>
|
||||
<span style="font-size:0.82rem;font-weight:600;color:${r.active?'var(--gold)':'var(--text-muted)'};">${r.name}</span>
|
||||
${r.vip?`<span class="vip-badge vip-badge-outline" style="font-size:0.58rem;padding:1px 4px;">VIP</span>`:''}
|
||||
</div>
|
||||
<span style="font-size:0.68rem;color:var(--text-faint);">${r.users}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div style="padding:10px 12px;border-top:1px solid var(--border-dim);">
|
||||
<div style="display:flex;align-items:center;gap:5px;">
|
||||
<span class="online-dot"></span>
|
||||
<span style="font-size:0.75rem;color:var(--text-muted);" id="chat-online">661 متصل</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chat Area -->
|
||||
<div class="chat-wrap" style="flex:1;">
|
||||
<div style="padding:10px 16px;border-bottom:1px solid var(--border-gold);display:flex;align-items:center;gap:10px;flex-shrink:0;background:var(--bg-surface);">
|
||||
<span id="room-icon" style="font-size:1.2rem;">🌍</span>
|
||||
<div>
|
||||
<div id="room-name" style="font-weight:800;color:var(--text-main);font-size:0.92rem;">الدردشة العامة</div>
|
||||
<div id="room-count" style="font-size:0.72rem;color:var(--green);">284 متصل</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-messages" id="chat-messages">
|
||||
<!-- messages injected by JS -->
|
||||
</div>
|
||||
<div class="chat-input-bar">
|
||||
<input class="chat-input" id="msg-input" placeholder="اكتب رسالتك..." onkeydown="if(event.key==='Enter')sendMsg()">
|
||||
<button class="btn btn-gold btn-sm" onclick="sendMsg()">إرسال ✈️</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="static/script.js"></script>
|
||||
<script>
|
||||
const SEED_MSGS = [
|
||||
{u:'ProShooter99',c:'🇸🇦',m:'أي شخص يريد لعب بلياردو؟ 🎱',t:'00:01'},
|
||||
{u:'ChessWizard',c:'🇲🇦',m:'هل هناك بطولة شطرنج اليوم؟',t:'00:03'},
|
||||
{u:'PoolKing_X',c:'🇪🇬',m:'ابحث عن منافس في لعبة 8-ball!',t:'00:05'},
|
||||
{u:'NightHunter',c:'🇱🇧',m:'GG أفضل لعبة الليلة 🏆',t:'00:08'},
|
||||
{u:'TacticalMove',c:'🇦🇪',m:'تحدي مفتوح في الشطرنج، ادخلوا غرفتي',t:'00:10'},
|
||||
{u:'BallMaster',c:'🇦🇪',m:'مستعد لأي تحدٍ في البلياردو 💪',t:'00:12'},
|
||||
{u:'KingSlayer',c:'🇪🇬',m:'من يريد لعبة شطرنج سريعة؟ ⏱️',t:'00:15'},
|
||||
{u:'SpinMaster',c:'🇰🇼',m:'أنا جاهز! تعال غرفتي',t:'00:16'},
|
||||
];
|
||||
|
||||
function renderMsg(m, own=false) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'chat-bubble animate-in';
|
||||
div.innerHTML = `
|
||||
<div class="chat-avatar" style="${own?'background:linear-gradient(135deg,var(--gold-dark),var(--gold-dim));':''}">${m.u.substring(0,2).toUpperCase()}</div>
|
||||
<div>
|
||||
<div style="display:flex;align-items:center;gap:6px;">
|
||||
<span class="chat-name" style="${own?'color:var(--gold);':''}">${m.u}</span>
|
||||
${m.c?`<span style="font-size:0.82rem;">${m.c}</span>`:''}
|
||||
<span class="chat-time">${m.t}</span>
|
||||
</div>
|
||||
<div class="chat-text">${m.m}</div>
|
||||
</div>`;
|
||||
return div;
|
||||
}
|
||||
|
||||
const box = document.getElementById('chat-messages');
|
||||
SEED_MSGS.forEach(m => box.appendChild(renderMsg(m)));
|
||||
box.scrollTop = box.scrollHeight;
|
||||
|
||||
function sendMsg() {
|
||||
const user = Auth.getSession();
|
||||
const inp = document.getElementById('msg-input');
|
||||
const txt = inp.value.trim();
|
||||
if (!txt || !user) return;
|
||||
const now = new Date();
|
||||
const t = now.getHours().toString().padStart(2,'0')+':'+now.getMinutes().toString().padStart(2,'0');
|
||||
box.appendChild(renderMsg({u:user.username,c:'',m:txt,t}, true));
|
||||
box.scrollTop = box.scrollHeight;
|
||||
inp.value = '';
|
||||
}
|
||||
|
||||
function switchRoom(el, roomId) {
|
||||
document.querySelectorAll('.r-active').forEach(r => {
|
||||
r.classList.remove('r-active');
|
||||
r.style.background = 'transparent';
|
||||
r.style.borderColor = 'transparent';
|
||||
r.querySelector('span:nth-child(2)') && (r.querySelector('span:nth-child(2)').style.color = 'var(--text-muted)');
|
||||
});
|
||||
el.classList.add('r-active');
|
||||
el.style.background = 'rgba(212,160,23,0.1)';
|
||||
el.style.borderColor = 'var(--border-gold)';
|
||||
Toast.show('انتقلت إلى ' + el.querySelector('span:nth-child(2)').textContent, 'gold', 2000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
5
app/public/favicon.svg
Normal file
5
app/public/favicon.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" rx="6" fill="#0a0e1a" />
|
||||
<circle cx="16" cy="16" r="11" fill="#00c851" opacity="0.15" stroke="#00c851" stroke-width="1.5" />
|
||||
<text x="16" y="22" text-anchor="middle" font-size="16">🎱</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 296 B |
31
app/public/firebase.json
Normal file
31
app/public/firebase.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"hosting": {
|
||||
"public": ".",
|
||||
"ignore": [
|
||||
"firebase.json",
|
||||
"**/.*",
|
||||
"**/node_modules/**"
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/app",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"source": "**/*.@(js|css)",
|
||||
"headers": [
|
||||
{ "key": "Cache-Control", "value": "max-age=86400" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "**",
|
||||
"headers": [
|
||||
{ "key": "X-Frame-Options", "value": "DENY" },
|
||||
{ "key": "X-Content-Type-Options", "value": "nosniff" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
86
app/public/game-details.html
Normal file
86
app/public/game-details.html
Normal file
@ -0,0 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>تفاصيل اللعبة - GAMEHUS</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="nav-bar fixed top-0 left-0 right-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 flex items-center justify-between h-16">
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="index.html" class="flex items-center gap-2 no-underline"><div class="logo-icon">🎱</div><span class="logo-text">GAMEHUS</span></a>
|
||||
<div class="hidden md:flex items-center gap-1 ml-6"><a href="index.html" class="nav-link">الرئيسية</a><a href="games.html" class="nav-link">الألعاب</a><a href="top.html" class="nav-link">المتصدرون</a><a href="chat.html" class="nav-link">الدردشة</a></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2"><div class="online-badge"><span class="online-dot"></span><span id="online-count">8,432</span> متصل</div><a href="login.html" class="btn-outline-sm">دخول</a><a href="register.html" class="btn-primary-sm">تسجيل</a><button class="md:hidden mobile-toggle p-2"><svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path></svg></button></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="mobile-menu" class="mobile-menu"><a href="index.html" class="block nav-link">الرئيسية</a><a href="games.html" class="block nav-link">الألعاب</a><a href="top.html" class="block nav-link">المتصدرون</a><a href="chat.html" class="block nav-link">الدردشة</a></div>
|
||||
|
||||
<div id="main-content" style="padding-top:64px;"></div>
|
||||
|
||||
<footer class="footer mt-16">
|
||||
<div class="max-w-7xl mx-auto px-4 py-12">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
<div><div class="flex items-center gap-2 mb-4"><span class="text-2xl">🎱</span><span class="text-xl font-bold text-white">GAMEHUS</span></div><p class="text-gray-400 text-sm">العب بلياردو وشطرنج مجانًا مع لاعبين من حول العالم.</p></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">الألعاب</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="games.html">8-Ball Pool</a></li><li><a href="games.html">9-Ball Pool</a></li><li><a href="games.html">الشطرنج</a></li></ul></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">المجتمع</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="top.html">المتصدرون</a></li><li><a href="chat.html">الدردشة</a></li><li><a href="tournaments.html">البطولات</a></li></ul></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">الحساب</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="register.html">إنشاء حساب</a></li><li><a href="login.html">تسجيل الدخول</a></li><li><a href="profile.html">الملف الشخصي</a></li></ul></div>
|
||||
</div>
|
||||
<div class="border-t border-gray-800 mt-8 pt-6 text-center text-gray-500 text-sm">© 2026 GAMEHUS - جميع الحقوق محفوظة</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const games = [
|
||||
{ id: "billiards-8ball", name: "8-Ball Pool", icon: "🎱", players: 1247, desc: "اللعبة الكلاسيكية الأشهر." },
|
||||
{ id: "billiards-9ball", name: "9-Ball Pool", icon: "🎱", players: 892, desc: "وضع سريع وتنافسي." },
|
||||
{ id: "billiards-snooker", name: "Snooker", icon: "🎯", players: 654, desc: "أسلوب احترافي لعشاق الدقة." },
|
||||
{ id: "chess-classic", name: "Classic Chess", icon: "♟️", players: 2103, desc: "استراتيجية وتخطيط." },
|
||||
{ id: "chess-rapid", name: "Rapid Chess", icon: "⏱️", players: 1456, desc: "حسم سريع خلال 10 دقائق." },
|
||||
{ id: "checkers", name: "Checkers", icon: "🔴", players: 445, desc: "داما ممتعة وسلسة." }
|
||||
];
|
||||
const params = new URLSearchParams(location.search);
|
||||
const id = params.get("id");
|
||||
const game = games.find(g => g.id === id) || games[0];
|
||||
const similar = games.filter(g => g.id !== game.id).slice(0, 3);
|
||||
document.title = `${game.name} - GAMEHUS`;
|
||||
document.getElementById("main-content").innerHTML = `
|
||||
<div class="max-w-7xl mx-auto px-4 py-12">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div class="lg:col-span-2">
|
||||
<div class="flex items-center gap-3 mb-6"><span class="text-3xl">${game.icon}</span><div><h1 class="text-2xl font-black text-white">${game.name}</h1><div class="flex items-center gap-2 mt-1"><span class="online-dot"></span><span style="color:#4ade80;font-size:0.85rem;">${game.players.toLocaleString()} يلعبون الآن</span></div></div></div>
|
||||
<div class="card" style="background:linear-gradient(135deg,#0d1a0d,#1a2e1a);border:1px solid rgba(0,200,81,0.2);animation:glow 3s infinite;">
|
||||
<div style="height:440px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:20px;position:relative;overflow:hidden;">
|
||||
<div style="position:absolute;inset:0;background-image:radial-gradient(rgba(0,200,81,0.1) 1px,transparent 1px);background-size:24px 24px;opacity:0.45;"></div>
|
||||
<div style="font-size:5rem;position:relative;z-index:1;">${game.icon}</div>
|
||||
<h2 style="font-size:1.8rem;font-weight:900;color:#fff;position:relative;z-index:1;">${game.name}</h2>
|
||||
<p style="color:#9ca3af;font-size:1rem;text-align:center;max-width:420px;position:relative;z-index:1;">${game.desc}</p>
|
||||
<div class="flex gap-4 relative z-10 flex-wrap justify-center"><a href="register.html" class="btn-primary" style="font-size:1.05rem;padding:14px 40px;">🎮 العب الآن - مجانًا</a><a href="rooms.html?gameId=${game.id}" class="btn-secondary" style="font-size:1rem;padding:14px 30px;">🏠 الغرف</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-6">
|
||||
<div class="card p-4">
|
||||
<h3 class="text-base font-bold text-white mb-4">🏠 غرف مفتوحة</h3>
|
||||
<div class="space-y-2">
|
||||
<div style="padding:10px 12px;background:rgba(255,255,255,0.03);border-radius:8px;border:1px solid rgba(255,255,255,0.06);"><div style="font-size:0.85rem;font-weight:700;color:#e2e8f0;">غرفة Ace #1001</div><div style="font-size:0.75rem;color:#6b7280;">بانتظار منافس</div></div>
|
||||
<div style="padding:10px 12px;background:rgba(255,255,255,0.03);border-radius:8px;border:1px solid rgba(255,255,255,0.06);"><div style="font-size:0.85rem;font-weight:700;color:#e2e8f0;">غرفة Pro #1038</div><div style="font-size:0.75rem;color:#6b7280;">بانتظار منافس</div></div>
|
||||
</div>
|
||||
<a href="rooms.html?gameId=${game.id}" class="btn-outline-sm w-full text-center mt-3 block text-sm">عرض كل الغرف</a>
|
||||
</div>
|
||||
<div class="card p-4">
|
||||
<h3 class="text-base font-bold text-white mb-4">🎮 ألعاب مشابهة</h3>
|
||||
<div class="space-y-3">${similar.map(s => `<a href="game-details.html?id=${s.id}" style="display:flex;align-items:center;gap:12px;padding:10px 12px;background:rgba(255,255,255,0.03);border-radius:8px;border:1px solid rgba(255,255,255,0.06);"><span style="font-size:1.7rem;">${s.icon}</span><div><div style="font-size:0.9rem;font-weight:700;color:#e2e8f0;">${s.name}</div><div style="font-size:0.75rem;color:#4ade80;">${s.players.toLocaleString()} يلعبون</div></div></a>`).join("")}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
</script>
|
||||
<script src="static/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
106
app/public/games.html
Normal file
106
app/public/games.html
Normal file
@ -0,0 +1,106 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GAMEHUS — الألعاب</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-page="games" class="auth-guard">
|
||||
|
||||
<div class="app-shell">
|
||||
<header id="topbar" class="topbar"></header>
|
||||
<div class="app-body">
|
||||
<aside id="sidebar" class="sidebar"></aside>
|
||||
<main class="content-area">
|
||||
|
||||
<!-- Inner tabs for game categories -->
|
||||
<div style="flex:1;overflow:hidden;display:flex;flex-direction:column;" data-inner-tabs>
|
||||
<div class="inner-tab-bar">
|
||||
<button class="inner-tab" data-inner-tab="all">🎮 الكل</button>
|
||||
<button class="inner-tab" data-inner-tab="billiards">🎱 البلياردو</button>
|
||||
<button class="inner-tab" data-inner-tab="chess">♟️ الشطرنج</button>
|
||||
<button class="inner-tab" data-inner-tab="checkers">🔴 الداما</button>
|
||||
</div>
|
||||
|
||||
<!-- All -->
|
||||
<div class="inner-panel" data-inner-panel="all">
|
||||
<div class="inner-content" id="grid-all"></div>
|
||||
</div>
|
||||
<!-- Billiards -->
|
||||
<div class="inner-panel" data-inner-panel="billiards">
|
||||
<div class="inner-content" id="grid-billiards"></div>
|
||||
</div>
|
||||
<!-- Chess -->
|
||||
<div class="inner-panel" data-inner-panel="chess">
|
||||
<div class="inner-content" id="grid-chess"></div>
|
||||
</div>
|
||||
<!-- Checkers -->
|
||||
<div class="inner-panel" data-inner-panel="checkers">
|
||||
<div class="inner-content" id="grid-checkers"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="static/script.js"></script>
|
||||
<script>
|
||||
const ALL_GAMES = [
|
||||
{id:'billiards-8ball', name:'8-Ball Pool', icon:'🎱', bg:'linear-gradient(135deg,#0a2010,#143020)', players:1247, badge:'الأكثر شعبية', cat:'billiards', desc:'اللعبة الكلاسيكية الأشهر — أدخل كراتك وأنهِ بالسوداء'},
|
||||
{id:'billiards-9ball', name:'9-Ball Pool', icon:'🎱', bg:'linear-gradient(135deg,#0a1a18,#102820)', players:892, badge:'مميز', cat:'billiards', desc:'العب بالأرقام بالترتيب وأدخل كرة 9 للفوز'},
|
||||
{id:'billiards-snooker',name:'Snooker', icon:'🎯', bg:'linear-gradient(135deg,#0a1810,#122018)', players:654, badge:'احترافي', cat:'billiards', desc:'طاولة كبيرة وتكتيك عالٍ — للمحترفين فقط'},
|
||||
{id:'chess-classic', name:'Classic Chess', icon:'♟️', bg:'linear-gradient(135deg,#10121a,#1a1e30)', players:2103, badge:'الأكثر شعبية', cat:'chess', desc:'الشطرنج الكلاسيكي — اختبر ذكاءك ضد أقوى اللاعبين'},
|
||||
{id:'chess-rapid', name:'Rapid Chess', icon:'⏱️', bg:'linear-gradient(135deg,#141418,#20202c)', players:1456, badge:'سريع', cat:'chess', desc:'10 دقائق للحسم — سرعة التفكير هي المفتاح'},
|
||||
{id:'checkers', name:'Checkers', icon:'🔴', bg:'linear-gradient(135deg,#1a0a0a,#2c1212)', players:445, badge:'كلاسيكي', cat:'checkers', desc:'الداما الكلاسيكية — استراتيجية بسيطة ومتعة لا تنتهي'},
|
||||
];
|
||||
|
||||
function buildCard(g) {
|
||||
return `
|
||||
<div class="game-card" onclick="location.href='game-details.html?id=${g.id}'">
|
||||
<div class="game-card-thumb" style="background:${g.bg};">
|
||||
<span style="position:relative;z-index:1;font-size:3.5rem;filter:drop-shadow(0 0 14px rgba(212,160,23,0.5));">${g.icon}</span>
|
||||
<span style="position:absolute;top:8px;right:8px;z-index:2;" class="badge badge-gold">${g.badge}</span>
|
||||
</div>
|
||||
<div class="game-card-body">
|
||||
<div class="game-card-title">${g.name}</div>
|
||||
<div class="game-card-sub" style="margin:4px 0 10px;">${g.desc}</div>
|
||||
<div style="display:flex;align-items:center;gap:5px;margin-bottom:10px;">
|
||||
<span class="online-dot"></span>
|
||||
<span style="color:#4ade80;font-size:0.78rem;font-weight:700;">${g.players.toLocaleString('ar')} يلعبون الآن</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:6px;">
|
||||
<button class="btn btn-gold btn-sm" style="flex:1;justify-content:center;" onclick="event.stopPropagation();location.href='game-details.html?id=${g.id}'">▶ العب</button>
|
||||
<a href="rooms.html?gameId=${g.id}" class="btn btn-ghost btn-sm" style="flex:1;justify-content:center;" onclick="event.stopPropagation()">🏠 الغرف</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderGrid(id, games) {
|
||||
document.getElementById(id).innerHTML = `
|
||||
<div style="margin-bottom:20px;">
|
||||
<h1 style="font-size:1.4rem;font-weight:900;" class="gold-text">🎮 ${id==='grid-all'?'جميع الألعاب':games[0]?.cat==='billiards'?'ألعاب البلياردو':games[0]?.cat==='chess'?'ألعاب الشطرنج':'ألعاب الداما'}</h1>
|
||||
<p style="color:var(--text-muted);font-size:0.85rem;margin-top:4px;">${games.length} لعبة متاحة</p>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px;">
|
||||
${games.map(buildCard).join('')}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
renderGrid('grid-all', ALL_GAMES);
|
||||
renderGrid('grid-billiards', ALL_GAMES.filter(g=>g.cat==='billiards'));
|
||||
renderGrid('grid-chess', ALL_GAMES.filter(g=>g.cat==='chess'));
|
||||
renderGrid('grid-checkers', ALL_GAMES.filter(g=>g.cat==='checkers'));
|
||||
// open tab from URL
|
||||
const cat = new URLSearchParams(location.search).get('cat') || 'all';
|
||||
const tab = document.querySelector(`[data-inner-tab="${cat}"]`);
|
||||
if (tab) tab.click();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
392
app/public/index.html
Normal file
392
app/public/index.html
Normal file
@ -0,0 +1,392 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GAMEHUS — الرئيسية</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-page="dashboard" class="auth-guard">
|
||||
|
||||
<div class="app-shell">
|
||||
|
||||
<!-- TOP BAR -->
|
||||
<header id="topbar" class="topbar"></header>
|
||||
|
||||
<!-- BODY ROW -->
|
||||
<div class="app-body">
|
||||
|
||||
<!-- SIDEBAR -->
|
||||
<aside id="sidebar" class="sidebar"></aside>
|
||||
|
||||
<!-- CONTENT AREA -->
|
||||
<main class="content-area" id="main-tabs-host">
|
||||
|
||||
<!-- Main Tab Bar -->
|
||||
<div class="tab-bar" id="main-tab-bar">
|
||||
<div class="tab-item active" data-tid="home">
|
||||
<span class="tab-icon">🏠</span>
|
||||
<span class="tab-label">الرئيسية</span>
|
||||
</div>
|
||||
<div class="tab-item" data-tid="games-tab" onclick="openTab('games-tab','🎮','الألعاب','games-panel')">
|
||||
<span class="tab-icon">🎮</span>
|
||||
<span class="tab-label">الألعاب</span>
|
||||
</div>
|
||||
<div class="tab-item" data-tid="top-tab" onclick="openTab('top-tab','🏆','المتصدرون','top-panel')">
|
||||
<span class="tab-icon">🏆</span>
|
||||
<span class="tab-label">المتصدرون</span>
|
||||
</div>
|
||||
<div class="tab-item" data-tid="chat-tab" onclick="openTab('chat-tab','💬','الدردشة','chat-panel')">
|
||||
<span class="tab-icon">💬</span>
|
||||
<span class="tab-label">الدردشة</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Panels -->
|
||||
<div class="tab-panels" id="main-tab-panels">
|
||||
|
||||
<!-- ══ HOME PANEL ════════════════════════════════════════ -->
|
||||
<div class="tab-panel active" data-panel="home">
|
||||
<div class="panel">
|
||||
|
||||
<!-- Welcome Banner -->
|
||||
<div id="welcome-banner" style="background:linear-gradient(135deg,rgba(212,160,23,0.13) 0%,rgba(122,92,12,0.07) 100%);border:1px solid var(--border-gold);border-radius:16px;padding:28px 32px;margin-bottom:28px;position:relative;overflow:hidden;">
|
||||
<div style="position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,var(--gold),transparent);"></div>
|
||||
<div style="position:absolute;inset:0;background-image:radial-gradient(circle 1px at 15% 50%,rgba(212,160,23,0.3) 0%,transparent 100%),radial-gradient(circle 1px at 85% 30%,rgba(212,160,23,0.2) 0%,transparent 100%);"></div>
|
||||
<div style="position:relative;z-index:1;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:16px;">
|
||||
<div>
|
||||
<div style="font-size:0.8rem;color:var(--gold-mid);font-weight:800;letter-spacing:1px;margin-bottom:6px;">مرحباً بعودتك 👑</div>
|
||||
<h1 id="welcome-name" style="font-size:1.8rem;font-weight:900;color:var(--text-main);margin-bottom:8px;">Loading...</h1>
|
||||
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
|
||||
<span id="welcome-vip"></span>
|
||||
<span style="font-size:0.82rem;color:var(--text-muted);">📅 آخر دخول: اليوم</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
||||
<div style="text-align:center;padding:14px 20px;background:rgba(0,0,0,0.2);border-radius:12px;border:1px solid rgba(212,160,23,0.2);">
|
||||
<div style="font-size:1.3rem;font-weight:900;" class="gold-text" id="dash-gold">0</div>
|
||||
<div style="font-size:0.72rem;color:var(--text-muted);margin-top:2px;">🪙 ذهب</div>
|
||||
</div>
|
||||
<div style="text-align:center;padding:14px 20px;background:rgba(0,0,0,0.2);border-radius:12px;border:1px solid rgba(176,184,200,0.2);">
|
||||
<div style="font-size:1.3rem;font-weight:900;color:var(--silver-light);" id="dash-silver">0</div>
|
||||
<div style="font-size:0.72rem;color:var(--text-muted);margin-top:2px;">🔘 فضة</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Row -->
|
||||
<div class="grid grid-cols-4 gap-4 mb-8" style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:28px;">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">👥</div>
|
||||
<div class="stat-value gold-text" data-count="8432">0</div>
|
||||
<div class="stat-label">متصل الآن</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">🎮</div>
|
||||
<div class="stat-value" style="color:#4ade80;" data-count="3219">0</div>
|
||||
<div class="stat-label">يلعبون الآن</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">🏠</div>
|
||||
<div class="stat-value" style="color:#a78bfa;" data-count="847">0</div>
|
||||
<div class="stat-label">غرفة مفتوحة</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">🏆</div>
|
||||
<div class="stat-value" style="color:var(--gold);" data-count="12">0</div>
|
||||
<div class="stat-label">بطولة نشطة</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Games + Leaderboard row -->
|
||||
<div style="display:grid;grid-template-columns:1fr 360px;gap:20px;margin-bottom:24px;">
|
||||
|
||||
<!-- Featured Games -->
|
||||
<div>
|
||||
<div class="section-title">🎮 ألعاب مميزة</div>
|
||||
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;">
|
||||
${[
|
||||
{id:'billiards-8ball',name:'8-Ball Pool',icon:'🎱',bg:'linear-gradient(135deg,#0a2010,#143020)',players:1247,badge:'الأكثر شعبية'},
|
||||
{id:'chess-classic', name:'الشطرنج', icon:'♟️',bg:'linear-gradient(135deg,#10121a,#1a1e30)',players:2103,badge:'استراتيجي'},
|
||||
{id:'billiards-9ball',name:'9-Ball', icon:'🎯',bg:'linear-gradient(135deg,#0a1a18,#102820)',players:892, badge:'مميز'},
|
||||
].map(g => `
|
||||
<div class="game-card" onclick="location.href='game-details.html?id=${g.id}'">
|
||||
<div class="game-card-thumb" style="background:${g.bg};">
|
||||
<span style="position:relative;z-index:1;filter:drop-shadow(0 0 12px rgba(212,160,23,0.4));">${g.icon}</span>
|
||||
<span style="position:absolute;top:8px;right:8px;z-index:2;" class="badge badge-gold">${g.badge}</span>
|
||||
</div>
|
||||
<div class="game-card-body">
|
||||
<div class="game-card-title">${g.name}</div>
|
||||
<div style="display:flex;align-items:center;gap:5px;margin-top:6px;">
|
||||
<span class="online-dot"></span>
|
||||
<span class="game-card-sub" style="color:#4ade80;">${g.players.toLocaleString('ar')} يلعبون</span>
|
||||
</div>
|
||||
<button class="btn btn-gold btn-sm" style="width:100%;justify-content:center;margin-top:10px;">▶ العب</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mini Leaderboard -->
|
||||
<div>
|
||||
<div class="section-title" style="display:flex;align-items:center;justify-content:space-between;">
|
||||
<span>🏆 المتصدرون</span>
|
||||
<a href="#" onclick="switchMainTab('top-tab');return false;" style="font-size:0.75rem;color:var(--gold);font-weight:700;">عرض الكل →</a>
|
||||
</div>
|
||||
<div class="card" style="padding:0;overflow:hidden;">
|
||||
<table class="rank-table">
|
||||
<tbody>
|
||||
${[
|
||||
{r:1,name:'ProShooter99',flag:'🇸🇦',pts:'15,420'},
|
||||
{r:2,name:'PoolKing_X', flag:'🇪🇬',pts:'14,200'},
|
||||
{r:3,name:'ChessWizard', flag:'🇲🇦',pts:'13,800'},
|
||||
{r:4,name:'BallMaster', flag:'🇦🇪',pts:'12,950'},
|
||||
{r:5,name:'NightHunter', flag:'🇱🇧',pts:'12,100'},
|
||||
].map(p => `
|
||||
<tr>
|
||||
<td class="rank-${p.r<=3?p.r:'rest'}">${p.r===1?'🥇':p.r===2?'🥈':p.r===3?'🥉':p.r}</td>
|
||||
<td style="font-weight:600;color:var(--text-main);">${p.flag} ${p.name}</td>
|
||||
<td class="gold-text" style="font-weight:800;font-size:0.85rem;">${p.pts}</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Monthly Points Train (preview) -->
|
||||
<div class="card card-gold" style="padding:20px;margin-bottom:24px;">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;flex-wrap:wrap;gap:8px;">
|
||||
<div>
|
||||
<div class="section-title" style="margin-bottom:2px;">🚂 قطار الجوائز الشهرية</div>
|
||||
<div style="font-size:0.8rem;color:var(--text-muted);">اجمع نقاطاً وصل إلى المحطات لتحصل على جوائز</div>
|
||||
</div>
|
||||
<a href="train.html" class="btn btn-outline-gold btn-sm">عرض التفاصيل</a>
|
||||
</div>
|
||||
<!-- Track preview -->
|
||||
<div class="train-track">
|
||||
${[
|
||||
{n:1,pts:'100',done:true,label:'بداية',reward:'50🔘'},
|
||||
{n:2,pts:'300',done:true,label:'محطة 2',reward:'150🔘'},
|
||||
{n:3,pts:'600',done:false,current:true,label:'محطة 3 ← أنت هنا',reward:'300🔘'},
|
||||
{n:4,pts:'1000',done:false,label:'محطة 4',reward:'500🔘'},
|
||||
{n:5,pts:'1500',done:false,label:'محطة 5',reward:'1🪙'},
|
||||
{n:6,pts:'2500',done:false,label:'نهاية الشهر',reward:'5🪙 + لقب'},
|
||||
].map((s,i,arr) => `
|
||||
${i>0?`<div class="station-line ${s.done?'done':''}"></div>`:''}
|
||||
<div class="station ${s.done?'done':''} ${s.current?'current':''}" title="${s.reward}">
|
||||
<div class="station-dot">${s.done?'✓':s.current?'★':s.n}</div>
|
||||
<div class="station-label" style="${s.current?'color:var(--gold);font-weight:700;':''}">${s.label}</div>
|
||||
<div style="font-size:0.62rem;color:var(--gold-mid);margin-top:2px;">${s.reward}</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- /home panel -->
|
||||
|
||||
<!-- ══ GAMES PANEL ═══════════════════════════════════════ -->
|
||||
<div class="tab-panel" data-panel="games-tab">
|
||||
<div style="flex:1;overflow:hidden;" data-inner-tabs>
|
||||
<div class="inner-tab-bar">
|
||||
<button class="inner-tab" data-inner-tab="all">الكل</button>
|
||||
<button class="inner-tab" data-inner-tab="billiards">🎱 البلياردو</button>
|
||||
<button class="inner-tab" data-inner-tab="chess">♟️ الشطرنج</button>
|
||||
<button class="inner-tab" data-inner-tab="checkers">🔴 الداما</button>
|
||||
</div>
|
||||
<div class="inner-panel" data-inner-panel="all">
|
||||
<div class="inner-content">
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px;">
|
||||
${[
|
||||
{id:'billiards-8ball',name:'8-Ball Pool',icon:'🎱',bg:'linear-gradient(135deg,#0a2010,#143020)',players:1247,badge:'الأكثر شعبية',cat:'billiards'},
|
||||
{id:'billiards-9ball',name:'9-Ball Pool',icon:'🎱',bg:'linear-gradient(135deg,#0a1a18,#102820)',players:892,badge:'مميز',cat:'billiards'},
|
||||
{id:'billiards-snooker',name:'Snooker',icon:'🎯',bg:'linear-gradient(135deg,#0a1810,#122018)',players:654,badge:'احترافي',cat:'billiards'},
|
||||
{id:'chess-classic',name:'Classic Chess',icon:'♟️',bg:'linear-gradient(135deg,#10121a,#1a1e30)',players:2103,badge:'الأكثر شعبية',cat:'chess'},
|
||||
{id:'chess-rapid',name:'Rapid Chess',icon:'⏱️',bg:'linear-gradient(135deg,#141418,#20202c)',players:1456,badge:'سريع',cat:'chess'},
|
||||
{id:'checkers',name:'Checkers',icon:'🔴',bg:'linear-gradient(135deg,#1a0a0a,#2c1212)',players:445,badge:'كلاسيكي',cat:'checkers'},
|
||||
].map(g => `
|
||||
<div class="game-card" onclick="location.href='game-details.html?id=${g.id}'">
|
||||
<div class="game-card-thumb" style="background:${g.bg};">
|
||||
<span style="position:relative;z-index:1;filter:drop-shadow(0 0 12px rgba(212,160,23,0.4));">${g.icon}</span>
|
||||
<span style="position:absolute;top:8px;right:8px;z-index:2;" class="badge badge-gold">${g.badge}</span>
|
||||
</div>
|
||||
<div class="game-card-body">
|
||||
<div class="game-card-title">${g.name}</div>
|
||||
<div style="display:flex;align-items:center;gap:5px;margin:6px 0;">
|
||||
<span class="online-dot"></span>
|
||||
<span class="game-card-sub" style="color:#4ade80;">${g.players.toLocaleString('ar')} يلعبون</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:6px;">
|
||||
<button class="btn btn-gold btn-sm" style="flex:1;justify-content:center;">▶ العب</button>
|
||||
<a href="rooms.html?gameId=${g.id}" class="btn btn-ghost btn-sm" style="flex:1;justify-content:center;">🏠</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inner-panel" data-inner-panel="billiards">
|
||||
<div class="inner-content"><p style="color:var(--text-muted);">يتم تحميل ألعاب البلياردو...</p></div>
|
||||
</div>
|
||||
<div class="inner-panel" data-inner-panel="chess">
|
||||
<div class="inner-content"><p style="color:var(--text-muted);">يتم تحميل ألعاب الشطرنج...</p></div>
|
||||
</div>
|
||||
<div class="inner-panel" data-inner-panel="checkers">
|
||||
<div class="inner-content"><p style="color:var(--text-muted);">يتم تحميل ألعاب الداما...</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══ TOP PANEL ══════════════════════════════════════════ -->
|
||||
<div class="tab-panel" data-panel="top-tab">
|
||||
<div style="flex:1;overflow:hidden;" data-inner-tabs>
|
||||
<div class="inner-tab-bar">
|
||||
<button class="inner-tab" data-inner-tab="top-billiards">🎱 البلياردو</button>
|
||||
<button class="inner-tab" data-inner-tab="top-chess">♟️ الشطرنج</button>
|
||||
</div>
|
||||
<div class="inner-panel" data-inner-panel="top-billiards">
|
||||
<div class="inner-content">
|
||||
<a href="top.html" class="btn btn-outline-gold btn-sm" style="margin-bottom:16px;">🔗 فتح الصفحة الكاملة</a>
|
||||
<div class="card" style="overflow:hidden;">
|
||||
<table class="rank-table">
|
||||
<thead><tr><th>#</th><th>اللاعب</th><th>الانتصارات</th><th>النقاط</th></tr></thead>
|
||||
<tbody>
|
||||
${[
|
||||
{r:1,n:'ProShooter99',f:'🇸🇦',w:2847,p:15420},
|
||||
{r:2,n:'PoolKing_X',f:'🇪🇬',w:2610,p:14200},
|
||||
{r:3,n:'SnookerLegend',f:'🇲🇦',w:2455,p:13800},
|
||||
{r:4,n:'BallMaster',f:'🇦🇪',w:2300,p:12950},
|
||||
{r:5,n:'CueTigerz',f:'🇮🇶',w:2190,p:12100},
|
||||
{r:6,n:'SilentStrike',f:'🇯🇴',w:2050,p:11300},
|
||||
{r:7,n:'NightHunter',f:'🇱🇧',w:1980,p:10800},
|
||||
{r:8,n:'SpinMaster',f:'🇰🇼',w:1870,p:10200},
|
||||
].map(p=>`
|
||||
<tr>
|
||||
<td class="rank-${p.r<=3?p.r:'rest'}">${p.r===1?'🥇':p.r===2?'🥈':p.r===3?'🥉':p.r}</td>
|
||||
<td style="font-weight:600;color:var(--text-main);">${p.f} ${p.n}</td>
|
||||
<td style="color:#4ade80;">${p.w.toLocaleString()}</td>
|
||||
<td class="gold-text" style="font-weight:800;">${p.p.toLocaleString()}</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inner-panel" data-inner-panel="top-chess">
|
||||
<div class="inner-content"><p style="color:var(--text-muted);">جدول الشطرنج...</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══ CHAT PANEL ═════════════════════════════════════════ -->
|
||||
<div class="tab-panel" data-panel="chat-tab">
|
||||
<div class="chat-wrap">
|
||||
<div class="chat-messages" id="chat-msgs">
|
||||
${[
|
||||
{u:'ProShooter99',c:'🇸🇦',m:'من يريد مباراة بلياردو؟ 🎱',t:'00:01'},
|
||||
{u:'ChessWizard',c:'🇲🇦',m:'هل هناك بطولة شطرنج اليوم؟',t:'00:03'},
|
||||
{u:'PoolKing_X',c:'🇪🇬',m:'أنا جاهز لتحدي 8-Ball!',t:'00:05'},
|
||||
{u:'NightHunter',c:'🇱🇧',m:'GG أفضل لعبة الليلة 🏆',t:'00:08'},
|
||||
{u:'TacticalMove',c:'🇦🇪',m:'تحدي مفتوح في الشطرنج، ادخلوا غرفتي',t:'00:10'},
|
||||
{u:'BallMaster',c:'🇦🇪',m:'مستعد لأي تحدٍ 💪',t:'00:12'},
|
||||
].map(m=>`
|
||||
<div class="chat-bubble">
|
||||
<div class="chat-avatar">${m.u.substring(0,2).toUpperCase()}</div>
|
||||
<div>
|
||||
<div style="display:flex;align-items:center;gap:6px;">
|
||||
<span class="chat-name">${m.u}</span>
|
||||
<span style="font-size:0.8rem;">${m.c}</span>
|
||||
<span class="chat-time">${m.t}</span>
|
||||
</div>
|
||||
<div class="chat-text">${m.m}</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div class="chat-input-bar">
|
||||
<input class="chat-input" id="chat-in" placeholder="اكتب رسالتك..." onkeydown="if(event.key==='Enter')sendMsg()">
|
||||
<button class="btn btn-gold btn-sm" onclick="sendMsg()">إرسال</button>
|
||||
<a href="chat.html" class="btn btn-ghost btn-sm">توسيع</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /tab-panels -->
|
||||
</main>
|
||||
|
||||
</div><!-- /app-body -->
|
||||
</div><!-- /app-shell -->
|
||||
|
||||
<script src="static/script.js"></script>
|
||||
<script>
|
||||
const user = Auth.requireAuth();
|
||||
if (user) {
|
||||
// populate welcome
|
||||
document.getElementById('welcome-name').textContent = 'أهلاً، ' + user.username + ' 👋';
|
||||
document.getElementById('dash-gold').textContent = (user.gold||0).toLocaleString('ar');
|
||||
document.getElementById('dash-silver').textContent = (user.silver||0).toLocaleString('ar');
|
||||
if (user.vip) {
|
||||
document.getElementById('welcome-vip').innerHTML = '<span class="vip-badge">✨ VIP</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// Tab switching for main tabs
|
||||
const mainTabBar = document.getElementById('main-tab-bar');
|
||||
const mainPanels = document.getElementById('main-tab-panels');
|
||||
|
||||
mainTabBar.querySelectorAll('.tab-item').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
mainTabBar.querySelectorAll('.tab-item').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
const tid = tab.dataset.tid;
|
||||
mainPanels.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
||||
const panel = mainPanels.querySelector(`[data-panel="${tid}"]`);
|
||||
if (panel) {
|
||||
panel.classList.add('active');
|
||||
// init inner tabs if first time
|
||||
panel.querySelectorAll('[data-inner-tabs]:not(.init-done)').forEach(el => {
|
||||
setupInnerTabs(el);
|
||||
el.classList.add('init-done');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function switchMainTab(tid) {
|
||||
const tab = mainTabBar.querySelector(`[data-tid="${tid}"]`);
|
||||
if (tab) tab.click();
|
||||
}
|
||||
|
||||
function sendMsg() {
|
||||
const inp = document.getElementById('chat-in');
|
||||
const msg = inp.value.trim();
|
||||
if (!msg || !user) return;
|
||||
const box = document.getElementById('chat-msgs');
|
||||
const now = new Date();
|
||||
const time = now.getHours().toString().padStart(2,'0') + ':' + now.getMinutes().toString().padStart(2,'0');
|
||||
const el = document.createElement('div');
|
||||
el.className = 'chat-bubble animate-in';
|
||||
el.innerHTML = `
|
||||
<div class="chat-avatar" style="background:linear-gradient(135deg,var(--gold-dark),var(--gold-dim));">${user.username.substring(0,2).toUpperCase()}</div>
|
||||
<div>
|
||||
<div style="display:flex;align-items:center;gap:6px;">
|
||||
<span class="chat-name">${user.username}</span>
|
||||
<span class="chat-time">${time}</span>
|
||||
</div>
|
||||
<div class="chat-text">${msg}</div>
|
||||
</div>`;
|
||||
box.appendChild(el);
|
||||
box.scrollTop = box.scrollHeight;
|
||||
inp.value = '';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
174
app/public/login.html
Normal file
174
app/public/login.html
Normal file
@ -0,0 +1,174 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GAMEHUS — ادخل إلى عالمك</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-page="login">
|
||||
|
||||
<!-- Animated background particles -->
|
||||
<div class="auth-screen" id="auth-screen">
|
||||
|
||||
<!-- Decorative gold lines -->
|
||||
<div style="position:absolute;inset:0;pointer-events:none;overflow:hidden;">
|
||||
<div style="position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(212,160,23,0.5),transparent);"></div>
|
||||
<div style="position:absolute;bottom:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(212,160,23,0.3),transparent);"></div>
|
||||
<!-- floating gold orbs -->
|
||||
<div style="position:absolute;width:300px;height:300px;border-radius:50%;background:radial-gradient(circle,rgba(212,160,23,0.07),transparent 70%);top:-80px;right:-80px;animation:particleDrift 8s ease-in-out infinite alternate;"></div>
|
||||
<div style="position:absolute;width:200px;height:200px;border-radius:50%;background:radial-gradient(circle,rgba(212,160,23,0.05),transparent 70%);bottom:60px;left:-40px;animation:particleDrift 10s ease-in-out infinite alternate-reverse;"></div>
|
||||
</div>
|
||||
|
||||
<div style="width:100%;max-width:460px;padding:16px;position:relative;z-index:1;">
|
||||
<div class="auth-card">
|
||||
|
||||
<!-- Logo -->
|
||||
<div class="auth-logo">
|
||||
<span class="logo-gem">💎</span>
|
||||
<div class="brand gold-text">GAMEHUS</div>
|
||||
<p style="color:var(--text-muted);font-size:0.85rem;margin-top:6px;">منصة الألعاب الفاخرة</p>
|
||||
</div>
|
||||
|
||||
<!-- Tab Switcher: Login / Register -->
|
||||
<div class="auth-tabs" role="tablist">
|
||||
<button class="auth-tab active" id="tab-login" onclick="switchTab('login')">تسجيل الدخول</button>
|
||||
<button class="auth-tab" id="tab-register" onclick="switchTab('register')">حساب جديد</button>
|
||||
</div>
|
||||
|
||||
<!-- LOGIN FORM -->
|
||||
<form id="form-login" onsubmit="handleLogin(event)">
|
||||
<div class="form-group">
|
||||
<label class="form-label">البريد الإلكتروني أو اسم المستخدم</label>
|
||||
<input type="text" id="login-id" class="form-input" placeholder="your@email.com" required autocomplete="username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">كلمة المرور</label>
|
||||
<div style="position:relative;">
|
||||
<input type="password" id="login-pass" class="form-input" placeholder="••••••••" required autocomplete="current-password">
|
||||
<button type="button" onclick="togglePass('login-pass',this)" style="position:absolute;left:12px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:0.9rem;">👁</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px;">
|
||||
<label style="display:flex;align-items:center;gap:7px;font-size:0.82rem;color:var(--text-muted);cursor:pointer;">
|
||||
<input type="checkbox" id="remember-me" style="accent-color:var(--gold-mid);width:14px;height:14px;"> تذكرني
|
||||
</label>
|
||||
<a href="#" style="font-size:0.82rem;color:var(--gold);font-weight:700;" onclick="Toast.show('سيتم إضافة استعادة كلمة المرور قريباً','info');return false;">نسيت كلمة المرور؟</a>
|
||||
</div>
|
||||
<div id="login-error" style="display:none;background:rgba(239,68,68,0.1);border:1px solid rgba(239,68,68,0.3);color:#f87171;padding:10px 14px;border-radius:8px;font-size:0.85rem;margin-bottom:14px;"></div>
|
||||
<button type="submit" class="btn btn-gold btn-lg" style="width:100%;justify-content:center;" id="login-btn">
|
||||
<span id="login-btn-text">🔑 دخول</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- REGISTER FORM (hidden by default) -->
|
||||
<form id="form-register" style="display:none;" onsubmit="handleRegister(event)">
|
||||
<div class="form-group">
|
||||
<label class="form-label">اسم المستخدم</label>
|
||||
<input type="text" id="reg-username" class="form-input" placeholder="اختر اسماً فريداً" required minlength="3" autocomplete="username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">البريد الإلكتروني</label>
|
||||
<input type="email" id="reg-email" class="form-input" placeholder="your@email.com" required autocomplete="email">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">كلمة المرور</label>
|
||||
<div style="position:relative;">
|
||||
<input type="password" id="reg-pass" class="form-input" placeholder="••••••••" required minlength="6" autocomplete="new-password">
|
||||
<button type="button" onclick="togglePass('reg-pass',this)" style="position:absolute;left:12px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:0.9rem;">👁</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom:20px;">
|
||||
<label class="form-label">تأكيد كلمة المرور</label>
|
||||
<input type="password" id="reg-pass2" class="form-input" placeholder="••••••••" required minlength="6" autocomplete="new-password">
|
||||
</div>
|
||||
<label style="display:flex;align-items:flex-start;gap:8px;font-size:0.82rem;color:var(--text-muted);cursor:pointer;margin-bottom:18px;">
|
||||
<input type="checkbox" required style="accent-color:var(--gold-mid);width:14px;height:14px;margin-top:2px;">
|
||||
<span>أوافق على <a href="terms.html" style="color:var(--gold);">شروط الاستخدام</a> و<a href="privacy.html" style="color:var(--gold);">سياسة الخصوصية</a></span>
|
||||
</label>
|
||||
<div id="reg-error" style="display:none;background:rgba(239,68,68,0.1);border:1px solid rgba(239,68,68,0.3);color:#f87171;padding:10px 14px;border-radius:8px;font-size:0.85rem;margin-bottom:14px;"></div>
|
||||
<button type="submit" class="btn btn-gold btn-lg" style="width:100%;justify-content:center;">✨ إنشاء الحساب</button>
|
||||
<p style="text-align:center;font-size:0.78rem;color:var(--text-muted);margin-top:14px;">التسجيل مجاني — تحصل على 1,200 فضة فور الانضمام 🔘</p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick test accounts hint -->
|
||||
<div style="margin-top:16px;background:rgba(212,160,23,0.06);border:1px solid rgba(212,160,23,0.15);border-radius:12px;padding:14px;font-size:0.78rem;color:var(--text-muted);text-align:center;">
|
||||
<div style="font-weight:700;color:var(--gold-mid);margin-bottom:6px;">🧪 حسابات الاختبار</div>
|
||||
<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap;">
|
||||
<span onclick="fillLogin('admin@gamehus.com','admin123')" style="cursor:pointer;color:var(--gold);text-decoration:underline;text-underline-offset:2px;">Admin</span>
|
||||
<span style="color:var(--text-faint)">·</span>
|
||||
<span onclick="fillLogin('vip@gamehus.com','vip123')" style="cursor:pointer;color:var(--gold);text-decoration:underline;text-underline-offset:2px;">VIP</span>
|
||||
<span style="color:var(--text-faint)">·</span>
|
||||
<span onclick="fillLogin('test@gamehus.com','test123')" style="cursor:pointer;color:var(--gold);text-decoration:underline;text-underline-offset:2px;">Test</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="static/script.js"></script>
|
||||
<script>
|
||||
// If already logged in → redirect
|
||||
if (Auth.getSession()) window.location.replace('index.html');
|
||||
// open register tab if hash says so
|
||||
if (location.hash === '#register') { switchTab('register'); history.replaceState(null,'',location.pathname); }
|
||||
|
||||
function switchTab(tab) {
|
||||
const isLogin = tab === 'login';
|
||||
document.getElementById('tab-login').classList.toggle('active', isLogin);
|
||||
document.getElementById('tab-register').classList.toggle('active', !isLogin);
|
||||
document.getElementById('form-login').style.display = isLogin ? 'block' : 'none';
|
||||
document.getElementById('form-register').style.display = isLogin ? 'none' : 'block';
|
||||
}
|
||||
|
||||
function handleLogin(e) {
|
||||
e.preventDefault();
|
||||
const id = document.getElementById('login-id').value.trim();
|
||||
const pass = document.getElementById('login-pass').value;
|
||||
const rem = document.getElementById('remember-me').checked;
|
||||
const errEl = document.getElementById('login-error');
|
||||
const btn = document.getElementById('login-btn-text');
|
||||
btn.textContent = '⏳ جارٍ التحقق...';
|
||||
setTimeout(() => {
|
||||
const result = Auth.login(id, pass, rem);
|
||||
if (result.ok) {
|
||||
btn.textContent = '✅ تم الدخول!';
|
||||
Toast.show('مرحباً بك ' + result.user.username + ' 👑', 'gold');
|
||||
setTimeout(() => window.location.replace('index.html'), 800);
|
||||
} else {
|
||||
errEl.textContent = result.msg;
|
||||
errEl.style.display = 'block';
|
||||
btn.textContent = '🔑 دخول';
|
||||
document.getElementById('login-pass').value = '';
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function handleRegister(e) {
|
||||
e.preventDefault();
|
||||
const p1 = document.getElementById('reg-pass').value;
|
||||
const p2 = document.getElementById('reg-pass2').value;
|
||||
const errEl = document.getElementById('reg-error');
|
||||
if (p1 !== p2) { errEl.textContent = 'كلمتا المرور غير متطابقتين'; errEl.style.display = 'block'; return; }
|
||||
errEl.style.display = 'none';
|
||||
Toast.show('🚧 التسجيل سيتم ربطه بـ Firebase قريباً', 'gold');
|
||||
}
|
||||
|
||||
function fillLogin(email, pass) {
|
||||
document.getElementById('login-id').value = email;
|
||||
document.getElementById('login-pass').value = pass;
|
||||
document.getElementById('tab-login').click();
|
||||
switchTab('login');
|
||||
}
|
||||
|
||||
function togglePass(inputId, btn) {
|
||||
const inp = document.getElementById(inputId);
|
||||
if (inp.type === 'password') { inp.type = 'text'; btn.textContent = '🙈'; }
|
||||
else { inp.type = 'password'; btn.textContent = '👁'; }
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
165
app/public/profile.html
Normal file
165
app/public/profile.html
Normal file
@ -0,0 +1,165 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GAMEHUS — الملف الشخصي</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-page="profile" class="auth-guard">
|
||||
|
||||
<div class="app-shell">
|
||||
<header id="topbar" class="topbar"></header>
|
||||
<div class="app-body">
|
||||
<aside id="sidebar" class="sidebar"></aside>
|
||||
<main class="content-area">
|
||||
|
||||
<div style="flex:1;overflow:hidden;display:flex;flex-direction:column;" data-inner-tabs>
|
||||
<div class="inner-tab-bar">
|
||||
<button class="inner-tab" data-inner-tab="p-info">📋 المعلومات</button>
|
||||
<button class="inner-tab" data-inner-tab="p-stats">📊 الإحصائيات</button>
|
||||
<button class="inner-tab" data-inner-tab="p-currency">💰 العملات</button>
|
||||
<button class="inner-tab" data-inner-tab="p-security">🔒 الأمان</button>
|
||||
</div>
|
||||
|
||||
<!-- Info Tab -->
|
||||
<div class="inner-panel" data-inner-panel="p-info">
|
||||
<div class="inner-content">
|
||||
<!-- Profile Header -->
|
||||
<div style="background:linear-gradient(135deg,rgba(212,160,23,0.1),rgba(0,0,0,0));border:1px solid var(--border-gold);border-radius:16px;padding:28px;margin-bottom:24px;display:flex;align-items:center;gap:20px;flex-wrap:wrap;">
|
||||
<div style="width:80px;height:80px;border-radius:50%;background:linear-gradient(135deg,var(--gold-dark),var(--gold-dim));border:3px solid var(--gold);display:flex;align-items:center;justify-content:center;font-size:2rem;font-weight:900;color:var(--gold-light);flex-shrink:0;" id="p-avatar">--</div>
|
||||
<div style="flex:1;">
|
||||
<div style="font-size:1.5rem;font-weight:900;color:var(--text-main);" id="p-name">--</div>
|
||||
<div style="font-size:0.82rem;color:var(--text-muted);margin-top:2px;" id="p-email">--</div>
|
||||
<div style="display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;" id="p-badges"></div>
|
||||
</div>
|
||||
<button class="btn btn-outline-gold btn-sm" onclick="Toast.show('تعديل الملف قريباً','gold')">✏️ تعديل</button>
|
||||
</div>
|
||||
|
||||
<!-- Info Form -->
|
||||
<div style="max-width:520px;">
|
||||
<div class="form-group">
|
||||
<label class="form-label">اسم المستخدم</label>
|
||||
<input class="form-input" id="pi-username" readonly style="opacity:0.7;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">البريد الإلكتروني</label>
|
||||
<input class="form-input" id="pi-email" readonly style="opacity:0.7;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">الدور</label>
|
||||
<input class="form-input" id="pi-role" readonly style="opacity:0.7;">
|
||||
</div>
|
||||
<button class="btn btn-gold" onclick="Toast.show('حفظ التغييرات قريباً مع Firebase','gold')">💾 حفظ التغييرات</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Tab -->
|
||||
<div class="inner-panel" data-inner-panel="p-stats">
|
||||
<div class="inner-content">
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:14px;margin-bottom:24px;">
|
||||
${[
|
||||
{icon:'🎮',label:'مباريات اللعب',val:'342',color:'var(--gold)'},
|
||||
{icon:'🏆',label:'انتصارات',val:'198',color:'#4ade80'},
|
||||
{icon:'💔',label:'خسائر',val:'144',color:'#f87171'},
|
||||
{icon:'⭐',label:'نسبة الفوز',val:'57%',color:'var(--gold)'},
|
||||
{icon:'🔥',label:'أعلى انتصارات',val:'12',color:'#fb923c'},
|
||||
{icon:'⏱️',label:'ساعات اللعب',val:'89',color:'#a78bfa'},
|
||||
].map(s=>`
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">${s.icon}</div>
|
||||
<div class="stat-value" style="color:${s.color};">${s.val}</div>
|
||||
<div class="stat-label">${s.label}</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Currency Tab -->
|
||||
<div class="inner-panel" data-inner-panel="p-currency">
|
||||
<div class="inner-content">
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;max-width:520px;margin-bottom:24px;">
|
||||
<!-- Gold -->
|
||||
<div style="background:linear-gradient(135deg,rgba(212,160,23,0.12),rgba(122,92,12,0.07));border:1px solid var(--border-gold);border-radius:14px;padding:22px;text-align:center;">
|
||||
<div style="font-size:2.5rem;margin-bottom:6px;">🪙</div>
|
||||
<div style="font-size:2rem;font-weight:900;" class="gold-text" id="pc-gold">0</div>
|
||||
<div style="font-size:0.8rem;color:var(--text-muted);margin:6px 0 14px;">ذهب مدفوع</div>
|
||||
<button class="btn btn-gold btn-sm" style="width:100%;justify-content:center;" onclick="openShop()">شحن الذهب ➕</button>
|
||||
</div>
|
||||
<!-- Silver -->
|
||||
<div style="background:rgba(176,184,200,0.07);border:1px solid rgba(176,184,200,0.2);border-radius:14px;padding:22px;text-align:center;">
|
||||
<div style="font-size:2.5rem;margin-bottom:6px;">🔘</div>
|
||||
<div style="font-size:2rem;font-weight:900;color:var(--silver-light);" id="pc-silver">0</div>
|
||||
<div style="font-size:0.8rem;color:var(--text-muted);margin:6px 0 14px;">فضة مجانية</div>
|
||||
<button class="btn btn-ghost btn-sm" style="width:100%;justify-content:center;" onclick="Toast.show('احصل على الفضة من خلال الألعاب والأنشطة','gold')">كيف أحصل عليها؟</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:rgba(212,160,23,0.05);border:1px solid rgba(212,160,23,0.15);border-radius:12px;padding:16px;font-size:0.82rem;color:var(--text-muted);max-width:520px;">
|
||||
<div style="font-weight:800;color:var(--gold-mid);margin-bottom:8px;">💡 كيف يعمل نظام العملات؟</div>
|
||||
<ul style="space-y:6px;padding-right:16px;line-height:2;">
|
||||
<li>🪙 <strong style="color:var(--text-main);">الذهب</strong> — عملة مدفوعة تُستخدم لشراء عناصر حصرية من المتجر</li>
|
||||
<li>🔘 <strong style="color:var(--text-main);">الفضة</strong> — مجانية تُكسب من الألعاب والأنشطة والمحطات</li>
|
||||
<li>⭐ <strong style="color:var(--text-main);">النقاط الشهرية</strong> — تتراكم طوال الشهر وتُحدّد جوائزك في القطار</li>
|
||||
<li>🚂 <strong style="color:var(--text-main);">تذكرة VIP</strong> — تُضاعف جوائز المحطات وتفتح محطات حصرية</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Security Tab -->
|
||||
<div class="inner-panel" data-inner-panel="p-security">
|
||||
<div class="inner-content" style="max-width:480px;">
|
||||
<div class="form-group">
|
||||
<label class="form-label">كلمة المرور الحالية</label>
|
||||
<input type="password" class="form-input" placeholder="••••••••">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">كلمة المرور الجديدة</label>
|
||||
<input type="password" class="form-input" placeholder="••••••••">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">تأكيد كلمة المرور الجديدة</label>
|
||||
<input type="password" class="form-input" placeholder="••••••••">
|
||||
</div>
|
||||
<button class="btn btn-gold" onclick="Toast.show('تغيير كلمة المرور سيتم ربطه بـ Firebase','gold')">🔒 تغيير كلمة المرور</button>
|
||||
<div class="divider divider-gold" style="margin:24px 0;"></div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px;background:rgba(239,68,68,0.06);border:1px solid rgba(239,68,68,0.2);border-radius:12px;">
|
||||
<div>
|
||||
<div style="font-weight:700;color:#f87171;font-size:0.9rem;">تسجيل الخروج من كل الأجهزة</div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted);margin-top:2px;">إنهاء جميع الجلسات النشطة</div>
|
||||
</div>
|
||||
<button class="btn btn-sm" style="background:rgba(239,68,68,0.1);border:1px solid rgba(239,68,68,0.3);color:#f87171;" onclick="Auth.logout()">خروج كامل</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="static/script.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const user = Auth.getSession();
|
||||
if (!user) return;
|
||||
const init = user.username.substring(0,2).toUpperCase();
|
||||
document.getElementById('p-avatar').textContent = init;
|
||||
document.getElementById('p-name').textContent = user.username;
|
||||
document.getElementById('p-email').textContent = user.email;
|
||||
document.getElementById('pi-username').value = user.username;
|
||||
document.getElementById('pi-email').value = user.email;
|
||||
document.getElementById('pi-role').value = user.role === 'admin' ? 'مدير' : 'مستخدم';
|
||||
document.getElementById('pc-gold').textContent = (user.gold||0).toLocaleString('ar');
|
||||
document.getElementById('pc-silver').textContent = (user.silver||0).toLocaleString('ar');
|
||||
const badgesEl = document.getElementById('p-badges');
|
||||
if (user.vip) badgesEl.innerHTML += `<span class="vip-badge">✨ VIP</span>`;
|
||||
if (user.role==='admin') badgesEl.innerHTML += `<span class="badge badge-gold">⚙️ مدير</span>`;
|
||||
badgesEl.innerHTML += `<span class="badge badge-green">🎮 لاعب نشط</span>`;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
17
app/public/register.html
Normal file
17
app/public/register.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GAMEHUS — إنشاء حساب</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-page="register">
|
||||
<script src="static/script.js"></script>
|
||||
<script>
|
||||
// redirect to login.html and open register tab
|
||||
window.location.replace('login.html#register');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
84
app/public/rooms.html
Normal file
84
app/public/rooms.html
Normal file
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>الغرف - GAMEHUS</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="nav-bar fixed top-0 left-0 right-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 flex items-center justify-between h-16">
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="index.html" class="flex items-center gap-2 no-underline"><div class="logo-icon">🎱</div><span class="logo-text">GAMEHUS</span></a>
|
||||
<div class="hidden md:flex items-center gap-1 ml-6"><a href="index.html" class="nav-link">الرئيسية</a><a href="games.html" class="nav-link">الألعاب</a><a href="top.html" class="nav-link">المتصدرون</a><a href="chat.html" class="nav-link">الدردشة</a></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2"><div class="online-badge"><span class="online-dot"></span><span id="online-count">8,432</span> متصل</div><a href="login.html" class="btn-outline-sm">دخول</a><a href="register.html" class="btn-primary-sm">تسجيل</a><button class="md:hidden mobile-toggle p-2"><svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path></svg></button></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="mobile-menu" class="mobile-menu"><a href="index.html" class="block nav-link">الرئيسية</a><a href="games.html" class="block nav-link">الألعاب</a><a href="top.html" class="block nav-link">المتصدرون</a><a href="chat.html" class="block nav-link">الدردشة</a></div>
|
||||
|
||||
<div id="main-content" style="padding-top:64px;"></div>
|
||||
|
||||
<footer class="footer mt-16">
|
||||
<div class="max-w-7xl mx-auto px-4 py-12">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
<div><div class="flex items-center gap-2 mb-4"><span class="text-2xl">🎱</span><span class="text-xl font-bold text-white">GAMEHUS</span></div><p class="text-gray-400 text-sm">العب بلياردو وشطرنج مجانًا مع لاعبين من حول العالم.</p></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">الألعاب</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="games.html">8-Ball Pool</a></li><li><a href="games.html">9-Ball Pool</a></li><li><a href="games.html">الشطرنج</a></li></ul></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">المجتمع</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="top.html">المتصدرون</a></li><li><a href="chat.html">الدردشة</a></li><li><a href="tournaments.html">البطولات</a></li></ul></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">الحساب</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="register.html">إنشاء حساب</a></li><li><a href="login.html">تسجيل الدخول</a></li><li><a href="profile.html">الملف الشخصي</a></li></ul></div>
|
||||
</div>
|
||||
<div class="border-t border-gray-800 mt-8 pt-6 text-center text-gray-500 text-sm">© 2026 GAMEHUS - جميع الحقوق محفوظة</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const games = {
|
||||
"billiards-8ball": { name: "8-Ball Pool", icon: "🎱" },
|
||||
"billiards-9ball": { name: "9-Ball Pool", icon: "🎱" },
|
||||
"billiards-snooker": { name: "Snooker", icon: "🎯" },
|
||||
"chess-classic": { name: "Classic Chess", icon: "♟️" },
|
||||
"chess-rapid": { name: "Rapid Chess", icon: "⏱️" },
|
||||
"checkers": { name: "Checkers", icon: "🔴" }
|
||||
};
|
||||
const id = new URLSearchParams(location.search).get("gameId") || "billiards-8ball";
|
||||
const game = games[id] || games["billiards-8ball"];
|
||||
const rooms = Array.from({ length: 9 }, (_, i) => ({
|
||||
id: 1001 + i * 37,
|
||||
name: `غرفة ${["الأبطال", "النخبة", "المبتدئين", "المحترفين", "السريعة", "الليلية", "العرب", "الخليج", "التحدي"][i]}`,
|
||||
host: ["ProShooter99", "PoolKing_X", "CueTigerz", "BallMaster", "NightHunter", "EagleEye", "SpinMaster", "DeepShot", "SilentStrike"][i],
|
||||
players: i % 3 === 0 ? "2/2" : "1/2",
|
||||
open: i % 3 !== 0,
|
||||
level: ["مبتدئ", "متوسط", "متقدم", "محترف"][i % 4]
|
||||
}));
|
||||
document.title = `غرف ${game.name} - GAMEHUS`;
|
||||
document.getElementById("main-content").innerHTML = `
|
||||
<div class="max-w-6xl mx-auto px-4 py-12">
|
||||
<div class="flex items-center gap-4 mb-8 flex-wrap">
|
||||
<a href="game-details.html?id=${id}" style="color:#6b7280;font-size:0.9rem;">← ${game.name}</a>
|
||||
<span style="color:#4b5563;">/</span>
|
||||
<div style="display:flex;align-items:center;gap:8px;"><span style="font-size:1.5rem;">${game.icon}</span><h1 style="font-size:1.5rem;font-weight:800;color:#fff;">غرف ${game.name}</h1></div>
|
||||
<div style="margin-right:auto;"><span style="background:rgba(0,200,81,0.1);border:1px solid rgba(0,200,81,0.3);color:#4ade80;padding:4px 12px;border-radius:20px;font-size:0.8rem;">${rooms.filter(r => r.open).length} غرفة متاحة</span></div>
|
||||
</div>
|
||||
<div class="flex gap-3 mb-6 flex-wrap">
|
||||
<a href="register.html" class="btn-primary text-sm py-2 px-5">+ إنشاء غرفة جديدة</a>
|
||||
<button class="btn-outline-sm">كل المستويات</button>
|
||||
<button class="btn-outline-sm">بدون رهان</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
${rooms.map(r => `
|
||||
<div class="card" style="padding:16px;">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;"><div><div style="font-weight:700;color:#fff;font-size:0.95rem;">${r.name}</div><div style="font-size:0.75rem;color:#6b7280;margin-top:2px;">#${r.id}</div></div><span style="font-size:0.75rem;font-weight:700;padding:3px 10px;border-radius:20px;background:${r.open ? "rgba(34,197,94,0.15)" : "rgba(239,68,68,0.15)"};color:${r.open ? "#22c55e" : "#ef4444"};">${r.open ? "انتظار" : "مكتملة"}</span></div>
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;"><div style="width:28px;height:28px;border-radius:50%;background:linear-gradient(135deg,#00c851,#0070f3);display:flex;align-items:center;justify-content:center;font-size:0.65rem;font-weight:700;flex-shrink:0;">${r.host.substring(0,2).toUpperCase()}</div><div><div style="font-size:0.8rem;font-weight:600;color:#d1d5db;">${r.host}</div><div style="font-size:0.7rem;color:#6b7280;">المضيف</div></div></div>
|
||||
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px;"><span style="font-size:0.72rem;padding:3px 8px;border-radius:20px;background:rgba(255,255,255,0.06);color:#9ca3af;">👥 ${r.players}</span><span style="font-size:0.72rem;padding:3px 8px;border-radius:20px;background:rgba(255,255,255,0.06);color:#9ca3af;">⚡ ${r.level}</span></div>
|
||||
${r.open ? `<a href="register.html" class="btn-primary w-full text-center text-sm py-2 block">▶ انضم للغرفة</a>` : `<button disabled style="width:100%;padding:8px;border-radius:8px;background:rgba(255,255,255,0.05);color:#4b5563;font-size:0.85rem;border:1px solid rgba(255,255,255,0.05);">🔒 الغرفة ممتلئة</button>`}
|
||||
</div>`).join("")}
|
||||
</div>
|
||||
</div>`;
|
||||
</script>
|
||||
<script src="static/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
382
app/public/static/script.js
Normal file
382
app/public/static/script.js
Normal file
@ -0,0 +1,382 @@
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
GAMEHUS — Core Engine
|
||||
Auth Guard · Tab System · Wallet · Toast · Counters
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
'use strict';
|
||||
|
||||
// ─── Fake Auth Store (will be replaced by Firebase Auth later) ───────────────
|
||||
const TEST_USERS = [
|
||||
{ email: 'admin@gamehus.com', password: 'admin123', username: 'Admin', role: 'admin', vip: true, gold: 15000, silver: 8400 },
|
||||
{ email: 'vip@gamehus.com', password: 'vip123', username: 'VIP_Player', role: 'user', vip: true, gold: 5200, silver: 3100 },
|
||||
{ email: 'test@gamehus.com', password: 'test123', username: 'TestUser', role: 'user', vip: false, gold: 0, silver: 1200 },
|
||||
{ email: 'player1@gamehus.com', password: 'play123', username: 'ProShooter', role: 'user', vip: false, gold: 200, silver: 4500 },
|
||||
{ email: 'player2@gamehus.com', password: 'play456', username: 'ChessMaster', role: 'user', vip: true, gold: 800, silver: 6700 },
|
||||
];
|
||||
|
||||
const AUTH_KEY = 'gh_session';
|
||||
const SESSION_TTL = 24 * 60 * 60 * 1000; // 24h
|
||||
|
||||
// ─── AUTH MODULE ─────────────────────────────────────────────────────────────
|
||||
const Auth = (() => {
|
||||
function getSession() {
|
||||
try {
|
||||
const raw = sessionStorage.getItem(AUTH_KEY) || localStorage.getItem(AUTH_KEY);
|
||||
if (!raw) return null;
|
||||
const data = JSON.parse(raw);
|
||||
if (Date.now() - data.ts > SESSION_TTL) { clearSession(); return null; }
|
||||
return data.user;
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
function saveSession(user, remember = false) {
|
||||
const payload = JSON.stringify({ user, ts: Date.now() });
|
||||
sessionStorage.setItem(AUTH_KEY, payload);
|
||||
if (remember) localStorage.setItem(AUTH_KEY, payload);
|
||||
}
|
||||
|
||||
function clearSession() {
|
||||
sessionStorage.removeItem(AUTH_KEY);
|
||||
localStorage.removeItem(AUTH_KEY);
|
||||
}
|
||||
|
||||
function login(identifier, password, remember = false) {
|
||||
const user = TEST_USERS.find(u =>
|
||||
(u.email === identifier || u.username === identifier) && u.password === password
|
||||
);
|
||||
if (!user) return { ok: false, msg: 'بيانات الدخول غير صحيحة' };
|
||||
const { password: _, ...safeUser } = user;
|
||||
saveSession(safeUser, remember);
|
||||
return { ok: true, user: safeUser };
|
||||
}
|
||||
|
||||
function logout() {
|
||||
clearSession();
|
||||
window.location.href = 'login.html';
|
||||
}
|
||||
|
||||
function requireAuth() {
|
||||
const user = getSession();
|
||||
if (!user) {
|
||||
window.location.replace('login.html');
|
||||
return null;
|
||||
}
|
||||
// reveal page
|
||||
document.querySelectorAll('.auth-guard').forEach(el => el.classList.add('revealed'));
|
||||
return user;
|
||||
}
|
||||
|
||||
return { getSession, saveSession, clearSession, login, logout, requireAuth };
|
||||
})();
|
||||
|
||||
// ─── TOAST MODULE ─────────────────────────────────────────────────────────────
|
||||
const Toast = (() => {
|
||||
let container;
|
||||
function getContainer() {
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.className = 'toast-container';
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
function show(msg, type = 'success', duration = 3000) {
|
||||
const icons = { success: '✅', gold: '🪙', error: '❌', info: 'ℹ️' };
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.innerHTML = `<span>${icons[type] || '💬'}</span><span>${msg}</span>`;
|
||||
getContainer().appendChild(toast);
|
||||
setTimeout(() => { toast.style.opacity = '0'; toast.style.transform = 'translateX(20px)'; toast.style.transition = 'all 0.3s'; setTimeout(() => toast.remove(), 300); }, duration);
|
||||
}
|
||||
return { show };
|
||||
})();
|
||||
|
||||
// ─── TAB SYSTEM ───────────────────────────────────────────────────────────────
|
||||
const TabSystem = (() => {
|
||||
const instances = new Map(); // instanceId -> { tabs, activeId, container }
|
||||
|
||||
function create(containerId, tabs, options = {}) {
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container) return;
|
||||
|
||||
const state = { tabs: [...tabs], activeId: tabs[0]?.id, container, options };
|
||||
instances.set(containerId, state);
|
||||
render(containerId);
|
||||
return { activate: (id) => activate(containerId, id), addTab: (tab) => addTab(containerId, tab), removeTab: (id) => removeTab(containerId, id) };
|
||||
}
|
||||
|
||||
function render(cid) {
|
||||
const state = instances.get(cid);
|
||||
if (!state) return;
|
||||
const { tabs, activeId, container, options } = state;
|
||||
|
||||
// Tab bar
|
||||
let barEl = container.querySelector('.tab-bar');
|
||||
if (!barEl) { barEl = document.createElement('div'); barEl.className = 'tab-bar'; container.prepend(barEl); }
|
||||
|
||||
barEl.innerHTML = tabs.map(tab => `
|
||||
<div class="tab-item ${tab.id === activeId ? 'active' : ''}" data-tid="${tab.id}">
|
||||
${tab.icon ? `<span class="tab-icon">${tab.icon}</span>` : ''}
|
||||
<span class="tab-label">${tab.label}</span>
|
||||
${!tab.pinned ? `<button class="tab-close" data-close="${tab.id}">✕</button>` : ''}
|
||||
</div>
|
||||
`).join('') + (options.addable ? `<button class="tab-add" title="تبويب جديد">+</button>` : '');
|
||||
|
||||
// click events
|
||||
barEl.querySelectorAll('.tab-item').forEach(el => {
|
||||
el.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.tab-close')) return;
|
||||
activate(cid, el.dataset.tid);
|
||||
});
|
||||
});
|
||||
barEl.querySelectorAll('.tab-close').forEach(btn => {
|
||||
btn.addEventListener('click', () => removeTab(cid, btn.dataset.close));
|
||||
});
|
||||
|
||||
// panels
|
||||
let panelsEl = container.querySelector('.tab-panels');
|
||||
if (!panelsEl) { panelsEl = document.createElement('div'); panelsEl.className = 'tab-panels'; container.appendChild(panelsEl); }
|
||||
|
||||
tabs.forEach(tab => {
|
||||
let panel = panelsEl.querySelector(`[data-panel="${tab.id}"]`);
|
||||
if (!panel) {
|
||||
panel = document.createElement('div');
|
||||
panel.className = 'tab-panel animate-in';
|
||||
panel.dataset.panel = tab.id;
|
||||
panel.innerHTML = tab.content || '';
|
||||
panelsEl.appendChild(panel);
|
||||
}
|
||||
panel.classList.toggle('active', tab.id === activeId);
|
||||
});
|
||||
}
|
||||
|
||||
function activate(cid, id) {
|
||||
const state = instances.get(cid);
|
||||
if (!state || !state.tabs.find(t => t.id === id)) return;
|
||||
state.activeId = id;
|
||||
render(cid);
|
||||
state.options.onActivate?.(id);
|
||||
}
|
||||
|
||||
function addTab(cid, tab) {
|
||||
const state = instances.get(cid);
|
||||
if (!state) return;
|
||||
if (!state.tabs.find(t => t.id === tab.id)) state.tabs.push(tab);
|
||||
activate(cid, tab.id);
|
||||
}
|
||||
|
||||
function removeTab(cid, id) {
|
||||
const state = instances.get(cid);
|
||||
if (!state) return;
|
||||
const idx = state.tabs.findIndex(t => t.id === id);
|
||||
if (idx === -1 || state.tabs[idx].pinned) return;
|
||||
state.tabs.splice(idx, 1);
|
||||
if (state.activeId === id) state.activeId = state.tabs[Math.max(0, idx - 1)]?.id;
|
||||
render(cid);
|
||||
}
|
||||
|
||||
return { create, activate, addTab, removeTab };
|
||||
})();
|
||||
|
||||
// ─── INNER TABS (simple, CSS-driven) ────────────────────────────────────────
|
||||
function setupInnerTabs(containerEl) {
|
||||
const tabs = containerEl.querySelectorAll('.inner-tab');
|
||||
const panels = containerEl.querySelectorAll('.inner-panel');
|
||||
tabs.forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
tabs.forEach(t => t.classList.remove('active'));
|
||||
panels.forEach(p => p.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
const target = containerEl.querySelector(`[data-inner-panel="${tab.dataset.innerTab}"]`);
|
||||
if (target) target.classList.add('active');
|
||||
});
|
||||
});
|
||||
if (tabs[0]) tabs[0].click();
|
||||
}
|
||||
|
||||
// ─── TOPBAR BUILDER ─────────────────────────────────────────────────────────
|
||||
function buildTopbar(user) {
|
||||
const bar = document.getElementById('topbar');
|
||||
if (!bar || !user) return;
|
||||
bar.innerHTML = `
|
||||
<div class="topbar-brand">
|
||||
<span class="gem">💎</span>
|
||||
<span class="name gold-text">GAMEHUS</span>
|
||||
</div>
|
||||
<div class="wallet-strip">
|
||||
<div class="wallet-coin wallet-gold" id="wallet-gold" title="ذهب - عملة مدفوعة">
|
||||
🪙 <span id="gold-amount">${(user.gold||0).toLocaleString('ar')}</span>
|
||||
</div>
|
||||
<div class="wallet-coin wallet-silver" id="wallet-silver" title="فضة - عملة مجانية">
|
||||
🔘 <span id="silver-amount">${(user.silver||0).toLocaleString('ar')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="online-badge hide-mobile">
|
||||
<span class="online-dot"></span>
|
||||
<span id="online-count">8,432</span> متصل
|
||||
</div>
|
||||
<div class="topbar-user" id="user-menu-btn">
|
||||
<div class="user-avatar">${(user.username||'?').substring(0,2).toUpperCase()}</div>
|
||||
<div>
|
||||
<div class="user-name">${user.username}</div>
|
||||
${user.vip ? '<div class="user-vip">✨ VIP</div>' : ''}
|
||||
</div>
|
||||
<span style="color:var(--text-muted);font-size:0.75rem;">▾</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// user menu dropdown
|
||||
document.getElementById('user-menu-btn')?.addEventListener('click', () => {
|
||||
const existing = document.getElementById('user-dropdown');
|
||||
if (existing) { existing.remove(); return; }
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.id = 'user-dropdown';
|
||||
dropdown.style.cssText = `position:fixed;top:${65}px;left:16px;background:var(--bg-card);border:1px solid var(--border-gold);border-radius:12px;padding:8px;min-width:180px;z-index:100;box-shadow:var(--glow-gold);animation:fadeIn 0.2s ease;`;
|
||||
dropdown.innerHTML = `
|
||||
<div style="padding:10px 12px 8px;border-bottom:1px solid var(--border-dim);margin-bottom:6px;">
|
||||
<div style="font-weight:800;color:var(--text-main);">${user.username}</div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted);">${user.email}</div>
|
||||
</div>
|
||||
<a href="profile.html" style="display:flex;align-items:center;gap:8px;padding:9px 12px;border-radius:8px;color:var(--text-muted);font-size:0.85rem;transition:all 0.2s;" onmouseover="this.style.background='rgba(255,255,255,0.05)'" onmouseout="this.style.background='transparent'">👤 الملف الشخصي</a>
|
||||
<div style="display:flex;align-items:center;gap:8px;padding:9px 12px;border-radius:8px;color:var(--text-muted);font-size:0.85rem;cursor:pointer;transition:all 0.2s;" onmouseover="this.style.background='rgba(212,160,23,0.07)';this.style.color='var(--gold)'" onmouseout="this.style.background='transparent';this.style.color='var(--text-muted)'" onclick="openShop()">🪙 شحن الذهب</div>
|
||||
<div style="height:1px;background:var(--border-dim);margin:6px 0;"></div>
|
||||
<div style="display:flex;align-items:center;gap:8px;padding:9px 12px;border-radius:8px;color:#f87171;font-size:0.85rem;cursor:pointer;transition:all 0.2s;" onmouseover="this.style.background='rgba(239,68,68,0.08)'" onmouseout="this.style.background='transparent'" onclick="Auth.logout()">🚪 تسجيل الخروج</div>
|
||||
`;
|
||||
document.body.appendChild(dropdown);
|
||||
setTimeout(() => document.addEventListener('click', function handler(e) {
|
||||
if (!dropdown.contains(e.target) && e.target.id !== 'user-menu-btn') { dropdown.remove(); document.removeEventListener('click', handler); }
|
||||
}), 10);
|
||||
});
|
||||
|
||||
// pulse online count
|
||||
const el = document.getElementById('online-count');
|
||||
if (el) {
|
||||
const base = 8432;
|
||||
let tick = 0;
|
||||
setInterval(() => { tick++; el.textContent = (base + Math.round(Math.sin(tick/3)*18)).toLocaleString('ar'); }, 7000);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── SIDEBAR BUILDER ─────────────────────────────────────────────────────────
|
||||
function buildSidebar(user, activePage = '') {
|
||||
const sb = document.getElementById('sidebar');
|
||||
if (!sb) return;
|
||||
|
||||
const items = [
|
||||
{ id: 'dashboard', icon: '🏠', label: 'الرئيسية', href: 'index.html' },
|
||||
{ id: 'games', icon: '🎮', label: 'الألعاب', href: 'games.html' },
|
||||
{ id: 'rooms', icon: '🏠', label: 'الغرف', href: 'rooms.html' },
|
||||
{ id: 'top', icon: '🏆', label: 'المتصدرون', href: 'top.html' },
|
||||
{ id: 'chat', icon: '💬', label: 'الدردشة', href: 'chat.html', badge: '3' },
|
||||
{ divider: true },
|
||||
{ id: 'train', icon: '🚂', label: 'محطات الجوائز', href: 'train.html' },
|
||||
{ id: 'shop', icon: '🛍️', label: 'المتجر', href: 'shop.html' },
|
||||
{ id: 'tournaments',icon:'🥇', label: 'البطولات', href: 'tournaments.html' },
|
||||
{ divider: true },
|
||||
{ id: 'profile', icon: '👤', label: 'الملف الشخصي', href: 'profile.html' },
|
||||
...(user?.role === 'admin' ? [{ id: 'admin', icon: '⚙️', label: 'لوحة الإدارة', href: 'admin.html' }] : []),
|
||||
];
|
||||
|
||||
sb.innerHTML = `
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-label">القائمة الرئيسية</div>
|
||||
${items.map(item => {
|
||||
if (item.divider) return `<div class="sidebar-divider"></div>`;
|
||||
const active = item.id === activePage;
|
||||
return `<a href="${item.href}" class="sidebar-item ${active ? 'active' : ''}">
|
||||
<span class="icon">${item.icon}</span>
|
||||
<span>${item.label}</span>
|
||||
${item.badge ? `<span class="badge-count">${item.badge}</span>` : ''}
|
||||
</a>`;
|
||||
}).join('')}
|
||||
</div>
|
||||
<div style="padding:16px 12px;margin-top:auto;">
|
||||
<div style="background:linear-gradient(135deg,rgba(212,160,23,0.12),rgba(122,92,12,0.08));border:1px solid var(--border-gold);border-radius:12px;padding:14px;">
|
||||
${user?.vip ? `
|
||||
<div class="vip-badge" style="margin-bottom:8px;">✨ VIP مفعّل</div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted);">تذكرة القطار الذهبي نشطة</div>
|
||||
` : `
|
||||
<div style="font-size:0.82rem;font-weight:700;color:var(--gold);margin-bottom:6px;">🚂 ترقية إلى VIP</div>
|
||||
<div style="font-size:0.73rem;color:var(--text-muted);margin-bottom:10px;">جوائز أكبر في كل المحطات</div>
|
||||
<a href="shop.html" class="btn-gold btn btn-sm" style="width:100%;justify-content:center;display:flex;">اشترِ التذكرة</a>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// ─── COUNTERS ────────────────────────────────────────────────────────────────
|
||||
function animateCounters() {
|
||||
document.querySelectorAll('[data-count]').forEach(el => {
|
||||
const target = parseInt(el.getAttribute('data-count') || '0', 10);
|
||||
if (!target) return;
|
||||
let cur = 0; const inc = target / 60;
|
||||
const t = setInterval(() => {
|
||||
cur += inc;
|
||||
if (cur >= target) { cur = target; clearInterval(t); }
|
||||
el.textContent = Math.floor(cur).toLocaleString('ar');
|
||||
}, 16);
|
||||
});
|
||||
}
|
||||
|
||||
// ─── SHOP MODAL (quick open) ──────────────────────────────────────────────────
|
||||
function openShop() {
|
||||
const existing = document.getElementById('shop-modal');
|
||||
if (existing) existing.remove();
|
||||
const modal = document.createElement('div');
|
||||
modal.id = 'shop-modal';
|
||||
modal.className = 'modal-overlay';
|
||||
modal.innerHTML = `
|
||||
<div class="modal-box" style="max-width:480px;">
|
||||
<button onclick="document.getElementById('shop-modal').remove()" style="position:absolute;top:14px;left:14px;background:none;border:none;color:var(--text-muted);font-size:1.2rem;cursor:pointer;">✕</button>
|
||||
<div style="text-align:center;margin-bottom:24px;">
|
||||
<div style="font-size:2.5rem;margin-bottom:8px;">🪙</div>
|
||||
<h2 class="gold-text" style="font-size:1.4rem;font-weight:900;">شحن الذهب</h2>
|
||||
<p style="color:var(--text-muted);font-size:0.85rem;margin-top:4px;">الذهب عملة مدفوعة تُستخدم لشراء العناصر الحصرية</p>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:20px;">
|
||||
${[
|
||||
{ gold: 500, price: '4.99$', label: 'مبتدئ', bonus: '' },
|
||||
{ gold: 1200, price: '9.99$', label: 'شائع', bonus: '+100 مجاناً' },
|
||||
{ gold: 2800, price: '19.99$', label: 'محترف', bonus: '+300 مجاناً' },
|
||||
{ gold: 6500, price: '39.99$', label: 'احترافي', bonus: '+700 مجاناً' },
|
||||
].map(p => `
|
||||
<div style="background:var(--bg-surface);border:1px solid var(--border-gold);border-radius:12px;padding:16px;text-align:center;cursor:pointer;transition:all 0.2s;" onmouseover="this.style.boxShadow='var(--glow-gold)'" onmouseout="this.style.boxShadow='none'" onclick="Toast.show('قريباً! سيتم ربط بوابة الدفع.','gold');document.getElementById('shop-modal').remove()">
|
||||
<div style="font-size:1.5rem;margin-bottom:4px;">🪙</div>
|
||||
<div style="font-size:1.1rem;font-weight:900;color:var(--gold);">${p.gold.toLocaleString()}</div>
|
||||
<div style="font-size:0.7rem;color:var(--text-muted);">${p.label}</div>
|
||||
${p.bonus ? `<div style="font-size:0.65rem;color:var(--green);margin-top:2px;">${p.bonus}</div>` : ''}
|
||||
<div style="margin-top:10px;font-size:0.88rem;font-weight:800;color:var(--text-main);">${p.price}</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div style="background:rgba(212,160,23,0.06);border:1px solid rgba(212,160,23,0.15);border-radius:10px;padding:12px;font-size:0.78rem;color:var(--text-muted);text-align:center;">
|
||||
🔒 جميع المعاملات آمنة ومشفرة — سيتم ربط بوابة الدفع قريباً
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
modal.addEventListener('click', e => { if (e.target === modal) modal.remove(); });
|
||||
document.body.appendChild(modal);
|
||||
}
|
||||
|
||||
// ─── PAGE INIT ────────────────────────────────────────────────────────────────
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const page = document.body.dataset.page || '';
|
||||
const isAuthPage = ['login', 'register'].includes(page);
|
||||
|
||||
if (!isAuthPage) {
|
||||
const user = Auth.requireAuth();
|
||||
if (!user) return;
|
||||
buildTopbar(user);
|
||||
buildSidebar(user, page);
|
||||
animateCounters();
|
||||
// setup any inner-tab containers on the page
|
||||
document.querySelectorAll('[data-inner-tabs]').forEach(el => setupInnerTabs(el));
|
||||
}
|
||||
});
|
||||
|
||||
// expose globally
|
||||
window.Auth = Auth;
|
||||
window.Toast = Toast;
|
||||
window.TabSystem = TabSystem;
|
||||
window.openShop = openShop;
|
||||
window.setupInnerTabs = setupInnerTabs;
|
||||
815
app/public/static/style.css
Normal file
815
app/public/static/style.css
Normal file
@ -0,0 +1,815 @@
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
GAMEHUS — Golden Luxury Theme
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800;900&display=swap');
|
||||
|
||||
:root {
|
||||
/* Gold Palette */
|
||||
--gold-light: #FFE566;
|
||||
--gold: #F0C040;
|
||||
--gold-mid: #D4A017;
|
||||
--gold-dark: #A07810;
|
||||
--gold-dim: #7A5C0C;
|
||||
|
||||
/* Silver Palette */
|
||||
--silver-light: #E8E8F0;
|
||||
--silver: #B0B8C8;
|
||||
--silver-dark: #6A7488;
|
||||
|
||||
/* Background Layers */
|
||||
--bg-base: #080A10;
|
||||
--bg-surface: #0E1118;
|
||||
--bg-card: #13171F;
|
||||
--bg-card2: #181D28;
|
||||
--bg-overlay: rgba(8,10,16,0.96);
|
||||
|
||||
/* Borders & Glow */
|
||||
--border-gold: rgba(212,160,23,0.35);
|
||||
--border-dim: rgba(255,255,255,0.07);
|
||||
--glow-gold: 0 0 24px rgba(212,160,23,0.45);
|
||||
--glow-gold-lg: 0 0 50px rgba(212,160,23,0.3);
|
||||
--glow-soft: 0 4px 30px rgba(0,0,0,0.6);
|
||||
|
||||
/* Text */
|
||||
--text-main: #E8E0D0;
|
||||
--text-muted: #6A7080;
|
||||
--text-faint: #3A404C;
|
||||
|
||||
/* Status */
|
||||
--green: #22C55E;
|
||||
--red: #EF4444;
|
||||
--blue: #3B82F6;
|
||||
|
||||
/* Sidebar */
|
||||
--sidebar-w: 240px;
|
||||
--topbar-h: 60px;
|
||||
--tab-h: 44px;
|
||||
}
|
||||
|
||||
/* ── Reset & Base ─────────────────────────────────────────── */
|
||||
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow: hidden; /* NO page scroll — only panels scroll */
|
||||
font-family: 'Cairo', 'Segoe UI', Tahoma, sans-serif;
|
||||
background: var(--bg-base);
|
||||
color: var(--text-main);
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
/* allow scroll only on .scrollable panels (docs pages etc.) */
|
||||
.scrollable { overflow-y: auto !important; }
|
||||
|
||||
a { text-decoration: none; color: inherit; }
|
||||
|
||||
/* ── Gold Gradient Utility ───────────────────────────────── */
|
||||
.gold-text {
|
||||
background: linear-gradient(135deg, var(--gold-light) 0%, var(--gold) 40%, var(--gold-mid) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
.gold-border { border-color: var(--border-gold) !important; }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
AUTH SCREEN (login.html / register.html)
|
||||
full-viewport, no scroll
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.auth-screen {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 50% 0%, rgba(212,160,23,0.12) 0%, transparent 65%),
|
||||
radial-gradient(ellipse 60% 40% at 80% 100%, rgba(212,160,23,0.06) 0%, transparent 60%),
|
||||
var(--bg-base);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* animated gold particles */
|
||||
.auth-screen::before {
|
||||
content: '';
|
||||
position: absolute; inset: 0;
|
||||
background-image:
|
||||
radial-gradient(circle 1px at 20% 30%, rgba(212,160,23,0.4) 0%, transparent 100%),
|
||||
radial-gradient(circle 1px at 75% 20%, rgba(212,160,23,0.3) 0%, transparent 100%),
|
||||
radial-gradient(circle 1px at 50% 70%, rgba(212,160,23,0.2) 0%, transparent 100%),
|
||||
radial-gradient(circle 1px at 85% 65%, rgba(212,160,23,0.25) 0%, transparent 100%);
|
||||
animation: particleDrift 12s ease-in-out infinite alternate;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes particleDrift {
|
||||
from { transform: translateY(0) scale(1); }
|
||||
to { transform: translateY(-20px) scale(1.02); }
|
||||
}
|
||||
|
||||
.auth-card {
|
||||
width: 100%;
|
||||
max-width: 440px;
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-gold);
|
||||
border-radius: 20px;
|
||||
padding: 48px 40px;
|
||||
box-shadow: var(--glow-gold), var(--glow-soft);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.auth-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 50%; transform: translateX(-50%);
|
||||
width: 60%; height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--gold), transparent);
|
||||
}
|
||||
|
||||
.auth-logo {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.auth-logo .logo-gem {
|
||||
font-size: 3.5rem;
|
||||
filter: drop-shadow(0 0 16px rgba(212,160,23,0.7));
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.auth-logo .brand {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 900;
|
||||
letter-spacing: 4px;
|
||||
}
|
||||
|
||||
.auth-divider {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
margin: 20px 0;
|
||||
color: var(--text-muted); font-size: 0.82rem;
|
||||
}
|
||||
.auth-divider::before, .auth-divider::after {
|
||||
content: ''; flex: 1; height: 1px;
|
||||
background: var(--border-dim);
|
||||
}
|
||||
|
||||
/* Tab switcher inside auth card */
|
||||
.auth-tabs {
|
||||
display: flex;
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-dim);
|
||||
border-radius: 10px;
|
||||
padding: 4px;
|
||||
margin-bottom: 28px;
|
||||
gap: 4px;
|
||||
}
|
||||
.auth-tab {
|
||||
flex: 1; padding: 8px; border-radius: 7px;
|
||||
font-size: 0.9rem; font-weight: 700;
|
||||
cursor: pointer; border: none;
|
||||
background: transparent; color: var(--text-muted);
|
||||
transition: all 0.25s;
|
||||
}
|
||||
.auth-tab.active {
|
||||
background: linear-gradient(135deg, var(--gold-dim), var(--gold-dark));
|
||||
color: var(--gold-light);
|
||||
box-shadow: 0 2px 8px rgba(212,160,23,0.3);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
APP SHELL (all pages after login)
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.app-shell {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Top Bar ─────────────────────────────────────────────── */
|
||||
.topbar {
|
||||
height: var(--topbar-h);
|
||||
background: var(--bg-surface);
|
||||
border-bottom: 1px solid var(--border-gold);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
gap: 16px;
|
||||
flex-shrink: 0;
|
||||
z-index: 50;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.topbar::after {
|
||||
content: '';
|
||||
position: absolute; bottom: -1px; left: 0; right: 0;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent 0%, var(--gold) 30%, var(--gold-light) 50%, var(--gold) 70%, transparent 100%);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.topbar-brand {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.topbar-brand .gem { font-size: 1.6rem; filter: drop-shadow(0 0 8px rgba(212,160,23,0.6)); }
|
||||
.topbar-brand .name {
|
||||
font-size: 1.2rem; font-weight: 900; letter-spacing: 3px;
|
||||
}
|
||||
|
||||
/* wallet strip */
|
||||
.wallet-strip {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
margin-right: auto;
|
||||
}
|
||||
.wallet-coin {
|
||||
display: flex; align-items: center; gap: 5px;
|
||||
padding: 5px 14px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.82rem; font-weight: 800;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.wallet-gold {
|
||||
background: rgba(212,160,23,0.12);
|
||||
border: 1px solid rgba(212,160,23,0.4);
|
||||
color: var(--gold);
|
||||
}
|
||||
.wallet-gold:hover { background: rgba(212,160,23,0.2); box-shadow: var(--glow-gold); }
|
||||
.wallet-silver {
|
||||
background: rgba(176,184,200,0.1);
|
||||
border: 1px solid rgba(176,184,200,0.25);
|
||||
color: var(--silver-light);
|
||||
}
|
||||
.wallet-silver:hover { background: rgba(176,184,200,0.18); }
|
||||
|
||||
/* user menu */
|
||||
.topbar-user {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
cursor: pointer; padding: 4px 10px; border-radius: 10px;
|
||||
border: 1px solid var(--border-dim);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.topbar-user:hover { border-color: var(--border-gold); background: rgba(212,160,23,0.06); }
|
||||
.user-avatar {
|
||||
width: 32px; height: 32px; border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--gold-dark), var(--gold-dim));
|
||||
border: 2px solid var(--gold-mid);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 0.75rem; font-weight: 800; color: var(--gold-light);
|
||||
}
|
||||
.user-name { font-size: 0.85rem; font-weight: 700; }
|
||||
.user-vip {
|
||||
font-size: 0.65rem; background: linear-gradient(135deg, var(--gold), var(--gold-mid));
|
||||
color: #000; padding: 1px 6px; border-radius: 10px; font-weight: 800;
|
||||
}
|
||||
|
||||
/* online badge */
|
||||
.online-badge {
|
||||
display: flex; align-items: center; gap: 5px;
|
||||
background: rgba(34,197,94,0.08);
|
||||
border: 1px solid rgba(34,197,94,0.2);
|
||||
padding: 4px 12px; border-radius: 20px;
|
||||
font-size: 0.78rem; color: var(--green);
|
||||
}
|
||||
.online-dot {
|
||||
width: 7px; height: 7px; border-radius: 50%;
|
||||
background: var(--green); animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
/* ── Body Row (sidebar + content) ───────────────────────── */
|
||||
.app-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Sidebar ─────────────────────────────────────────────── */
|
||||
.sidebar {
|
||||
width: var(--sidebar-w);
|
||||
background: var(--bg-surface);
|
||||
border-left: 1px solid var(--border-gold);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.sidebar-section { padding: 16px 12px 8px; }
|
||||
.sidebar-label {
|
||||
font-size: 0.68rem; font-weight: 800; letter-spacing: 2px;
|
||||
color: var(--gold-dim); text-transform: uppercase;
|
||||
padding: 0 8px; margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.sidebar-item {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 9px 12px; border-radius: 10px;
|
||||
font-size: 0.88rem; font-weight: 600;
|
||||
color: var(--text-muted); cursor: pointer;
|
||||
transition: all 0.2s; border: 1px solid transparent;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.sidebar-item:hover {
|
||||
color: var(--text-main);
|
||||
background: rgba(255,255,255,0.04);
|
||||
}
|
||||
.sidebar-item.active {
|
||||
background: linear-gradient(135deg, rgba(212,160,23,0.15), rgba(212,160,23,0.07));
|
||||
border-color: var(--border-gold);
|
||||
color: var(--gold);
|
||||
}
|
||||
.sidebar-item .icon { width: 20px; text-align: center; font-size: 1rem; flex-shrink: 0; }
|
||||
.sidebar-item .badge-count {
|
||||
margin-right: auto;
|
||||
background: var(--gold-dim); color: var(--gold-light);
|
||||
font-size: 0.65rem; font-weight: 800;
|
||||
padding: 1px 6px; border-radius: 10px;
|
||||
}
|
||||
|
||||
.sidebar-divider {
|
||||
height: 1px; margin: 8px 16px;
|
||||
background: linear-gradient(90deg, transparent, var(--border-dim), transparent);
|
||||
}
|
||||
|
||||
/* ── Main Content Area ──────────────────────────────────── */
|
||||
.content-area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background: var(--bg-base);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
DYNAMIC TAB SYSTEM
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.tab-bar {
|
||||
height: var(--tab-h);
|
||||
background: var(--bg-surface);
|
||||
border-bottom: 1px solid var(--border-gold);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 0 12px;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.tab-bar::-webkit-scrollbar { height: 3px; }
|
||||
.tab-bar::-webkit-scrollbar-thumb { background: var(--gold-dim); border-radius: 2px; }
|
||||
|
||||
.tab-item {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
font-size: 0.82rem; font-weight: 700;
|
||||
color: var(--text-muted); cursor: pointer;
|
||||
white-space: nowrap;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-bottom: none;
|
||||
transition: all 0.2s;
|
||||
position: relative;
|
||||
bottom: -1px;
|
||||
}
|
||||
.tab-item:hover { color: var(--text-main); background: rgba(255,255,255,0.04); }
|
||||
.tab-item.active {
|
||||
background: var(--bg-base);
|
||||
border-color: var(--border-gold);
|
||||
border-bottom-color: var(--bg-base);
|
||||
color: var(--gold);
|
||||
}
|
||||
.tab-item .tab-icon { font-size: 0.9rem; }
|
||||
.tab-close {
|
||||
width: 16px; height: 16px; border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 0.65rem; opacity: 0;
|
||||
background: rgba(255,255,255,0.1);
|
||||
transition: all 0.15s; cursor: pointer; border: none; color: inherit;
|
||||
}
|
||||
.tab-item:hover .tab-close { opacity: 1; }
|
||||
.tab-close:hover { background: rgba(239,68,68,0.3); color: #fca5a5; }
|
||||
.tab-add {
|
||||
padding: 6px 10px; border-radius: 8px 8px 0 0;
|
||||
color: var(--text-muted); cursor: pointer; font-size: 1.1rem;
|
||||
background: transparent; border: none;
|
||||
transition: all 0.2s; position: relative; bottom: -1px;
|
||||
}
|
||||
.tab-add:hover { color: var(--gold); }
|
||||
|
||||
/* Tab Panel */
|
||||
.tab-panels { flex: 1; overflow: hidden; position: relative; }
|
||||
.tab-panel {
|
||||
position: absolute; inset: 0;
|
||||
opacity: 0; pointer-events: none;
|
||||
transition: opacity 0.2s;
|
||||
overflow: hidden;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
.tab-panel.active {
|
||||
opacity: 1; pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Inner tab bar (nested tabs) */
|
||||
.inner-tab-bar {
|
||||
display: flex; gap: 0;
|
||||
background: var(--bg-card);
|
||||
border-bottom: 1px solid var(--border-dim);
|
||||
padding: 0 16px;
|
||||
flex-shrink: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.inner-tab-bar::-webkit-scrollbar { display: none; }
|
||||
.inner-tab {
|
||||
padding: 10px 18px;
|
||||
font-size: 0.82rem; font-weight: 700;
|
||||
color: var(--text-muted); cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all 0.2s; white-space: nowrap;
|
||||
background: none; border-top: none; border-left: none; border-right: none;
|
||||
}
|
||||
.inner-tab:hover { color: var(--text-main); }
|
||||
.inner-tab.active { color: var(--gold); border-bottom-color: var(--gold); }
|
||||
|
||||
.inner-panel { display: none; flex: 1; overflow: hidden; }
|
||||
.inner-panel.active { display: flex; flex-direction: column; }
|
||||
.inner-content { flex: 1; overflow-y: auto; padding: 20px; }
|
||||
|
||||
/* ── Panel base ─────────────────────────────────────────── */
|
||||
.panel { flex: 1; overflow-y: auto; padding: 24px; }
|
||||
.panel-header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.panel-title {
|
||||
font-size: 1.4rem; font-weight: 900; color: var(--text-main);
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
CARDS
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-dim);
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.card:hover {
|
||||
border-color: var(--border-gold);
|
||||
box-shadow: var(--glow-gold), 0 8px 30px rgba(0,0,0,0.4);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
.card-gold {
|
||||
background: linear-gradient(135deg, rgba(212,160,23,0.1) 0%, rgba(122,92,12,0.08) 100%);
|
||||
border-color: var(--border-gold);
|
||||
}
|
||||
|
||||
/* stat card */
|
||||
.stat-card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-dim);
|
||||
border-radius: 14px; padding: 20px;
|
||||
display: flex; flex-direction: column; gap: 8px;
|
||||
transition: all 0.3s; cursor: default;
|
||||
}
|
||||
.stat-card:hover { border-color: var(--border-gold); box-shadow: var(--glow-gold); }
|
||||
.stat-icon { font-size: 1.6rem; }
|
||||
.stat-value { font-size: 1.6rem; font-weight: 900; }
|
||||
.stat-label { font-size: 0.78rem; color: var(--text-muted); }
|
||||
|
||||
/* game card */
|
||||
.game-card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-dim);
|
||||
border-radius: 14px; overflow: hidden;
|
||||
transition: all 0.3s; cursor: pointer;
|
||||
}
|
||||
.game-card:hover {
|
||||
border-color: var(--border-gold);
|
||||
box-shadow: var(--glow-gold);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
.game-card-thumb {
|
||||
height: 120px; position: relative;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 3.5rem;
|
||||
}
|
||||
.game-card-thumb::after {
|
||||
content: '';
|
||||
position: absolute; inset: 0;
|
||||
background: linear-gradient(0deg, var(--bg-card) 0%, transparent 60%);
|
||||
}
|
||||
.game-card-body { padding: 14px 16px; }
|
||||
.game-card-title { font-size: 1rem; font-weight: 800; color: #fff; margin-bottom: 4px; }
|
||||
.game-card-sub { font-size: 0.78rem; color: var(--text-muted); }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
BUTTONS
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
gap: 7px; padding: 10px 22px; border-radius: 10px;
|
||||
font-size: 0.88rem; font-weight: 800; cursor: pointer;
|
||||
transition: all 0.25s; border: none; white-space: nowrap;
|
||||
font-family: inherit;
|
||||
}
|
||||
.btn-gold {
|
||||
background: linear-gradient(135deg, var(--gold-light) 0%, var(--gold) 50%, var(--gold-mid) 100%);
|
||||
color: #1a0e00;
|
||||
box-shadow: 0 2px 12px rgba(212,160,23,0.35);
|
||||
}
|
||||
.btn-gold:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--glow-gold-lg);
|
||||
}
|
||||
.btn-outline-gold {
|
||||
background: transparent;
|
||||
border: 1.5px solid var(--border-gold);
|
||||
color: var(--gold);
|
||||
}
|
||||
.btn-outline-gold:hover { background: rgba(212,160,23,0.1); box-shadow: var(--glow-gold); }
|
||||
.btn-ghost {
|
||||
background: rgba(255,255,255,0.05);
|
||||
border: 1px solid var(--border-dim);
|
||||
color: var(--text-main);
|
||||
}
|
||||
.btn-ghost:hover { background: rgba(255,255,255,0.09); border-color: var(--border-gold); color: var(--gold); }
|
||||
.btn-sm { padding: 6px 14px; font-size: 0.78rem; border-radius: 8px; }
|
||||
.btn-lg { padding: 14px 36px; font-size: 1rem; border-radius: 12px; }
|
||||
|
||||
/* Legacy compat */
|
||||
.btn-primary { @extend .btn; @extend .btn-gold; }
|
||||
.btn-primary-sm { display: inline-flex; align-items: center; gap: 5px; padding: 6px 14px; background: linear-gradient(135deg, var(--gold), var(--gold-mid)); color: #1a0e00; border-radius: 8px; font-size: 0.82rem; font-weight: 800; cursor: pointer; border: none; transition: all 0.2s; }
|
||||
.btn-primary-sm:hover { transform: translateY(-1px); box-shadow: var(--glow-gold); }
|
||||
.btn-outline-sm { display: inline-flex; align-items: center; gap: 5px; padding: 6px 14px; border: 1.5px solid var(--border-gold); color: var(--gold); border-radius: 8px; font-size: 0.82rem; font-weight: 700; cursor: pointer; background: transparent; transition: all 0.2s; }
|
||||
.btn-outline-sm:hover { background: rgba(212,160,23,0.1); }
|
||||
.btn-secondary { display: inline-flex; align-items: center; gap: 7px; padding: 10px 22px; border-radius: 10px; background: transparent; border: 1.5px solid var(--border-dim); color: var(--text-main); font-size: 0.88rem; font-weight: 700; cursor: pointer; transition: all 0.25s; }
|
||||
.btn-secondary:hover { border-color: var(--border-gold); color: var(--gold); }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
FORM ELEMENTS
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.form-group { margin-bottom: 18px; }
|
||||
.form-label { font-size: 0.85rem; font-weight: 700; color: var(--silver); margin-bottom: 7px; display: block; }
|
||||
.form-input {
|
||||
width: 100%;
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-dim);
|
||||
color: var(--text-main);
|
||||
padding: 11px 16px;
|
||||
border-radius: 10px;
|
||||
font-size: 0.92rem;
|
||||
transition: all 0.2s;
|
||||
direction: rtl;
|
||||
font-family: inherit;
|
||||
}
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--border-gold);
|
||||
box-shadow: 0 0 0 3px rgba(212,160,23,0.12);
|
||||
}
|
||||
.form-input::placeholder { color: var(--text-faint); }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
CURRENCY DISPLAY
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.currency-gold {
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
color: var(--gold); font-weight: 800;
|
||||
}
|
||||
.currency-gold::before { content: '🪙'; font-size: 0.9em; }
|
||||
.currency-silver {
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
color: var(--silver-light); font-weight: 700;
|
||||
}
|
||||
.currency-silver::before { content: '🔘'; font-size: 0.9em; }
|
||||
|
||||
/* VIP Badge */
|
||||
.vip-badge {
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
background: linear-gradient(135deg, var(--gold-light), var(--gold));
|
||||
color: #1a0e00; padding: 3px 10px; border-radius: 12px;
|
||||
font-size: 0.72rem; font-weight: 900; letter-spacing: 0.5px;
|
||||
}
|
||||
.vip-badge-outline {
|
||||
background: transparent;
|
||||
border: 1px solid var(--gold);
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
/* Train / Station strip */
|
||||
.train-track {
|
||||
display: flex; align-items: center; gap: 0;
|
||||
overflow-x: auto; padding: 16px 0;
|
||||
}
|
||||
.train-track::-webkit-scrollbar { display: none; }
|
||||
.station {
|
||||
display: flex; flex-direction: column; align-items: center;
|
||||
flex-shrink: 0; position: relative;
|
||||
}
|
||||
.station-dot {
|
||||
width: 36px; height: 36px; border-radius: 50%;
|
||||
border: 2px solid var(--border-dim);
|
||||
background: var(--bg-card);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 0.75rem; font-weight: 800; color: var(--text-muted);
|
||||
transition: all 0.3s; z-index: 1;
|
||||
}
|
||||
.station.done .station-dot {
|
||||
background: linear-gradient(135deg, var(--gold), var(--gold-mid));
|
||||
border-color: var(--gold); color: #1a0e00;
|
||||
}
|
||||
.station.current .station-dot {
|
||||
border-color: var(--gold); color: var(--gold);
|
||||
box-shadow: var(--glow-gold); animation: stationPulse 2s infinite;
|
||||
}
|
||||
.station.vip .station-dot {
|
||||
border-color: var(--gold); background: rgba(212,160,23,0.15);
|
||||
}
|
||||
@keyframes stationPulse {
|
||||
0%,100% { box-shadow: 0 0 10px rgba(212,160,23,0.3); }
|
||||
50% { box-shadow: 0 0 22px rgba(212,160,23,0.7); }
|
||||
}
|
||||
.station-line {
|
||||
width: 50px; height: 2px;
|
||||
background: var(--border-dim); flex-shrink: 0;
|
||||
}
|
||||
.station-line.done { background: linear-gradient(90deg, var(--gold-dim), var(--gold)); }
|
||||
.station-label { font-size: 0.65rem; color: var(--text-muted); margin-top: 6px; white-space: nowrap; }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
TABLES
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.rank-table { width: 100%; border-collapse: collapse; }
|
||||
.rank-table th {
|
||||
text-align: right; padding: 10px 14px;
|
||||
font-size: 0.75rem; font-weight: 800;
|
||||
color: var(--gold-dim); border-bottom: 1px solid var(--border-gold);
|
||||
letter-spacing: 1px; text-transform: uppercase;
|
||||
}
|
||||
.rank-table td {
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.03);
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
.rank-table tr:hover td { background: rgba(212,160,23,0.04); }
|
||||
.rank-1 { color: var(--gold); font-weight: 900; font-size: 1.1rem; }
|
||||
.rank-2 { color: var(--silver); font-weight: 700; }
|
||||
.rank-3 { color: #cd7f32; font-weight: 700; }
|
||||
.rank-rest { color: var(--text-muted); }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
CHAT
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.chat-wrap { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
|
||||
.chat-messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 6px; }
|
||||
.chat-bubble { display: flex; gap: 8px; align-items: flex-start; }
|
||||
.chat-avatar {
|
||||
width: 30px; height: 30px; border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--gold-dark), var(--gold-dim));
|
||||
border: 1.5px solid var(--border-gold);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 0.65rem; font-weight: 800; color: var(--gold-light); flex-shrink: 0;
|
||||
}
|
||||
.chat-name { font-size: 0.75rem; color: var(--gold); font-weight: 700; }
|
||||
.chat-text { font-size: 0.85rem; color: var(--text-main); }
|
||||
.chat-time { font-size: 0.67rem; color: var(--text-muted); }
|
||||
.chat-input-bar {
|
||||
padding: 12px 16px;
|
||||
border-top: 1px solid var(--border-gold);
|
||||
display: flex; gap: 8px;
|
||||
}
|
||||
.chat-input {
|
||||
flex: 1;
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-dim);
|
||||
color: var(--text-main);
|
||||
padding: 9px 14px; border-radius: 10px;
|
||||
font-size: 0.88rem; direction: rtl; font-family: inherit;
|
||||
}
|
||||
.chat-input:focus { outline: none; border-color: var(--border-gold); }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
UTILITY CLASSES
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.badge {
|
||||
font-size: 0.68rem; font-weight: 800; padding: 2px 8px;
|
||||
border-radius: 12px; display: inline-block; letter-spacing: 0.3px;
|
||||
}
|
||||
.badge-gold { background: rgba(212,160,23,0.2); color: var(--gold); border: 1px solid rgba(212,160,23,0.3); }
|
||||
.badge-green { background: rgba(34,197,94,0.15); color: #4ade80; }
|
||||
.badge-red { background: rgba(239,68,68,0.15); color: #f87171; }
|
||||
.badge-blue { background: rgba(59,130,246,0.15); color: #93c5fd; }
|
||||
|
||||
.divider { height: 1px; background: var(--border-dim); margin: 16px 0; }
|
||||
.divider-gold { background: linear-gradient(90deg, transparent, var(--border-gold), transparent); }
|
||||
|
||||
.text-gold { color: var(--gold); }
|
||||
.text-silver { color: var(--silver); }
|
||||
.text-muted { color: var(--text-muted); }
|
||||
.text-main { color: var(--text-main); }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
ANIMATIONS
|
||||
════════════════════════════════════════════════════════════ */
|
||||
@keyframes pulse {
|
||||
0%,100% { opacity:1; transform:scale(1); }
|
||||
50% { opacity:0.5; transform:scale(1.4); }
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from { opacity:0; transform:translateY(8px); }
|
||||
to { opacity:1; transform:translateY(0); }
|
||||
}
|
||||
@keyframes slideIn {
|
||||
from { opacity:0; transform:translateX(16px); }
|
||||
to { opacity:1; transform:translateX(0); }
|
||||
}
|
||||
@keyframes shimmer {
|
||||
0% { background-position: -200% 0; }
|
||||
100% { background-position: 200% 0; }
|
||||
}
|
||||
.animate-in { animation: fadeIn 0.4s ease forwards; }
|
||||
.animate-slide { animation: slideIn 0.35s ease forwards; }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
SCROLLBAR
|
||||
════════════════════════════════════════════════════════════ */
|
||||
::-webkit-scrollbar { width: 5px; height: 5px; }
|
||||
::-webkit-scrollbar-track { background: var(--bg-surface); }
|
||||
::-webkit-scrollbar-thumb { background: var(--gold-dim); border-radius: 3px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: var(--gold-dark); }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
MODAL / OVERLAY
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.modal-overlay {
|
||||
position: fixed; inset: 0; z-index: 200;
|
||||
background: rgba(0,0,0,0.75);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
backdrop-filter: blur(4px);
|
||||
animation: fadeIn 0.2s ease;
|
||||
}
|
||||
.modal-box {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-gold);
|
||||
border-radius: 18px; padding: 36px;
|
||||
width: 100%; max-width: 440px;
|
||||
box-shadow: var(--glow-gold-lg);
|
||||
position: relative;
|
||||
}
|
||||
.modal-box::before {
|
||||
content: '';
|
||||
position: absolute; top: 0; left: 50%; transform: translateX(-50%);
|
||||
width: 50%; height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--gold), transparent);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
TOAST NOTIFICATION
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.toast-container { position: fixed; top: 72px; left: 20px; z-index: 300; display: flex; flex-direction: column; gap: 8px; }
|
||||
.toast {
|
||||
padding: 12px 20px; border-radius: 10px;
|
||||
font-size: 0.88rem; font-weight: 700;
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
animation: slideIn 0.3s ease;
|
||||
box-shadow: var(--glow-soft);
|
||||
}
|
||||
.toast-success { background: rgba(34,197,94,0.15); border: 1px solid rgba(34,197,94,0.35); color: #4ade80; }
|
||||
.toast-gold { background: rgba(212,160,23,0.15); border: 1px solid var(--border-gold); color: var(--gold); }
|
||||
.toast-error { background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.35); color: #f87171; }
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
SECTION TITLE
|
||||
════════════════════════════════════════════════════════════ */
|
||||
.section-title {
|
||||
font-size: 1.1rem; font-weight: 900; color: var(--text-main);
|
||||
display: flex; align-items: center; gap: 8px; margin-bottom: 16px;
|
||||
}
|
||||
.section-title::after {
|
||||
content: ''; flex: 1; height: 1px;
|
||||
background: linear-gradient(90deg, var(--border-gold), transparent);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════
|
||||
RESPONSIVE — collapse sidebar on small screens
|
||||
════════════════════════════════════════════════════════════ */
|
||||
@media (max-width: 768px) {
|
||||
:root { --sidebar-w: 0px; }
|
||||
.sidebar { display: none; }
|
||||
.sidebar.open { display: flex; width: 240px; position: fixed; top: var(--topbar-h); bottom: 0; right: 0; z-index: 80; }
|
||||
.topbar-brand .name { font-size: 1rem; letter-spacing: 2px; }
|
||||
.wallet-strip .wallet-coin span:not(.coin-icon) { display: none; }
|
||||
.tab-item .tab-label { display: none; }
|
||||
}
|
||||
|
||||
/* ── Protect pages — hide content before auth check ──────── */
|
||||
.auth-guard { visibility: hidden; }
|
||||
.auth-guard.revealed { visibility: visible; }
|
||||
143
app/public/top.html
Normal file
143
app/public/top.html
Normal file
@ -0,0 +1,143 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GAMEHUS — المتصدرون</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-page="top" class="auth-guard">
|
||||
|
||||
<div class="app-shell">
|
||||
<header id="topbar" class="topbar"></header>
|
||||
<div class="app-body">
|
||||
<aside id="sidebar" class="sidebar"></aside>
|
||||
<main class="content-area">
|
||||
|
||||
<div style="flex:1;overflow:hidden;display:flex;flex-direction:column;" data-inner-tabs>
|
||||
<div class="inner-tab-bar">
|
||||
<button class="inner-tab" data-inner-tab="board-billiards">🎱 البلياردو</button>
|
||||
<button class="inner-tab" data-inner-tab="board-chess">♟️ الشطرنج</button>
|
||||
</div>
|
||||
|
||||
<!-- Billiards board -->
|
||||
<div class="inner-panel" data-inner-panel="board-billiards">
|
||||
<div class="inner-content">
|
||||
<!-- Period filters -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:20px;flex-wrap:wrap;align-items:center;justify-content:space-between;">
|
||||
<h1 style="font-size:1.4rem;font-weight:900;" class="gold-text">🏆 متصدرو البلياردو</h1>
|
||||
<div style="display:flex;gap:6px;" id="period-btns">
|
||||
${['اليوم','الأسبوع','الشهر','الكل'].map((p,i)=>`
|
||||
<button onclick="setPeriod(this)" style="padding:6px 14px;border-radius:8px;font-size:0.8rem;font-weight:700;border:1px solid ${i===3?'var(--border-gold)':'rgba(255,255,255,0.1)'};background:${i===3?'rgba(212,160,23,0.12)':'transparent'};color:${i===3?'var(--gold)':'var(--text-muted)'};cursor:pointer;transition:all 0.2s;">${p}</button>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Podium Top 3 -->
|
||||
<div style="display:grid;grid-template-columns:1fr 1.2fr 1fr;gap:12px;margin-bottom:24px;align-items:end;">
|
||||
<!-- 2nd -->
|
||||
<div style="text-align:center;animation:fadeIn 0.5s ease 0.1s both;">
|
||||
<div style="width:56px;height:56px;border-radius:50%;background:linear-gradient(135deg,#8a8a9a,#5a5a6a);border:2px solid var(--silver);margin:0 auto 8px;display:flex;align-items:center;justify-content:center;font-size:1.4rem;font-weight:900;color:#fff;">2</div>
|
||||
<div style="font-weight:700;color:var(--text-main);font-size:0.9rem;">🇪🇬 PoolKing_X</div>
|
||||
<div style="font-size:0.78rem;color:var(--silver);margin-top:2px;">14,200 نقطة</div>
|
||||
<div style="background:linear-gradient(135deg,var(--silver-dark),var(--silver));height:60px;margin-top:8px;border-radius:8px 8px 0 0;display:flex;align-items:center;justify-content:center;font-size:1.5rem;">🥈</div>
|
||||
</div>
|
||||
<!-- 1st -->
|
||||
<div style="text-align:center;animation:fadeIn 0.5s ease both;">
|
||||
<div style="font-size:1.2rem;margin-bottom:4px;">👑</div>
|
||||
<div style="width:72px;height:72px;border-radius:50%;background:linear-gradient(135deg,var(--gold-light),var(--gold-mid));border:3px solid var(--gold);margin:0 auto 8px;display:flex;align-items:center;justify-content:center;font-size:1.8rem;font-weight:900;color:#1a0e00;box-shadow:var(--glow-gold);">1</div>
|
||||
<div style="font-weight:800;color:var(--gold);font-size:1rem;">🇸🇦 ProShooter99</div>
|
||||
<div style="font-size:0.82rem;color:var(--gold-mid);margin-top:2px;">15,420 نقطة</div>
|
||||
<div style="background:linear-gradient(135deg,var(--gold-mid),var(--gold-dark));height:90px;margin-top:8px;border-radius:8px 8px 0 0;display:flex;align-items:center;justify-content:center;font-size:2rem;">🥇</div>
|
||||
</div>
|
||||
<!-- 3rd -->
|
||||
<div style="text-align:center;animation:fadeIn 0.5s ease 0.2s both;">
|
||||
<div style="width:48px;height:48px;border-radius:50%;background:linear-gradient(135deg,#8a5a1a,#5a3a0a);border:2px solid #cd7f32;margin:0 auto 8px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;font-weight:900;color:#fff;">3</div>
|
||||
<div style="font-weight:700;color:var(--text-main);font-size:0.9rem;">🇲🇦 SnookerLegend</div>
|
||||
<div style="font-size:0.78rem;color:#cd7f32;margin-top:2px;">13,800 نقطة</div>
|
||||
<div style="background:linear-gradient(135deg,#8a5a1a,#5a3a0a);height:44px;margin-top:8px;border-radius:8px 8px 0 0;display:flex;align-items:center;justify-content:center;font-size:1.3rem;">🥉</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Full Table -->
|
||||
<div class="card" style="overflow:hidden;">
|
||||
<table class="rank-table">
|
||||
<thead><tr><th>#</th><th>اللاعب</th><th>الانتصارات</th><th>النقاط</th></tr></thead>
|
||||
<tbody>
|
||||
${[
|
||||
{r:1,n:'ProShooter99',f:'🇸🇦',w:2847,p:15420},
|
||||
{r:2,n:'PoolKing_X',f:'🇪🇬',w:2610,p:14200},
|
||||
{r:3,n:'SnookerLegend',f:'🇲🇦',w:2455,p:13800},
|
||||
{r:4,n:'BallMaster',f:'🇦🇪',w:2300,p:12950},
|
||||
{r:5,n:'CueTigerz',f:'🇮🇶',w:2190,p:12100},
|
||||
{r:6,n:'SilentStrike',f:'🇯🇴',w:2050,p:11300},
|
||||
{r:7,n:'NightHunter',f:'🇱🇧',w:1980,p:10800},
|
||||
{r:8,n:'SpinMaster',f:'🇰🇼',w:1870,p:10200},
|
||||
{r:9,n:'DeepShot',f:'🇸🇾',w:1750,p:9500},
|
||||
{r:10,n:'EagleEye',f:'🇧🇭',w:1620,p:8900},
|
||||
].map(p=>`
|
||||
<tr style="animation:fadeIn 0.3s ease ${p.r*0.05}s both;">
|
||||
<td class="rank-${p.r<=3?p.r:'rest'}">${p.r===1?'🥇':p.r===2?'🥈':p.r===3?'🥉':p.r}</td>
|
||||
<td style="font-weight:600;color:var(--text-main);">${p.f} ${p.n}</td>
|
||||
<td style="color:#4ade80;font-weight:600;">${p.w.toLocaleString()}</td>
|
||||
<td class="gold-text" style="font-weight:800;">${p.p.toLocaleString()}</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chess board -->
|
||||
<div class="inner-panel" data-inner-panel="board-chess">
|
||||
<div class="inner-content">
|
||||
<h1 style="font-size:1.4rem;font-weight:900;margin-bottom:20px;" class="gold-text">🏆 متصدرو الشطرنج</h1>
|
||||
<div class="card" style="overflow:hidden;">
|
||||
<table class="rank-table">
|
||||
<thead><tr><th>#</th><th>اللاعب</th><th>الانتصارات</th><th>النقاط</th></tr></thead>
|
||||
<tbody>
|
||||
${[
|
||||
{r:1,n:'GrandMaster_Z',f:'🇸🇦',w:1920,p:18500},
|
||||
{r:2,n:'KingSlayer',f:'🇪🇬',w:1780,p:17200},
|
||||
{r:3,n:'ChessWizard',f:'🇲🇦',w:1650,p:16100},
|
||||
{r:4,n:'TacticalMove',f:'🇦🇪',w:1540,p:15400},
|
||||
{r:5,n:'QueenTrapper',f:'🇮🇶',w:1410,p:14200},
|
||||
{r:6,n:'EndgamePro',f:'🇯🇴',w:1320,p:13500},
|
||||
{r:7,n:'RookRush',f:'🇱🇧',w:1200,p:12300},
|
||||
{r:8,n:'BishopBoss',f:'🇰🇼',w:1090,p:11100},
|
||||
].map(p=>`
|
||||
<tr>
|
||||
<td class="rank-${p.r<=3?p.r:'rest'}">${p.r===1?'🥇':p.r===2?'🥈':p.r===3?'🥉':p.r}</td>
|
||||
<td style="font-weight:600;color:var(--text-main);">${p.f} ${p.n}</td>
|
||||
<td style="color:#4ade80;font-weight:600;">${p.w.toLocaleString()}</td>
|
||||
<td class="gold-text" style="font-weight:800;">${p.p.toLocaleString()}</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="static/script.js"></script>
|
||||
<script>
|
||||
function setPeriod(btn) {
|
||||
document.querySelectorAll('#period-btns button').forEach(b => {
|
||||
b.style.borderColor = 'rgba(255,255,255,0.1)';
|
||||
b.style.background = 'transparent';
|
||||
b.style.color = 'var(--text-muted)';
|
||||
});
|
||||
btn.style.borderColor = 'var(--border-gold)';
|
||||
btn.style.background = 'rgba(212,160,23,0.12)';
|
||||
btn.style.color = 'var(--gold)';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
74
app/public/tournaments.html
Normal file
74
app/public/tournaments.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>البطولات - GAMEHUS</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<link href="static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="nav-bar fixed top-0 left-0 right-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 flex items-center justify-between h-16">
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="index.html" class="flex items-center gap-2 no-underline"><div class="logo-icon">🎱</div><span class="logo-text">GAMEHUS</span></a>
|
||||
<div class="hidden md:flex items-center gap-1 ml-6"><a href="index.html" class="nav-link">الرئيسية</a><a href="games.html" class="nav-link">الألعاب</a><a href="top.html" class="nav-link">المتصدرون</a><a href="chat.html" class="nav-link">الدردشة</a></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2"><div class="online-badge"><span class="online-dot"></span><span id="online-count">8,432</span> متصل</div><a href="login.html" class="btn-outline-sm">دخول</a><a href="register.html" class="btn-primary-sm">تسجيل</a><button class="md:hidden mobile-toggle p-2"><svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path></svg></button></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="mobile-menu" class="mobile-menu"><a href="index.html" class="block nav-link">الرئيسية</a><a href="games.html" class="block nav-link">الألعاب</a><a href="top.html" class="block nav-link">المتصدرون</a><a href="chat.html" class="block nav-link">الدردشة</a></div>
|
||||
|
||||
<div style="padding-top:64px;">
|
||||
<div class="max-w-6xl mx-auto px-4 py-12">
|
||||
<div class="text-center mb-12">
|
||||
<h1 style="font-size:2.5rem;font-weight:900;color:#fff;margin-bottom:8px;">🏆 البطولات والمسابقات</h1>
|
||||
<p style="color:#6b7280;">انضم إلى البطولات ونافس على الجوائز</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-4 mb-12">
|
||||
<div style="text-align:center;padding:20px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.07);border-radius:12px;"><div style="font-size:1.8rem;">🏆</div><div style="font-size:1.6rem;font-weight:900;color:#ffd700;">4</div><div style="font-size:.8rem;color:#6b7280;">بطولات نشطة</div></div>
|
||||
<div style="text-align:center;padding:20px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.07);border-radius:12px;"><div style="font-size:1.8rem;">👥</div><div style="font-size:1.6rem;font-weight:900;color:#ffd700;">1,240</div><div style="font-size:.8rem;color:#6b7280;">مشارك هذا الشهر</div></div>
|
||||
<div style="text-align:center;padding:20px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.07);border-radius:12px;"><div style="font-size:1.8rem;">💰</div><div style="font-size:1.6rem;font-weight:900;color:#ffd700;">43,000</div><div style="font-size:.8rem;color:#6b7280;">إجمالي الجوائز</div></div>
|
||||
</div>
|
||||
<div id="tournaments-grid" class="grid grid-cols-1 md:grid-cols-2 gap-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="footer mt-16">
|
||||
<div class="max-w-7xl mx-auto px-4 py-12">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
<div><div class="flex items-center gap-2 mb-4"><span class="text-2xl">🎱</span><span class="text-xl font-bold text-white">GAMEHUS</span></div><p class="text-gray-400 text-sm">العب بلياردو وشطرنج مجانًا مع لاعبين من حول العالم.</p></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">الألعاب</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="games.html">8-Ball Pool</a></li><li><a href="games.html">9-Ball Pool</a></li><li><a href="games.html">الشطرنج</a></li></ul></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">المجتمع</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="top.html">المتصدرون</a></li><li><a href="chat.html">الدردشة</a></li><li><a href="tournaments.html">البطولات</a></li></ul></div>
|
||||
<div><h4 class="text-white font-semibold mb-3">الحساب</h4><ul class="space-y-2 text-sm text-gray-400"><li><a href="register.html">إنشاء حساب</a></li><li><a href="login.html">تسجيل الدخول</a></li><li><a href="profile.html">الملف الشخصي</a></li></ul></div>
|
||||
</div>
|
||||
<div class="border-t border-gray-800 mt-8 pt-6 text-center text-gray-500 text-sm">© 2026 GAMEHUS - جميع الحقوق محفوظة</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const tournaments = [
|
||||
{ name: "بطولة رمضان للبلياردو", game: "🎱 8-Ball", date: "15 مارس", prize: "10,000 نقطة", players: "64/128", status: "مفتوح للتسجيل", color: "#22c55e" },
|
||||
{ name: "كأس الشطرنج الأسبوعي", game: "♟️ الشطرنج", date: "12 مارس", prize: "5,000 نقطة", players: "48/64", status: "جارٍ التسجيل", color: "#f59e0b" },
|
||||
{ name: "بطولة 9-Ball الكبرى", game: "🎱 9-Ball", date: "20 مارس", prize: "8,000 نقطة", players: "32/64", status: "مفتوح للتسجيل", color: "#22c55e" },
|
||||
{ name: "دوري الداما الشهري", game: "🔴 الداما", date: "18 مارس", prize: "3,000 نقطة", players: "16/32", status: "قريبًا", color: "#6b7280" }
|
||||
];
|
||||
document.getElementById("tournaments-grid").innerHTML = tournaments.map((t) => `
|
||||
<div class="card p-6">
|
||||
<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:12px;">
|
||||
<div><h3 style="font-weight:800;color:#fff;font-size:1.05rem;margin-bottom:4px;">${t.name}</h3><span style="font-size:.85rem;color:#9ca3af;">${t.game}</span></div>
|
||||
<span style="font-size:.75rem;font-weight:700;padding:4px 12px;border-radius:20px;background:rgba(255,255,255,.06);color:${t.color};">${t.status}</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-3 mb-4">
|
||||
<div style="text-align:center;padding:10px;background:rgba(255,215,0,.08);border-radius:8px;"><div style="font-size:.75rem;color:#6b7280;">الجائزة</div><div style="font-weight:700;color:#ffd700;font-size:.9rem;">🏆 ${t.prize}</div></div>
|
||||
<div style="text-align:center;padding:10px;background:rgba(255,255,255,.03);border-radius:8px;"><div style="font-size:.75rem;color:#6b7280;">المشاركون</div><div style="font-weight:700;color:#e2e8f0;font-size:.9rem;">👥 ${t.players}</div></div>
|
||||
<div style="text-align:center;padding:10px;background:rgba(255,255,255,.03);border-radius:8px;"><div style="font-size:.75rem;color:#6b7280;">التاريخ</div><div style="font-weight:700;color:#e2e8f0;font-size:.9rem;">📅 ${t.date}</div></div>
|
||||
</div>
|
||||
<a href="register.html" class="btn-primary" style="display:block;text-align:center;padding:10px;">✅ سجّل في البطولة</a>
|
||||
</div>`).join("");
|
||||
</script>
|
||||
<script src="static/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user