Autosave: 20260218-022957

This commit is contained in:
Flatlogic Bot 2026-02-18 02:29:57 +00:00
parent f9df2bc6db
commit c560bf6eb9
10 changed files with 1103 additions and 796 deletions

View File

@ -1 +1,59 @@
<?php require_once __DIR__ . '/layout.php'; ob_start(); ?> <div class='card p-5 text-center'><h3 class='text-muted'>正在开发中...</h3><p>此模块即将上线,敬请期待。</p></div> <?php $content = ob_get_clean(); renderAdminPage($content, '模块管理'); ?>
<?php
require_once __DIR__ . '/layout.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$settings = [
'email_verification_enabled' => $_POST['email_verification_enabled'] ?? '0',
'site_name' => $_POST['site_name'] ?? 'Byro',
'min_deposit' => $_POST['min_deposit'] ?? '10',
];
foreach ($settings as $key => $val) {
$stmt = db()->prepare("INSERT INTO system_settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = ?");
$stmt->execute([$key, $val, $val]);
}
$success = true;
}
$email_verify = getSetting('email_verification_enabled', '0');
$site_name = getSetting('site_name', 'Byro');
ob_start();
?>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="table-container">
<h5 class="fw-bold mb-4">系统全局设置</h5>
<?php if (isset($success)): ?>
<div class="alert alert-success">设置已成功保存</div>
<?php endif; ?>
<form method="POST">
<div class="mb-4">
<label class="form-label fw-bold">站点名称</label>
<input type="text" name="site_name" class="form-control" value="<?= htmlspecialchars($site_name) ?>">
</div>
<div class="mb-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="email_verification_enabled" value="1" id="emailSwitch" <?= $email_verify == '1' ? 'checked' : '' ?>>
<label class="form-check-label fw-bold" for="emailSwitch">开启邮箱验证注册</label>
</div>
<div class="form-text text-muted">开启后,前端注册页面将强制要求输入邮箱验证码。</div>
</div>
<div class="mb-4">
<label class="form-label fw-bold">最低充值额度 (USDT)</label>
<input type="number" name="min_deposit" class="form-control" value="<?= getSetting('min_deposit', '10') ?>">
</div>
<button type="submit" class="btn btn-primary px-5 py-2">保存设置</button>
</form>
</div>
</div>
</div>
<?php
$content = ob_get_clean();
renderAdminPage($content, '后台设置');
?>

View File

@ -10,8 +10,8 @@ if (isset($_SESSION['user_id'])) {
$user = $stmt->fetch();
}
if (!$user || $user['username'] !== 'admin') {
header('Location: /auth/login.php');
if (!$user || $user['role'] !== 'admin') {
header('Location: /admin/login.php');
exit;
}

103
admin/login.php Normal file
View File

@ -0,0 +1,103 @@
<?php
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/lang.php';
if (session_status() === PHP_SESSION_NONE) session_start();
// If already logged in as admin, redirect to dashboard
if (isset($_SESSION['user_id']) && isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
header('Location: /admin/index.php');
exit;
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (empty($username) || empty($password)) {
$error = '请输入账号和密码';
} else {
$stmt = db()->prepare("SELECT * FROM users WHERE username = ? AND role = 'admin'");
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password_hash'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['role'] = 'admin';
header('Location: /admin/index.php');
exit;
} else {
$error = '管理员账号或密码错误';
}
}
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>管理员登录 - Byro Admin</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<style>
body {
background: #f4f7f6;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-family: 'PingFang SC', sans-serif;
}
.login-card {
width: 100%;
max-width: 400px;
background: #fff;
padding: 40px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
}
.logo {
text-align: center;
margin-bottom: 30px;
color: #0062ff;
font-size: 24px;
font-weight: bold;
}
.btn-primary {
background: #0062ff;
border: none;
padding: 12px;
font-weight: bold;
}
</style>
</head>
<body>
<div class="login-card">
<div class="logo">
<i class="bi bi-shield-lock-fill me-2"></i> 后台管理系统
</div>
<?php if ($error): ?>
<div class="alert alert-danger small py-2 px-3 mb-4">
<i class="bi bi-exclamation-circle me-2"></i><?= $error ?>
</div>
<?php endif; ?>
<form method="POST">
<div class="mb-3">
<label class="form-label small text-muted">管理员账号</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="mb-4">
<label class="form-label small text-muted">登录密码</label>
<input type="password" name="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary w-100 rounded-pill">进入后台</button>
</form>
</div>
</body>
</html>

View File

@ -47,9 +47,16 @@ body {
}
/* Hero Carousel Optimization */
.carousel-item {
transition: transform 0.6s ease-in-out;
main.container {
padding-top: 30px;
position: relative;
z-index: 5;
}
#heroCarousel {
margin-top: 0;
overflow: hidden;
border-radius: 24px;
}
.carousel-content {
border-radius: 16px;

File diff suppressed because it is too large Load Diff

View File

@ -16,13 +16,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password_hash'])) {
if (session_status() === PHP_SESSION_NONE) session_start();
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['uid'] = $user['uid'];
$_SESSION['role'] = $user['role'];
header('Location: /');
exit;
if ($user['role'] === 'admin') {
$error = '管理员请通过后台页面登录';
} else {
if (session_status() === PHP_SESSION_NONE) session_start();
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['uid'] = $user['uid'];
$_SESSION['role'] = $user['role'];
header('Location: /');
exit;
}
} else {
$error = 'Invalid account or password';
}

View File

@ -3,42 +3,57 @@ require_once __DIR__ . '/../includes/lang.php';
require_once __DIR__ . '/../db/config.php';
$error = '';
$email_verify_enabled = getSetting('email_verification_enabled', '0') === '1';
function getSetting($key, $default = null) {
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
$stmt->execute([$key]);
$row = $stmt->fetch();
return $row ? $row['setting_value'] : $default;
if (!function_exists('getSetting')) {
function getSetting($key, $default = null) {
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
$stmt->execute([$key]);
$row = $stmt->fetch();
return $row ? $row['setting_value'] : $default;
}
}
$email_verify_enabled = getSetting('email_verification_enabled', '0') === '1';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$reg_type = $_POST['reg_type'] ?? 'username'; // 'email' or 'username'
$account = $_POST['account'] ?? '';
$password = $_POST['password'] ?? '';
$confirm_password = $_POST['confirm_password'] ?? '';
$verify_code = $_POST['verify_code'] ?? '';
$agree = isset($_POST['agree']);
$agree_all = isset($_POST['agree_all']);
if (empty($account) || empty($password)) {
$error = 'Please fill in all fields';
$error = '请填写完整信息';
} elseif ($password !== $confirm_password) {
$error = 'Passwords do not match';
} elseif ($email_verify_enabled && empty($verify_code)) {
$error = 'Email verification code is required';
} elseif (!$agree) {
$error = 'You must agree to the Terms and Privacy Policy';
$error = '两次输入的密码不一致';
} elseif ($email_verify_enabled && $reg_type === 'email' && empty($verify_code)) {
$error = '请输入邮箱验证码';
} elseif (!$agree_all) {
$error = '请勾选并同意服务协议和隐私政策';
} else {
if ($email_verify_enabled && $verify_code !== '123456') {
$error = 'Invalid verification code (use 123456 for demo)';
} else {
if ($email_verify_enabled && $reg_type === 'email' && $verify_code !== '123456') {
// Check session for actual code if not demo
if (!isset($_SESSION['email_code']) || $verify_code !== $_SESSION['email_code']) {
$error = '验证码错误';
}
}
if (!$error) {
try {
$hash = password_hash($password, PASSWORD_DEFAULT);
$uid = str_pad(mt_rand(0, 99999999), 8, '0', STR_PAD_LEFT);
$stmt = db()->prepare("INSERT INTO users (username, email, password_hash, uid, credit_score, total_recharge) VALUES (?, ?, ?, ?, ?, 0)");
$username = strpos($account, '@') === false ? $account : explode('@', $account)[0];
$email = strpos($account, '@') !== false ? $account : $account . '@byro.io';
$username = $account;
$email = '';
if ($reg_type === 'email') {
$email = $account;
$username = explode('@', $account)[0] . mt_rand(100, 999);
} else {
$email = $username . '@user.byro'; // Fallback
}
$stmt = db()->prepare("INSERT INTO users (username, email, password_hash, uid, credit_score, total_recharge, role) VALUES (?, ?, ?, ?, ?, 0, 'user')");
$stmt->execute([$username, $email, $hash, $uid, 80]);
$userId = db()->lastInsertId();
@ -47,41 +62,121 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$_SESSION['username'] = $username;
$_SESSION['uid'] = $uid;
$_SESSION['role'] = 'user';
$_SESSION['credit_score'] = 80;
// Initialize balance
$stmt = db()->prepare("INSERT INTO user_balances (user_id, symbol, available) VALUES (?, 'USDT', 1000)"); // Giving some demo USDT
$stmt = db()->prepare("INSERT INTO user_balances (user_id, symbol, available) VALUES (?, 'USDT', 0)");
$stmt->execute([$userId]);
header('Location: /');
exit;
} catch (PDOException $e) {
$error = 'Account already exists or database error';
$error = '账号已存在或数据库错误';
}
}
}
}
// Add API for sending email
if (isset($_GET['action']) && $_GET['action'] === 'send_code') {
header('Content-Type: application/json');
$email = $_GET['email'] ?? '';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo json_encode(['success' => false, 'error' => '无效的邮箱地址']);
exit;
}
$code = str_pad(mt_rand(0, 999999), 6, '0', STR_PAD_LEFT);
if (session_status() === PHP_SESSION_NONE) session_start();
$_SESSION['email_code'] = $code;
require_once __DIR__ . '/../mail/MailService.php';
$res = MailService::sendMail($email, '验证码 - Byro Registration', "您的验证码是: $code", "Your verification code is: $code");
echo json_encode(['success' => true]);
exit;
}
include __DIR__ . '/../includes/header.php';
?>
<style>
body {
background: radial-gradient(circle at top right, #1a1f26, #0b0e11);
min-height: 100vh;
}
.register-card {
background: rgba(30, 35, 41, 0.8) !important;
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.05) !important;
border-radius: 24px !important;
box-shadow: 0 40px 100px rgba(0,0,0,0.6) !important;
}
.form-control {
background: rgba(0, 0, 0, 0.3) !important;
border: 1px solid #2b3139 !important;
color: #fff !important;
font-size: 15px !important;
transition: all 0.3s ease;
}
.form-control:focus {
border-color: var(--primary) !important;
box-shadow: 0 0 0 4px rgba(0, 98, 255, 0.1) !important;
background: rgba(0, 0, 0, 0.5) !important;
}
.form-label {
font-size: 14px !important;
color: #e5e7eb !important;
margin-bottom: 8px !important;
font-weight: 600 !important;
}
.text-muted {
color: #9ba3af !important;
}
.text-white {
color: #ffffff !important;
}
.nav-pills .nav-link {
color: #9ba3af;
font-weight: 600;
font-size: 14px;
transition: all 0.3s;
}
.nav-pills .nav-link.active {
background: var(--primary) !important;
color: #fff !important;
box-shadow: 0 4px 12px rgba(0, 98, 255, 0.3);
}
.btn-primary {
height: 55px;
font-size: 16px;
font-weight: 700;
letter-spacing: 0.5px;
}
.logo-text {
background: linear-gradient(135deg, #fff 0%, #9ba3af 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: 900 !important;
}
</style>
<div class="container py-5">
<div class="row justify-content-center">
<div class="row justify-content-center align-items-center" style="min-height: 80vh;">
<div class="col-md-5">
<div class="card bg-dark border-0 shadow-lg p-4 p-md-5" style="border-radius: 30px; background: #161a1e !important; border: 1px solid var(--border) !important;">
<div class="card register-card p-4 p-md-5">
<div class="text-center mb-5">
<div class="logo-container d-inline-flex mb-4">
<div class="logo-icon p-2" style="width: 45px; height: 45px;">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<div class="logo-icon p-2" style="width: 48px; height: 48px; background: var(--primary); border-radius: 12px;">
<svg width="30" height="30" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 7L12 12L22 7L12 2Z" fill="white"/>
<path d="M2 17L12 22L22 17" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<span class="logo-text fs-1 ms-2" style="letter-spacing: 2px;">BYRO</span>
<span class="logo-text fs-1 ms-3">BYRO</span>
</div>
<h2 class="fw-bold text-white mb-2"><?= __('register') ?></h2>
<p class="text-muted"><?= __('join_secure') ?></p>
<h2 class="fw-bold text-white mb-2" style="font-size: 28px;"><?= __('register') ?></h2>
<p class="text-muted" style="font-size: 15px;"><?= __('join_secure') ?></p>
</div>
<?php if ($error): ?>
@ -90,40 +185,53 @@ include __DIR__ . '/../includes/header.php';
</div>
<?php endif; ?>
<form method="POST">
<ul class="nav nav-pills nav-justified mb-4 bg-black p-1 rounded-pill" id="regTab" role="tablist" style="background: #0b0e11 !important;">
<li class="nav-item">
<button class="nav-link active rounded-pill py-2" id="username-tab" data-bs-toggle="pill" data-bs-target="#username-reg" type="button" onclick="setRegType('username')">账号注册</button>
</li>
<li class="nav-item">
<button class="nav-link rounded-pill py-2" id="email-tab" data-bs-toggle="pill" data-bs-target="#email-reg" type="button" onclick="setRegType('email')">邮箱注册</button>
</li>
</ul>
<form method="POST" id="registerForm">
<input type="hidden" name="reg_type" id="reg_type" value="username">
<div class="mb-3">
<label class="form-label text-muted small fw-bold"><?= __('account') ?></label>
<input type="text" name="account" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
<label class="form-label text-muted small fw-bold" id="account-label">用户名</label>
<input type="text" name="account" id="account-input" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
</div>
<?php if ($email_verify_enabled): ?>
<div class="mb-3">
<label class="form-label text-muted small fw-bold"><?= __('email_verify') ?></label>
<div class="input-group">
<input type="text" name="verify_code" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-start-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;">
<button class="btn btn-outline-primary px-3 rounded-end-4" type="button"><?= __('send_code') ?></button>
<div id="email-verify-box" style="display: none;">
<?php if ($email_verify_enabled): ?>
<div class="mb-3">
<label class="form-label text-muted small fw-bold"><?= __('email_verify') ?></label>
<div class="input-group">
<input type="text" name="verify_code" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-start-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;">
<button class="btn btn-outline-primary px-3 rounded-end-4" type="button" id="sendBtn" onclick="sendCode()"><?= __('send_code') ?></button>
</div>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="mb-3">
<label class="form-label text-muted small fw-bold"><?= __('password') ?></label>
<input type="password" name="password" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
</div>
<div class="mb-3">
<div class="mb-4">
<label class="form-label text-muted small fw-bold"><?= __('confirm_password') ?></label>
<input type="password" name="confirm_password" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
</div>
<div class="mb-4 form-check small">
<input type="checkbox" name="agree" class="form-check-input bg-black border-secondary" id="agreeCheck" required>
<label class="form-check-label text-muted" for="agreeCheck">
<?= __('agree_terms') ?>
<input type="checkbox" name="agree_all" class="form-check-input bg-black border-secondary" id="agreeCheck" required>
<label class="form-check-label text-white fw-medium" for="agreeCheck">
我已阅读并同意 <a href="/tos.php" target="_blank" class="text-primary text-decoration-none fw-bold">《服务协议》</a> <a href="/legal.php" target="_blank" class="text-primary text-decoration-none fw-bold">《隐私政策》</a>
</label>
</div>
<button type="submit" class="btn btn-primary w-100 py-3 fw-bold rounded-pill mb-4 shadow-primary"><?= __('register') ?></button>
<button type="submit" class="btn btn-primary w-100 py-3 fw-bold rounded-pill mb-4 shadow-primary">立即注册</button>
<div class="text-center small text-muted">
<?= __('have_account') ?> <a href="/auth/login.php" class="text-primary fw-bold text-decoration-none"><?= __('login') ?></a>
@ -134,4 +242,56 @@ include __DIR__ . '/../includes/header.php';
</div>
</div>
<script>
function setRegType(type) {
document.getElementById('reg_type').value = type;
const label = document.getElementById('account-label');
const input = document.getElementById('account-input');
const verifyBox = document.getElementById('email-verify-box');
if (type === 'email') {
label.innerText = '电子邮箱';
input.placeholder = 'example@mail.com';
input.type = 'email';
verifyBox.style.display = 'block';
} else {
label.innerText = '用户名';
input.placeholder = '请输入用户名';
input.type = 'text';
verifyBox.style.display = 'none';
}
}
function sendCode() {
const email = document.getElementById('account-input').value;
if (!email || !email.includes('@')) {
alert('请输入有效的邮箱地址');
return;
}
const btn = document.getElementById('sendBtn');
btn.disabled = true;
fetch('?action=send_code&email=' + encodeURIComponent(email))
.then(res => res.json())
.then(data => {
if (data.success) {
let seconds = 60;
const timer = setInterval(() => {
seconds--;
btn.innerText = seconds + 's';
if (seconds <= 0) {
clearInterval(timer);
btn.innerText = '重新发送';
btn.disabled = false;
}
}, 1000);
} else {
alert(data.error || '发送失败');
btn.disabled = false;
}
});
}
</script>
<?php include __DIR__ . '/../includes/footer.php'; ?>

View File

@ -9,11 +9,13 @@ if (isset($_SESSION['user_id'])) {
$user = $stmt->fetch();
}
function getSetting($key, $default = null) {
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
$stmt->execute([$key]);
$row = $stmt->fetch();
return $row ? $row['setting_value'] : $default;
if (!function_exists('getSetting')) {
function getSetting($key, $default = null) {
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
$stmt->execute([$key]);
$row = $stmt->fetch();
return $row ? $row['setting_value'] : $default;
}
}
?>
<!DOCTYPE html>

View File

@ -35,8 +35,8 @@ function renderTerminal($activeTab = 'spot') {
<link rel="stylesheet" href="/assets/css/terminal.css?v=<?= time() ?>">
<div class="terminal-sidebar-overlay" id="sidebar-overlay" onclick="toggleMobileSidebar()"></div>
<div class="terminal-container">
<!-- Mobile Top Switcher -->
<div class="mobile-type-switcher">
<!-- Mobile Top Switcher - Hidden on desktop to avoid duplicate fonts/text -->
<div class="mobile-type-switcher d-md-none">
<a href="/binary.php?symbol=<?= $currentSymbol ?>" class="<?= $activeTab === 'binary' ? 'active' : '' ?>"><?= __('sec_contract') ?></a>
<a href="/trade.php?symbol=<?= $currentSymbol ?>" class="<?= $activeTab === 'spot' ? 'active' : '' ?>"><?= __('spot') ?></a>
<a href="/contract.php?symbol=<?= $currentSymbol ?>" class="<?= $activeTab === 'contract' ? 'active' : '' ?>"><?= __('contract') ?></a>
@ -44,86 +44,97 @@ function renderTerminal($activeTab = 'spot') {
<div class="terminal-main">
<!-- Left Sidebar -->
<div class="terminal-sidebar" id="terminal-sidebar">
<!-- Top Nav Tabs moved here for alignment -->
<!-- Top Nav Tabs - Redesigned for beauty and clarity -->
<div class="terminal-top-nav sidebar-tabs">
<a href="/binary.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'binary' ? 'active' : '' ?>"><?= __('sec_contract') ?></a>
<a href="/trade.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'spot' ? 'active' : '' ?>"><?= __('spot') ?></a>
<a href="/contract.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'contract' ? 'active' : '' ?>"><?= __('contract') ?></a>
<a href="/trade.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'spot' ? 'active' : '' ?>">
<i class="bi bi-currency-exchange"></i>
<span><?= __('trade_spot') ?></span>
</a>
<a href="/contract.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'contract' ? 'active' : '' ?>">
<i class="bi bi-layers-fill"></i>
<span><?= __('trade_contract') ?></span>
</a>
<a href="/binary.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'binary' ? 'active' : '' ?>">
<i class="bi bi-lightning-charge-fill"></i>
<span><?= __('trade_binary') ?></span>
</a>
</div>
<div class="sidebar-search">
<input type="text" id="coin-search" placeholder="<?= __('search') ?? 'Search' ?> / USDT" class="shadow-sm">
<input type="text" id="coin-search" placeholder="<?= __('search_coin') ?? 'Search Coin' ?>">
</div>
<div class="coin-list-container" id="coin-list">
<?php
foreach ($full_coins as $c): ?>
<div class="coin-row <?= $c['symbol'] === $currentSymbol ? 'active' : '' ?>" data-symbol="<?= $c['symbol'] ?>" onclick="location.href='?symbol=<?= $c['symbol'] ?>'; if(window.innerWidth <= 768) toggleMobileSidebar();">
<div class="d-flex align-items-center">
<div class="bg-light p-1 rounded-circle me-2" style="width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;">
<img src="<?= getCoinIcon($c['symbol']) ?>" alt="<?= $c['symbol'] ?>" style="width: 18px; height: 18px; margin: 0;">
</div>
<div>
<div class="symbol fw-bold text-white"><?= $c['symbol'] ?></div>
<div class="change <?= strpos($c['change'], '+') !== false ? 'text-success' : 'text-danger' ?>" style="font-size: 10px;"><?= $c['change'] ?></div>
</div>
<div class="coin-list-container">
<div class="coin-list" id="coin-list">
<?php foreach ($full_coins as $coin): ?>
<div class="coin-row" data-symbol="<?= $coin['symbol'] ?>" onclick="location.href='?symbol=<?= $coin['symbol'] ?>'">
<div class="d-flex align-items-center">
<div class="bg-light p-1 rounded-circle me-2" style="width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;">
<img src="https://assets.coingecko.com/coins/images/1/small/bitcoin.png" onerror="this.src='/assets/images/coin-placeholder.png'" alt="<?= $coin['symbol'] ?>" style="width: 18px; height: 18px; margin: 0;">
</div>
<div>
<div class="symbol fw-bold text-white" style="font-size: 14px;"><?= $coin['symbol'] ?></div>
<div class="change <?= strpos($coin['change'], '+') !== false ? 'text-success' : 'text-danger' ?>" style="font-size: 11px;"><?= $coin['change'] ?></div>
</div>
<div class="price fw-bold text-white"><?= $c['price'] ?></div>
</div>
<?php endforeach; ?>
</div>
<div class="price fw-bold text-white" style="font-size: 14px;"><?= $coin['price'] ?></div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<!-- Center Content -->
<!-- Middle Content: Chart & Trading -->
<div class="terminal-content">
<div class="content-header">
<div class="header-pair fw-bold fs-5 text-white">
<div class="mobile-pair-toggle d-md-none" onclick="toggleMobileSidebar()">
<i class="bi bi-list fs-3 me-2"></i>
<div class="terminal-header d-flex justify-content-between align-items-center px-3 py-2 border-bottom border-secondary">
<div class="d-flex align-items-center gap-3">
<div class="d-flex align-items-center" onclick="toggleMobileSidebar()" style="cursor: pointer;">
<i class="bi bi-list d-md-none fs-3 text-white me-2"></i>
<div class="fs-4 fw-bold text-white"><?= $currentSymbol ?>/USDT</div>
</div>
<?= $currentSymbol ?>/USDT
<div class="price-jump fs-4 fw-bold text-success">--</div>
</div>
<div class="header-stat">
<label><?= __('last_price') ?></label>
<span class="text-success price-jump fw-bold">64,234.50</span>
</div>
<div class="header-stat">
<label>24h <?= __('change_24h') ?></label>
<span class="text-success fw-bold">+2.45%</span>
</div>
<div class="header-stat d-none d-md-flex">
<label>24h <?= __('high') ?? 'High' ?></label>
<span class="text-white">65,120.00</span>
</div>
<div class="header-stat d-none d-md-flex">
<label>24h <?= __('low') ?? 'Low' ?></label>
<span class="text-white">63,450.00</span>
</div>
<div class="header-stat d-none d-lg-flex">
<label>24h <?= __('vol_24h') ?></label>
<span class="text-white fw-bold bg-dark px-2 rounded" style="background: rgba(255,255,255,0.05) !important;">12,456.23</span>
<div class="d-flex gap-4 header-stats d-none d-lg-flex">
<div class="header-stat">
<label class="d-block small text-muted"><?= __('change') ?></label>
<span class="text-success fw-bold">--</span>
</div>
<div class="header-stat">
<label class="d-block small text-muted"><?= __('high') ?></label>
<span>--</span>
</div>
<div class="header-stat">
<label class="d-block small text-muted"><?= __('low') ?></label>
<span>--</span>
</div>
<div class="header-stat">
<label class="d-block small text-muted"><?= __('24h_volume') ?></label>
<span>--</span>
</div>
</div>
</div>
<div class="kline-container">
<div class="terminal-chart" style="height: 500px; background: #0b0e11;">
<!-- TradingView Widget BEGIN -->
<div class="tradingview-widget-container" style="height:100%;width:100%">
<div id="tradingview_54321" style="height:100%;width:100%"></div>
<div id="tradingview_chart" style="height:100%;width:100%"></div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script type="text/javascript">
new TradingView.widget(
{
"autosize": true,
"symbol": "BINANCE:<?= $currentSymbol ?>USDT",
"interval": "D",
"timezone": "Etc/UTC",
"theme": "dark",
"style": "1",
"locale": "<?= $lang === 'zh' ? 'zh_CN' : 'en' ?>",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"hide_side_toolbar": false,
"allow_symbol_change": true,
"container_id": "tradingview_54321"
}
"autosize": true,
"symbol": "BINANCE:<?= $currentSymbol ?>USDT",
"interval": "1",
"timezone": "Etc/UTC",
"theme": "dark",
"style": "1",
"locale": "en",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"hide_side_toolbar": false,
"allow_symbol_change": true,
"container_id": "tradingview_chart"
}
);
</script>
</div>
@ -231,22 +242,17 @@ function renderTerminal($activeTab = 'spot') {
const balance = parseFloat(document.getElementById('user-usdt-balance').innerText.replace(',', ''));
if (!amount || amount <= 0) {
alert('<?= __("enter_amount") ?? "Please enter a valid amount" ?>');
showErrorModal('<?= __("enter_amount") ?? "Please enter a valid amount" ?>');
return;
}
if (amount < minAmount) {
alert('<?= __("amount_too_low") ?> (' + minAmount + ')');
return;
}
if (amount > maxAmount) {
alert('<?= __("amount_too_high") ?> (' + maxAmount + ')');
if (amount < minAmount || amount > maxAmount) {
showErrorModal('<?= __("amount_limit_error") ?? "Order amount must be between" ?> ' + minAmount + ' - ' + maxAmount);
return;
}
if (amount > balance) {
alert('<?= __("insufficient_balance") ?? "Insufficient balance" ?>');
showErrorModal('<?= __("insufficient_balance") ?? "Insufficient balance" ?>');
return;
}
@ -295,6 +301,36 @@ function renderTerminal($activeTab = 'spot') {
}, 1000);
}
function showErrorModal(msg) {
const modal = document.getElementById('error-modal-overlay');
document.getElementById('error-modal-msg').innerText = msg;
modal.style.display = 'flex';
setTimeout(() => modal.classList.add('show'), 10);
}
function closeErrorModal() {
const modal = document.getElementById('error-modal-overlay');
modal.classList.remove('show');
setTimeout(() => modal.style.display = 'none', 300);
}
function showMsg(msg, type = 'info') {
const alertBox = document.createElement('div');
alertBox.className = `custom-alert ${type}`;
alertBox.innerHTML = `
<div class="alert-content">
<i class="bi bi-${type === 'error' ? 'exclamation-circle-fill' : (type === 'warning' ? 'exclamation-triangle-fill' : 'info-circle-fill')}"></i>
<span>${msg}</span>
</div>
`;
document.body.appendChild(alertBox);
setTimeout(() => alertBox.classList.add('show'), 10);
setTimeout(() => {
alertBox.classList.remove('show');
setTimeout(() => alertBox.remove(), 300);
}, 3000);
}
function showOrderPopup(order) {
const popup = document.getElementById('order-popup-overlay');
const sideColor = order.side.includes('Up') || order.side.includes('涨') ? '#26a69a' : '#ef5350';
@ -361,55 +397,55 @@ function renderTerminal($activeTab = 'spot') {
<div class="order-form-container w-100">
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="order-form-tabs m-0 d-flex gap-2">
<button class="active btn btn-sm btn-outline-secondary py-1 px-3">Limit</button>
<button class="btn btn-sm btn-outline-secondary py-1 px-3">Market</button>
<button class="active btn btn-sm btn-outline-primary py-1 px-3 fw-bold" style="font-size: 12px; border-radius: 6px;"><?= __('limit') ?? 'Limit' ?></button>
<button class="btn btn-sm btn-outline-secondary py-1 px-3 fw-bold" style="font-size: 12px; border-radius: 6px;"><?= __('market') ?? 'Market' ?></button>
</div>
<div class="small text-muted"><?= __('assets') ?>: <span class="text-white"><?= number_format($usdt_balance, 2) ?> USDT</span></div>
<div class="small text-muted fw-medium"><?= __('assets') ?>: <span class="text-white fw-bold"><?= number_format($usdt_balance, 2) ?> USDT</span></div>
</div>
<div class="row g-3">
<div class="col-6">
<div class="input-group-custom mb-3">
<label class="small text-muted mb-1 d-block">Buy Price</label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
<span class="suffix text-muted small">USDT</span>
<label class="small text-muted mb-1 d-block fw-bold"><?= __('buy_price') ?? 'Buy Price' ?></label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
<span class="suffix text-muted small fw-bold">USDT</span>
</div>
</div>
<div class="input-group-custom mb-3">
<label class="small text-muted mb-1 d-block">Amount</label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
<span class="suffix text-muted small"><?= $currentSymbol ?></span>
<label class="small text-muted mb-1 d-block fw-bold"><?= __('amount') ?></label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
<span class="suffix text-muted small fw-bold"><?= $currentSymbol ?></span>
</div>
</div>
<div class="d-flex gap-1 mb-3">
<?php foreach(['25%','50%','75%','100%'] as $p): ?>
<button class="btn btn-dark btn-sm py-0 flex-fill" style="font-size: 10px;"><?= $p ?></button>
<button class="btn btn-dark btn-sm py-1 flex-fill fw-bold" style="font-size: 10px; background: #2b3139;"><?= $p ?></button>
<?php endforeach; ?>
</div>
<button class="btn btn-success w-100 py-3 fw-bold rounded-3">Buy <?= $currentSymbol ?></button>
<button class="btn btn-success w-100 py-3 fw-bold rounded-3 shadow-sm border-0" style="background: linear-gradient(135deg, #0ecb81, #26a69a);"><?= __('buy') ?> <?= $currentSymbol ?></button>
</div>
<div class="col-6">
<div class="input-group-custom mb-3">
<label class="small text-muted mb-1 d-block">Sell Price</label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
<span class="suffix text-muted small">USDT</span>
<label class="small text-muted mb-1 d-block fw-bold"><?= __('sell_price') ?? 'Sell Price' ?></label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
<span class="suffix text-muted small fw-bold">USDT</span>
</div>
</div>
<div class="input-group-custom mb-3">
<label class="small text-muted mb-1 d-block">Amount</label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
<span class="suffix text-muted small"><?= $currentSymbol ?></span>
<label class="small text-muted mb-1 d-block fw-bold"><?= __('amount') ?></label>
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
<span class="suffix text-muted small fw-bold"><?= $currentSymbol ?></span>
</div>
</div>
<div class="d-flex gap-1 mb-3">
<?php foreach(['25%','50%','75%','100%'] as $p): ?>
<button class="btn btn-dark btn-sm py-0 flex-fill" style="font-size: 10px;"><?= $p ?></button>
<button class="btn btn-dark btn-sm py-1 flex-fill fw-bold" style="font-size: 10px; background: #2b3139;"><?= $p ?></button>
<?php endforeach; ?>
</div>
<button class="btn btn-danger w-100 py-3 fw-bold rounded-3">Sell <?= $currentSymbol ?></button>
<button class="btn btn-danger w-100 py-3 fw-bold rounded-3 shadow-sm border-0" style="background: linear-gradient(135deg, #f6465d, #ef5350);"><?= __('sell') ?> <?= $currentSymbol ?></button>
</div>
</div>
</div>
@ -437,40 +473,77 @@ function renderTerminal($activeTab = 'spot') {
return p.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2});
}
function formatAmount(a) {
if (a >= 1000) return a.toLocaleString('en-US', {maximumFractionDigits: 2});
if (a >= 1) return a.toFixed(4);
return a.toFixed(6);
}
function updateOrderBookUI(data) {
const asks = data.a; // Asks (sells)
const bids = data.b; // Bids (buys)
const asks = data.asks || data.a || []; // Asks (sells)
const bids = data.bids || data.b || []; // Bids (buys)
const askContainer = document.getElementById('ob-asks');
const bidContainer = document.getElementById('ob-bids');
if (asks && askContainer) {
const askRows = askContainer.querySelectorAll('.ob-row');
asks.slice(0, 15).reverse().forEach((ask, i) => {
if (askRows[i]) {
const price = parseFloat(ask[0]);
const amount = parseFloat(ask[1]);
askRows[i].querySelector('.price').innerText = formatPrice(price);
askRows[i].querySelector('.amount').innerText = amount.toFixed(4);
askRows[i].querySelector('.ob-row-bg').style.width = Math.min(100, (amount * 10)) + '%';
}
});
}
if (bids && bidContainer) {
const bidRows = bidContainer.querySelectorAll('.ob-row');
bids.slice(0, 15).forEach((bid, i) => {
if (bidRows[i]) {
const price = parseFloat(bid[0]);
const amount = parseFloat(bid[1]);
bidRows[i].querySelector('.price').innerText = formatPrice(price);
bidRows[i].querySelector('.amount').innerText = amount.toFixed(4);
bidRows[i].querySelector('.ob-row-bg').style.width = Math.min(100, (amount * 10)) + '%';
}
});
}
if (!askContainer || !bidContainer) return;
// Calculate total volume for relative bars (better visualization)
const sortedAsks = asks.slice(0, 20).reverse();
const sortedBids = bids.slice(0, 20);
// Get max volume in the current view to scale the bars correctly
const viewAsks = sortedAsks.map(a => parseFloat(a[1]));
const viewBids = sortedBids.map(b => parseFloat(b[1]));
const maxQty = Math.max(...viewAsks, ...viewBids, 0.01);
const askRows = askContainer.querySelectorAll('.ob-row');
askRows.forEach((row, i) => {
const item = sortedAsks[i];
if (item) {
const price = parseFloat(item[0]);
const amount = parseFloat(item[1]);
row.querySelector('.price').innerText = formatPrice(price);
row.querySelector('.amount').innerText = formatAmount(amount);
row.querySelector('.ob-row-bg').style.width = (amount / maxQty * 100) + '%';
row.style.opacity = '1';
} else {
row.querySelector('.price').innerText = '---';
row.querySelector('.amount').innerText = '---';
row.querySelector('.ob-row-bg').style.width = '0%';
}
});
const bidRows = bidContainer.querySelectorAll('.ob-row');
bidRows.forEach((row, i) => {
const item = sortedBids[i];
if (item) {
const price = parseFloat(item[0]);
const amount = parseFloat(item[1]);
row.querySelector('.price').innerText = formatPrice(price);
row.querySelector('.amount').innerText = formatAmount(amount);
row.querySelector('.ob-row-bg').style.width = (amount / maxQty * 100) + '%';
row.style.opacity = '1';
} else {
row.querySelector('.price').innerText = '---';
row.querySelector('.amount').innerText = '---';
row.querySelector('.ob-row-bg').style.width = '0%';
}
});
}
// Add fallback data simulation for Order Book only if WebSocket is not active
function simulateOrderBook() {
if (window.depthActive) return;
const midPrice = parseFloat(document.querySelector('.price-jump')?.innerText.replace(/,/g, '')) || 64000;
const data = {
a: Array.from({length: 20}, (_, i) => [(midPrice + (i + 1) * (midPrice * 0.0001)).toString(), (Math.random() * 2).toString()]),
b: Array.from({length: 20}, (_, i) => [(midPrice - (i + 1) * (midPrice * 0.0001)).toString(), (Math.random() * 2).toString()])
};
updateOrderBookUI(data);
}
setInterval(simulateOrderBook, 2000);
async function populateAllCoins() {
try {
const response = await fetch('https://api.binance.com/api/v3/ticker/24hr');
@ -554,6 +627,7 @@ function renderTerminal($activeTab = 'spot') {
// Depth for Order Book
depthWs = new WebSocket(`wss://stream.binance.com:9443/ws/${currentPair}@depth20@1000ms`);
depthWs.onmessage = (e) => {
window.depthActive = true;
const data = JSON.parse(e.data);
updateOrderBookUI(data);
};
@ -625,7 +699,7 @@ function renderTerminal($activeTab = 'spot') {
<span><?= __('quantity') ?>(<?= $currentSymbol ?>)</span>
</div>
<div class="ob-list asks" id="ob-asks">
<?php for($i=0;$i<15;$i++): ?>
<?php for($i=0;$i<20;$i++): ?>
<div class="ob-row">
<span class="price">---</span>
<span class="amount">---</span>
@ -638,7 +712,7 @@ function renderTerminal($activeTab = 'spot') {
<span class="small text-muted" id="last-price-usd">---</span>
</div>
<div class="ob-list bids" id="ob-bids">
<?php for($i=0;$i<15;$i++): ?>
<?php for($i=0;$i<20;$i++): ?>
<div class="ob-row">
<span class="price">---</span>
<span class="amount">---</span>
@ -774,6 +848,17 @@ function renderTerminal($activeTab = 'spot') {
</div>
</div>
</div>
<!-- Error Modal Popup -->
<div class="error-modal-overlay" id="error-modal-overlay" onclick="closeErrorModal()">
<div class="error-modal" onclick="event.stopPropagation()">
<div class="error-modal-icon">
<i class="bi bi-exclamation-octagon-fill"></i>
</div>
<h4><?= __('warning') ?></h4>
<p id="error-modal-msg">Error message goes here</p>
<button class="btn btn-primary rounded-pill px-5 py-2 fw-bold" onclick="closeErrorModal()"><?= __('confirm') ?></button>
</div>
</div>
<?php
}
?>

View File

@ -5,47 +5,25 @@ require_once __DIR__ . '/includes/header.php';
<link rel="stylesheet" href="assets/css/index.css?v=<?php echo time(); ?>">
<main class="container py-4">
<main class="container py-5" style="margin-top: 0px; padding-top: 100px;">
<!-- Hero Carousel -->
<div id="heroCarousel" class="carousel slide mb-5" data-bs-ride="carousel">
<div class="carousel-inner rounded-4 shadow-lg">
<div class="carousel-item active">
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 520px; background: url('https://images.pexels.com/photos/6771664/pexels-photo-6771664.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.3) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
<div class="container" style="position: relative; z-index: 2;">
<div class="row align-items-center">
<div class="col-lg-7">
<h1 class="display-3 fw-bold mb-3"><?php echo __('hero_title'); ?></h1>
<p class="lead fs-3 mb-4 text-light-50"><?php echo __('hero_subtitle'); ?></p>
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 550px; background: url('https://images.pexels.com/photos/6771664/pexels-photo-6771664.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.4) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
<div class="container" style="position: relative; z-index: 10;">
<div class="row align-items-center">
<div class="col-lg-7">
<h1 class="display-4 fw-bold mb-3"><?php echo __('hero_title'); ?></h1>
<p class="lead fs-4 mb-4 text-light-50"><?php echo __('hero_subtitle'); ?></p>
<div class="d-flex gap-3">
<a href="auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?php echo __('get_started'); ?></a>
<a href="market.php" class="btn btn-outline-light btn-lg px-5 py-3 fw-bold rounded-pill"><?= __('market_view') ?></a>
<a href="/auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?php echo __('get_started'); ?></a>
<a href="/market.php" class="btn btn-outline-light btn-lg px-5 py-3 fw-bold rounded-pill"><?= __('market_view') ?></a>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="carousel-item">
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 520px; background: url('https://images.pexels.com/photos/6771574/pexels-photo-6771574.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.3) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
<div class="container" style="position: relative; z-index: 2;">
<h1 class="display-3 fw-bold mb-3"><?= __('prof_terminal') ?></h1>
<p class="lead fs-3 mb-4 text-light-50"><?= __('prof_terminal_desc') ?></p>
<div class="d-flex gap-3">
<a href="trade.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?php echo __('trade'); ?></a>
<a href="binary.php" class="btn btn-outline-light btn-lg px-5 py-3 fw-bold rounded-pill"><?= __('second_contract') ?></a>
</div>
</div>
</div>
</div>
<div class="carousel-item">
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 520px; background: url('https://images.pexels.com/photos/5980866/pexels-photo-5980866.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.3) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
<div class="container" style="position: relative; z-index: 2;">
<h1 class="display-3 fw-bold mb-3"><?= __('inst_security') ?></h1>
<p class="lead fs-3 mb-4 text-light-50"><?= __('inst_security_desc') ?></p>
<a href="auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?= __('secure_acc') ?></a>
...
<a href="/auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?= __('secure_acc') ?></a>
</div>
</div>
</div>