342 lines
18 KiB
HTML
342 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<link rel="icon" href="{{ url_for('assets', path='img/favicon.ico') }}">
|
|
<title>Blitz Panel | {% block title %}{% endblock %}</title>
|
|
|
|
<!-- Google Font: Source Sans Pro -->
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
|
|
<!-- Font Awesome Icons -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
|
<!-- Theme style -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.2.0/css/adminlte.min.css">
|
|
<!-- iCheck Bootstrap -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/icheck-bootstrap@3.0.1/icheck-bootstrap.min.css">
|
|
<!-- SweetAlert2 -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
|
<!-- Custom CSS -->
|
|
<link rel="stylesheet" href="{{ url_for('assets', path='css/custom.css') }}">
|
|
{% block stylesheets %}{% endblock %}
|
|
</head>
|
|
|
|
<body class="hold-transition sidebar-mini sidebar-collapse">
|
|
<div class="wrapper">
|
|
|
|
<!-- Update Notification Bar -->
|
|
<div id="updateBar" class="m-0 rounded-0 border-0" style="display: none; position: relative; z-index: 1100; background: linear-gradient(135deg, #f0f2ff 0%, #e6e9ff 100%); box-shadow: 0 2px 8px rgba(102, 16, 242, 0.15); border-bottom: 1px solid rgba(0,0,0,0.05);">
|
|
<div class="container-fluid py-3">
|
|
<div class="d-flex align-items-center justify-content-between">
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex align-items-center justify-content-center mr-3" style="width: 36px; height: 36px; background: rgba(255,255,255,0.9); border-radius: 50%; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
|
<i class="fas fa-rocket text-indigo" style="font-size: 16px;"></i>
|
|
</div>
|
|
<div>
|
|
<div class="d-flex align-items-center">
|
|
<span id="updateMessage" class="font-weight-bold text-indigo mb-0" style="font-size: 15px;">New version available</span>
|
|
<button type="button" class="btn btn-link btn-sm p-0 ml-2 text-indigo" id="showChangelog" style="text-decoration: none; opacity: 0.8; transition: all 0.2s ease;">
|
|
<i class="fas fa-chevron-down" style="font-size: 12px;"></i>
|
|
</button>
|
|
</div>
|
|
<small class="d-block" style="font-size: 13px; margin-top: 2px; color: #6f7a99;">Click to view changelog and update options</small>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex align-items-center">
|
|
<div class="dropdown">
|
|
<button class="btn btn-sm dropdown-toggle text-indigo font-weight-bold" type="button" style="background: rgba(255,255,255,0.7); border: 1px solid rgba(102, 16, 242, 0.3); padding: 8px 16px; border-radius: 20px; font-size: 13px;" data-toggle="dropdown">
|
|
<i class="fas fa-download mr-1"></i> Update Options
|
|
</button>
|
|
<div class="dropdown-menu dropdown-menu-right shadow-sm">
|
|
<a class="dropdown-item" href="#" id="viewRelease">
|
|
<i class="fas fa-external-link-alt mr-2 text-success"></i> View Release Page
|
|
</a>
|
|
<div class="dropdown-divider"></div>
|
|
<a class="dropdown-item" href="#" id="remindLater">
|
|
<i class="fas fa-clock mr-2 text-info"></i> Remind me tomorrow
|
|
</a>
|
|
<a class="dropdown-item" href="#" id="skipVersion">
|
|
<i class="fas fa-times mr-2 text-warning"></i> Skip this version
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn btn-sm ml-2 text-indigo" id="closeUpdateBar" style="background: rgba(255,255,255,0.7); border: 1px solid rgba(102, 16, 242, 0.3); width: 32px; height: 32px; border-radius: 50%; padding: 0; opacity: 0.8; transition: all 0.2s ease;">
|
|
<i class="fas fa-times" style="font-size: 12px;"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="changelogContent" class="mt-3" style="display: none;">
|
|
<div style="background: rgba(255,255,255,0.9); border-radius: 8px; padding: 16px; box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);">
|
|
<div class="d-flex align-items-center mb-2">
|
|
<i class="fas fa-list-ul text-info mr-2"></i>
|
|
<h6 class="mb-0 font-weight-bold text-dark">Release Notes</h6>
|
|
</div>
|
|
<div id="changelogText" style="max-height: 180px; overflow-y: auto; font-size: 14px; line-height: 1.5; color: #2d3436;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Navbar -->
|
|
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
|
|
<ul class="navbar-nav">
|
|
<li class="nav-item">
|
|
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a>
|
|
</li>
|
|
</ul>
|
|
<!-- Right navbar links -->
|
|
<ul class="navbar-nav ml-auto">
|
|
<li class="nav-item">
|
|
<a class="nav-link" id="darkModeToggle" href="#">
|
|
<i id="darkModeIcon" class="fas fa-moon"></i>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ url_for('logout') }}">
|
|
<i class="fas fa-sign-out-alt"></i>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<!-- Main Sidebar Container -->
|
|
<aside class="main-sidebar sidebar-dark-primary elevation-4">
|
|
<!-- Brand Logo -->
|
|
<a href="{{ url_for('index') }}" class="brand-link">
|
|
<img src="{{ url_for('assets', path='img/logo.png') }}" alt="Blitz Logo"
|
|
class="brand-image img-circle elevation-3" style="background-color: #f8f9fa; padding: 3px;">
|
|
<span class="brand-text font-weight-light">Blitz Dashboard</span>
|
|
</a>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="sidebar">
|
|
<!-- Sidebar Menu -->
|
|
<nav class="mt-2">
|
|
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
|
|
<li class="nav-item">
|
|
<a href="{{ url_for('index') }}" class="nav-link {% if request.path == url_for('index') %}active{% endif %}">
|
|
<i class="nav-icon fas fa-tachometer-alt"></i>
|
|
<p>Dashboard</p>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a href="{{ url_for('users') }}" class="nav-link {% if request.path == url_for('users') %}active{% endif %}">
|
|
<i class="nav-icon fas fa-users"></i>
|
|
<p>Users</p>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a href="{{ url_for('settings') }}" class="nav-link {% if request.path == url_for('settings') %}active{% endif %}">
|
|
<i class="nav-icon fas fa-tools"></i>
|
|
<p>Settings</p>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a href="{{ url_for('config') }}" class="nav-link {% if request.path == url_for('config') %}active{% endif %}">
|
|
<i class="nav-icon fas fa-cog"></i>
|
|
<p>Config</p>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a href="#" class="nav-link">
|
|
<i class="nav-icon fas fa-book"></i>
|
|
<p>
|
|
Documentation
|
|
<i class="right fas fa-angle-left"></i>
|
|
</p>
|
|
</a>
|
|
<ul class="nav nav-treeview">
|
|
<li class="nav-item">
|
|
<a href="{{ url_for('index') }}docs" class="nav-link">
|
|
<i class="nav-icon fas fa-network-wired"></i>
|
|
<p>API Documentation</p>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a href="https://returnfi.github.io/Blitz-docs/" target="_blank" rel="noopener noreferrer" class="nav-link">
|
|
<i class="nav-icon fas fa-lightbulb"></i>
|
|
<p>Guides & Tutorials</p>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Content Wrapper -->
|
|
<div class="content-wrapper">
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<footer class="main-footer">
|
|
<div class="d-flex align-items-center">
|
|
<a href="https://github.com/ReturnFI/Blitz" target="_blank" rel="noopener noreferrer" class="text-decoration-none mr-3">
|
|
<i class="fab fa-github"></i> GitHub
|
|
</a>
|
|
<a href="https://t.me/hysteria2_panel" target="_blank" rel="noopener noreferrer" class="text-decoration-none mr-3">
|
|
<i class="fab fa-telegram-plane"></i> Telegram
|
|
</a>
|
|
<div class="ml-auto">
|
|
<a href="https://github.com/ReturnFI/Blitz/releases" target="_blank" rel="noopener noreferrer" class="text-decoration-none">
|
|
<i class="fas fa-code-branch"></i> <span id="panel-version">Loading version...</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
|
|
<!-- REQUIRED SCRIPTS -->
|
|
<!-- jQuery -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
|
<!-- Bootstrap 4 -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
|
|
<!-- AdminLTE App -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.2.0/js/adminlte.min.js"></script>
|
|
<!-- SweetAlert2 -->
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.js"></script>
|
|
|
|
<script>
|
|
$(function () {
|
|
const darkModeToggle = $("#darkModeToggle");
|
|
const darkModeIcon = $("#darkModeIcon");
|
|
const isDarkMode = localStorage.getItem("darkMode") === "enabled";
|
|
|
|
setDarkMode(isDarkMode);
|
|
updateIcon(isDarkMode);
|
|
|
|
darkModeToggle.on("click", function (e) {
|
|
e.preventDefault();
|
|
const enabled = $("body").hasClass("dark-mode");
|
|
localStorage.setItem("darkMode", enabled ? "disabled" : "enabled");
|
|
setDarkMode(!enabled);
|
|
updateIcon(!enabled);
|
|
});
|
|
|
|
function setDarkMode(enabled) {
|
|
$("body").toggleClass("dark-mode", enabled);
|
|
|
|
if (enabled) {
|
|
$(".main-header").addClass("navbar-dark").removeClass("navbar-light navbar-white");
|
|
$(".card").addClass("bg-dark");
|
|
} else {
|
|
$(".main-header").addClass("navbar-white navbar-light").removeClass("navbar-dark");
|
|
$(".card").removeClass("bg-dark");
|
|
}
|
|
}
|
|
|
|
function updateIcon(enabled) {
|
|
darkModeIcon.removeClass("fa-moon fa-sun")
|
|
.addClass(enabled ? "fa-sun" : "fa-moon");
|
|
}
|
|
|
|
const versionUrl = "{{ url_for('get_version_info') }}";
|
|
$.ajax({
|
|
url: versionUrl,
|
|
type: 'GET',
|
|
success: function (response) {
|
|
$('#panel-version').text(`Version: ${response.current_version || 'N/A'}`);
|
|
},
|
|
error: function (error) {
|
|
console.error("Error fetching version:", error);
|
|
$('#panel-version').text('Version: Error');
|
|
}
|
|
});
|
|
|
|
function shouldCheckForUpdates() {
|
|
const lastCheck = localStorage.getItem('lastUpdateCheck');
|
|
const updateDismissed = localStorage.getItem('updateDismissed');
|
|
const now = Date.now();
|
|
const checkInterval = 24 * 60 * 60 * 1000;
|
|
|
|
if (!lastCheck) return true;
|
|
if (updateDismissed && now - parseInt(updateDismissed) < 7 * 24 * 60 * 60 * 1000) return false;
|
|
|
|
return now - parseInt(lastCheck) > checkInterval;
|
|
}
|
|
|
|
function showUpdateBar(version, changelog) {
|
|
$('#updateMessage').text(`Version ${version} is now available`);
|
|
$('#changelogText').html(changelog ? changelog.replace(/\n/g, '<br>') : 'No changelog available');
|
|
$('#updateBar').slideDown(300);
|
|
|
|
$('#viewRelease').off('click').on('click', function(e) {
|
|
e.preventDefault();
|
|
window.open('https://github.com/ReturnFI/Blitz/releases/latest', '_blank');
|
|
});
|
|
|
|
$('#showChangelog').off('click').on('click', function() {
|
|
const $content = $('#changelogContent');
|
|
const $icon = $(this).find('i');
|
|
|
|
if ($content.is(':visible')) {
|
|
$content.slideUp(250);
|
|
$icon.removeClass('fa-chevron-up').addClass('fa-chevron-down');
|
|
$(this).css('opacity', '0.8');
|
|
} else {
|
|
$content.slideDown(250);
|
|
$icon.removeClass('fa-chevron-down').addClass('fa-chevron-up');
|
|
$(this).css('opacity', '1');
|
|
}
|
|
});
|
|
|
|
$('.dropdown-toggle').dropdown();
|
|
|
|
$('#remindLater').off('click').on('click', function(e) {
|
|
e.preventDefault();
|
|
$('#updateBar').slideUp(350);
|
|
});
|
|
|
|
$('#skipVersion').off('click').on('click', function(e) {
|
|
e.preventDefault();
|
|
localStorage.setItem('dismissedVersion', version);
|
|
localStorage.setItem('updateDismissed', Date.now().toString());
|
|
$('#updateBar').slideUp(350);
|
|
});
|
|
|
|
$('#closeUpdateBar').off('click').on('click', function() {
|
|
$('#updateBar').slideUp(350);
|
|
});
|
|
}
|
|
|
|
function checkForUpdates() {
|
|
if (!shouldCheckForUpdates()) return;
|
|
|
|
const checkVersionUrl = "{{ url_for('check_version_info') }}";
|
|
$.ajax({
|
|
url: checkVersionUrl,
|
|
type: 'GET',
|
|
timeout: 10000,
|
|
success: function (response) {
|
|
localStorage.setItem('lastUpdateCheck', Date.now().toString());
|
|
|
|
if (response.is_latest) {
|
|
localStorage.removeItem('updateDismissed');
|
|
return;
|
|
}
|
|
|
|
const dismissedVersion = localStorage.getItem('dismissedVersion');
|
|
if (dismissedVersion === response.latest_version) return;
|
|
|
|
showUpdateBar(response.latest_version, response.changelog);
|
|
},
|
|
error: function (xhr, status, error) {
|
|
if (status !== 'timeout') {
|
|
console.warn("Update check failed:", error);
|
|
}
|
|
localStorage.setItem('lastUpdateCheck', Date.now().toString());
|
|
}
|
|
});
|
|
}
|
|
|
|
setTimeout(checkForUpdates, 2000);
|
|
});
|
|
</script>
|
|
{% block javascripts %}{% endblock %}
|
|
</body>
|
|
|
|
</html> |