mirror of
https://github.com/zoriya/Kyoo.git
synced 2026-02-20 10:10:08 -05:00
Make native web tabbar
This commit is contained in:
parent
2f5423073e
commit
637505dde9
@ -1,14 +1,21 @@
|
||||
import Browse from "@material-symbols/svg-400/rounded/browse-fill.svg";
|
||||
// import Downloading from "@material-symbols/svg-400/rounded/downloading-fill.svg";
|
||||
import Home from "@material-symbols/svg-400/rounded/home-fill.svg";
|
||||
import { Tabs } from "expo-router";
|
||||
import { Slot, Tabs } from "expo-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform } from "react-native";
|
||||
import { Icon } from "~/primitives";
|
||||
import { cn } from "~/utils";
|
||||
|
||||
export const unstable_settings = {
|
||||
initialRouteName: "index",
|
||||
};
|
||||
|
||||
export default function TabsLayout() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (Platform.OS === "web") return <Slot />;
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import { Stack } from "expo-router";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { useCSSVariable, useResolveClassNames } from "uniwind";
|
||||
import { NavbarRight, NavbarTitle } from "~/ui/navbar";
|
||||
import { NavbarLeft, NavbarRight } from "~/ui/navbar";
|
||||
|
||||
export { ErrorBoundary } from "~/ui/error-bondary";
|
||||
|
||||
export const unstable_settings = {
|
||||
initialRouteName: "(tabs)",
|
||||
};
|
||||
|
||||
export default function Layout() {
|
||||
const insets = useSafeAreaInsets();
|
||||
const accent = useCSSVariable("--color-accent");
|
||||
@ -13,7 +17,7 @@ export default function Layout() {
|
||||
return (
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerTitle: () => <NavbarTitle />,
|
||||
headerTitle: () => <NavbarLeft />,
|
||||
headerRight: () => <NavbarRight />,
|
||||
contentStyle: {
|
||||
paddingLeft: insets.left,
|
||||
|
||||
@ -6,6 +6,10 @@ import "../global.css";
|
||||
import { Tooltip, useMobileHover } from "~/primitives";
|
||||
import "~/fonts.web.css";
|
||||
|
||||
export const unstable_settings = {
|
||||
initialRouteName: "(app)",
|
||||
};
|
||||
|
||||
export default function Layout() {
|
||||
useMobileHover();
|
||||
|
||||
|
||||
@ -5,11 +5,11 @@ import {
|
||||
Platform,
|
||||
Pressable,
|
||||
type PressableProps,
|
||||
Text,
|
||||
type TextProps,
|
||||
} from "react-native";
|
||||
import { useResolveClassNames } from "uniwind";
|
||||
import { cn } from "~/utils";
|
||||
import { P } from "./text";
|
||||
|
||||
export function useLinkTo({
|
||||
href,
|
||||
@ -57,7 +57,7 @@ export const A = ({
|
||||
const linkProps = useLinkTo({ href, replace });
|
||||
|
||||
return (
|
||||
<Text
|
||||
<P
|
||||
{...linkProps}
|
||||
className={cn(
|
||||
"select-text text-accent hover:underline focus:underline",
|
||||
@ -66,7 +66,7 @@ export const A = ({
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
</P>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -45,6 +45,24 @@ import { useAccount, useAccounts } from "~/providers/account-context";
|
||||
import { logout } from "~/ui/login/logic";
|
||||
import { cn } from "~/utils";
|
||||
|
||||
export const NavbarLeft = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (Platform.OS !== "web") return <NavbarTitle />;
|
||||
|
||||
return (
|
||||
<View className="flex-row items-center gap-2">
|
||||
<NavbarTitle />
|
||||
<A
|
||||
href="/browse"
|
||||
className="font-headers text-lg text-slate-200 uppercase dark:text-slate-200"
|
||||
>
|
||||
{t("navbar.browse")}
|
||||
</A>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export const NavbarTitle = ({
|
||||
className,
|
||||
...props
|
||||
@ -64,68 +82,24 @@ export const NavbarTitle = ({
|
||||
);
|
||||
};
|
||||
|
||||
const getDisplayUrl = (url: string) => {
|
||||
url = url.replace(/\/api$/, "");
|
||||
url = url.replace(/https?:\/\//, "");
|
||||
return url;
|
||||
};
|
||||
|
||||
export const NavbarProfile = () => {
|
||||
export const NavbarRight = () => {
|
||||
const { t } = useTranslation();
|
||||
const account = useAccount();
|
||||
const accounts = useAccounts();
|
||||
const isAdmin = false; //useHasPermission(AdminPage.requiredPermissions);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
Trigger={Avatar<PressableProps>}
|
||||
as={PressableFeedback}
|
||||
src={account?.logo}
|
||||
placeholder={account?.username}
|
||||
alt={t("navbar.login")}
|
||||
className="m-2"
|
||||
{...tooltip(account?.username ?? t("navbar.login"))}
|
||||
>
|
||||
{accounts?.map((x) => (
|
||||
<Menu.Item
|
||||
key={x.id}
|
||||
label={
|
||||
Platform.OS === "web"
|
||||
? x.username
|
||||
: `${x.username} - ${getDisplayUrl(x.apiUrl)}`
|
||||
}
|
||||
left={
|
||||
<Avatar placeholder={x.username} src={x.logo} className="mx-2" />
|
||||
}
|
||||
selected={x.selected}
|
||||
onSelect={() => x.select()}
|
||||
<View className="shrink flex-row items-center">
|
||||
<SearchBar />
|
||||
{isAdmin && (
|
||||
<IconButton
|
||||
icon={Admin}
|
||||
as={Link}
|
||||
href={"/admin"}
|
||||
iconClassName="fill-slate-200 dark:fill-slate-200"
|
||||
{...tooltip(t("navbar.admin"))}
|
||||
/>
|
||||
))}
|
||||
{accounts.length > 0 && <HR />}
|
||||
<Menu.Item label={t("misc.settings")} icon={Settings} href="/settings" />
|
||||
{!account ? (
|
||||
<>
|
||||
<Menu.Item label={t("login.login")} icon={Login} href="/login" />
|
||||
<Menu.Item
|
||||
label={t("login.register")}
|
||||
icon={Register}
|
||||
href="/register"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Menu.Item
|
||||
label={t("login.add-account")}
|
||||
icon={Login}
|
||||
href="/login"
|
||||
/>
|
||||
<Menu.Item
|
||||
label={t("login.logout")}
|
||||
icon={Logout}
|
||||
onSelect={logout}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Menu>
|
||||
<NavbarProfile />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@ -217,24 +191,68 @@ const SearchBar = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const NavbarRight = () => {
|
||||
const getDisplayUrl = (url: string) => {
|
||||
url = url.replace(/\/api$/, "");
|
||||
url = url.replace(/https?:\/\//, "");
|
||||
return url;
|
||||
};
|
||||
|
||||
export const NavbarProfile = () => {
|
||||
const { t } = useTranslation();
|
||||
const isAdmin = false; //useHasPermission(AdminPage.requiredPermissions);
|
||||
const account = useAccount();
|
||||
const accounts = useAccounts();
|
||||
|
||||
return (
|
||||
<View className="shrink flex-row items-center">
|
||||
<SearchBar />
|
||||
{isAdmin && (
|
||||
<IconButton
|
||||
icon={Admin}
|
||||
as={Link}
|
||||
href={"/admin"}
|
||||
iconClassName="fill-slate-200 dark:fill-slate-200"
|
||||
{...tooltip(t("navbar.admin"))}
|
||||
<Menu
|
||||
Trigger={Avatar<PressableProps>}
|
||||
as={PressableFeedback}
|
||||
src={account?.logo}
|
||||
placeholder={account?.username}
|
||||
alt={t("navbar.login")}
|
||||
className="m-2"
|
||||
{...tooltip(account?.username ?? t("navbar.login"))}
|
||||
>
|
||||
{accounts?.map((x) => (
|
||||
<Menu.Item
|
||||
key={x.id}
|
||||
label={
|
||||
Platform.OS === "web"
|
||||
? x.username
|
||||
: `${x.username} - ${getDisplayUrl(x.apiUrl)}`
|
||||
}
|
||||
left={
|
||||
<Avatar placeholder={x.username} src={x.logo} className="mx-2" />
|
||||
}
|
||||
selected={x.selected}
|
||||
onSelect={() => x.select()}
|
||||
/>
|
||||
))}
|
||||
{accounts.length > 0 && <HR />}
|
||||
<Menu.Item label={t("misc.settings")} icon={Settings} href="/settings" />
|
||||
{!account ? (
|
||||
<>
|
||||
<Menu.Item label={t("login.login")} icon={Login} href="/login" />
|
||||
<Menu.Item
|
||||
label={t("login.register")}
|
||||
icon={Register}
|
||||
href="/register"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Menu.Item
|
||||
label={t("login.add-account")}
|
||||
icon={Login}
|
||||
href="/login"
|
||||
/>
|
||||
<Menu.Item
|
||||
label={t("login.logout")}
|
||||
icon={Logout}
|
||||
onSelect={logout}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<NavbarProfile />
|
||||
</View>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user