mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-04 22:24:14 -04:00
Split image backround and gradient image background
This commit is contained in:
parent
cc50444384
commit
95086777af
@ -22,6 +22,7 @@ import { LinearGradient, type LinearGradientProps } from "expo-linear-gradient";
|
|||||||
import type { ComponentProps, ComponentType, ReactElement, ReactNode } from "react";
|
import type { ComponentProps, ComponentType, ReactElement, ReactNode } from "react";
|
||||||
import { type ImageStyle, View, type ViewProps, type ViewStyle } from "react-native";
|
import { type ImageStyle, View, type ViewProps, type ViewStyle } from "react-native";
|
||||||
import { percent } from "yoshiki/native";
|
import { percent } from "yoshiki/native";
|
||||||
|
import { useYoshiki } from "yoshiki/native";
|
||||||
import { imageBorderRadius } from "../constants";
|
import { imageBorderRadius } from "../constants";
|
||||||
import { ContrastArea } from "../themes";
|
import { ContrastArea } from "../themes";
|
||||||
import type { ImageLayout, Props, YoshikiEnhanced } from "./base-image";
|
import type { ImageLayout, Props, YoshikiEnhanced } from "./base-image";
|
||||||
@ -53,51 +54,50 @@ export const PosterBackground = ({
|
|||||||
...props
|
...props
|
||||||
}: Omit<ComponentProps<typeof ImageBackground>, "layout"> & { style?: ImageStyle } & {
|
}: Omit<ComponentProps<typeof ImageBackground>, "layout"> & { style?: ImageStyle } & {
|
||||||
layout: YoshikiEnhanced<{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }>;
|
layout: YoshikiEnhanced<{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }>;
|
||||||
}) => (
|
}) => {
|
||||||
|
const { css } = useYoshiki();
|
||||||
|
|
||||||
|
return (
|
||||||
<ImageBackground
|
<ImageBackground
|
||||||
alt={alt!}
|
alt={alt!}
|
||||||
layout={{ aspectRatio: 2 / 3, ...layout }}
|
layout={{ aspectRatio: 2 / 3, ...layout }}
|
||||||
hideLoad={false}
|
{...css({ borderRadius: imageBorderRadius }, props)}
|
||||||
gradient={false}
|
|
||||||
{...props}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ImageBackgroundProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
containerStyle?: YoshikiEnhanced<ViewStyle>;
|
||||||
|
imageStyle?: YoshikiEnhanced<ImageStyle>;
|
||||||
|
layout?: ImageLayout;
|
||||||
|
contrast?: "light" | "dark" | "user";
|
||||||
|
};
|
||||||
|
|
||||||
export const ImageBackground = <AsProps = ViewProps>({
|
export const ImageBackground = <AsProps = ViewProps>({
|
||||||
src,
|
src,
|
||||||
alt,
|
alt,
|
||||||
quality,
|
quality,
|
||||||
gradient = true,
|
|
||||||
as,
|
as,
|
||||||
children,
|
children,
|
||||||
containerStyle,
|
containerStyle,
|
||||||
imageStyle,
|
imageStyle,
|
||||||
forcedLoading,
|
|
||||||
hideLoad = true,
|
|
||||||
contrast = "dark",
|
|
||||||
layout,
|
layout,
|
||||||
|
contrast = "dark",
|
||||||
|
imageSibling,
|
||||||
...asProps
|
...asProps
|
||||||
}: {
|
}: {
|
||||||
as?: ComponentType<AsProps>;
|
as?: ComponentType<AsProps>;
|
||||||
gradient?: Partial<LinearGradientProps> | boolean;
|
imageSibling?: ReactElement;
|
||||||
children?: ReactNode;
|
|
||||||
containerStyle?: YoshikiEnhanced<ViewStyle>;
|
|
||||||
imageStyle?: YoshikiEnhanced<ImageStyle>;
|
|
||||||
hideLoad?: boolean;
|
|
||||||
contrast?: "light" | "dark" | "user";
|
|
||||||
layout?: ImageLayout;
|
|
||||||
} & AsProps &
|
} & AsProps &
|
||||||
|
ImageBackgroundProps &
|
||||||
Props) => {
|
Props) => {
|
||||||
const Container = as ?? View;
|
const Container = as ?? View;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContrastArea contrastText mode={contrast}>
|
<ContrastArea contrastText mode={contrast}>
|
||||||
{({ css, theme }) => (
|
{({ css }) => (
|
||||||
<Container
|
<Container {...(css([layout, { overflow: "hidden" }], asProps) as AsProps)}>
|
||||||
{...(css(
|
|
||||||
[layout, { borderRadius: imageBorderRadius, overflow: "hidden" }],
|
|
||||||
asProps,
|
|
||||||
) as AsProps)}
|
|
||||||
>
|
|
||||||
<View
|
<View
|
||||||
{...css([
|
{...css([
|
||||||
{
|
{
|
||||||
@ -112,24 +112,46 @@ export const ImageBackground = <AsProps = ViewProps>({
|
|||||||
containerStyle,
|
containerStyle,
|
||||||
])}
|
])}
|
||||||
>
|
>
|
||||||
{(src || !hideLoad) && (
|
{src && (
|
||||||
<Image
|
<Image
|
||||||
src={src}
|
src={src}
|
||||||
quality={quality}
|
quality={quality}
|
||||||
forcedLoading={forcedLoading}
|
|
||||||
alt={alt!}
|
alt={alt!}
|
||||||
layout={{ width: percent(100), height: percent(100) }}
|
layout={{ width: percent(100), height: percent(100) }}
|
||||||
Err={hideLoad ? null : undefined}
|
|
||||||
{...(css([{ borderWidth: 0, borderRadius: 0 }, imageStyle]) as {
|
{...(css([{ borderWidth: 0, borderRadius: 0 }, imageStyle]) as {
|
||||||
style: ImageStyle;
|
style: ImageStyle;
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{gradient && (
|
{imageSibling}
|
||||||
|
</View>
|
||||||
|
{children}
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
</ContrastArea>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GradientImageBackground = <AsProps = ViewProps>({
|
||||||
|
contrast = "dark",
|
||||||
|
gradient,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
as?: ComponentType<AsProps>;
|
||||||
|
gradient?: Partial<LinearGradientProps>;
|
||||||
|
} & AsProps &
|
||||||
|
ImageBackgroundProps &
|
||||||
|
Props) => {
|
||||||
|
const { css, theme } = useYoshiki();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ImageBackground
|
||||||
|
contrast={contrast}
|
||||||
|
imageSibling={
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
start={{ x: 0, y: 0.25 }}
|
start={{ x: 0, y: 0.25 }}
|
||||||
end={{ x: 0, y: 1 }}
|
end={{ x: 0, y: 1 }}
|
||||||
colors={["transparent", theme.darkOverlay]}
|
colors={["transparent", theme[contrast].darkOverlay]}
|
||||||
{...css(
|
{...css(
|
||||||
{
|
{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@ -141,11 +163,8 @@ export const ImageBackground = <AsProps = ViewProps>({
|
|||||||
typeof gradient === "object" ? gradient : undefined,
|
typeof gradient === "object" ? gradient : undefined,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
}
|
||||||
</View>
|
{...(props as any)}
|
||||||
{children}
|
/>
|
||||||
</Container>
|
|
||||||
)}
|
|
||||||
</ContrastArea>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
import type { KyooImage, WatchStatusV } from "@kyoo/models";
|
import type { KyooImage, WatchStatusV } from "@kyoo/models";
|
||||||
import {
|
import {
|
||||||
|
GradientImageBackground,
|
||||||
Heading,
|
Heading,
|
||||||
ImageBackground,
|
|
||||||
Link,
|
Link,
|
||||||
P,
|
P,
|
||||||
Poster,
|
Poster,
|
||||||
@ -33,7 +33,6 @@ import {
|
|||||||
} from "@kyoo/primitives";
|
} from "@kyoo/primitives";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Platform, View } from "react-native";
|
import { Platform, View } from "react-native";
|
||||||
import type { Stylable } from "yoshiki";
|
|
||||||
import { percent, px, rem, useYoshiki } from "yoshiki/native";
|
import { percent, px, rem, useYoshiki } from "yoshiki/native";
|
||||||
import { ItemContext } from "../components/context-menus";
|
import { ItemContext } from "../components/context-menus";
|
||||||
import type { Layout } from "../fetch";
|
import type { Layout } from "../fetch";
|
||||||
@ -65,19 +64,13 @@ export const ItemList = ({
|
|||||||
const [moreOpened, setMoreOpened] = useState(false);
|
const [moreOpened, setMoreOpened] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImageBackground
|
<GradientImageBackground
|
||||||
src={thumbnail}
|
src={thumbnail}
|
||||||
alt={name}
|
alt={name}
|
||||||
quality="medium"
|
quality="medium"
|
||||||
as={Link}
|
as={Link}
|
||||||
href={moreOpened ? undefined : href}
|
href={moreOpened ? undefined : href}
|
||||||
onLongPress={() => setMoreOpened(true)}
|
onLongPress={() => setMoreOpened(true)}
|
||||||
containerStyle={{
|
|
||||||
borderRadius: px(imageBorderRadius),
|
|
||||||
}}
|
|
||||||
imageStyle={{
|
|
||||||
borderRadius: px(imageBorderRadius),
|
|
||||||
}}
|
|
||||||
{...css(
|
{...css(
|
||||||
{
|
{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@ -162,7 +155,7 @@ export const ItemList = ({
|
|||||||
<PosterBackground src={poster} alt="" quality="low" layout={{ height: percent(80) }}>
|
<PosterBackground src={poster} alt="" quality="low" layout={{ height: percent(80) }}>
|
||||||
<ItemWatchStatus watchStatus={watchStatus} unseenEpisodesCount={unseenEpisodesCount} />
|
<ItemWatchStatus watchStatus={watchStatus} unseenEpisodesCount={unseenEpisodesCount} />
|
||||||
</PosterBackground>
|
</PosterBackground>
|
||||||
</ImageBackground>
|
</GradientImageBackground>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,7 +27,15 @@ import {
|
|||||||
type QueryPage,
|
type QueryPage,
|
||||||
getDisplayDate,
|
getDisplayDate,
|
||||||
} from "@kyoo/models";
|
} from "@kyoo/models";
|
||||||
import { Container, Head, ImageBackground, P, Skeleton, ts, usePageStyle } from "@kyoo/primitives";
|
import {
|
||||||
|
Container,
|
||||||
|
GradientImageBackground,
|
||||||
|
Head,
|
||||||
|
P,
|
||||||
|
Skeleton,
|
||||||
|
ts,
|
||||||
|
usePageStyle,
|
||||||
|
} from "@kyoo/primitives";
|
||||||
import { forwardRef } from "react";
|
import { forwardRef } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Platform, View, type ViewProps } from "react-native";
|
import { Platform, View, type ViewProps } from "react-native";
|
||||||
@ -50,7 +58,7 @@ const Header = ({ slug }: { slug: string }) => {
|
|||||||
<>
|
<>
|
||||||
<Head title={data?.name} description={data?.overview} image={data?.thumbnail?.high} />
|
<Head title={data?.name} description={data?.overview} image={data?.thumbnail?.high} />
|
||||||
|
|
||||||
<ImageBackground
|
<GradientImageBackground
|
||||||
src={data?.thumbnail}
|
src={data?.thumbnail}
|
||||||
quality="high"
|
quality="high"
|
||||||
alt=""
|
alt=""
|
||||||
@ -70,7 +78,7 @@ const Header = ({ slug }: { slug: string }) => {
|
|||||||
studio={null}
|
studio={null}
|
||||||
{...css(ShowHeader.childStyle)}
|
{...css(ShowHeader.childStyle)}
|
||||||
/>
|
/>
|
||||||
</ImageBackground>
|
</GradientImageBackground>
|
||||||
|
|
||||||
<Container
|
<Container
|
||||||
{...css({
|
{...css({
|
||||||
|
@ -25,7 +25,16 @@ import {
|
|||||||
type QueryIdentifier,
|
type QueryIdentifier,
|
||||||
useInfiniteFetch,
|
useInfiniteFetch,
|
||||||
} from "@kyoo/models";
|
} from "@kyoo/models";
|
||||||
import { Container, H2, ImageBackground, Link, P, focusReset, ts } from "@kyoo/primitives";
|
import {
|
||||||
|
Container,
|
||||||
|
GradientImageBackground,
|
||||||
|
H2,
|
||||||
|
ImageBackground,
|
||||||
|
Link,
|
||||||
|
P,
|
||||||
|
focusReset,
|
||||||
|
ts,
|
||||||
|
} from "@kyoo/primitives";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { type Theme, useYoshiki } from "yoshiki/native";
|
import { type Theme, useYoshiki } from "yoshiki/native";
|
||||||
import { ErrorView } from "../errors";
|
import { ErrorView } from "../errors";
|
||||||
@ -59,11 +68,15 @@ export const PartOf = ({
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<ImageBackground
|
<GradientImageBackground
|
||||||
src={thumbnail}
|
src={thumbnail}
|
||||||
alt=""
|
alt=""
|
||||||
quality="medium"
|
quality="medium"
|
||||||
gradient={{ colors: [theme.darkOverlay, theme.darkOverlay] }}
|
gradient={{
|
||||||
|
colors: [theme.darkOverlay, "transparent"],
|
||||||
|
start: { x: 0, y: 0 },
|
||||||
|
end: { x: 1, y: 0 },
|
||||||
|
}}
|
||||||
{...css({
|
{...css({
|
||||||
padding: ts(3),
|
padding: ts(3),
|
||||||
})}
|
})}
|
||||||
@ -72,7 +85,7 @@ export const PartOf = ({
|
|||||||
{t("show.partOf")} {name}
|
{t("show.partOf")} {name}
|
||||||
</H2>
|
</H2>
|
||||||
<P {...css({ textAlign: "justify" })}>{overview}</P>
|
<P {...css({ textAlign: "justify" })}>{overview}</P>
|
||||||
</ImageBackground>
|
</GradientImageBackground>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,7 @@ import {
|
|||||||
Skeleton,
|
Skeleton,
|
||||||
SubP,
|
SubP,
|
||||||
focusReset,
|
focusReset,
|
||||||
|
imageBorderRadius,
|
||||||
important,
|
important,
|
||||||
tooltip,
|
tooltip,
|
||||||
ts,
|
ts,
|
||||||
@ -98,6 +99,7 @@ export const EpisodeBox = ({
|
|||||||
borderColor: (theme) => theme.background,
|
borderColor: (theme) => theme.background,
|
||||||
borderWidth: ts(0.5),
|
borderWidth: ts(0.5),
|
||||||
borderStyle: "solid",
|
borderStyle: "solid",
|
||||||
|
borderRadius: imageBorderRadius,
|
||||||
},
|
},
|
||||||
more: {
|
more: {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
@ -123,9 +125,8 @@ export const EpisodeBox = ({
|
|||||||
src={thumbnail}
|
src={thumbnail}
|
||||||
quality="low"
|
quality="low"
|
||||||
alt=""
|
alt=""
|
||||||
gradient={false}
|
|
||||||
layout={{ width: percent(100), aspectRatio: 16 / 9 }}
|
layout={{ width: percent(100), aspectRatio: 16 / 9 }}
|
||||||
{...(css("poster") as any)}
|
{...css("poster")}
|
||||||
>
|
>
|
||||||
{(watchedPercent || watchedStatus === WatchStatusV.Completed) && (
|
{(watchedPercent || watchedStatus === WatchStatusV.Completed) && (
|
||||||
<ItemProgress watchPercent={watchedPercent ?? 100} />
|
<ItemProgress watchPercent={watchedPercent ?? 100} />
|
||||||
@ -254,12 +255,11 @@ export const EpisodeLine = ({
|
|||||||
src={thumbnail}
|
src={thumbnail}
|
||||||
quality="low"
|
quality="low"
|
||||||
alt=""
|
alt=""
|
||||||
gradient={false}
|
|
||||||
layout={{
|
layout={{
|
||||||
width: percent(18),
|
width: percent(18),
|
||||||
aspectRatio: 16 / 9,
|
aspectRatio: 16 / 9,
|
||||||
}}
|
}}
|
||||||
{...(css({ flexShrink: 0, m: ts(1) }) as { style: ImageStyle })}
|
{...css({ flexShrink: 0, m: ts(1) })}
|
||||||
>
|
>
|
||||||
{(watchedPercent || watchedStatus === WatchStatusV.Completed) && (
|
{(watchedPercent || watchedStatus === WatchStatusV.Completed) && (
|
||||||
<>
|
<>
|
||||||
|
@ -35,13 +35,13 @@ import {
|
|||||||
Chip,
|
Chip,
|
||||||
Container,
|
Container,
|
||||||
DottedSeparator,
|
DottedSeparator,
|
||||||
|
GradientImageBackground,
|
||||||
H1,
|
H1,
|
||||||
H2,
|
H2,
|
||||||
HR,
|
HR,
|
||||||
Head,
|
Head,
|
||||||
IconButton,
|
IconButton,
|
||||||
IconFab,
|
IconFab,
|
||||||
ImageBackground,
|
|
||||||
LI,
|
LI,
|
||||||
Link,
|
Link,
|
||||||
Menu,
|
Menu,
|
||||||
@ -509,7 +509,7 @@ export const Header = ({
|
|||||||
{({ isLoading, ...data }) => (
|
{({ isLoading, ...data }) => (
|
||||||
<>
|
<>
|
||||||
<Head title={data?.name} description={data?.overview} image={data?.thumbnail?.high} />
|
<Head title={data?.name} description={data?.overview} image={data?.thumbnail?.high} />
|
||||||
<ImageBackground
|
<GradientImageBackground
|
||||||
src={data?.thumbnail}
|
src={data?.thumbnail}
|
||||||
quality="high"
|
quality="high"
|
||||||
alt=""
|
alt=""
|
||||||
@ -531,7 +531,7 @@ export const Header = ({
|
|||||||
watchStatus={data?.watchStatus?.status ?? null}
|
watchStatus={data?.watchStatus?.status ?? null}
|
||||||
{...css(Header.childStyle)}
|
{...css(Header.childStyle)}
|
||||||
/>
|
/>
|
||||||
</ImageBackground>
|
</GradientImageBackground>
|
||||||
<Description
|
<Description
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
overview={data?.overview}
|
overview={data?.overview}
|
||||||
|
@ -86,13 +86,11 @@ const DownloadedItem = ({
|
|||||||
src={image}
|
src={image}
|
||||||
quality="low"
|
quality="low"
|
||||||
alt=""
|
alt=""
|
||||||
gradient={false}
|
|
||||||
hideLoad={false}
|
|
||||||
layout={{
|
layout={{
|
||||||
width: percent(25),
|
width: percent(25),
|
||||||
aspectRatio: kind === "episode" ? 16 / 9 : 2 / 3,
|
aspectRatio: kind === "episode" ? 16 / 9 : 2 / 3,
|
||||||
}}
|
}}
|
||||||
{...(css({ flexShrink: 0, m: ts(1) }) as { style: ImageStyle })}
|
{...css({ flexShrink: 0, m: ts(1) })}
|
||||||
>
|
>
|
||||||
{/* {(watchedPercent || watchedStatus === WatchStatusV.Completed) && ( */}
|
{/* {(watchedPercent || watchedStatus === WatchStatusV.Completed) && ( */}
|
||||||
{/* <> */}
|
{/* <> */}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
import { type KyooImage, type LibraryItem, LibraryItemP, type QueryIdentifier } from "@kyoo/models";
|
import { type KyooImage, type LibraryItem, LibraryItemP, type QueryIdentifier } from "@kyoo/models";
|
||||||
import {
|
import {
|
||||||
|
GradientImageBackground,
|
||||||
H1,
|
H1,
|
||||||
H2,
|
H2,
|
||||||
IconButton,
|
IconButton,
|
||||||
@ -60,7 +61,7 @@ export const Header = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImageBackground
|
<GradientImageBackground
|
||||||
src={thumbnail}
|
src={thumbnail}
|
||||||
alt=""
|
alt=""
|
||||||
quality="high"
|
quality="high"
|
||||||
@ -108,7 +109,7 @@ export const Header = ({
|
|||||||
)}
|
)}
|
||||||
</Skeleton>
|
</Skeleton>
|
||||||
</View>
|
</View>
|
||||||
</ImageBackground>
|
</GradientImageBackground>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user