New Vesion Aslam

This commit is contained in:
Flatlogic Bot 2026-02-24 23:03:19 +00:00
parent 4f61082b27
commit 7cb17c6136
19 changed files with 780 additions and 160 deletions

View File

@ -90,7 +90,7 @@ class AdminController extends Controller {
$status = $_POST['status'] ?? 'published';
$is_vip = isset($_POST['is_vip']) ? 1 : 0;
$icon_path = $this->handleUpload('icon_file');
$icon_path = $this->handleUpload('icon_file', true);
$db = db_pdo();
$stmt = $db->prepare("INSERT INTO apks (title, slug, description, version, image_url, icon_path, download_url, category_id, status, is_vip, display_order) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)");
@ -121,7 +121,7 @@ class AdminController extends Controller {
$db = db_pdo();
$apk = $db->query("SELECT * FROM apks WHERE id = " . $params['id'])->fetch();
$icon_path = $this->handleUpload('icon_file') ?: $apk['icon_path'];
$icon_path = $this->handleUpload('icon_file', true) ?: $apk['icon_path'];
$stmt = $db->prepare("UPDATE apks SET title = ?, description = ?, version = ?, image_url = ?, icon_path = ?, download_url = ?, category_id = ?, status = ?, is_vip = ? WHERE id = ?");
$stmt->execute([$title, $description, $version, $image_url, $icon_path, $download_url, $category_id, $status, $is_vip, $params['id']]);
@ -141,7 +141,7 @@ class AdminController extends Controller {
echo json_encode(['success' => true]);
}
private function handleUpload($field) {
private function handleUpload($field, $compress = false) {
if (!isset($_FILES[$field]) || $_FILES[$field]['error'] !== UPLOAD_ERR_OK) {
return null;
}
@ -155,13 +155,61 @@ class AdminController extends Controller {
$fileName = uniqid() . '.' . $ext;
$targetPath = $uploadDir . $fileName;
if (move_uploaded_file($_FILES[$field]['tmp_name'], $targetPath)) {
return $targetPath;
if ($compress) {
if (compress_image($_FILES[$field]['tmp_name'], $targetPath, 75)) {
return $targetPath;
}
} else {
if (move_uploaded_file($_FILES[$field]['tmp_name'], $targetPath)) {
return $targetPath;
}
}
return null;
}
// Settings Management
public function settingsForm() {
$this->checkAuth();
$settings = [
'site_name' => get_setting('site_name'),
'site_icon' => get_setting('site_icon'),
'site_favicon' => get_setting('site_favicon'),
'meta_description' => get_setting('meta_description'),
'meta_keywords' => get_setting('meta_keywords'),
'head_js' => get_setting('head_js'),
'body_js' => get_setting('body_js'),
];
$this->view('admin/settings', ['settings' => $settings]);
}
public function saveSettings() {
$this->checkAuth();
$db = db_pdo();
$fields = ['site_name', 'meta_description', 'meta_keywords', 'head_js', 'body_js'];
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = ?");
$stmt->execute([$_POST[$field], $field]);
}
}
$site_icon = $this->handleUpload('site_icon_file');
if ($site_icon) {
$stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'site_icon'");
$stmt->execute([$site_icon]);
}
$site_favicon = $this->handleUpload('site_favicon_file');
if ($site_favicon) {
$stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'site_favicon'");
$stmt->execute([$site_favicon]);
}
$this->redirect('/admin/settings');
}
// Category Management
public function categories() {
$this->checkAuth();
@ -207,7 +255,6 @@ class AdminController extends Controller {
public function rejectWithdrawal($params) {
$this->checkAuth();
$db = db_pdo();
// Refund balance if rejected? The user didn't specify, but let's do it for fairness
$wd = $db->query("SELECT * FROM withdrawals WHERE id = " . $params['id'])->fetch();
if ($wd && $wd['status'] === 'pending') {
$stmt = $db->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");

View File

@ -17,7 +17,8 @@ class AuthController extends Controller {
if (isset($_SESSION['user_id'])) {
$this->redirect('/profile');
}
$ref = $_GET['ref'] ?? '';
// Check GET first, then Session
$ref = $_GET['ref'] ?? ($_SESSION['global_ref'] ?? '');
$this->view('auth/register', ['ref' => $ref]);
}

View File

@ -16,6 +16,11 @@ class HomeController extends Controller {
$db = db_pdo();
$category = $_GET['category'] ?? null;
// Store global referral code if present
if (isset($_GET['ref'])) {
$_SESSION['global_ref'] = $_GET['ref'];
}
$sql = "SELECT * FROM apks WHERE status = 'published'";
$params = [];
@ -32,7 +37,7 @@ class HomeController extends Controller {
return $this->view('home', [
'apks' => $apks,
'title' => 'ApkNusa - Professional APK Download Portal'
'title' => get_setting('site_name', 'ApkNusa') . ' - Professional APK Download Portal'
]);
}
@ -47,12 +52,17 @@ class HomeController extends Controller {
$this->redirect('/');
}
// Store referral code if present
// Store referral code if present specifically for this APK
if (isset($_GET['ref'])) {
$_SESSION['ref_download_' . $apk['id']] = $_GET['ref'];
}
$this->view('apk_detail', ['apk' => $apk]);
$this->view('apk_detail', [
'apk' => $apk,
'title' => 'Download ' . $apk['title'] . ' ' . $apk['version'] . ' - ' . get_setting('site_name', 'ApkNusa'),
'meta_description' => 'Download ' . $apk['title'] . ' ' . $apk['version'] . ' APK for free. ' . substr(strip_tags($apk['description']), 0, 150) . '...',
'meta_keywords' => $apk['title'] . ', ' . $apk['title'] . ' apk, download ' . $apk['title']
]);
}
public function download($params) {
@ -67,7 +77,9 @@ class HomeController extends Controller {
}
// Check for referral earnings
$ref_code = $_SESSION['ref_download_' . $apk['id']] ?? null;
// Try specific APK referral first, then global referral
$ref_code = $_SESSION['ref_download_' . $apk['id']] ?? ($_SESSION['global_ref'] ?? null);
if ($ref_code) {
$stmt = $db->prepare("SELECT id FROM users WHERE referral_code = ?");
$stmt->execute([$ref_code]);
@ -91,7 +103,8 @@ class HomeController extends Controller {
$stmt->execute([$referrer_id, $apk['id'], $ip]);
}
}
// Clear session after processing
// Clear session specific to this APK, but maybe keep global_ref?
// The user might download other APKs too.
unset($_SESSION['ref_download_' . $apk['id']]);
}
@ -102,4 +115,4 @@ class HomeController extends Controller {
// Redirect to actual file
$this->redirect($apk['download_url']);
}
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\Controllers;
use App\Core\Controller;
use App\Services\ApkService;
class SitemapController extends Controller {
public function index() {
$apkService = new ApkService();
$apks = $apkService->getAllApks();
$db = db_pdo();
$categories = $db->query("SELECT * FROM categories")->fetchAll();
header("Content-Type: application/xml; charset=utf-8");
$baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]";
echo '<?xml version="1.0" encoding="UTF-8"?>';
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
// Home
echo '<url>';
echo '<loc>' . $baseUrl . '/</loc>';
echo '<priority>1.0</priority>';
echo '<changefreq>daily</changefreq>';
echo '</url>';
// APKs
foreach ($apks as $apk) {
echo '<url>';
echo '<loc>' . $baseUrl . '/apk/' . htmlspecialchars($apk['slug']) . '</loc>';
echo '<lastmod>' . date('Y-m-d', strtotime($apk['created_at'] ?? 'now')) . '</lastmod>';
echo '<priority>0.8</priority>';
echo '<changefreq>weekly</changefreq>';
echo '</url>';
}
// Categories (if you have category pages, assuming /category/slug)
foreach ($categories as $category) {
echo '<url>';
echo '<loc>' . $baseUrl . '/category/' . htmlspecialchars($category['slug']) . '</loc>';
echo '<priority>0.6</priority>';
echo '<changefreq>weekly</changefreq>';
echo '</url>';
}
echo '</urlset>';
}
}

View File

@ -2,15 +2,49 @@
use App\Services\LanguageService;
function lang($key) {
return LanguageService::translate($key);
}
function asset($path) {
return '/' . ltrim($path, '/');
}
function db_pdo() {
require_once __DIR__ . '/../../db/config.php';
return db();
}
function view($view, $data = []) {
extract($data);
$viewPath = __DIR__ . '/../../views/' . $view . '.php';
if (file_exists($viewPath)) {
require $viewPath;
} else {
echo "View $view not found";
}
}
function redirect($path) {
header("Location: $path");
exit;
}
function __($key, $default = null) {
return LanguageService::translate($key, $default);
}
function get_setting($key, $default = '') {
$db = db();
$stmt = $db->prepare("SELECT setting_value FROM settings WHERE setting_key = ?");
$stmt->execute([$key]);
$result = $stmt->fetch();
return $result ? $result['setting_value'] : $default;
}
function compress_image($source, $destination, $quality) {
$info = getimagesize($source);
if ($info['mime'] == 'image/jpeg') {
$image = imagecreatefromjpeg($source);
} elseif ($info['mime'] == 'image/gif') {
$image = imagecreatefromgif($source);
} elseif ($info['mime'] == 'image/png') {
$image = imagecreatefrompng($source);
} else {
return false;
}
imagejpeg($image, $destination, $quality);
return $destination;
}

View File

@ -3,8 +3,43 @@
namespace App\Services;
class LanguageService {
public static function translate($key) {
// Mock translation
return $key;
private static $translations = [];
private static $lang = 'id';
public static function init() {
if (isset($_SESSION['lang'])) {
self::$lang = $_SESSION['lang'];
} elseif (isset($_COOKIE['lang'])) {
self::$lang = $_COOKIE['lang'];
}
$langFile = __DIR__ . '/../../lang/' . self::$lang . '.php';
if (file_exists($langFile)) {
self::$translations = require $langFile;
} else {
// Default to English if the translation file doesn't exist
self::$lang = 'en';
$langFile = __DIR__ . '/../../lang/' . self::$lang . '.php';
if (file_exists($langFile)) {
self::$translations = require $langFile;
}
}
}
}
public static function translate($key, $default = null) {
if (empty(self::$translations)) {
self::init();
}
return self::$translations[$key] ?? ($default ?? $key);
}
public static function setLang($lang) {
self::$lang = $lang;
$_SESSION['lang'] = $lang;
setcookie('lang', $lang, time() + (86400 * 30), "/");
}
public static function getLang() {
return self::$lang;
}
}

View File

@ -0,0 +1,5 @@
INSERT IGNORE INTO settings (setting_key, setting_value) VALUES
('meta_description', 'Download the latest APKs for free.'),
('meta_keywords', 'apk, download, android, games, apps'),
('head_js', ''),
('body_js', '');

View File

@ -1,16 +1,46 @@
<?php
require_once 'app/Core/Router.php';
require_once 'app/Core/Controller.php';
// Autoloader
spl_autoload_register(function ($class) {
$prefix = 'App\';
$base_dir = __DIR__ . '/app/';
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
$relative_class = substr($class, $len);
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
if (file_exists($file)) {
require $file;
}
});
require_once 'app/Helpers/functions.php';
require_once 'db/config.php';
session_start();
// Initialize Language Service
\App\Services\LanguageService::init();
use App\Core\Router;
$router = new Router();
// Sitemap
$router->get('/sitemap.xml', 'SitemapController@index');
// Language Switch
$router->get('/lang/:code', function($params) {
$code = $params['code'];
\App\Services\LanguageService::setLang($code);
header('Location: ' . ($_SERVER['HTTP_REFERER'] ?? '/'));
exit;
});
// Home & APKs
$router->get('/', 'HomeController@index');
$router->get('/apk/:slug', 'HomeController@apkDetail');
@ -33,6 +63,10 @@ $router->get('/admin/logout', 'AdminController@logout');
// Admin Dashboard
$router->get('/admin/dashboard', 'AdminController@dashboard');
// Admin Settings
$router->get('/admin/settings', 'AdminController@settingsForm');
$router->post('/admin/settings', 'AdminController@saveSettings');
// Admin APKs
$router->get('/admin/apks', 'AdminController@apks');
$router->get('/admin/apks/add', 'AdminController@addApkForm');

174
install.php Normal file
View File

@ -0,0 +1,174 @@
<?php
session_start();
if (file_exists('db/config.php') && !isset($_GET['force'])) {
// Check if DB is already connected
require_once 'db/config.php';
try {
db();
die("Application already installed. Delete db/config.php if you want to reinstall.");
} catch (Exception $e) {
// Continue to installation
}
}
$step = $_GET['step'] ?? 1;
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($step == 2) {
$host = $_POST['db_host'];
$name = $_POST['db_name'];
$user = $_POST['db_user'];
$pass = $_POST['db_pass'];
try {
$pdo = new PDO("mysql:host=$host;charset=utf8mb4", $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
$pdo->exec("CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
$pdo->exec("USE `$name`");
// Save config
$configContent = "<?php\ndefine('DB_HOST', '$host');\ndefine('DB_NAME', '$name');\ndefine('DB_USER', '$user');\ndefine('DB_PASS', '$pass');\n\nfunction db() {\n static \$pdo;\n if (!\$pdo) {\n \$pdo = new PDO('mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4', DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);\n }\n return \$pdo;
}\n";
file_put_contents('db/config.php', $configContent);
$_SESSION['install_pdo'] = ['host' => $host, 'name' => $name, 'user' => $user, 'pass' => $pass];
header("Location: install.php?step=3");
exit;
} catch (PDOException $e) {
$error = "Database Error: " . $e->getMessage();
}
}
if ($step == 3) {
require_once 'db/config.php';
$db = db();
// Import Schema
$schemaFile = 'full_schema.sql';
if (file_exists($schemaFile)) {
$sql = file_get_contents($schemaFile);
$db->exec($sql);
} else {
// Basic tables if full_schema.sql is missing
$db->exec("CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) UNIQUE, password VARCHAR(255), balance DECIMAL(10,2) DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");
$db->exec("CREATE TABLE IF NOT EXISTS settings (id INT AUTO_INCREMENT PRIMARY KEY, setting_key VARCHAR(255) UNIQUE, setting_value TEXT)");
$db->exec("INSERT IGNORE INTO settings (setting_key, setting_value) VALUES ('site_name', 'My APK Store'), ('site_icon', ''), ('site_favicon', '')");
}
// Create Admin
$admin_user = $_POST['admin_user'];
$admin_pass = password_hash($_POST['admin_pass'], PASSWORD_DEFAULT);
$stmt = $db->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->execute([$admin_user, $admin_pass]);
$success = "Installation complete!";
$step = 4;
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Installer</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { background-color: #f4f7f6; }
.install-box { max-width: 500px; margin: 100px auto; background: #fff; padding: 40px; border-radius: 10px; box-shadow: 0 5px 15px rgba(0,0,0,0.1); }
.step-indicator { display: flex; justify-content: space-between; margin-bottom: 30px; }
.step { width: 30px; height: 30px; border-radius: 50%; background: #ddd; text-align: center; line-height: 30px; color: #fff; }
.step.active { background: #0d6efd; }
</style>
</head>
<body>
<div class="install-box">
<h3 class="text-center mb-4">Web Installer</h3>
<div class="step-indicator">
<div class="step <?php echo $step >= 1 ? 'active' : ''; ">1</div>
<div class="step <?php echo $step >= 2 ? 'active' : ''; ">2</div>
<div class="step <?php echo $step >= 3 ? 'active' : ''; ">3</div>
<div class="step <?php echo $step >= 4 ? 'active' : ''; ">4</div>
</div>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<?php if ($step == 1): ?>
<h5>Welcome</h5>
<p>This wizard will help you install the application on your server.</p>
<div class="d-grid">
<a href="?step=2" class="btn btn-primary">Start Installation</a>
</div>
<?php endif; ?>
<?php if ($step == 2): ?>
<h5>Database Configuration</h5>
<form method="POST">
<div class="mb-3">
<label>DB Host</label>
<input type="text" name="db_host" class="form-control" value="localhost" required>
</div>
<div class="mb-3">
<label>DB Name</label>
<input type="text" name="db_name" class="form-control" required>
</div>
<div class="mb-3">
<label>DB User</label>
<input type="text" name="db_user" class="form-control" required>
</div>
<div class="mb-3">
<label>DB Password</label>
<input type="password" name="db_pass" class="form-control">
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">Connect & Continue</button>
</div>
</form>
<?php endif; ?>
<?php if ($step == 3): ?>
<h5>Admin Account</h5>
<form method="POST">
<div class="mb-3">
<label>Admin Username</label>
<input type="text" name="admin_user" class="form-control" required>
</div>
<div class="mb-3">
<label>Admin Password</label>
<input type="password" name="admin_pass" class="form-control" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">Finish Installation</button>
</div>
</form>
<?php endif; ?>
<?php if ($step == 4): ?>
<div class="text-center">
<h1 class="text-success"><i class="fas fa-check-circle"></i></h1>
<h5>Installation Successful!</h5>
<p>You can now log in to your admin panel.</p>
<div class="alert alert-warning">
<strong>Important:</strong> Please delete <code>install.php</code> file from your server.
</div>
<div class="d-grid">
<a href="/admin/login" class="btn btn-primary">Go to Admin Panel</a>
</div>
</div>
<?php endif; ?>
</div>
</body>
</html>

35
lang/en.php Normal file
View File

@ -0,0 +1,35 @@
<?php
return [
'home' => 'Home',
'search' => 'Search...',
'login' => 'Login',
'register' => 'Register',
'logout' => 'Logout',
'profile' => 'Profile',
'admin' => 'Admin',
'download' => 'Download',
'share' => 'Share',
'categories' => 'Categories',
'all_categories' => 'All Categories',
'latest_apks' => 'Latest APKs',
'featured_apks' => 'Featured APKs',
'download_now' => 'Download Now',
'share_link' => 'Share Link',
'balance' => 'Balance',
'referral_link' => 'Referral Link',
'withdraw' => 'Withdraw',
'withdrawal_history' => 'Withdrawal History',
'settings' => 'Settings',
'site_name' => 'Site Name',
'site_icon' => 'Site Icon',
'site_favicon' => 'Site Favicon',
'save_settings' => 'Save Settings',
'select_language' => 'Select Language',
'language_indonesia' => 'Indonesian',
'language_english' => 'English',
'admin_dashboard' => 'Admin Dashboard',
'manage_apks' => 'Manage APKs',
'manage_categories' => 'Manage Categories',
'manage_withdrawals' => 'Manage Withdrawals',
'general_settings' => 'General Settings',
];

35
lang/id.php Normal file
View File

@ -0,0 +1,35 @@
<?php
return [
'home' => 'Beranda',
'search' => 'Cari...',
'login' => 'Masuk',
'register' => 'Daftar',
'logout' => 'Keluar',
'profile' => 'Profil',
'admin' => 'Admin',
'download' => 'Unduh',
'share' => 'Bagikan',
'categories' => 'Kategori',
'all_categories' => 'Semua Kategori',
'latest_apks' => 'APK Terbaru',
'featured_apks' => 'APK Unggulan',
'download_now' => 'Unduh Sekarang',
'share_link' => 'Bagikan Link',
'balance' => 'Saldo',
'referral_link' => 'Link Referral',
'withdraw' => 'Tarik Saldo',
'withdrawal_history' => 'Riwayat Penarikan',
'settings' => 'Pengaturan',
'site_name' => 'Nama Website',
'site_icon' => 'Ikon Website',
'site_favicon' => 'Favicon Website',
'save_settings' => 'Simpan Pengaturan',
'select_language' => 'Pilih Bahasa',
'language_indonesia' => 'Indonesia',
'language_english' => 'English',
'admin_dashboard' => 'Dashboard Admin',
'manage_apks' => 'Kelola APK',
'manage_categories' => 'Kelola Kategori',
'manage_withdrawals' => 'Kelola Penarikan',
'general_settings' => 'Pengaturan Umum',
];

View File

@ -5,26 +5,26 @@
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4">
<div class="card-header bg-white py-3">
<h5 class="m-0 fw-bold"><?php echo $action === 'add' ? 'Add New APK' : 'Edit APK: ' . $apk['title']; ?></h5>
<h5 class="m-0 fw-bold"><?php echo $action === 'add' ? 'Add New APK' : 'Edit APK: ' . htmlspecialchars($apk['title']); ?></h5>
</div>
<div class="card-body p-4">
<form action="<?php echo $action === 'add' ? '/admin/apks/add' : '/admin/apks/edit/' . $apk['id']; ?>" method="POST" enctype="multipart/form-data">
<div class="mb-3">
<label for="title" class="form-label fw-medium">APK Title</label>
<input type="text" class="form-control" id="title" name="title" value="<?php echo $apk['title'] ?? ''; ?>" required>
<input type="text" class="form-control" id="title" name="title" value="<?php echo htmlspecialchars($apk['title'] ?? ''); ?>" required>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="version" class="form-label fw-medium">Version</label>
<input type="text" class="form-control" id="version" name="version" value="<?php echo $apk['version'] ?? ''; ?>" required>
<input type="text" class="form-control" id="version" name="version" value="<?php echo htmlspecialchars($apk['version'] ?? ''); ?>" required>
</div>
<div class="col-md-6 mb-3">
<label for="category_id" class="form-label fw-medium">Category</label>
<label for="category_id" class="form-label fw-medium"><?php echo __('categories'); ?></label>
<select class="form-select" id="category_id" name="category_id">
<option value="">Uncategorized</option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat['id']; ?>" <?php echo (isset($apk['category_id']) && $apk['category_id'] == $cat['id']) ? 'selected' : ''; ?>><?php echo $cat['name']; ?></option>
<option value="<?php echo $cat['id']; ?>" <?php echo (isset($apk['category_id']) && $apk['category_id'] == $cat['id']) ? 'selected' : ''; ?>><?php echo htmlspecialchars($cat['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
@ -32,26 +32,29 @@
<div class="mb-3">
<label for="description" class="form-label fw-medium">Description</label>
<textarea class="form-control" id="description" name="description" rows="4" required><?php echo $apk['description'] ?? ''; ?></textarea>
<textarea class="form-control" id="description" name="description" rows="4" required><?php echo htmlspecialchars($apk['description'] ?? ''); ?></textarea>
</div>
<div class="mb-4">
<label class="form-label fw-medium">APK Icon</label>
<div class="d-flex align-items-center mb-2">
<?php if (isset($apk['icon_path'])): ?>
<img src="/<?php echo $apk['icon_path']; ?>" class="rounded me-3 border" width="60" height="60">
<?php if (!empty($apk['icon_path'])): ?>
<img src="/<?php echo $apk['icon_path']; ?>" class="rounded me-3 border shadow-sm" width="64" height="64">
<?php endif; ?>
<input type="file" class="form-control" id="icon_file" name="icon_file" accept="image/*">
<div class="flex-grow-1">
<input type="file" class="form-control" id="icon_file" name="icon_file" accept="image/*">
<div class="form-text text-muted"><i class="fas fa-info-circle me-1"></i> Icons are automatically compressed to optimize speed.</div>
</div>
</div>
<div class="mb-3">
<label for="image_url" class="form-label fw-medium">External Icon URL (Optional)</label>
<input type="url" class="form-control" id="image_url" name="image_url" value="<?php echo $apk['image_url'] ?? ''; ?>" placeholder="https://example.com/icon.png">
<input type="url" class="form-control" id="image_url" name="image_url" value="<?php echo htmlspecialchars($apk['image_url'] ?? ''); ?>" placeholder="https://example.com/icon.png">
</div>
</div>
<div class="mb-3">
<label for="download_url" class="form-label fw-medium">Download URL</label>
<input type="url" class="form-control" id="download_url" name="download_url" value="<?php echo $apk['download_url'] ?? ''; ?>" required>
<input type="url" class="form-control" id="download_url" name="download_url" value="<?php echo htmlspecialchars($apk['download_url'] ?? ''); ?>" required>
</div>
<div class="row mb-4">
@ -65,14 +68,14 @@
<div class="col-md-6 d-flex align-items-center mt-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_vip" name="is_vip" <?php echo (isset($apk['is_vip']) && $apk['is_vip']) ? 'checked' : ''; ?>>
<label class="form-check-label" for="is_vip">VIP APK</label>
<label class="form-check-label fw-medium" for="is_vip">VIP APK</label>
</div>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="/admin/apks" class="btn btn-light px-4">Cancel</a>
<button type="submit" class="btn btn-primary px-5">Save APK</button>
<div class="d-grid gap-2 d-md-flex justify-content-md-end border-top pt-4">
<a href="/admin/apks" class="btn btn-light px-4 fw-bold">Cancel</a>
<button type="submit" class="btn btn-primary px-5 fw-bold"><i class="fas fa-save me-2"></i>Save APK</button>
</div>
</form>
</div>
@ -81,4 +84,4 @@
</div>
</div>
<?php include __DIR__ . '/../footer.php'; ?>
<?php include __DIR__ . '/../footer.php'; ?>

View File

@ -2,25 +2,28 @@
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">Dashboard Overview</h1>
<h1 class="h3 mb-0 text-gray-800 fw-bold"><?php echo __('admin_dashboard'); ?></h1>
<div class="d-flex gap-2">
<a href="/admin/apks/add" class="btn btn-primary shadow-sm rounded-pill px-4">
<i class="bi bi-plus-lg me-1"></i> Add APK
<a href="/admin/apks/add" class="btn btn-primary shadow-sm rounded-pill px-4 fw-bold">
<i class="fas fa-plus me-1"></i> Add APK
</a>
<a href="/admin/settings" class="btn btn-outline-secondary shadow-sm rounded-pill px-4 fw-bold">
<i class="fas fa-cog me-1"></i> <?php echo __('settings'); ?>
</a>
</div>
</div>
<div class="row g-4 mb-4">
<div class="col-xl-3 col-md-6">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-primary border-4">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-primary border-4 bg-white">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Total APKs</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?php echo number_format($total_apks); ?></div>
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1 small fw-bold">Total APKs</div>
<div class="h4 mb-0 font-weight-bold text-gray-800"><?php echo number_format($total_apks); ?></div>
</div>
<div class="col-auto">
<i class="bi bi-android2 fs-1 text-gray-300"></i>
<i class="fas fa-mobile-alt fa-2x text-gray-300"></i>
</div>
</div>
</div>
@ -28,15 +31,15 @@
</div>
<div class="col-xl-3 col-md-6">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-success border-4">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-success border-4 bg-white">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Total Downloads</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?php echo number_format($total_downloads); ?></div>
<div class="text-xs font-weight-bold text-success text-uppercase mb-1 small fw-bold">Total Downloads</div>
<div class="h4 mb-0 font-weight-bold text-gray-800"><?php echo number_format($total_downloads); ?></div>
</div>
<div class="col-auto">
<i class="bi bi-download fs-1 text-gray-300"></i>
<i class="fas fa-download fa-2x text-gray-300"></i>
</div>
</div>
</div>
@ -44,15 +47,15 @@
</div>
<div class="col-xl-3 col-md-6">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-info border-4">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-info border-4 bg-white">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Total Users</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?php echo number_format($total_users); ?></div>
<div class="text-xs font-weight-bold text-info text-uppercase mb-1 small fw-bold">Total Users</div>
<div class="h4 mb-0 font-weight-bold text-gray-800"><?php echo number_format($total_users); ?></div>
</div>
<div class="col-auto">
<i class="bi bi-people fs-1 text-gray-300"></i>
<i class="fas fa-users fa-2x text-gray-300"></i>
</div>
</div>
</div>
@ -60,15 +63,15 @@
</div>
<div class="col-xl-3 col-md-6">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-warning border-4">
<div class="card border-0 shadow-sm rounded-4 h-100 py-2 border-start border-warning border-4 bg-white">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Pending Withdrawals</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?php echo number_format($pending_withdrawals); ?></div>
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1 small fw-bold">Pending Withdrawals</div>
<div class="h4 mb-0 font-weight-bold text-gray-800"><?php echo number_format($pending_withdrawals); ?></div>
</div>
<div class="col-auto">
<i class="bi bi-wallet2 fs-1 text-gray-300"></i>
<i class="fas fa-wallet fa-2x text-gray-300"></i>
</div>
</div>
</div>
@ -78,32 +81,32 @@
<div class="row g-4">
<div class="col-lg-8">
<div class="card shadow border-0 rounded-4 mb-4">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary">Recent APKs</h6>
<div class="card shadow-sm border-0 rounded-4 mb-4 bg-white">
<div class="card-header bg-white py-3 border-bottom border-light">
<h6 class="m-0 font-weight-bold text-primary fw-bold">Recent APKs</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>Title</th>
<th>Version</th>
<th>Downloads</th>
<th>Status</th>
<th class="border-0">Title</th>
<th class="border-0">Version</th>
<th class="border-0">Downloads</th>
<th class="border-0">Status</th>
</tr>
</thead>
<tbody>
<?php foreach ($recent_apks as $apk): ?>
<tr>
<td>
<div class="fw-bold text-gray-800"><?php echo $apk['title']; ?></div>
<small class="text-muted"><?php echo $apk['slug']; ?></small>
<div class="fw-bold text-dark"><?php echo htmlspecialchars($apk['title']); ?></div>
<small class="text-muted"><?php echo htmlspecialchars($apk['slug']); ?></small>
</td>
<td>v<?php echo $apk['version']; ?></td>
<td><?php echo number_format($apk['total_downloads']); ?></td>
<td>v<?php echo htmlspecialchars($apk['version']); ?></td>
<td><i class="fas fa-download me-1 text-muted"></i> <?php echo number_format($apk['total_downloads']); ?></td>
<td>
<span class="badge bg-<?php echo $apk['status'] === 'published' ? 'success' : 'secondary'; ?>">
<span class="badge rounded-pill bg-<?php echo $apk['status'] === 'published' ? 'success' : 'secondary'; ?> px-3 py-2">
<?php echo ucfirst($apk['status']); ?>
</span>
</td>
@ -117,24 +120,27 @@
</div>
<div class="col-lg-4">
<div class="card shadow border-0 rounded-4">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary">Quick Navigation</h6>
<div class="card shadow-sm border-0 rounded-4 bg-white">
<div class="card-header bg-white py-3 border-bottom border-light">
<h6 class="m-0 font-weight-bold text-primary fw-bold">Quick Navigation</h6>
</div>
<div class="card-body p-0">
<div class="list-group list-group-flush">
<a href="/admin/apks" class="list-group-item list-group-item-action py-3 px-4">
<i class="bi bi-android2 me-2 text-primary"></i> Manage APKs
<div class="list-group list-group-flush rounded-bottom-4">
<a href="/admin/apks" class="list-group-item list-group-item-action py-3 px-4 border-0">
<i class="fas fa-mobile-alt me-2 text-primary"></i> Manage APKs
</a>
<a href="/admin/categories" class="list-group-item list-group-item-action py-3 px-4">
<i class="bi bi-tags me-2 text-info"></i> Categories
<a href="/admin/categories" class="list-group-item list-group-item-action py-3 px-4 border-0">
<i class="fas fa-tags me-2 text-info"></i> <?php echo __('categories'); ?>
</a>
<a href="/admin/withdrawals" class="list-group-item list-group-item-action py-3 px-4">
<i class="bi bi-cash-stack me-2 text-success"></i> Withdrawal Requests
<a href="/admin/withdrawals" class="list-group-item list-group-item-action py-3 px-4 border-0">
<i class="fas fa-cash-register me-2 text-success"></i> <?php echo __('manage_withdrawals'); ?>
<?php if ($pending_withdrawals > 0): ?>
<span class="badge bg-danger rounded-pill float-end"><?php echo $pending_withdrawals; ?></span>
<?php endif; ?>
</a>
<a href="/admin/settings" class="list-group-item list-group-item-action py-3 px-4 border-0">
<i class="fas fa-cog me-2 text-secondary"></i> <?php echo __('settings'); ?>
</a>
</div>
</div>
</div>
@ -142,4 +148,4 @@
</div>
</div>
<?php include __DIR__ . '/footer.php'; ?>
<?php include __DIR__ . '/footer.php'; ?>

View File

@ -1,11 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<html lang="<?php echo \App\Services\LanguageService::getLang(); ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel - APK Portal</title>
<title><?php echo __('admin_dashboard'); ?> - <?php echo htmlspecialchars(get_setting('site_name', 'APK 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.10.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="icon" type="image/x-icon" href="/<?php echo get_setting('site_favicon'); ?>">
<style>
:root {
--primary-color: #4e73df;
@ -19,32 +20,33 @@
background-color: #fff;
box-shadow: 0 .15rem 1.75rem 0 rgba(58,59,69,.15);
}
.sidebar {
min-height: calc(100vh - 56px);
background-color: #4e73df;
background-image: linear-gradient(180deg,#4e73df 10%,#224abe 100%);
background-size: cover;
}
.nav-link {
color: rgba(255,255,255,.8);
padding: 1rem 1.5rem;
border-bottom: 1px solid rgba(255,255,255,.05);
color: #4e73df;
padding: 0.5rem 1rem;
border-radius: 0.35rem;
transition: all 0.2s;
font-weight: 600;
}
.nav-link:hover {
color: #fff;
background-color: rgba(255,255,255,.1);
background-color: rgba(78, 115, 223, 0.1);
color: #224abe;
}
.nav-link.active {
color: #fff;
font-weight: 700;
background-color: #4e73df;
color: #fff !important;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-admin sticky-top py-3">
<div class="container-fluid px-4">
<a class="navbar-brand fw-bold text-primary" href="/admin/dashboard">
<i class="bi bi-shield-lock-fill me-2"></i>APK ADMIN
<a class="navbar-brand fw-bold text-primary d-flex align-items-center" href="/admin/dashboard">
<?php if (get_setting('site_icon')): ?>
<img src="/<?php echo get_setting('site_icon'); ?>" alt="Logo" class="me-2" style="height: 30px;">
<?php else: ?>
<i class="fas fa-shield-halved me-2"></i>
<?php endif; ?>
<?php echo htmlspecialchars(get_setting('site_name', 'APK ADMIN')); ?>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
@ -52,23 +54,35 @@
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link text-dark px-3" href="/admin/dashboard">Dashboard</a>
<a class="nav-link px-3" href="/admin/dashboard"><i class="fas fa-tachometer-alt me-1"></i> Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark px-3" href="/admin/apks">APKs</a>
<a class="nav-link px-3" href="/admin/apks"><i class="fas fa-mobile-alt me-1"></i> APKs</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark px-3" href="/admin/categories">Categories</a>
<a class="nav-link px-3" href="/admin/categories"><i class="fas fa-list me-1"></i> <?php echo __('categories'); ?></a>
</li>
<li class="nav-item">
<a class="nav-link text-dark px-3" href="/admin/withdrawals">Withdrawals</a>
<a class="nav-link px-3" href="/admin/withdrawals"><i class="fas fa-wallet me-1"></i> <?php echo __('manage_withdrawals'); ?></a>
</li>
<li class="nav-item">
<a class="nav-link px-3" href="/admin/settings"><i class="fas fa-cog me-1"></i> <?php echo __('settings'); ?></a>
</li>
</ul>
<div class="d-flex align-items-center">
<span class="text-muted me-3">Welcome, <b><?php echo $_SESSION['username'] ?? 'Admin'; ?></b></span>
<a href="/" class="btn btn-outline-secondary btn-sm me-2" target="_blank">View Site</a>
<a href="/admin/logout" class="btn btn-danger btn-sm">Logout</a>
<div class="dropdown me-3">
<button class="btn btn-outline-primary btn-sm dropdown-toggle fw-bold" type="button" data-bs-toggle="dropdown">
<i class="fas fa-globe me-1"></i> <?php echo \App\Services\LanguageService::getLang() == 'id' ? 'ID' : 'EN'; ?>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow border-0">
<li><a class="dropdown-item" href="/lang/id">🇮🇩 Indonesia</a></li>
<li><a class="dropdown-item" href="/lang/en">🇺🇸 English</a></li>
</ul>
</div>
<span class="text-muted me-3 d-none d-md-inline"><b><?php echo $_SESSION['username'] ?? 'Admin'; ?></b></span>
<a href="/" class="btn btn-outline-secondary btn-sm me-2" target="_blank"><i class="fas fa-external-link-alt"></i></a>
<a href="/admin/logout" class="btn btn-danger btn-sm"><i class="fas fa-sign-out-alt"></i></a>
</div>
</div>
</div>
</nav>
</nav>

96
views/admin/settings.php Normal file
View File

@ -0,0 +1,96 @@
<?php include 'header.php'; ?>
<div class="container-fluid py-4">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-sm border-0">
<div class="card-header bg-white py-3">
<h5 class="mb-0 fw-bold text-primary"><i class="fas fa-cog me-2"></i><?php echo __('general_settings'); ?></h5>
</div>
<div class="card-body p-4">
<form action="/admin/settings" method="POST" enctype="multipart/form-data">
<div class="mb-4">
<label class="form-label fw-semibold"><?php echo __('site_name'); ?></label>
<input type="text" name="site_name" class="form-control form-control-lg" value="<?php echo htmlspecialchars($settings['site_name']); ?>" required>
</div>
<div class="row mb-4">
<div class="col-md-6">
<label class="form-label fw-semibold"><?php echo __('site_icon'); ?></label>
<input type="file" name="site_icon_file" class="form-control" accept="image/*">
<?php if ($settings['site_icon']): ?>
<div class="mt-2">
<img src="/<?php echo $settings['site_icon']; ?>" alt="Icon" class="img-thumbnail" style="max-height: 50px;">
</div>
<?php endif; ?>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold"><?php echo __('site_favicon'); ?></label>
<input type="file" name="site_favicon_file" class="form-control" accept="image/*">
<?php if ($settings['site_favicon']): ?>
<div class="mt-2">
<img src="/<?php echo $settings['site_favicon']; ?>" alt="Favicon" class="img-thumbnail" style="max-height: 32px;">
</div>
<?php endif; ?>
</div>
</div>
<hr class="my-4">
<h5 class="fw-bold mb-3"><i class="fas fa-search me-2"></i>SEO Settings</h5>
<div class="mb-4">
<label class="form-label fw-semibold">Meta Description</label>
<textarea name="meta_description" class="form-control" rows="3"><?php echo htmlspecialchars($settings['meta_description'] ?? ''); ?></textarea>
<div class="form-text">Brief description of your site for search engines.</div>
</div>
<div class="mb-4">
<label class="form-label fw-semibold">Meta Keywords</label>
<input type="text" name="meta_keywords" class="form-control" value="<?php echo htmlspecialchars($settings['meta_keywords'] ?? ''); ?>">
<div class="form-text">Comma separated keywords (e.g. apk, games, mod).</div>
</div>
<hr class="my-4">
<h5 class="fw-bold mb-3"><i class="fas fa-code me-2"></i>Custom Scripts & Ads</h5>
<div class="mb-4">
<label class="form-label fw-semibold">Head JS (Ads/Analytics)</label>
<textarea name="head_js" class="form-control" rows="5" placeholder="<script>...</script>"><?php echo htmlspecialchars($settings['head_js'] ?? ''); ?></textarea>
<div class="form-text">Injected before &lt;/head&gt;.</div>
</div>
<div class="mb-4">
<label class="form-label fw-semibold">Body JS (Ads/Analytics)</label>
<textarea name="body_js" class="form-control" rows="5" placeholder="<script>...</script>"><?php echo htmlspecialchars($settings['body_js'] ?? ''); ?></textarea>
<div class="form-text">Injected before &lt;/body&gt;.</div>
</div>
<div class="d-grid mt-4">
<button type="submit" class="btn btn-primary btn-lg py-3 fw-bold">
<i class="fas fa-save me-2"></i><?php echo __('save_settings'); ?>
</button>
</div>
</form>
</div>
</div>
<div class="card shadow-sm border-0 mt-4">
<div class="card-header bg-white py-3">
<h5 class="mb-0 fw-bold text-primary"><i class="fas fa-language me-2"></i><?php echo __('select_language'); ?></h5>
</div>
<div class="card-body p-4 text-center">
<div class="btn-group w-100" role="group">
<a href="/lang/id" class="btn btn-outline-primary py-3 fw-bold <?php echo \App\Services\LanguageService::getLang() == 'id' ? 'active' : ''; ?>">
🇮🇩 <?php echo __('language_indonesia'); ?>
</a>
<a href="/lang/en" class="btn btn-outline-primary py-3 fw-bold <?php echo \App\Services\LanguageService::getLang() == 'en' ? 'active' : ''; ?>">
🇺🇸 <?php echo __('language_english'); ?>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@ -6,14 +6,14 @@
<div class="card shadow border-0 rounded-4 mb-4">
<div class="card-body text-center p-5">
<div class="bg-success text-white rounded-circle d-inline-flex align-items-center justify-content-center mb-4" style="width: 80px; height: 80px;">
<i class="bi bi-person-fill fs-1"></i>
<i class="fas fa-user fs-1"></i>
</div>
<h3 class="fw-bold mb-0"><?php echo $user['username']; ?></h3>
<p class="text-muted">Member since <?php echo date('M Y', strtotime($user['created_at'])); ?></p>
<hr>
<div class="row g-0">
<div class="col-6 border-end">
<h4 class="fw-bold text-success mb-0"><?php echo $user['points']; ?></h4>
<h4 class="fw-bold text-success mb-0"><?php echo number_format($user['points']); ?></h4>
<small class="text-muted text-uppercase">Points</small>
</div>
<div class="col-6">
@ -26,10 +26,10 @@
<div class="card shadow border-0 rounded-4 mb-4">
<div class="card-body p-4 text-center bg-light">
<h6 class="text-uppercase text-muted fw-bold mb-2">Current Balance</h6>
<h6 class="text-uppercase text-muted fw-bold mb-2"><?php echo __('balance'); ?></h6>
<h2 class="fw-bold text-success mb-3">Rp <?php echo number_format($user['balance'], 0, ',', '.'); ?></h2>
<button class="btn btn-success btn-lg px-5 rounded-pill" data-bs-toggle="modal" data-bs-target="#withdrawModal">
<i class="bi bi-wallet2 me-2"></i> Withdraw
<i class="fas fa-wallet me-2"></i> <?php echo __('withdraw'); ?>
</button>
<p class="small text-muted mt-3 mb-0">Min. withdraw: Rp 10.000</p>
</div>
@ -46,12 +46,12 @@
<div class="card shadow border-0 rounded-4 mb-4">
<div class="card-header bg-white py-3">
<h5 class="m-0 fw-bold">My Referral Code</h5>
<h5 class="m-0 fw-bold"><?php echo __('referral_link'); ?></h5>
</div>
<div class="card-body p-4">
<p>Share your referral link to earn <b>Rp 500</b> for every download.</p>
<div class="input-group mb-3">
<input type="text" class="form-control bg-light" id="refLink" value="<?php echo 'http://' . $_SERVER['HTTP_HOST'] . '/register?ref=' . $user['referral_code']; ?>" readonly>
<input type="text" class="form-control bg-light" id="refLink" value="<?php echo 'http://' . $_SERVER['HTTP_HOST'] . '/?ref=' . $user['referral_code']; ?>" readonly>
<button class="btn btn-outline-success" type="button" onclick="copyText('refLink')">Copy Link</button>
</div>
<div class="small text-muted">Example APK referral link:</div>
@ -63,7 +63,7 @@
<div class="card shadow border-0 rounded-4">
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
<h5 class="m-0 fw-bold">Withdrawal History</h5>
<h5 class="m-0 fw-bold"><?php echo __('withdrawal_history'); ?></h5>
<span class="badge bg-light text-dark">Recent activities</span>
</div>
<div class="card-body p-0">

View File

@ -1,13 +1,18 @@
</main>
</main>
<footer class="bg-white border-top py-5">
<div class="container">
<div class="row g-4">
<div class="col-lg-4">
<a class="navbar-brand fw-bold text-success" href="/">
<i class="bi bi-robot"></i> ApkNusa
<a class="navbar-brand fw-bold text-success d-flex align-items-center" href="/">
<?php if (get_setting('site_icon')): ?>
<img src="/<?php echo get_setting('site_icon'); ?>" alt="Logo" class="me-2" style="height: 30px;">
<?php else: ?>
<i class="bi bi-robot"></i>
<?php endif; ?>
<?php echo htmlspecialchars(get_setting('site_name', 'ApkNusa')); ?>
</a>
<p class="text-muted mt-3 pe-lg-5">
ApkNusa is your premier source for professional APK downloads, offering the latest and safest Android applications and games.
<?php echo htmlspecialchars(get_setting('site_name', 'ApkNusa')); ?> is your premier source for professional APK downloads, offering the latest and safest Android applications and games.
</p>
</div>
<div class="col-6 col-lg-2">
@ -38,7 +43,7 @@
<hr class="my-5 text-black-50 opacity-25">
<div class="row align-items-center">
<div class="col-md-6 text-center text-md-start">
<span class="text-muted small">&copy; <?php echo date('Y'); ?> ApkNusa. All rights reserved.</span>
<span class="text-muted small">&copy; <?php echo date('Y'); ?> <?php echo htmlspecialchars(get_setting('site_name', 'ApkNusa')); ?>. All rights reserved.</span>
</div>
<div class="col-md-6 text-center text-md-end mt-3 mt-md-0">
<div class="d-flex justify-content-center justify-content-md-end gap-3">
@ -53,5 +58,6 @@
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="/assets/js/main.js"></script>
<?php echo get_setting('body_js'); ?>
</body>
</html>
</html>

View File

@ -1,22 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<html lang="<?php echo \App\Services\LanguageService::getLang(); ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $title ?? 'ApkNusa'; ?></title>
<meta name="description" content="<?php echo $_SERVER['PROJECT_DESCRIPTION'] ?? 'Download Professional APKs with ApkNusa.'; ?>">
<title><?php echo $title ?? htmlspecialchars(get_setting('site_name', 'ApkNusa')); ?></title>
<meta name="description" content="<?php echo $meta_description ?? htmlspecialchars(get_setting('meta_description', 'Download Professional APKs.')); ?>">
<meta name="keywords" content="<?php echo $meta_keywords ?? htmlspecialchars(get_setting('meta_keywords', 'apk, android, download')); ?>">
<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.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="icon" type="image/x-icon" href="/<?php echo get_setting('site_favicon'); ?>">
<link rel="stylesheet" href="/assets/css/custom.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<?php echo get_setting('head_js'); ?>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white border-bottom py-3 sticky-top">
<div class="container">
<a class="navbar-brand fw-bold text-success" href="/">
<i class="bi bi-robot"></i> ApkNusa
<a class="navbar-brand fw-bold text-success d-flex align-items-center" href="/">
<?php if (get_setting('site_icon')): ?>
<img src="/<?php echo get_setting('site_icon'); ?>" alt="Logo" class="me-2" style="height: 30px;">
<?php else: ?>
<i class="fas fa-robot"></i>
<?php endif; ?>
<?php echo htmlspecialchars(get_setting('site_name', 'ApkNusa')); ?>
</a>
<button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
@ -24,27 +36,34 @@
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto align-items-center">
<li class="nav-item">
<a class="nav-link px-3" href="/">Home</a>
<a class="nav-link px-3" href="/"><?php echo __('home'); ?></a>
</li>
<li class="nav-item">
<a class="nav-link px-3" href="#">Games</a>
</li>
<li class="nav-item">
<a class="nav-link px-3" href="#">Apps</a>
<a class="nav-link px-3" href="#"><?php echo __('categories'); ?></a>
</li>
<li class="nav-item dropdown px-3">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
<i class="fas fa-globe me-1"></i> <?php echo \App\Services\LanguageService::getLang() == 'id' ? 'ID' : 'EN'; ?>
</a>
<ul class="dropdown-menu dropdown-menu-end shadow border-0">
<li><a class="dropdown-item" href="/lang/id">🇮🇩 Indonesia</a></li>
<li><a class="dropdown-item" href="/lang/en">🇺🇸 English</a></li>
</ul>
</li>
<?php if (isset($_SESSION['user_id'])): ?>
<li class="nav-item ms-lg-3">
<a class="btn btn-outline-success rounded-pill px-4 d-flex align-items-center" href="/profile">
<i class="bi bi-person-circle me-2"></i> Profile
<i class="fas fa-user-circle me-2"></i> <?php echo __('profile'); ?>
</a>
</li>
<?php else: ?>
<li class="nav-item ms-lg-3">
<a class="btn btn-outline-dark rounded-pill px-4" href="/login">Login</a>
<a class="btn btn-outline-dark rounded-pill px-4" href="/login"><?php echo __('login'); ?></a>
</li>
<li class="nav-item ms-lg-2">
<a class="btn btn-success rounded-pill px-4" href="/register">Join Free</a>
<a class="btn btn-success rounded-pill px-4" href="/register"><?php echo __('register'); ?></a>
</li>
<?php endif; ?>
</ul>

View File

@ -1,7 +1,7 @@
<?php include 'header.php'; ?>
<div class="container">
<div class="row align-items-center mb-5">
<div class="row align-items-center mb-5 mt-4">
<div class="col-lg-7">
<h1 class="display-4 fw-bold mb-3">Download the Best <span class="text-success">Android APKs</span> Professionally</h1>
<p class="lead text-muted mb-4">Fast, safe, and secure downloads for your favorite mobile apps and games. No registration required to browse.</p>
@ -10,23 +10,23 @@
<a href="/register" class="btn btn-outline-dark btn-lg px-4 rounded-pill">Join Referral</a>
</div>
</div>
<div class="col-lg-5 d-none d-lg-block">
<div class="col-lg-5 d-none d-lg-block text-center">
<div class="position-relative">
<div class="bg-success opacity-10 position-absolute rounded-circle" style="width: 400px; height: 400px; top: -50px; right: -50px; z-index: -1;"></div>
<img src="https://img.icons8.com/color/512/android-os.png" class="img-fluid floating-animation" alt="Android APKs">
<img src="https://img.icons8.com/color/512/android-os.png" class="img-fluid floating-animation" alt="Android APKs" style="max-height: 350px;">
</div>
</div>
</div>
<section id="latest" class="mb-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold mb-0">Latest Releases</h2>
<h2 class="fw-bold mb-0"><?php echo __('latest_apks'); ?></h2>
<div class="dropdown">
<button class="btn btn-light dropdown-toggle rounded-pill" type="button" data-bs-toggle="dropdown">
Categories
<?php echo __('categories'); ?>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/">All</a></li>
<li><a class="dropdown-item" href="/"><?php echo __('all_categories'); ?></a></li>
<?php
$db = db();
$categories = $db->query("SELECT * FROM categories")->fetchAll();
@ -36,28 +36,27 @@
</ul>
</div>
</div>
<div class="row g-4">
<!-- Grid optimized for 3 columns on desktop and mobile as requested -->
<div class="row g-2 g-md-4">
<?php foreach ($apks as $apk): ?>
<div class="col-12 col-md-6 col-lg-4">
<div class="col-4 col-md-4">
<div class="card h-100 border-0 shadow-sm rounded-4 hover-lift">
<div class="card-body p-4">
<div class="d-flex align-items-center mb-3">
<div class="card-body p-2 p-md-4 text-center text-md-start">
<div class="d-md-flex align-items-center mb-2 mb-md-3">
<?php
$icon = !empty($apk['icon_path']) ? '/'.$apk['icon_path'] : $apk['image_url'];
?>
<img src="<?php echo $icon; ?>" class="rounded-3 me-3" width="60" height="60" alt="<?php echo $apk['title']; ?>" style="object-fit: cover;">
<div>
<h5 class="card-title fw-bold mb-0 text-truncate" style="max-width: 180px;"><?php echo $apk['title']; ?></h5>
<span class="badge bg-light text-dark fw-normal">v<?php echo $apk['version']; ?></span>
<?php if ($apk['is_vip']): ?>
<span class="badge bg-warning text-dark ms-1"><i class="bi bi-star-fill"></i> VIP</span>
<?php endif; ?>
<img src="<?php echo $icon; ?>" class="rounded-3 mx-auto mx-md-0 mb-2 mb-md-0 d-block d-md-inline-block" width="50" height="50" alt="<?php echo $apk['title']; ?>" style="object-fit: cover; width: 50px; height: 50px;">
<div class="ms-md-3">
<h6 class="card-title fw-bold mb-0 text-truncate mx-auto" style="max-width: 100%;"><?php echo $apk['title']; ?></h6>
<span class="badge bg-light text-dark fw-normal d-none d-md-inline-block">v<?php echo $apk['version']; ?></span>
</div>
</div>
<p class="card-text text-muted small mb-4 line-clamp-2"><?php echo $apk['description']; ?></p>
<div class="d-flex justify-content-between align-items-center">
<span class="text-muted small"><i class="bi bi-download me-1"></i> <?php echo number_format($apk['total_downloads']); ?></span>
<a href="/apk/<?php echo $apk['slug']; ?>" class="btn btn-success rounded-pill px-4 btn-sm fw-medium">Details</a>
<p class="card-text text-muted small mb-3 line-clamp-2 d-none d-md-block"><?php echo $apk['description']; ?></p>
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center gap-2">
<span class="text-muted small d-none d-md-inline-block"><i class="fas fa-download me-1"></i> <?php echo number_format($apk['total_downloads']); ?></span>
<a href="/apk/<?php echo $apk['slug']; ?>" class="btn btn-success rounded-pill px-3 btn-sm fw-medium w-100 w-md-auto">Details</a>
</div>
</div>
</div>
@ -79,4 +78,16 @@
</div>
</div>
<style>
@media (max-width: 767px) {
.card-title {
font-size: 0.8rem;
}
.btn-sm {
font-size: 0.7rem;
padding: 0.25rem 0.5rem;
}
}
</style>
<?php include 'footer.php'; ?>