diff --git a/packages/notion-types/src/block.ts b/packages/notion-types/src/block.ts index 48140b8c..141e92b8 100644 --- a/packages/notion-types/src/block.ts +++ b/packages/notion-types/src/block.ts @@ -277,6 +277,9 @@ export interface ToggleBlock extends BaseBlock { export interface ImageBlock extends BaseContentBlock { type: 'image' + format: { + image_hyperlink: string + } & BaseContentBlock['format'] } export interface EmbedBlock extends BaseContentBlock { diff --git a/packages/react-notion-x/src/components/asset-wrapper.tsx b/packages/react-notion-x/src/components/asset-wrapper.tsx index 7d575292..b91b40d2 100644 --- a/packages/react-notion-x/src/components/asset-wrapper.tsx +++ b/packages/react-notion-x/src/components/asset-wrapper.tsx @@ -1,5 +1,5 @@ import type React from 'react' -import { type BaseContentBlock, type Block } from 'notion-types' +import { type BaseContentBlock, type Block, type ImageBlock } from 'notion-types' import { parsePageId } from 'notion-utils' import { useNotionContext } from '..' @@ -7,6 +7,19 @@ import { cs } from '../utils' import { Asset } from './asset' import { Text } from './text' +interface PageInfo { + type: 'page' + id: string + url: string +} + +interface ExternalInfo { + type: 'external' + url: string +} + +type URLInfo = PageInfo | ExternalInfo | null + const urlStyle = { width: '100%' } export function AssetWrapper({ @@ -19,18 +32,11 @@ export function AssetWrapper({ const value = block as BaseContentBlock const { components, mapPageUrl, rootDomain, zoom } = useNotionContext() - let isURL = false - if (block.type === 'image') { - const caption: string | undefined = value?.properties?.caption?.[0]?.[0] - if (caption) { - const id = parsePageId(caption, { uuid: true }) + const caption = value.properties?.caption?.[0]?.[0] + const imageHyperlink = (value as ImageBlock).format?.image_hyperlink + const linkToUse = imageHyperlink || caption || '' - const isPage = caption.charAt(0) === '/' && id - if (isPage || isValidURL(caption)) { - isURL = true - } - } - } + const urlInfo = getURLInfo(value, linkToUse) const figure = (
- - {value?.properties?.caption && !isURL && ( + + {value?.properties?.caption && (
@@ -52,23 +58,21 @@ export function AssetWrapper({ ) // allows for an image to be a link - if (isURL) { - const caption: string | undefined = value?.properties?.caption?.[0]?.[0] - const id = parsePageId(caption, { uuid: true }) - const isPage = caption?.charAt(0) === '/' && id - const captionHostname = extractHostname(caption) + if (urlInfo?.url) { + const urlHostName = extractHostname(urlInfo.url) + const isExternalLink = + urlHostName && urlHostName !== rootDomain && !caption?.startsWith('/') + + const href = + urlInfo.type === 'page' && urlInfo.id + ? mapPageUrl(urlInfo.id) + : urlInfo.url return ( {figure} @@ -77,6 +81,31 @@ export function AssetWrapper({ return figure } +function getURLInfo(block: BaseContentBlock, link?: string): URLInfo { + if (!link || block.type !== 'image') { + return null + } + + const id = parsePageId(link, { uuid: true }) + const isPage = link.charAt(0) === '/' && id + + if (isPage) { + return { + type: 'page' as const, + id, + url: link + } + } + + if (isValidURL(link)) { + return { + type: 'external' as const, + url: link + } + } + + return null +} function isValidURL(str: string) { // TODO: replace this with a more well-tested package @@ -91,7 +120,6 @@ function isValidURL(str: string) { ) return !!pattern.test(str) } - function extractHostname(url?: string) { try { const hostname = new URL(url!).hostname