class SummarizeController extends window.StimulusModule.Controller { static targets = ['suggest', 'clear']; static values = { input: { default: '', type: String }, type: { default: 'teaser', type: String }, length: { default: 'short', type: String }, }; static css = /* css */ ` .summarize-output { margin-top: 1rem; } .suggestion { display: block; margin-top: 0.5rem; margin-bottom: 0.5rem; border-radius: 0.25rem; padding: 0.5rem; background-color: lightblue; color: black; } `; static icon = /* html */ ` `; static { const css = new CSSStyleSheet(); css.replaceSync(this.css); document.adoptedStyleSheets.push(css); } static get shouldLoad() { return 'Summarizer' in window; } /** A cached Summarizer instance Promise to avoid recreating it unnecessarily. */ #summarizer = null; contentLanguage = document.documentElement.lang || 'en'; /** Promise of a browser Summarizer instance. */ get summarizer() { if (this.#summarizer) return this.#summarizer; // Return from cache const sharedContext = 'A summary of the content on a webpage, suitable for use as a meta description.'; // eslint-disable-next-line no-undef this.#summarizer = Summarizer.create({ sharedContext, type: this.typeValue, length: this.lengthValue, format: 'plain-text', expectedInputLanguages: [this.contentLanguage], outputLanguage: document.documentElement.lang, monitor: (m) => { m.addEventListener('downloadprogress', (event) => { const label = this.suggestLabel; const { loaded, total } = event; if (loaded === total) { label.textContent = 'Generating…'; return; } const percent = Math.round((loaded / total) * 100); label.textContent = `Loading AI… ${percent}%`; }); }, }); return this.#summarizer; } // Override only for JSDoc/typing purposes, not for functionality /** @returns {HTMLElement} */ get element() { return super.element; } get suggestLabel() { return this.suggestTarget.lastElementChild; } connect() { this.generate = this.generate.bind(this); this.input = this.element.querySelector(this.inputValue); this.renderFurniture(); } renderFurniture() { this.renderSuggestButton(); this.renderOutputArea(); } renderSuggestButton() { if (this.hasSuggestTarget) return; const prefix = this.element.closest('[id]').id; const buttonId = `${prefix}-generate`; const button = /* html */ ` `; this.element.insertAdjacentHTML('beforeend', button); } renderOutputArea() { this.outputArea = document.createElement('div'); this.outputArea.classList.add('summarize-output'); this.element.append(this.outputArea); } clearOutputArea() { this.outputArea.innerHTML = ''; // Clear previous output this.clearTarget.hidden = true; // Hide the clear button } renderSuggestion(suggestion) { const template = document.createElement('template'); template.innerHTML = /* html */ `