From 4ba17ca9bf0b020bc941f72f74a98f23637dafa6 Mon Sep 17 00:00:00 2001 From: Jason Hirsch Date: Fri, 21 Feb 2025 22:12:13 +0100 Subject: [PATCH] Caroouusseelll gemacht und bookmarks --- Dashboard_V2/app.py | 62 +++- Dashboard_V2/templates/dashboard.html | 460 +++++++++++++++++--------- 2 files changed, 364 insertions(+), 158 deletions(-) diff --git a/Dashboard_V2/app.py b/Dashboard_V2/app.py index 0a05787..2821a57 100644 --- a/Dashboard_V2/app.py +++ b/Dashboard_V2/app.py @@ -48,6 +48,7 @@ def init_db(): title TEXT NOT NULL, url TEXT NOT NULL, icon_class TEXT NOT NULL DEFAULT 'fas fa-bookmark', + bg_color TEXT NOT NULL DEFAULT 'fas fa-bookmark', FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE ); """) @@ -381,16 +382,32 @@ def manage_bookmarks(user_id): bookmarks = db.execute("SELECT * FROM bookmarks WHERE user_id=?", (user_id,)).fetchall() return render_template('admin.html', single_user=user, bookmarks=bookmarks) -@app.route('/admin/delete_bookmark//', methods=['POST']) -def delete_bookmark(bookmark_id, user_id): - if not is_admin(): - flash("Zugriff verweigert!", "red") - return redirect(url_for('dashboard')) +@app.route('/bookmarks/delete/', methods=['POST']) +def delete_bookmark(bookmark_id): + """Löscht ein Lesezeichen, wenn der Benutzer es besitzt oder Admin ist.""" + if 'user_id' not in session: + flash("Bitte melde dich an!", "red") + return redirect(url_for('login')) + + user_id = session['user_id'] db = get_db() + + # Prüfen, ob der Benutzer das Lesezeichen besitzt + bookmark = db.execute("SELECT user_id FROM bookmarks WHERE id=?", (bookmark_id,)).fetchone() + if not bookmark: + flash("Lesezeichen nicht gefunden!", "red") + return redirect(url_for('dashboard')) + + # Benutzer darf nur eigene Lesezeichen löschen, Admin kann alle löschen + if bookmark['user_id'] != user_id and not is_admin(): + flash("Keine Berechtigung zum Löschen!", "red") + return redirect(url_for('dashboard')) + db.execute("DELETE FROM bookmarks WHERE id=?", (bookmark_id,)) db.commit() + flash("Lesezeichen gelöscht!", "green") - return redirect(url_for('manage_bookmarks', user_id=user_id)) + return redirect(url_for('dashboard')) # ------------------------------------------------------------ # ZEITERFASSUNG @@ -490,7 +507,7 @@ def dashboard(): # DB-Bookmarks für den eingeloggten User user_bookmarks = db.execute(""" - SELECT id, title, url, icon_class + SELECT id, title, url, icon_class, bg_color FROM bookmarks WHERE user_id=? ORDER BY id DESC @@ -708,6 +725,37 @@ def add_notification_multi(): flash("Benachrichtigungen erstellt!", "green") return redirect(url_for('admin_panel')) +# ------------------------------------------------------------ +# BENUTZER-LESEZEICHEN (nur für sich selbst) +# ------------------------------------------------------------ + +@app.route('/bookmarks/add', methods=['POST']) +def add_bookmark(): + if 'user_id' not in session: + flash("Bitte melde dich an!", "red") + return redirect(url_for('login')) + + user_id = session['user_id'] + title = request.form.get('title') + url_ = request.form.get('url') + icon_class = request.form.get('icon_class', 'fas fa-bookmark') + bg_color = request.form.get('bg_color', 'bg-blue-500') # Standardfarbe + + if not title or not url_: + flash("Bitte Titel und URL angeben!", "red") + return redirect(url_for('dashboard')) + + db = get_db() + db.execute( + "INSERT INTO bookmarks (user_id, title, url, icon_class, bg_color) VALUES (?, ?, ?, ?, ?)", + (user_id, title, url_, icon_class, bg_color) + ) + db.commit() + + flash("Lesezeichen erfolgreich hinzugefügt!", "green") + return redirect(url_for('dashboard')) + + @app.route('/admin/bookmarks/multi', methods=['POST']) def add_bookmarks_multi(): diff --git a/Dashboard_V2/templates/dashboard.html b/Dashboard_V2/templates/dashboard.html index ef8b6ba..8a7c3f3 100644 --- a/Dashboard_V2/templates/dashboard.html +++ b/Dashboard_V2/templates/dashboard.html @@ -25,9 +25,8 @@
- + - - - - - - - - - - - - - - - - - - -
- - - - @@ -288,7 +359,7 @@ setInterval(updateClock, 1000); updateClock(); - // GSAP-Effekte + // GSAP-Effekte (vorausgesetzt, GSAP ist in base.html eingebunden) gsap.from(".glassmorphism", { duration: 1, opacity: 0, y: 50, stagger: 0.2, ease: "power3.out" }); @@ -338,7 +409,7 @@ }); }); - // Websuche (inline) + // Websuche const searchForm = document.getElementById('searchForm'); const searchInput = document.getElementById('searchInput'); const searchEngine = document.getElementById('searchEngine'); @@ -355,7 +426,7 @@ window.open(url, '_blank'); }); - // Support Modal: Nachricht senden (aus V1) + // Support Modal: Nachricht senden const sendSupportMessage = document.getElementById('sendSupportMessage'); if (sendSupportMessage) { sendSupportMessage.addEventListener('click', () => { @@ -383,16 +454,15 @@ }); } - // Settings Modal (Wallpaper, Stadt, etc.) aus V1 - // Lese/Schreibe Settings per '/get_settings' und '/save_settings' + // Settings Modal: Wallpaper und Stadt let selectedWallpaper = '{{ wallpaper }}'; - - // Markiere ausgewähltes Wallpaper const wallpaperThumbs = document.querySelectorAll('.wallpaper-thumb'); wallpaperThumbs.forEach(thumb => { thumb.addEventListener('click', function() { - wallpaperThumbs.forEach(t => t.classList.remove('border-blue-500')); - wallpaperThumbs.forEach(t => t.classList.add('border-transparent')); + wallpaperThumbs.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'); @@ -431,5 +501,93 @@ }); }); } + + // Icon Auswahl + const iconButtons = document.querySelectorAll('.icon-option'); + const selectedIconInput = document.getElementById('selectedIcon'); + const previewIcon = document.getElementById('previewIcon'); + iconButtons.forEach(button => { + button.addEventListener("click", function () { + // Alle Buttons zurücksetzen + iconButtons.forEach(btn => btn.classList.remove("bg-blue-500")); + // Aktuelles Icon markieren + this.classList.add("bg-blue-500"); + // Icon-Name setzen + const iconClass = this.getAttribute("data-icon"); + selectedIconInput.value = iconClass; + previewIcon.className = `fas ${iconClass} text-white text-xl`; + }); + }); + + // Farb-Auswahl: Live Vorschau für die Hintergrundfarbe + const colorButtons = document.querySelectorAll('.color-option'); + const selectedColorInput = document.getElementById('selectedColor'); + const bookmarkPreview = document.getElementById('bookmarkPreview'); + colorButtons.forEach(button => { + button.addEventListener('click', function() { + // Optional: optisch markieren (hier per ring) + colorButtons.forEach(btn => btn.classList.remove('ring-2', 'ring-white')); + this.classList.add('ring-2', 'ring-white'); + const colorClass = this.getAttribute('data-color'); + selectedColorInput.value = colorClass; + // Hintergrund der Vorschau aktualisieren + bookmarkPreview.className = `w-12 h-12 flex items-center justify-center rounded-xl ${colorClass}`; + }); + }); + + // Öffnen des Bookmark-Modals über Dock-Icon + const openBookmarkModal = document.getElementById('openBookmarkModal'); + if (openBookmarkModal) { + openBookmarkModal.addEventListener('click', () => { + const modal = document.getElementById('bookmarkModal'); + modal.classList.remove('hidden'); + modal.classList.add('flex'); + }); + } + // Schließen des Bookmark-Modals über Schließen-Button + const closeBookmarkModal = document.getElementById('closeBookmarkModal'); + if (closeBookmarkModal) { + closeBookmarkModal.addEventListener('click', () => { + const modal = document.getElementById('bookmarkModal'); + modal.classList.remove('flex'); + modal.classList.add('hidden'); + }); + } + + // + document.addEventListener("DOMContentLoaded", function () { + const track = document.getElementById("carouselTrack"); + const slides = document.querySelectorAll(".carousel-slide"); + const prevButton = document.getElementById("carouselPrev"); + const nextButton = document.getElementById("carouselNext"); + + let currentIndex = 0; + const totalSlides = slides.length; + + function updateCarousel() { + const newTransformValue = `translateX(-${currentIndex * 100}%)`; + track.style.transform = newTransformValue; + } + + nextButton.addEventListener("click", function () { + if (currentIndex < totalSlides - 1) { + currentIndex++; + updateCarousel(); + } + }); + + prevButton.addEventListener("click", function () { + if (currentIndex > 0) { + currentIndex--; + updateCarousel(); + } + }); + + // Falls nur eine Seite vorhanden ist, Navigation ausblenden + if (totalSlides <= 1) { + prevButton.style.display = "none"; + nextButton.style.display = "none"; + } + }); {% endblock content %}