4141 {{ $t('navbar.configuration') }}
4242 </a >
4343 </li >
44- <li class =" nav-item" >
45- <a class =" nav-link" href =" ./password" >
46- <Shield :size =" 18 " class="icon"></Shield >
47- {{ $t('navbar.password') }}
48- </a >
49- </li >
5044 <li class =" nav-item" >
5145 <a class =" nav-link" href =" ./troubleshooting" >
5246 <Info :size =" 18 " class="icon"></Info >
5347 {{ $t('navbar.troubleshoot') }}
5448 </a >
5549 </li >
50+ </ul >
51+ <ul class =" navbar-nav ms-auto mb-2 mb-lg-0" >
5652 <li class =" nav-item" >
5753 <ThemeToggle />
5854 </li >
55+ <li class =" nav-item dropdown" >
56+ <button class =" nav-link dropdown-toggle" type =" button" id =" navbarUserMenu"
57+ data-bs-toggle =" dropdown" aria-expanded =" false" aria-label =" User menu" title =" User menu" >
58+ <CircleUserRound :size =" 18 " class="icon"></CircleUserRound >
59+ </button >
60+ <ul class =" dropdown-menu dropdown-menu-end" aria-labelledby =" navbarUserMenu" >
61+ <li >
62+ <a class =" dropdown-item d-flex align-items-center" href =" ./password" >
63+ <Shield :size =" 18 " class="icon"></Shield >
64+ {{ $t('navbar.password') }}
65+ </a >
66+ </li >
67+ <li ><hr class =" dropdown-divider" ></li >
68+ <li >
69+ <button type =" button" class =" dropdown-item d-flex align-items-center" @click =" logout" >
70+ <LogOut :size =" 18 " class="icon"></LogOut >
71+ {{ $t('navbar.logout') }}
72+ </button >
73+ </li >
74+ </ul >
75+ </li >
5976 </ul >
6077 </div >
6178 </div >
6582</template >
6683
6784<script >
68- import { Home , Lock , Layers , Star , Settings , Shield , Info } from ' lucide-vue-next'
85+ import { CircleUserRound , Home , Info , Layers , Lock , LogOut , Settings , Shield , Star } from ' lucide-vue-next'
6986import ThemeToggle from ' ./ThemeToggle.vue'
7087import Notification from ' ./Notification.vue'
7188
@@ -79,14 +96,48 @@ export default {
7996 Star,
8097 Settings,
8198 Shield,
82- Info
99+ Info,
100+ CircleUserRound,
101+ LogOut
83102 },
84103 created () {
85104 console .log (" Header mounted!" )
86105 },
87106 mounted () {
88- let el = document .querySelector (" a[href='" + document .location .pathname + " ']" );
89- if (el) el .classList .add (" active" )
107+ const currentPath = globalThis .location .pathname .replace (/ \/ $ / , ' ' ) || ' /'
108+ const links = document .querySelectorAll (' .navbar-sunshine a[href]' )
109+
110+ for (const link of links) {
111+ const href = link .getAttribute (' href' )
112+ if (! href || href === ' #' ) {
113+ continue
114+ }
115+
116+ const linkPath = new URL (href, globalThis .location .href ).pathname .replace (/ \/ $ / , ' ' ) || ' /'
117+ if (linkPath !== currentPath) {
118+ continue
119+ }
120+
121+ link .classList .add (' active' )
122+ }
123+ },
124+ methods: {
125+ logout () {
126+ const cacheBuster = Date .now ().toString ()
127+ const logoutPageUrl = new URL (' /logout' , globalThis .location .href )
128+ const request = new XMLHttpRequest ()
129+ const finish = () => {
130+ globalThis .location .replace (logoutPageUrl .toString ())
131+ }
132+
133+ request .open (' GET' , ' /' , true , ' sunshine-logout' , cacheBuster)
134+ request .setRequestHeader (' Cache-Control' , ' no-store' )
135+ request .onload = finish
136+ request .onerror = finish
137+ request .ontimeout = finish
138+ request .timeout = 5000
139+ request .send ()
140+ }
90141 }
91142}
92143 </script >
0 commit comments