11<template >
22 <div class =" flex h-screen w-screen bg-gray-50" >
3+ <!-- Side menu -->
34 <aside v-if =" isLoggedIn" :class =" { 'w-64': !isCollapsed, 'w-20': isCollapsed }" class =" flex flex-col bg-gray-800 text-white transition-all duration-300 ease-in-out shadow-lg fixed h-full z-20" >
45 <div class =" p-4 flex justify-end" >
56 <button @click =" isCollapsed = !isCollapsed" class =" p-2 rounded-full hover:bg-gray-700 transition duration-150" :title =" isCollapsed ? 'Développer' : 'Réduire'" >
67 <svg v-if =" isCollapsed" class =" w-6 h-6" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" xmlns =" http://www.w3.org/2000/svg" ><path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M13 5l7 7-7 7M5 5l7 7-7 7" ></path ></svg >
78 <svg v-else class =" w-6 h-6" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" xmlns =" http://www.w3.org/2000/svg" ><path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M11 19l-7-7 7-7m8 14l-7-7 7-7" ></path ></svg >
89 </button >
910 </div >
11+ <img src =" /images/sentinel-kit_logo.png" alt =" Sentinel Kit Logo" class =" mx-auto mt-6 mb-6" :class =" { 'w-12 h-12': isCollapsed, 'w-24 h-24': !isCollapsed }" />
1012 <nav class =" flex-grow space-y-2 p-3" >
11- <RouterLink v-for =" item in menuItems" :key =" item.name" :to =" { name: item.route }" class =" flex items-center p-3 rounded-lg hover:bg-gray-700 transition duration-150 group" :class =" { 'justify-center': isCollapsed }" :title =" isCollapsed ? item.name : ''" >
12- <span :class =" `w-6 h-6 flex-shrink-0 icon-[ ${item.icon}] size-10 bg-white `" ></span >
13+ <RouterLink v-for =" item in menuItems" :key =" item.name" :to =" { name: item.route }" class =" flex items-center p-3 rounded-lg hover:bg-gray-400 transition duration-150 group text-white " :class =" { 'justify-center': isCollapsed }" :title =" isCollapsed ? item.name : ''" >
14+ <span :class =" `text-white bg-gray-300 w-6 h-6 flex-shrink-0 ${item.icon} size-10`" ></span >
1315 <span v-if =" !isCollapsed" class =" ml-4 font-medium whitespace-nowrap overflow-hidden" >
1416 <RouterLink :key =" item.name" :to =" { name: item.route }" class =" link link-primary [--link-color:orange]" >{{ item.name }}</RouterLink >
1517 </span >
2325 title =" Log out"
2426 >
2527 <svg class =" w-5 h-5 mr-2" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" xmlns =" http://www.w3.org/2000/svg" ><path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" ></path ></svg >
26- Log out
28+ < span v-if = " !isCollapsed " class = " whitespace-nowrap " > Log out</ span >
2729 </button >
2830
2931
3032 </aside >
3133
3234 <div :class =" { 'ml-64': !isCollapsed, 'ml-20': isCollapsed }" class =" flex-1 flex flex-col transition-all duration-300 ease-in-out" >
3335 <main class =" p-6 flex-1 overflow-y-auto" >
34- <RouterView />
36+ <RouterView @show-notification = " showNotification " />
3537 </main >
3638 </div >
39+
40+ <!-- Notification Modal -->
41+ <div
42+ v-if =" notification.visible"
43+ class =" fixed top-4 left-1/2 transform -translate-x-1/2 z-50 max-w-md w-full mx-4"
44+ >
45+ <div
46+ class =" rounded-lg shadow-lg transition-all duration-300 ease-in-out transform overflow-hidden"
47+ :class =" {
48+ 'bg-blue-100 border-l-4 border-blue-500': notification.type === 'info',
49+ 'bg-yellow-100 border-l-4 border-yellow-500': notification.type === 'warning',
50+ 'bg-red-100 border-l-4 border-red-500': notification.type === 'error'
51+ }"
52+ >
53+ <div class =" p-4" >
54+ <div class =" flex items-start" >
55+ <div class =" flex-shrink-0" >
56+ <span
57+ class =" w-6 h-6"
58+ :class =" {
59+ 'icon-[material-symbols--info] text-blue-500 bg-blue-400': notification.type === 'info',
60+ 'icon-[material-symbols--warning] text-yellow-500 bg-yellow-400': notification.type === 'warning',
61+ 'icon-[material-symbols--error] text-red-500 bg-red-400': notification.type === 'error'
62+ }"
63+ ></span >
64+ </div >
65+ <div class =" ml-3 flex-1" >
66+ <p
67+ class =" text-sm font-medium"
68+ :class =" {
69+ 'text-blue-800': notification.type === 'info',
70+ 'text-yellow-800': notification.type === 'warning',
71+ 'text-red-800': notification.type === 'error'
72+ }"
73+ >
74+ {{ notification.message }}
75+ </p >
76+ </div >
77+ <div class =" ml-4 flex-shrink-0" >
78+ <a
79+ @click =" hideNotification"
80+ class =" btn-btn-sm btn-primary inline-flex rounded-md p-1.5 focus:outline-none focus:ring-2 focus:ring-offset-2"
81+ :class =" {
82+ 'text-blue-400 hover:bg-blue-200 focus:ring-blue-600': notification.type === 'info',
83+ 'text-yellow-400 hover:bg-yellow-200 focus:ring-yellow-600': notification.type === 'warning',
84+ 'text-red-400 hover:bg-red-200 focus:ring-red-600': notification.type === 'error'
85+ }"
86+ >
87+ <span class =" sr-only" >Close</span >
88+ <span class =" icon-[material-symbols--close] w-4 h-4" ></span >
89+ </a >
90+ </div >
91+ </div >
92+ </div >
93+
94+ <!-- notification progress-bar -->
95+ <div class =" h-1 w-full relative overflow-hidden" >
96+ <div
97+ class =" h-full progress-bar"
98+ :class =" {
99+ 'bg-blue-600': notification.type === 'info',
100+ 'bg-yellow-600': notification.type === 'warning',
101+ 'bg-red-600': notification.type === 'error'
102+ }"
103+ ></div >
104+ </div >
105+ </div >
106+ </div >
37107 </div >
38108</template >
39109
@@ -45,6 +115,40 @@ const router = useRouter();
45115const isLoggedIn = ref (false );
46116const isCollapsed = ref (true );
47117
118+ // Notification system
119+ const notification = ref ({
120+ visible: false ,
121+ type: ' info' , // 'info', 'warning', 'error'
122+ message: ' '
123+ });
124+
125+ let notificationTimer = null ;
126+
127+ const showNotification = ({ type, message }) => {
128+ if (notificationTimer) {
129+ clearTimeout (notificationTimer);
130+ }
131+
132+ notification .value = {
133+ visible: true ,
134+ type,
135+ message
136+ };
137+
138+ // Auto-hide after 15 seconds
139+ notificationTimer = setTimeout (() => {
140+ hideNotification ();
141+ }, 15000 );
142+ };
143+
144+ const hideNotification = () => {
145+ notification .value .visible = false ;
146+ if (notificationTimer) {
147+ clearTimeout (notificationTimer);
148+ notificationTimer = null ;
149+ }
150+ };
151+
48152onMounted (() => {
49153 const token = localStorage .getItem (' auth_token' );
50154 isLoggedIn .value = !! token;
@@ -54,13 +158,30 @@ const logout = () => {
54158 router .push ({ name: ' Logout' });
55159};
56160
161+ // Side menu items
57162const menuItems = [
58- { name: ' Home' , icon: ' mdi-light--home ' , route: ' Home' },
59- { name: ' Dashboard' , icon: ' svg-spinners--blocks-wave ' , route: ' Home' },
60- { name: ' Assets & groups' , icon: ' line-md--computer-twotone' , route: ' Home' },
61- { name: ' Rulesets' , icon: ' mdi--account-child' , route: ' RulesList' },
62- { name: ' Detections' , icon: ' shield ' , route: ' Home' },
63- { name: ' Users' , icon: ' line-md--account' , route: ' Home' },
64- { name: ' Settings' , icon: ' settings' , route: ' Home' }
163+ { name: ' Home' , icon: ' icon-[svg-spinners--blocks-wave] ' , route: ' Home' },
164+ { name: ' Dashboard' , icon: ' icon-[solar--presentation-graph-bold] ' , route: ' Home' },
165+ { name: ' Assets & groups' , icon: ' icon-[ line-md--computer-twotone] ' , route: ' Home' },
166+ { name: ' Rulesets' , icon: ' icon-[ mdi--account-child] ' , route: ' RulesList' },
167+ { name: ' Detections' , icon: ' icon-[solar--eye-scan-broken] ' , route: ' Home' },
168+ { name: ' Users' , icon: ' icon-[ line-md--account] ' , route: ' Home' },
169+ { name: ' Settings' , icon: ' icon-[solar-- settings-bold-duotone] ' , route: ' Home' }
65170];
66- </script >
171+ </script >
172+
173+ <style scoped>
174+ .progress-bar {
175+ width : 100% ;
176+ animation : progress-countdown 15s linear forwards ;
177+ }
178+
179+ @keyframes progress-countdown {
180+ from {
181+ width : 100% ;
182+ }
183+ to {
184+ width : 0% ;
185+ }
186+ }
187+ </style >
0 commit comments