mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Rework chip to support links and skeletons
This commit is contained in:
parent
0272b82166
commit
9304c7ad2f
@ -28,7 +28,7 @@ export const Button = ({
|
|||||||
text,
|
text,
|
||||||
...props
|
...props
|
||||||
}: { text: string } & ComponentProps<typeof PressableFeedback>) => {
|
}: { text: string } & ComponentProps<typeof PressableFeedback>) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki("button");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PressableFeedback
|
<PressableFeedback
|
||||||
|
@ -18,54 +18,88 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { px, rem, Stylable, Theme, useYoshiki } from "yoshiki/native";
|
import { px, rem, Theme, useYoshiki } from "yoshiki/native";
|
||||||
|
import { Link } from "./links";
|
||||||
import { P } from "./text";
|
import { P } from "./text";
|
||||||
import { ts } from "./utils";
|
import { capitalize, ts } from "./utils";
|
||||||
import { A } from "./links";
|
import { EnhancedStyle } from "yoshiki/src/native/type";
|
||||||
import { ComponentType } from "react";
|
import { TextProps, TextStyle, ViewStyle } from "react-native";
|
||||||
|
import { Skeleton } from "./skeleton";
|
||||||
|
|
||||||
export const Chip = <AsProps = { label: string },>({
|
export const Chip = ({
|
||||||
color,
|
color,
|
||||||
size = "medium",
|
size = "medium",
|
||||||
outline = false,
|
outline = false,
|
||||||
as,
|
label,
|
||||||
|
href,
|
||||||
|
replace,
|
||||||
|
target,
|
||||||
|
textProps,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
color?: string;
|
color?: string;
|
||||||
size?: "small" | "medium" | "large";
|
size?: "small" | "medium" | "large";
|
||||||
outline?: boolean;
|
outline?: boolean;
|
||||||
as?: ComponentType<AsProps>;
|
label?: string;
|
||||||
} & AsProps) => {
|
href?: string;
|
||||||
const { css } = useYoshiki();
|
replace?: boolean;
|
||||||
|
target?: string;
|
||||||
|
textProps?: TextProps;
|
||||||
|
}) => {
|
||||||
|
const { css } = useYoshiki("chip");
|
||||||
|
|
||||||
|
textProps ??= {};
|
||||||
|
|
||||||
const sizeMult = size == "medium" ? 1 : size == "small" ? 0.5 : 1.5;
|
const sizeMult = size == "medium" ? 1 : size == "small" ? 0.5 : 1.5;
|
||||||
|
|
||||||
const As = as ?? (P as any);
|
|
||||||
// @ts-ignore backward compatibilty
|
|
||||||
if (!as && props.label) props.children = props.label;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<As
|
<Link
|
||||||
|
href={href}
|
||||||
|
replace={replace}
|
||||||
|
target={target}
|
||||||
{...css(
|
{...css(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
pY: ts(1 * sizeMult),
|
pY: ts(1 * sizeMult),
|
||||||
pX: ts(2.5 * sizeMult),
|
pX: ts(2.5 * sizeMult),
|
||||||
borderRadius: ts(3),
|
borderRadius: ts(3),
|
||||||
fontSize: rem(0.8),
|
overflow: "hidden",
|
||||||
},
|
|
||||||
!outline && {
|
|
||||||
color: (theme: Theme) => theme.alternate.contrast,
|
|
||||||
bg: color ?? ((theme: Theme) => theme.accent),
|
|
||||||
},
|
},
|
||||||
outline && {
|
outline && {
|
||||||
borderColor: color ?? ((theme: Theme) => theme.accent),
|
borderColor: color ?? ((theme: Theme) => theme.accent),
|
||||||
borderStyle: "solid",
|
borderStyle: "solid",
|
||||||
borderWidth: px(1),
|
borderWidth: px(1),
|
||||||
|
fover: {
|
||||||
|
self: {
|
||||||
|
bg: (theme: Theme) => theme.accent,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
color: (theme: Theme) => theme.alternate.contrast,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
!outline && {
|
||||||
|
bg: color ?? ((theme: Theme) => theme.accent),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
props,
|
props,
|
||||||
)}
|
)}
|
||||||
/>
|
>
|
||||||
|
<P
|
||||||
|
{...css(
|
||||||
|
[
|
||||||
|
"text",
|
||||||
|
{
|
||||||
|
marginVertical: 0,
|
||||||
|
fontSize: rem(0.8),
|
||||||
|
color: (theme: Theme) => (outline ? theme.contrast : theme.alternate.contrast),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
textProps,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{label ? capitalize(label) : <Skeleton {...css({ width: rem(3) })} />}
|
||||||
|
</P>
|
||||||
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { forwardRef, ReactNode } from "react";
|
import { forwardRef, ReactNode } from "react";
|
||||||
import { Platform, Pressable, TextProps, View, PressableProps } from "react-native";
|
import { Platform, Pressable, TextProps, View, PressableProps, Linking } from "react-native";
|
||||||
import { TextLink, useLink } from "solito/link";
|
import { TextLink, useLink } from "solito/link";
|
||||||
import { useTheme, useYoshiki } from "yoshiki/native";
|
import { useTheme, useYoshiki } from "yoshiki/native";
|
||||||
import { alpha } from "./themes";
|
import { alpha } from "./themes";
|
||||||
@ -107,7 +107,16 @@ export const Link = ({
|
|||||||
// @ts-ignore Missing hrefAttrs type definition.
|
// @ts-ignore Missing hrefAttrs type definition.
|
||||||
linkProps.hrefAttrs = { ...linkProps.hrefAttrs, target };
|
linkProps.hrefAttrs = { ...linkProps.hrefAttrs, target };
|
||||||
return (
|
return (
|
||||||
<PressableFeedback {...linkProps} {...props}>
|
<PressableFeedback
|
||||||
|
{...linkProps}
|
||||||
|
{...props}
|
||||||
|
onPress={(e?: any) => {
|
||||||
|
props?.onPress?.(e);
|
||||||
|
if (e?.defaultPrevented) return;
|
||||||
|
if (Platform.OS !== "web" && href?.includes("://")) Linking.openURL(href);
|
||||||
|
else linkProps.onPress(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</PressableFeedback>
|
</PressableFeedback>
|
||||||
);
|
);
|
||||||
|
@ -30,7 +30,7 @@ export const Rating = ({ rating, color }: { rating?: number; color: Breakpoint<s
|
|||||||
<View {...css({ flexDirection: "row", alignItems: "center" })}>
|
<View {...css({ flexDirection: "row", alignItems: "center" })}>
|
||||||
<Icon icon={Star} color={color} {...css({ marginRight: ts(0.5) })} />
|
<Icon icon={Star} color={color} {...css({ marginRight: ts(0.5) })} />
|
||||||
<Skeleton {...css({ width: rem(2) })}>
|
<Skeleton {...css({ width: rem(2) })}>
|
||||||
{rating !== undefined && <P {...css({ color })}>{rating ? rating / 10 : "??"} / 10</P>}
|
{rating !== undefined && <P {...css({ color, verticalAlign: "middle" })}>{rating ? rating / 10 : "??"} / 10</P>}
|
||||||
</Skeleton>
|
</Skeleton>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -172,7 +172,7 @@ export const EpisodeLine = ({
|
|||||||
watchedStatus: WatchStatusV | null;
|
watchedStatus: WatchStatusV | null;
|
||||||
}> &
|
}> &
|
||||||
Stylable) => {
|
Stylable) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki("episode-line");
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -52,7 +52,7 @@ import {
|
|||||||
} from "@kyoo/primitives";
|
} from "@kyoo/primitives";
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ImageStyle, Platform, View } from "react-native";
|
import { ImageStyle, Platform, Text, View } from "react-native";
|
||||||
import {
|
import {
|
||||||
Theme,
|
Theme,
|
||||||
md,
|
md,
|
||||||
@ -458,28 +458,17 @@ export const Header = ({
|
|||||||
<P {...css({ marginRight: ts(0.5), textAlign: "center" })}>{t("show.links")}:</P>
|
<P {...css({ marginRight: ts(0.5), textAlign: "center" })}>{t("show.links")}:</P>
|
||||||
{(!isLoading
|
{(!isLoading
|
||||||
? Object.entries(data.externalId!).filter(([_, data]) => data.link)
|
? Object.entries(data.externalId!).filter(([_, data]) => data.link)
|
||||||
: [...Array(3)].map((_, i) => [i, undefined] as const)
|
: [...Array(3)].map((_) => [undefined, undefined] as const)
|
||||||
).map(([name, data]) => (
|
).map(([name, data], i) => (
|
||||||
<Chip
|
<Chip
|
||||||
key={name}
|
key={name ?? i}
|
||||||
as={A}
|
label={name}
|
||||||
href={data?.link}
|
href={data?.link || undefined}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
size="small"
|
size="small"
|
||||||
outline
|
outline
|
||||||
{...(css({
|
{...css({ m: ts(0.5) })}
|
||||||
m: ts(0.5),
|
/>
|
||||||
color: (theme: Theme) => theme.contrast,
|
|
||||||
fover: {
|
|
||||||
self: {
|
|
||||||
color: (theme: Theme) => theme.alternate.contrast,
|
|
||||||
bg: (theme: Theme) => theme.accent,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}) as any)}
|
|
||||||
>
|
|
||||||
{data ? capitalize(name) : <Skeleton {...css({ width: rem(3) })} />}
|
|
||||||
</Chip>
|
|
||||||
))}
|
))}
|
||||||
</Container>
|
</Container>
|
||||||
{type === "show" && (data.watchStatus as ShowWatchStatus)?.nextEpisode && (
|
{type === "show" && (data.watchStatus as ShowWatchStatus)?.nextEpisode && (
|
||||||
|
@ -166,9 +166,7 @@ export const ItemDetails = ({
|
|||||||
{(isLoading || genres) && (
|
{(isLoading || genres) && (
|
||||||
<ScrollView horizontal {...css({ alignItems: "center" })}>
|
<ScrollView horizontal {...css({ alignItems: "center" })}>
|
||||||
{(genres || [...Array(3)])?.map((x, i) => (
|
{(genres || [...Array(3)])?.map((x, i) => (
|
||||||
<Chip key={x ?? i} size="small" {...css({ mX: ts(0.5) })}>
|
<Chip key={x ?? i} label={x} size="small" {...css({ mX: ts(0.5) })} />
|
||||||
{x ?? <Skeleton {...css({ width: rem(3), height: rem(0.8) })} />}
|
|
||||||
</Chip>
|
|
||||||
))}
|
))}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user