import { LoadingIcon, OpenIcon } from '@blocksuite/affine-components/icons'; import type { EmbedGithubModel, EmbedGithubStyles, } from '@blocksuite/affine-model'; import { ImageProxyService } from '@blocksuite/affine-shared/adapters'; import { ThemeProvider } from '@blocksuite/affine-shared/services'; import { BlockSelection, isGfxBlockComponent } from '@blocksuite/std'; import { html, nothing } from 'lit'; import { property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { repeat } from 'lit/directives/repeat.js'; import { styleMap } from 'lit/directives/style-map.js'; import { EmbedBlockComponent } from '../common/embed-block-element.js'; import { getEmbedCardIcons } from '../common/utils.js'; import { githubUrlRegex } from './embed-github-model.js'; import type { EmbedGithubBlockService } from './embed-github-service.js'; import { GithubIcon, styles } from './styles.js'; import { getGithubStatusIcon, refreshEmbedGithubStatus, refreshEmbedGithubUrlData, } from './utils.js'; export class EmbedGithubBlockComponent extends EmbedBlockComponent< EmbedGithubModel, EmbedGithubBlockService > { static override styles = styles; override _cardStyle: (typeof EmbedGithubStyles)[number] = 'horizontal'; open = () => { let link = this.model.props.url; if (!link.match(/^[a-zA-Z]+:\/\//)) { link = 'https://' + link; } window.open(link, '_blank'); }; refreshData = () => { refreshEmbedGithubUrlData(this, this.fetchAbortController.signal).catch( console.error ); }; refreshStatus = () => { refreshEmbedGithubStatus(this, this.fetchAbortController.signal).catch( console.error ); }; private _handleAssigneeClick(assignee: string) { const link = `https://www.github.com/${assignee}`; window.open(link, '_blank'); } 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.owner || !this.model.props.repo || !this.model.props.githubId ) { this.store.withoutTransact(() => { const url = this.model.props.url; const urlMatch = url.match(githubUrlRegex); if (urlMatch) { const [, owner, repo, githubType, githubId] = urlMatch; this.store.updateBlock(this.model, { owner, repo, githubType: githubType === 'issue' ? 'issue' : 'pr', githubId, }); } }); } this.store.withoutTransact(() => { if (!this.model.props.description && !this.model.props.title) { this.refreshData(); } else { this.refreshStatus(); } }); this.disposables.add( this.model.propsUpdated.subscribe(({ key }) => { if (key === 'url') { this.refreshData(); } }) ); } override renderBlock() { const { title = 'GitHub', githubType, status, statusReason, owner, repo, createdAt, assignees, description, image, style, } = this.model.props; const loading = this.loading; const theme = this.std.get(ThemeProvider).theme; const imageProxyService = this.store.get(ImageProxyService); const { EmbedCardBannerIcon } = getEmbedCardIcons(theme); const titleIcon = loading ? LoadingIcon() : GithubIcon; const statusIcon = status ? getGithubStatusIcon(githubType, status, statusReason) : nothing; const statusText = loading ? '' : status; const titleText = loading ? 'Loading...' : title; const descriptionText = loading ? '' : description; const bannerImage = !loading && image ? html`banner` : EmbedCardBannerIcon; let dateText = ''; if (createdAt) { const date = new Date(createdAt); dateText = date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', }); const day = date.getDate(); const suffix = ['th', 'st', 'nd', 'rd'][((day / 10) | 0) !== 1 ? day % 10 : 4] || 'th'; dateText = dateText.replace(/\d+/, `${day}${suffix}`); } return this.renderEmbed( () => html`
${titleIcon}
${status && statusText ? html`
${statusIcon} ${statusText}
` : nothing}
${titleText}
${descriptionText}
${githubType === 'issue' && assignees ? html`
Assignees
${assignees.length === 0 ? html`No one` : repeat( assignees, assignee => assignee, (assignee, index) => html` this._handleAssigneeClick(assignee)} >${`@${assignee}`} ${index === assignees.length - 1 ? '' : `, `}` )}
` : nothing}
${`${owner}/${repo} |`} ${createdAt ? html`` : nothing} github.com
${OpenIcon}
${bannerImage}
` ); } @property({ attribute: false }) accessor loading = false; }