File size: 2,454 Bytes
9d2d895 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import { Panel } from './Panel';
import type { CustomWidgetSpec } from '@/services/widget-store';
import { t } from '@/services/i18n';
import { wrapWidgetHtml, wrapProWidgetHtml } from '@/utils/widget-sanitizer';
import { h } from '@/utils/dom-utils';
import { unsafeRawHtml } from '@/utils/sanitize';
export class CustomWidgetPanel extends Panel {
private spec: CustomWidgetSpec;
constructor(spec: CustomWidgetSpec) {
super({
id: spec.id,
title: spec.title,
closable: true,
className: 'custom-widget-panel',
defaultRowSpan: 2,
});
this.spec = spec;
this.addHeaderButtons();
this.renderWidget();
}
private addHeaderButtons(): void {
const closeBtn = this.header.querySelector('.panel-close-btn');
const chatBtn = h('button', {
className: 'icon-btn panel-widget-chat-btn widget-header-btn',
title: t('widgets.modifyWithAi'),
'aria-label': t('widgets.modifyWithAi'),
}, '\u2726');
chatBtn.addEventListener('click', (e) => {
e.stopPropagation();
this.element.dispatchEvent(new CustomEvent('wm:widget-modify', {
bubbles: true,
detail: { widgetId: this.spec.id },
}));
});
if (this.spec.tier === 'pro') {
const badge = h('span', { className: 'widget-pro-badge' }, t('widgets.proBadge'));
if (closeBtn) {
this.header.insertBefore(badge, closeBtn);
} else {
this.header.appendChild(badge);
}
}
if (closeBtn) {
this.header.insertBefore(chatBtn, closeBtn);
} else {
this.header.appendChild(chatBtn);
}
}
renderWidget(): void {
if (this.spec.tier === 'pro') {
this.setSafeContent(unsafeRawHtml(wrapProWidgetHtml(this.spec.html), 'legacy Panel.setContent() migration'));
} else {
this.setSafeContent(unsafeRawHtml(wrapWidgetHtml(this.spec.html), 'legacy Panel.setContent() migration'));
}
this.applyAccentColor();
}
private applyAccentColor(): void {
if (this.spec.accentColor) {
this.element.style.setProperty('--widget-accent', this.spec.accentColor);
} else {
this.element.style.removeProperty('--widget-accent');
}
}
updateSpec(spec: CustomWidgetSpec): void {
this.spec = spec;
const titleEl = this.header.querySelector('.panel-title');
if (titleEl) titleEl.textContent = spec.title;
this.renderWidget();
}
getSpec(): CustomWidgetSpec {
return this.spec;
}
}
|