Added autohide with animation for flash message
This commit is contained in:
@@ -1 +1,16 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
/* 1. Die CSS-Variable für die Animation definieren */
|
||||||
|
--animate-shrink: shrink 5s linear forwards;
|
||||||
|
|
||||||
|
/* 2. Die dazugehörigen Keyframes festlegen */
|
||||||
|
@keyframes shrink {
|
||||||
|
0% {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scaleX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
40
app/javascript/controllers/flash_controller.js
Normal file
40
app/javascript/controllers/flash_controller.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus";
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ["notification"];
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
// Startet den Timer: Ruft nach 5000 Millisekunden (5 Sekunden) die dismiss-Methode auf
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.dismiss();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
// Wichtig: Löscht den Timer, falls der Nutzer die Nachricht vor Ablauf der 5 Sekunden manuell schließt
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss() {
|
||||||
|
// 1. Tailwind-Klassen für das Ausblenden hinzufügen
|
||||||
|
// this.notificationTarget.classList.add("opacity-0","translate-y-2","scale-95");
|
||||||
|
|
||||||
|
// Verschiebt das Element auf der X-Achse weit nach rechts (translate-x-full)
|
||||||
|
// und blendet es leicht aus, damit es weicher wirkt
|
||||||
|
// 1. Alten Startpunkt entfernen (wichtig für Tailwind v4/v3)
|
||||||
|
this.notificationTarget.classList.remove("translate-x-0", "opacity-100");
|
||||||
|
// 2. Neuen Endpunkt hinzufügen (löst die Animation aus)
|
||||||
|
this.notificationTarget.classList.add("translate-x-full", "opacity-20");
|
||||||
|
|
||||||
|
// Fügt Klassen für Deckkraft (0) und minimale Skalierung hinzu
|
||||||
|
// 1. Den Startwert (voll sichtbar) entfernen
|
||||||
|
//this.notificationTarget.classList.remove("opacity-100");
|
||||||
|
// 2. Den Endwert (vollständig transparent) hinzufügen -> startet das Verblassen
|
||||||
|
//this.notificationTarget.classList.add("opacity-0", "scale-95");
|
||||||
|
|
||||||
|
// 2. Nach dem Ende der CSS-Animation (300ms) das Element komplett aus dem DOM löschen
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.remove();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
app/views/layouts/_flash.html.erb
Normal file
37
app/views/layouts/_flash.html.erb
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<% flash.each do |type, message| %>
|
||||||
|
<%
|
||||||
|
bg_color = type == "notice" ? "bg-green-50 border-green-200 text-green-800" : "bg-red-50 border-red-200 text-red-800"
|
||||||
|
icon_color = type == "notice" ? "text-green-500" : "text-red-500"
|
||||||
|
# Die Farbe des Balkens passend zum Typ festlegen
|
||||||
|
bar_color = type == "notice" ? "bg-green-500" : "bg-red-500"
|
||||||
|
%>
|
||||||
|
|
||||||
|
<div data-controller="flash" class="fixed top-5 right-5 z-50 max-w-sm w-full">
|
||||||
|
|
||||||
|
<!-- Das relative Attribut und overflow-hidden sind wichtig für den Balken -->
|
||||||
|
<div data-flash-target="notification"
|
||||||
|
class="relative overflow-hidden transition-all duration-300 ease-out opacity-100 flex items-start p-4 pb-5 rounded-lg border shadow-lg <%= bg_color %>">
|
||||||
|
|
||||||
|
<!-- Nachricht -->
|
||||||
|
<div class="flex-1 ml-3 text-sm font-medium">
|
||||||
|
<%= message %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Schließen-Button -->
|
||||||
|
<div class="ml-4 flex shrink-0">
|
||||||
|
<button data-action="click->flash#dismiss"
|
||||||
|
class="inline-flex rounded-md p-1.5 focus:outline-none focus:ring-2 focus:ring-offset-2 hover:bg-black/5 <%= icon_color %>">
|
||||||
|
<span class="sr-only">Schließen</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DER FORTSCHRITTSBALKEN -->
|
||||||
|
<!-- 'animate-shrink' ist unsere eigene Animation, die wir gleich definieren -->
|
||||||
|
<div class="absolute bottom-0 left-0 h-1 w-full origin-left animate-shrink <%= bar_color %>"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -30,10 +30,10 @@
|
|||||||
<div class="min-h-screen bg-gray-100 flex relative overflow-x-hidden">
|
<div class="min-h-screen bg-gray-100 flex relative overflow-x-hidden">
|
||||||
|
|
||||||
<!-- STEUERUNG 1: Mobile Sidebar (Standard-Burger via CSS) -->
|
<!-- STEUERUNG 1: Mobile Sidebar (Standard-Burger via CSS) -->
|
||||||
<input type="checkbox" id="mobile-sidebar-toggle" class="peer hidden" />
|
<input type="checkbox" id="mobile-sidebar-toggle" class="peer hidden">
|
||||||
|
|
||||||
<!-- STEUERUNG 2: Desktop Sidebar (Einklappen via CSS) -->
|
<!-- STEUERUNG 2: Desktop Sidebar (Einklappen via CSS) -->
|
||||||
<input type="checkbox" id="desktop-sidebar-toggle" class="hidden" />
|
<input type="checkbox" id="desktop-sidebar-toggle" class="hidden">
|
||||||
|
|
||||||
<!-- DUNKLES HINTERGRUND-OVERLAY (Ausblend-Animation nur auf Mobile aktiv) -->
|
<!-- DUNKLES HINTERGRUND-OVERLAY (Ausblend-Animation nur auf Mobile aktiv) -->
|
||||||
<label for="mobile-sidebar-toggle"
|
<label for="mobile-sidebar-toggle"
|
||||||
@@ -129,12 +129,14 @@
|
|||||||
|
|
||||||
<!-- INHALT DER JEWEILIGEN VIEW -->
|
<!-- INHALT DER JEWEILIGEN VIEW -->
|
||||||
<main class="p-4 md:p-6 flex-1 w-full mx-auto px-4 md:px-8">
|
<main class="p-4 md:p-6 flex-1 w-full mx-auto px-4 md:px-8">
|
||||||
<!-- Platzhalter für Flash-Meldungen (z.B. erfolgreiches Speichern) -->
|
<!-- Platzhalter für Flash-Meldungen (z.B. erfolgreiches Speichern)
|
||||||
<% flash.each do |type, message| %>
|
<% flash.each do |type, message| %>
|
||||||
<div class="mb-4 p-4 text-sm rounded-lg border <%= type == 'notice' ? 'bg-green-50 text-green-800 border-green-200' : 'bg-red-50 text-red-800 border-red-200' %>">
|
<div class="mb-4 p-4 text-sm rounded-lg border <%= type == 'notice' ? 'bg-green-50 text-green-800 border-green-200' : 'bg-red-50 text-red-800 border-red-200' %>">
|
||||||
<%= message %>
|
<%= message %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
-->
|
||||||
|
<%= render "layouts/flash" %>
|
||||||
|
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
</main>
|
</main>
|
||||||
@@ -145,4 +147,3 @@
|
|||||||
<%= turbo_frame_tag "modal" %>
|
<%= turbo_frame_tag "modal" %>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user