611 lines
30 KiB
HTML
611 lines
30 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de" class="dark">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Dashboard</title>
|
|
<!-- Tailwind & FontAwesome -->
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
|
|
<!-- GSAP (Animations) -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
|
|
<script>
|
|
tailwind.config = {
|
|
darkMode: 'class',
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
primary: '#3b82f6',
|
|
secondary: '#10b981',
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style>
|
|
/* Hintergrundbild per CSS (aus settings) */
|
|
body {
|
|
background-image: url('{{ url_for("static", filename=wallpaper) }}');
|
|
background-size: cover;
|
|
background-position: center;
|
|
background-attachment: fixed;
|
|
}
|
|
.glassmorphism {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
backdrop-filter: blur(10px);
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
border-radius: 10px;
|
|
}
|
|
.dark .glassmorphism {
|
|
background: rgba(0, 0, 0, 0.2);
|
|
}
|
|
/* Eingabe-Felder in Dark Mode */
|
|
.dark input[type="text"],
|
|
.dark input[type="email"],
|
|
.dark input[type="password"],
|
|
.dark textarea,
|
|
.dark select {
|
|
background-color: #374151;
|
|
color: #fff;
|
|
}
|
|
.dock-icon {
|
|
transition: all 0.3s ease;
|
|
}
|
|
.dock-icon:hover {
|
|
transform: scale(1.1);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="min-h-screen bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-white transition-colors duration-300">
|
|
<div class="container mx-auto p-4 sm:p-6 lg:p-8 pb-20 flex flex-col items-center">
|
|
<!-- Bookmark Modal (Pop-up für Lesezeichen) -->
|
|
<div id="bookmarkModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
|
|
<div class="bg-white dark:bg-gray-800 glassmorphism p-6 rounded-lg max-w-md w-full mx-4">
|
|
<h2 class="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Lesezeichen</h2>
|
|
<div class="mb-4">
|
|
<input type="text" id="bookmarkInput" placeholder="URL eingeben..." class="w-full p-2 border rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<button id="addBookmark" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded transition-colors duration-200">Hinzufügen</button>
|
|
<button class="bg-gray-300 dark:bg-gray-600 hover:bg-gray-400 dark:hover:bg-gray-500 text-gray-800 dark:text-white px-4 py-2 rounded transition-colors duration-200 close-modal">Schließen</button>
|
|
</div>
|
|
<div class="mt-6">
|
|
<h3 class="text-lg font-semibold mb-2 text-gray-900 dark:text-white">Meine Lesezeichen</h3>
|
|
<ul id="bookmarksList" class="space-y-2 max-h-60 overflow-y-auto">
|
|
<!-- Dynamisch per JS -->
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bookmark-Button (öffnet das Modal) -->
|
|
<button id="bookmarkButton" class="fixed top-4 left-4 z-10 w-12 h-12 bg-blue-500 hover:bg-blue-600 text-white rounded-xl transition-colors duration-200 flex items-center justify-center">
|
|
<i class="fas fa-bookmark text-xl"></i>
|
|
</button>
|
|
|
|
<!-- Dark Mode Toggle (Sonne/Mond) -->
|
|
<button id="darkModeToggle" class="fixed top-4 right-4 w-12 h-12 rounded-xl bg-gray-200 dark:bg-gray-800 z-10 transition-colors duration-300">
|
|
<i class="fas fa-sun text-yellow-400 dark:hidden text-xl"></i>
|
|
<i class="fas fa-moon text-blue-200 hidden dark:inline text-xl"></i>
|
|
</button>
|
|
|
|
<!-- Logo, Begrüßung, Uhr -->
|
|
<div class="flex flex-col items-center justify-center space-y-4 text-center mb-6">
|
|
<a id="logo-link" href="https://{{ domain }}" target="_blank">
|
|
<img id="logo-img" src="{{ logo_path }}" alt="Firmenlogo" class="w-20 h-auto mb-2">
|
|
</a>
|
|
<h1 class="text-2xl sm:text-3xl font-bold text-gray-800 dark:text-white transition-colors duration-300">
|
|
Willkommen zurück, {{ user }}
|
|
</h1>
|
|
<div id="clock" class="text-xl sm:text-2xl font-semibold"></div>
|
|
</div>
|
|
|
|
<!-- Flash Messages -->
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
<div class="mb-4">
|
|
{% for category, message in messages %}
|
|
<div class="alert flex items-center bg-{{ category }}-500 text-white text-sm font-bold px-4 py-3" role="alert">
|
|
<p>{{ message }}</p>
|
|
<svg class="fill-current h-6 w-6 text-white ml-auto close-flash" role="button" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
|
<title>Schließen</title>
|
|
<path d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697L8.302 10 5.651 7.349a1.2 1.2 0 1 1 1.697-1.697L10 8.181l2.651-2.529a1.2 1.2 0 1 1 1.697 1.697L11.698 10l2.651 2.651a1.2 1.2 0 0 1 0 1.698z"/>
|
|
</svg>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
{% endwith %}
|
|
|
|
<!-- Widgets (Wetter, Speicher, usw.) -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-6 w-full max-w-3xl">
|
|
<!-- Wetter-Box -->
|
|
<div class="glassmorphism p-2 sm:p-3 shadow-lg rounded-md">
|
|
<h2 class="text-xs sm:text-sm font-semibold mb-1 text-center sm:text-left">Wetter in {{ city }}</h2>
|
|
<div class="flex items-center justify-center sm:justify-start mb-2">
|
|
<i class="fas {{ weather_icon }} text-base sm:text-lg md:text-xl mr-1"></i>
|
|
<p class="text-sm sm:text-base md:text-lg font-bold">{{ current_temp }}°C</p>
|
|
</div>
|
|
<!-- Forecast -->
|
|
<div class="space-y-1">
|
|
{% for day in forecast %}
|
|
<div class="flex items-center justify-between rounded-sm p-1">
|
|
<div class="flex items-center">
|
|
<i class="fas {{ day.weather_icon }} text-2xs sm:text-xs mr-1"></i>
|
|
<p class="text-2xs sm:text-xs">{{ day.date }}</p>
|
|
</div>
|
|
<p class="text-2xs sm:text-xs font-semibold">{{ day.day.avgtemp_c }}°C</p>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
<!-- Beispiel: Speicher / RAM (nur Demo, falls du Systemdaten abrufst) -->
|
|
<div class="glassmorphism p-4 shadow-lg">
|
|
<h2 class="text-lg font-semibold mb-2">Speicher</h2>
|
|
<p class="text-xl font-bold mb-1">— Demo —</p>
|
|
</div>
|
|
<div class="glassmorphism p-4 shadow-lg">
|
|
<h2 class="text-lg font-semibold mb-2">RAM-Nutzung</h2>
|
|
<p class="text-xl font-bold mb-1">— Demo —</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- App Launcher (Carousel) -->
|
|
<div class="glassmorphism p-4 mb-12 relative w-full max-w-3xl">
|
|
<div id="appCarousel" class="overflow-hidden">
|
|
<div class="flex transition-transform duration-300 ease-in-out">
|
|
{% for app_chunk in user_app_chunks %}
|
|
<div class="w-full flex-shrink-0">
|
|
<div class="grid grid-cols-3 sm:grid-cols-5 gap-4">
|
|
{% for app in app_chunk %}
|
|
<a href="https://{{ app.subdomain }}.{{ domain }}" class="flex flex-col items-center" title="{{ app.appkey }}">
|
|
<div class="w-12 h-12 flex items-center justify-center {{ app.bg_color }} rounded-xl mb-1 hover:scale-110 transition-transform">
|
|
<i class="{{ app.icon_class }} text-white text-xl"></i>
|
|
</div>
|
|
<p class="text-center text-xs font-medium">{{ app.name }}</p>
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
<button id="prevSlide" class="absolute top-1/2 left-2 transform -translate-y-1/2 bg-white/50 dark:bg-black/50 text-gray-800 dark:text-white rounded-full p-1 hover:bg-white/70 dark:hover:bg-black/70 transition-colors duration-200">
|
|
<i class="fas fa-chevron-left text-sm"></i>
|
|
</button>
|
|
<button id="nextSlide" class="absolute top-1/2 right-2 transform -translate-y-1/2 bg-white/50 dark:bg-black/50 text-gray-800 dark:text-white rounded-full p-1 hover:bg-white/70 dark:hover:bg-black/70 transition-colors duration-200">
|
|
<i class="fas fa-chevron-right text-sm"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dock mit Buttons: Home, Suche, Settings, Support -->
|
|
<div class="fixed bottom-4 left-1/2 transform -translate-x-1/2 glassmorphism p-2 flex space-x-4">
|
|
<button class="dock-icon w-12 h-12 flex items-center justify-center bg-blue-500 hover:bg-blue-600 rounded-xl" data-modal="homeModal">
|
|
<i class="fas fa-home text-white text-xl"></i>
|
|
</button>
|
|
<button class="dock-icon w-12 h-12 flex items-center justify-center bg-green-500 hover:bg-green-600 rounded-xl" data-modal="searchModal">
|
|
<i class="fas fa-search text-white text-xl"></i>
|
|
</button>
|
|
<button class="dock-icon w-12 h-12 flex items-center justify-center bg-yellow-500 hover:bg-yellow-600 rounded-xl" data-modal="settingsModal">
|
|
<i class="fas fa-cog text-white text-xl"></i>
|
|
</button>
|
|
<button class="dock-icon w-12 h-12 flex items-center justify-center bg-purple-500 hover:bg-purple-600 rounded-xl" data-modal="supportModal">
|
|
<i class="fas fa-question-circle text-white text-xl"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Home Modal (Konto löschen, Daten-Export, Logout) -->
|
|
<div id="homeModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
|
|
<div class="bg-white dark:bg-gray-800 glassmorphism p-6 rounded-lg max-w-md w-full mx-auto shadow-lg">
|
|
<h2 class="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
|
|
Willkommen Zuhause, {{ user }}!
|
|
</h2>
|
|
<p class="mb-4">Schneller Zugriff auf wichtige Funktionen</p>
|
|
|
|
<!-- Datenexport -->
|
|
<form action="{{ url_for('request_data_export') }}" method="GET" class="mb-3">
|
|
<button type="submit" class="w-full bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded transition ease-in-out duration-150">
|
|
Daten exportieren
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Konto löschen -->
|
|
<form action="{{ url_for('delete_account') }}" method="POST">
|
|
<button type="submit" class="w-full bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded transition ease-in-out duration-150" onclick="return confirm('Sind Sie sicher, dass Sie Ihr Konto löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.');">
|
|
Konto löschen
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Logout -->
|
|
<form action="{{ url_for('logout') }}" method="POST" class="mb-3 mt-2">
|
|
<button type="submit" class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition ease-in-out duration-150">
|
|
Abmelden
|
|
</button>
|
|
</form>
|
|
|
|
<button class="mt-4 bg-gray-300 dark:bg-gray-700 hover:bg-gray-400 dark:hover:bg-gray-800 text-gray-800 dark:text-white font-bold py-2 px-4 rounded transition ease-in-out duration-150 close-modal">
|
|
Schließen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Search Modal -->
|
|
<div id="searchModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center">
|
|
<div class="bg-white dark:bg-gray-800 glassmorphism p-6 rounded-lg max-w-md w-full mx-4">
|
|
<h2 class="text-2xl font-bold mb-4">Suche</h2>
|
|
<input type="text" id="searchInput" placeholder="Suchen..." class="w-full p-2 border rounded mb-4">
|
|
<select id="searchEngine" class="w-full p-2 border rounded mb-4">
|
|
<option value="qwant">Qwant</option>
|
|
<option value="google">Google</option>
|
|
</select>
|
|
<button id="startSearch" class="bg-green-500 text-white px-4 py-2 rounded">Suche starten</button>
|
|
<button class="mt-4 bg-blue-500 text-white px-4 py-2 rounded close-modal">Schließen</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Einstellungen-Modal -->
|
|
<div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center overflow-auto">
|
|
<div class="bg-white dark:bg-gray-800 glassmorphism p-6 rounded-lg w-full max-w-md max-h-screen overflow-y-auto mx-4">
|
|
<h2 class="text-2xl font-bold mb-4">Einstellungen</h2>
|
|
<p>Hier können Sie Ihre Einstellungen anpassen und das System nach Ihren Wünschen konfigurieren.</p>
|
|
|
|
<!-- Wallpaper-Auswahl -->
|
|
<h3 class="text-lg font-semibold mb-2">Hintergrundbild auswählen</h3>
|
|
<div id="wallpaperSelection" class="grid grid-cols-2 sm:grid-cols-3 gap-2 mb-4">
|
|
{% for i in range(1, 27) %}
|
|
<img src="{{ url_for('static', filename=i ~ '.png') }}"
|
|
alt="Wallpaper {{ i }}"
|
|
class="w-full h-auto wallpaper-thumb cursor-pointer border-2
|
|
{{ 'border-blue-500' if wallpaper == i ~ '.png' else 'border-transparent' }}
|
|
rounded"
|
|
data-wallpaper="{{ i }}.png">
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<!-- Stadt -->
|
|
<h3 class="text-lg font-semibold mb-2">Stadt ändern</h3>
|
|
<input type="text" id="cityInput" class="w-full p-2 border rounded mb-4" placeholder="Geben Sie Ihre Stadt ein" value="{{ city }}">
|
|
|
|
<!-- Wettervorhersage Toggle (versteckt, aber im Code notwendig) -->
|
|
<div style="display: none;">
|
|
<h3 class="text-lg font-semibold mb-2">Wochenvorhersage anzeigen</h3>
|
|
<label class="inline-flex items-center mt-2">
|
|
<input type="checkbox"
|
|
id="weatherForecastToggle"
|
|
class="form-checkbox h-5 w-5 text-blue-600"
|
|
{% if show_forecast %} checked {% endif %}>
|
|
<span class="ml-2 text-gray-700 dark:text-gray-300">Wochenvorhersage anzeigen</span>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Nur für Admins: Benutzerverwaltung -->
|
|
{% if role == 'admin' %}
|
|
<div class="mt-6 p-4 bg-gray-100 dark:bg-gray-700 rounded">
|
|
<h3 class="text-lg font-semibold mb-2 text-gray-900 dark:text-white">Benutzerverwaltung</h3>
|
|
<p class="text-sm mb-3">
|
|
Als Admin kannst du hier neue Benutzer anlegen, bearbeiten oder löschen
|
|
</p>
|
|
<a href="{{ url_for('admin') }}"
|
|
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded">
|
|
Zum Admin-Panel
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<button id="saveSettings" class="mt-4 bg-yellow-500 text-white px-4 py-2 rounded hover:bg-yellow-600 transition-colors duration-200">Speichern</button>
|
|
<button class="mt-4 ml-2 bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600 transition-colors duration-200 close-modal">Schließen</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Support Modal -->
|
|
<div id="supportModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center">
|
|
<div class="bg-white dark:bg-gray-800 p-8 rounded-lg max-w-md w-full">
|
|
<h2 class="text-2xl font-bold mb-4">Support kontaktieren</h2>
|
|
<label for="problemType" class="block mb-2 text-lg font-semibold">Art des Problems</label>
|
|
<select id="problemType" class="w-full p-2 border rounded mb-4">
|
|
<option value="Technisches Problem">Technisches Problem</option>
|
|
<option value="Account Problem">Account Problem</option>
|
|
<option value="Sonstiges">Sonstiges</option>
|
|
</select>
|
|
<label for="emailInput" class="block mb-2 text-lg font-semibold">Ihre E-Mail</label>
|
|
<input type="email" id="emailInput" class="w-full p-2 border rounded mb-4" placeholder="Ihre E-Mail-Adresse">
|
|
<label for="messageInput" class="block mb-2 text-lg font-semibold">Nachricht</label>
|
|
<textarea id="messageInput" class="w-full p-2 border rounded mb-4" rows="4" placeholder="Beschreiben Sie Ihr Problem"></textarea>
|
|
<button id="sendSupportMessage" class="bg-purple-500 text-white px-4 py-2 rounded hover:bg-purple-600 transition-colors duration-200">
|
|
Nachricht senden
|
|
</button>
|
|
<button class="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition-colors duration-200 close-modal">
|
|
Schließen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript für Modal, Dark Mode, Clock, App Carousel, Bookmarks, usw. -->
|
|
<script>
|
|
// Dark Mode
|
|
const darkModeToggle = document.getElementById('darkModeToggle');
|
|
function toggleDarkMode() {
|
|
document.documentElement.classList.toggle('dark');
|
|
localStorage.setItem('darkMode', document.documentElement.classList.contains('dark'));
|
|
}
|
|
darkModeToggle.addEventListener('click', toggleDarkMode);
|
|
if (localStorage.getItem('darkMode') === 'true' ||
|
|
(!('darkMode' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
document.documentElement.classList.add('dark');
|
|
}
|
|
|
|
// Uhr
|
|
function updateClock() {
|
|
const now = new Date();
|
|
const timeString = now.toLocaleTimeString('de-DE');
|
|
const dateString = now.toLocaleDateString('de-DE', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
|
document.getElementById('clock').innerHTML = `${timeString}<br><span class="text-sm font-normal">${dateString}</span>`;
|
|
}
|
|
setInterval(updateClock, 1000);
|
|
updateClock();
|
|
|
|
// Carousel
|
|
const carousel = document.getElementById('appCarousel');
|
|
const carouselContent = carousel.querySelector('.flex');
|
|
const prevButton = document.getElementById('prevSlide');
|
|
const nextButton = document.getElementById('nextSlide');
|
|
let currentSlide = 0;
|
|
const totalSlides = carouselContent.children.length;
|
|
|
|
function showSlide(index) {
|
|
currentSlide = index;
|
|
const offset = -currentSlide * 100;
|
|
gsap.to(carouselContent, {duration: 0.5, x: `${offset}%`, ease: "power2.inOut"});
|
|
}
|
|
|
|
prevButton.addEventListener('click', () => {
|
|
currentSlide = (currentSlide - 1 + totalSlides) % totalSlides;
|
|
showSlide(currentSlide);
|
|
});
|
|
|
|
nextButton.addEventListener('click', () => {
|
|
currentSlide = (currentSlide + 1) % totalSlides;
|
|
showSlide(currentSlide);
|
|
});
|
|
|
|
// Animations
|
|
gsap.from(".glassmorphism", {duration: 1, opacity: 0, y: 50, stagger: 0.2, ease: "power3.out"});
|
|
gsap.from(".dock-icon", {duration: 0.5, opacity: 0, y: 20, stagger: 0.1, ease: "back.out(1.7)", delay: 1});
|
|
|
|
// Modal-Fenster öffnen/schließen
|
|
const modals = document.querySelectorAll('[id$="Modal"]');
|
|
const modalTriggers = document.querySelectorAll('[data-modal]');
|
|
const closeButtons = document.querySelectorAll('.close-modal');
|
|
|
|
modalTriggers.forEach(trigger => {
|
|
trigger.addEventListener('click', () => {
|
|
const modalId = trigger.getAttribute('data-modal');
|
|
const modal = document.getElementById(modalId);
|
|
modal.classList.remove('hidden');
|
|
modal.classList.add('flex');
|
|
});
|
|
});
|
|
|
|
closeButtons.forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
const modal = button.closest('[id$="Modal"]');
|
|
modal.classList.remove('flex');
|
|
modal.classList.add('hidden');
|
|
});
|
|
});
|
|
|
|
modals.forEach(modal => {
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
modal.classList.remove('flex');
|
|
modal.classList.add('hidden');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Wallpaper-Auswahl
|
|
let selectedWallpaper = '{{ wallpaper }}';
|
|
const wallpaperThumbnails = document.querySelectorAll('.wallpaper-thumb');
|
|
wallpaperThumbnails.forEach(thumb => {
|
|
thumb.addEventListener('click', function() {
|
|
wallpaperThumbnails.forEach(t => {
|
|
t.classList.remove('border-blue-500');
|
|
t.classList.add('border-transparent');
|
|
});
|
|
this.classList.remove('border-transparent');
|
|
this.classList.add('border-blue-500');
|
|
selectedWallpaper = this.getAttribute('data-wallpaper');
|
|
});
|
|
});
|
|
|
|
// Save Settings
|
|
document.getElementById('saveSettings').addEventListener('click', function() {
|
|
const city = document.getElementById('cityInput').value.trim();
|
|
const showForecast = document.getElementById('weatherForecastToggle').checked;
|
|
|
|
// Aktuelle Settings laden, um Bookmarks nicht zu überschreiben
|
|
fetch('/get_settings')
|
|
.then(res => res.json())
|
|
.then(settings => {
|
|
const bookmarks = settings.bookmarks || [];
|
|
fetch('/save_settings', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
'wallpaper': selectedWallpaper,
|
|
'city': city,
|
|
'show_forecast': showForecast,
|
|
'bookmarks': bookmarks
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Fehler beim Speichern der Einstellungen: ' + (data.message || 'unbekannt'));
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Websuche
|
|
document.getElementById('startSearch').addEventListener('click', () => {
|
|
const query = document.getElementById('searchInput').value.trim();
|
|
const engine = document.getElementById('searchEngine').value;
|
|
if (query) {
|
|
let searchURL = '';
|
|
if (engine === 'qwant') {
|
|
searchURL = `https://www.qwant.com/?q=${encodeURIComponent(query)}`;
|
|
} else {
|
|
searchURL = `https://www.google.com/search?q=${encodeURIComponent(query)}`;
|
|
}
|
|
window.open(searchURL, '_blank');
|
|
}
|
|
});
|
|
|
|
// Bookmarks
|
|
const bookmarkModal = document.getElementById('bookmarkModal');
|
|
const bookmarkButton = document.getElementById('bookmarkButton');
|
|
const bookmarkInput = document.getElementById('bookmarkInput');
|
|
const addBookmark = document.getElementById('addBookmark');
|
|
const bookmarksList = document.getElementById('bookmarksList');
|
|
|
|
function openBookmarkModal() {
|
|
bookmarkModal.classList.remove('hidden');
|
|
bookmarkModal.classList.add('flex');
|
|
loadBookmarks();
|
|
}
|
|
function closeBookmarkModal() {
|
|
bookmarkModal.classList.remove('flex');
|
|
bookmarkModal.classList.add('hidden');
|
|
}
|
|
bookmarkButton.addEventListener('click', openBookmarkModal);
|
|
bookmarkModal.addEventListener('click', (e) => {
|
|
if (e.target === bookmarkModal) {
|
|
closeBookmarkModal();
|
|
}
|
|
});
|
|
closeButtons.forEach(button => {
|
|
button.addEventListener('click', closeBookmarkModal);
|
|
});
|
|
|
|
addBookmark.addEventListener('click', () => {
|
|
let url = bookmarkInput.value.trim();
|
|
if (url) {
|
|
const urlPattern = /^https?:\/\//i;
|
|
if (!urlPattern.test(url)) {
|
|
alert('Bitte gib eine vollständige URL mit http:// oder https:// ein.');
|
|
return;
|
|
}
|
|
addBookmarkToList(url);
|
|
bookmarkInput.value = '';
|
|
saveBookmarks();
|
|
}
|
|
});
|
|
|
|
function addBookmarkToList(url) {
|
|
const li = document.createElement('li');
|
|
li.innerHTML = `
|
|
<div class="flex items-center justify-between p-2 bg-gray-100 dark:bg-gray-700 rounded">
|
|
<a href="${url}" target="_blank" class="text-blue-600 dark:text-blue-400 hover:underline truncate">${url}</a>
|
|
<button class="delete-bookmark text-red-500 hover:text-red-700">
|
|
<i class="fas fa-trash-alt"></i>
|
|
</button>
|
|
</div>
|
|
`;
|
|
bookmarksList.appendChild(li);
|
|
|
|
const deleteButton = li.querySelector('.delete-bookmark');
|
|
deleteButton.addEventListener('click', () => {
|
|
li.remove();
|
|
saveBookmarks();
|
|
});
|
|
}
|
|
|
|
function loadBookmarks() {
|
|
fetch('/get_settings')
|
|
.then(res => res.json())
|
|
.then(settings => {
|
|
const b = settings.bookmarks || [];
|
|
bookmarksList.innerHTML = '';
|
|
b.forEach(bookmark => addBookmarkToList(bookmark));
|
|
});
|
|
}
|
|
|
|
function saveBookmarks() {
|
|
const b = Array.from(bookmarksList.children).map(li => li.querySelector('a').href);
|
|
fetch('/get_settings')
|
|
.then(res => res.json())
|
|
.then(settings => {
|
|
const city = settings.city;
|
|
const wallpaper = settings.wallpaper_url.split('/').pop();
|
|
const show_forecast = settings.show_forecast;
|
|
fetch('/save_settings', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
bookmarks: b,
|
|
city: city,
|
|
wallpaper: wallpaper,
|
|
show_forecast: show_forecast
|
|
})
|
|
}).then(response => {
|
|
if (!response.ok) {
|
|
alert('Fehler beim Speichern der Lesezeichen.');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
// Beim Laden sofort Lesezeichen laden
|
|
window.addEventListener('DOMContentLoaded', loadBookmarks);
|
|
|
|
// Support Modal
|
|
const supportModal = document.getElementById('supportModal');
|
|
const supportModalToggle = document.querySelector('[data-modal="supportModal"]');
|
|
supportModalToggle.addEventListener('click', () => {
|
|
supportModal.classList.remove('hidden');
|
|
supportModal.classList.add('flex');
|
|
});
|
|
|
|
const sendSupportMessage = document.getElementById('sendSupportMessage');
|
|
sendSupportMessage.addEventListener('click', () => {
|
|
const email = document.getElementById('emailInput').value.trim();
|
|
const problemType = document.getElementById('problemType').value;
|
|
const message = document.getElementById('messageInput').value.trim();
|
|
if (email && message) {
|
|
fetch('/send_support_message', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email, problemType, message })
|
|
}).then(response => {
|
|
if (response.ok) {
|
|
alert('Ihre Nachricht wurde erfolgreich gesendet.');
|
|
supportModal.classList.remove('flex');
|
|
supportModal.classList.add('hidden');
|
|
} else {
|
|
alert('Fehler beim Senden der Nachricht.');
|
|
}
|
|
});
|
|
} else {
|
|
alert('Bitte füllen Sie alle Felder aus.');
|
|
}
|
|
});
|
|
|
|
// Flash-Nachrichten per Klick schließen
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const flashCloseBtns = document.querySelectorAll('.close-flash');
|
|
flashCloseBtns.forEach(btn => {
|
|
btn.addEventListener('click', function () {
|
|
const alertBox = this.closest('.alert');
|
|
alertBox.style.transition = 'opacity 0.5s ease';
|
|
alertBox.style.opacity = '0';
|
|
setTimeout(() => alertBox.remove(), 500);
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|