Skip to content

Commit

Permalink
feat(blocks): support embed linked doc and synced doc html block adap…
Browse files Browse the repository at this point in the history
  • Loading branch information
donteatfriedrice committed Dec 9, 2024
1 parent aaf7756 commit 0c26cad
Show file tree
Hide file tree
Showing 16 changed files with 719 additions and 44 deletions.
14 changes: 14 additions & 0 deletions packages/affine/block-embed/src/common/adapters/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { ReferenceParams } from '@blocksuite/affine-model';

import { toURLSearchParams } from '@blocksuite/affine-shared/adapters';

export function generateDocUrl(
docBaseUrl: string,
pageId: string,
params: ReferenceParams
) {
const search = toURLSearchParams(params);
const query = search?.size ? `?${search.toString()}` : '';
const url = docBaseUrl ? `${docBaseUrl}/${pageId}${query}` : '';
return url;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
import {
BlockHtmlAdapterExtension,
type BlockHtmlAdapterMatcher,
} from '@blocksuite/affine-shared/adapters';

import { generateDocUrl } from '../../common/adapters/utils.js';

export const embedLinkedDocBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
flavour: EmbedLinkedDocBlockSchema.model.flavour,
toMatch: () => false,
fromMatch: o => o.node.flavour === EmbedLinkedDocBlockSchema.model.flavour,
toBlockSnapshot: {},
fromBlockSnapshot: {
enter: (o, context) => {
const { configs, walkerContext } = context;
// Parse as link
if (!o.node.props.pageId) {
return;
}
const title = configs.get('title:' + o.node.props.pageId) ?? 'untitled';
const url = generateDocUrl(
configs.get('docLinkBaseUrl') ?? '',
String(o.node.props.pageId),
o.node.props.params ?? Object.create(null)
);

walkerContext
.openNode(
{
type: 'element',
tagName: 'div',
properties: {
className: ['affine-paragraph-block-container'],
},
children: [],
},
'children'
)
.openNode(
{
type: 'element',
tagName: 'a',
properties: {
href: url,
},
children: [
{
type: 'text',
value: title,
},
],
},
'children'
)
.closeNode()
.closeNode();
},
},
};

export const EmbedLinkedDocHtmlAdapterExtension = BlockHtmlAdapterExtension(
embedLinkedDocBlockHtmlAdapterMatcher
);
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './html.js';
export * from './markdown.js';
export * from './plain-text.js';
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
import {
BlockMarkdownAdapterExtension,
type BlockMarkdownAdapterMatcher,
toURLSearchParams,
} from '@blocksuite/affine-shared/adapters';

import { generateDocUrl } from '../../common/adapters/utils.js';

export const embedLinkedDocBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher =
{
flavour: EmbedLinkedDocBlockSchema.model.flavour,
Expand All @@ -19,11 +20,11 @@ export const embedLinkedDocBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatc
return;
}
const title = configs.get('title:' + o.node.props.pageId) ?? 'untitled';
const params = o.node.props.params ?? {};
const search = toURLSearchParams(params);
const query = search?.size ? `?${search.toString()}` : '';
const baseUrl = configs.get('docLinkBaseUrl') ?? '';
const url = baseUrl ? `${baseUrl}/${o.node.props.pageId}${query}` : '';
const url = generateDocUrl(
configs.get('docLinkBaseUrl') ?? '',
String(o.node.props.pageId),
o.node.props.params ?? Object.create(null)
);
walkerContext
.openNode(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
import {
BlockPlainTextAdapterExtension,
type BlockPlainTextAdapterMatcher,
toURLSearchParams,
} from '@blocksuite/affine-shared/adapters';

import { generateDocUrl } from '../../common/adapters/utils.js';

export const embedLinkedDocBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher =
{
flavour: EmbedLinkedDocBlockSchema.model.flavour,
Expand All @@ -19,11 +20,11 @@ export const embedLinkedDocBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMa
return;
}
const title = configs.get('title:' + o.node.props.pageId) ?? 'untitled';
const params = o.node.props.params ?? {};
const search = toURLSearchParams(params);
const query = search?.size ? `?${search.toString()}` : '';
const baseUrl = configs.get('docLinkBaseUrl') ?? '';
const url = baseUrl ? `${baseUrl}/${o.node.props.pageId}${query}` : '';
const url = generateDocUrl(
configs.get('docLinkBaseUrl') ?? '',
String(o.node.props.pageId),
o.node.props.params ?? Object.create(null)
);
textBuffer.content += `${title}: ${url}\n`;
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { EmbedSyncedDocBlockSchema } from '@blocksuite/affine-model';
import {
BlockHtmlAdapterExtension,
type BlockHtmlAdapterMatcher,
} from '@blocksuite/affine-shared/adapters';

export const embedSyncedDocBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
flavour: EmbedSyncedDocBlockSchema.model.flavour,
toMatch: () => false,
fromMatch: o => o.node.flavour === EmbedSyncedDocBlockSchema.model.flavour,
toBlockSnapshot: {},
fromBlockSnapshot: {
enter: async (o, context) => {
const { configs, walker, walkerContext, job } = context;
const type = configs.get('embedSyncedDocExportType');

// this context is used for nested sync block
if (
walkerContext.getGlobalContext('embed-synced-doc-counter') === undefined
) {
walkerContext.setGlobalContext('embed-synced-doc-counter', 0);
}
let counter = walkerContext.getGlobalContext(
'embed-synced-doc-counter'
) as number;
walkerContext.setGlobalContext('embed-synced-doc-counter', ++counter);

if (type === 'content') {
const syncedDocId = o.node.props.pageId as string;
const syncedDoc = job.collection.getDoc(syncedDocId);
walkerContext.setGlobalContext('hast:html-root-doc', false);
if (!syncedDoc) return;

if (counter === 1) {
const syncedSnapshot = await job.docToSnapshot(syncedDoc);
if (syncedSnapshot) {
await walker.walkONode(syncedSnapshot.blocks);
}
} else {
walkerContext
.openNode(
{
type: 'element',
tagName: 'div',
properties: {
className: ['affine-paragraph-block-container'],
},
children: [],
},
'children'
)
.openNode(
{
type: 'element',
tagName: 'p',
properties: {},
children: [
{ type: 'text', value: syncedDoc.meta?.title ?? '' },
],
},
'children'
)
.closeNode()
.closeNode();
}
}
},
leave: (_, context) => {
const { walkerContext } = context;
const counter = walkerContext.getGlobalContext(
'embed-synced-doc-counter'
) as number;
const currentCounter = counter - 1;
walkerContext.setGlobalContext(
'embed-synced-doc-counter',
currentCounter
);
// When leave the last embed synced doc block, we need to set the html root doc context to true
walkerContext.setGlobalContext(
'hast:html-root-doc',
currentCounter === 0
);
},
},
};

export const EmbedSyncedDocBlockHtmlAdapterExtension =
BlockHtmlAdapterExtension(embedSyncedDocBlockHtmlAdapterMatcher);
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './html.js';
export * from './markdown.js';
export * from './plain-text.js';
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ export const embedSyncedDocBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatc
},
};

export const EmbedSyncedDocMarkdownAdapterExtension =
export const EmbedSyncedDocBlockMarkdownAdapterExtension =
BlockMarkdownAdapterExtension(embedSyncedDocBlockMarkdownAdapterMatcher);
1 change: 1 addition & 0 deletions packages/affine/block-embed/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const EmbedExtensions: ExtensionType[] = [
export { createEmbedBlockHtmlAdapterMatcher } from './common/adapters/html.js';
export { createEmbedBlockMarkdownAdapterMatcher } from './common/adapters/markdown.js';
export { createEmbedBlockPlainTextAdapterMatcher } from './common/adapters/plain-text.js';
export { generateDocUrl } from './common/adapters/utils.js';
export { EmbedBlockComponent } from './common/embed-block-element.js';
export { insertEmbedCard } from './common/insert-embed-card.js';
export {
Expand Down
Loading

0 comments on commit 0c26cad

Please sign in to comment.