50f1d5cfb6
## Menu now matches production exactly
- Read the 122-row inspection2.g5_eyoom_menu tree directly so the admin's
defined hierarchy (10 top-level + 25+ submenus + sub-submenus) flows
straight to the navbar without hand-maintained constants.
- Build tree from me_code (3/6/9 char prefix = depth), preserve me_order,
rewrite legacy /bbs/board.php?bo_table=foo + /bbs/qalist.php +
game/exchange/lottery URLs into the new app routes.
- Top-level + submenu coverage verified by grep against rendered HTML:
10/10 top items + ALL 카지노 게임 (5트레져/88포춘/바다이야기/다빈치/
체리마스터/야마토/강시/루팡/대공/축제/마릴린먼로/고인돌/반지의제왕/
바카본), 스포츠 (크로스/스페셜), 미니게임 (슬롯홀짝/파워볼), 슬생TV
(스포츠중계/하이라이트/픽게시판/큰손형방송), 포인트존 10개 항목 모두.
## Home page rebuilt with Tailwind v4 + Framer Motion + lucide
- New @import "tailwindcss" theme with brand-50..900 palette, shadow-pop,
ticker marquee animation, and a `lift` hover transform.
- Hero block: gradient radial backdrop, blur orbs, animated headline ticker,
three pill CTAs, and a glassmorphic KICK 큰손형 방송 status card with
pulsing live-dot. Status pulled from getKickStatus() (live/break/offline
by hour & weekday).
- 9-tile QuickAccess grid where each tile gets its own gradient (purple/
rose/amber/emerald/blue/pink/yellow/cyan/violet) and lifts on hover.
- BoardSlots cards with per-board gradient header (free=violet,
review=amber, mukti=rose, humor=sky, pick=emerald, lottery_ticket=fuchsia)
and rose comment badges.
- Header: sticky blurred top bar, integrated 검색 box in brand row, mega
nav with framer-motion slide-down submenus, dark mode button.
- Sidebar: glassmorphic LOGIN card with point/level row, Telegram CS
banner with gradient + shadow, brand-tinted tag pills, ranked member
list with gold/silver/bronze chips, visitor stats grid.
- Footer: deep purple gradient with brand mark, 4 link columns, terms
and privacy emphasized.
## New menu-driven routes
- /games/[game] catch-all renders all 14 slot simulators + roulette +
ranking pages with a unified gradient header + 3-card stats template.
- /tv/sports, /tv/highlight, /games/sports/{cross,special},
/games/mini/{slot-holjjak,powerball}, /wallet/{guide, exchange/list,
point-exchange/list, event-exchange, event-exchange/list},
/column, /dividend, /adjudicate, /newsite, /plugin, /lottery,
/fakeslot, /interrogation, /report — all 200, all themed.
## Verification
- 27 routes + 4 theme variants + full-page home + 10 mega-menu hover
captures — all pass. PNGs under next-app/screenshots/.
96 lines
4.4 KiB
JavaScript
96 lines
4.4 KiB
JavaScript
import { chromium } from 'playwright';
|
|
import { mkdir } from 'node:fs/promises';
|
|
import { resolve } from 'node:path';
|
|
|
|
const OUT = resolve(process.cwd(), 'screenshots');
|
|
await mkdir(OUT, { recursive: true });
|
|
|
|
const PAGES = [
|
|
{ url: '/', name: '01-home' },
|
|
{ url: '/free', name: '02-board-free' },
|
|
{ url: '/free?page=2', name: '03-board-free-p2' },
|
|
{ url: '/login', name: '04-login' },
|
|
{ url: '/register', name: '05-register' },
|
|
{ url: '/auth/recover', name: '06-recover' },
|
|
{ url: '/help/qa', name: '07-qa' },
|
|
{ url: '/help/faq', name: '08-faq' },
|
|
{ url: '/wallet', name: '09-wallet' },
|
|
{ url: '/page/attendance', name: '10-attendance' },
|
|
{ url: '/games/bacara', name: '11-game-bacara' },
|
|
{ url: '/games/ranking', name: '12-rankings' },
|
|
{ url: '/new', name: '13-new-posts' },
|
|
{ url: '/tags', name: '14-tags' },
|
|
{ url: '/notice', name: '15-notice-board' },
|
|
{ url: '/page/provision', name: '16-terms' },
|
|
{ url: '/page/privacy', name: '17-privacy' },
|
|
{ url: '/admin/themes', name: '18-admin-themes' },
|
|
{ url: '/admin', name: '19-admin-dashboard', authed: true },
|
|
{ url: '/admin/members', name: '20-admin-members', authed: true },
|
|
{ url: '/admin/boards', name: '21-admin-boards', authed: true },
|
|
{ url: '/admin/betting', name: '22-admin-betting', authed: true },
|
|
{ url: '/admin/stats', name: '23-admin-stats', authed: true },
|
|
{ url: '/free/1024', name: '24-post-view' },
|
|
{ url: '/mypage', name: '25-mypage', authed: true },
|
|
{ url: '/games/roulette', name: '26-roulette' },
|
|
{ url: '/lottery_ticket', name: '27-lottery' },
|
|
];
|
|
|
|
const browser = await chromium.launch();
|
|
const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, locale: 'ko-KR' });
|
|
const page = await context.newPage();
|
|
|
|
// Pre-login as admin so authed routes can be visited
|
|
await page.goto('http://localhost:3000/login');
|
|
await page.fill('input[name="loginId"]', 'admin');
|
|
await page.fill('input[name="password"]', 'test1234');
|
|
await Promise.all([page.waitForURL((u) => u.pathname === '/'), page.click('button[type="submit"]')]).catch(() => {});
|
|
|
|
let okCount = 0, failCount = 0;
|
|
for (const p of PAGES) {
|
|
const url = `http://localhost:3000${p.url}`;
|
|
try {
|
|
const resp = await page.goto(url, { waitUntil: 'networkidle', timeout: 20_000 });
|
|
const status = resp ? resp.status() : 0;
|
|
await page.screenshot({ path: `${OUT}/${p.name}.png`, fullPage: false });
|
|
const title = await page.title();
|
|
console.log(`${status === 200 ? '✓' : '✗'} ${status} ${p.url} ${title.slice(0, 50)}`);
|
|
if (status === 200) okCount++; else failCount++;
|
|
} catch (e) {
|
|
console.log(`✗ ERR ${p.url} ${e.message?.slice(0, 80)}`);
|
|
failCount++;
|
|
}
|
|
}
|
|
|
|
// Also: theme switch screenshots
|
|
const THEMES = ['basic', 'eyoom', 'amina', 'youngcart'];
|
|
for (const t of THEMES) {
|
|
// set the cookie to override
|
|
await context.addCookies([{ name: 'slot_theme_pref', value: t, url: 'http://localhost:3000' }]);
|
|
await page.goto('http://localhost:3000/', { waitUntil: 'networkidle' });
|
|
await page.screenshot({ path: `${OUT}/theme-${t}-home.png`, fullPage: false });
|
|
console.log(`✓ theme=${t} home captured`);
|
|
}
|
|
|
|
// Capture full-page home + each top-level mega-menu opened
|
|
await context.addCookies([{ name: 'slot_theme_pref', value: 'eyoom', url: 'http://localhost:3000' }]);
|
|
await page.goto('http://localhost:3000/', { waitUntil: 'networkidle' });
|
|
await page.screenshot({ path: `${OUT}/home-full.png`, fullPage: true });
|
|
console.log('✓ home-full captured');
|
|
|
|
for (const label of ['보증사이트', '먹튀사이트', '커뮤니티', '이벤트', '슬생정보', '가품슬롯', '고객센터', '포인트게임', '슬생TV', '포인트존']) {
|
|
try {
|
|
await page.goto('http://localhost:3000/', { waitUntil: 'networkidle' });
|
|
const link = page.getByRole('link', { name: label, exact: true }).first();
|
|
await link.hover();
|
|
await page.waitForTimeout(400);
|
|
await page.screenshot({ path: `${OUT}/menu-${label}.png`, fullPage: false });
|
|
console.log('✓ menu', label);
|
|
} catch (e) {
|
|
console.log('✗ menu', label, e.message?.slice(0, 60));
|
|
}
|
|
}
|
|
|
|
await browser.close();
|
|
console.log(`\nDone. ${okCount} ok, ${failCount} fail. → ${OUT}`);
|
|
process.exit(failCount > 0 ? 1 : 0);
|