Andrey Antukh ec1af4ad96 🎉 Import penpot-plugins repository
As commit 819a549e4928d2b1fa98e52bee82d59aec0f70d8
2025-12-30 14:56:15 +01:00

149 lines
3.8 KiB
TypeScript

import { Component, ElementRef, ViewChild, inject } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import type {
PluginMessageEvent,
ReplaceText,
ThemePluginEvent,
} from '../app/model';
import { filter, fromEvent, map, merge, take } from 'rxjs';
import { FormsModule } from '@angular/forms';
import { Shape } from '@penpot/plugin-types';
@Component({
imports: [RouterModule, CommonModule, FormsModule],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
host: {
'[attr.data-theme]': 'theme()',
},
})
export class AppComponent {
@ViewChild('searchElement') public searchElement!: ElementRef;
@ViewChild('addElement') public addElement!: ElementRef;
route = inject(ActivatedRoute);
messages$ = fromEvent<MessageEvent<PluginMessageEvent>>(window, 'message');
public textToReplace: ReplaceText = {
search: '',
replace: '',
};
public addText = '[Original layer name]';
public tab: 'add' | 'replace' = 'add';
public btnFeedback = false;
constructor() {
this.sendMessage({ type: 'ready' });
}
initialTheme$ = this.route.queryParamMap.pipe(
map((params) => params.get('theme')),
filter((theme) => !!theme),
take(1),
);
theme = toSignal(
merge(
this.initialTheme$,
this.messages$.pipe(
filter((event) => event.data.type === 'theme'),
map((event) => {
return (event.data as ThemePluginEvent).content;
}),
),
),
);
previewList = toSignal(
this.messages$.pipe(
filter(
(event) =>
event.data.type === 'init' || event.data.type === 'selection',
),
map((event) => {
if (event.data.type === 'init') {
return event.data.content.selection;
} else if (event.data.type === 'selection') {
return event.data.content.selection;
}
return [];
}),
),
{
initialValue: [],
},
);
public updateText() {
if (this.tab === 'replace') {
this.sendMessage({ type: 'replace-text', content: this.textToReplace });
this.handleBtnFeedback();
this.searchElement.nativeElement.focus();
this.resetForm();
} else {
const elementsToUpdate = this.previewList().map((item) => {
return {
current: item.name,
new: this.resultAddText(item),
};
});
this.sendMessage({ type: 'add-text', content: elementsToUpdate });
this.handleBtnFeedback();
this.addElement.nativeElement.focus();
this.resetForm();
}
}
public previewReplace() {
this.sendMessage({
type: 'preview-replace-text',
content: this.textToReplace,
});
}
public resultReplaceText(text: string) {
return text.replace(this.textToReplace.search, this.textToReplace.replace);
}
public highlightMatch(text: string) {
if (this.textToReplace.search) {
return text.replace(
this.textToReplace.search,
`<span class="highlight">${this.textToReplace.search}</span>`,
);
} else {
return text;
}
}
public selectTab(tab: 'add' | 'replace') {
this.tab = tab;
this.resetForm();
}
public resetForm() {
this.textToReplace.search = '';
this.textToReplace.replace = '';
this.addText = '[Original layer name]';
this.sendMessage({ type: 'ready' });
}
public handleBtnFeedback() {
this.btnFeedback = true;
setTimeout(() => {
this.btnFeedback = false;
}, 750);
}
public resultAddText(shape: Shape) {
return this.addText.replace('[Original layer name]', shape.name);
}
private sendMessage(message: PluginMessageEvent): void {
parent.postMessage(message, '*');
}
}