From 95b839355f8873e6c03e94b795363d68a48ca3f3 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sat, 11 Jul 2026 01:44:08 +0200 Subject: [PATCH] fix: portal search overlay to escape transform stacking context, auto-fill IMDB from ttXXXX input --- spa/src/components/search-overlay.tsx | 110 ++++++++++++++------------ 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/spa/src/components/search-overlay.tsx b/spa/src/components/search-overlay.tsx index 4301f4a..4b39bec 100644 --- a/spa/src/components/search-overlay.tsx +++ b/spa/src/components/search-overlay.tsx @@ -1,4 +1,5 @@ import { useState } from "react" +import { createPortal } from "react-dom" import { useTranslation } from "react-i18next" import { PenLine, Search, X } from "lucide-react" import { Button } from "@/components/ui/button" @@ -27,6 +28,8 @@ type SearchOverlayProps = { onSelect: (movie: MovieSelection) => void } +const IMDB_RE = /^tt\d{4,}$/i + export function SearchOverlay({ open, onClose, onSelect }: SearchOverlayProps) { const { t } = useTranslation() const [query, setQuery] = useState("") @@ -38,6 +41,15 @@ export function SearchOverlay({ open, onClose, onSelect }: SearchOverlayProps) { const debouncedQuery = useDebounce(query, 300) const { data, isPending } = useSearch({ q: debouncedQuery || undefined }) + function handleQueryChange(value: string) { + setQuery(value) + if (IMDB_RE.test(value.trim())) { + setManualImdbId(value.trim()) + setManual(true) + setQuery("") + } + } + if (!open) return null const hasImdbId = manualImdbId.trim().length > 0 @@ -56,62 +68,58 @@ export function SearchOverlay({ open, onClose, onSelect }: SearchOverlayProps) { }) } - if (manual) { - return ( -
-
- - -
-
- - - {t("searchOverlay.addManuallyTitle")} - {t("searchOverlay.addManuallyDesc")} - - -
- - setManualImdbId(e.target.value)} placeholder={t("searchOverlay.imdbPlaceholder")} autoFocus /> -

{t("searchOverlay.imdbHelp")}

-
- -

{t("searchOverlay.orSearchByTitle")}

-
- - setManualTitle(e.target.value)} placeholder={t("searchOverlay.titlePlaceholder")} /> -
-
- - setManualYear(e.target.value)} placeholder={t("searchOverlay.yearPlaceholder")} /> -
-
- - setManualDirector(e.target.value)} placeholder={t("searchOverlay.directorPlaceholder")} /> -
- -
-
-
-
- ) - } - const hasResults = (data?.movies?.items?.length ?? 0) > 0 const searched = debouncedQuery.length > 0 && !isPending - return ( + const content = manual ? ( +
+
+ + +
+
+ + + {t("searchOverlay.addManuallyTitle")} + {t("searchOverlay.addManuallyDesc")} + + +
+ + setManualImdbId(e.target.value)} placeholder={t("searchOverlay.imdbPlaceholder")} autoFocus /> +

{t("searchOverlay.imdbHelp")}

+
+ +

{t("searchOverlay.orSearchByTitle")}

+
+ + setManualTitle(e.target.value)} placeholder={t("searchOverlay.titlePlaceholder")} /> +
+
+ + setManualYear(e.target.value)} placeholder={t("searchOverlay.yearPlaceholder")} /> +
+
+ + setManualDirector(e.target.value)} placeholder={t("searchOverlay.directorPlaceholder")} /> +
+ +
+
+
+
+ ) : (
- setQuery(e.target.value)} placeholder={t("searchOverlay.searchPlaceholder")} className="pl-9" autoFocus /> + handleQueryChange(e.target.value)} placeholder={t("searchOverlay.searchPlaceholder")} className="pl-9" autoFocus /> {query && (