Browse Source

webview header

master
mortezaei 2 weeks ago
parent
commit
2179b767c5
  1. 7
      src/components/ui/sticky-header.tsx
  2. 35
      src/lib/view-paddings.ts

7
src/components/ui/sticky-header.tsx

@ -3,6 +3,9 @@
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { useViewPaddings } from "@/hooks/use-view-paddings"; import { useViewPaddings } from "@/hooks/use-view-paddings";
// پدینگ بالای طراحی هدر (معادل pt-7 = 28px). فضای امن دستگاه به این اضافه می‌شود.
const DESIGN_TOP_PADDING = 28;
type StickyHeaderProps = { type StickyHeaderProps = {
children: ReactNode; children: ReactNode;
className?: string; className?: string;
@ -16,9 +19,9 @@ export default function StickyHeader({
return ( return (
<header <header
style={{ top: `-${top}px`, paddingTop: `${top}px` }}
style={{ top: `-${top}px`, paddingTop: `${DESIGN_TOP_PADDING + top}px` }}
className={[ className={[
"sticky z-30 rounded-b-[15px] bg-[linear-gradient(135deg,#E03950_0%,#FE6F82_100%)] px-[17px] pt-7 pb-5",
"sticky z-30 rounded-b-[15px] bg-[linear-gradient(135deg,#E03950_0%,#FE6F82_100%)] px-[17px] pb-5",
className, className,
] ]
.filter(Boolean) .filter(Boolean)

35
src/lib/view-paddings.ts

@ -46,6 +46,14 @@ function num(value: unknown): number {
return typeof value === "number" && Number.isFinite(value) ? value : 0; return typeof value === "number" && Number.isFinite(value) ? value : 0;
} }
function safeParse(value: string): unknown {
try {
return JSON.parse(value);
} catch {
return null;
}
}
function readEdges(source: EdgeSource): ViewPaddings { function readEdges(source: EdgeSource): ViewPaddings {
return { return {
top: num(source?.top), top: num(source?.top),
@ -99,9 +107,36 @@ class ViewPaddingsBridge {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
this.setupFlutterListener(); this.setupFlutterListener();
this.setupConfigEventListener();
this.requestConfig(); this.requestConfig();
} }
// مسیر جایگزین: برخی نسخه‌های اپ به‌جای onFlutterResponse، کانفیگ را با
// CustomEvent('flutterConfig') یا postMessage می‌فرستند (طبق سند پل).
// payload در این مسیر همان بدنه‌ی initial_config است (بدون پوشش action/data).
private setupConfigEventListener() {
const handle = (raw: unknown) => {
if (!raw || typeof raw !== "object") return;
const data = raw as Record<string, any>;
// فقط وقتی هنوز initial_config رسمی نرسیده و این payload فضای امن دارد.
if (this.hasInitialConfig) return;
if (!data.safeArea && !data.viewInsets) return;
this.applyInitialConfig(data);
};
window.addEventListener("flutterConfig", (event) => {
handle((event as CustomEvent).detail);
});
window.addEventListener("message", (event) => {
const data =
typeof event.data === "string"
? safeParse(event.data)
: event.data;
handle(data);
});
}
private setupFlutterListener() { private setupFlutterListener() {
const win = window as Window & { const win = window as Window & {
addFlutterResponseListener?: ( addFlutterResponseListener?: (

Loading…
Cancel
Save