|
2 | 2 | {% comment %} |
3 | 3 | How this works: |
4 | 4 | - A htmx response responds with either "showMessage" or "messages" "HX-Trigger" event. |
5 | | -- htmx traps the event and create another event for the toast layer. |
| 5 | +- htmx traps the event and creates another event for the toast layer. |
6 | 6 | - The toast layer listens to the event and adds the toast to the list. |
| 7 | +- Toasts can be paused on hover and dismissed manually |
| 8 | +- Supports different message types with corresponding styles and icons |
7 | 9 | {% endcomment %} |
8 | 10 |
|
9 | 11 | <!-- Toast layer --> |
10 | 12 | <script> |
11 | 13 | function toastHandler() { |
12 | 14 | "use strict"; |
13 | | - const AUTO_HIDE_TIMEOUT = 2500; |
| 15 | + const AUTO_HIDE_TIMEOUT = 3000; |
14 | 16 | return { |
15 | 17 | toasts: [], |
16 | 18 | visible: [], |
|
56 | 58 | }, |
57 | 59 | }; |
58 | 60 | } |
| 61 | + |
| 62 | + const createNoticeEvent = (detail) => new CustomEvent("notice", { |
| 63 | + detail, |
| 64 | + bubbles: true, |
| 65 | + cancelable: true, |
| 66 | + composed: true |
| 67 | + }); |
| 68 | + |
59 | 69 | htmx.on("showMessage", (e) => { |
60 | | - let message_detail = { type: "success", text: e.detail.value }; |
61 | | - dispatchEvent( |
62 | | - new CustomEvent("notice", { |
63 | | - detail: message_detail, |
64 | | - bubbles: true, |
65 | | - cancelable: true, |
66 | | - composed: true, |
67 | | - }) |
68 | | - ); |
| 70 | + dispatchEvent(createNoticeEvent({ type: "success", text: e.detail.value })); |
69 | 71 | }); |
| 72 | + |
70 | 73 | htmx.on("messages", (e) => { |
71 | | - e.detail.value.forEach((message) => { |
72 | | - let message_detail = { type: message.tags, text: message.message }; |
73 | | - console.log(message_detail); |
74 | | - dispatchEvent( |
75 | | - new CustomEvent("notice", { |
76 | | - detail: message_detail, |
77 | | - bubbles: true, |
78 | | - cancelable: true, |
79 | | - composed: true, |
80 | | - }) |
81 | | - ); |
| 74 | + e.detail.value.forEach(message => { |
| 75 | + dispatchEvent(createNoticeEvent({ type: message.tags, text: message.message })); |
82 | 76 | }); |
83 | 77 | }); |
84 | 78 | </script> |
85 | 79 |
|
86 | 80 | <div |
87 | 81 | x-data="toastHandler()" |
88 | | - class="flex fixed inset-0 flex-col justify-start items-end px-4 w-screen h-screen pointer-events-none" |
| 82 | + class="flex fixed inset-0 z-50 flex-col justify-start items-end px-8 mx-auto w-screen h-screen pointer-events-none max-w-[2200px]" |
89 | 83 | @notice.window="add($event.detail)" |
90 | 84 | > |
91 | 85 | <template x-for="toast of toasts" :key="toast.id"> |
|
96 | 90 | x-show="visible.includes(toast)" |
97 | 91 | x-transition:enter="transition ease-in duration-200" |
98 | 92 | x-transition:enter-start="transform opacity-0 translate-y-2" |
99 | | - x-transition:enter-end="transform opacity-100" |
| 93 | + x-transition:enter-end="transform opacity-100 translate-y-0" |
100 | 94 | x-transition:leave="transition ease-out duration-500" |
101 | 95 | x-transition:leave-start="transform translate-x-0 opacity-100" |
102 | 96 | x-transition:leave-end="transform translate-x-full opacity-0" |
103 | 97 | @click="remove(toast.id)" |
104 | 98 | @mouseenter="pause(toast.id)" |
105 | 99 | @mouseleave="resume(toast.id)" |
106 | | - class="relative py-3 px-4 mt-4 w-full max-w-full text-sm font-bold text-white rounded-md shadow-xl cursor-pointer sm:w-auto sm:max-w-sm group" |
| 100 | + class="relative py-3 px-4 mt-4 w-full max-w-full text-sm font-semibold text-white rounded-md shadow-xl cursor-pointer sm:w-auto sm:max-w-sm break-anywhere hyphens-auto group sm:min-w-64" |
107 | 101 | :class="{ |
108 | | - 'bg-gray-500': toast.type === 'debug', |
109 | | - 'bg-green-500': toast.type === 'success', |
| 102 | + 'bg-neutral-500': toast.type === 'debug', |
| 103 | + 'bg-green-600': toast.type === 'success', |
110 | 104 | 'bg-blue-500': toast.type === 'info', |
111 | 105 | 'bg-orange-500': toast.type === 'warning', |
112 | 106 | 'bg-red-500': toast.type === 'error', |
113 | 107 | }" |
114 | 108 | style="pointer-events:all" |
115 | 109 | > |
116 | | - <div class="flex gap-2 items-center"> |
| 110 | + <div class="flex gap-4 items-center"> |
117 | 111 | <span x-show="toast.type == 'info'" aria-hidden="true"> |
118 | | - {% heroicon_solid "information-circle" size=24 class="inline-block rounded-full" %} |
| 112 | + {% heroicon_solid "light-bulb" size=24 class="inline-block rounded-full" %} |
119 | 113 | </span> |
120 | 114 | <span x-show="toast.type == 'success'" aria-hidden="true"> |
121 | 115 | {% heroicon_solid "check-circle" size=24 class="inline-block rounded-full" %} |
122 | 116 | </span> |
| 117 | + <span x-show="toast.type == 'warning'" aria-hidden="true"> |
| 118 | + {% heroicon_solid "exclamation-circle" size=24 class="inline-block rounded-full" %} |
| 119 | + </span> |
| 120 | + <span x-show="toast.type == 'error'" aria-hidden="true"> |
| 121 | + {% heroicon_solid "exclamation-triangle" size=24 class="inline-block rounded-full" %} |
| 122 | + </span> |
| 123 | + <span x-show="toast.type == 'debug'" aria-hidden="true"> |
| 124 | + {% heroicon_solid "wrench" size=24 class="inline-block rounded-full" %} |
| 125 | + </span> |
123 | 126 | <span x-text="toast.text"></span> |
124 | 127 | </div> |
125 | 128 | <button class="absolute -top-3 -left-3 invisible p-1 transition-all group-hover:visible"> |
|
0 commit comments