mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-02 01:49:51 +08:00
refactor(editor): unify directories naming (#11516)
**Directory Structure Changes** - Renamed multiple block-related directories by removing the "block-" prefix: - `block-attachment` → `attachment` - `block-bookmark` → `bookmark` - `block-callout` → `callout` - `block-code` → `code` - `block-data-view` → `data-view` - `block-database` → `database` - `block-divider` → `divider` - `block-edgeless-text` → `edgeless-text` - `block-embed` → `embed`
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import { EmbedFigmaBlockHtmlAdapterExtension } from './html.js';
|
||||
import { EmbedFigmaMarkdownAdapterExtension } from './markdown.js';
|
||||
import { EmbedFigmaBlockNotionHtmlAdapterExtension } from './notion-html.js';
|
||||
import { EmbedFigmaBlockPlainTextAdapterExtension } from './plain-text.js';
|
||||
|
||||
export const EmbedFigmaBlockAdapterExtensions: ExtensionType[] = [
|
||||
EmbedFigmaBlockHtmlAdapterExtension,
|
||||
EmbedFigmaMarkdownAdapterExtension,
|
||||
EmbedFigmaBlockPlainTextAdapterExtension,
|
||||
EmbedFigmaBlockNotionHtmlAdapterExtension,
|
||||
];
|
||||
@@ -0,0 +1,11 @@
|
||||
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
|
||||
import { BlockHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
|
||||
|
||||
import { createEmbedBlockHtmlAdapterMatcher } from '../../common/adapters/html.js';
|
||||
|
||||
export const embedFigmaBlockHtmlAdapterMatcher =
|
||||
createEmbedBlockHtmlAdapterMatcher(EmbedFigmaBlockSchema.model.flavour);
|
||||
|
||||
export const EmbedFigmaBlockHtmlAdapterExtension = BlockHtmlAdapterExtension(
|
||||
embedFigmaBlockHtmlAdapterMatcher
|
||||
);
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './html.js';
|
||||
export * from './markdown.js';
|
||||
export * from './notion-html.js';
|
||||
export * from './plain-text.js';
|
||||
@@ -0,0 +1,11 @@
|
||||
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
|
||||
import { BlockMarkdownAdapterExtension } from '@blocksuite/affine-shared/adapters';
|
||||
|
||||
import { createEmbedBlockMarkdownAdapterMatcher } from '../../common/adapters/markdown.js';
|
||||
|
||||
export const embedFigmaBlockMarkdownAdapterMatcher =
|
||||
createEmbedBlockMarkdownAdapterMatcher(EmbedFigmaBlockSchema.model.flavour);
|
||||
|
||||
export const EmbedFigmaMarkdownAdapterExtension = BlockMarkdownAdapterExtension(
|
||||
embedFigmaBlockMarkdownAdapterMatcher
|
||||
);
|
||||
@@ -0,0 +1,14 @@
|
||||
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
|
||||
import { BlockNotionHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
|
||||
|
||||
import { createEmbedBlockNotionHtmlAdapterMatcher } from '../../common/adapters/notion-html.js';
|
||||
import { figmaUrlRegex } from '../embed-figma-model.js';
|
||||
|
||||
export const embedFigmaBlockNotionHtmlAdapterMatcher =
|
||||
createEmbedBlockNotionHtmlAdapterMatcher(
|
||||
EmbedFigmaBlockSchema.model.flavour,
|
||||
figmaUrlRegex
|
||||
);
|
||||
|
||||
export const EmbedFigmaBlockNotionHtmlAdapterExtension =
|
||||
BlockNotionHtmlAdapterExtension(embedFigmaBlockNotionHtmlAdapterMatcher);
|
||||
@@ -0,0 +1,10 @@
|
||||
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
|
||||
import { BlockPlainTextAdapterExtension } from '@blocksuite/affine-shared/adapters';
|
||||
|
||||
import { createEmbedBlockPlainTextAdapterMatcher } from '../../common/adapters/plain-text.js';
|
||||
|
||||
export const embedFigmaBlockPlainTextAdapterMatcher =
|
||||
createEmbedBlockPlainTextAdapterMatcher(EmbedFigmaBlockSchema.model.flavour);
|
||||
|
||||
export const EmbedFigmaBlockPlainTextAdapterExtension =
|
||||
BlockPlainTextAdapterExtension(embedFigmaBlockPlainTextAdapterMatcher);
|
||||
@@ -0,0 +1,39 @@
|
||||
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
|
||||
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
|
||||
import { FigmaDuotoneIcon } from '@blocksuite/icons/lit';
|
||||
|
||||
import { FigmaTooltip } from './tooltips';
|
||||
|
||||
export const embedFigmaSlashMenuConfig: SlashMenuConfig = {
|
||||
items: [
|
||||
{
|
||||
name: 'Figma',
|
||||
description: 'Embed a Figma document.',
|
||||
icon: FigmaDuotoneIcon(),
|
||||
tooltip: {
|
||||
figure: FigmaTooltip,
|
||||
caption: 'Figma',
|
||||
},
|
||||
group: '4_Content & Media@8',
|
||||
when: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:embed-figma'),
|
||||
action: ({ std, model }) => {
|
||||
(async () => {
|
||||
const { host } = std;
|
||||
const parentModel = host.doc.getParent(model);
|
||||
if (!parentModel) {
|
||||
return;
|
||||
}
|
||||
const index = parentModel.children.indexOf(model) + 1;
|
||||
await toggleEmbedCardCreateModal(
|
||||
host,
|
||||
'Figma',
|
||||
'The added Figma link will be displayed as an embed view.',
|
||||
{ mode: 'page', parentModel, index }
|
||||
);
|
||||
if (model.text?.length === 0) std.store.deleteBlock(model);
|
||||
})().catch(console.error);
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,25 @@
|
||||
import { EdgelessClipboardConfig } from '@blocksuite/affine-block-surface';
|
||||
import { type BlockSnapshot } from '@blocksuite/store';
|
||||
|
||||
export class EdgelessClipboardEmbedFigmaConfig extends EdgelessClipboardConfig {
|
||||
static override readonly key = 'affine:embed-figma';
|
||||
|
||||
override createBlock(figmaEmbed: BlockSnapshot): string | null {
|
||||
if (!this.surface) return null;
|
||||
const { xywh, style, url, caption, title, description } = figmaEmbed.props;
|
||||
|
||||
const embedFigmaId = this.crud.addBlock(
|
||||
'affine:embed-figma',
|
||||
{
|
||||
xywh,
|
||||
style,
|
||||
url,
|
||||
caption,
|
||||
title,
|
||||
description,
|
||||
},
|
||||
this.surface.model.id
|
||||
);
|
||||
return embedFigmaId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { toEdgelessEmbedBlock } from '../common/to-edgeless-embed-block.js';
|
||||
import { EmbedFigmaBlockComponent } from './embed-figma-block.js';
|
||||
|
||||
export class EmbedEdgelessBlockComponent extends toEdgelessEmbedBlock(
|
||||
EmbedFigmaBlockComponent
|
||||
) {}
|
||||
@@ -0,0 +1,130 @@
|
||||
import { OpenIcon } from '@blocksuite/affine-components/icons';
|
||||
import type {
|
||||
EmbedFigmaModel,
|
||||
EmbedFigmaStyles,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { BlockSelection } from '@blocksuite/std';
|
||||
import { html, nothing } from 'lit';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import { EmbedBlockComponent } from '../common/embed-block-element.js';
|
||||
import { FigmaIcon, styles } from './styles.js';
|
||||
|
||||
export class EmbedFigmaBlockComponent extends EmbedBlockComponent<EmbedFigmaModel> {
|
||||
static override styles = styles;
|
||||
|
||||
override _cardStyle: (typeof EmbedFigmaStyles)[number] = 'figma';
|
||||
|
||||
open = () => {
|
||||
let link = this.model.props.url;
|
||||
if (!link.match(/^[a-zA-Z]+:\/\//)) {
|
||||
link = 'https://' + link;
|
||||
}
|
||||
window.open(link, '_blank');
|
||||
};
|
||||
|
||||
refreshData = () => {};
|
||||
|
||||
private _handleDoubleClick(event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
this.open();
|
||||
}
|
||||
|
||||
private _selectBlock() {
|
||||
const selectionManager = this.host.selection;
|
||||
const blockSelection = selectionManager.create(BlockSelection, {
|
||||
blockId: this.blockId,
|
||||
});
|
||||
selectionManager.setGroup('note', [blockSelection]);
|
||||
}
|
||||
|
||||
protected _handleClick(event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
this._selectBlock();
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._cardStyle = this.model.props.style;
|
||||
|
||||
if (!this.model.props.title) {
|
||||
this.doc.withoutTransact(() => {
|
||||
this.doc.updateBlock(this.model, {
|
||||
title: 'Figma',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.disposables.add(
|
||||
this.model.propsUpdated.subscribe(({ key }) => {
|
||||
if (key === 'url') {
|
||||
this.refreshData();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
override renderBlock() {
|
||||
const { title, description, url } = this.model.props;
|
||||
const titleText = title ?? 'Figma';
|
||||
|
||||
return this.renderEmbed(
|
||||
() => html`
|
||||
<div
|
||||
class=${classMap({
|
||||
'affine-embed-figma-block': true,
|
||||
selected: this.selected$.value,
|
||||
})}
|
||||
style=${styleMap({
|
||||
transform: `scale(${this._scale})`,
|
||||
transformOrigin: '0 0',
|
||||
})}
|
||||
@click=${this._handleClick}
|
||||
@dblclick=${this._handleDoubleClick}
|
||||
>
|
||||
<div class="affine-embed-figma">
|
||||
<div class="affine-embed-figma-iframe-container">
|
||||
<iframe
|
||||
src=${`https://www.figma.com/embed?embed_host=blocksuite&url=${url}`}
|
||||
allowfullscreen
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
|
||||
<!-- overlay to prevent the iframe from capturing pointer events -->
|
||||
<div
|
||||
class=${classMap({
|
||||
'affine-embed-figma-iframe-overlay': true,
|
||||
hide: !this.showOverlay$.value,
|
||||
})}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="affine-embed-figma-content">
|
||||
<div class="affine-embed-figma-content-header">
|
||||
<div class="affine-embed-figma-content-title-icon">
|
||||
${FigmaIcon}
|
||||
</div>
|
||||
|
||||
<div class="affine-embed-figma-content-title-text">
|
||||
${titleText}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${description
|
||||
? html`<div class="affine-embed-figma-content-description">
|
||||
${description}
|
||||
</div>`
|
||||
: nothing}
|
||||
|
||||
<div class="affine-embed-figma-content-url" @click=${this.open}>
|
||||
<span>www.figma.com</span>
|
||||
|
||||
<div class="affine-embed-figma-content-url-icon">${OpenIcon}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export const figmaUrlRegex: RegExp =
|
||||
/https:\/\/[\w.-]+\.?figma.com\/([\w-]+)\/([0-9a-zA-Z]{22,128})(?:\/.*)?$/;
|
||||
@@ -0,0 +1,14 @@
|
||||
import {
|
||||
EmbedFigmaBlockSchema,
|
||||
EmbedFigmaStyles,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { EmbedOptionConfig } from '@blocksuite/affine-shared/services';
|
||||
|
||||
import { figmaUrlRegex } from './embed-figma-model.js';
|
||||
|
||||
export const EmbedFigmaBlockOptionConfig = EmbedOptionConfig({
|
||||
flavour: EmbedFigmaBlockSchema.model.flavour,
|
||||
urlRegex: figmaUrlRegex,
|
||||
styles: EmbedFigmaStyles,
|
||||
viewType: 'embed',
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
|
||||
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
|
||||
import { BlockViewExtension, FlavourExtension } from '@blocksuite/std';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
import { literal } from 'lit/static-html.js';
|
||||
|
||||
import { createBuiltinToolbarConfigExtension } from '../configs/toolbar';
|
||||
import { EmbedFigmaBlockAdapterExtensions } from './adapters/extension';
|
||||
import { embedFigmaSlashMenuConfig } from './configs/slash-menu';
|
||||
import { EmbedFigmaBlockComponent } from './embed-figma-block';
|
||||
import { EmbedFigmaBlockOptionConfig } from './embed-figma-service';
|
||||
|
||||
const flavour = EmbedFigmaBlockSchema.model.flavour;
|
||||
|
||||
export const EmbedFigmaBlockSpec: ExtensionType[] = [
|
||||
FlavourExtension(flavour),
|
||||
BlockViewExtension(flavour, model => {
|
||||
return model.parent?.flavour === 'affine:surface'
|
||||
? literal`affine-embed-edgeless-figma-block`
|
||||
: literal`affine-embed-figma-block`;
|
||||
}),
|
||||
EmbedFigmaBlockAdapterExtensions,
|
||||
EmbedFigmaBlockOptionConfig,
|
||||
createBuiltinToolbarConfigExtension(flavour, EmbedFigmaBlockComponent),
|
||||
SlashMenuConfigExtension(flavour, embedFigmaSlashMenuConfig),
|
||||
].flat();
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from './adapters/index.js';
|
||||
export * from './edgeless-clipboard-config';
|
||||
export * from './embed-figma-block.js';
|
||||
export * from './embed-figma-model.js';
|
||||
export * from './embed-figma-spec.js';
|
||||
export { FigmaIcon } from './styles.js';
|
||||
@@ -0,0 +1,225 @@
|
||||
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
||||
import { css, html } from 'lit';
|
||||
|
||||
export const styles = css`
|
||||
.affine-embed-figma-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
padding: 12px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--affine-background-tertiary-color);
|
||||
|
||||
opacity: var(--add, 1);
|
||||
background: var(--affine-background-primary-color);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.affine-embed-figma {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
opacity: var(--add, 1);
|
||||
}
|
||||
|
||||
.affine-embed-figma img,
|
||||
.affine-embed-figma object,
|
||||
.affine-embed-figma svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 4px 4px var(--1, 0px) var(--1, 0px);
|
||||
}
|
||||
|
||||
.affine-embed-figma-iframe-container {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.affine-embed-figma-iframe-container > iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px 4px var(--1, 0px) var(--1, 0px);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.affine-embed-figma-iframe-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.affine-embed-figma-iframe-overlay.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.affine-embed-figma-content {
|
||||
display: block;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
border-radius: var(--1, 0px);
|
||||
opacity: var(--add, 1);
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
|
||||
align-self: stretch;
|
||||
padding: var(--1, 0px);
|
||||
border-radius: var(--1, 0px);
|
||||
opacity: var(--add, 1);
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-title-icon {
|
||||
display: flex;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-title-icon img,
|
||||
.affine-embed-figma-content-title-icon object,
|
||||
.affine-embed-figma-content-title-icon svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: var(--affine-background-primary-color);
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-title-text {
|
||||
flex: 1 0 0;
|
||||
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
word-break: break-word;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--affine-text-primary-color);
|
||||
|
||||
font-family: var(--affine-font-family);
|
||||
font-size: var(--affine-font-sm);
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-description {
|
||||
height: 40px;
|
||||
|
||||
position: relative;
|
||||
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--affine-text-primary-color);
|
||||
|
||||
font-family: var(--affine-font-family);
|
||||
font-size: var(--affine-font-xs);
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-description::after {
|
||||
content: '...';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--affine-background-primary-color);
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-url {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 4px;
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.affine-embed-figma-content-url > span {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: ${unsafeCSSVarV2('icon/primary')};
|
||||
|
||||
font-family: var(--affine-font-family);
|
||||
font-size: var(--affine-font-xs);
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
}
|
||||
.affine-embed-figma-content-url:hover > span {
|
||||
color: var(--affine-link-color);
|
||||
}
|
||||
.affine-embed-figma-content-url:hover .open-icon {
|
||||
fill: var(--affine-link-color);
|
||||
}
|
||||
|
||||
.affine-embed-figma-content-url-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
.affine-embed-figma-content-url-icon svg {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
fill: ${unsafeCSSVarV2('icon/primary')};
|
||||
}
|
||||
|
||||
.affine-embed-figma-block.selected {
|
||||
.affine-embed-figma-content-url > span {
|
||||
color: var(--affine-link-color);
|
||||
}
|
||||
.affine-embed-figma-content-url .open-icon {
|
||||
fill: var(--affine-link-color);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const FigmaIcon = html`<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.66898 17.9165C9.00426 17.9165 10.088 16.7342 10.088 15.2776V12.6387H7.66898C6.3337 12.6387 5.25 13.8209 5.25 15.2776C5.25 16.7342 6.3337 17.9165 7.66898 17.9165Z"
|
||||
fill="#0ACF83"
|
||||
/>
|
||||
<path
|
||||
d="M5.25 10.0002C5.25 8.54355 6.3337 7.36133 7.66898 7.36133H10.088V12.6391H7.66898C6.3337 12.6391 5.25 11.4569 5.25 10.0002Z"
|
||||
fill="#A259FF"
|
||||
/>
|
||||
<path
|
||||
d="M5.25 4.72238C5.25 3.26572 6.3337 2.0835 7.66898 2.0835H10.088V7.36127H7.66898C6.3337 7.36127 5.25 6.17905 5.25 4.72238Z"
|
||||
fill="#F24E1E"
|
||||
/>
|
||||
<path
|
||||
d="M10.0879 2.0835H12.5069C13.8421 2.0835 14.9259 3.26572 14.9259 4.72238C14.9259 6.17905 13.8421 7.36127 12.5069 7.36127H10.0879V2.0835Z"
|
||||
fill="#FF7262"
|
||||
/>
|
||||
<path
|
||||
d="M14.9259 10.0002C14.9259 11.4569 13.8421 12.6391 12.5069 12.6391C11.1716 12.6391 10.0879 11.4569 10.0879 10.0002C10.0879 8.54355 11.1716 7.36133 12.5069 7.36133C13.8421 7.36133 14.9259 8.54355 14.9259 10.0002Z"
|
||||
fill="#1ABCFE"
|
||||
/>
|
||||
</svg>`;
|
||||
Reference in New Issue
Block a user