Commit d57f6772 authored by Mahmoud Aglan's avatar Mahmoud Aglan

go

parent 932ff403
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules node_modules
dist dist
dist-ssr .env
*.local *.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
screenshots/
Connections and docs /
*.pem
EL3AB_PLAYER_APP_DATA.md
V1_PLAN.md
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAwNRFitb/O8fS9TaUoCZ/VJZUEehvdyb1EgCjPrQbTeT6TlZh
rvkzHYcGIKsgarI6wuP9aK4+rLW8SL9VP6Ey3G4CgY/Hx9ZxhoSN5N2ffZkJE1Ji
hvgkDXzSN+l4P3e422ICxuVQqozba8/o8pZo46EzgRry760i9RcR8Q8JsXysjeQ1
Q68F8JhUYt1GNQlc5/A1EHEHyv1XIMDkYQ0eart1iUf9uvU/tp6pFTNUq/UtL/BT
RaJdnShbstS7bsfZwkyRtzXUlu15z/xdCsoXbbz+GC4oV7thzZQ+eRS8sZBGTsHF
6AaNqvd3QQnbFEpUSDzK3xupVEvLw3BbwYFvxwIDAQABAoIBAB4Gr9F/yvynD/1p
A1mwxPEJ+4tSU1ENeunTuZfA+eN2PVfHcayKV2BIrzaVDxYuLKI+WC5du5qvLeNy
D7c5xa63XqKIHgbLKKBWsbWqoPQwyU397SOxLgP/pMhaDYRsgxd+Oop4GMiF6IDw
PgjQTQLtDhUTejLCFghuEDgmLE87oi4oV3m8y36Yl1gHSHLzHivk8tiJoFdd9Jw3
FdM9wPS2FcafGaT7CDhbmo8XtHgynxbjCAX6D8tOpsbhVuClseRLXMfhkai0UuO4
JhgJ4tvDoxW3G/3qZkSvL/jUr5gybUCjVAcBfE7HIvfcYKQxU+iX9R8Q7cWzFO/d
RjooSWECgYEA9DDSYxBXuOkVHq9KDWnRBWUslLk2i9nvPEL+JVPqzR6Q+uRnZzl/
j54XBd25lAcCkTDmjZTHKFroX5uvgBzHGfGZFGtoZuObfVkzK9eicupPqTe7rcN6
fTJWeJnNJsYbkGzv0jrqvBJOG+/9zGVsn7UQZvWHiS9lgKYrDz2Vx5cCgYEAyieS
3xFK+lytLgJ6pqNx6RuvEAKgouZi3sgYIxwyMSA9Yap/5po6Osj8w9X18Bvm6YYF
gok+Zx63pEB7296RrmGDxkOw5Hl/gH07Yx2hvM4et3RyvK3udOXCdcXgWN0ue/Uf
H75UZ4CLAmNALEUa9lOcB2uydVHOhXCmgPveH1ECgYAtShzLKM3MStaS8VnfsP+G
a6RgFRXrzEjVuWsfizfiQUgMcG5JM93Xyi9k9CGmNcKhIRuxqKVjc7DjgqGDNlMr
GacVpXIgmxhMoE2gVQcZHyIVNXQGn1nJfJuTFJt7FIUqPTohmLHOneqEvfcpgKor
2M4o+mLf6718pdUYp4hvEwKBgBSJhLBIz3cz5xwfgFphjHcEKvrTaYJjKXQ8m8cl
XCwFfHbpnWjODlBejt9OY1frXcAnr3Odgct0IW/8ZRjnOaGfooWH5vavKTbigiAF
qKLHxfMZT3a/rNQPa3wPiEU+4zQQqQLOkUCanIS3lJNqydxwjg9q74xfrT19Pk0o
SV6hAoGBAKfidUGqWGH3FugbgG2cm7rK54nh978brZLKglekR1RlRWKG7QpRP33v
D13y3BD1rRM3vguD2aABhwqbYVt1hjHA+mv+yDzJps08FtZIasiTRpm2mFanOD84
yKf+0/HMD2G45HzoMYdG6BdZ5HP1y4WFNfRoxjwCTnwyrDMNJhOl
-----END RSA PRIVATE KEY-----
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
## React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
This diff is collapsed.
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
globals: globals.browser,
},
},
])
...@@ -3,16 +3,15 @@ ...@@ -3,16 +3,15 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="theme-color" content="#071120" /> <meta name="theme-color" content="#071120" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<title>EL3AB - العب</title>
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=Cairo:wght@600;700;900&display=swap" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@400;500;600;700&family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet" />
<title>EL3AB - العب</title>
</head> </head>
<body class="bg-background text-text-primary antialiased overflow-x-hidden"> <body>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/main.tsx"></script> <script type="module" src="/src/main.tsx"></script>
</body> </body>
......
...@@ -6,9 +6,6 @@ server { ...@@ -6,9 +6,6 @@ server {
location / { location / {
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
} }
location /assets { location /assets {
......
This diff is collapsed.
{ {
"name": "el3ab-player", "name": "el3ab-player",
"private": true, "private": true,
"version": "0.0.0", "version": "2.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@supabase/supabase-js": "^2.106.2", "@supabase/supabase-js": "^2.49.0",
"chess.js": "^1.4.0", "chess.js": "^1.0.0-beta.8",
"framer-motion": "^12.40.0", "framer-motion": "^12.0.0",
"howler": "^2.2.4", "howler": "^2.2.4",
"lucide-react": "^1.16.0",
"react": "^19.2.6", "react": "^19.2.6",
"react-dom": "^19.2.6", "react-dom": "^19.2.6",
"react-router-dom": "^7.15.1", "react-router-dom": "^7.1.0",
"zustand": "^5.0.13" "zustand": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@tailwindcss/vite": "^4.0.0",
"@tailwindcss/vite": "^4.3.0", "@types/howler": "^2.2.12",
"@types/howler": "^2.2.13",
"@types/node": "^24.12.3",
"@types/react": "^19.2.14", "@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1", "@vitejs/plugin-react": "^6.0.1",
"eslint": "^10.3.0", "tailwindcss": "^4.0.0",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0",
"playwright": "^1.60.0",
"tailwindcss": "^4.3.0",
"typescript": "~6.0.2", "typescript": "~6.0.2",
"typescript-eslint": "^8.59.2",
"vite": "^8.0.12" "vite": "^8.0.12"
} }
} }
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<defs> <rect width="32" height="32" rx="6" fill="#071120"/>
<linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"> <text x="16" y="22" font-family="Inter, sans-serif" font-size="14" font-weight="800" fill="#E7A832" text-anchor="middle">E3</text>
<stop offset="0%" stop-color="#E8C55A"/>
<stop offset="100%" stop-color="#B8964A"/>
</linearGradient>
</defs>
<rect width="32" height="32" rx="6" fill="#0A0A14"/>
<path d="M16 5L20 11L27 8L24 19H8L5 8L12 11L16 5Z" fill="url(#g)"/>
<rect x="8" y="19" width="16" height="3" rx="1" fill="url(#g)"/>
<circle cx="16" cy="8" r="1.2" fill="#FFF8E1"/>
<circle cx="11" cy="11" r="1" fill="#FFF8E1"/>
<circle cx="21" cy="11" r="1" fill="#FFF8E1"/>
</svg> </svg>
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="bluesky-icon" viewBox="0 0 16 17">
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
</symbol>
<symbol id="discord-icon" viewBox="0 0 20 19">
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
</symbol>
<symbol id="documentation-icon" viewBox="0 0 21 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
</symbol>
<symbol id="github-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
</symbol>
<symbol id="social-icon" viewBox="0 0 20 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
</symbol>
<symbol id="x-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
</symbol>
</svg>
import { chromium } from 'playwright'
import { mkdirSync } from 'fs'
const BASE_URL = 'https://el3ab-player.caprover.al-arcade.com'
const VIEWPORT = { width: 390, height: 844 }
const EMAIL = 'testplayer1@el3ab.com'
const PASSWORD = 'test123456'
async function main() {
mkdirSync('screenshots', { recursive: true })
const browser = await chromium.launch()
const context = await browser.newContext({
viewport: VIEWPORT,
deviceScaleFactor: 2,
locale: 'ar',
})
const page = await context.newPage()
// Login
await page.goto(`${BASE_URL}/login`, { waitUntil: 'networkidle', timeout: 15000 })
await page.waitForTimeout(1000)
await page.fill('input[type="email"]', EMAIL)
await page.fill('input[type="password"]', PASSWORD)
await page.click('button[type="submit"]')
await page.waitForTimeout(3000)
// Navigate to bot game directly
await page.goto(`${BASE_URL}/game/bot/amina`, { waitUntil: 'networkidle', timeout: 15000 })
await page.waitForTimeout(2000)
await page.screenshot({ path: 'screenshots/bot-match-01-start.png' })
console.log('captured: initial board')
// Target squares specifically within the chess board grid (data-testid="chess-board")
const squares = page.locator('[data-testid="chess-board"] > div')
const squareCount = await squares.count()
console.log(`found ${squareCount} squares on the board`)
// The board is an 8x8 grid. For white's perspective (not flipped):
// Grid index = row*8 + col, where row 0 = rank 8 (top), row 7 = rank 1 (bottom)
// e2 = file e (col 4), rank 2 (row 6) -> index: 6*8 + 4 = 52
// e4 = file e (col 4), rank 4 (row 4) -> index: 4*8 + 4 = 36
// Click e2 (select white pawn)
console.log('clicking e2 (index 52)...')
await squares.nth(52).click()
await page.waitForTimeout(800)
await page.screenshot({ path: 'screenshots/bot-match-02-selected-e2.png' })
console.log('captured: selected e2')
// Click e4 (move pawn)
console.log('clicking e4 (index 36)...')
await squares.nth(36).click()
await page.waitForTimeout(800)
await page.screenshot({ path: 'screenshots/bot-match-03-moved-e4.png' })
console.log('captured: moved e4')
// Wait for bot to respond (up to 12 seconds)
console.log('waiting for bot to respond...')
await page.waitForTimeout(10000)
await page.screenshot({ path: 'screenshots/bot-match-04-bot-responded.png' })
console.log('captured: after bot response')
// Play another move: d2-d4
// d2 = file d (col 3), rank 2 (row 6) -> index: 6*8 + 3 = 51
// d4 = file d (col 3), rank 4 (row 4) -> index: 4*8 + 3 = 35
console.log('clicking d2 (index 51)...')
await squares.nth(51).click()
await page.waitForTimeout(800)
console.log('clicking d4 (index 35)...')
await squares.nth(35).click()
await page.waitForTimeout(800)
await page.screenshot({ path: 'screenshots/bot-match-05-moved-d4.png' })
console.log('captured: moved d4')
// Wait for bot second response
console.log('waiting for bot second response...')
await page.waitForTimeout(10000)
await page.screenshot({ path: 'screenshots/bot-match-06-bot-responded-2.png' })
console.log('captured: after bot second response')
// Play Nf3
// g1 = file g (col 6), rank 1 (row 7) -> index: 7*8 + 6 = 62
// f3 = file f (col 5), rank 3 (row 5) -> index: 5*8 + 5 = 45
console.log('clicking g1 (index 62)...')
await squares.nth(62).click()
await page.waitForTimeout(800)
console.log('clicking f3 (index 45)...')
await squares.nth(45).click()
await page.waitForTimeout(800)
// Wait for bot
console.log('waiting for bot third response...')
await page.waitForTimeout(10000)
await page.screenshot({ path: 'screenshots/bot-match-07-after-3-moves.png' })
console.log('captured: after 3 moves each')
await browser.close()
console.log('done - bot match test complete')
}
main()
import { chromium } from 'playwright'
import { mkdirSync } from 'fs'
const PAGES = [
{ name: 'login', url: '/login' },
{ name: 'register', url: '/register' },
{ name: 'home', url: '/' },
{ name: 'play', url: '/play' },
{ name: 'profile', url: '/profile' },
{ name: 'friends', url: '/friends' },
{ name: 'tournaments', url: '/tournaments' },
{ name: 'leaderboard', url: '/leaderboard' },
{ name: 'shop', url: '/shop' },
{ name: 'notifications', url: '/notifications' },
{ name: 'settings', url: '/settings' },
{ name: 'bot-select', url: '/bot-select' },
{ name: 'matchmaking', url: '/matchmaking' },
]
const BASE = 'https://el3ab-player.caprover.al-arcade.com'
async function main() {
mkdirSync('screenshots', { recursive: true })
const browser = await chromium.launch()
// Mobile viewport
const mobile = await browser.newContext({
viewport: { width: 390, height: 844 },
deviceScaleFactor: 2,
locale: 'ar',
})
// Desktop viewport
const desktop = await browser.newContext({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1,
locale: 'ar',
})
// Login first to get session for protected pages
const loginPage = await mobile.newPage()
await loginPage.goto(`${BASE}/login`, { waitUntil: 'networkidle', timeout: 20000 })
await loginPage.waitForTimeout(1000)
await loginPage.fill('input[type="email"]', 'testplayer1@el3ab.com')
await loginPage.fill('input[type="password"]', 'test123456')
await loginPage.click('button[type="submit"]')
await loginPage.waitForTimeout(3000)
await loginPage.close()
// Also login on desktop context
const loginDesktop = await desktop.newPage()
await loginDesktop.goto(`${BASE}/login`, { waitUntil: 'networkidle', timeout: 20000 })
await loginDesktop.waitForTimeout(1000)
await loginDesktop.fill('input[type="email"]', 'testplayer1@el3ab.com')
await loginDesktop.fill('input[type="password"]', 'test123456')
await loginDesktop.click('button[type="submit"]')
await loginDesktop.waitForTimeout(3000)
await loginDesktop.close()
for (const { name, url } of PAGES) {
// Mobile screenshot
const mPage = await mobile.newPage()
await mPage.goto(`${BASE}${url}`, { waitUntil: 'networkidle', timeout: 15000 })
await mPage.waitForTimeout(1500)
await mPage.screenshot({ path: `screenshots/${name}-mobile.png` })
console.log(`captured ${name}-mobile`)
await mPage.close()
// Desktop screenshot
const dPage = await desktop.newPage()
await dPage.goto(`${BASE}${url}`, { waitUntil: 'networkidle', timeout: 15000 })
await dPage.waitForTimeout(1500)
await dPage.screenshot({ path: `screenshots/${name}-desktop.png` })
console.log(`captured ${name}-desktop`)
await dPage.close()
}
await browser.close()
console.log('Done! All screenshots captured.')
}
main()
This diff is collapsed.
import { chromium } from 'playwright'
import { mkdirSync } from 'fs'
async function main() {
mkdirSync('screenshots', { recursive: true })
const browser = await chromium.launch()
const context = await browser.newContext({
viewport: { width: 390, height: 844 },
deviceScaleFactor: 2,
locale: 'ar',
})
const page = await context.newPage()
await page.goto('https://el3ab-player.caprover.al-arcade.com/login', { waitUntil: 'networkidle', timeout: 15000 })
await page.waitForTimeout(2000)
await page.screenshot({ path: 'screenshots/login.png' })
console.log('captured login')
await browser.close()
}
main()
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
export { AnimatedIcon } from './AnimatedIcon'
export { GoldCrown } from './GoldCrown'
This diff is collapsed.
This diff is collapsed.
export function DecorativeBackground() {
return (
<div className="fixed inset-0 pointer-events-none z-0">
<div
className="absolute inset-0"
style={{
background: 'radial-gradient(ellipse at 50% 0%, rgba(23, 37, 60, 0.5) 0%, transparent 60%)',
}}
/>
</div>
)
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
export { AppShell } from './AppShell'
export { DecorativeBackground } from './DecorativeBackground'
export { Header } from './Header'
export { BottomNav } from './BottomNav'
export { PageTransition } from './PageTransition'
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
export { Button } from './Button'
export { Card } from './Card'
export { GamePanel } from './GamePanel'
export { GameProgressBar } from './GameProgressBar'
export { Input } from './Input'
export { RibbonHeader } from './RibbonHeader'
export { ShieldBadge } from './ShieldBadge'
export { ToastContainer } from './ToastContainer'
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment