diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index 266735ce..531b5dfb 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -1,4 +1,4 @@ -import { ReactNode, useState } from "react"; +import { ReactNode } from "react"; import { Link } from "react-router-dom"; import { IconPatch } from "@/components/buttons/IconPatch"; @@ -6,7 +6,6 @@ import { Icons } from "@/components/Icon"; import { Lightbar } from "@/components/utils/Lightbar"; import { useBannerSize } from "@/hooks/useBanner"; import { conf } from "@/setup/config"; -import SettingsModal from "@/views/SettingsModal"; import { BrandPill } from "./BrandPill"; @@ -17,7 +16,6 @@ export interface NavigationProps { export function Navigation(props: NavigationProps) { const bannerHeight = useBannerSize(); - const [showModal, setShowModal] = useState(false); return ( <>
@@ -52,14 +50,6 @@ export function Navigation(props: NavigationProps) { props.children ? "hidden sm:flex" : "flex" } relative flex-row gap-4`} > - { - setShowModal(true); - }} - />
- setShowModal(false)} /> ); diff --git a/src/setup/App.tsx b/src/setup/App.tsx index b3a49685..e5c5bb1f 100644 --- a/src/setup/App.tsx +++ b/src/setup/App.tsx @@ -15,9 +15,9 @@ import { Layout } from "@/setup/Layout"; import { BookmarkContextProvider } from "@/state/bookmark"; import { SettingsProvider } from "@/state/settings"; import { WatchedContextProvider } from "@/state/watched"; +import { NotFoundPage } from "@/views/errors/NotFoundPage"; +import { HomePage } from "@/views/HomePage"; import { MediaView } from "@/views/media/MediaView"; -import { NotFoundPage } from "@/views/notfound/NotFoundView"; -import { SearchView } from "@/views/search/SearchView"; function LegacyUrlView({ children }: { children: ReactElement }) { const location = useLocation(); @@ -85,16 +85,14 @@ function App() { {/* other */} import("@/views/developer/DeveloperView") - )} + component={lazy(() => import("@/views/DeveloperPage"))} /> diff --git a/src/views/HomePage.tsx b/src/views/HomePage.tsx index e69de29b..2a5ab65a 100644 --- a/src/views/HomePage.tsx +++ b/src/views/HomePage.tsx @@ -0,0 +1,64 @@ +import { useEffect, useState } from "react"; +import { Helmet } from "react-helmet"; +import { useTranslation } from "react-i18next"; + +import { MWQuery } from "@/backend/metadata/types/mw"; +import { WideContainer } from "@/components/layout/WideContainer"; +import { useDebounce } from "@/hooks/useDebounce"; +import { useSearchQuery } from "@/hooks/useSearchQuery"; +import { HomeLayout } from "@/views/layouts/HomeLayout"; +import { BookmarksPart } from "@/views/parts/home/BookmarksPart"; +import { HeroPart } from "@/views/parts/home/HeroPart"; +import { WatchingPart } from "@/views/parts/home/WatchingPart"; +import { SearchListPart } from "@/views/parts/search/SearchListPart"; +import { SearchLoadingPart } from "@/views/parts/search/SearchLoadingPart"; + +function useSearch(search: MWQuery) { + const [searching, setSearching] = useState(false); + const [loading, setLoading] = useState(false); + + const debouncedSearch = useDebounce(search, 500); + useEffect(() => { + setSearching(search.searchQuery !== ""); + setLoading(search.searchQuery !== ""); + }, [search]); + useEffect(() => { + setLoading(false); + }, [debouncedSearch]); + + return { + loading, + searching, + }; +} + +export function HomePage() { + const { t } = useTranslation(); + const [showBg, setShowBg] = useState(false); + const searchParams = useSearchQuery(); + const [search] = searchParams; + const s = useSearch(search); + + return ( + +
+ + {t("global.name")} + + +
+ + {s.loading ? ( + + ) : s.searching ? ( + + ) : ( + <> + + + + )} + +
+ ); +} diff --git a/src/views/search/SearchResultsView.tsx b/src/views/SearchPage.tsx similarity index 95% rename from src/views/search/SearchResultsView.tsx rename to src/views/SearchPage.tsx index f6507ef1..64ab09e9 100644 --- a/src/views/search/SearchResultsView.tsx +++ b/src/views/SearchPage.tsx @@ -9,8 +9,7 @@ import { SectionHeading } from "@/components/layout/SectionHeading"; import { MediaGrid } from "@/components/media/MediaGrid"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { useLoading } from "@/hooks/useLoading"; - -import { SearchLoadingView } from "./SearchLoadingView"; +import { SearchLoadingPart } from "@/views/parts/search/SearchLoadingPart"; function SearchSuffix(props: { failed?: boolean; results?: number }) { const { t } = useTranslation(); @@ -63,7 +62,7 @@ export function SearchResultsView({ searchQuery }: { searchQuery: MWQuery }) { if (searchQuery.searchQuery !== "") runSearch(searchQuery); }, [searchQuery, runSearchQuery]); - if (loading) return ; + if (loading) return ; if (error) return ; if (!results) return null; diff --git a/src/views/SearchPart.tsx b/src/views/SearchPart.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/views/SettingsModal.tsx b/src/views/SettingsModal.tsx deleted file mode 100644 index 2eb8adf6..00000000 --- a/src/views/SettingsModal.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { useMemo } from "react"; -import { useTranslation } from "react-i18next"; - -import CaptionColorSelector, { - colors, -} from "@/components/CaptionColorSelector"; -import { Dropdown } from "@/components/Dropdown"; -import { Icon, Icons } from "@/components/Icon"; -import { Modal, ModalCard } from "@/components/layout/Modal"; -import { Slider } from "@/components/Slider"; -import { conf } from "@/setup/config"; -import { appLanguageOptions } from "@/setup/i18n"; -import { - CaptionLanguageOption, - LangCode, - captionLanguages, -} from "@/setup/iso6391"; -import { useSettings } from "@/state/settings"; -import { CaptionCue } from "@/video/components/actions/CaptionRendererAction"; - -export default function SettingsModal(props: { - onClose: () => void; - show: boolean; -}) { - const { - captionSettings, - language, - setLanguage, - setCaptionLanguage, - setCaptionBackgroundColor, - setCaptionFontSize, - } = useSettings(); - const { t, i18n } = useTranslation(); - - const selectedCaptionLanguage = useMemo( - () => captionLanguages.find((l) => l.id === captionSettings.language), - [captionSettings.language] - ) as CaptionLanguageOption; - const appLanguage = useMemo( - () => appLanguageOptions.find((l) => l.id === language), - [language] - ) as CaptionLanguageOption; - const captionBackgroundOpacity = ( - (parseInt(captionSettings.style.backgroundColor.substring(7, 9), 16) / - 255) * - 100 - ).toFixed(0); - return ( - - -
-
- {t("settings.title")} -
props.onClose()} - className="hover:cursor-pointer" - > - -
-
-
-
-
- - { - i18n.changeLanguage(val.id); - setLanguage(val.id as LangCode); - }} - options={appLanguageOptions} - /> -
-
- - { - setCaptionLanguage(val.id as LangCode); - }} - options={captionLanguages} - /> -
-
- setCaptionFontSize(e.target.valueAsNumber)} - /> - - setCaptionBackgroundColor(e.target.valueAsNumber) - } - /> -
- -
- {colors.map((color) => ( - - ))} -
-
-
-
-
-
-
-
- -
-
-
-
-
-
v{conf().APP_VERSION}
- - - ); -} diff --git a/src/views/errors/NotFoundPage.tsx b/src/views/errors/NotFoundPage.tsx new file mode 100644 index 00000000..d906fb3a --- /dev/null +++ b/src/views/errors/NotFoundPage.tsx @@ -0,0 +1,23 @@ +import { useTranslation } from "react-i18next"; + +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { ArrowLink } from "@/components/text/ArrowLink"; +import { Title } from "@/components/text/Title"; +import { ErrorWrapperPart } from "@/views/parts/errors/ErrorWrapperPart"; + +export function NotFoundPage() { + const { t } = useTranslation(); + + return ( + + + {t("notFound.page.title")} +

{t("notFound.page.description")}

+ +
+ ); +} diff --git a/src/views/layouts/HomeLayout.tsx b/src/views/layouts/HomeLayout.tsx new file mode 100644 index 00000000..9b50c9c1 --- /dev/null +++ b/src/views/layouts/HomeLayout.tsx @@ -0,0 +1,14 @@ +import { FooterView } from "@/components/layout/Footer"; +import { Navigation } from "@/components/layout/Navigation"; + +export function HomeLayout(props: { + showBg: boolean; + children: React.ReactNode; +}) { + return ( + + + {props.children} + + ); +} diff --git a/src/views/layouts/PageLayout.tsx b/src/views/layouts/PageLayout.tsx new file mode 100644 index 00000000..01c2a017 --- /dev/null +++ b/src/views/layouts/PageLayout.tsx @@ -0,0 +1,11 @@ +import { FooterView } from "@/components/layout/Footer"; +import { Navigation } from "@/components/layout/Navigation"; + +export function PageLayout(props: { children: React.ReactNode }) { + return ( + + + {props.children} + + ); +} diff --git a/src/views/media/MediaView.tsx b/src/views/media/MediaView.tsx index ada4f9f8..060340fe 100644 --- a/src/views/media/MediaView.tsx +++ b/src/views/media/MediaView.tsx @@ -24,10 +24,11 @@ import { SourceController } from "@/video/components/controllers/SourceControlle import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; import { VideoPlayer } from "@/video/components/VideoPlayer"; import { VideoPlayerMeta } from "@/video/state/types"; +import { ErrorWrapperPart } from "@/views/parts/errors/ErrorWrapperPart"; +import { MediaNotFoundPart } from "@/views/parts/errors/MediaNotFoundPart"; import { MediaFetchErrorView } from "./MediaErrorView"; import { MediaScrapeLog } from "./MediaScrapeLog"; -import { NotFoundMedia, NotFoundWrapper } from "../notfound/NotFoundView"; function MediaViewLoading(props: { onGoBack(): void }) { const { t } = useTranslation(); @@ -241,9 +242,9 @@ export function MediaView() { if (error) return ; if (!meta || !selected) return ( - - - + + + ); // scraping view will start scraping and return with onStream diff --git a/src/views/notfound/NotFoundView.tsx b/src/views/notfound/NotFoundView.tsx deleted file mode 100644 index 21ba4c63..00000000 --- a/src/views/notfound/NotFoundView.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { ReactNode } from "react"; -import { Helmet } from "react-helmet"; -import { useTranslation } from "react-i18next"; - -import { IconPatch } from "@/components/buttons/IconPatch"; -import { Icons } from "@/components/Icon"; -import { Navigation } from "@/components/layout/Navigation"; -import { ArrowLink } from "@/components/text/ArrowLink"; -import { Title } from "@/components/text/Title"; -import { useGoBack } from "@/hooks/useGoBack"; -import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; - -export function NotFoundWrapper(props: { - children?: ReactNode; - video?: boolean; -}) { - const { t } = useTranslation(); - const goBack = useGoBack(); - - return ( -
- - {t("notFound.genericTitle")} - - {props.video ? ( -
- -
- ) : ( - - )} -
- {props.children} -
-
- ); -} - -export function NotFoundMedia() { - const { t } = useTranslation(); - - return ( -
- - {t("notFound.media.title")} -

{t("notFound.media.description")}

- -
- ); -} - -export function NotFoundProvider() { - const { t } = useTranslation(); - - return ( -
- - {t("notFound.provider.title")} -

- {t("notFound.provider.description")} -

- -
- ); -} - -export function NotFoundPage() { - const { t } = useTranslation(); - - return ( - - - {t("notFound.page.title")} -

{t("notFound.page.description")}

- -
- ); -} diff --git a/src/views/parts/errors/ErrorWrapperPart.tsx b/src/views/parts/errors/ErrorWrapperPart.tsx new file mode 100644 index 00000000..2272cc9f --- /dev/null +++ b/src/views/parts/errors/ErrorWrapperPart.tsx @@ -0,0 +1,33 @@ +import { ReactNode } from "react"; +import { Helmet } from "react-helmet"; +import { useTranslation } from "react-i18next"; + +import { Navigation } from "@/components/layout/Navigation"; +import { useGoBack } from "@/hooks/useGoBack"; +import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; + +export function ErrorWrapperPart(props: { + children?: ReactNode; + video?: boolean; +}) { + const { t } = useTranslation(); + const goBack = useGoBack(); + + return ( +
+ + {t("notFound.genericTitle")} + + {props.video ? ( +
+ +
+ ) : ( + + )} +
+ {props.children} +
+
+ ); +} diff --git a/src/views/parts/errors/MediaNotFoundPart.tsx b/src/views/parts/errors/MediaNotFoundPart.tsx new file mode 100644 index 00000000..9fcf24e6 --- /dev/null +++ b/src/views/parts/errors/MediaNotFoundPart.tsx @@ -0,0 +1,22 @@ +import { useTranslation } from "react-i18next"; + +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { ArrowLink } from "@/components/text/ArrowLink"; +import { Title } from "@/components/text/Title"; + +export function MediaNotFoundPart() { + const { t } = useTranslation(); + + return ( +
+ + {t("notFound.media.title")} +

{t("notFound.media.description")}

+ +
+ ); +} diff --git a/src/views/parts/errors/ProviderNotFoundPart.tsx b/src/views/parts/errors/ProviderNotFoundPart.tsx new file mode 100644 index 00000000..1cc58794 --- /dev/null +++ b/src/views/parts/errors/ProviderNotFoundPart.tsx @@ -0,0 +1,24 @@ +import { useTranslation } from "react-i18next"; + +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { ArrowLink } from "@/components/text/ArrowLink"; +import { Title } from "@/components/text/Title"; + +export function ProviderNotFoundPart() { + const { t } = useTranslation(); + + return ( +
+ + {t("notFound.provider.title")} +

+ {t("notFound.provider.description")} +

+ +
+ ); +} diff --git a/src/views/parts/home/HeroPart.tsx b/src/views/parts/home/HeroPart.tsx new file mode 100644 index 00000000..6e924957 --- /dev/null +++ b/src/views/parts/home/HeroPart.tsx @@ -0,0 +1,55 @@ +import { useCallback, useState } from "react"; +import { useTranslation } from "react-i18next"; +import Sticky from "react-stickynode"; + +import { ThinContainer } from "@/components/layout/ThinContainer"; +import { SearchBarInput } from "@/components/SearchBar"; +import { Title } from "@/components/text/Title"; +import { useBannerSize } from "@/hooks/useBanner"; +import { useSearchQuery } from "@/hooks/useSearchQuery"; + +export interface HeroPartProps { + setIsSticky: (val: boolean) => void; + searchParams: ReturnType; +} + +export function HeroPart({ setIsSticky, searchParams }: HeroPartProps) { + const { t } = useTranslation(); + const [search, setSearch, setSearchUnFocus] = searchParams; + const [, setShowBg] = useState(false); + const bannerSize = useBannerSize(); + const stickStateChanged = useCallback( + ({ status }: Sticky.Status) => { + const val = status === Sticky.STATUS_FIXED; + setShowBg(val); + setIsSticky(val); + }, + [setShowBg, setIsSticky] + ); + + return ( + +
+
+ {t("search.title")} +
+
+ + + +
+
+
+ ); +} diff --git a/src/views/parts/home/WatchingPart.tsx b/src/views/parts/home/WatchingPart.tsx index c9281dd5..be222398 100644 --- a/src/views/parts/home/WatchingPart.tsx +++ b/src/views/parts/home/WatchingPart.tsx @@ -2,13 +2,18 @@ import { useAutoAnimate } from "@formkit/auto-animate/react"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { EditButton } from "@/components/buttons/EditButton"; +import { Icons } from "@/components/Icon"; +import { SectionHeading } from "@/components/layout/SectionHeading"; +import { MediaGrid } from "@/components/media/MediaGrid"; +import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { getIfBookmarkedFromPortable, useBookmarkContext, } from "@/state/bookmark"; import { useWatchedContext } from "@/state/watched"; -function Watched() { +export function WatchingPart() { const { t } = useTranslation(); const { getFilteredBookmarks } = useBookmarkContext(); const { getFilteredWatched, removeProgress } = useWatchedContext(); diff --git a/src/views/parts/search/SearchListPart.tsx b/src/views/parts/search/SearchListPart.tsx new file mode 100644 index 00000000..7e0db1e6 --- /dev/null +++ b/src/views/parts/search/SearchListPart.tsx @@ -0,0 +1,88 @@ +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import { searchForMedia } from "@/backend/metadata/search"; +import { MWMediaMeta, MWQuery } from "@/backend/metadata/types/mw"; +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { SectionHeading } from "@/components/layout/SectionHeading"; +import { MediaGrid } from "@/components/media/MediaGrid"; +import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; +import { useLoading } from "@/hooks/useLoading"; +import { SearchLoadingPart } from "@/views/parts/search/SearchLoadingPart"; + +function SearchSuffix(props: { failed?: boolean; results?: number }) { + const { t } = useTranslation(); + + const icon: Icons = props.failed ? Icons.WARNING : Icons.EYE_SLASH; + + return ( +
+ + + {/* standard suffix */} + {!props.failed ? ( +
+ {(props.results ?? 0) > 0 ? ( +

{t("search.allResults")}

+ ) : ( +

{t("search.noResults")}

+ )} +
+ ) : null} + + {/* Error result */} + {props.failed ? ( +
+

{t("search.allFailed")}

+
+ ) : null} +
+ ); +} + +export function SearchListPart({ searchQuery }: { searchQuery: MWQuery }) { + const { t } = useTranslation(); + + const [results, setResults] = useState([]); + const [runSearchQuery, loading, error] = useLoading((query: MWQuery) => + searchForMedia(query) + ); + + useEffect(() => { + async function runSearch(query: MWQuery) { + const searchResults = await runSearchQuery(query); + if (!searchResults) return; + setResults(searchResults); + } + + if (searchQuery.searchQuery !== "") runSearch(searchQuery); + }, [searchQuery, runSearchQuery]); + + if (loading) return ; + if (error) return ; + if (!results) return null; + + return ( +
+ {results.length > 0 ? ( +
+ + + {results.map((v) => ( + + ))} + +
+ ) : null} + + +
+ ); +} diff --git a/src/views/search/SearchLoadingView.tsx b/src/views/parts/search/SearchLoadingPart.tsx similarity index 86% rename from src/views/search/SearchLoadingView.tsx rename to src/views/parts/search/SearchLoadingPart.tsx index 0c59f5d9..bce56db1 100644 --- a/src/views/search/SearchLoadingView.tsx +++ b/src/views/parts/search/SearchLoadingPart.tsx @@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next"; import { Loading } from "@/components/layout/Loading"; -export function SearchLoadingView() { +export function SearchLoadingPart() { const { t } = useTranslation(); return ( diff --git a/src/views/search/HomeView.tsx b/src/views/search/HomeView.tsx deleted file mode 100644 index 5c80eff1..00000000 --- a/src/views/search/HomeView.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { useAutoAnimate } from "@formkit/auto-animate/react"; -import { useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import { EditButton } from "@/components/buttons/EditButton"; -import { Icons } from "@/components/Icon"; -import { SectionHeading } from "@/components/layout/SectionHeading"; -import { MediaGrid } from "@/components/media/MediaGrid"; -import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; -import { - getIfBookmarkedFromPortable, - useBookmarkContext, -} from "@/state/bookmark"; -import { useWatchedContext } from "@/state/watched"; - -function Bookmarks() { - const { t } = useTranslation(); - const { getFilteredBookmarks, setItemBookmark } = useBookmarkContext(); - const bookmarks = getFilteredBookmarks(); - const [editing, setEditing] = useState(false); - const [gridRef] = useAutoAnimate(); - const { watched } = useWatchedContext(); - - const bookmarksSorted = useMemo(() => { - return bookmarks - .map((v) => { - return { - ...v, - watched: watched.items - .sort((a, b) => b.watchedAt - a.watchedAt) - .find((watchedItem) => watchedItem.item.meta.id === v.id), - }; - }) - .sort( - (a, b) => (b.watched?.watchedAt || 0) - (a.watched?.watchedAt || 0) - ); - }, [watched.items, bookmarks]); - - if (bookmarks.length === 0) return null; - - return ( -
- - - - - {bookmarksSorted.map((v) => ( - setItemBookmark(v, false)} - /> - ))} - -
- ); -} - -function Watched() { - const { t } = useTranslation(); - const { getFilteredBookmarks } = useBookmarkContext(); - const { getFilteredWatched, removeProgress } = useWatchedContext(); - const [editing, setEditing] = useState(false); - const [gridRef] = useAutoAnimate(); - - const bookmarks = getFilteredBookmarks(); - const watchedItems = getFilteredWatched().filter( - (v) => !getIfBookmarkedFromPortable(bookmarks, v.item.meta) - ); - - if (watchedItems.length === 0) return null; - - return ( -
- - - - - {watchedItems.map((v) => ( - removeProgress(v.item.meta.id)} - /> - ))} - -
- ); -} - -export function HomeView() { - return ( -
- - -
- ); -} diff --git a/src/views/search/SearchResultsPartial.tsx b/src/views/search/SearchResultsPartial.tsx deleted file mode 100644 index e7cfc509..00000000 --- a/src/views/search/SearchResultsPartial.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect, useMemo, useState } from "react"; - -import { MWQuery } from "@/backend/metadata/types/mw"; -import { useDebounce } from "@/hooks/useDebounce"; - -import { HomeView } from "./HomeView"; -import { SearchLoadingView } from "./SearchLoadingView"; -import { SearchResultsView } from "./SearchResultsView"; - -interface SearchResultsPartialProps { - search: MWQuery; -} - -export function SearchResultsPartial({ search }: SearchResultsPartialProps) { - const [searching, setSearching] = useState(false); - const [loading, setLoading] = useState(false); - - const debouncedSearch = useDebounce(search, 500); - useEffect(() => { - setSearching(search.searchQuery !== ""); - setLoading(search.searchQuery !== ""); - }, [search]); - useEffect(() => { - setLoading(false); - }, [debouncedSearch]); - - const resultView = useMemo(() => { - if (loading) return ; - if (searching) return ; - return ; - }, [loading, searching, debouncedSearch]); - - return resultView; -} diff --git a/src/views/search/SearchView.tsx b/src/views/search/SearchView.tsx deleted file mode 100644 index 17df6663..00000000 --- a/src/views/search/SearchView.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { useCallback, useState } from "react"; -import { Helmet } from "react-helmet"; -import { useTranslation } from "react-i18next"; -import Sticky from "react-stickynode"; - -import { FooterView } from "@/components/layout/Footer"; -import { Navigation } from "@/components/layout/Navigation"; -import { ThinContainer } from "@/components/layout/ThinContainer"; -import { WideContainer } from "@/components/layout/WideContainer"; -import { SearchBarInput } from "@/components/SearchBar"; -import { Title } from "@/components/text/Title"; -import { useBannerSize } from "@/hooks/useBanner"; -import { useSearchQuery } from "@/hooks/useSearchQuery"; - -import { SearchResultsPartial } from "./SearchResultsPartial"; - -export function SearchView() { - const { t } = useTranslation(); - const [search, setSearch, setSearchUnFocus] = useSearchQuery(); - const [showBg, setShowBg] = useState(false); - const bannerSize = useBannerSize(); - - const stickStateChanged = useCallback( - ({ status }: Sticky.Status) => setShowBg(status === Sticky.STATUS_FIXED), - [setShowBg] - ); - - return ( - - -
- - {t("global.name")} - - -
-
- {t("search.title")} -
-
- - - -
-
-
-
- - - -
- ); -}