AstraOS Ver. 1.17:

- Comments entfernt
This commit is contained in:
MrWhiff 2025-12-21 23:56:29 +01:00
parent fd707cd0b7
commit f4bfa163a7
17 changed files with 17 additions and 153 deletions

View file

@ -11,7 +11,6 @@
</header> </header>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Verification Form -->
<div class="bg-black/40 p-6 rounded-xl backdrop-blur border {% if maintenance_active %}border-yellow-500/30{% else %}border-purple-500/20{% endif %}"> <div class="bg-black/40 p-6 rounded-xl backdrop-blur border {% if maintenance_active %}border-yellow-500/30{% else %}border-purple-500/20{% endif %}">
<h3 class="text-2xl font-semibold mb-4">Neue Überprüfung</h3> <h3 class="text-2xl font-semibold mb-4">Neue Überprüfung</h3>
<form method="POST" class="space-y-4"> <form method="POST" class="space-y-4">
@ -61,7 +60,6 @@
{% endif %} {% endif %}
</div> </div>
<!-- User Search -->
<div class="bg-black/40 p-6 rounded-xl backdrop-blur border {% if maintenance_active %}border-yellow-500/30{% else %}border-purple-500/20{% endif %}"> <div class="bg-black/40 p-6 rounded-xl backdrop-blur border {% if maintenance_active %}border-yellow-500/30{% else %}border-purple-500/20{% endif %}">
<h3 class="text-2xl font-semibold mb-4">Benutzer suchen</h3> <h3 class="text-2xl font-semibold mb-4">Benutzer suchen</h3>
<form method="GET" class="flex gap-2 mb-4"> <form method="GET" class="flex gap-2 mb-4">
@ -97,9 +95,8 @@
function copyToClipboard(elementId) { function copyToClipboard(elementId) {
const input = document.getElementById(elementId); const input = document.getElementById(elementId);
input.select(); input.select();
input.setSelectionRange(0, 99999); // For mobile devices input.setSelectionRange(0, 99999);
document.execCommand('copy'); document.execCommand('copy');
// Optional: Visuelles Feedback geben
const originalButtonText = event.target.innerText; const originalButtonText = event.target.innerText;
event.target.innerText = 'Kopiert!'; event.target.innerText = 'Kopiert!';
setTimeout(() => { setTimeout(() => {

View file

@ -32,7 +32,6 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<!-- HEADER -->
<header class="flex justify-between items-center mb-6"> <header class="flex justify-between items-center mb-6">
<div> <div>
<a href="{{ url_for('discord_bots') }}" class="text-sm {% if maintenance_active %}text-yellow-400 hover:text-yellow-300{% else %}text-purple-400 hover:text-purple-300{% endif %}"> Zurück zur Übersicht</a> <a href="{{ url_for('discord_bots') }}" class="text-sm {% if maintenance_active %}text-yellow-400 hover:text-yellow-300{% else %}text-purple-400 hover:text-purple-300{% endif %}"> Zurück zur Übersicht</a>
@ -50,7 +49,6 @@
</div> </div>
</header> </header>
<!-- CONSOLE -->
<div id="console-output"> <div id="console-output">
<div class="log-line log-system">Initialisiere Konsolenverbindung...</div> <div class="log-line log-system">Initialisiere Konsolenverbindung...</div>
</div> </div>

View file

@ -12,7 +12,6 @@
box-shadow: 0 0 20px rgba(192,132,252,0.3); box-shadow: 0 0 20px rgba(192,132,252,0.3);
transform: translateY(-4px); transform: translateY(-4px);
} }
/* Schriftgröße für Systemstatus-Text im Wartungsmodus noch kleiner und mittig */
#system-status-text.small { #system-status-text.small {
font-size: 2rem; font-size: 2rem;
text-align: center; text-align: center;
@ -45,7 +44,6 @@
</div> </div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Aktive Benutzer -->
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur <div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Aktive Benutzer</h3> <h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Aktive Benutzer</h3>
@ -60,14 +58,12 @@
</p> </p>
</div> </div>
<!-- Server-Auslastung -->
<div id="server-load-card" class="glow-card opacity-0 translate-y-8 bg-black/40 border border-red-500/40 rounded-xl p-6 backdrop-blur"> <div id="server-load-card" class="glow-card opacity-0 translate-y-8 bg-black/40 border border-red-500/40 rounded-xl p-6 backdrop-blur">
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Server-Auslastung</h3> <h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Server-Auslastung</h3>
<p class="text-4xl font-bold" id="server-load">{{ stats.server_load.percent }}%</p> <p class="text-4xl font-bold" id="server-load">{{ stats.server_load.percent }}%</p>
<p class="text-red-400 text-sm mt-1" id="server-load-status">{{ stats.server_load.status }}</p> <p class="text-red-400 text-sm mt-1" id="server-load-status">{{ stats.server_load.status }}</p>
</div> </div>
<!-- Offene Tickets -->
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur <div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Offene Tickets</h3> <h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Offene Tickets</h3>
@ -75,7 +71,6 @@
<p class="text-gray-400 text-sm mt-1">Keine offenen Anfragen</p> <p class="text-gray-400 text-sm mt-1">Keine offenen Anfragen</p>
</div> </div>
<!-- Systemstatus -->
<div id="system-status-card" class="glow-card opacity-0 translate-y-8 bg-black/40 border border-green-500/40 rounded-xl p-6 backdrop-blur"> <div id="system-status-card" class="glow-card opacity-0 translate-y-8 bg-black/40 border border-green-500/40 rounded-xl p-6 backdrop-blur">
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Systemstatus</h3> <h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Systemstatus</h3>
{% set status = stats.system_status.status %} {% set status = stats.system_status.status %}
@ -97,7 +92,6 @@
</p> </p>
</div> </div>
<!-- Geplante Wartung -->
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur <div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Geplante Wartung</h3> <h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Geplante Wartung</h3>
@ -114,7 +108,6 @@
{% endif %} {% endif %}
</div> </div>
<!-- Letzte Benutzererstellung -->
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur <div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Letzte Benutzererstellung</h3> <h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Letzte Benutzererstellung</h3>
@ -126,15 +119,11 @@
<script> <script>
gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollTrigger);
// Lade-Timeline
setTimeout(() => { setTimeout(() => {
// Timeline für Header + Cards
const tl = gsap.timeline({ defaults: { duration: 0.4, ease: "power3.out" } }); const tl = gsap.timeline({ defaults: { duration: 0.4, ease: "power3.out" } });
// Header
tl.to("header", { opacity: 1, y: 0 }); tl.to("header", { opacity: 1, y: 0 });
// Cards schnell einblenden
tl.to(".glow-card", { opacity: 1, y: 0, stagger: 0.08 }); tl.to(".glow-card", { opacity: 1, y: 0, stagger: 0.08 });
// Header Parallax // Header Parallax
@ -149,7 +138,6 @@ setTimeout(() => {
}); });
}, 800); }, 800);
// Hover Glow
document.querySelectorAll(".glow-card").forEach(card => { document.querySelectorAll(".glow-card").forEach(card => {
card.addEventListener("mouseenter", () => { card.addEventListener("mouseenter", () => {
gsap.to(card, { boxShadow: "0 0 30px rgba(192,132,252,0.4)", duration: 0.2 }); gsap.to(card, { boxShadow: "0 0 30px rgba(192,132,252,0.4)", duration: 0.2 });
@ -159,7 +147,6 @@ document.querySelectorAll(".glow-card").forEach(card => {
}); });
}); });
// Server-Auslastung alle 5 Sekunden aktualisieren
function updateServerLoad() { function updateServerLoad() {
fetch('/api/server_load') fetch('/api/server_load')
.then(res => res.json()) .then(res => res.json())
@ -194,7 +181,6 @@ function updateServerLoad() {
setInterval(updateServerLoad, 5000); setInterval(updateServerLoad, 5000);
updateServerLoad(); updateServerLoad();
// Systemstatus dynamisch Randfarbe anpassen
function updateSystemStatusCard() { function updateSystemStatusCard() {
const card = document.getElementById('system-status-card'); const card = document.getElementById('system-status-card');
const statusText = document.getElementById('system-status-text'); const statusText = document.getElementById('system-status-text');
@ -211,8 +197,7 @@ function updateSystemStatusCard() {
card.classList.add('border-red-500/40'); card.classList.add('border-red-500/40');
} }
} }
setTimeout(updateSystemStatusCard, 100); // initial nach Render setTimeout(updateSystemStatusCard, 100);
// Optional: falls Systemstatus dynamisch per AJAX kommt, hier regelmäßig prüfen
setInterval(updateSystemStatusCard, 2000); setInterval(updateSystemStatusCard, 2000);
</script> </script>
{% endblock %} {% endblock %}

View file

@ -5,7 +5,6 @@
{% block head %} {% block head %}
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script> <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
<style> <style>
/* Toggle Switch */
.switch { position: relative; display: inline-block; width: 50px; height: 28px; } .switch { position: relative; display: inline-block; width: 50px; height: 28px; }
.switch input { opacity: 0; width: 0; height: 0; } .switch input { opacity: 0; width: 0; height: 0; }
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #4a5568; transition: .4s; border-radius: 28px; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #4a5568; transition: .4s; border-radius: 28px; }
@ -17,7 +16,6 @@
{% block content %} {% block content %}
<div x-data="{ showUploadModal: false, showDeleteModal: false, botToDelete: null }"> <div x-data="{ showUploadModal: false, showDeleteModal: false, botToDelete: null }">
<!-- HEADER -->
<header class="flex justify-between items-center mb-10"> <header class="flex justify-between items-center mb-10">
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord Bot Management</h2> <h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord Bot Management</h2>
<button @click="showUploadModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white <button @click="showUploadModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white
@ -26,7 +24,6 @@
</button> </button>
</header> </header>
<!-- BOT LIST -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{% for bot in bots %} {% for bot in bots %}
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-6 flex flex-col justify-between <div class="bg-black/40 rounded-xl backdrop-blur-lg p-6 flex flex-col justify-between
@ -62,7 +59,6 @@
{% endfor %} {% endfor %}
</div> </div>
<!-- UPLOAD BOT MODAL -->
<div x-show="showUploadModal" @keydown.escape.window="showUploadModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;"> <div x-show="showUploadModal" @keydown.escape.window="showUploadModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
<div @click.away="showUploadModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-md <div @click.away="showUploadModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-md
{% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}"> {% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}">
@ -86,7 +82,6 @@
</div> </div>
</div> </div>
<!-- DELETE CONFIRMATION MODAL -->
<div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;"> <div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
<div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md"> <div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md">
<h3 class="text-2xl font-bold text-red-400 mb-4">Bot löschen</h3> <h3 class="text-2xl font-bold text-red-400 mb-4">Bot löschen</h3>

View file

@ -5,7 +5,6 @@
{% block head %} {% block head %}
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style> <style>
/* Toggle Switch Styles */
.switch { position: relative; display: inline-block; width: 50px; height: 28px; } .switch { position: relative; display: inline-block; width: 50px; height: 28px; }
.switch input { opacity: 0; width: 0; height: 0; } .switch input { opacity: 0; width: 0; height: 0; }
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #4a5568; transition: .4s; border-radius: 28px; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #4a5568; transition: .4s; border-radius: 28px; }
@ -17,12 +16,10 @@
{% block content %} {% block content %}
<div x-data="{ isCheater: false }" class="space-y-10"> <div x-data="{ isCheater: false }" class="space-y-10">
<!-- HEADER -->
<header class="flex justify-between items-center"> <header class="flex justify-between items-center">
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">IP Analyzer</h2> <h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">IP Analyzer</h2>
</header> </header>
<!-- INPUT FORM -->
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> <div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<form action="{{ url_for('ip_analyzer') }}" method="POST" class="space-y-6"> <form action="{{ url_for('ip_analyzer') }}" method="POST" class="space-y-6">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
@ -58,7 +55,6 @@
</form> </form>
</div> </div>
<!-- RESULTS -->
{% if error %} {% if error %}
<div class="bg-red-500/20 border border-red-500/30 text-red-300 p-4 rounded-lg">{{ error }}</div> <div class="bg-red-500/20 border border-red-500/30 text-red-300 p-4 rounded-lg">{{ error }}</div>
{% endif %} {% endif %}

View file

@ -5,29 +5,22 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AstraOS — Login</title> <title>AstraOS — Login</title>
<link rel="icon" href="{{ url_for('static', filename='media/AstraOS_Logo.ico') }}" type="image/x-icon"> <link rel="icon" href="{{ url_for('static', filename='media/AstraOS_Logo.ico') }}" type="image/x-icon">
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/TextPlugin.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/TextPlugin.min.js"></script>
<style> <style>
body { body {
background: radial-gradient(circle at top, #1b1b26, #0a0a0f 70%); background: radial-gradient(circle at top, #1b1b26, #0a0a0f 70%);
} }
</style> </style>
</head> </head>
<body class="text-white"> <body class="text-white">
<div id="startup" class="fixed inset-0 bg-black flex flex-col items-center justify-center z-50"> <div id="startup" class="fixed inset-0 bg-black flex flex-col items-center justify-center z-50">
<div id="star" class="w-16 h-16 relative"> <div id="star" class="w-16 h-16 relative">
<div class="absolute inset-0 rounded-full blur-2xl opacity-70" <div class="absolute inset-0 rounded-full blur-2xl opacity-70"
style="background: rgba(192, 132, 252, 0.7)"></div> style="background: rgba(192, 132, 252, 0.7)"></div>
<svg class="relative z-10" viewBox="0 0 100 100"> <svg class="relative z-10" viewBox="0 0 100 100">
<path <path
d="M50 5 d="M50 5
L63 40 L63 40
@ -40,7 +33,6 @@
Z" Z"
fill="#c084fc" fill="#c084fc"
/> />
<path <path
d="M50 28 d="M50 28
L58 45 L58 45
@ -54,20 +46,14 @@
fill="#ffffff" fill="#ffffff"
opacity="0.9" opacity="0.9"
/> />
</svg> </svg>
</div> </div>
<p class="mt-4 text-xl tracking-wide opacity-80">AstraOS</p> <p class="mt-4 text-xl tracking-wide opacity-80">AstraOS</p>
</div> </div>
<div id="loginContent" class="min-h-screen flex items-center justify-center px-4"> <div id="loginContent" class="min-h-screen flex items-center justify-center px-4">
<div id="loginBox" class="w-full max-w-md bg-black/40 border border-purple-500/20 rounded-2xl p-8 backdrop-blur-lg shadow-xl opacity-0"> <div id="loginBox" class="w-full max-w-md bg-black/40 border border-purple-500/20 rounded-2xl p-8 backdrop-blur-lg shadow-xl opacity-0">
<h1 id="loginTitle" class="text-3xl font-bold text-center mb-6 tracking-wider text-purple-300"> <h1 id="loginTitle" class="text-3xl font-bold text-center mb-6 tracking-wider text-purple-300">
</h1> </h1>
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %} {% if messages %}
{% for category, message in messages %} {% for category, message in messages %}
@ -77,7 +63,6 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<form id="loginForm" action="/login" method="POST" class="flex flex-col gap-5 opacity-0"> <form id="loginForm" action="/login" method="POST" class="flex flex-col gap-5 opacity-0">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div> <div>
@ -86,7 +71,6 @@
class="mt-1 w-full px-4 py-2 rounded-lg bg-gray-800/60 text-white class="mt-1 w-full px-4 py-2 rounded-lg bg-gray-800/60 text-white
focus:outline-none focus:ring-2 focus:ring-purple-600"> focus:outline-none focus:ring-2 focus:ring-purple-600">
</div> </div>
<div x-data="{ showPassword: false }"> <div x-data="{ showPassword: false }">
<label class="text-gray-300 text-sm">Passwort</label> <label class="text-gray-300 text-sm">Passwort</label>
<div class="relative"> <div class="relative">
@ -104,31 +88,24 @@
</button> </button>
</div> </div>
</div> </div>
<button type="submit" <button type="submit"
class="mt-2 bg-purple-600 hover:bg-purple-700 text-white py-2 rounded-lg class="mt-2 bg-purple-600 hover:bg-purple-700 text-white py-2 rounded-lg
font-semibold transition"> font-semibold transition">
Login Login
</button> </button>
<div class="flex items-center my-1"> <div class="flex items-center my-1">
<div class="flex-grow border-t border-gray-600"></div> <div class="flex-grow border-t border-gray-600"></div>
<span class="flex-shrink mx-4 text-gray-400 text-sm">oder</span> <span class="flex-shrink mx-4 text-gray-400 text-sm">oder</span>
<div class="flex-grow border-t border-gray-600"></div> <div class="flex-grow border-t border-gray-600"></div>
</div> </div>
<a href="{{ url_for('login_discord') }}" <a href="{{ url_for('login_discord') }}"
class="flex items-center justify-center bg-[#5865F2] hover:bg-[#4752C4] text-white py-2 rounded-lg font-semibold transition"> class="flex items-center justify-center bg-[#5865F2] hover:bg-[#4752C4] text-white py-2 rounded-lg font-semibold transition">
<svg class="w-6 h-6 mr-2" aria-hidden="true" role="img" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.36981C18.2767 3.20426 16.1224 2.27659 13.8468 1.61774C13.679 1.57584 13.5041 1.68116 13.4343 1.84475C12.8151 3.24952 12.3413 4.96228 12.0009 6.53635C10.6866 6.37181 9.36521 6.37181 8.01525 6.53635C7.67488 4.96228 7.20103 3.24952 6.58181 1.84475C6.51205 1.68116 6.33712 1.57584 6.16931 1.61774C3.89372 2.27659 1.73942 3.20426 -0.300884 4.36981C-0.535332 4.49339 -0.620213 4.7833 -0.499842 5.01329C0.0107496 5.92333 0.406433 6.97593 0.683583 8.0343C0.715011 8.14443 0.801901 8.23132 0.912038 8.26275C2.43731 8.73725 3.93953 9.1111 5.42371 9.34818C5.60563 9.3789 5.75754 9.24538 5.71964 9.06346C5.54471 8.25822 5.3928 7.43716 5.24089 6.62322C5.22194 6.52066 5.28274 6.4181 5.3853 6.39233C9.41501 5.69637 14.5858 5.69637 18.6155 6.39233C18.7181 6.4181 18.7789 6.52066 18.7599 6.62322C18.608 7.43716 18.4561 8.25822 18.2812 9.06346C18.2433 9.24538 18.3952 9.3789 18.5771 9.34818C20.0613 9.1111 21.5635 8.73725 23.0888 8.26275C23.1989 8.23132 23.2858 8.14443 23.3172 8.0343C23.5944 6.97593 23.9901 5.92333 24.4998 5.01329C24.6202 4.7833 24.5353 4.49339 24.3009 4.36981L20.317 4.36981Z"></path><path fill="currentColor" d="M12.0009 16.4373C14.2131 16.4373 16.0013 14.834 16.0013 12.8337C16.0013 10.8334 14.2202 9.23004 12.0009 9.23004C9.78161 9.23004 8.00049 10.8334 8.00049 12.8337C8.00049 14.834 9.78161 16.4373 12.0009 16.4373ZM18.0016 16.4373C20.2138 16.4373 22.002 14.834 22.002 12.8337C22.002 10.8334 20.2209 9.23004 18.0016 9.23004C15.7823 9.23004 14.0012 10.8334 14.0012 12.8337C14.0012 14.834 15.7823 16.4373 18.0016 16.4373Z"></path></svg> <svg class="w-6 h-6 mr-2" aria-hidden="true" role="img" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.36981C18.2767 3.20426 16.1224 2.27659 13.8468 1.61774C13.679 1.57584 13.5041 1.68116 13.4343 1.84475C12.8151 3.24952 12.3413 4.96228 12.0009 6.53635C10.6866 6.37181 9.36521 6.37181 8.01525 6.53635C7.67488 4.96228 7.20103 3.24952 6.58181 1.84475C6.51205 1.68116 6.33712 1.57584 6.16931 1.61774C3.89372 2.27659 1.73942 3.20426 -0.300884 4.36981C-0.535332 4.49339 -0.620213 4.7833 -0.499842 5.01329C0.0107496 5.92333 0.406433 6.97593 0.683583 8.0343C0.715011 8.14443 0.801901 8.23132 0.912038 8.26275C2.43731 8.73725 3.93953 9.1111 5.42371 9.34818C5.60563 9.3789 5.75754 9.24538 5.71964 9.06346C5.54471 8.25822 5.3928 7.43716 5.24089 6.62322C5.22194 6.52066 5.28274 6.4181 5.3853 6.39233C9.41501 5.69637 14.5858 5.69637 18.6155 6.39233C18.7181 6.4181 18.7789 6.52066 18.7599 6.62322C18.608 7.43716 18.4561 8.25822 18.2812 9.06346C18.2433 9.24538 18.3952 9.3789 18.5771 9.34818C20.0613 9.1111 21.5635 8.73725 23.0888 8.26275C23.1989 8.23132 23.2858 8.14443 23.3172 8.0343C23.5944 6.97593 23.9901 5.92333 24.4998 5.01329C24.6202 4.7833 24.5353 4.49339 24.3009 4.36981L20.317 4.36981Z"></path><path fill="currentColor" d="M12.0009 16.4373C14.2131 16.4373 16.0013 14.834 16.0013 12.8337C16.0013 10.8334 14.2202 9.23004 12.0009 9.23004C9.78161 9.23004 8.00049 10.8334 8.00049 12.8337C8.00049 14.834 9.78161 16.4373 12.0009 16.4373ZM18.0016 16.4373C20.2138 16.4373 22.002 14.834 22.002 12.8337C22.002 10.8334 20.2209 9.23004 18.0016 9.23004C15.7823 9.23004 14.0012 10.8334 14.0012 12.8337C14.0012 14.834 15.7823 16.4373 18.0016 16.4373Z"></path></svg>
Mit Discord anmelden Mit Discord anmelden
</a> </a>
</form> </form>
</div> </div>
</div> </div>
<script> <script>
gsap.to("#star", { gsap.to("#star", {
rotation: 360, rotation: 360,
@ -136,7 +113,6 @@
ease: "power1.inOut", ease: "power1.inOut",
repeat: -1 repeat: -1
}); });
gsap.to("#star", { gsap.to("#star", {
scale: 1.22, scale: 1.22,
duration: 1, duration: 1,
@ -144,20 +120,15 @@
repeat: -1, repeat: -1,
ease: "power1.inOut" ease: "power1.inOut"
}); });
gsap.registerPlugin(TextPlugin); gsap.registerPlugin(TextPlugin);
{% if not get_flashed_messages() %} {% if not get_flashed_messages() %}
// Nur Animation abspielen, wenn keine Nachrichten vorhanden sind (erster Besuch)
setTimeout(() => { setTimeout(() => {
gsap.to("#startup", { gsap.to("#startup", {
opacity: 0, opacity: 0,
duration: 0.5, duration: 0.5,
onComplete: () => { onComplete: () => {
document.getElementById("startup").style.display = "none"; document.getElementById("startup").style.display = "none";
const tl = gsap.timeline(); const tl = gsap.timeline();
tl.fromTo("#loginBox", tl.fromTo("#loginBox",
{ opacity: 0, scale: 0.8 }, { opacity: 0, scale: 0.8 },
{ {
@ -167,13 +138,11 @@
ease: "power2.out" ease: "power2.out"
} }
); );
tl.to("#loginTitle", { tl.to("#loginTitle", {
duration: 0.8, duration: 0.8,
text: "AstraOS Login", text: "AstraOS Login",
ease: "none" ease: "none"
}, "-=0.2"); }, "-=0.2");
tl.to("#loginForm", { tl.to("#loginForm", {
opacity: 1, opacity: 1,
duration: 0.4 duration: 0.4
@ -182,13 +151,11 @@
}); });
}, 800); }, 800);
{% else %} {% else %}
// Wenn Nachrichten vorhanden sind, Animation überspringen
document.getElementById("startup").style.display = "none"; document.getElementById("startup").style.display = "none";
document.getElementById("loginBox").style.opacity = 1; document.getElementById("loginBox").style.opacity = 1;
document.getElementById("loginForm").style.opacity = 1; document.getElementById("loginForm").style.opacity = 1;
document.getElementById("loginTitle").textContent = "AstraOS Login"; document.getElementById("loginTitle").textContent = "AstraOS Login";
{% endif %} {% endif %}
</script> </script>
</body> </body>
</html> </html>

View file

@ -37,7 +37,6 @@
</div> </div>
</div> </div>
<!-- PAGINATION -->
{% if total_pages > 1 %} {% if total_pages > 1 %}
<nav class="mt-6 flex items-center justify-between"> <nav class="mt-6 flex items-center justify-between">
<div> <div>

View file

@ -14,7 +14,6 @@
</style> </style>
</head> </head>
<body class="text-white"> <body class="text-white">
<div class="min-h-screen flex flex-col items-center justify-center text-center px-4"> <div class="min-h-screen flex flex-col items-center justify-center text-center px-4">
<div id="star" class="w-16 h-16 relative mb-6"> <div id="star" class="w-16 h-16 relative mb-6">
<div class="absolute inset-0 rounded-full blur-2xl opacity-70" style="background: rgba(243, 156, 18, 0.7)"></div> <div class="absolute inset-0 rounded-full blur-2xl opacity-70" style="background: rgba(243, 156, 18, 0.7)"></div>
@ -22,7 +21,6 @@
<path stroke-linecap="round" stroke-linejoin="round" d="M11.42 15.17L17.25 21A2.652 2.652 0 0021 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.73-.664 1.203-.832l3.528-1.604a2.652 2.652 0 10-3.528-3.528l-1.604 3.528c-.168.473-.448.886-.832 1.203l-3.03 2.496m0 0l-5.877-5.877A2.652 2.652 0 003 9.02l5.877 5.877m0 0l-2.496 3.03c-.317.384-.73.664-1.203.832L3 21a2.652 2.652 0 003.528 3.528l1.604-3.528c.168-.473.448-.886.832-1.203l3.03-2.496m0 0l5.877 5.877a2.652 2.652 0 003.528-3.528l-5.877-5.877m0 0L9.02 3a2.652 2.652 0 00-3.528 3.528L9.02 9.02" /> <path stroke-linecap="round" stroke-linejoin="round" d="M11.42 15.17L17.25 21A2.652 2.652 0 0021 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.73-.664 1.203-.832l3.528-1.604a2.652 2.652 0 10-3.528-3.528l-1.604 3.528c-.168.473-.448.886-.832 1.203l-3.03 2.496m0 0l-5.877-5.877A2.652 2.652 0 003 9.02l5.877 5.877m0 0l-2.496 3.03c-.317.384-.73.664-1.203.832L3 21a2.652 2.652 0 003.528 3.528l1.604-3.528c.168-.473.448-.886.832-1.203l3.03-2.496m0 0l5.877 5.877a2.652 2.652 0 003.528-3.528l-5.877-5.877m0 0L9.02 3a2.652 2.652 0 00-3.528 3.528L9.02 9.02" />
</svg> </svg>
</div> </div>
<h1 class="text-4xl md:text-5xl font-bold text-yellow-400 tracking-wide mb-4">Wartungsarbeiten</h1> <h1 class="text-4xl md:text-5xl font-bold text-yellow-400 tracking-wide mb-4">Wartungsarbeiten</h1>
<p class="text-lg text-gray-300 max-w-2xl mb-2"> <p class="text-lg text-gray-300 max-w-2xl mb-2">
{{ maint_info.status if maint_info and maint_info.status else 'Wir führen zurzeit planmäßige Wartungsarbeiten durch, um unsere Dienste zu verbessern.' }} {{ maint_info.status if maint_info and maint_info.status else 'Wir führen zurzeit planmäßige Wartungsarbeiten durch, um unsere Dienste zu verbessern.' }}
@ -30,7 +28,6 @@
<p class="text-lg text-gray-300 max-w-2xl"> <p class="text-lg text-gray-300 max-w-2xl">
Wir sind bald wieder für Sie da. Wir sind bald wieder für Sie da.
</p> </p>
{% if maint_info and maint_info.time %} {% if maint_info and maint_info.time %}
<div class="mt-8 bg-black/30 border border-yellow-500/30 rounded-lg p-4"> <div class="mt-8 bg-black/30 border border-yellow-500/30 rounded-lg p-4">
<p class="text-gray-400">Voraussichtliches Ende:</p> <p class="text-gray-400">Voraussichtliches Ende:</p>
@ -38,14 +35,12 @@
<p class="text-xl font-semibold text-yellow-300">{{ end_time.strftime('%d. %B %Y, %H:%M Uhr') }}</p> <p class="text-xl font-semibold text-yellow-300">{{ end_time.strftime('%d. %B %Y, %H:%M Uhr') }}</p>
</div> </div>
{% endif %} {% endif %}
<div class="absolute bottom-10"> <div class="absolute bottom-10">
<a href="{{ url_for('maintenance_login') }}" class="px-5 py-2 border border-yellow-500/40 text-yellow-300 rounded-lg hover:bg-yellow-500/10 transition-colors text-sm"> <a href="{{ url_for('maintenance_login') }}" class="px-5 py-2 border border-yellow-500/40 text-yellow-300 rounded-lg hover:bg-yellow-500/10 transition-colors text-sm">
Wartungsarbeiten Login Wartungsarbeiten Login
</a> </a>
</div> </div>
</div> </div>
<script> <script>
gsap.to("#star", { gsap.to("#star", {
rotation: 360, rotation: 360,
@ -54,6 +49,5 @@
repeat: -1 repeat: -1
}); });
</script> </script>
</body> </body>
</html> </html>

View file

@ -5,21 +5,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AstraOS — Maintenance Login</title> <title>AstraOS — Maintenance Login</title>
<link rel="icon" href="{{ url_for('static', filename='media/AstraOS_Logo.ico') }}" type="image/x-icon"> <link rel="icon" href="{{ url_for('static', filename='media/AstraOS_Logo.ico') }}" type="image/x-icon">
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/TextPlugin.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/TextPlugin.min.js"></script>
<style> <style>
body { body {
background: radial-gradient(circle at top, #2c2315, #0a0a0f 70%); background: radial-gradient(circle at top, #2c2315, #0a0a0f 70%);
} }
</style> </style>
</head> </head>
<body class="text-white"> <body class="text-white">
<div id="startup" class="fixed inset-0 bg-black flex flex-col items-center justify-center z-50"> <div id="startup" class="fixed inset-0 bg-black flex flex-col items-center justify-center z-50">
<div id="star" class="w-16 h-16 relative"> <div id="star" class="w-16 h-16 relative">
<div class="absolute inset-0 rounded-full blur-2xl opacity-70" style="background: rgba(243, 156, 18, 0.7)"></div> <div class="absolute inset-0 rounded-full blur-2xl opacity-70" style="background: rgba(243, 156, 18, 0.7)"></div>
@ -29,20 +25,14 @@
</div> </div>
<p class="mt-4 text-xl tracking-wide opacity-80">AstraOS Maintenance</p> <p class="mt-4 text-xl tracking-wide opacity-80">AstraOS Maintenance</p>
</div> </div>
<div id="loginContent" class="min-h-screen flex items-center justify-center px-4"> <div id="loginContent" class="min-h-screen flex items-center justify-center px-4">
<div id="loginBox" class="w-full max-w-md bg-black/40 border border-yellow-500/20 rounded-2xl p-8 backdrop-blur-lg shadow-xl opacity-0"> <div id="loginBox" class="w-full max-w-md bg-black/40 border border-yellow-500/20 rounded-2xl p-8 backdrop-blur-lg shadow-xl opacity-0">
<div class="flex justify-center items-center gap-4 mb-6"> <div class="flex justify-center items-center gap-4 mb-6">
<svg class="w-8 h-8 text-yellow-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <svg class="w-8 h-8 text-yellow-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
</svg> </svg>
<h1 id="loginTitle" class="text-3xl font-bold text-center tracking-wider text-yellow-300"></h1> <h1 id="loginTitle" class="text-3xl font-bold text-center tracking-wider text-yellow-300"></h1>
</div> </div>
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %} {% if messages %}
{% for category, message in messages %} {% for category, message in messages %}
@ -52,7 +42,6 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<form id="loginForm" action="{{ url_for('maintenance_login') }}" method="POST" class="flex flex-col gap-5 opacity-0"> <form id="loginForm" action="{{ url_for('maintenance_login') }}" method="POST" class="flex flex-col gap-5 opacity-0">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div> <div>
@ -61,7 +50,6 @@
class="mt-1 w-full px-4 py-2 rounded-lg bg-gray-800/60 text-white class="mt-1 w-full px-4 py-2 rounded-lg bg-gray-800/60 text-white
focus:outline-none focus:ring-2 focus:ring-yellow-500"> focus:outline-none focus:ring-2 focus:ring-yellow-500">
</div> </div>
<div x-data="{ showPassword: false }"> <div x-data="{ showPassword: false }">
<label class="text-gray-300 text-sm">Passwort</label> <label class="text-gray-300 text-sm">Passwort</label>
<div class="relative"> <div class="relative">
@ -79,19 +67,14 @@
</button> </button>
</div> </div>
</div> </div>
<button type="submit" <button type="submit"
class="mt-2 bg-yellow-600 hover:bg-yellow-700 text-white py-2 rounded-lg class="mt-2 bg-yellow-600 hover:bg-yellow-700 text-white py-2 rounded-lg
font-semibold transition"> font-semibold transition">
Bypass Login Bypass Login
</button> </button>
</form> </form>
</div> </div>
</div> </div>
<script> <script>
gsap.to("#star", { gsap.to("#star", {
rotation: 360, rotation: 360,
@ -99,20 +82,15 @@
ease: "none", ease: "none",
repeat: -1 repeat: -1
}); });
gsap.registerPlugin(TextPlugin); gsap.registerPlugin(TextPlugin);
{% if not get_flashed_messages() %} {% if not get_flashed_messages() %}
// Nur Animation abspielen, wenn keine Nachrichten vorhanden sind
setTimeout(() => { setTimeout(() => {
gsap.to("#startup", { gsap.to("#startup", {
opacity: 0, opacity: 0,
duration: 0.5, duration: 0.5,
onComplete: () => { onComplete: () => {
document.getElementById("startup").style.display = "none"; document.getElementById("startup").style.display = "none";
const tl = gsap.timeline(); const tl = gsap.timeline();
tl.fromTo("#loginBox", tl.fromTo("#loginBox",
{ opacity: 0, scale: 0.8 }, { opacity: 0, scale: 0.8 },
{ {
@ -122,13 +100,11 @@
ease: "power2.out" ease: "power2.out"
} }
); );
tl.to("#loginTitle", { tl.to("#loginTitle", {
duration: 0.8, duration: 0.8,
text: "Maintenance Login", text: "Maintenance Login",
ease: "none" ease: "none"
}, "-=0.2"); }, "-=0.2");
tl.to("#loginForm", { tl.to("#loginForm", {
opacity: 1, opacity: 1,
duration: 0.4 duration: 0.4
@ -137,7 +113,6 @@
}); });
}, 800); }, 800);
{% else %} {% else %}
// Wenn Nachrichten vorhanden sind, Animation überspringen
document.getElementById("startup").style.display = "none"; document.getElementById("startup").style.display = "none";
document.getElementById("loginBox").style.opacity = 1; document.getElementById("loginBox").style.opacity = 1;
document.getElementById("loginForm").style.opacity = 1; document.getElementById("loginForm").style.opacity = 1;

View file

@ -5,7 +5,6 @@
{% block head %} {% block head %}
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style> <style>
/* Toggle Switch Styles */
.switch { position: relative; display: inline-block; width: 60px; height: 34px; } .switch { position: relative; display: inline-block; width: 60px; height: 34px; }
.switch input { opacity: 0; width: 0; height: 0; } .switch input { opacity: 0; width: 0; height: 0; }
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #4a5568; transition: .4s; border-radius: 34px; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #4a5568; transition: .4s; border-radius: 34px; }
@ -17,18 +16,15 @@
{% block content %} {% block content %}
<main class="flex-1 p-8 space-y-10" id="mainContent"> <main class="flex-1 p-8 space-y-10" id="mainContent">
<!-- HEADER -->
<header class="flex justify-between items-center mb-10"> <header class="flex justify-between items-center mb-10">
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Maintenance Management</h2> <h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Maintenance Management</h2>
</header> </header>
<!-- SETTINGS FORM -->
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 <div class="bg-black/40 rounded-xl backdrop-blur-lg p-8
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<form action="{{ url_for('update_maintenance') }}" method="POST" class="space-y-8"> <form action="{{ url_for('update_maintenance') }}" method="POST" class="space-y-8">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<!-- Maintenance Mode Toggle -->
<div class="flex items-center justify-between p-4 bg-gray-900/50 rounded-lg"> <div class="flex items-center justify-between p-4 bg-gray-900/50 rounded-lg">
<div> <div>
<h3 class="text-xl font-semibold {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Wartungsmodus</h3> <h3 class="text-xl font-semibold {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Wartungsmodus</h3>
@ -40,7 +36,6 @@
</label> </label>
</div> </div>
<!-- Discord Bots Wartungsmodus Toggle -->
<div class="flex items-center justify-between p-4 bg-gray-900/50 rounded-lg"> <div class="flex items-center justify-between p-4 bg-gray-900/50 rounded-lg">
<div> <div>
<h3 class="text-xl font-semibold {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord Bots Wartungsmodus</h3> <h3 class="text-xl font-semibold {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord Bots Wartungsmodus</h3>
@ -52,7 +47,6 @@
</label> </label>
</div> </div>
<!-- Maintenance Details -->
<div class="space-y-6"> <div class="space-y-6">
<div> <div>
<label for="status_message" class="block text-sm font-medium text-gray-300">Wartungsnachricht</label> <label for="status_message" class="block text-sm font-medium text-gray-300">Wartungsnachricht</label>
@ -79,7 +73,6 @@
</div> </div>
</div> </div>
<!-- Submit Button -->
<div class="flex justify-end pt-4"> <div class="flex justify-end pt-4">
<button type="submit" class="px-6 py-2 text-white font-semibold rounded-lg transition <button type="submit" class="px-6 py-2 text-white font-semibold rounded-lg transition
{% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}"> {% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}">

View file

@ -7,7 +7,6 @@
{% block content %} {% block content %}
<div x-data="{ showAddRoleModal: false, showDeleteModal: false, roleToDelete: null, roleToEdit: null }"> <div x-data="{ showAddRoleModal: false, showDeleteModal: false, roleToDelete: null, roleToEdit: null }">
<!-- HEADER -->
<header class="flex justify-between items-center mb-10"> <header class="flex justify-between items-center mb-10">
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Rollen verwalten</h2> <h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Rollen verwalten</h2>
<button @click="showAddRoleModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white <button @click="showAddRoleModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white
@ -15,7 +14,6 @@
+ Neue Rolle hinzufügen + Neue Rolle hinzufügen
</button> </button>
</header> </header>
<!-- ROLE TABLE -->
<div class="bg-black/40 rounded-xl backdrop-blur-lg overflow-hidden <div class="bg-black/40 rounded-xl backdrop-blur-lg overflow-hidden
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<table class="min-w-full divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/20{% endif %}"> <table class="min-w-full divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/20{% endif %}">
@ -55,7 +53,6 @@
</table> </table>
</div> </div>
<!-- ADD/EDIT ROLE MODAL -->
<div x-show="showAddRoleModal" @keydown.escape.window="showAddRoleModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;"> <div x-show="showAddRoleModal" @keydown.escape.window="showAddRoleModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
<div @click.away="showAddRoleModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-lg <div @click.away="showAddRoleModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-lg
{% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}"> {% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}">
@ -94,7 +91,6 @@
</form> </form>
</div> </div>
</div> </div>
<!-- DELETE CONFIRMATION MODAL -->
<div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;"> <div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
<div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md"> <div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md">
<h3 class="text-2xl font-bold text-red-400 mb-4">Rolle löschen</h3> <h3 class="text-2xl font-bold text-red-400 mb-4">Rolle löschen</h3>

View file

@ -11,7 +11,6 @@
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Einstellungen</h2> <h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Einstellungen</h2>
</header> </header>
<!-- ACCOUNT-INFORMATIONEN -->
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> <div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Account-Informationen</h3> <h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Account-Informationen</h3>
<div class="space-y-4"> <div class="space-y-4">
@ -23,7 +22,6 @@
</div> </div>
</div> </div>
<!-- PASSWORT ÄNDERN -->
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> <div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Passwort ändern</h3> <h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Passwort ändern</h3>
<form action="{{ url_for('update_password') }}" method="POST" class="space-y-4 max-w-md"> <form action="{{ url_for('update_password') }}" method="POST" class="space-y-4 max-w-md">
@ -48,7 +46,6 @@
</form> </form>
</div> </div>
<!-- DISCORD-VERKNÜPFUNG -->
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> <div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord-Verknüpfung</h3> <h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord-Verknüpfung</h3>
{% if user.discord_id %} {% if user.discord_id %}

View file

@ -8,13 +8,11 @@
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<style> <style>
/* Custom scrollbar */
::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: #0a0a0f; } ::-webkit-scrollbar-track { background: #0a0a0f; }
::-webkit-scrollbar-thumb { background-color: #4b5563; border-radius: 4px; } ::-webkit-scrollbar-thumb { background-color: #4b5563; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background-color: #6b7280; } ::-webkit-scrollbar-thumb:hover { background-color: #6b7280; }
/* Hintergrund / global (vereinheitlicht mit Referenz) */
body { body {
background: radial-gradient(circle at top, #1b1b26, #0a0a0f 70%); background: radial-gradient(circle at top, #1b1b26, #0a0a0f 70%);
overflow-x: hidden; overflow-x: hidden;
@ -40,18 +38,18 @@
justify-content: center; justify-content: center;
transition: background-color 0.2s, border-color 0.2s; transition: background-color 0.2s, border-color 0.2s;
margin-right: 0.75rem; margin-right: 0.75rem;
border-color: #8b5cf6; /* purple-500 */ border-color: #8b5cf6;
} }
.custom-checkbox-label.maintenance .custom-checkbox-box { .custom-checkbox-label.maintenance .custom-checkbox-box {
border-color: #f59e0b; /* yellow-600 */ border-color: #f59e0b;
} }
input[type="checkbox"]:checked + .custom-checkbox-box { input[type="checkbox"]:checked + .custom-checkbox-box {
background-color: #8b5cf6; /* purple-500 */ background-color: #8b5cf6;
border-color: #8b5cf6; /* purple-500 */ border-color: #8b5cf6;
} }
.custom-checkbox-label.maintenance input[type="checkbox"]:checked + .custom-checkbox-box { .custom-checkbox-label.maintenance input[type="checkbox"]:checked + .custom-checkbox-box {
background-color: #f59e0b; /* yellow-600 */ background-color: #f59e0b;
border-color: #f59e0b; /* yellow-600 */ border-color: #f59e0b;
} }
input[type="checkbox"]:checked + .custom-checkbox-box svg { input[type="checkbox"]:checked + .custom-checkbox-box svg {
display: block; display: block;
@ -122,7 +120,6 @@
0% { transform: translateY(100vh) scale(1); } 0% { transform: translateY(100vh) scale(1); }
100% { transform: translateY(-10vh) scale(1.5); } 100% { transform: translateY(-10vh) scale(1.5); }
} }
/* Benachrichtigungen: normale (schmale) Breite + Slide/Fade */
.toast-container { .toast-container {
position: fixed; position: fixed;
top: 1.25rem; top: 1.25rem;
@ -135,30 +132,25 @@
pointer-events: none; pointer-events: none;
max-width: calc(100% - 3rem); max-width: calc(100% - 3rem);
} }
/* Einzelne Toasts: normale Desktop-Breite (~28rem), mobil volle Breite */
.toast { .toast {
pointer-events: auto; pointer-events: auto;
width: 100%; width: 100%;
max-width: 28rem; /* <- hier die "normale" Breite einstellen */ max-width: 28rem;
box-sizing: border-box; box-sizing: border-box;
word-break: break-word; word-break: break-word;
background: rgba(8,10,12,0.95); background: rgba(8,10,12,0.95);
border-radius: 0.5rem; border-radius: 0.5rem;
border: 1px solid rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.04);
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
/* Slide + Fade (zusätzlich zu Alpine/Tailwind x-transition) */
transition: transform 0.32s cubic-bezier(.2,.9,.2,1), opacity 0.32s ease; transition: transform 0.32s cubic-bezier(.2,.9,.2,1), opacity 0.32s ease;
transform: translateX(0); transform: translateX(0);
opacity: 1; opacity: 1;
} }
/* Wenn ein Toast noch im "enter-start" Zustand ist (Tailwind-Klassen verwenden translate-x-8 / opacity-0),
sorgt die transition-Einstellung oben für sanftes Rein-/Rausrutschen. */
</style> </style>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
{% block head %}{% endblock %} {% block head %}{% endblock %}
</head> </head>
<body class="text-white flex flex-col min-h-screen font-sans antialiased"> <body class="text-white flex flex-col min-h-screen font-sans antialiased">
<!-- Loading Screen überall (vereinheitlicht) -->
<div id="startup"> <div id="startup">
<div id="star"> <div id="star">
<div class="blur"></div> <div class="blur"></div>
@ -170,11 +162,9 @@
<p>AstraOS</p> <p>AstraOS</p>
</div> </div>
<!-- Animierter Hintergrund überall -->
<div class="animated-bg"></div> <div class="animated-bg"></div>
<div class="flex h-screen"> <!-- overflow-hidden entfernt, damit die Seite scrollen kann --> <div class="flex h-screen">
<!-- Sidebar -->
<aside class="fixed top-0 left-0 w-64 h-screen bg-black/40 border-r p-6 backdrop-blur-lg flex flex-col flex-shrink-0 z-20 <aside class="fixed top-0 left-0 w-64 h-screen bg-black/40 border-r p-6 backdrop-blur-lg flex flex-col flex-shrink-0 z-20
{% if maintenance_active %}border-yellow-500/30{% else %}border-purple-500/20{% endif %}"> {% if maintenance_active %}border-yellow-500/30{% else %}border-purple-500/20{% endif %}">
<h1 class="text-3xl font-bold mb-8 tracking-wide <h1 class="text-3xl font-bold mb-8 tracking-wide
@ -307,7 +297,6 @@
</aside> </aside>
<div class="ml-64 flex-1 flex flex-col min-h-screen"> <div class="ml-64 flex-1 flex flex-col min-h-screen">
<!-- FLASH MESSAGES (zentral, breit, non-overlap) -->
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %} {% if messages %}
<div class="toast-container" x-data> <div class="toast-container" x-data>
@ -347,7 +336,6 @@
</footer> </footer>
</div> </div>
</div> </div>
<!-- LOGOUT BUTTON -->
<a href="{{ url_for('logout') }}" class="fixed bottom-6 left-6 text-white font-bold py-3 px-5 rounded-full shadow-lg transition-all backdrop-blur-sm flex items-center gap-2 z-30 <a href="{{ url_for('logout') }}" class="fixed bottom-6 left-6 text-white font-bold py-3 px-5 rounded-full shadow-lg transition-all backdrop-blur-sm flex items-center gap-2 z-30
{% if maintenance_active %} {% if maintenance_active %}
bg-yellow-600/50 hover:bg-yellow-500/80 hover:shadow-yellow-500/40 border border-yellow-500/20 bg-yellow-600/50 hover:bg-yellow-500/80 hover:shadow-yellow-500/40 border border-yellow-500/20
@ -360,14 +348,12 @@
<span>Logout</span> <span>Logout</span>
</a> </a>
<script src="{{ url_for('static', filename='JAVASCRIPT/main.js') }}"></script> <script src="{{ url_for('static', filename='JAVASCRIPT/main.js') }}"></script>
{% if maintenance_active %} {% if maintenance_active %}
<script>document.body.classList.add('maintenance-active');</script> <script>document.body.classList.add('maintenance-active');</script>
{% endif %} {% endif %}
<script> <script>
// GSAP Animationen und Ladebildschirm-Logik
gsap.to("#star", { gsap.to("#star", {
rotation: 360, rotation: 360,
duration: 1.2, duration: 1.2,
@ -393,7 +379,6 @@
}); });
}, 400); }, 400);
// Animierter Hintergrund
const bg = document.querySelector('.animated-bg'); const bg = document.querySelector('.animated-bg');
if (bg) { if (bg) {
for (let i = 0; i < 50; i++) { for (let i = 0; i < 50; i++) {

View file

@ -30,11 +30,10 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<!-- HEADER -->
<header class="flex justify-between items-center mb-10"> <header class="flex justify-between items-center mb-10">
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">System Status</h2> <h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">System Status</h2>
</header> </header>
<!-- STATUS LIST -->
<div class="space-y-4" id="status-list"> <div class="space-y-4" id="status-list">
<div class="bg-black/40 rounded-xl p-6 backdrop-blur-lg flex justify-between items-center <div class="bg-black/40 rounded-xl p-6 backdrop-blur-lg flex justify-between items-center
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
@ -69,12 +68,12 @@
</div> </div>
</div> </div>
</div> </div>
<script> <script>
function updateStatusPage() { function updateStatusPage() {
fetch('/api/system_status') fetch('/api/system_status')
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
// Helper
function setStatus(id, status) { function setStatus(id, status) {
let text = ""; let text = "";
let indicator = ""; let indicator = "";

View file

@ -21,7 +21,6 @@
} }
}"> }">
<div class="space-y-10"> <div class="space-y-10">
<!-- HEADER -->
<header class="flex justify-between items-center"> <header class="flex justify-between items-center">
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">User Management</h2> <h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">User Management</h2>
<button @click="userToEdit = null; showAddUserModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white <button @click="userToEdit = null; showAddUserModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white
@ -30,7 +29,6 @@
</button> </button>
</header> </header>
<!-- USER TABLE -->
<div class="bg-black/40 rounded-xl backdrop-blur-lg overflow-hidden <div class="bg-black/40 rounded-xl backdrop-blur-lg overflow-hidden
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<table class="min-w-full divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/20{% endif %}"> <table class="min-w-full divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/20{% endif %}">
@ -69,7 +67,6 @@
</div> </div>
</div> </div>
<!-- ADD/EDIT USER MODAL -->
<div x-show="showAddUserModal" @keydown.escape.window="showAddUserModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;"> <div x-show="showAddUserModal" @keydown.escape.window="showAddUserModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
<div @click.away="showAddUserModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-md <div @click.away="showAddUserModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-md
{% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}"> {% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}">
@ -125,7 +122,6 @@
</form> </form>
</div> </div>
</div> </div>
<!-- DELETE CONFIRMATION MODAL -->
<div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;"> <div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
<div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md"> <div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md">
<h3 class="text-2xl font-bold text-red-400 mb-4">Benutzer löschen</h3> <h3 class="text-2xl font-bold text-red-400 mb-4">Benutzer löschen</h3>
@ -138,7 +134,6 @@
</div> </div>
</div> </div>
<!-- Daten für Alpine.js bereitstellen -->
<script id="users-data" type="application/json"> <script id="users-data" type="application/json">
{{ users_for_modal | tojson | safe }} {{ users_for_modal | tojson | safe }}
</script> </script>

View file

@ -68,7 +68,6 @@
{% endif %} {% endif %}
</div> </div>
<!-- DELETE CONFIRMATION MODAL -->
<div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;"> <div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
<div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md"> <div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md">
<h3 class="text-2xl font-bold text-red-400 mb-4">Eintrag löschen</h3> <h3 class="text-2xl font-bold text-red-400 mb-4">Eintrag löschen</h3>
@ -86,9 +85,8 @@
function copyToClipboard(elementId) { function copyToClipboard(elementId) {
const input = document.getElementById(elementId); const input = document.getElementById(elementId);
input.select(); input.select();
input.setSelectionRange(0, 99999); // For mobile devices input.setSelectionRange(0, 99999);
document.execCommand('copy'); document.execCommand('copy');
// Optional: Visuelles Feedback geben
const originalButtonText = event.target.innerText; const originalButtonText = event.target.innerText;
event.target.innerText = 'Kopiert!'; event.target.innerText = 'Kopiert!';
setTimeout(() => { setTimeout(() => {

View file

@ -1,6 +1,5 @@
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
// --- Initial Load: Set correct open/closed state ---
document.querySelectorAll('.collapsible').forEach(button => { document.querySelectorAll('.collapsible').forEach(button => {
const content = button.nextElementSibling; const content = button.nextElementSibling;
const chevron = button.querySelector('svg'); const chevron = button.querySelector('svg');
@ -19,15 +18,12 @@ document.addEventListener('DOMContentLoaded', function () {
} }
}); });
// --- Accordion Click Behavior ---
document.querySelectorAll('.collapsible').forEach(button => { document.querySelectorAll('.collapsible').forEach(button => {
button.addEventListener('click', () => { button.addEventListener('click', () => {
const content = button.nextElementSibling; const content = button.nextElementSibling;
const chevron = button.querySelector('svg'); const chevron = button.querySelector('svg');
// First close all others
document.querySelectorAll('.collapsible').forEach(other => { document.querySelectorAll('.collapsible').forEach(other => {
if (other !== button) { if (other !== button) {
const otherContent = other.nextElementSibling; const otherContent = other.nextElementSibling;
@ -48,7 +44,6 @@ document.addEventListener('DOMContentLoaded', function () {
} }
}); });
// Toggle current
if (content.classList.contains('hidden')) { if (content.classList.contains('hidden')) {
content.classList.remove('hidden'); content.classList.remove('hidden');
gsap.fromTo(content, gsap.fromTo(content,