clip.mp4
app/views/layouts/application.html.erb
<body class="min-h-screen relative">
<%= render "layouts/flash" %>
</body>
app/views/layouts/_flash.html.erb
<% flash.each do |type, message| %>
<div class="fixed inset-x-0 top-0 flex items-end justify-right px-4 py-5 sm:p-5 justify-end z-30 pointer-events-none">
<div
data-controller="removeable"
data-removeable-show-class="translate-x-0 opacity-75"
data-removeable-hide-class="translate-x-full opacity-0"
class="max-w-sm w-full shadow-lg px-4 py-2 rounded relative bg-white dark:bg-gray-600 border-l-8 border-pink-800 text-gray-600 pointer-events-auto transition translate-x-full transform ease-in-out duration-1000 opacity-0">
<div class="p-2">
<div class="flex items-start">
<div class="ml-3 w-0 flex-1">
<p class="text-sm leading-5 font-medium">
<%= content_tag :div, message, class: 'dark:text-gray-300' %>
</p>
</div>
<div class="ml-4 flex-shrink-0 flex">
<button data-action="removeable#close"
class="inline-flex dark:text-gray-300 text-gray-500 focus:outline-none dark:focus:text-gray-400 focus:text-gray-600 top-1"
style='margin-top: 4px;'>
<svg class="h-4 w-4" 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>
</div>
</div>
</div>
</div>
<% end %>
app/javascript/controllers/removeable_controller.js
import { Controller } from "@hotwired/stimulus";
// Connects to data-controller="removeable"
export default class extends Controller {
static values = {
showDelay: { type: Number, default: 200 },
removeDelay: { type: Number, default: 5000 },
dismissAfter: { type: Boolean, default: true }
}
static classes = [
"show",
"hide"
]
initialize() {
this.hide()
}
connect() {
// Auto show (default hidden)
setTimeout(() => {
this.show();
// Auto dismiss if defined
if (this.dismissAfterValue) {
setTimeout(() => {
this.close();
}, this.removeDelayValue);
}
}, this.showDelayValue);
}
close() {
this.hide()
setTimeout(() => {
this.element.remove()
}, this.removeDelayValue)
}
show() {
this.element.classList.add(...this.showClasses)
this.element.classList.remove(...this.hideClasses)
}
hide() {
this.element.classList.add(...this.hideClasses)
this.element.classList.remove(...this.showClasses)
}
}
You don't need to write in controllers or turbo_stream.erb a separate turbo_render method for flash render. It is enough to create a new application.turbo_stream.erb file in the "app/views/layouts" folder with the following content:
and flash drives will be automatically rendered
PS It does not conflict with application.html.erb