feat: 新增 navBar 毛玻璃效果
This commit is contained in:
parent
da7c5673ef
commit
2093a6161a
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav
|
<nav
|
||||||
class="fixed top-0 w-full h-14 lg:h-16 bg-white/50 backdrop-blur-sm shadow-md flex justify-between items-center px-4 sm:px-6 lg:px-8 z-[80]"
|
class="fixed top-0 w-full h-14 lg:h-16 bg-white/50 backdrop-blur-sm shadow-md grid grid-cols-[1fr_auto_1fr] items-center px-4 sm:px-6 lg:px-8 z-[80]"
|
||||||
>
|
>
|
||||||
<!-- 左側:Logo + 機構切換 -->
|
<!-- 左側:Logo + 機構切換 -->
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-4 sm:gap-8 shrink-0 w-[240px] md:w-[280px] lg:w-[340px]"
|
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">
|
<RouterLink to="/" class="h-9 md:h-11">
|
||||||
<img src="/img/logo.png" alt="Logo" class="h-full w-auto" />
|
<img src="/img/logo.png" alt="Logo" class="h-full w-auto" />
|
||||||
@ -22,7 +22,6 @@
|
|||||||
@keydown.enter.prevent="toggleFacility"
|
@keydown.enter.prevent="toggleFacility"
|
||||||
@keydown.space.prevent="toggleFacility"
|
@keydown.space.prevent="toggleFacility"
|
||||||
>
|
>
|
||||||
<!-- 直接顯示,不再隱藏 -->
|
|
||||||
<span class="tracking-wider">{{ displayLabel }}</span>
|
<span class="tracking-wider">{{ displayLabel }}</span>
|
||||||
<!-- caret icon -->
|
<!-- caret icon -->
|
||||||
<svg
|
<svg
|
||||||
@ -41,7 +40,7 @@
|
|||||||
<div
|
<div
|
||||||
v-show="isFacilityOpen"
|
v-show="isFacilityOpen"
|
||||||
ref="panelRef"
|
ref="panelRef"
|
||||||
class="absolute top-12 left-0 md:top-12 md:left-0 lg:left-0 z-50 w-56 md:w-64 rounded-md border border-gray-100 bg-white shadow-lg p-2"
|
class="absolute top-12 left-0 z-50 w-56 md:w-64 rounded-md border border-gray-100 bg-white shadow-lg p-2"
|
||||||
@click.stop
|
@click.stop
|
||||||
>
|
>
|
||||||
<ul class="max-h-48 overflow-y-auto text-brand-black">
|
<ul class="max-h-48 overflow-y-auto text-brand-black">
|
||||||
@ -59,16 +58,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 中間:導覽(手機隱藏;平板以上顯示;桌機放大間距) -->
|
<!-- 中間:導覽(平板以上顯示;置中) -->
|
||||||
<div
|
<div
|
||||||
class="hidden lg:grid min-w-[300px] grid-cols-3 items-center shadow-md rounded-full md:px-0 xl:min-w-[360px] bg-white/60"
|
class="col-span-1 justify-self-center hidden lg:flex items-center rounded-full min-w-[300px] w-[300px] bg-white/60 shadow-md"
|
||||||
>
|
>
|
||||||
|
<nav class="w-full grid grid-cols-3 divide-x divide-transparent">
|
||||||
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="navigate"
|
@click="navigate"
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 lg:px-6 py-2 rounded-full flex justify-center items-center transition-colors',
|
'w-full py-2 flex justify-center items-center rounded-full transition-colors',
|
||||||
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
]"
|
]"
|
||||||
>首頁</a
|
>首頁</a
|
||||||
@ -80,7 +80,7 @@
|
|||||||
:href="href"
|
:href="href"
|
||||||
@click="navigate"
|
@click="navigate"
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 lg:px-6 py-2 rounded-full flex justify-center items-center transition-colors',
|
'w-full py-2 flex justify-center items-center rounded-full transition-colors',
|
||||||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
]"
|
]"
|
||||||
>營運</a
|
>營運</a
|
||||||
@ -92,16 +92,19 @@
|
|||||||
:href="href"
|
:href="href"
|
||||||
@click="navigate"
|
@click="navigate"
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 lg:px-6 py-2 rounded-full flex justify-center items-center transition-colors',
|
'w-full py-2 flex justify-center items-center rounded-full transition-colors',
|
||||||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
]"
|
]"
|
||||||
>照護</a
|
>照護</a
|
||||||
>
|
>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右側:通知 + 使用者(手機只顯示圖示;平板顯示文字) -->
|
<!-- 右側:通知 + 使用者(桌機顯示) -->
|
||||||
<div class="hidden lg:flex items-center gap-3 sm:gap-6">
|
<div
|
||||||
|
class="col-span-1 justify-self-end hidden lg:flex items-center gap-3 sm:gap-6"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
class="btn bg-white text-brand-black hover:opacity-90 shadow-md border-none rounded-full p-2"
|
class="btn bg-white text-brand-black hover:opacity-90 shadow-md border-none rounded-full p-2"
|
||||||
aria-label="通知"
|
aria-label="通知"
|
||||||
@ -155,7 +158,7 @@
|
|||||||
|
|
||||||
<!-- 手機:漢堡按鈕-->
|
<!-- 手機:漢堡按鈕-->
|
||||||
<button
|
<button
|
||||||
class="lg:hidden btn bg-white text-brand-black hover:opacity-90 shadow-md border-none rounded-md p-2"
|
class="lg:hidden btn bg-white text-brand-black hover:opacity-90 shadow-md border-none rounded-md p-2 justify-self-end"
|
||||||
@click="toggleMobileMenu"
|
@click="toggleMobileMenu"
|
||||||
:aria-expanded="isMobileMenuOpen"
|
:aria-expanded="isMobileMenuOpen"
|
||||||
aria-controls="mobile-menu"
|
aria-controls="mobile-menu"
|
||||||
@ -233,10 +236,7 @@
|
|||||||
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="
|
@click="navigate, closeMobileMenu()"
|
||||||
navigate;
|
|
||||||
closeMobileMenu();
|
|
||||||
"
|
|
||||||
:class="[
|
:class="[
|
||||||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||||||
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
@ -260,10 +260,7 @@
|
|||||||
<RouterLink to="/operation" v-slot="{ href, navigate, isActive }">
|
<RouterLink to="/operation" v-slot="{ href, navigate, isActive }">
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="
|
@click="navigate, closeMobileMenu()"
|
||||||
navigate;
|
|
||||||
closeMobileMenu();
|
|
||||||
"
|
|
||||||
:class="[
|
:class="[
|
||||||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||||||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
@ -287,10 +284,7 @@
|
|||||||
<RouterLink to="/nursing" v-slot="{ href, navigate, isActive }">
|
<RouterLink to="/nursing" v-slot="{ href, navigate, isActive }">
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="
|
@click="navigate, closeMobileMenu()"
|
||||||
navigate;
|
|
||||||
closeMobileMenu();
|
|
||||||
"
|
|
||||||
:class="[
|
:class="[
|
||||||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||||||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
@ -376,10 +370,7 @@
|
|||||||
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
<RouterLink to="/" v-slot="{ href, navigate, isExactActive }">
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="
|
@click="navigate, closeMobileMenu()"
|
||||||
navigate;
|
|
||||||
closeMobileMenu();
|
|
||||||
"
|
|
||||||
:class="[
|
:class="[
|
||||||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||||||
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isExactActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
@ -403,10 +394,7 @@
|
|||||||
<RouterLink to="/operation" v-slot="{ href, navigate, isActive }">
|
<RouterLink to="/operation" v-slot="{ href, navigate, isActive }">
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="
|
@click="navigate, closeMobileMenu()"
|
||||||
navigate;
|
|
||||||
closeMobileMenu();
|
|
||||||
"
|
|
||||||
:class="[
|
:class="[
|
||||||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||||||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
@ -420,7 +408,7 @@
|
|||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fill="currentColor"
|
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"
|
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>
|
</svg>
|
||||||
<span class="text-brand-black">營運</span>
|
<span class="text-brand-black">營運</span>
|
||||||
@ -430,10 +418,7 @@
|
|||||||
<RouterLink to="/nursing" v-slot="{ href, navigate, isActive }">
|
<RouterLink to="/nursing" v-slot="{ href, navigate, isActive }">
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="
|
@click="navigate, closeMobileMenu()"
|
||||||
navigate;
|
|
||||||
closeMobileMenu();
|
|
||||||
"
|
|
||||||
:class="[
|
:class="[
|
||||||
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
'flex items-center gap-3 rounded-lg px-3 py-3 transition-colors',
|
||||||
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
isActive ? 'bg-brand-green-light' : 'hover:bg-gray-100',
|
||||||
|
@ -64,7 +64,7 @@ const props = defineProps({
|
|||||||
chartKey: { type: String, required: true },
|
chartKey: { type: String, required: true },
|
||||||
currentLegend: { type: String, required: true },
|
currentLegend: { type: String, required: true },
|
||||||
totalLegend: { type: String, required: true },
|
totalLegend: { type: String, required: true },
|
||||||
duration: { type: Number, default: 100 },
|
duration: { type: Number, default: 300 },
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["select"]);
|
const emit = defineEmits(["select"]);
|
||||||
|
@ -1112,7 +1112,7 @@ function getResidentsHtml(name) {
|
|||||||
? [p.hospitalized.current, p.hospitalized.total]
|
? [p.hospitalized.current, p.hospitalized.total]
|
||||||
: [0, 0];
|
: [0, 0];
|
||||||
return `
|
return `
|
||||||
<div class="tip p-2" style="cursor:pointer" data-facility="${name}">
|
<div class="tip p-2" style="cursor:pointer; touch-action:none; overscroll-behavior:contain" data-facility="${name}">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="inline-flex justify-between items-center text-brand-purple-dark font-noto">
|
<div class="inline-flex justify-between items-center text-brand-purple-dark font-noto">
|
||||||
<div class="inline-flex justify-start items-center gap-1">
|
<div class="inline-flex justify-start items-center gap-1">
|
||||||
@ -1149,7 +1149,7 @@ function getDietHtml(name) {
|
|||||||
veg: { total: 0, normal: 0, soft: 0, tube: 0 },
|
veg: { total: 0, normal: 0, soft: 0, tube: 0 },
|
||||||
};
|
};
|
||||||
return `
|
return `
|
||||||
<div class="tip p-2" style="cursor:pointer" data-facility="${name}">
|
<div class="tip p-2" style="cursor:pointer; touch-action:none; overscroll-behavior:contain" data-facility="${name}">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="inline-flex justify-between items-center text-brand-purple-dark font-noto">
|
<div class="inline-flex justify-between items-center text-brand-purple-dark font-noto">
|
||||||
<div class="inline-flex justify-start items-center gap-1">
|
<div class="inline-flex justify-start items-center gap-1">
|
||||||
@ -1245,17 +1245,49 @@ function syncTooltips() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 掛上 click
|
// 掛上 click
|
||||||
|
// 掛上事件:全面阻止滾動/焦點帶來的捲動,再執行 select
|
||||||
const t = m.getTooltip?.();
|
const t = m.getTooltip?.();
|
||||||
if (t && typeof t.getElement === "function") {
|
if (t && typeof t.getElement === "function") {
|
||||||
const el = t.getElement();
|
const el = t.getElement();
|
||||||
if (el && !el.__clickBound) {
|
if (el && !el.__bound) {
|
||||||
el.__clickBound = true;
|
el.__bound = true;
|
||||||
el.style.cursor = "pointer";
|
el.style.cursor = "pointer";
|
||||||
el.addEventListener("click", (e) => {
|
el.setAttribute("tabindex", "-1"); // 避免被聚焦造成 scroll-into-view
|
||||||
const target = e.currentTarget;
|
|
||||||
const facility = target?.getAttribute?.("data-facility") || name;
|
// 會造成頁面或容器滾動的事件一律攔截
|
||||||
selectFacility(facility);
|
const block = (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 滑鼠/指標/觸控的「按下/移動/滾動」事件,全部阻止預設
|
||||||
|
[
|
||||||
|
"wheel",
|
||||||
|
"mousewheel",
|
||||||
|
"DOMMouseScroll",
|
||||||
|
"touchstart",
|
||||||
|
"touchmove",
|
||||||
|
"pointerdown",
|
||||||
|
"pointermove",
|
||||||
|
"mousedown",
|
||||||
|
"mousemove",
|
||||||
|
].forEach((type) => {
|
||||||
|
el.addEventListener(type, block, { passive: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 點擊行為:先攔截,再執行你的選取邏輯
|
||||||
|
el.addEventListener(
|
||||||
|
"click",
|
||||||
|
(e) => {
|
||||||
|
block(e);
|
||||||
|
const facility = el.getAttribute("data-facility") || name;
|
||||||
|
selectFacility(facility);
|
||||||
|
},
|
||||||
|
{ passive: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 也順手擋掉雙擊(避免瀏覽器雙擊選字或縮放)
|
||||||
|
el.addEventListener("dblclick", block, { passive: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user