@@ -44,6 +44,30 @@ async function adminApi(path, options = {}) {
4444
4545function $a ( sel ) { return document . querySelector ( sel ) ; }
4646
47+ const ADMIN_TOAST_ICONS = {
48+ success : '<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' ,
49+ error : '<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M15 9l-6 6M9 9l6 6"/></svg>' ,
50+ info : '<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>' ,
51+ warning : '<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>' ,
52+ } ;
53+
54+ function showAdminToast ( message , type = 'success' ) {
55+ const container = $a ( '#admin-toast-container' ) || ( ( ) => {
56+ const el = document . createElement ( 'div' ) ;
57+ el . id = 'admin-toast-container' ;
58+ el . className = 'toast-container' ;
59+ document . body . appendChild ( el ) ;
60+ return el ;
61+ } ) ( ) ;
62+
63+ const toast = document . createElement ( 'div' ) ;
64+ toast . className = `toast toast-${ type } ` ;
65+ toast . innerHTML = ( ADMIN_TOAST_ICONS [ type ] || ADMIN_TOAST_ICONS . success ) + `<span>${ message } </span>` ;
66+ toast . addEventListener ( 'click' , ( ) => toast . remove ( ) ) ;
67+ container . appendChild ( toast ) ;
68+ setTimeout ( ( ) => { if ( toast . parentNode ) toast . remove ( ) ; } , 4000 ) ;
69+ }
70+
4771function adminNavigateTo ( page ) {
4872 const parts = page . split ( '/' ) ;
4973 const basePage = parts [ 0 ] || 'servers' ;
0 commit comments