xref: /plugin/aichat/script/AIChatButton.js (revision 23cafd9f3dfd845bbe20957f7f347fc4e39e6620)
1class AIChatButton extends HTMLElement {
2    #root = null;
3    #dialog = null;
4
5
6    constructor() {
7        super();
8        this.#root = this.attachShadow({mode: 'open'});
9        this.#root.innerHTML = `
10            <button>
11                <svg viewBox="0 0 24 24"><path d="M12,3C17.5,3 22,6.58 22,11C22,15.42 17.5,19 12,19C10.76,19 9.57,18.82 8.47,18.5C5.55,21 2,21 2,21C4.33,18.67 4.7,17.1 4.75,16.5C3.05,15.07 2,13.13 2,11C2,6.58 6.5,3 12,3Z" /></svg>
12            </button>
13            <dialog>
14                <div>
15                    <header>
16                        <h1>AI Chat</h1>
17                        <button>
18                            <svg viewBox="0 0 24 24"><path d="M13.46,12L19,17.54V19H17.54L12,13.46L6.46,19H5V17.54L10.54,12L5,6.46V5H6.46L12,10.54L17.54,5H19V6.46L13.46,12Z" /></svg>
19                        </button>
20                    </header>
21                    <main>
22                        <slot></slot>
23                    </main>
24                </div>
25            </dialog>
26        `;
27
28        this.#root.appendChild(this.getStyle());
29        this.#dialog = this.#root.querySelector('dialog');
30
31        const buttons = this.#root.querySelectorAll('button');
32        buttons.forEach(function (button) {
33            button.addEventListener('click', this.toggleDialog.bind(this))
34        }.bind(this));
35    }
36
37    /**
38     * Called when the DOM has been connected
39     *
40     * We initialize the attribute based states here
41     */
42    connectedCallback() {
43        this.#dialog.querySelector('header h1').textContent = this.getAttribute('title') || 'AI Chat';
44    }
45
46    /**
47     * Define the web component's internal styles
48     *
49     * @returns {HTMLStyleElement}
50     */
51    getStyle() {
52        const style = document.createElement('style');
53        style.textContent = `
54            :host {
55                --color-chat-icon: #4881bf;
56            }
57            button {
58                background: none;
59                border: none;
60                cursor: pointer;
61            }
62            :host > button svg {
63                fill: var(--color-chat-icon);
64            }
65            svg {
66                width: 2em;
67                height: 2em;
68
69            }
70            dialog {
71                width: 500px;
72                max-width: 90vw;
73                height: 800px;
74                max-height: 90vh;
75
76                position: fixed;
77                top: 1em;
78                right: 1em;
79                left: auto;
80
81                padding: 0.25em;
82
83                box-shadow: 0 4px 5px rgb(0 0 0 / 30%);
84                border-radius: 8px;
85                border: 1px solid #fff;
86            }
87            dialog > div {
88                display: flex;
89                flex-direction: column;
90                height: 100%;
91            }
92            dialog header {
93                display: flex;
94                justify-content: space-between;
95                align-items: flex-start;
96            }
97            dialog main {
98                overflow: auto;
99                flex-grow: 1;
100            }
101        `;
102        return style;
103    }
104
105    toggleDialog() {
106        if (this.#dialog.open) {
107            this.#dialog.close();
108        } else {
109            this.#dialog.show();
110        }
111    }
112}
113
114window.customElements.define('aichat-button', AIChatButton);
115