240 lines
7.2 KiB
Vue
240 lines
7.2 KiB
Vue
<template>
|
||
<nav
|
||
class="w-full h-[64px] bg-white bg-opacity-50 shadow-md flex justify-between items-center px-8"
|
||
>
|
||
<!-- 左側 logo、選單區 -->
|
||
<div class="flex justify-start items-center gap-12">
|
||
<RouterLink to="/" class="h-[45px]">
|
||
<img src="/img/logo.png" alt="Logo" class="w-full h-full" />
|
||
</RouterLink>
|
||
|
||
<div class="relative">
|
||
<div
|
||
ref="triggerRef"
|
||
class="btn text-white bg-brand-green hover:opacity-90 shadow-md border-none rounded-full px-8 tracking-widest"
|
||
role="button"
|
||
tabindex="0"
|
||
aria-haspopup="true"
|
||
:aria-expanded="isOpen ? 'true' : 'false'"
|
||
@click="toggle"
|
||
@keydown.enter.prevent="toggle"
|
||
@keydown.space.prevent="toggle"
|
||
>
|
||
{{ displayLabel }}
|
||
<span>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="16"
|
||
height="16"
|
||
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>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- Modal:定位在按鈕右下方 -->
|
||
<div
|
||
v-show="isOpen"
|
||
ref="panelRef"
|
||
class="absolute top-16 left-0 z-50 w-64 rounded-md border border-gray-100 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-gray-100"
|
||
:class="selectedItem === item ? 'bg-brand-green-light' : ''"
|
||
>
|
||
{{ item }}
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 中間 導覽按鈕區 -->
|
||
|
||
<div
|
||
class="min-w-[300px] text-brand-black bg-white shadow-md rounded-full grid grid-cols-3 items-center"
|
||
>
|
||
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
||
<a
|
||
:href="href"
|
||
@click="navigate"
|
||
:class="[
|
||
'px-5 py-2 rounded-full flex justify-center items-center 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="[
|
||
'px-5 py-2 rounded-full flex justify-center items-center 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="[
|
||
'px-5 py-2 rounded-full flex justify-center items-center transition-colors',
|
||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||
]"
|
||
>
|
||
照護
|
||
</a>
|
||
</RouterLink>
|
||
</div>
|
||
|
||
<!-- 右側 登入區 -->
|
||
<div class="flex justify-end items-center gap-8">
|
||
<div
|
||
class="btn text-brand-black bg-white hover:opacity-90 shadow-md border-none rounded-full p-2 flex justify-center items-center"
|
||
>
|
||
<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>
|
||
</div>
|
||
|
||
<div
|
||
class="btn text-brand-black bg-white hover:opacity-90 shadow-md border-none rounded-full px-6 flex justify-center items-center gap-3"
|
||
>
|
||
<span>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="16"
|
||
height="16"
|
||
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>
|
||
</span>
|
||
<p>使用者</p>
|
||
<span>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="16"
|
||
height="16"
|
||
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>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted, onUnmounted, defineOptions } from "vue";
|
||
|
||
// modal 操作
|
||
const selectItem = (item) => {
|
||
selectedItem.value = item;
|
||
isOpen.value = false;
|
||
};
|
||
|
||
// 按鈕顯示文字(>4 字就加 …)
|
||
const displayLabel = computed(() => {
|
||
const label = String(selectedItem.value ?? "護祐");
|
||
return label.length > 4 ? label.slice(0, 4) + "..." : label;
|
||
});
|
||
|
||
defineOptions({ name: "NavBar" });
|
||
|
||
const isOpen = ref(false);
|
||
const triggerRef = ref(null);
|
||
const panelRef = ref(null);
|
||
|
||
// 機構名稱清單
|
||
const facilities = [
|
||
"總部",
|
||
"護祐護理之家",
|
||
"崇祐護理之家",
|
||
"崇祐長照中心(養護型)",
|
||
"育祐護理之家",
|
||
"崇恩長照中心(養護型)",
|
||
"崇恩護理之家",
|
||
"崇恩居家護理所",
|
||
"傳心日間照顧中心",
|
||
"敬慈居家服務中心",
|
||
"傳祐長照中心(養護型)",
|
||
"中安崇恩長照中心(養護型)",
|
||
"崇智護理之家",
|
||
"慈祐長照中心(養護型)",
|
||
];
|
||
|
||
// 預設選中第一筆(同時讓按鈕顯示第一筆、li 也保持選中底色)
|
||
const selectedItem = ref(facilities[0]);
|
||
|
||
// 切換開/關
|
||
const toggle = () => {
|
||
isOpen.value = !isOpen.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) {
|
||
isOpen.value = false;
|
||
}
|
||
};
|
||
|
||
// Esc 關閉
|
||
const onKeydown = (e) => {
|
||
if (e.key === "Escape") isOpen.value = false;
|
||
};
|
||
|
||
onMounted(() => {
|
||
document.addEventListener("click", onClickOutside);
|
||
document.addEventListener("keydown", onKeydown);
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
document.removeEventListener("click", onClickOutside);
|
||
document.removeEventListener("keydown", onKeydown);
|
||
});
|
||
</script>
|
||
|
||
<style scoped></style>
|