mirror of
https://github.com/mivodev/mivo.git
synced 2026-01-26 05:25:42 +07:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51ca6d3669 | ||
|
|
9cee55c05a | ||
|
|
a0e8c097f7 | ||
|
|
aee64ac137 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -32,4 +32,5 @@ deploy.ps1
|
|||||||
!/public/uploads/.gitignore
|
!/public/uploads/.gitignore
|
||||||
|
|
||||||
# Plugins
|
# Plugins
|
||||||
/plugins/*
|
/plugins/*
|
||||||
|
!/plugins/.gitkeep
|
||||||
@@ -29,8 +29,15 @@ RUN mkdir -p /var/www/html/app/Database && \
|
|||||||
chown -R www-data:www-data /var/www/html && \
|
chown -R www-data:www-data /var/www/html && \
|
||||||
chmod -R 755 /var/www/html
|
chmod -R 755 /var/www/html
|
||||||
|
|
||||||
|
# Copy Entrypoint
|
||||||
|
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
# Start Supervisor (which starts Nginx & PHP-FPM)
|
# Use Entrypoint
|
||||||
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
|
|
||||||
|
# Start Supervisor
|
||||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace App\Config;
|
|||||||
|
|
||||||
class SiteConfig {
|
class SiteConfig {
|
||||||
const APP_NAME = 'MIVO';
|
const APP_NAME = 'MIVO';
|
||||||
const APP_VERSION = 'v1.2.0';
|
const APP_VERSION = 'v1.2.2';
|
||||||
const APP_FULL_NAME = 'MIVO - Mikrotik Voucher';
|
const APP_FULL_NAME = 'MIVO - Mikrotik Voucher';
|
||||||
const CREDIT_NAME = 'MivoDev';
|
const CREDIT_NAME = 'MivoDev';
|
||||||
const CREDIT_URL = 'https://github.com/mivodev';
|
const CREDIT_URL = 'https://github.com/mivodev';
|
||||||
|
|||||||
@@ -97,10 +97,16 @@ class Router {
|
|||||||
|
|
||||||
$path = parse_url($uri, PHP_URL_PATH);
|
$path = parse_url($uri, PHP_URL_PATH);
|
||||||
|
|
||||||
// Handle subdirectory
|
// Handle subdirectory (SKIP for PHP Built-in Server to avoid SCRIPT_NAME issues)
|
||||||
$scriptName = dirname($_SERVER['SCRIPT_NAME']);
|
if (php_sapi_name() !== 'cli-server') {
|
||||||
if (strpos($path, $scriptName) === 0) {
|
$scriptName = dirname($_SERVER['SCRIPT_NAME']);
|
||||||
$path = substr($path, strlen($scriptName));
|
// Normalize backslashes (Windows)
|
||||||
|
$scriptName = str_replace('\\', '/', $scriptName);
|
||||||
|
|
||||||
|
// Ensure we don't strip root slash
|
||||||
|
if ($scriptName !== '/' && strpos($path, $scriptName) === 0) {
|
||||||
|
$path = substr($path, strlen($scriptName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$path = $this->normalizePath($path);
|
$path = $this->normalizePath($path);
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,6 @@ class LanguageHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $languages;
|
return \App\Core\Hooks::applyFilters('get_available_languages', $languages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<i data-lucide="book-open" class="w-4 h-4"></i>
|
<i data-lucide="book-open" class="w-4 h-4"></i>
|
||||||
<span>Docs</span>
|
<span>Docs</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/mivodev/mivo/issues" target="_blank" class="hover:text-foreground transition-colors flex items-center gap-2">
|
<a href="https://github.com/mivodev/mivo/discussions" target="_blank" class="hover:text-foreground transition-colors flex items-center gap-2">
|
||||||
<i data-lucide="message-circle" class="w-4 h-4"></i>
|
<i data-lucide="message-circle" class="w-4 h-4"></i>
|
||||||
<span>Community</span>
|
<span>Community</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<i data-lucide="book-open" class="w-4 h-4"></i>
|
<i data-lucide="book-open" class="w-4 h-4"></i>
|
||||||
<span>Docs</span>
|
<span>Docs</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/mivodev/mivo/issues" target="_blank" class="hover:text-foreground transition-colors flex items-center gap-2">
|
<a href="https://github.com/mivodev/mivo/discussions" target="_blank" class="hover:text-foreground transition-colors flex items-center gap-2">
|
||||||
<i data-lucide="message-circle" class="w-4 h-4"></i>
|
<i data-lucide="message-circle" class="w-4 h-4"></i>
|
||||||
<span>Community</span>
|
<span>Community</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -53,8 +53,9 @@ $uri = $_SERVER['REQUEST_URI'] ?? '/';
|
|||||||
<?php
|
<?php
|
||||||
$languages = \App\Helpers\LanguageHelper::getAvailableLanguages();
|
$languages = \App\Helpers\LanguageHelper::getAvailableLanguages();
|
||||||
foreach ($languages as $lang):
|
foreach ($languages as $lang):
|
||||||
|
$pathArg = isset($lang['path']) ? "', '" . $lang['path'] : "";
|
||||||
?>
|
?>
|
||||||
<button onclick="Mivo.modules.I18n.loadLanguage('<?= $lang['code'] ?>')" class="w-full text-left flex items-center gap-3 px-4 py-2.5 text-sm hover:bg-accents-1 transition-colors text-accents-6 hover:text-foreground group/lang">
|
<button onclick="Mivo.modules.I18n.loadLanguage('<?= $lang['code'] ?><?= $pathArg ?>')" class="w-full text-left flex items-center gap-3 px-4 py-2.5 text-sm hover:bg-accents-1 transition-colors text-accents-6 hover:text-foreground group/lang">
|
||||||
<span class="fi fi-<?= $lang['flag'] ?> rounded-sm shadow-sm transition-transform group-hover/lang:scale-110"></span>
|
<span class="fi fi-<?= $lang['flag'] ?> rounded-sm shadow-sm transition-transform group-hover/lang:scale-110"></span>
|
||||||
<span><?= $lang['name'] ?></span>
|
<span><?= $lang['name'] ?></span>
|
||||||
</button>
|
</button>
|
||||||
@@ -123,8 +124,10 @@ $uri = $_SERVER['REQUEST_URI'] ?? '/';
|
|||||||
<span class="text-xs font-bold text-accents-4 uppercase tracking-wider">Select Language</span>
|
<span class="text-xs font-bold text-accents-4 uppercase tracking-wider">Select Language</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2 overflow-x-auto pb-2 -mx-4 px-4 scrollbar-hide snap-x">
|
<div class="flex items-center gap-2 overflow-x-auto pb-2 -mx-4 px-4 scrollbar-hide snap-x">
|
||||||
<?php foreach ($languages as $lang): ?>
|
<?php foreach ($languages as $lang):
|
||||||
<button onclick="changeLanguage('<?= $lang['code'] ?>')" class="flex-shrink-0 flex items-center gap-2 px-4 py-2 rounded-full border border-accents-2 bg-background hover:border-foreground transition-all text-sm font-medium snap-start shadow-sm">
|
$pathArg = isset($lang['path']) ? "', '" . $lang['path'] : "";
|
||||||
|
?>
|
||||||
|
<button onclick="changeLanguage('<?= $lang['code'] ?><?= $pathArg ?>')" class="flex-shrink-0 flex items-center gap-2 px-4 py-2 rounded-full border border-accents-2 bg-background hover:border-foreground transition-all text-sm font-medium snap-start shadow-sm">
|
||||||
<span class="fi fi-<?= $lang['flag'] ?> rounded-full shadow-sm"></span>
|
<span class="fi fi-<?= $lang['flag'] ?> rounded-full shadow-sm"></span>
|
||||||
<span class="whitespace-nowrap"><?= $lang['name'] ?></span>
|
<span class="whitespace-nowrap"><?= $lang['name'] ?></span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ $getInitials = function($name) {
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Community -->
|
<!-- Community -->
|
||||||
<a href="https://github.com/mivodev/mivo/issues" target="_blank" class="flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors text-accents-6 hover:text-foreground hover:bg-white/5">
|
<a href="https://github.com/mivodev/mivo/discussions" target="_blank" class="flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors text-accents-6 hover:text-foreground hover:bg-white/5">
|
||||||
<i data-lucide="message-circle" class="w-4 h-4"></i>
|
<i data-lucide="message-circle" class="w-4 h-4"></i>
|
||||||
<span data-i18n="sidebar.community">Community</span>
|
<span data-i18n="sidebar.community">Community</span>
|
||||||
<i data-lucide="external-link" class="w-3 h-3 ml-auto opacity-50"></i>
|
<i data-lucide="external-link" class="w-3 h-3 ml-auto opacity-50"></i>
|
||||||
|
|||||||
25
docker/entrypoint.sh
Normal file
25
docker/entrypoint.sh
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Ensure Database directory exists
|
||||||
|
mkdir -p /var/www/html/app/Database
|
||||||
|
|
||||||
|
# Fix permissions for the Database directory
|
||||||
|
# This is crucial for SQLite when volumes are mounted from host
|
||||||
|
if [ -d "/var/www/html/app/Database" ]; then
|
||||||
|
chown -R www-data:www-data /var/www/html/app/Database
|
||||||
|
chmod -R 775 /var/www/html/app/Database
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Also ensure .env is writable if it exists, or create it from example
|
||||||
|
if [ ! -f "/var/www/html/.env" ] && [ -f "/var/www/html/.env.example" ]; then
|
||||||
|
cp /var/www/html/.env.example /var/www/html/.env
|
||||||
|
chown www-data:www-data /var/www/html/.env
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/var/www/html/.env" ]; then
|
||||||
|
chmod 664 /var/www/html/.env
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Execute the command passed to docker run (usually supervisor)
|
||||||
|
exec "$@"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mivo",
|
"name": "mivo",
|
||||||
"version": "1.2.0",
|
"version": "1.2.2",
|
||||||
"description": "This is a complete rewrite of Mivo using a modern MVC architecture.\r It runs on a lightweight custom core designed for performance on low-end devices (STB/Android).",
|
"description": "This is a complete rewrite of Mivo using a modern MVC architecture.\r It runs on a lightweight custom core designed for performance on low-end devices (STB/Android).",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
0
plugins/.gitkeep
Normal file
0
plugins/.gitkeep
Normal file
@@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use App\Core\Hooks;
|
|
||||||
use App\Core\Router;
|
|
||||||
|
|
||||||
// 1. Hook into Router to add a custom page
|
|
||||||
Hooks::addAction('router_init', function(Router $router) {
|
|
||||||
$router->get('/plugin-test', function() {
|
|
||||||
echo "<h1>Hello from Example Plugin!</h1>";
|
|
||||||
echo "<p>This page is registered via <code>router_init</code> hook.</p>";
|
|
||||||
echo "<a href='/'>Back to Home</a>";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. Hook into Head to add custom CSS
|
|
||||||
Hooks::addAction('mivo_head', function() {
|
|
||||||
echo "<!-- Example Plugin CSS -->";
|
|
||||||
echo "<style>body { border-top: 5px solid #10b981; }</style>";
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. Hook into Footer to add custom JS or Text
|
|
||||||
Hooks::addAction('mivo_footer', function() {
|
|
||||||
echo "<!-- Example Plugin Footer -->";
|
|
||||||
echo "<div style='text-align:center; padding: 10px; background: #f0fdf4; color: #166534; font-weight: bold;'>
|
|
||||||
Plugin System is Working! 🚀
|
|
||||||
</div>";
|
|
||||||
});
|
|
||||||
@@ -19,10 +19,12 @@ class I18n {
|
|||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadLanguage(lang) {
|
async loadLanguage(lang, customUrl = null) {
|
||||||
try {
|
try {
|
||||||
const cacheBuster = Date.now();
|
const cacheBuster = Date.now();
|
||||||
const response = await fetch(`/lang/${lang}.json?v=${cacheBuster}`);
|
// Use custom URL if provided, otherwise default to public/lang structure
|
||||||
|
const url = customUrl || `/lang/${lang}.json`;
|
||||||
|
const response = await fetch(`${url}?v=${cacheBuster}`);
|
||||||
if (!response.ok) throw new Error(`Failed to load language: ${lang}`);
|
if (!response.ok) throw new Error(`Failed to load language: ${lang}`);
|
||||||
|
|
||||||
this.translations = await response.json();
|
this.translations = await response.json();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"name": "English",
|
"name": "English",
|
||||||
"flag": "gb"
|
"flag": "us"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ $router->group(['middleware' => 'router.valid'], function($router) {
|
|||||||
// Temporary Test Route
|
// Temporary Test Route
|
||||||
$router->get('/test-alert', [HomeController::class, 'testAlert']);
|
$router->get('/test-alert', [HomeController::class, 'testAlert']);
|
||||||
|
|
||||||
|
// Plugin Language Route - DEPRECATED
|
||||||
|
// Plugins now handle their own routing via Hooks::addAction('router_init')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Protected Admin Routes (Requires Auth)
|
// Protected Admin Routes (Requires Auth)
|
||||||
|
|||||||
Reference in New Issue
Block a user