Fix narrow PWA layout on tablet with standalone width rules.
Allow any orientation in manifest, widen content and enable dual-column mode in installed apps on tablet viewports, with iOS display-mode fallback. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -126,4 +126,34 @@
|
|||||||
.zen-card {
|
.zen-card {
|
||||||
@apply bg-card/85 backdrop-blur-sm;
|
@apply bg-card/85 backdrop-blur-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PWA 安装后:iPad 等平板视口常 <1024px,单独放宽宽度与双栏 */
|
||||||
|
@media (display-mode: standalone) and (min-width: 768px) and (max-width: 1919px) {
|
||||||
|
.site-content-shell {
|
||||||
|
max-width: 72rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-content-shell-narrow {
|
||||||
|
max-width: 64rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-workspace-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iOS PWA 兜底:部分系统不识别 display-mode 媒体查询 */
|
||||||
|
@media (min-width: 768px) and (max-width: 1919px) {
|
||||||
|
html[data-display-mode="standalone"] .site-content-shell {
|
||||||
|
max-width: 72rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-display-mode="standalone"] .site-content-shell-narrow {
|
||||||
|
max-width: 64rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-display-mode="standalone"] .mode-workspace-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { Metadata, Viewport } from "next";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Umami from "@/components/umami";
|
import Umami from "@/components/umami";
|
||||||
import PwaProvider from "@/components/pwa/pwa-provider";
|
import PwaProvider from "@/components/pwa/pwa-provider";
|
||||||
|
import PwaDisplayMode from "@/components/pwa/pwa-display-mode";
|
||||||
import { ThemeProvider } from "next-themes";
|
import { ThemeProvider } from "next-themes";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -14,6 +15,10 @@ export const metadata: Metadata = {
|
|||||||
title: "知命阁",
|
title: "知命阁",
|
||||||
statusBarStyle: "default",
|
statusBarStyle: "default",
|
||||||
},
|
},
|
||||||
|
other: {
|
||||||
|
"mobile-web-app-capable": "yes",
|
||||||
|
"apple-mobile-web-app-capable": "yes",
|
||||||
|
},
|
||||||
manifest: "/manifest.webmanifest",
|
manifest: "/manifest.webmanifest",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,6 +54,7 @@ export default function RootLayout({
|
|||||||
disableTransitionOnChange
|
disableTransitionOnChange
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
<PwaDisplayMode />
|
||||||
<PwaProvider />
|
<PwaProvider />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
<Umami />
|
<Umami />
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ export default function manifest(): MetadataRoute.Manifest {
|
|||||||
"融合周易智慧与人工智能 — 易经学习、六爻算卦、生辰八字、综合测算",
|
"融合周易智慧与人工智能 — 易经学习、六爻算卦、生辰八字、综合测算",
|
||||||
start_url: "/",
|
start_url: "/",
|
||||||
display: "standalone",
|
display: "standalone",
|
||||||
orientation: "portrait-primary",
|
orientation: "any",
|
||||||
background_color: "#f5f5f4",
|
background_color: "#f5f5f4",
|
||||||
theme_color: "#525252",
|
theme_color: "#525252",
|
||||||
lang: "zh-CN",
|
lang: "zh-CN",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ function Footer() {
|
|||||||
return (
|
return (
|
||||||
<footer className="relative z-10 flex items-center justify-center gap-1 border-t border-border/40 bg-card/70 py-4 text-xs text-muted-foreground/80">
|
<footer className="relative z-10 flex items-center justify-center gap-1 border-t border-border/40 bg-card/70 py-4 text-xs text-muted-foreground/80">
|
||||||
<div
|
<div
|
||||||
className={`${SITE_WIDTH_INNER} flex items-center justify-center gap-1`}
|
className={`site-content-shell ${SITE_WIDTH_INNER} flex items-center justify-center gap-1`}
|
||||||
>
|
>
|
||||||
<span className="italic">心诚则灵</span>
|
<span className="italic">心诚则灵</span>
|
||||||
<span className="text-muted-foreground/60">·</span>
|
<span className="text-muted-foreground/60">·</span>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export default function Header() {
|
|||||||
return (
|
return (
|
||||||
<header className="relative z-10 border-b border-border/40 bg-card/70 py-3 shadow-sm backdrop-blur-md">
|
<header className="relative z-10 border-b border-border/40 bg-card/70 py-3 shadow-sm backdrop-blur-md">
|
||||||
<div
|
<div
|
||||||
className={`${SITE_WIDTH_INNER} grid grid-cols-[1fr_auto] items-center gap-y-2 sm:flex sm:justify-between`}
|
className={`site-content-shell ${SITE_WIDTH_INNER} grid grid-cols-[1fr_auto] items-center gap-y-2 sm:flex sm:justify-between`}
|
||||||
>
|
>
|
||||||
<Link href="/" className="flex items-center gap-2">
|
<Link href="/" className="flex items-center gap-2">
|
||||||
<TaijiIcon />
|
<TaijiIcon />
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export function ModeWorkspace({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="py-6 lg:py-8">
|
<div className="py-6 lg:py-8">
|
||||||
<div className="grid gap-6 lg:grid-cols-2 lg:items-stretch lg:gap-8 xl:gap-10">
|
<div className="mode-workspace-grid grid gap-6 lg:grid-cols-2 lg:items-stretch lg:gap-8 xl:gap-10">
|
||||||
<div className="grid h-full min-h-0 auto-rows-fr gap-5 lg:min-h-[calc(100vh-9rem)]">
|
<div className="grid h-full min-h-0 auto-rows-fr gap-5 lg:min-h-[calc(100vh-9rem)]">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ export default function PageShell({
|
|||||||
<Header />
|
<Header />
|
||||||
<main
|
<main
|
||||||
className={cn(
|
className={cn(
|
||||||
"mx-auto flex w-full flex-1 flex-col border-border/40 bg-background sm:border-x",
|
"site-content-shell mx-auto flex w-full flex-1 flex-col border-border/40 bg-background sm:border-x",
|
||||||
|
width === "narrow" && "site-content-shell-narrow",
|
||||||
SHELL_WIDTH[width],
|
SHELL_WIDTH[width],
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
/** iOS / iPad PWA 部分版本不识别 display-mode 媒体查询,用 data 属性兜底 */
|
||||||
|
export default function PwaDisplayMode() {
|
||||||
|
useEffect(() => {
|
||||||
|
const standalone =
|
||||||
|
window.matchMedia("(display-mode: standalone)").matches ||
|
||||||
|
(window.navigator as Navigator & { standalone?: boolean }).standalone ===
|
||||||
|
true;
|
||||||
|
|
||||||
|
if (standalone) {
|
||||||
|
document.documentElement.dataset.displayMode = "standalone";
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user