mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-01-14 00:48:18 -05:00
179 lines
4.3 KiB
TypeScript
179 lines
4.3 KiB
TypeScript
import {
|
|
Box,
|
|
Flex,
|
|
HStack,
|
|
Input,
|
|
LoadingState,
|
|
Text,
|
|
VStack,
|
|
} from '@metafam/ds';
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
|
|
import { MetaLink } from '#components/Link';
|
|
import { Maybe } from '#graphql/autogen/hasura-sdk';
|
|
import { useDelay } from '#lib/hooks/useDelay';
|
|
import { BoxMetadata } from '#utils/boxTypes';
|
|
import { errorHandler } from '#utils/errorHandler';
|
|
|
|
const metadataLink = '/api/metadata?url=';
|
|
|
|
type EmbeddedUrlProps = {
|
|
url?: string;
|
|
};
|
|
|
|
interface URIMetadata {
|
|
url?: Maybe<string>;
|
|
title?: Maybe<string>;
|
|
description?: Maybe<string>;
|
|
image?: Maybe<string>;
|
|
site_name?: Maybe<string>;
|
|
}
|
|
|
|
export const EmbeddedUrl: React.FC<EmbeddedUrlProps> = ({
|
|
url: inputUrl = '',
|
|
}) => {
|
|
const [metadata, setMetadata] = useState<Maybe<URIMetadata>>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const updateMetadata = useCallback(async (uri: string) => {
|
|
setLoading(true);
|
|
try {
|
|
const res = await fetch(metadataLink + uri);
|
|
const { error, response } = await res.json();
|
|
|
|
if (error) throw error;
|
|
|
|
setMetadata(response.og as unknown as URIMetadata);
|
|
} catch (err) {
|
|
console.error(`No metadata found for the URL "${uri}"`, err);
|
|
errorHandler(err as Error);
|
|
setMetadata(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const delayedUpdate = useDelay(updateMetadata);
|
|
|
|
useEffect(() => delayedUpdate(inputUrl), [inputUrl, delayedUpdate]);
|
|
|
|
if (!metadata || loading) {
|
|
return (
|
|
<Flex
|
|
minH="21rem"
|
|
w="100%"
|
|
borderRadius="lg"
|
|
backdropFilter="blur(7px)"
|
|
borderWidth={0}
|
|
justify="center"
|
|
align="center"
|
|
>
|
|
{loading && <LoadingState />}
|
|
</Flex>
|
|
);
|
|
}
|
|
|
|
const { image, description, title, site_name: siteName, url } = metadata;
|
|
|
|
return (
|
|
<MetaLink
|
|
_hover={{}}
|
|
href={url ?? inputUrl}
|
|
isExternal
|
|
w="100%"
|
|
borderRadius="lg"
|
|
backdropFilter="blur(7px)"
|
|
borderWidth={0}
|
|
minH="21rem"
|
|
>
|
|
<Flex w="100%" direction="column">
|
|
{image && (
|
|
<Box
|
|
bgImage={`url(${image})`}
|
|
height="auto"
|
|
minH="12rem"
|
|
w="100%"
|
|
bgSize="cover"
|
|
bgRepeat="no-repeat"
|
|
bgPosition="center"
|
|
/>
|
|
)}
|
|
<VStack p={4} spacing={1} align="stretch">
|
|
{title && (
|
|
<Text
|
|
as="span"
|
|
fontWeight="bold"
|
|
display="-webkit-box"
|
|
textOverflow="ellipsis"
|
|
overflow="hidden"
|
|
maxW="calc(100%)"
|
|
color="white"
|
|
minH="1.5rem"
|
|
sx={{
|
|
lineClamp: 1,
|
|
WebkitLineClamp: 1,
|
|
WebkitBoxOrient: 'vertical',
|
|
}}
|
|
>
|
|
{title}
|
|
</Text>
|
|
)}
|
|
{description && (
|
|
<Text
|
|
minH="4rem"
|
|
as="span"
|
|
display="-webkit-box"
|
|
textOverflow="ellipsis"
|
|
overflow="hidden"
|
|
maxW="calc(100%)"
|
|
fontSize="sm"
|
|
color="white"
|
|
sx={{
|
|
lineClamp: 3,
|
|
WebkitLineClamp: 3,
|
|
WebkitBoxOrient: 'vertical',
|
|
}}
|
|
>
|
|
{description}
|
|
</Text>
|
|
)}
|
|
<HStack spacing={1} minH="1.5rem">
|
|
{siteName && (
|
|
<Text
|
|
as="span"
|
|
color="cyanText"
|
|
fontSize="sm"
|
|
whiteSpace="nowrap"
|
|
>
|
|
{siteName} •
|
|
</Text>
|
|
)}
|
|
<Text as="span" noOfLines={1} fontSize="sm" pb={0}>
|
|
{url ?? inputUrl}
|
|
</Text>
|
|
</HStack>
|
|
</VStack>
|
|
</Flex>
|
|
</MetaLink>
|
|
);
|
|
};
|
|
|
|
export const EmbeddedUrlMetadata: React.FC<{
|
|
metadata: BoxMetadata;
|
|
setMetadata: (d: BoxMetadata) => void;
|
|
}> = ({ metadata, setMetadata }) => (
|
|
<Input
|
|
bg="dark"
|
|
w="100%"
|
|
placeholder="Provide the URL of the content"
|
|
_placeholder={{ color: 'whiteAlpha.500' }}
|
|
value={metadata.url ?? ''}
|
|
onChange={({ target: { value: url } }) => setMetadata({ url })}
|
|
size="lg"
|
|
borderRadius={0}
|
|
borderColor="borderPurple"
|
|
fontSize="md"
|
|
borderWidth="2px"
|
|
/>
|
|
);
|