[PROMOTE] 晉升 dev 變更至 demo 環境
1. 晉升提交 610899d:優化後台管理系統側邊欄佈局與全局頁面跳轉載入機制。 - 解決 Alpine.js 載入前的排版跳動 (CLS/FOUC)。 - 精確過濾站內實際跳轉,避免 Loading 畫面卡死與誤觸。 - 增加平滑的淡入淡出 Transition 與高斯模糊效果。
This commit is contained in:
commit
6885b1a99f
@ -1,25 +1,12 @@
|
||||
<div x-data="{
|
||||
loading: true
|
||||
loading: false
|
||||
}"
|
||||
x-on:show-global-loading.window="loading = true"
|
||||
x-on:hide-global-loading.window="loading = false"
|
||||
x-init="
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const simulateDelay = urlParams.get('simulate_loading');
|
||||
const delay = simulateDelay ? parseInt(simulateDelay) : 300;
|
||||
|
||||
const hideLoading = () => setTimeout(() => loading = false, delay);
|
||||
|
||||
if (document.readyState === 'complete') {
|
||||
hideLoading();
|
||||
} else {
|
||||
window.addEventListener('load', hideLoading);
|
||||
// 安全保險:模擬模式下為 30 秒,正常模式下為 5 秒
|
||||
const safetyTimeout = simulateDelay ? 30000 : 5000;
|
||||
setTimeout(hideLoading, safetyTimeout);
|
||||
}
|
||||
"
|
||||
x-show="loading"
|
||||
x-transition:enter="transition ease-out duration-150"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-300"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
|
||||
@ -26,6 +26,12 @@
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
window.applyAdminSidebarLayout = (collapsed) => {
|
||||
document.documentElement.style.setProperty('--admin-sidebar-offset', collapsed ? '6rem' : '256px');
|
||||
document.documentElement.style.setProperty('--admin-sidebar-width', collapsed ? '60px' : '14rem');
|
||||
};
|
||||
window.applyAdminSidebarLayout(localStorage.getItem('sidebarCollapsed') === 'true');
|
||||
</script>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
@ -36,7 +42,12 @@
|
||||
sidebarOpen: false,
|
||||
sidebarCollapsed: localStorage.getItem('sidebarCollapsed') === 'true',
|
||||
userDropdownOpen: false
|
||||
}" x-init="$watch('sidebarCollapsed', value => localStorage.setItem('sidebarCollapsed', value))">
|
||||
}" x-init="
|
||||
$watch('sidebarCollapsed', value => {
|
||||
localStorage.setItem('sidebarCollapsed', value);
|
||||
window.applyAdminSidebarLayout?.(value);
|
||||
})
|
||||
">
|
||||
<!-- Option A: Loading Screen -->
|
||||
<x-loading-screen />
|
||||
|
||||
@ -44,14 +55,59 @@
|
||||
<div id="top-loading-bar" class="top-loading-bar"></div>
|
||||
|
||||
<script>
|
||||
// 僅保留最基本的導航列觸發,不使用全螢幕遮罩防止卡死
|
||||
window.addEventListener('beforeunload', () => {
|
||||
document.getElementById('top-loading-bar').classList.add('loading');
|
||||
});
|
||||
(() => {
|
||||
const topLoadingBar = () => document.getElementById('top-loading-bar');
|
||||
const showPageLoading = () => {
|
||||
topLoadingBar()?.classList.remove('loading');
|
||||
window.dispatchEvent(new CustomEvent('show-global-loading'));
|
||||
};
|
||||
const hidePageLoading = () => {
|
||||
topLoadingBar()?.classList.remove('loading');
|
||||
window.dispatchEvent(new CustomEvent('hide-global-loading'));
|
||||
};
|
||||
const shouldShowPageLoading = (event, link) => {
|
||||
if (
|
||||
event.defaultPrevented ||
|
||||
event.button !== 0 ||
|
||||
event.metaKey ||
|
||||
event.ctrlKey ||
|
||||
event.shiftKey ||
|
||||
event.altKey
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
window.addEventListener('pageshow', () => {
|
||||
document.getElementById('top-loading-bar').classList.remove('loading');
|
||||
});
|
||||
if (
|
||||
!link.href ||
|
||||
link.hasAttribute('download') ||
|
||||
link.target && link.target !== '_self'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const url = new URL(link.href, window.location.href);
|
||||
const isHashOnlyNavigation = url.pathname === window.location.pathname &&
|
||||
url.search === window.location.search &&
|
||||
url.hash;
|
||||
|
||||
return url.origin === window.location.origin &&
|
||||
url.href !== window.location.href &&
|
||||
!isHashOnlyNavigation &&
|
||||
!url.href.startsWith('javascript:');
|
||||
};
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
const link = event.target.closest('a[href]');
|
||||
if (!link || !shouldShowPageLoading(event, link)) {
|
||||
return;
|
||||
}
|
||||
|
||||
showPageLoading();
|
||||
});
|
||||
|
||||
window.addEventListener('beforeunload', showPageLoading);
|
||||
window.addEventListener('pageshow', hidePageLoading);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Sidebar Overlay (Mobile) -->
|
||||
@ -63,8 +119,7 @@
|
||||
|
||||
<!-- ========== HEADER ========== -->
|
||||
<header
|
||||
class="sticky top-0 inset-x-0 flex flex-wrap sm:justify-start sm:flex-nowrap z-[48] w-full bg-white/80 backdrop-blur-md border-b border-slate-200/50 text-sm py-2.5 sm:py-4 lg:pl-[256px] dark:bg-[#0f172a]/80 dark:border-slate-800/50 shadow-sm transition-all duration-300"
|
||||
:class="sidebarCollapsed ? 'lg:pl-24' : 'lg:pl-[256px]'">
|
||||
class="sticky top-0 inset-x-0 flex flex-wrap sm:justify-start sm:flex-nowrap z-[48] w-full bg-white/80 backdrop-blur-md border-b border-slate-200/50 text-sm py-2.5 sm:py-4 lg:pl-[var(--admin-sidebar-offset)] dark:bg-[#0f172a]/80 dark:border-slate-800/50 shadow-sm transition-all duration-300">
|
||||
<nav class="flex basis-full items-center w-full mx-auto pl-4 lg:pl-0 pr-4 sm:pr-6 md:pr-8" aria-label="Global">
|
||||
<div class="mr-5 lg:mr-0 lg:hidden text-center">
|
||||
<a class="flex items-center gap-x-2 flex-none text-xl font-bold dark:text-white font-display tracking-tight"
|
||||
@ -384,10 +439,9 @@
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div id="application-sidebar"
|
||||
class="fixed top-0 left-0 bottom-0 z-[60] bg-white dark:bg-[#0f172a] pt-5 pb-10 border-e border-slate-200 dark:border-none overflow-y-auto overflow-x-hidden transition-all duration-300 transform lg:translate-x-0 shadow-xl dark:shadow-2xl flex flex-col"
|
||||
class="fixed top-0 left-0 bottom-0 z-[60] w-[var(--admin-sidebar-width)] bg-white dark:bg-[#0f172a] pt-5 pb-10 border-e border-slate-200 dark:border-none overflow-y-auto overflow-x-hidden transition-all duration-300 transform lg:translate-x-0 shadow-xl dark:shadow-2xl flex flex-col"
|
||||
:class="[
|
||||
sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0',
|
||||
sidebarCollapsed ? 'w-[60px]' : 'w-56'
|
||||
sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'
|
||||
]" x-init="$nextTick(() => {
|
||||
const activeItem = $el.querySelector('.active, .bg-slate-100, .dark\\:bg-white\\/5');
|
||||
if (activeItem) {
|
||||
@ -441,10 +495,9 @@
|
||||
<!-- End Sidebar -->
|
||||
|
||||
<!-- Content -->
|
||||
<div class="w-full pt-4 lg:pt-5 pb-12 px-4 sm:px-6 md:px-8 transition-all duration-300"
|
||||
:class="sidebarCollapsed ? 'lg:pl-24' : 'lg:pl-[256px]'">
|
||||
<div class="w-full pt-4 lg:pt-5 pb-12 px-4 sm:px-6 md:px-8 lg:pl-[var(--admin-sidebar-offset)]">
|
||||
<x-breadcrumbs class="mb-4 hidden lg:flex" />
|
||||
<main class="animate-fade-up">
|
||||
<main>
|
||||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
@ -459,4 +512,4 @@
|
||||
@yield('scripts')
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user