main
html 231 lines 6.92 KB
Raw
1 <html>
2 <head>
3 <title>Notification Toast Stack</title>
4 <script type="module">
5 import { store } from "/components/notifications/notification-store.js";
6 </script>
7 </head>
8 <body>
9 <div x-data>
10 <template x-if="$store.notificationStore">
11 <!-- Toast Stack Container -->
12 <div class="toast-stack-container"
13 x-show="$store.notificationStore.toastStack.length > 0">
14
15 <template x-for="(toast, index) in $store.notificationStore.toastStack" :key="toast.toastId">
16 <div class="toast-item"
17 :class="$store.notificationStore.getNotificationClass(toast.type)"
18 @click="$store.notificationStore.handleToastClick(toast.toastId, $event)"
19 @mouseenter="$store.notificationStore.clearToastTimer(toast.toastId)"
20 @mouseleave="$store.notificationStore.restartToastTimer(toast.toastId)"
21 x-transition:enter="toast-enter"
22 x-transition:leave="toast-leave">
23
24 <!-- Toast Icon -->
25 <div class="toast-icon"
26 x-html="$store.notificationStore.getNotificationIcon(toast.type)">
27 </div>
28
29 <!-- Toast Content -->
30 <div class="toast-content">
31 <div class="toast-title"
32 x-show="toast.title"
33 x-text="toast.title">
34 </div>
35 <div class="toast-message"
36 x-html="toast.message">
37 </div>
38 <!-- <div class="toast-timestamp"
39 x-text="$store.notificationStore.formatTimestamp(toast.timestamp)">
40 </div> -->
41 </div>
42
43 <!-- Toast Dismiss -->
44 <button class="toast-dismiss"
45 @click.stop="$store.notificationStore.dismissToast(toast.toastId)"
46 title="Dismiss">
47 <x-icon name="close"></x-icon>
48 </button>
49 </div>
50 </template>
51 </div>
52 </template>
53 </div>
54
55 <style>
56 /* Toast Stack Container */
57 .toast-stack-container {
58 position: absolute;
59 bottom: 5px; /* Spacing from the bottom of the zero-height container */
60 padding-right: 5px;
61 z-index: 8900;
62 display: flex;
63 flex-direction: column-reverse; /* Stack toasts upwards */
64 gap: 8px;
65 pointer-events: none;
66 max-width: 400px;
67 right: 5px; /* Anchor to the right */
68 align-items: flex-end;
69 }
70
71 /* Individual Toast Items */
72 .toast-item {
73 pointer-events: auto;
74 display: flex;
75 align-items: flex-start;
76 gap: 12px;
77 padding: 16px;
78 background: var(--color-panel);
79 border: 1px solid var(--color-border);
80 border-radius: 8px;
81 cursor: pointer;
82 transition: background-color 0.2s ease, border-color 0.2s ease,
83 box-shadow 0.2s ease, filter 0.2s ease;
84 /* backdrop-filter: blur(10px); */
85 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
86 position: relative;
87 min-height: 60px;
88 max-height: 15em;
89 overflow-y: auto;
90 }
91
92 .toast-item:hover {
93 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
94 filter: brightness(1.02);
95 }
96
97 /* Toast Type Styling */
98 .toast-item.notification-info {
99 border-left: 4px solid #2196F3;
100 /* background: rgba(33, 150, 243, 0.1); */
101 }
102
103 .toast-item.notification-success {
104 border-left: 4px solid #4CAF50;
105 /* background: rgba(76, 175, 80, 0.1); */
106 }
107
108 .toast-item.notification-warning {
109 border-left: 4px solid #FF9800;
110 /* background: rgba(255, 152, 0, 0.1); */
111 }
112
113 .toast-item.notification-error {
114 border-left: 4px solid #F44336;
115 /* background: rgba(244, 67, 54, 0.1); */
116 }
117
118 .toast-item.notification-progress {
119 border-left: 4px solid #9C27B0;
120 /* background: rgba(156, 39, 176, 0.1); */
121 }
122
123 /* Toast Icon */
124 .toast-icon {
125 font-size: 1.2rem;
126 line-height: 1;
127 min-width: 24px;
128 text-align: center;
129 margin-top: 2px;
130 }
131
132 /* Toast Content */
133 .toast-content {
134 flex: 1;
135 min-width: 0;
136 }
137
138 .toast-title {
139 font-weight: 600;
140 font-size: 0.9rem;
141 color: var(--color-primary);
142 margin-bottom: 4px;
143 line-height: 1.3;
144 }
145
146 .toast-message {
147 font-size: 0.85rem;
148 color: var(--color-text);
149 line-height: 1.4;
150 margin-bottom: 4px;
151 }
152
153 .toast-action-row {
154 margin-top: var(--spacing-sm);
155 }
156
157 .toast-timestamp {
158 font-size: 0.75rem;
159 color: var(--color-text);
160 opacity: 0.6;
161 }
162
163 /* Toast Dismiss */
164 .toast-dismiss {
165 background: transparent; /* No background by default */
166 border: none;
167 border-radius: 4px;
168 color: var(--color-text);
169 cursor: pointer;
170 padding: 4px 6px;
171 font-size: 0.8rem;
172 transition: all 0.2s ease;
173 opacity: 1; /* Always visible */
174 }
175
176 .toast-dismiss:hover {
177 background: var(--color-panel);
178 color: var(--color-primary);
179 }
180
181 /* Toast Animations */
182 .toast-enter {
183 transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
184 opacity: 0;
185 transform: translateX(100%) scale(0.8);
186 }
187
188 .toast-leave {
189 transition: all 0.2s ease;
190 opacity: 0;
191 transform: translateX(100%) scale(0.8);
192 }
193
194
195 /* Mobile Responsive */
196 @media (max-width: 768px) {
197 .toast-stack-container {
198 bottom: 10px;
199 right: 10px;
200 left: 10px;
201 max-width: none;
202 }
203
204 .toast-item {
205 padding: 12px;
206 font-size: 0.9rem;
207 }
208
209 .toast-title {
210 font-size: 0.85rem;
211 }
212
213 .toast-message {
214 font-size: 0.8rem;
215 }
216 }
217
218 /* Accessibility */
219 @media (prefers-reduced-motion: reduce) {
220 .toast-enter,
221 .toast-leave {
222 transition: none;
223 }
224
225 .toast-item:hover {
226 filter: none;
227 }
228 }
229 </style>
230 </body>
231 </html>