Kyoo/front/src/primitives/image-background.tsx
2025-06-22 21:22:37 +02:00

106 lines
2.5 KiB
TypeScript

import { ImageBackground as EImageBackground } from "expo-image";
import { LinearGradient, type LinearGradientProps } from "expo-linear-gradient";
import type { ComponentProps, ReactNode } from "react";
import type { ImageStyle } from "react-native";
import { Platform } from "react-native";
import { useYoshiki } from "yoshiki/native";
import type { KImage } from "~/models";
import { useToken } from "~/providers/account-context";
import type { ImageLayout, YoshikiEnhanced } from "./image";
// This should stay in think with `Image`.
// (copy-pasted but change `EImage` with `EImageBackground`)
// ALSO, remove `border-radius` (it's weird otherwise)
export const ImageBackground = ({
src,
quality,
alt,
layout,
...props
}: {
src: KImage | null;
quality: "low" | "medium" | "high";
alt?: string;
style?: ImageStyle;
layout: ImageLayout;
children: ReactNode;
}) => {
const { css } = useYoshiki();
const { apiUrl, authToken } = useToken();
return (
<EImageBackground
source={{
uri: src ? `${apiUrl}${src[quality ?? "high"]}` : null,
// use cookies on web to allow `img` to make the call instead of js
headers:
authToken && Platform.OS !== "web"
? {
Authorization: authToken,
}
: undefined,
}}
placeholder={{ blurhash: src?.blurhash }}
accessibilityLabel={alt}
{...(css(layout, props) as any)}
/>
);
};
export const PosterBackground = ({
alt,
layout,
...props
}: Omit<ComponentProps<typeof ImageBackground>, "layout"> & {
style?: ImageStyle;
layout: YoshikiEnhanced<
{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }
>;
}) => {
const { css } = useYoshiki();
return (
<ImageBackground
alt={alt!}
layout={{ aspectRatio: 2 / 3, ...layout }}
{...css({ borderRadius: 10, overflow: "hidden" }, props)}
/>
);
};
export const GradientImageBackground = ({
gradient,
gradientStyle,
children,
...props
}: ComponentProps<typeof ImageBackground> & {
gradient?: Partial<LinearGradientProps>;
gradientStyle?: Parameters<ReturnType<typeof useYoshiki>["css"]>[0];
}) => {
const { css, theme } = useYoshiki();
return (
<ImageBackground {...props}>
<LinearGradient
start={{ x: 0, y: 0.25 }}
end={{ x: 0, y: 1 }}
colors={["transparent", theme.darkOverlay]}
{...css(
[
{
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0,
},
gradientStyle,
],
typeof gradient === "object" ? gradient : undefined,
)}
>
{children}
</LinearGradient>
</ImageBackground>
);
};