Alerte
Un composant de notification pour afficher des messages importants aux utilisateurs. Prend en charge les variantes succès, erreur, avertissement et info avec des icônes optionnelles et une fonctionnalité de fermeture.
Aperçu et code
_alert.html.erb
<%#
Alert Component (Classic)
Usage:
<%= render "components/alert", message: "Success!" %>
<%= render "components/alert", message: "Something went wrong", variant: :error %>
<%= render "components/alert", message: "Please note...", variant: :info, dismissible: true %>
%>
<%
variant ||= :success
dismissible ||= false
icon ||= nil
additional_class ||= defined?(binding.local_variable_get(:class)) ? binding.local_variable_get(:class) : ""
base_classes = "flex items-start gap-3 p-4 rounded-lg text-sm shadow-sm"
variant_config = case variant.to_sym
when :success
{
classes: "bg-emerald-50 text-emerald-800 border border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800",
icon_color: "text-emerald-500 dark:text-emerald-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
when :error
{
classes: "bg-red-50 text-red-800 border border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800",
icon_color: "text-red-500 dark:text-red-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
when :warning
{
classes: "bg-amber-50 text-amber-800 border border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800",
icon_color: "text-amber-500 dark:text-amber-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>'
}
when :info
{
classes: "bg-blue-50 text-blue-800 border border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-800",
icon_color: "text-blue-500 dark:text-blue-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
else
{
classes: "bg-emerald-50 text-emerald-800 border border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800",
icon_color: "text-emerald-500 dark:text-emerald-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
end
all_classes = [base_classes, variant_config[:classes], additional_class].join(" ")
display_icon = icon || variant_config[:default_icon]
%>
<div class="<%= all_classes %>" <% if dismissible %>data-controller="alert"<% end %> role="alert">
<span class="<%= variant_config[:icon_color] %>">
<%= display_icon.html_safe %>
</span>
<div class="flex-1">
<%= message %>
</div>
<% if dismissible %>
<button type="button" data-action="alert#dismiss" class="shrink-0 p-1 rounded hover:bg-black/5 transition-colors cursor-pointer">
<svg class="w-4 h-4 opacity-50" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<% end %>
</div>
alert_controller.js
import { Controller } from "@hotwired/stimulus"
// Handles dismissible alert functionality
export default class extends Controller {
dismiss() {
this.element.classList.add("opacity-0", "transition-opacity", "duration-300")
setTimeout(() => {
this.element.remove()
}, 300)
}
}
alert_component.rb
# frozen_string_literal: true
class AlertComponent < ViewComponent::Base
VARIANTS = %i[success error warning info].freeze
attr_reader :message, :variant, :dismissible, :icon
def initialize(message:, variant: :success, dismissible: false, icon: nil, **extra_classes)
@message = message
@variant = variant.to_sym
@dismissible = dismissible
@icon = icon
@extra_classes = extra_classes[:class] || ""
end
def alert_classes
[ base_classes, variant_classes, @extra_classes ].compact.join(" ")
end
def icon_classes
variant_config[:icon_color]
end
def display_icon
@icon || variant_config[:default_icon]
end
private
def base_classes
"flex items-start gap-3 p-4 rounded-lg text-sm shadow-sm"
end
def variant_classes
variant_config[:classes]
end
def variant_config
@variant_config ||= case @variant
when :success
{
classes: "bg-emerald-50 text-emerald-800 border border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800",
icon_color: "text-emerald-500 dark:text-emerald-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
when :error
{
classes: "bg-red-50 text-red-800 border border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800",
icon_color: "text-red-500 dark:text-red-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
when :warning
{
classes: "bg-amber-50 text-amber-800 border border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800",
icon_color: "text-amber-500 dark:text-amber-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>'
}
when :info
{
classes: "bg-blue-50 text-blue-800 border border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-800",
icon_color: "text-blue-500 dark:text-blue-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
else
{
classes: "bg-emerald-50 text-emerald-800 border border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800",
icon_color: "text-emerald-500 dark:text-emerald-400",
default_icon: '<svg class="w-5 h-5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
}
end
end
end
alert_component.html.erb
<div class="<%= alert_classes %>" <% if @dismissible %>data-controller="alert"<% end %> role="alert">
<span class="<%= icon_classes %>">
<%= display_icon.html_safe %>
</span>
<div class="flex-1">
<%= @message %>
</div>
<% if @dismissible %>
<button type="button" data-action="alert#dismiss" class="shrink-0 p-1 rounded hover:bg-black/5 transition-colors cursor-pointer">
<svg class="w-4 h-4 opacity-50" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<% end %>
</div>
alert_controller.js
import { Controller } from "@hotwired/stimulus"
// Handles dismissible alert functionality
export default class extends Controller {
dismiss() {
this.element.classList.add("opacity-0", "transition-opacity", "duration-300")
setTimeout(() => {
this.element.remove()
}, 300)
}
}
Journal des modifications
- Initial release with success, error, warning, and info variants
- Optional dismiss button with Stimulus controller
- Icon support with default icons per variant
Vous aimez ce composant gratuit ? Obtenez les 78 composants avec un paiement unique.
Obtenir Tous les Composants