mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
wip: Rewrite router
This commit is contained in:
parent
d953e9e769
commit
cb65325c56
@ -22,7 +22,7 @@ import { SearchPage } from "@kyoo/ui";
|
||||
import { Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { createParam } from "solito";
|
||||
import { useRouter } from "solito/router";
|
||||
import { useRouter } from "@kyoo/primitives";
|
||||
import { useTheme } from "yoshiki/native";
|
||||
|
||||
const { useParam } = createParam<{ q?: string }>();
|
||||
|
@ -54,8 +54,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/html-elements": "^0.9.1",
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"solito": "^4.2.0"
|
||||
"@tanstack/react-query": "^5.17.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@radix-ui/react-select": "^2.0.0",
|
||||
|
@ -42,3 +42,4 @@ export * from "./chip";
|
||||
|
||||
export * from "./utils";
|
||||
export * from "./constants";
|
||||
export * from "./navigation/router";
|
||||
|
@ -18,19 +18,10 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type { UrlObject } from "node:url";
|
||||
import { type ReactNode, forwardRef } from "react";
|
||||
import {
|
||||
Linking,
|
||||
Platform,
|
||||
Pressable,
|
||||
type PressableProps,
|
||||
type TextProps,
|
||||
type View,
|
||||
} from "react-native";
|
||||
import { TextLink, useLink } from "solito/link";
|
||||
import { parseNextPath } from "solito/router";
|
||||
import { forwardRef, type ReactNode } from "react";
|
||||
import { Platform, Pressable, type TextProps, type View, type PressableProps } from "react-native";
|
||||
import { useTheme, useYoshiki } from "yoshiki/native";
|
||||
import type { UrlObject } from "node:url";
|
||||
import { alpha } from "./themes";
|
||||
|
||||
export const A = ({
|
||||
@ -122,9 +113,7 @@ export const Link = ({
|
||||
{...props}
|
||||
onPress={(e?: any) => {
|
||||
props?.onPress?.(e);
|
||||
if (e?.defaultPrevented) return;
|
||||
if (Platform.OS !== "web" && href?.includes("://")) Linking.openURL(href);
|
||||
else linkProps.onPress(e);
|
||||
linkProps.onPress(e);
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
@ -39,6 +39,7 @@ import { useRouter } from "solito/router";
|
||||
import { percent, px, sm, useYoshiki, vh, xl } from "yoshiki/native";
|
||||
import { Icon, IconButton } from "./icons";
|
||||
import { PressableFeedback } from "./links";
|
||||
import { useRouter } from "./navigation/router";
|
||||
import { P } from "./text";
|
||||
import { ContrastArea, SwitchVariant } from "./themes";
|
||||
import { ts } from "./utils";
|
||||
|
44
front/packages/primitives/src/navigation/link.ts
Normal file
44
front/packages/primitives/src/navigation/link.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { type UrlObject, format } from "node:url";
|
||||
import type { MouseEvent } from "react";
|
||||
import { Platform, type PressableProps, Linking } from "react-native";
|
||||
import { useRouter } from "./router";
|
||||
|
||||
export const useLink = (
|
||||
route: string | UrlObject,
|
||||
opts: { replace?: boolean; target?: "_blank"; isNested?: boolean } = {},
|
||||
) => {
|
||||
const router = useRouter();
|
||||
const href = typeof route === "object" ? format(route) : route;
|
||||
|
||||
return {
|
||||
accessibilityRole: "link",
|
||||
href,
|
||||
onPress: (e) => {
|
||||
if (e?.defaultPrevented) return;
|
||||
if (Platform.OS !== "web" && href.includes("://")) {
|
||||
Linking.openURL(href);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Platform.OS === "web" && e) {
|
||||
// Web event
|
||||
const we = e as unknown as MouseEvent;
|
||||
if (
|
||||
// ignore clicks with modifier keys
|
||||
we.metaKey ||
|
||||
we.altKey ||
|
||||
we.ctrlKey ||
|
||||
we.shiftKey ||
|
||||
// ignore everything but left clicks
|
||||
we.button !== null ||
|
||||
we.button !== 0
|
||||
)
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
if (opts.replace === true) router.replace(href, { isNested: opts.isNested });
|
||||
else router.push(href);
|
||||
},
|
||||
} satisfies PressableProps & { href?: string };
|
||||
};
|
18
front/packages/primitives/src/navigation/router.ts
Normal file
18
front/packages/primitives/src/navigation/router.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { navigate } from "vike/client/router";
|
||||
import { type UrlObject, format } from "node:url";
|
||||
|
||||
export const useRouter = () => {
|
||||
return {
|
||||
push: (route: string | UrlObject) => {
|
||||
if (typeof route === "object") route = format(route);
|
||||
navigate(route);
|
||||
},
|
||||
replace: (route: string | UrlObject, opts: {isNested?: boolean} = {}) => {
|
||||
if (typeof route === "object") route = format(route);
|
||||
navigate(route, { overwriteLastHistoryEntry: opts.isNested });
|
||||
},
|
||||
back: () => {
|
||||
window.history.back();
|
||||
},
|
||||
};
|
||||
};
|
18
front/packages/primitives/src/navigation/router.web.ts
Normal file
18
front/packages/primitives/src/navigation/router.web.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { navigate } from "vike/client/router";
|
||||
import { type UrlObject, format } from "node:url";
|
||||
|
||||
export const useRouter = () => {
|
||||
return {
|
||||
push: (route: string | UrlObject) => {
|
||||
if (typeof route === "object") route = format(route);
|
||||
navigate(route);
|
||||
},
|
||||
replace: (route: string | UrlObject, isNested = true) => {
|
||||
if (typeof route === "object") route = format(route);
|
||||
navigate(route, { overwriteLastHistoryEntry: true });
|
||||
},
|
||||
back: () => {
|
||||
window.history.back();
|
||||
},
|
||||
};
|
||||
};
|
@ -44,10 +44,7 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({
|
||||
const { css } = useYoshiki();
|
||||
|
||||
useEffect(() => {
|
||||
if (!apiUrl && Platform.OS !== "web")
|
||||
router.replace("/server-url", undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
|
||||
});
|
||||
if (!apiUrl && Platform.OS !== "web") router.replace("/server-url", false);
|
||||
}, [apiUrl, router]);
|
||||
|
||||
return (
|
||||
@ -73,9 +70,7 @@ export const LoginPage: QueryPage<{ apiUrl?: string; error?: string }> = ({
|
||||
});
|
||||
setError(error);
|
||||
if (error) return;
|
||||
router.replace("/", undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
|
||||
});
|
||||
router.replace("/", false);
|
||||
}}
|
||||
{...css({
|
||||
m: ts(1),
|
||||
|
@ -26,12 +26,11 @@ import {
|
||||
oidcLogin,
|
||||
useFetch,
|
||||
} from "@kyoo/models";
|
||||
import { Button, HR, Link, P, Skeleton, ts } from "@kyoo/primitives";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ImageBackground, View } from "react-native";
|
||||
import { useRouter } from "solito/router";
|
||||
import { useRouter, Button, HR, Link, P, Skeleton, ts } from "@kyoo/primitives";
|
||||
import { View, ImageBackground } from "react-native";
|
||||
import { percent, rem, useYoshiki } from "yoshiki/native";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { ErrorView } from "../errors";
|
||||
|
||||
export const OidcLogin = ({ apiUrl }: { apiUrl?: string }) => {
|
||||
@ -105,18 +104,12 @@ export const OidcCallbackPage: QueryPage<{
|
||||
hasRun.current = true;
|
||||
|
||||
function onError(error: string) {
|
||||
router.replace({ pathname: "/login", query: { error, apiUrl } }, undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
|
||||
});
|
||||
router.replace({ pathname: "/login", query: { error, apiUrl } }, false);
|
||||
}
|
||||
async function run() {
|
||||
const { error: loginError } = await oidcLogin(provider, code, apiUrl);
|
||||
if (loginError) onError(loginError);
|
||||
else {
|
||||
router.replace("/", undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
|
||||
});
|
||||
}
|
||||
else router.replace("/", false);
|
||||
}
|
||||
|
||||
if (error) onError(error);
|
||||
|
@ -18,13 +18,11 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { type QueryPage, login } from "@kyoo/models";
|
||||
import { A, Button, H1, Input, P, ts } from "@kyoo/primitives";
|
||||
import { login, type QueryPage } from "@kyoo/models";
|
||||
import { Button, P, Input, ts, H1, A, useRouter } from "@kyoo/primitives";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans } from "react-i18next";
|
||||
import { Platform } from "react-native";
|
||||
import { useRouter } from "solito/router";
|
||||
import { percent, px, useYoshiki } from "yoshiki/native";
|
||||
import { DefaultLayout } from "../layout";
|
||||
import { FormPage } from "./form";
|
||||
@ -43,10 +41,7 @@ export const RegisterPage: QueryPage<{ apiUrl?: string }> = ({ apiUrl }) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
useEffect(() => {
|
||||
if (!apiUrl && Platform.OS !== "web")
|
||||
router.replace("/server-url", undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
|
||||
});
|
||||
if (!apiUrl && Platform.OS !== "web") router.replace("/server-url", false);
|
||||
}, [apiUrl, router]);
|
||||
|
||||
return (
|
||||
@ -84,9 +79,7 @@ export const RegisterPage: QueryPage<{ apiUrl?: string }> = ({ apiUrl }) => {
|
||||
const { error } = await login("register", { email, username, password, apiUrl });
|
||||
setError(error);
|
||||
if (error) return;
|
||||
router.replace("/", undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
|
||||
});
|
||||
router.replace("/", false);
|
||||
}}
|
||||
{...css({
|
||||
m: ts(1),
|
||||
|
@ -25,11 +25,10 @@ import {
|
||||
ServerInfoP,
|
||||
useFetch,
|
||||
} from "@kyoo/models";
|
||||
import { Button, H1, HR, Input, Link, P, ts } from "@kyoo/primitives";
|
||||
import { useRouter, Button, P, Link, Input, ts, H1, HR } from "@kyoo/primitives";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ImageBackground, Platform, View } from "react-native";
|
||||
import { useRouter } from "solito/router";
|
||||
import { type Theme, percent, useYoshiki } from "yoshiki/native";
|
||||
import { DefaultLayout } from "../layout";
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type { Audio, Chapter, KyooImage, Subtitle } from "@kyoo/models";
|
||||
import {
|
||||
CircularProgress,
|
||||
ContrastArea,
|
||||
@ -35,15 +34,16 @@ import {
|
||||
tooltip,
|
||||
ts,
|
||||
useIsTouch,
|
||||
useRouter,
|
||||
} from "@kyoo/primitives";
|
||||
import ArrowBack from "@material-symbols/svg-400/rounded/arrow_back-fill.svg";
|
||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { atom } from "jotai";
|
||||
import { type ReactNode, useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { Chapter, KyooImage, Subtitle, Audio } from "@kyoo/models";
|
||||
import { useAtomValue, useSetAtom, useAtom } from "jotai";
|
||||
import { type ImageStyle, Platform, Pressable, View, type ViewProps } from "react-native";
|
||||
import { useRouter } from "solito/router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { percent, rem, useYoshiki } from "yoshiki/native";
|
||||
import ArrowBack from "@material-symbols/svg-400/rounded/arrow_back-fill.svg";
|
||||
import { type ReactNode, useCallback, useEffect, useRef, useState } from "react";
|
||||
import { atom } from "jotai";
|
||||
import {
|
||||
bufferedAtom,
|
||||
durationAtom,
|
||||
|
@ -28,12 +28,11 @@ import {
|
||||
WatchInfoP,
|
||||
useFetch,
|
||||
} from "@kyoo/models";
|
||||
import { Head } from "@kyoo/primitives";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { type ComponentProps, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Head, useRouter } from "@kyoo/primitives";
|
||||
import { useState, useEffect, type ComponentProps } from "react";
|
||||
import { Platform, StyleSheet, View } from "react-native";
|
||||
import { useRouter } from "solito/router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { useYoshiki } from "yoshiki/native";
|
||||
import { episodeDisplayNumber } from "../details/episode";
|
||||
import { ErrorView } from "../errors";
|
||||
@ -159,14 +158,8 @@ export const Player = ({
|
||||
startTime={startTime}
|
||||
onEnd={() => {
|
||||
if (!data) return;
|
||||
if (data.type === "movie")
|
||||
router.replace(`/movie/${data.slug}`, undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true },
|
||||
});
|
||||
else
|
||||
router.replace(next ?? `/show/${data.show!.slug}`, undefined, {
|
||||
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: true },
|
||||
});
|
||||
if (data.type === "movie") router.replace(`/movie/${data.slug}`, true);
|
||||
else router.replace(next ?? `/show/${data.show!.slug}`, true);
|
||||
}}
|
||||
{...css(StyleSheet.absoluteFillObject)}
|
||||
/>
|
||||
|
@ -20,9 +20,9 @@
|
||||
|
||||
import type { Subtitle } from "@kyoo/models";
|
||||
import { atom, useSetAtom } from "jotai";
|
||||
import { useRouter } from "@kyoo/primitives";
|
||||
import { useEffect } from "react";
|
||||
import { Platform } from "react-native";
|
||||
import { useRouter } from "solito/router";
|
||||
import {
|
||||
durationAtom,
|
||||
fullscreenAtom,
|
||||
|
@ -19,8 +19,8 @@
|
||||
*/
|
||||
|
||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { useRouter } from "@kyoo/primitives";
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "solito/router";
|
||||
import { reducerAtom } from "./keyboard";
|
||||
import { durationAtom, playAtom, progressAtom } from "./state";
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user