/* * Kyoo - A portable and vast media library solution. * Copyright (c) Kyoo. * * See AUTHORS.md and LICENSE file in the project root for full license information. * * Kyoo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Kyoo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kyoo. If not, see . */ import { Library, LibraryP, Page, Paged, QueryIdentifier } from "@kyoo/models"; import { Input, IconButton, Header, Avatar, A, Skeleton, tooltip, ts, Link, } from "@kyoo/primitives"; import { Platform, TextInput, View } from "react-native"; import { useTranslation } from "react-i18next"; import { createParam } from "solito"; import { useRouter } from "solito/router"; import { rem, Stylable, useTheme, useYoshiki } from "yoshiki/native"; import Menu from "@material-symbols/svg-400/rounded/menu-fill.svg"; import Search from "@material-symbols/svg-400/rounded/search-fill.svg"; import { Fetch } from "../fetch"; import { KyooLongLogo } from "./icon"; import { forwardRef, useRef, useState } from "react"; export const NavbarTitle = (props: Stylable) => { const { t } = useTranslation(); return ( ); }; const { useParam } = createParam<{ q?: string }>(); const SearchBar = forwardRef< TextInput, { onBlur?: (value: string | undefined) => void } & Stylable >(function _SearchBar({ onBlur, ...props }, ref) { const { css, theme } = useYoshiki(); const { t } = useTranslation(); const { push, replace, back } = useRouter(); const [query] = useParam("q"); return ( { if (Platform.OS === "web") { const action = window.location.pathname.startsWith("/search") ? replace : push; if (q) action(`/search?q=${q}`, undefined, { shallow: true }); else back(); } }} placeholder={t("navbar.search")} placeholderTextColor={theme.light.overlay0} {...tooltip(t("navbar.search"))} {...css({ borderColor: (theme) => theme.colors.white }, props)} /> ); }); export const NavbarProfile = () => { const { css, theme } = useYoshiki(); const { t } = useTranslation(); return ( ); }; export const NavbarRight = () => { const { css } = useYoshiki(); const { t } = useTranslation(); const [isSearching, setSearch] = useState(false); const ref = useRef(null); const [query] = useParam("q"); const { push } = useRouter(); const searchExpanded = isSearching || query; return ( {Platform.OS === "web" && ( { if (!q) setSearch(false); }} {...css({ display: { xs: searchExpanded ? "flex" : "none", md: "flex" }, })} /> )} {!searchExpanded && ( { setSearch(true); setTimeout(() => ref.current?.focus(), 0); } : () => push("/search") } {...tooltip(t("navbar.search"))} {...css(Platform.OS === "web" && { display: { xs: "flex", md: "none" } })} /> )} ); }; export const Navbar = (props: Stylable) => { const { css, theme } = useYoshiki(); return (
theme.appbar, paddingX: ts(2), height: { xs: 48, sm: 64 }, flexDirection: "row", justifyContent: { xs: "space-between", sm: "flex-start" }, alignItems: "center", shadowColor: "#000", shadowOffset: { width: 0, height: 4, }, shadowOpacity: 0.3, shadowRadius: 4.65, elevation: 8, zIndex: 1, }, props, )} > {(library, i) => !library.isLoading ? ( {library.name} ) : ( ) }
); }; Navbar.query = (): QueryIdentifier> => ({ parser: Paged(LibraryP), path: ["libraries"], });