Vitron-Front/app/components/SearchTopBar.tsx
Arda Samadi b4d5f8d8db fix(ios): respect safe-area insets so chrome clears the notch/home bar
Content was drawing under the iOS status bar and home indicator because
the app uses viewport-fit=cover + black-translucent but the fixed/sticky
chrome didn't reserve the safe areas.

- bottom nav (MyLayout): move the 50px row into an inner box and let the
  bar extend by env(safe-area-inset-bottom) so icons sit above the home
  indicator (previously the fixed height clipped the inset padding).
- top headers gain env(safe-area-inset-top): HomePageTopBar, ExploreTopBar,
  SearchTopBar, CartHeader, ChatHeader, and wrapper-padded HeaderWithSupport
  / ProfilePagesHeader (so their absolutely-positioned buttons shift too).
- chat input pads bottom by the inset; chat scroll area height accounts for
  the taller header/input.
- _index.tsx no longer overrides the viewport meta (it was dropping
  viewport-fit=cover on the home page); the global one in root.tsx wins.

env(safe-area-inset-*) is 0 on non-notch devices, so desktop/Android render
identically — only iOS gains the padding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:42:51 +03:30

70 lines
2.0 KiB
TypeScript

import React from "react";
import { useSearchParams } from "@remix-run/react";
import AppInput from "./AppInput";
import { Search as SearchIcon } from "lucide-react";
import FilterDrawer from "./FilterDrawer";
interface SearchTopBarProps {
searchValue: string;
setSearchValue: (value: string) => void;
placeholder?: string;
minimumPrice?: number;
maximumPrice?: number;
onSearch?: () => void;
}
const SearchTopBar: React.FC<SearchTopBarProps> = ({
searchValue,
setSearchValue,
placeholder = "جستجو...",
minimumPrice = 0,
maximumPrice = 10000000,
onSearch,
}) => {
const [searchParams, setSearchParams] = useSearchParams();
const isChangedSearchBar = searchValue !== (searchParams.get("q") || "");
const handleSearch = () => {
if (onSearch) {
onSearch();
return;
}
if (isChangedSearchBar) {
const params = new URLSearchParams(searchParams);
if (searchValue.trim()) {
params.set("q", searchValue);
} else {
params.delete("q");
}
setSearchParams(params, { replace: true });
}
};
return (
<div className="flex flex-col gap-4 pb-4 pt-[calc(1rem_+_env(safe-area-inset-top))] px-4 w-full sticky top-0 z-30 bg-WHITE">
<div className="flex items-center justify-center gap-2 rounded-[10px] w-full relative">
<AppInput
inputIcon={SearchIcon}
inputDir="rtl"
inputTitle={""}
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
handleSearch();
}
}}
className="bg-WHITE2 focus:border-blue-500"
inputValue={searchValue}
inputPlaceholder={placeholder}
inputOnChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSearchValue(e.target.value);
}}
/>
<FilterDrawer minimumPrice={minimumPrice} maximumPrice={maximumPrice} />
</div>
</div>
);
};
export default SearchTopBar;