Skip to content

Commit

Permalink
feat(text): support Link Mention format
Browse files Browse the repository at this point in the history
- Fixed an issue where the newly introduced "Link Mention" feature in Notion was unsupported, causing an "unsupported text format" error.
- Now, it's correctly rendered in a way similar to Notion's functionality.
  • Loading branch information
nightohl committed Feb 17, 2025
1 parent b2682fe commit ba12aee
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/notion-types/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export type InlineEquationFormat = ['e', string]
export type DiscussionFormat = ['m', string]
export type ExternalLinkFormat = ['‣', [string, string]]
export type DateFormat = ['d', FormattedDate]
export type LinkMentionFormat = ['lm', string]

export interface FormattedDate {
type: 'date' | 'daterange' | 'datetime' | 'datetimerange'
Expand All @@ -145,6 +146,7 @@ export type SubDecoration =
| ExternalLinkFormat
| DiscussionFormat
| ExternalObjectInstanceFormat
| LinkMentionFormat

export type BaseDecoration = [string]
export type AdditionalDecoration = [string, SubDecoration[]]
Expand Down
72 changes: 72 additions & 0 deletions packages/react-notion-x/src/components/link-mention.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as React from 'react'

export type LinkMentionData = {
href: string
title: string
icon_url: string
description: string
link_provider: string
thumbnail_url: string
}

export function LinkMention({ metadata }: { metadata: LinkMentionData }) {
return (
<span className='notion-link-mention'>
<LinkMentionInline metadata={metadata} />
<LinkMentionPreview metadata={metadata} />
</span>
)
}

function LinkMentionInline({ metadata }: { metadata: LinkMentionData }) {
return (
<a
href={metadata.href}
target='_blank'
rel='noopener noreferrer'
className='notion-link-mention-link'
>
<img
className='notion-link-mention-icon'
src={metadata.icon_url}
alt={metadata.link_provider}
/>
{metadata.link_provider && (
<span className='notion-link-mention-provider'>
{metadata.link_provider}
</span>
)}
<span className='notion-link-mention-title'>{metadata.title}</span>
</a>
)
}

function LinkMentionPreview({ metadata }: { metadata: LinkMentionData }) {
return (
<div className='notion-link-mention-preview'>
<article className='notion-link-mention-card'>
<img
className='notion-link-mention-preview-thumbnail'
src={metadata.thumbnail_url}
alt={metadata.title}
/>
<div className='notion-link-mention-preview-content'>
<p className='notion-link-mention-preview-title'>{metadata.title}</p>
<p className='notion-link-mention-preview-description'>
{metadata.description}
</p>
<div className='notion-link-mention-preview-footer'>
<img
className='notion-link-mention-preview-icon'
src={metadata.icon_url}
alt={metadata.link_provider}
/>
<span className='notion-link-mention-preview-provider'>
{metadata.link_provider}
</span>
</div>
</div>
</article>
</div>
)
}
7 changes: 7 additions & 0 deletions packages/react-notion-x/src/components/text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { formatDate, getHashFragmentValue } from '../utils'
import { EOI } from './eoi'
import { GracefulImage } from './graceful-image'
import { PageTitle } from './page-title'
import { LinkMention, type LinkMentionData } from './link-mention'

/**
* Renders a single piece of Notion text, including basic rich text formatting.
Expand All @@ -20,6 +21,7 @@ import { PageTitle } from './page-title'
* TODO: I think this implementation would be more correct if the reduce just added
* attributes to the final element's style.
*/

export function Text({
value,
block,
Expand Down Expand Up @@ -244,6 +246,11 @@ export function Text({
)
}

case 'lm': {
const metadata = decorator[1] as unknown as LinkMentionData
return <LinkMention metadata={metadata} />
}

case 'eoi': {
const blockId = decorator[1]
const externalObjectInstance = recordMap.block[blockId]
Expand Down
107 changes: 107 additions & 0 deletions packages/react-notion-x/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -2976,3 +2976,110 @@ svg.notion-page-icon {
text-decoration: underline;
cursor: pointer;
}

/* Link Mention Styles */
.notion-link-mention {
position: relative;
display: inline-flex;
align-items: center;
vertical-align: middle;
}

.notion-link-mention-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}

.notion-link-mention-icon {
width: 1.5rem;
height: 1.5rem;
border-radius: 0.375rem;
}

.notion-link-mention-provider {
font-size: 0.875rem;
color: var(--fg-color);
}

.notion-link-mention-title {
font-size: 0.875rem;
font-weight: 600;
color: var(--fg-color);
}

/* Preview card (appears on hover) */
.notion-link-mention-preview {
display: none;
position: absolute;
top: 100%;
left: 0;
margin-top: 0.5rem;
z-index: 100000;
}

.notion-link-mention:hover .notion-link-mention-preview {
display: block;
}

.notion-link-mention-card {
width: 18rem;
height: 15rem;
background: var(--bg-color);
border-radius: 0.75rem;
border: 1px solid rgba(27, 31, 36, 0.15);
overflow: hidden;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
}

.notion-link-mention-preview-thumbnail {
width: 100%;
height: 55%;
object-fit: cover;
}

.notion-link-mention-preview-content {
display: flex;
flex-direction: column;
height: 45%;
padding: 0.5rem 1rem;
gap: 0.125rem;
}

.notion-link-mention-preview-title {
font-size: 0.875rem;
font-weight: 700;
color: var(--fg-color);
margin: 0;
}

.notion-link-mention-preview-description {
font-size: 0.875rem;
color: var(--fg-color);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
margin: 0;
}

.notion-link-mention-preview-footer {
display: flex;
align-items: center;
gap: 0.375rem;
margin-top: auto;
padding-bottom: 0.5rem;
}

.notion-link-mention-preview-icon {
width: 1rem;
height: 1rem;
border-radius: 0.25rem;
}

.notion-link-mention-preview-provider {
font-size: 0.875rem;
color: var(--fg-color-2);
}

0 comments on commit ba12aee

Please sign in to comment.