import '../_common/components/embed-card/embed-card-caption.js';
import { PathFinder } from '@blockeditor/block-std';
import { assertExists } from '@blockeditor/global/utils';
import { flip, offset } from '@floating-ui/dom';
import { html, nothing } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ref } from 'lit/directives/ref.js';
import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.js';
import type { EmbedCardCaption } from '../_common/components/embed-card/embed-card-caption.js';
import { HoverController } from '../_common/components/hover/controller.js';
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH } from '../_common/consts.js';
import { EmbedBlockElement } from '../_common/embed-block-helper/embed-block-element.js';
import { OpenIcon } from '../_common/icons/text.js';
import { getEmbedCardIcons } from '../_common/utils/url.js';
import type { EmbedGithubStyles } from './embed-github-model.js';
import { type EmbedGithubModel, githubUrlRegex } from './embed-github-model.js';
import type { EmbedGithubService } from './embed-github-service.js';
import { GithubIcon, styles } from './styles.js';
import {
getGithubStatusIcon,
refreshEmbedGithubStatus,
refreshEmbedGithubUrlData,
} from './utils.js';
@customElement('affine-embed-github-block')
export class EmbedGithubBlockComponent extends EmbedBlockElement<
EmbedGithubModel,
EmbedGithubService
> {
static override styles = styles;
override _cardStyle: (typeof EmbedGithubStyles)[number] = 'horizontal';
@state()
private _isSelected = false;
@property({ attribute: false })
loading = false;
@state()
showCaption = false;
@query('embed-card-caption')
captionElement!: EmbedCardCaption;
open = () => {
let link = this.model.url;
if (!link.match(/^[a-zA-Z]+:\/\//)) {
link = 'https://' + link;
}
window.open(link, '_blank');
};
refreshData = () => {
refreshEmbedGithubUrlData(this).catch(console.error);
};
refreshStatus = () => {
refreshEmbedGithubStatus(this).catch(console.error);
};
private _selectBlock() {
const selectionManager = this.host.selection;
const blockSelection = selectionManager.create('block', {
path: this.path,
});
selectionManager.setGroup('note', [blockSelection]);
}
private _handleClick() {
if (!this.isInSurface) {
this._selectBlock();
}
}
private _handleDoubleClick(event: MouseEvent) {
event.stopPropagation();
this.open();
}
private _handleAssigneeClick(assignee: string) {
const link = `https://www.github.com/${assignee}`;
window.open(link, '_blank');
}
override connectedCallback() {
super.connectedCallback();
if (!!this.model.caption && !!this.model.caption.length) {
this.showCaption = true;
}
if (!this.model.owner || !this.model.repo || !this.model.githubId) {
this.page.withoutTransact(() => {
const url = this.model.url;
const urlMatch = url.match(githubUrlRegex);
if (urlMatch) {
const [, owner, repo, githubType, githubId] = urlMatch;
this.page.updateBlock(this.model, {
owner,
repo,
githubType: githubType === 'issue' ? 'issue' : 'pr',
githubId,
});
}
});
}
this.page.withoutTransact(() => {
if (!this.model.description && !this.model.title) this.refreshData();
else this.refreshStatus();
});
this.disposables.add(
this.model.propsUpdated.on(({ key }) => {
this.requestUpdate();
if (key === 'url') this.refreshData();
})
);
this.disposables.add(
this.selection.slots.changed.on(sels => {
this._isSelected = sels.some(sel =>
PathFinder.equals(sel.path, this.path)
);
})
);
if (this.isInSurface) {
const surface = this.surface;
assertExists(surface);
this.disposables.add(
this.model.propsUpdated.on(() => {
this.requestUpdate();
})
);
}
}
private _whenHover = new HoverController(this, ({ abortController }) => {
const selection = this.host.selection;
const textSelection = selection.find('text');
if (
!!textSelection &&
(!!textSelection.to || !!textSelection.from.length)
) {
return null;
}
const blockSelections = selection.filter('block');
if (
blockSelections.length > 1 ||
(blockSelections.length === 1 && blockSelections[0].path !== this.path)
) {
return null;
}
return {
template: html`