Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/notion-types/src/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
89 changes: 60 additions & 29 deletions packages/react-notion-x/src/components/asset-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import type * as 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 '..'
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({
Expand All @@ -19,18 +35,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 = (
<figure
Expand All @@ -41,8 +50,8 @@ export function AssetWrapper({
blockId
)}
>
<Asset block={value} zoomable={zoom && !isURL}>
{value?.properties?.caption && !isURL && (
<Asset block={value} zoomable={zoom && !urlInfo}>
{value?.properties?.caption && (
<figcaption className='notion-asset-caption'>
<Text value={value.properties.caption} block={block} />
</figcaption>
Expand All @@ -52,23 +61,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 (
<components.PageLink
style={urlStyle}
href={isPage ? mapPageUrl(id) : caption}
target={
captionHostname &&
captionHostname !== rootDomain &&
!caption?.startsWith('/')
? 'blank_'
: null
}
href={href}
target={isExternalLink ? 'blank_' : null}
>
{figure}
</components.PageLink>
Expand All @@ -77,6 +84,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
Expand All @@ -91,7 +123,6 @@ function isValidURL(str: string) {
)
return !!pattern.test(str)
}

function extractHostname(url?: string) {
try {
const hostname = new URL(url!).hostname
Expand Down