Last active
September 19, 2023 15:03
-
-
Save tawachan/b12129561f9969259fbdd51b36d6afe1 to your computer and use it in GitHub Desktop.
リッチリンクの独自コンポーネント
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
AspectRatio, | |
HStack, | |
Heading, | |
Image, | |
Stack, | |
Text, | |
Link, | |
} from "@chakra-ui/react"; | |
import React, { useMemo } from "react"; | |
import { FC } from "react"; | |
import { isValidUrl } from "../helpers/url"; | |
import { useQuery } from "react-query"; | |
import { useWidthLevel } from "../hooks/useWidthLevel"; | |
type Props = { | |
href: string; | |
}; | |
export const RichLink: FC<Props> = ({ href }) => { | |
const url = href; | |
const isValid = isValidUrl(url); | |
const defaultImageLink = "/default-web-thumbnail.jpg"; | |
const isSameDomain = useMemo(() => { | |
if (!isValid) return false; | |
// windowの有無を確認しないとSSR時にエラーになる | |
if (typeof window === "undefined") return false; | |
const currentDomain = window.location.hostname; | |
const urlDomain = new URL(url).hostname; | |
return currentDomain === urlDomain; | |
}, [isValid]); | |
const { isMobile } = useWidthLevel(); | |
const { data: allData } = useQuery( | |
"ogp-data", | |
async () => { | |
const res = await fetch("/ogp-data.json"); | |
const data = await res.json(); | |
return data; | |
}, | |
{ enabled: isValid } | |
); | |
const data = useMemo(() => { | |
if (!allData) return null; | |
return allData[url]; | |
}, [allData, url]); | |
if (!isValid) return null; | |
if (!data) { | |
return ( | |
<Link href={url} isExternal={!isSameDomain} textDecor="none !important"> | |
<HStack | |
borderWidth="1px" | |
borderRadius={12} | |
p={0} | |
h="140px" | |
overflow="hidden" | |
> | |
<Stack flex={1} overflow="hidden" p={6} spacing={3}> | |
<Heading as="strong" fontSize="md" isTruncated> | |
{url} | |
</Heading> | |
</Stack> | |
<Stack w={isMobile ? "140px" : "250px"}> | |
<AspectRatio ratio={isMobile ? 1 : 16 / 9} w="full" h="full"> | |
<Image | |
src={defaultImageLink} | |
alt={url} | |
w="full" | |
h="full" | |
overflow="hidden" | |
objectFit="cover" | |
/> | |
</AspectRatio> | |
</Stack> | |
</HStack> | |
</Link> | |
); | |
} | |
return ( | |
<Link href={url} isExternal={!isSameDomain} textDecor="none !important"> | |
<HStack | |
borderWidth="1px" | |
borderRadius={12} | |
p={0} | |
h="140px" | |
overflow="hidden" | |
> | |
<Stack flex={1} overflow="hidden" p={6} spacing={3}> | |
<Heading as="strong" fontSize="md" isTruncated> | |
{data.title} | |
</Heading> | |
<Text fontSize="sm" m="0px !important" isTruncated color="gray.500"> | |
{data.description} | |
</Text> | |
<Text fontSize="xs" m="0px !important" color="gray.800" isTruncated> | |
{isMobile ? data.domain : data.url} | |
</Text> | |
</Stack> | |
<Stack w={isMobile ? "140px" : "250px"}> | |
<AspectRatio ratio={isMobile ? 1 : 16 / 9} w="full" h="full"> | |
<Image | |
src={data.image || defaultImageLink} | |
alt={data.title} | |
w="full" | |
h="full" | |
overflow="hidden" | |
objectFit="cover" | |
/> | |
</AspectRatio> | |
</Stack> | |
</HStack> | |
</Link> | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment