853ae776f9
FB IAB on Xiaomi (and similar WebViews that don't shrink 100dvh) keeps the chat input covered by the soft keyboard. Fix by writing the visualViewport-derived keyboard height to a CSS variable on <html> and consuming it as padding-bottom on the chat input bar. - Add useKeyboardHeight hook (visualViewport + rAF batching, no re-renders) - Apply --keyboard-height + env(safe-area-inset-bottom) to .bar padding - Add scrollIntoView on textarea focus so the input stays visible - Add viewportFit: cover so safe-area-inset-bottom is reported
67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import type { Metadata, Viewport } from "next";
|
||
import { SerwistProvider } from "@serwist/turbopack/react";
|
||
import { SessionProvider } from "@/providers/session-provider";
|
||
import { geistSans, geistMono, athelas } from "@/core/fonts";
|
||
import "./globals.css";
|
||
|
||
import { RootProviders } from "@/providers/root-providers";
|
||
|
||
export const metadata: Metadata = {
|
||
title: "cozsweet",
|
||
description: "cozsweet frontend (Next.js)",
|
||
// PWA:链接到 public/manifest.json(由 @ducanh2912/next-pwa 体系使用)
|
||
manifest: "/manifest.json",
|
||
// iOS Safari "添加到主屏" 元数据
|
||
appleWebApp: {
|
||
capable: true,
|
||
statusBarStyle: "default",
|
||
title: "cozsweet",
|
||
},
|
||
// iOS 触屏图标
|
||
icons: {
|
||
icon: "/favicon.ico",
|
||
apple: "/favicon.ico",
|
||
},
|
||
};
|
||
|
||
/**
|
||
* Next.js 14+ 推荐:viewport 相关元数据独立导出。
|
||
* 之前放在 `metadata.themeColor` 会在 Next.js 16 触发 deprecation 警告。
|
||
* 详见 https://nextjs.org/docs/app/api-reference/functions/generate-viewport
|
||
*/
|
||
export const viewport: Viewport = {
|
||
// 浏览器顶栏 / Android PWA 顶栏颜色
|
||
themeColor: "#f84d96",
|
||
// 让页面延伸到 notch / home indicator 区域,
|
||
// env(safe-area-inset-bottom) 才能取到非零值(见 chat-input-bar.module.css)。
|
||
// Next.js 16 的 Viewport 类型未列出此键,但 generate-viewport.md 允许附加原始 meta 值。
|
||
viewportFit: "cover",
|
||
};
|
||
|
||
export default function RootLayout({
|
||
children,
|
||
}: Readonly<{
|
||
children: React.ReactNode;
|
||
}>) {
|
||
return (
|
||
// suppressHydrationWarning:next/font + Tailwind v4 偶发类名差异;详见
|
||
// `src/app/api/auth/[...nextauth]/route.ts` 的"水合闪屏"说明。
|
||
<html
|
||
lang="en"
|
||
suppressHydrationWarning
|
||
className={`${geistSans.variable} ${geistMono.variable} ${athelas.variable} h-full antialiased`}
|
||
>
|
||
<body className="min-h-full flex flex-col">
|
||
{/* NextAuth SessionProvider:为所有客户端组件提供 useSession() 上下文 */}
|
||
<SessionProvider>
|
||
<RootProviders>
|
||
{/* PWA Service Worker 注册器 —— Serwist Turbopack 在 build 时编译 app/sw.ts,
|
||
通过 /serwist/sw.js 路由 handler 服务。SerwistProvider 内部处理注册 + 生命周期。 */}
|
||
<SerwistProvider swUrl="/serwist/sw.js">{children}</SerwistProvider>
|
||
</RootProviders>
|
||
</SessionProvider>
|
||
</body>
|
||
</html>
|
||
);
|
||
}
|