diff --git a/front/packages/models/src/login.ts b/front/packages/models/src/login.ts index eef923b1..5ee3c104 100644 --- a/front/packages/models/src/login.ts +++ b/front/packages/models/src/login.ts @@ -24,6 +24,7 @@ import { zdate } from "./utils"; import { queryFn } from "./query"; import { KyooErrors } from "./kyoo-errors"; import { Platform } from "react-native"; +import { useEffect, useState } from "react"; const TokenP = z.object({ token_type: z.literal("Bearer"), @@ -38,8 +39,21 @@ type Result = | { ok: true; value: A; error?: undefined } | { ok: false; value?: undefined; error: B }; -export type Account = Token & { apiUrl: string; username: string | null }; +export type Account = Token & { apiUrl: string; username: string }; +export const useAccounts = () => { + const [accounts, setAccounts] = useState([]); + const [selected, setSelected] = useState(0); + + useEffect(() => { + async function run() { + setAccounts(JSON.parse(await getSecureItem("accounts") ?? "[]")); + } + + run(); + }, []); + return {accounts, selected, setSelected}; +} const addAccount = async (token: Token, apiUrl: string, username: string | null): Promise => { const accounts: Account[] = JSON.parse(await getSecureItem("accounts") ?? "[]"); diff --git a/front/packages/primitives/src/avatar.tsx b/front/packages/primitives/src/avatar.tsx index c73a6638..502ae5c2 100644 --- a/front/packages/primitives/src/avatar.tsx +++ b/front/packages/primitives/src/avatar.tsx @@ -72,7 +72,8 @@ export const Avatar = forwardRef< [ { borderRadius: 999999, - p: ts(1), + height: size, + width: size, }, fill && { bg: col, @@ -92,8 +93,6 @@ export const Avatar = forwardRef<

({ const MenuItem = ({ label, selected, + left, onSelect, href, icon, @@ -121,12 +122,15 @@ const MenuItem = ({ }: { label: string; selected?: boolean; + left?: ReactElement; icon?: ComponentType; } & ({ onSelect: () => void; href?: undefined } | { href: string; onSelect?: undefined })) => { const { css, theme } = useYoshiki(); const setOpen = useContext(MenuContext); const router = useRouter(); + const icn = (icon || selected) && ; + return ( { @@ -145,8 +149,10 @@ const MenuItem = ({ props as any, )} > - {(icon || selected) && } -

{label}

+ {left && left} + {!left && icn && icn} +

{label}

+ {left && icn && icn} ); }; diff --git a/front/packages/primitives/src/menu.web.tsx b/front/packages/primitives/src/menu.web.tsx index b9ab0244..f4bd61d2 100644 --- a/front/packages/primitives/src/menu.web.tsx +++ b/front/packages/primitives/src/menu.web.tsx @@ -19,7 +19,7 @@ */ import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; -import { ComponentProps, ComponentType, forwardRef, ReactNode } from "react"; +import { ComponentProps, ComponentType, forwardRef, ReactElement, ReactNode } from "react"; import Link from "next/link"; import { PressableProps } from "react-native"; import { useYoshiki } from "yoshiki/web"; @@ -119,6 +119,7 @@ const Item = forwardRef< const MenuItem = ({ label, icon, + left, selected, onSelect, href, @@ -126,6 +127,7 @@ const MenuItem = ({ }: { label: string; icon?: ComponentType; + left?: ReactElement; selected?: boolean; } & ({ onSelect: () => void; href?: undefined } | { href: string; onSelect?: undefined })) => { const { css: nCss } = useNativeYoshiki(); @@ -152,6 +154,7 @@ const MenuItem = ({ props as any, )} > + {left && left} {(icon || selected) && ( )} - {

{label}

} + {

{label}

} ); diff --git a/front/packages/ui/src/navbar/index.tsx b/front/packages/ui/src/navbar/index.tsx index 99c4ac06..bc5fc8ab 100644 --- a/front/packages/ui/src/navbar/index.tsx +++ b/front/packages/ui/src/navbar/index.tsx @@ -26,6 +26,7 @@ import { Page, Paged, QueryIdentifier, + useAccounts, User, UserP, } from "@kyoo/models"; @@ -41,6 +42,7 @@ import { ts, Menu, PressableFeedback, + HR, } from "@kyoo/primitives"; import { Platform, TextInput, View, ViewProps } from "react-native"; import { useTranslation } from "react-i18next"; @@ -49,6 +51,8 @@ import { useRouter } from "solito/router"; import { px, rem, Stylable, useYoshiki } from "yoshiki/native"; import MenuIcon from "@material-symbols/svg-400/rounded/menu-fill.svg"; import Search from "@material-symbols/svg-400/rounded/search-fill.svg"; +import Login from "@material-symbols/svg-400/rounded/login.svg"; +import Register from "@material-symbols/svg-400/rounded/app_registration.svg"; import Logout from "@material-symbols/svg-400/rounded/logout.svg"; import Delete from "@material-symbols/svg-400/rounded/delete.svg"; import { Fetch, FetchNE } from "../fetch"; @@ -102,10 +106,17 @@ export const MeQuery: QueryIdentifier = { parser: UserP, }; +const getDisplayUrl = (url: string) => { + url = url.replace(/\/api$/, ""); + url = url.replace(/https?:\/\//, ""); + return url; +}; + export const NavbarProfile = () => { const { css, theme } = useYoshiki(); const { t } = useTranslation(); const queryClient = useQueryClient(); + const { accounts, selected, setSelected } = useAccounts(); return ( @@ -120,13 +131,24 @@ export const NavbarProfile = () => { {...css({ marginLeft: ts(1), justifyContent: "center" })} {...tooltip(username ?? t("navbar.login"))} > + {accounts.map((x, i) => ( + } + selected={selected === i} + onSelect={() => setSelected(i)} + /> + ))} + {accounts.length > 0 &&
} {isGuest ? ( <> - - + + ) : ( <> + { onPress={ Platform.OS === "web" ? () => { - setSearch(true); - setTimeout(() => ref.current?.focus(), 0); - } + setSearch(true); + setTimeout(() => ref.current?.focus(), 0); + } : () => push("/search") } {...tooltip(t("navbar.search"))} diff --git a/front/translations/en.json b/front/translations/en.json index dac76964..756d9f78 100644 --- a/front/translations/en.json +++ b/front/translations/en.json @@ -60,6 +60,7 @@ "login": { "login": "Login", "register": "Register", + "add-account": "Add account", "logout": "Logout", "server": "Server Address", "email": "Email", diff --git a/front/translations/fr.json b/front/translations/fr.json index 2310108a..c40929e5 100644 --- a/front/translations/fr.json +++ b/front/translations/fr.json @@ -60,6 +60,7 @@ "login": { "login": "Connexion", "register": "Créer un compte", + "add-account": "Ajouter un compte", "logout": "Déconnexion", "server": "Addresse du serveur", "email": "Email",