607 lines
22 KiB
Vue
607 lines
22 KiB
Vue
<template>
|
||
<nav
|
||
class="fixed top-0 w-full h-14 lg:h-16 bg-white/20 backdrop-blur-sm border-b-2 grid grid-cols-[1fr_auto_1fr] items-center px-4 sm:px-6 lg:px-8 z-[80]"
|
||
>
|
||
<!-- 左側:Logo + 機構切換 -->
|
||
<div
|
||
class="col-span-1 justify-self-start flex items-center gap-4 sm:gap-8 shrink-0 w-[240px] md:w-[280px] lg:w-[340px]"
|
||
>
|
||
<RouterLink to="/" class="h-9 md:h-11">
|
||
<img src="/img/common/logo.png" alt="Logo" class="h-full w-auto" />
|
||
</RouterLink>
|
||
|
||
<div class="relative" v-if="!isHome">
|
||
<div
|
||
ref="triggerRef"
|
||
class="btn bg-brand-green text-white hover:opacity-90 shadow border-none rounded-full px-6 lg:px-8 h-10 gap-2"
|
||
role="button"
|
||
tabindex="0"
|
||
aria-haspopup="true"
|
||
:aria-expanded="isFacilityOpen"
|
||
@click="toggleFacility"
|
||
@keydown.enter.prevent="toggleFacility"
|
||
@keydown.space.prevent="toggleFacility"
|
||
>
|
||
<span class="tracking-wider">{{ displayLabel }}</span>
|
||
<!-- caret icon -->
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
class="w-4 h-4"
|
||
viewBox="0 0 512 512"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="m98 190.06l139.78 163.12a24 24 0 0 0 36.44 0L414 190.06c13.34-15.57 2.28-39.62-18.22-39.62h-279.6c-20.5 0-31.56 24.05-18.18 39.62"
|
||
/>
|
||
</svg>
|
||
</div>
|
||
|
||
<!-- Dropdown -->
|
||
<div
|
||
v-show="isFacilityOpen"
|
||
ref="panelRef"
|
||
class="absolute top-12 left-0 z-50 w-56 md:w-64 rounded-md border border-brand-gray-light bg-white shadow-lg p-2"
|
||
@click.stop
|
||
>
|
||
<ul class="max-h-48 overflow-y-auto text-brand-black">
|
||
<li
|
||
v-for="item in facilities"
|
||
:key="item"
|
||
@click="selectItem(item)"
|
||
class="px-3 py-2 rounded-md cursor-pointer hover:bg-brand-gray-light tracking-wider"
|
||
:class="selectedItem === item ? 'bg-brand-green-light' : ''"
|
||
>
|
||
{{ item }}
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 中間:導覽(平板以上顯示;置中) -->
|
||
<div
|
||
class="col-span-1 justify-self-center hidden lg:flex items-center rounded-full min-w-[300px] w-[300px] bg-white/60 shadow"
|
||
>
|
||
<nav class="w-full grid grid-cols-3 divide-x divide-transparent">
|
||
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate"
|
||
:class="[
|
||
'w-full py-2 flex justify-center items-center rounded-full transition-colors',
|
||
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>首頁</a
|
||
>
|
||
</RouterLink>
|
||
|
||
<RouterLink to="/operation" v-slot="{ href, navigate, isActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate"
|
||
:class="[
|
||
'w-full py-2 flex justify-center items-center rounded-full transition-colors',
|
||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>營運</a
|
||
>
|
||
</RouterLink>
|
||
|
||
<RouterLink to="/nursing" v-slot="{ href, navigate, isActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate"
|
||
:class="[
|
||
'w-full py-2 flex justify-center items-center rounded-full transition-colors',
|
||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>照護</a
|
||
>
|
||
</RouterLink>
|
||
</nav>
|
||
</div>
|
||
|
||
<!-- 右側:通知 + 使用者(桌機顯示) -->
|
||
<div
|
||
class="col-span-1 justify-self-end hidden lg:flex items-center gap-3 sm:gap-6"
|
||
>
|
||
<button
|
||
class="relative btn bg-white text-brand-black hover:opacity-90 shadow border-none rounded-full p-2"
|
||
aria-label="通知"
|
||
@click="notif.open()"
|
||
>
|
||
<!-- 鈴鐺 -->
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="24"
|
||
height="24"
|
||
viewBox="0 0 16 16"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M8 2a4.5 4.5 0 0 0-4.5 4.5v2.401l-.964 2.414A.5.5 0 0 0 3 12h3c0 1.108.892 2 2 2s2-.892 2-2h3a.5.5 0 0 0 .464-.685L12.5 8.9V6.5A4.5 4.5 0 0 0 8 2m1 10c0 .556-.444 1-1 1s-1-.444-1-1zM4.5 6.5a3.5 3.5 0 1 1 7 0v2.498a.5.5 0 0 0 .036.185L12.262 11H3.738l.726-1.817a.5.5 0 0 0 .036-.185z"
|
||
/>
|
||
</svg>
|
||
|
||
<!-- 紅色圓圈徽章 -->
|
||
<span
|
||
class="absolute top-0 -right-3 w-5 h-5 rounded-full bg-brand-red-dark text-white text-xs font-bold flex items-center justify-center leading-none shadow"
|
||
aria-label="未讀通知 3 則"
|
||
>3</span
|
||
>
|
||
</button>
|
||
|
||
<div
|
||
class="btn bg-white text-brand-black hover:opacity-90 shadow border-none rounded-full px-3 md:px-5 h-9 md:h-10 gap-2 md:gap-3"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
class="w-4 h-4 md:w-5 md:h-5"
|
||
viewBox="0 0 16 16"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M11 7c0 1.66-1.34 3-3 3S5 8.66 5 7s1.34-3 3-3s3 1.34 3 3"
|
||
/>
|
||
<path
|
||
fill="currentColor"
|
||
fill-rule="evenodd"
|
||
d="M16 8c0 4.42-3.58 8-8 8s-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8M4 13.75C4.16 13.484 5.71 11 7.99 11c2.27 0 3.83 2.49 3.99 2.75A6.98 6.98 0 0 0 14.99 8c0-3.87-3.13-7-7-7s-7 3.13-7 7c0 2.38 1.19 4.49 3.01 5.75"
|
||
clip-rule="evenodd"
|
||
/>
|
||
</svg>
|
||
<p class="hidden md:inline">使用者</p>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
class="hidden md:block w-4 h-4"
|
||
viewBox="0 0 512 512"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="m98 190.06l139.78 163.12a24 24 0 0 0 36.44 0L414 190.06c13.34-15.57 2.28-39.62-18.22-39.62h-279.6c-20.5 0-31.56 24.05-18.18 39.62"
|
||
/>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 手機:漢堡按鈕-->
|
||
<button
|
||
class="lg:hidden btn bg-white text-brand-black hover:opacity-90 shadow border-none rounded-md p-2 justify-self-end"
|
||
@click="toggleMobileMenu"
|
||
:aria-expanded="isMobileMenuOpen"
|
||
aria-controls="mobile-menu"
|
||
:aria-label="isMobileMenuOpen ? '關閉主選單' : '開啟主選單'"
|
||
>
|
||
<!-- 關閉(叉叉) -->
|
||
<svg
|
||
v-if="isMobileMenuOpen"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
class="w-6 h-6"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="m12 10.586l4.95-4.95l1.414 1.414L13.414 12l4.95 4.95l-1.414 1.414L12 13.414l-4.95 4.95l-1.414-1.414L10.586 12l-4.95-4.95l1.414-1.414z"
|
||
/>
|
||
</svg>
|
||
<!-- 漢堡 -->
|
||
<svg
|
||
v-else
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
class="w-6 h-6"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path fill="currentColor" d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z" />
|
||
</svg>
|
||
</button>
|
||
|
||
<!-- 手機:全螢幕 ham menu(白底,hover 灰,active 綠) -->
|
||
<div
|
||
id="mobile-menu-overlay"
|
||
class="sm:hidden fixed inset-0 z-[1100] bg-white p-4 flex flex-col gap-4 transition-opacity duration-200"
|
||
:class="
|
||
isMobileMenuOpen
|
||
? 'opacity-100 pointer-events-auto'
|
||
: 'opacity-0 pointer-events-none'
|
||
"
|
||
role="dialog"
|
||
aria-modal="true"
|
||
aria-label="主選單"
|
||
@keydown.esc.prevent="closeMobileMenu"
|
||
>
|
||
<div
|
||
v-show="isMobileMenuOpen"
|
||
id="mobile-menu"
|
||
class="md:hidden fixed inset-0 z-[1100] bg-white p-4 flex flex-col gap-4"
|
||
role="dialog"
|
||
aria-modal="true"
|
||
aria-label="主選單"
|
||
@keydown.esc.prevent="closeMobileMenu"
|
||
>
|
||
<!-- 頂部:標題 + 叉叉(和右上按鈕行為一致) -->
|
||
<div class="flex items-center justify-between">
|
||
<p class="font-semibold text-brand-black text-base">選單</p>
|
||
<button
|
||
class="btn btn-sm bg-white border-none shadow text-brand-black"
|
||
@click="closeMobileMenu"
|
||
aria-label="關閉主選單"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
class="w-5 h-5"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="m12 10.586l4.95-4.95l1.414 1.414L13.414 12l4.95 4.95l-1.414 1.414L12 13.414l-4.95 4.95l-1.414-1.414L10.586 12l-4.95-4.95l1.414-1.414z"
|
||
/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 導覽(icon + 文字) -->
|
||
<nav class="space-y-2">
|
||
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate, closeMobileMenu()"
|
||
:class="[
|
||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M4 19v-9q0-.475.213-.9t.587-.7l6-4.5q.525-.4 1.2-.4t1.2.4l6 4.5q.375.275.588.7T20 10v9q0 .825-.588 1.413T18 21h-3q-.425 0-.712-.288T14 20v-5q0-.425-.288-.712T13 14h-2q-.425 0-.712.288T10 15v5q0 .425-.288.713T9 21H6q-.825 0-1.412-.587T4 19"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">首頁</span>
|
||
</a>
|
||
</RouterLink>
|
||
|
||
<RouterLink to="/operation" v-slot="{ href, navigate, isActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate, closeMobileMenu()"
|
||
:class="[
|
||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M20 13.75a.75.75 0 0 0-.75-.75h-3a.75.75 0 0 0-.75.75v6.75H14V4.25c0-.728-.002-1.2-.048-1.546c-.044-.325-.115-.427-.172-.484s-.159-.128-.484-.172C12.949 2.002 12.478 2 11.75 2s-1.2.002-1.546.048c-.325.044-.427.115-.484.172s-.128.159-.172.484c-.046.347-.048.818-.048 1.546V20.5H8V8.75A.75.75 0 0 0 7.25 8h-3a.75.75 0 0 0-.75.75V20.5H1.75a.75.75 0 0 0 0 1.5h20a.75.75 0 0 0 0-1.5H20z"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">營運</span>
|
||
</a>
|
||
</RouterLink>
|
||
|
||
<RouterLink to="/nursing" v-slot="{ href, navigate, isActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate, closeMobileMenu()"
|
||
:class="[
|
||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M22 9.95v4.11a1.78 1.78 0 0 1-1.78 1.78h-4.39v4.39a1.73 1.73 0 0 1-.52 1.25a1.8 1.8 0 0 1-1.26.52H9.94a1.8 1.8 0 0 1-1.26-.52a1.8 1.8 0 0 1-.52-1.25v-4.39H3.78A1.78 1.78 0 0 1 2 14.06V9.95a1.78 1.78 0 0 1 1.78-1.78h4.38V3.78a1.8 1.8 0 0 1 1.103-1.646A1.8 1.8 0 0 1 9.94 2H14a1.8 1.8 0 0 1 1.26.52a1.77 1.77 0 0 1 .52 1.26v4.39h4.39c.472.003.924.19 1.26.52A1.78 1.78 0 0 1 22 9.95"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">照護</span>
|
||
</a>
|
||
</RouterLink>
|
||
</nav>
|
||
|
||
<hr class="border-gray-200" />
|
||
|
||
<!-- 通知 + 使用者(放在全螢幕 menu 內;同樣 hover 灰、active 綠) -->
|
||
<div class="space-y-2">
|
||
<button
|
||
class="w-full flex items-center gap-3 rounded-lg px-3 py-3 transition-colors hover:bg-gray-100 text-left"
|
||
@click="closeMobileMenu()"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 20 20"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M12.45 16.002a2.5 2.5 0 0 1-4.9 0zM9.998 2c3.149 0 5.744 2.335 5.984 5.355l.013.223l.005.224l-.001 3.606l.954 2.587l.025.085l.016.086l.005.089c0 .315-.196.59-.522.707l-.114.033l-.114.01H3.751a.8.8 0 0 1-.259-.047c-.287-.105-.476-.372-.482-.716l.004-.117l.034-.13l.95-2.584L4 7.793l.004-.225C4.127 4.451 6.771 2 9.998 2"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">通知</span>
|
||
</button>
|
||
|
||
<button
|
||
class="w-full flex items-center gap-3 rounded-lg px-3 py-3 transition-colors hover:bg-gray-100 text-left"
|
||
@click="closeMobileMenu()"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M7 7a5 5 0 1 1 10 0A5 5 0 0 1 7 7M3.5 19a5 5 0 0 1 5-5h7a5 5 0 0 1 5 5v2h-17z"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">使用者</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="mt-auto text-xs text-gray-500">© U-ARK</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 平板直式 modal:在 640px~1023px 顯示,位置在漢堡鈕下方 -->
|
||
<div
|
||
v-show="isMobileMenuOpen"
|
||
class="hidden sm:block lg:hidden absolute right-4 top-16 z-[1100] w-[88vw] sm:w-[240px] bg-white rounded-xl shadow-md border border-gray-100 p-4"
|
||
role="dialog"
|
||
aria-modal="true"
|
||
aria-label="主選單(平板)"
|
||
@click.stop
|
||
>
|
||
<!-- 頂部:標題 + 關閉 -->
|
||
<div class="flex items-center justify-between mb-2">
|
||
<p class="font-semibold text-brand-black text-base">選單</p>
|
||
</div>
|
||
|
||
<!-- 導覽(icon + 文字) -->
|
||
<nav class="space-y-2">
|
||
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate, closeMobileMenu()"
|
||
:class="[
|
||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M4 19v-9q0-.475.213-.9t.587-.7l6-4.5q.525-.4 1.2-.4t1.2.4l6 4.5q.375.275.588.7T20 10v9q0 .825-.588 1.413T18 21h-3q-.425 0-.712-.288T14 20v-5q0-.425-.288-.712T13 14h-2q-.425 0-.712.288T10 15v5q0 .425-.288.713T9 21H6q-.825 0-1.412-.587T4 19"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">首頁</span>
|
||
</a>
|
||
</RouterLink>
|
||
|
||
<RouterLink to="/operation" v-slot="{ href, navigate, isActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate, closeMobileMenu()"
|
||
:class="[
|
||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M20 13.75a.75.75 0 0 0-.75-.75h-3a.75.75 0 0 0-.75.75v6.75H14V4.25c0-.728-.002-1.2-.048-1.546c-.044-.325-.115-.427-.172-.484s-.159-.128-.484-.172C12.949 2.002 12.478 2 11.75 2s-1.2.002-1.546.048c-.325.044-.427.115-.484.172s-.128.159-.172.484c-.046.347-.048 1.818-.048 1.546V20.5H8V8.75A.75.75 0 0 0 7.25 8h-3a.75.75 0 0 0-.75.75V20.5H1.75a.75.75 0 0 0 0 1.5h20a.75.75 0 0 0 0-1.5H20z"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">營運</span>
|
||
</a>
|
||
</RouterLink>
|
||
|
||
<RouterLink to="/nursing" v-slot="{ href, navigate, isActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate, closeMobileMenu()"
|
||
:class="[
|
||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M22 9.95v4.11a1.78 1.78 0 0 1-1.78 1.78h-4.39v4.39a1.73 1.73 0 0 1-.52 1.25a1.8 1.8 0 0 1-1.26.52H9.94a1.8 1.8 0 0 1-1.26-.52a1.8 1.8 0 0 1-.52-1.25v-4.39H3.78A1.78 1.78 0 0 1 2 14.06V9.95a1.78 1.78 0 0 1 1.78-1.78h4.38V3.78a1.8 1.8 0 0 1 1.103-1.646A1.8 1.8 0 0 1 9.94 2H14a1.8 1.8 0 0 1 1.26.52a1.77 1.77 0 0 1 .52 1.26v4.39h4.39c.472.003.924.19 1.26.52A1.78 1.78 0 0 1 22 9.95"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">照護</span>
|
||
</a>
|
||
</RouterLink>
|
||
</nav>
|
||
|
||
<hr class="border-gray-200 my-3" />
|
||
|
||
<!-- 通知 + 使用者(放在全螢幕 menu 內;同樣 hover 灰、active 綠) -->
|
||
<div class="space-y-2">
|
||
<button
|
||
class="w-full flex items-center gap-3 rounded-lg px-3 py-3 transition-colors hover:bg-gray-100 text-left"
|
||
@click="closeMobileMenu()"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 20 20"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M12.45 16.002a2.5 2.5 0 0 1-4.9 0zM9.998 2c3.149 0 5.744 2.335 5.984 5.355l.013.223l.005.224l-.001 3.606l.954 2.587l.025.085l.016.086l.005.089c0 .315-.196.59-.522.707l-.114.033l-.114.01H3.751a.8.8 0 0 1-.259-.047c-.287-.105-.476-.372-.482-.716l.004-.117l.034-.13l.95-2.584L4 7.793l.004-.225C4.127 4.451 6.771 2 9.998 2"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">通知</span>
|
||
</button>
|
||
|
||
<button
|
||
class="w-full flex items-center gap-3 rounded-lg px-3 py-3 transition-colors hover:bg-gray-100 text-left"
|
||
@click="closeMobileMenu()"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
fill="currentColor"
|
||
d="M7 7a5 5 0 1 1 10 0A5 5 0 0 1 7 7M3.5 19a5 5 0 0 1 5-5h7a5 5 0 0 1 5 5v2h-17z"
|
||
/>
|
||
</svg>
|
||
<span class="text-brand-black">使用者</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
ref,
|
||
computed,
|
||
onMounted,
|
||
onUnmounted,
|
||
defineOptions,
|
||
nextTick,
|
||
watch,
|
||
} from "vue";
|
||
import { useRoute } from "vue-router";
|
||
import { useNotifStore } from "@/stores/notif";
|
||
const notif = useNotifStore();
|
||
|
||
// ====== 通知 Modal 狀態與行為 ======
|
||
const isNotifOpen = ref(false);
|
||
const notifBtnRef = ref(null);
|
||
const notifPanelRef = ref(null);
|
||
const notifCloseRef = ref(null);
|
||
|
||
const openNotif = async () => {
|
||
isNotifOpen.value = true;
|
||
await nextTick();
|
||
// 開啟後把焦點放到關閉鍵(無障礙友善)
|
||
notifCloseRef.value?.focus?.();
|
||
};
|
||
|
||
const closeNotif = async () => {
|
||
isNotifOpen.value = false;
|
||
await nextTick();
|
||
// 關閉後將焦點還給原本的通知按鈕
|
||
notifBtnRef.value?.focus?.();
|
||
};
|
||
|
||
// ====== 首頁隱藏(機構選單功能)======
|
||
const route = useRoute();
|
||
const isHome = computed(() => route.name === "home" || route.path === "/");
|
||
// Dropdown 狀態
|
||
const isOpen = ref(false);
|
||
watch(
|
||
() => route.fullPath,
|
||
(p) => {
|
||
if (p === "/" || route.name === "home") isOpen.value = false;
|
||
}
|
||
);
|
||
|
||
// ====== Dropdown(機構清單)======
|
||
const isFacilityOpen = ref(false);
|
||
const triggerRef = ref(null);
|
||
const panelRef = ref(null);
|
||
|
||
const facilities = ["A 機構", "B 機構", "C 機構", "D 機構", "E 機構", "F 機構"];
|
||
const selectedItem = ref(facilities[0]);
|
||
|
||
const selectItem = (item) => {
|
||
selectedItem.value = item;
|
||
isOpen.value = false;
|
||
};
|
||
const displayLabel = computed(() => {
|
||
const label = String(selectedItem.value ?? "護祐");
|
||
return label.length > 4 ? label.slice(0, 4) + "..." : label;
|
||
});
|
||
defineOptions({ name: "NavBar" });
|
||
|
||
const toggleFacility = () => {
|
||
isFacilityOpen.value = !isFacilityOpen.value;
|
||
};
|
||
|
||
const onClickOutside = (e) => {
|
||
const t = e.target;
|
||
if (!triggerRef.value || !panelRef.value) return;
|
||
const clickedInsideTrigger = triggerRef.value.contains(t);
|
||
const clickedInsidePanel = panelRef.value.contains(t);
|
||
if (!clickedInsideTrigger && !clickedInsidePanel) {
|
||
isFacilityOpen.value = false;
|
||
}
|
||
};
|
||
|
||
// ====== 手機版抽屜(漢堡選單)======
|
||
const isMobileMenuOpen = ref(false);
|
||
const toggleMobileMenu = async () => {
|
||
isMobileMenuOpen.value = !isMobileMenuOpen.value;
|
||
if (isMobileMenuOpen.value) {
|
||
await nextTick();
|
||
// 需要的話在這裡把焦點移到關閉鈕或第一個連結
|
||
}
|
||
};
|
||
const closeMobileMenu = () => {
|
||
isMobileMenuOpen.value = false;
|
||
};
|
||
|
||
// ====== 全域鍵盤(Esc 同時關閉兩種面板)======
|
||
const handleKeydown = (e) => {
|
||
if (e.key === "Escape") {
|
||
isFacilityOpen.value = false; // 關 dropdown
|
||
isMobileMenuOpen.value = false; // 關 ham menu
|
||
isNotifOpen.value = false; // 關通知 Modal
|
||
}
|
||
};
|
||
|
||
onMounted(() => {
|
||
document.addEventListener("click", onClickOutside);
|
||
document.addEventListener("keydown", handleKeydown);
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
document.removeEventListener("click", onClickOutside);
|
||
document.removeEventListener("keydown", handleKeydown);
|
||
});
|
||
</script>
|
||
|
||
<style scoped></style>
|