const { useState, useEffect } = React; function ensureHoroscopeUnifiedTheme() { const currentPage = window.location.pathname.split('/').pop() || 'dial.html'; if (/^(dial|horoscope)\.html$/.test(currentPage)) return; document.body.classList.add('horoscope-unified'); if (!document.querySelector('link[data-horoscope-theme]')) { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = '/css/horoscope-theme.css?v=2'; link.dataset.horoscopeTheme = 'true'; document.head.appendChild(link); } } ensureHoroscopeUnifiedTheme(); function PlayfulTabIcon({ name, soft = false }) { const outline = soft ? '#7A82A2' : '#687093'; const common = { viewBox:'0 0 32 32', fill:'none', stroke:outline, strokeWidth:1.35, strokeLinecap:'round', strokeLinejoin:'round', className:'w-[28px] h-[28px]', style:{filter:'drop-shadow(0 3px 2px rgba(73,65,111,.16))'}, 'aria-hidden':true }; const shine = ; const icons = { home: ( {shine} ), divination: ( ), ai: ( {shine} ), community: ( ), profile: ( ) }; return icons[name]; } function TabBar({ currentPath, variant = 'default' }) { useEffect(() => { const viewport = window.visualViewport; const syncViewportHeight = () => { const height = viewport ? viewport.height : window.innerHeight; document.documentElement.style.setProperty('--app-height', `${Math.round(height)}px`); }; syncViewportHeight(); // Some calculation pages render the fixed tab bar outside their // scrollable #root. Reserve its space inside that viewport so the // final action cannot end up behind the browser chrome or tab bar. const pageName = window.location.pathname.split('/').pop() || 'dial.html'; const appRoot = document.getElementById('root'); const hasExternalTabbar = Boolean(document.getElementById('tabbar-root')); if (appRoot && hasExternalTabbar && pageName !== 'dial.html') { appRoot.style.height = 'var(--app-height, 100dvh)'; appRoot.style.boxSizing = 'border-box'; appRoot.style.paddingBottom = 'calc(82px + env(safe-area-inset-bottom, 0px))'; appRoot.dataset.tabbarViewport = 'true'; } viewport?.addEventListener('resize', syncViewportHeight); viewport?.addEventListener('scroll', syncViewportHeight); window.addEventListener('orientationchange', syncViewportHeight); return () => { viewport?.removeEventListener('resize', syncViewportHeight); viewport?.removeEventListener('scroll', syncViewportHeight); window.removeEventListener('orientationchange', syncViewportHeight); }; }, []); const tabs = [ { id: 'home', name: '首页', icon: ( ), path: 'dial.html', activePattern: /(dial\.html|app_home\.html)$/ }, { id: 'divination', name: '测算', icon: ( ), path: 'divination.html', activePattern: /(divination\.html|quick_test\.html|index\.html|bazi\.html|horoscope\.html|compatibility\.html|destiny\.html|attachment\.html|mental\.html|relationship\.html|app_divination\.html)$/ }, { id: 'ai', name: 'AI陪伴', icon: ( ), path: 'ai.html', activePattern: /(ai\.html|ai_chat\.html)$/ }, { id: 'community', name: '广场', icon: ( ), path: 'community.html', activePattern: /(community\.html|app_community\.html)$/ }, { id: 'profile', name: '我的', icon: ( ), path: 'profile.html', activePattern: /(profile\.html|app_profile\.html|history\.html)$/ } ]; const currentFilename = currentPath || window.location.pathname.split('/').pop() || 'dial.html'; const useFloatingStyle = true; const useDreamyStyle = variant === 'dreamy' || document.body.classList.contains('horoscope-unified'); const usePlayfulStyle = variant === 'playful' || useDreamyStyle; const activeIndex = tabs.findIndex(tab => tab.activePattern.test(currentFilename)) !== -1 ? tabs.findIndex(tab => tab.activePattern.test(currentFilename)) : 0; const handleNavigation = (path) => { if (path === '#') return; window.location.href = window.location.protocol === 'file:' ? path : '/' + path; }; return (
{tabs.map((tab, idx) => { const isActive = idx === activeIndex; return (
handleNavigation(tab.path)} className="flex flex-col items-center justify-center cursor-pointer flex-1 h-full select-none relative" > {/* Default active background used by the other pages. */} {isActive && !useFloatingStyle && (
)}
{usePlayfulStyle ? : tab.icon}
{tab.name} {useFloatingStyle && isActive && !usePlayfulStyle && ( )}
); })}
); } window.TabBar = TabBar;