33
33
.fh-toast-error { background-color: #F44336; }
34
34
"""
35
35
36
+ js = '''htmx.onLoad(() => {
37
+ if (!htmx.find('#fh-toast-container')) {
38
+ const ctn = document.createElement('div');
39
+ ctn.id = 'fh-toast-container';
40
+ document.body.appendChild(ctn);
41
+ }
42
+ });'''
43
+
36
44
def Toast (message : str , typ : str = "info" , dismiss : bool = False , duration :int = 5000 ):
37
45
x_btn = Button ('x' , cls = "fh-toast-dismiss" , onclick = "htmx.remove(this?.parentElement);" ) if dismiss else None
38
- return Div (Span (message ), x_btn , cls = f"fh-toast fh-toast-{ typ } " , hx_on_transitionend = "setTimeout(() => this?.remove(), %d );" % duration )
46
+ return Div (Span (message ), x_btn , cls = f"fh-toast fh-toast-{ typ } " , hx_on_transitionend = f "setTimeout(() => this?.remove(), { duration } );" )
39
47
40
48
def add_toast (sess , message : str , typ : str = "info" , dismiss : bool = False ):
41
49
assert typ in ("info" , "success" , "warning" , "error" ), '`typ` not in ("info", "success", "warning", "error")'
42
50
sess .setdefault (sk , []).append ((message , typ , dismiss ))
43
51
44
52
def render_toasts (sess ):
45
53
toasts = [Toast (msg , typ , dismiss , sess ['toast_duration' ]) for msg , typ , dismiss in sess .pop (sk , [])]
46
- return Div (* toasts , id = tcid , hx_swap_oob = 'afterbegin ' )
54
+ return Div (* toasts , hx_swap_oob = f'beforeend:# { tcid } ' )
47
55
48
56
def toast_after (resp , req , sess ):
49
57
if sk in sess and (not resp or isinstance (resp , (tuple ,FT ,FtResponse ))):
@@ -52,5 +60,5 @@ def toast_after(resp, req, sess):
52
60
53
61
def setup_toasts (app , duration = 5000 ):
54
62
app .state .toast_duration = duration
55
- app .hdrs += [Style (toast_css )]
63
+ app .hdrs += [Style (toast_css ), Script ( js ) ]
56
64
app .after .append (toast_after )
0 commit comments