1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-19 13:19:39 +02:00

Add persistent notification with dismiss and action button (#611)

* Update notification partial

* Update locals args

* Lint

* Move content to body in notification helper

* Avoid dynamic Tailwind class

* Styling

* Add notification to localization file

* Lint

* Normalize locales

* Auto dismiss by default
This commit is contained in:
Thibaut Gorioux 2024-04-16 19:33:51 +02:00 committed by GitHub
parent 5516b03b6e
commit a22c7a0e9c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 42 additions and 21 deletions

View file

@ -26,7 +26,7 @@ class AccountsController < ApplicationController
format.html { redirect_to accounts_path, notice: t(".success") } format.html { redirect_to accounts_path, notice: t(".success") }
format.turbo_stream do format.turbo_stream do
render turbo_stream: [ render turbo_stream: [
turbo_stream.append("notification-tray", partial: "shared/notification", locals: { type: "success", content: t(".success") }), turbo_stream.append("notification-tray", partial: "shared/notification", locals: { type: "success", content: { body: t(".success") } }),
turbo_stream.replace("account_#{@account.id}", partial: "accounts/account", locals: { account: @account }) turbo_stream.replace("account_#{@account.id}", partial: "accounts/account", locals: { account: @account })
] ]
end end
@ -58,7 +58,7 @@ class AccountsController < ApplicationController
respond_to do |format| respond_to do |format|
format.html { redirect_to account_path(@account), notice: t(".success") } format.html { redirect_to account_path(@account), notice: t(".success") }
format.turbo_stream do format.turbo_stream do
render turbo_stream: turbo_stream.append("notification-tray", partial: "shared/notification", locals: { type: "success", content: t(".success") }) render turbo_stream: turbo_stream.append("notification-tray", partial: "shared/notification", locals: { type: "success", content: { body: t(".success") } })
end end
end end
end end

View file

@ -78,7 +78,7 @@ class TransactionsController < ApplicationController
format.html { redirect_to transaction_url(@transaction), notice: t(".success") } format.html { redirect_to transaction_url(@transaction), notice: t(".success") }
format.turbo_stream do format.turbo_stream do
render turbo_stream: [ render turbo_stream: [
turbo_stream.append("notification-tray", partial: "shared/notification", locals: { type: "success", content: t(".success") }), turbo_stream.append("notification-tray", partial: "shared/notification", locals: { type: "success", content: { body: t(".success") } }),
turbo_stream.replace("transaction_#{@transaction.id}", partial: "transactions/transaction", locals: { transaction: @transaction }) turbo_stream.replace("transaction_#{@transaction.id}", partial: "transactions/transaction", locals: { transaction: @transaction })
] ]
end end

View file

@ -17,7 +17,7 @@ module ApplicationHelper
content = tag.p(text) content = tag.p(text)
content = capture &block if block_given? content = capture &block if block_given?
render partial: "shared/notification", locals: { type: options[:type], content: content } render partial: "shared/notification", locals: { type: options[:type], content: { body: content } }
end end
# Wrap view with <%= modal do %> ... <% end %> to have it open in a modal # Wrap view with <%= modal do %> ... <% end %> to have it open in a modal

View file

@ -1,23 +1,42 @@
<%# locals: (type: "success", content:) -%> <%# locals: (type: "success", content: { title: '', body: ''}, action: { label:'' , url:'' }, options: { auto_dismiss: true }) -%>
<turbo-stream action="append" target="notification-tray"> <turbo-stream action="append" target="notification-tray">
<template> <template>
<div <% actions = options[:auto_dismiss] ? "animationend->element-removal#remove" : "" %>
class="max-w-80 bg-white shadow-xs border border-alpha-black-50 border-solid py-3 px-4 rounded-[10px] text-sm font-medium flex gap-3 animate-[appear-then-fade_5s_300ms_both]" <% animation = options[:auto_dismiss] ? "animate-[appear-then-fades_5s_300ms_both]" : "animate-[appear_5s_300ms_both]" %>
role="<%= type == "error" ? "alert" : "status" %>" <%= content_tag :div,
data-controller="element-removal" class: "max-w-80 bg-white shadow-xs border border-alpha-black-50 border-solid py-3 px-4 rounded-[10px] text-sm font-medium flex gap-4 #{animation}",
data-action="click->element-removal#remove animationend->element-removal#remove"> data: {controller: "element-removal", action: actions },
role: type == "error" ? "alert" : "status" do -%>
<% base_class = "w-5 h-5 p-1 text-white flex shrink-0 items-center justify-center rounded-full" %> <% base_class = "w-5 h-5 p-1 text-white flex shrink-0 items-center justify-center rounded-full" %>
<%= type.in?(["error", "alert"]) ? lucide_icon("x", class: "#{base_class} bg-error") : lucide_icon("check", class: "#{base_class} bg-success") %> <%= type.in?(["error", "alert"]) ? lucide_icon("x", class: "#{base_class} bg-error") : lucide_icon("check", class: "#{base_class} bg-success") %>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-1">
<% if content[:title].present? %>
<h1 class="text-sm text-gray-900 font-medium"><%= content[:title] %></h1>
<% end %>
<p class="text-sm text-gray-500 font-normal"><%= content[:body] %></p>
</div>
<%= content %> <div class="flex flex-row justify-end gap-2">
<% if !options[:auto_dismiss] %>
<%= content_tag :a, t(".dismiss"), data: { action: "click->element-removal#remove" }, class:"flex gap-1 font-medium items-center text-gray-900 px-3 py-1.5 rounded-lg cursor-pointer" %>
<% end %>
<% if action[:label].present? && action[:url].present? %>
<%= link_to action[:label], action[:url], class: "flex gap-1 font-medium items-center bg-gray-50 text-gray-900 px-3 py-1.5 rounded-lg" %>
<% end %>
</div>
</div>
<button aria-label="Close notification" data-action="click->element-removal#remove" class="shrink-0 h-5"> <% if options[:auto_dismiss] %>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="shrink-0"> <div class="shrink-0 h-5">
<path d="M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10ZM3.6 10C3.6 13.5346 6.46538 16.4 10 16.4C13.5346 16.4 16.4 13.5346 16.4 10C16.4 6.46538 13.5346 3.6 10 3.6C6.46538 3.6 3.6 6.46538 3.6 10Z" fill="#E5E5E5" /> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="shrink-0">
<circle class="origin-center -rotate-90 animate-[stroke-fill_5s_300ms_forwards]" stroke="#141414" stroke-opacity="0.4" r="7.2" cx="10" cy="10" stroke-dasharray="43.9822971503" stroke-dashoffset="43.9822971503" /> <path d="M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10ZM3.6 10C3.6 13.5346 6.46538 16.4 10 16.4C13.5346 16.4 16.4 13.5346 16.4 10C16.4 6.46538 13.5346 3.6 10 3.6C6.46538 3.6 3.6 6.46538 3.6 10Z" fill="#E5E5E5" />
</svg> <circle class="origin-center -rotate-90 animate-[stroke-fill_5s_300ms_forwards]" stroke="#141414" stroke-opacity="0.4" r="7.2" cx="10" cy="10" stroke-dasharray="43.9822971503" stroke-dashoffset="43.9822971503" />
</button> </svg>
</div> </div>
</template> <% end %>
<% end -%>
</div>
</template>
</turbo-stream> </turbo-stream>

View file

@ -1,4 +1,4 @@
<%= turbo_stream.replace Valuation.new, body: turbo_frame_tag(dom_id(Valuation.new)) %> <%= turbo_stream.replace Valuation.new, body: turbo_frame_tag(dom_id(Valuation.new)) %>
<%= turbo_stream.append "notification-tray", partial: "shared/notification", locals: { type: "success", content: "Valuation created" } %> <%= turbo_stream.append "notification-tray", partial: "shared/notification", locals: { type: "success", content: { body: "Valuation created" } } %>
<%= turbo_stream.replace "valuations_list", partial: "accounts/account_valuation_list", locals: { valuation_series: @account.valuations.to_series } %> <%= turbo_stream.replace "valuations_list", partial: "accounts/account_valuation_list", locals: { valuation_series: @account.valuations.to_series } %>
<%= turbo_stream.replace "sync_message", partial: "accounts/sync_message", locals: { is_syncing: true } %> <%= turbo_stream.replace "sync_message", partial: "accounts/sync_message", locals: { is_syncing: true } %>

View file

@ -1,4 +1,4 @@
<%= turbo_stream.remove @valuation %> <%= turbo_stream.remove @valuation %>
<%= turbo_stream.append "notification-tray", partial: "shared/notification", locals: { type: "success", content: "Valuation deleted" } %> <%= turbo_stream.append "notification-tray", partial: "shared/notification", locals: { type: "success", content: { body: "Valuation deleted" } } %>
<%= turbo_stream.replace "valuations_list", partial: "accounts/account_valuation_list", locals: { valuation_series: @account.valuations.to_series } %> <%= turbo_stream.replace "valuations_list", partial: "accounts/account_valuation_list", locals: { valuation_series: @account.valuations.to_series } %>
<%= turbo_stream.replace "sync_message", partial: "accounts/sync_message", locals: { is_syncing: true } %> <%= turbo_stream.replace "sync_message", partial: "accounts/sync_message", locals: { is_syncing: true } %>

View file

@ -21,6 +21,8 @@ en:
back is by re-entering it manually via a new entry</p>" back is by re-entering it manually via a new entry</p>"
title: Delete Entry? title: Delete Entry?
shared: shared:
notification:
dismiss: Dismiss
upgrade_notification: upgrade_notification:
app_upgraded: The app has been upgraded to %{version}. app_upgraded: The app has been upgraded to %{version}.
dismiss: Dismiss dismiss: Dismiss