ios pwa沉浸式状态栏

This commit is contained in:
mtvpls
2026-07-18 12:20:15 +08:00
parent 1bbea13c62
commit f742787044
7 changed files with 42 additions and 21 deletions
+1 -2
View File
@@ -14,6 +14,7 @@ const manifestPath = path.join(publicDir, 'manifest.json');
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTVPlus'; const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTVPlus';
// manifest.json 模板 // manifest.json 模板
// Apple 状态栏等配置应写在 HTML metalayout appleWebApp),非标准 manifest 字段浏览器会忽略
const manifestTemplate = { const manifestTemplate = {
name: siteName, name: siteName,
short_name: siteName, short_name: siteName,
@@ -22,8 +23,6 @@ const manifestTemplate = {
scope: '/', scope: '/',
display: 'standalone', display: 'standalone',
background_color: '#000000', background_color: '#000000',
'apple-mobile-web-app-capable': 'yes',
'apple-mobile-web-app-status-bar-style': 'black',
icons: [ icons: [
{ {
src: '/icons/icon-192x192.png', src: '/icons/icon-192x192.png',
+6
View File
@@ -40,6 +40,12 @@ export async function generateMetadata(): Promise<Metadata> {
title: siteName, title: siteName,
description: '影视聚合', description: '影视聚合',
manifest: '/manifest.json', manifest: '/manifest.json',
// iOS 添加到主屏幕:沉浸式状态栏(需配合 viewport-fit=cover + 顶部 safe-area
appleWebApp: {
capable: true,
statusBarStyle: 'black-translucent',
title: siteName,
},
}; };
} }
+5 -2
View File
@@ -2093,7 +2093,10 @@ export default function MusicClient({ children: _children }: { children?: React.
</div> </div>
)} )}
{/* Header */} {/* Header */}
<header className="fixed top-0 left-0 right-0 z-40 bg-zinc-950/95 backdrop-blur-md border-b border-white/10 px-4 md:px-6"> <header
className="fixed top-0 left-0 right-0 z-40 bg-zinc-950/95 backdrop-blur-md border-b border-white/10 px-4 md:px-6"
style={{ paddingTop: 'env(safe-area-inset-top)' }}
>
<div className="w-full mx-auto flex items-center justify-between gap-3 md:gap-4 py-3"> <div className="w-full mx-auto flex items-center justify-between gap-3 md:gap-4 py-3">
<div className="flex items-center justify-between md:justify-start md:gap-6 w-full md:w-auto"> <div className="flex items-center justify-between md:justify-start md:gap-6 w-full md:w-auto">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@@ -2118,7 +2121,7 @@ export default function MusicClient({ children: _children }: { children?: React.
</header> </header>
{/* Main Content */} {/* Main Content */}
<main className="pt-[80px] md:pt-[76px] pb-32 px-4 md:px-6"> <main className="pt-[calc(80px+env(safe-area-inset-top))] md:pt-[calc(76px+env(safe-area-inset-top))] pb-32 px-4 md:px-6">
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
{_children} {_children}
</div> </div>
+15 -12
View File
@@ -15,8 +15,11 @@ interface MobileHeaderProps {
const MobileHeader = ({ showBackButton = false }: MobileHeaderProps) => { const MobileHeader = ({ showBackButton = false }: MobileHeaderProps) => {
const { siteName } = useSite(); const { siteName } = useSite();
return ( return (
<header className='md:hidden fixed top-0 left-0 right-0 z-[999] w-full bg-white/70 backdrop-blur-xl border-b border-gray-200/50 shadow-sm dark:bg-gray-900/70 dark:border-gray-700/50'> <header
<div className='h-12 flex items-center justify-between px-4'> className='md:hidden fixed top-0 left-0 right-0 z-[999] w-full bg-white/70 backdrop-blur-xl border-b border-gray-200/50 shadow-sm dark:bg-gray-900/70 dark:border-gray-700/50'
style={{ paddingTop: 'env(safe-area-inset-top)' }}
>
<div className='relative h-12 flex items-center justify-between px-4'>
{/* 左侧:搜索按钮、返回按钮和设置按钮 */} {/* 左侧:搜索按钮、返回按钮和设置按钮 */}
<div className='flex items-center gap-2'> <div className='flex items-center gap-2'>
<Link <Link
@@ -47,17 +50,17 @@ const MobileHeader = ({ showBackButton = false }: MobileHeaderProps) => {
<UserMenu /> <UserMenu />
<UpdateNotification /> <UpdateNotification />
</div> </div>
</div>
{/* 中间:Logo绝对居中 */} {/* 中间:Logo相对内容行居中,避免被 safe-area 顶偏 */}
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'> <div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
<Link <Link
href='/' href='/'
prefetch={false} prefetch={false}
className='text-2xl font-bold text-green-600 tracking-tight hover:opacity-80 transition-opacity' className='text-2xl font-bold text-green-600 tracking-tight hover:opacity-80 transition-opacity'
> >
{siteName} {siteName}
</Link> </Link>
</div>
</div> </div>
</header> </header>
); );
+1 -1
View File
@@ -107,7 +107,7 @@ const PageLayout = ({ children, activePath = '/', hideNavigation = false }: Page
{/* 主内容 */} {/* 主内容 */}
<main <main
className='flex-1 md:min-h-0 mb-14 md:mb-0 md:mt-0 mt-12' className='flex-1 md:min-h-0 mb-14 md:mb-0 md:mt-0 mt-[calc(3rem+env(safe-area-inset-top))]'
style={{ style={{
paddingBottom: 'calc(3.5rem + env(safe-area-inset-bottom))', paddingBottom: 'calc(3.5rem + env(safe-area-inset-bottom))',
}} }}
+9 -2
View File
@@ -119,7 +119,10 @@ export default function BooksLayout({
return ( return (
<div className='min-h-screen bg-[radial-gradient(circle_at_top_left,#fce7f3_0,transparent_34rem),linear-gradient(180deg,#fff7fb_0%,#f8fafc_44%,#f8fafc_100%)] text-slate-900 dark:bg-[radial-gradient(circle_at_top_left,rgba(6,95,70,0.26)_0,transparent_32rem),linear-gradient(180deg,#050505_0%,#09090b_100%)] dark:text-gray-100'> <div className='min-h-screen bg-[radial-gradient(circle_at_top_left,#fce7f3_0,transparent_34rem),linear-gradient(180deg,#fff7fb_0%,#f8fafc_44%,#f8fafc_100%)] text-slate-900 dark:bg-[radial-gradient(circle_at_top_left,rgba(6,95,70,0.26)_0,transparent_32rem),linear-gradient(180deg,#050505_0%,#09090b_100%)] dark:text-gray-100'>
<header className='fixed inset-x-0 top-0 z-40 border-b border-emerald-100/80 bg-white/85 shadow-sm shadow-emerald-950/5 backdrop-blur-xl dark:border-emerald-500/10 dark:bg-gray-950/85 dark:shadow-black/20'> <header
className='fixed inset-x-0 top-0 z-40 border-b border-emerald-100/80 bg-white/85 shadow-sm shadow-emerald-950/5 backdrop-blur-xl dark:border-emerald-500/10 dark:bg-gray-950/85 dark:shadow-black/20'
style={{ paddingTop: 'env(safe-area-inset-top)' }}
>
<div className='mx-auto flex h-16 max-w-6xl items-center gap-3 px-4'> <div className='mx-auto flex h-16 max-w-6xl items-center gap-3 px-4'>
{isRead || pathname === '/books/detail' ? ( {isRead || pathname === '/books/detail' ? (
<Link <Link
@@ -240,7 +243,11 @@ export default function BooksLayout({
</div> </div>
</header> </header>
<main <main
className={`mx-auto max-w-6xl ${isRead ? 'pt-16' : 'px-4 pb-24 pt-24'}`} className={`mx-auto max-w-6xl ${
isRead
? 'pt-[calc(4rem+env(safe-area-inset-top))]'
: 'px-4 pb-24 pt-[calc(6rem+env(safe-area-inset-top))]'
}`}
> >
{children} {children}
</main> </main>
+5 -2
View File
@@ -64,7 +64,10 @@ export default function MangaLayout({ children }: MangaLayoutProps) {
return ( return (
<div className='min-h-screen bg-gray-50 text-gray-900 dark:bg-black dark:text-gray-100'> <div className='min-h-screen bg-gray-50 text-gray-900 dark:bg-black dark:text-gray-100'>
<header className='fixed inset-x-0 top-0 z-[999] border-b border-gray-200/70 bg-white/85 backdrop-blur-xl shadow-sm dark:border-gray-800/80 dark:bg-gray-950/85'> <header
className='fixed inset-x-0 top-0 z-[999] border-b border-gray-200/70 bg-white/85 backdrop-blur-xl shadow-sm dark:border-gray-800/80 dark:bg-gray-950/85'
style={{ paddingTop: 'env(safe-area-inset-top)' }}
>
<div className='mx-auto flex h-14 max-w-7xl items-center gap-3 px-3 sm:h-16 sm:px-6'> <div className='mx-auto flex h-14 max-w-7xl items-center gap-3 px-3 sm:h-16 sm:px-6'>
<div className='flex min-w-0 flex-1 items-center gap-2'> <div className='flex min-w-0 flex-1 items-center gap-2'>
{meta.backHref ? ( {meta.backHref ? (
@@ -154,7 +157,7 @@ export default function MangaLayout({ children }: MangaLayoutProps) {
</header> </header>
<main <main
className={`mx-auto max-w-7xl pt-20 sm:pt-24 ${ className={`mx-auto max-w-7xl pt-[calc(5rem+env(safe-area-inset-top))] sm:pt-[calc(6rem+env(safe-area-inset-top))] ${
isReadingPage isReadingPage
? 'px-0 pb-24 sm:px-0 sm:pb-28 lg:pb-10' ? 'px-0 pb-24 sm:px-0 sm:pb-28 lg:pb-10'
: 'px-3 pb-[calc(5rem+env(safe-area-inset-bottom))] sm:px-6 sm:pb-[calc(5rem+env(safe-area-inset-bottom))] lg:pb-10' : 'px-3 pb-[calc(5rem+env(safe-area-inset-bottom))] sm:px-6 sm:pb-[calc(5rem+env(safe-area-inset-bottom))] lg:pb-10'