Skip to content

Commit 881ad6d

Browse files
committed
Add: Reusable client toast notification snippet (toast.js + demo + README)
1 parent d9e42aa commit 881ad6d

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Demo client script showing how to use SnToast
2+
// Place in a Client Script (onLoad or onChange) or run from browser console
3+
4+
function onLoad() {
5+
// Example: success toast
6+
SnToast.showToast('success', 'Record saved successfully', { duration: 3000 });
7+
8+
// Example: error toast after a simulated async operation
9+
setTimeout(function() {
10+
SnToast.showToast('error', 'Failed to sync with external system', { duration: 5000 });
11+
}, 1200);
12+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
(function(){
2+
if (window.SnToast) return;
3+
4+
// Create container and attach to body when needed
5+
function ensureContainer() {
6+
var id = 'sn-toast-container';
7+
var c = document.getElementById(id);
8+
if (!c) {
9+
c = document.createElement('div');
10+
c.id = id;
11+
c.style.position = 'fixed';
12+
c.style.top = '12px';
13+
c.style.right = '12px';
14+
c.style.zIndex = '99999';
15+
c.style.display = 'flex';
16+
c.style.flexDirection = 'column';
17+
c.style.alignItems = 'flex-end';
18+
document.body.appendChild(c);
19+
}
20+
return c;
21+
}
22+
23+
function buildToast(message, type) {
24+
var t = document.createElement('div');
25+
t.className = 'sn-toast';
26+
t.textContent = message || '';
27+
t.style.minWidth = '160px';
28+
t.style.maxWidth = '420px';
29+
t.style.padding = '10px 14px';
30+
t.style.marginTop = '8px';
31+
t.style.borderRadius = '8px';
32+
t.style.boxShadow = '0 6px 18px rgba(0,0,0,0.12)';
33+
t.style.fontSize = '13px';
34+
t.style.lineHeight = '1.2';
35+
t.style.color = '#fff';
36+
t.style.opacity = '1';
37+
t.style.transition = 'opacity 0.3s ease, transform 0.25s ease';
38+
t.style.transform = 'translateY(0)';
39+
// background based on type
40+
var bg = '#2ecc71'; // success
41+
if (type === 'error') bg = '#e74c3c';
42+
else if (type === 'warning') bg = '#f39c12';
43+
else if (type === 'info') bg = '#3498db';
44+
t.style.background = bg;
45+
return t;
46+
}
47+
48+
window.SnToast = {
49+
showToast: function(type, message, opts) {
50+
try {
51+
if (typeof type !== 'string') { message = type; type = 'info'; }
52+
opts = opts || {};
53+
var duration = (typeof opts.duration === 'number') ? opts.duration : 3500;
54+
var container = ensureContainer();
55+
var toast = buildToast(message, type);
56+
container.appendChild(toast);
57+
58+
// Auto-dismiss
59+
setTimeout(function() {
60+
toast.style.opacity = '0';
61+
toast.style.transform = 'translateY(-6px)';
62+
setTimeout(function(){
63+
if (toast && toast.parentNode) toast.parentNode.removeChild(toast);
64+
}, 300);
65+
}, duration);
66+
} catch (e) {
67+
/* fallback to default g_form messages if available */
68+
if (window.g_form && g_form.addInfoMessage) {
69+
g_form.addInfoMessage(message);
70+
} else {
71+
console.error('SnToast error:', e);
72+
}
73+
}
74+
}
75+
};
76+
})();

0 commit comments

Comments
 (0)