mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-06 00:41:39 +08:00
refactor(editor): move menu context to components (#9302)
This commit is contained in:
@@ -1,228 +0,0 @@
|
||||
import {
|
||||
CenterPeekIcon,
|
||||
CopyIcon,
|
||||
DeleteIcon,
|
||||
DuplicateIcon,
|
||||
OpenIcon,
|
||||
RefreshIcon,
|
||||
} from '@blocksuite/affine-components/icons';
|
||||
import { isPeekable, peek } from '@blocksuite/affine-components/peek';
|
||||
import { toast } from '@blocksuite/affine-components/toast';
|
||||
import { getBlockProps } from '@blocksuite/affine-shared/utils';
|
||||
import { WithDisposable } from '@blocksuite/global/utils';
|
||||
import { Slice } from '@blocksuite/store';
|
||||
import { css, html, LitElement, nothing } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
|
||||
import {
|
||||
isEmbedLinkedDocBlock,
|
||||
isEmbedSyncedDocBlock,
|
||||
} from '../../../root-block/edgeless/utils/query.js';
|
||||
import type { EmbedBlockComponent } from './type.js';
|
||||
|
||||
export class EmbedCardMoreMenu extends WithDisposable(LitElement) {
|
||||
static override styles = css`
|
||||
.embed-card-more-menu {
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.embed-card-more-menu-container {
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
background: var(--affine-background-overlay-panel-color);
|
||||
box-shadow: var(--affine-shadow-2);
|
||||
}
|
||||
|
||||
.embed-card-more-menu-container > .menu-item {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.embed-card-more-menu-container > .menu-item:hover {
|
||||
background: var(--affine-hover-color);
|
||||
}
|
||||
|
||||
.embed-card-more-menu-container > .menu-item:hover.delete {
|
||||
background: var(--affine-background-error-color);
|
||||
color: var(--affine-error-color);
|
||||
}
|
||||
.embed-card-more-menu-container > .menu-item:hover.delete > svg {
|
||||
color: var(--affine-error-color);
|
||||
}
|
||||
|
||||
.embed-card-more-menu-container > .menu-item svg {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.embed-card-more-menu-container > .divider {
|
||||
width: 148px;
|
||||
height: 1px;
|
||||
margin: 8px;
|
||||
background-color: var(--affine-border-color);
|
||||
}
|
||||
`;
|
||||
|
||||
private get _doc() {
|
||||
return this.block.doc;
|
||||
}
|
||||
|
||||
private get _model() {
|
||||
return this.block.model;
|
||||
}
|
||||
|
||||
get _openButtonDisabled() {
|
||||
return (
|
||||
isEmbedLinkedDocBlock(this._model) && this._model.pageId === this._doc.id
|
||||
);
|
||||
}
|
||||
|
||||
private get _std() {
|
||||
return this.block.std;
|
||||
}
|
||||
|
||||
private async _copyBlock() {
|
||||
const slice = Slice.fromModels(this._doc, [this._model]);
|
||||
await this._std.clipboard.copySlice(slice);
|
||||
toast(this.block.host, 'Copied link to clipboard');
|
||||
this.abortController.abort();
|
||||
}
|
||||
|
||||
private _duplicateBlock() {
|
||||
const model = this._model;
|
||||
const blockProps = getBlockProps(model);
|
||||
const {
|
||||
width: _width,
|
||||
height: _height,
|
||||
xywh: _xywh,
|
||||
rotate: _rotate,
|
||||
zIndex: _zIndex,
|
||||
...duplicateProps
|
||||
} = blockProps;
|
||||
|
||||
const { doc } = model;
|
||||
const parent = doc.getParent(model);
|
||||
const index = parent?.children.indexOf(model);
|
||||
doc.addBlock(
|
||||
model.flavour as BlockSuite.Flavour,
|
||||
duplicateProps,
|
||||
parent,
|
||||
index
|
||||
);
|
||||
this.abortController.abort();
|
||||
}
|
||||
|
||||
private _open() {
|
||||
this.block.open();
|
||||
this.abortController.abort();
|
||||
}
|
||||
|
||||
private _peek() {
|
||||
peek(this.block);
|
||||
}
|
||||
|
||||
private _peekable() {
|
||||
return isPeekable(this.block);
|
||||
}
|
||||
|
||||
private _refreshData() {
|
||||
this.block.refreshData();
|
||||
this.abortController.abort();
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<div class="embed-card-more-menu">
|
||||
<div
|
||||
class="embed-card-more-menu-container"
|
||||
@pointerdown=${(e: MouseEvent) => e.stopPropagation()}
|
||||
>
|
||||
<icon-button
|
||||
width="126px"
|
||||
height="32px"
|
||||
class="menu-item open"
|
||||
text="Open"
|
||||
@click=${() => this._open()}
|
||||
?disabled=${this._openButtonDisabled}
|
||||
>
|
||||
${OpenIcon}
|
||||
</icon-button>
|
||||
|
||||
${this._peekable()
|
||||
? html`<icon-button
|
||||
width="126px"
|
||||
height="32px"
|
||||
text="Open in center peek"
|
||||
class="menu-item center-peek"
|
||||
@click=${() => this._peek()}
|
||||
>
|
||||
${CenterPeekIcon}
|
||||
</icon-button>`
|
||||
: nothing}
|
||||
|
||||
<icon-button
|
||||
width="126px"
|
||||
height="32px"
|
||||
class="menu-item copy"
|
||||
text="Copy"
|
||||
@click=${() => this._copyBlock()}
|
||||
>
|
||||
${CopyIcon}
|
||||
</icon-button>
|
||||
|
||||
<icon-button
|
||||
width="126px"
|
||||
height="32px"
|
||||
class="menu-item duplicate"
|
||||
text="Duplicate"
|
||||
?disabled=${this._doc.readonly}
|
||||
@click=${() => this._duplicateBlock()}
|
||||
>
|
||||
${DuplicateIcon}
|
||||
</icon-button>
|
||||
|
||||
${isEmbedLinkedDocBlock(this._model) ||
|
||||
isEmbedSyncedDocBlock(this._model)
|
||||
? nothing
|
||||
: html`<icon-button
|
||||
width="126px"
|
||||
height="32px"
|
||||
class="menu-item reload"
|
||||
text="Reload"
|
||||
?disabled=${this._doc.readonly}
|
||||
@click=${() => this._refreshData()}
|
||||
>
|
||||
${RefreshIcon}
|
||||
</icon-button>`}
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<icon-button
|
||||
width="126px"
|
||||
height="32px"
|
||||
class="menu-item delete"
|
||||
text="Delete"
|
||||
?disabled=${this._doc.readonly}
|
||||
@click=${() => this._doc.deleteBlock(this._model)}
|
||||
>
|
||||
${DeleteIcon}
|
||||
</icon-button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor abortController!: AbortController;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor block!: EmbedBlockComponent;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'embed-card-more-menu': EmbedCardMoreMenu;
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
import type {
|
||||
BookmarkBlockModel,
|
||||
ColorScheme,
|
||||
EmbedGithubModel,
|
||||
EmbedLinkedDocModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { WithDisposable } from '@blocksuite/global/utils';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
|
||||
import type { EmbedCardStyle } from '../../types.js';
|
||||
import { getEmbedCardIcons } from '../../utils/url.js';
|
||||
|
||||
export class EmbedCardStyleMenu extends WithDisposable(LitElement) {
|
||||
static override styles = css`
|
||||
.embed-card-style-menu {
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.embed-card-style-menu-container {
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: var(--affine-background-overlay-panel-color);
|
||||
box-shadow: var(--affine-shadow-2);
|
||||
}
|
||||
|
||||
.embed-card-style-menu-container > icon-button {
|
||||
padding: var(--1, 0px);
|
||||
}
|
||||
|
||||
.embed-card-style-menu-container > icon-button.selected {
|
||||
border: 1px solid var(--affine-brand-color);
|
||||
}
|
||||
`;
|
||||
|
||||
private _setEmbedCardStyle(style: EmbedCardStyle) {
|
||||
this.model.doc.updateBlock(this.model, { style });
|
||||
this.requestUpdate();
|
||||
this.abortController.abort();
|
||||
}
|
||||
|
||||
override render() {
|
||||
const { EmbedCardHorizontalIcon, EmbedCardListIcon } = getEmbedCardIcons(
|
||||
this.theme
|
||||
);
|
||||
return html`
|
||||
<div class="embed-card-style-menu">
|
||||
<div
|
||||
class="embed-card-style-menu-container"
|
||||
@pointerdown=${(e: MouseEvent) => e.stopPropagation()}
|
||||
>
|
||||
<icon-button
|
||||
width="76px"
|
||||
height="76px"
|
||||
class=${classMap({
|
||||
selected: this.model.style === 'horizontal',
|
||||
'card-style-button-horizontal': true,
|
||||
})}
|
||||
@click=${() => this._setEmbedCardStyle('horizontal')}
|
||||
>
|
||||
${EmbedCardHorizontalIcon}
|
||||
<affine-tooltip .offset=${4}
|
||||
>${'Large horizontal style'}</affine-tooltip
|
||||
>
|
||||
</icon-button>
|
||||
|
||||
<icon-button
|
||||
width="76px"
|
||||
height="76px"
|
||||
class=${classMap({
|
||||
selected: this.model.style === 'list',
|
||||
'card-style-button-list': true,
|
||||
})}
|
||||
@click=${() => this._setEmbedCardStyle('list')}
|
||||
>
|
||||
${EmbedCardListIcon}
|
||||
<affine-tooltip .offset=${4}
|
||||
>${'Small horizontal style'}</affine-tooltip
|
||||
>
|
||||
</icon-button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor abortController!: AbortController;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor model!: BookmarkBlockModel | EmbedGithubModel | EmbedLinkedDocModel;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor theme!: ColorScheme;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'embed-card-style-menu': EmbedCardStyleMenu;
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -1,4 +1,9 @@
|
||||
import { toast } from '@blocksuite/affine-components/toast';
|
||||
import type { EmbedCardStyle } from '@blocksuite/affine-model';
|
||||
import {
|
||||
EMBED_CARD_HEIGHT,
|
||||
EMBED_CARD_WIDTH,
|
||||
} from '@blocksuite/affine-shared/consts';
|
||||
import { EmbedOptionProvider } from '@blocksuite/affine-shared/services';
|
||||
import type { EditorHost } from '@blocksuite/block-std';
|
||||
import { ShadowlessElement } from '@blocksuite/block-std';
|
||||
@@ -14,8 +19,6 @@ import { property, query, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
|
||||
import type { EdgelessRootBlockComponent } from '../../../../root-block/edgeless/edgeless-root-block.js';
|
||||
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH } from '../../../consts.js';
|
||||
import type { EmbedCardStyle } from '../../../types.js';
|
||||
import { getRootByEditorHost, isValidUrl } from '../../../utils/index.js';
|
||||
import { embedCardModalStyles } from './styles.js';
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from '@blocksuite/affine-shared/consts';
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { BlockSnapshot, SliceSnapshot } from '@blocksuite/store';
|
||||
|
||||
import {
|
||||
mergeToCodeModel,
|
||||
transformModel,
|
||||
} from '../../root-block/utils/operations/model.js';
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import type { BlockSnapshot, SliceSnapshot } from '@blocksuite/store';
|
||||
|
||||
class DocTestUtils {
|
||||
// block model operations (data layer)
|
||||
|
||||
@@ -6,11 +6,10 @@ import type {
|
||||
ParagraphBlockModel,
|
||||
SurfaceRefBlockModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { DEFAULT_IMAGE_PROXY_ENDPOINT } from '@blocksuite/affine-shared/consts';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { DeltaOperation, JobMiddleware } from '@blocksuite/store';
|
||||
|
||||
import { DEFAULT_IMAGE_PROXY_ENDPOINT } from '../consts.js';
|
||||
|
||||
export const replaceIdMiddleware: JobMiddleware = ({ slots, collection }) => {
|
||||
const idMap = new Map<string, string>();
|
||||
slots.afterImport.on(payload => {
|
||||
|
||||
@@ -1,55 +1,8 @@
|
||||
import {
|
||||
DarkLoadingIcon,
|
||||
EmbedCardDarkBannerIcon,
|
||||
EmbedCardDarkCubeIcon,
|
||||
EmbedCardDarkHorizontalIcon,
|
||||
EmbedCardDarkListIcon,
|
||||
EmbedCardDarkVerticalIcon,
|
||||
EmbedCardLightBannerIcon,
|
||||
EmbedCardLightCubeIcon,
|
||||
EmbedCardLightHorizontalIcon,
|
||||
EmbedCardLightListIcon,
|
||||
EmbedCardLightVerticalIcon,
|
||||
LightLoadingIcon,
|
||||
} from '@blocksuite/affine-components/icons';
|
||||
import {
|
||||
ColorScheme,
|
||||
type DocMode,
|
||||
DocModes,
|
||||
type ReferenceInfo,
|
||||
} from '@blocksuite/affine-model';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
type EmbedCardIcons = {
|
||||
LoadingIcon: TemplateResult<1>;
|
||||
EmbedCardBannerIcon: TemplateResult<1>;
|
||||
EmbedCardHorizontalIcon: TemplateResult<1>;
|
||||
EmbedCardListIcon: TemplateResult<1>;
|
||||
EmbedCardVerticalIcon: TemplateResult<1>;
|
||||
EmbedCardCubeIcon: TemplateResult<1>;
|
||||
};
|
||||
|
||||
export function getEmbedCardIcons(theme: ColorScheme): EmbedCardIcons {
|
||||
if (theme === ColorScheme.Light) {
|
||||
return {
|
||||
LoadingIcon: LightLoadingIcon,
|
||||
EmbedCardBannerIcon: EmbedCardLightBannerIcon,
|
||||
EmbedCardHorizontalIcon: EmbedCardLightHorizontalIcon,
|
||||
EmbedCardListIcon: EmbedCardLightListIcon,
|
||||
EmbedCardVerticalIcon: EmbedCardLightVerticalIcon,
|
||||
EmbedCardCubeIcon: EmbedCardLightCubeIcon,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
LoadingIcon: DarkLoadingIcon,
|
||||
EmbedCardBannerIcon: EmbedCardDarkBannerIcon,
|
||||
EmbedCardHorizontalIcon: EmbedCardDarkHorizontalIcon,
|
||||
EmbedCardListIcon: EmbedCardDarkListIcon,
|
||||
EmbedCardVerticalIcon: EmbedCardDarkVerticalIcon,
|
||||
EmbedCardCubeIcon: EmbedCardDarkCubeIcon,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function extractSearchParams(link: string) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user