ide-assi 0.528.0 → 0.530.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -202894,43 +202894,366 @@ class ideAssiSettings extends HTMLElement
202894
202894
 
202895
202895
  customElements.define("ide-assi-settings", ideAssiSettings);
202896
202896
 
202897
- class IdeTipPopup extends HTMLElement
202898
- {
202897
+ // aiLoadingTips.js
202898
+ // This file contains the full source code for the nx-ai-loading-tips web component.
202899
+
202900
+
202901
+ class IdeLoadingTips extends HTMLElement {
202902
+ #tips = []; // Stores tip objects {text: string, images: string[]}
202903
+ #currentTipIndex = 0; // Index of the currently displayed tip
202904
+ #currentImageIndex = 0; // Index of the currently displayed image for the current tip
202905
+ #tipIntervalId = null; // Interval ID for cycling through tips
202906
+ #imageIntervalId = null; // Interval ID for cycling through images within a tip
202907
+ #tipDisplayDuration = 5000; // How long each tip is displayed (5 seconds)
202908
+ #imageDisplayDuration = 2000; // How long each image within a tip is displayed (2 seconds)
202909
+
202910
+ // DOM element references (cached for performance)
202911
+ tipElement = null;
202912
+ loadingAnimation = null;
202913
+ tipImageElement = null;
202914
+ tipImageContainer = null;
202915
+
202899
202916
  constructor() {
202900
-
202901
202917
  super();
202902
202918
  this.attachShadow({ mode: 'open' });
202903
202919
  }
202904
202920
 
202905
202921
  connectedCallback() {
202906
-
202922
+ // Set up the initial structure of the component in its Shadow DOM
202907
202923
  this.shadowRoot.innerHTML = `
202908
- <style>
202909
- @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideAssi.css";
202910
- ${ninegrid.getCustomPath(this,"ideAssi.css")}
202911
- </style>
202924
+ <style>
202925
+ /* Import ninegrid's base AI CSS */
202926
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ai.css";
202927
+ /* Import custom CSS specific to this component (adjust path as needed) */
202928
+ ${ninegrid.getCustomPath(this, "ai.css")}
202912
202929
 
202913
- <nx-dialog>
202914
- <div class="buttons">
202915
- adfa
202916
- </div>
202917
-
202918
- </nx-dialog>
202919
- `;
202930
+ /* Component-specific styles */
202931
+ :host {
202932
+ display: flex;
202933
+ justify-content: flex-start;
202934
+ padding: 5px;
202935
+ flex-direction: column;
202936
+ }
202937
+
202938
+ .chat-message.loading-tips-message {
202939
+ max-width: 80%;
202940
+ border-radius: 8px;
202941
+ font-size: 14px;
202942
+ background-color: #fff;
202943
+ color: black;
202944
+ align-self: flex-start;
202945
+ text-align: left;
202946
+ position: relative;
202947
+ box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.15);
202948
+ padding: 12px 16px;
202949
+ display: flex;
202950
+ flex-direction: column;
202951
+ align-items: flex-start;
202952
+ padding-bottom: 8px; /* Adjusted for image container */
202953
+ }
202954
+
202955
+ .loading-animation {
202956
+ width: 20px;
202957
+ height: 20px;
202958
+ border: 3px solid #f3f3f3;
202959
+ border-top: 3px solid #3498db;
202960
+ border-radius: 50%;
202961
+ animation: spin 1s linear infinite;
202962
+ margin-bottom: 8px;
202963
+ display: none; /* Controlled by JS */
202964
+ }
202965
+
202966
+ .tip-content {
202967
+ width: 100%;
202968
+ }
202969
+
202970
+ .tip-label {
202971
+ font-size: 0.85em;
202972
+ color: #666;
202973
+ margin: 0 0 5px 0;
202974
+ font-weight: bold;
202975
+ }
202976
+
202977
+ .current-tip {
202978
+ font-size: 1em;
202979
+ margin: 0;
202980
+ color: #333;
202981
+ line-height: 1.5;
202982
+ margin-bottom: 10px; /* Space between text and image */
202983
+ }
202984
+
202985
+ .tip-image-container {
202986
+ width: 100%;
202987
+ max-height: 150px; /* Max height for the image area */
202988
+ overflow: hidden;
202989
+ display: flex;
202990
+ justify-content: center;
202991
+ align-items: center;
202992
+ background-color: #f0f0f0; /* Optional background for image area */
202993
+ border-radius: 4px;
202994
+ margin-top: 5px;
202995
+ display: none; /* Controlled by JS */
202996
+ }
202997
+
202998
+ .tip-image {
202999
+ max-width: 100%;
203000
+ max-height: 100%;
203001
+ object-fit: contain; /* Ensures image fits without cropping, maintaining aspect ratio */
203002
+ border-radius: 4px;
203003
+ display: none; /* Controlled by JS */
203004
+ }
203005
+
203006
+ @keyframes spin {
203007
+ 0% { transform: rotate(0deg); }
203008
+ 100% { transform: rotate(360deg); }
203009
+ }
203010
+ </style>
203011
+ <div class="chat-message loading-tips-message">
203012
+ <div class="loading-animation"></div>
203013
+ <div class="tip-content">
203014
+ <p class="tip-label">오늘의 AI 팁:</p>
203015
+ <p class="current-tip"></p>
203016
+ <div class="tip-image-container">
203017
+ <img class="tip-image" src="" alt="팁 관련 이미지">
203018
+ </div>
203019
+ </div>
203020
+ </div>
203021
+ `;
203022
+ // Cache DOM element references
203023
+ this.tipElement = this.shadowRoot.querySelector('.current-tip');
203024
+ this.loadingAnimation = this.shadowRoot.querySelector('.loading-animation');
203025
+ this.tipImageElement = this.shadowRoot.querySelector('.tip-image');
203026
+ this.tipImageContainer = this.shadowRoot.querySelector('.tip-image-container');
203027
+ }
203028
+
203029
+ disconnectedCallback() {
203030
+ // Clean up all intervals when the component is removed from the DOM
203031
+ this.stopTips();
203032
+ }
203033
+
203034
+ /**
203035
+ * Loads tips asynchronously from a JSON URL and starts displaying them.
203036
+ * @param {string} tipsUrl - The URL of the JSON file containing tip data.
203037
+ * @param {string} tipCategory - The key in the JSON file's data that corresponds to the desired tip array (e.g., 'componentTips').
203038
+ */
203039
+ async startTips(tipsUrl, tipCategory) {
203040
+ if (!tipsUrl || !tipCategory) {
203041
+ console.error("Tips URL or category not provided for aiLoadingTips.");
203042
+ return;
203043
+ }
203044
+
203045
+ try {
203046
+ const response = await fetch(tipsUrl);
203047
+ if (!response.ok) {
203048
+ throw new Error(`Failed to fetch tips: ${response.statusText}`);
203049
+ }
203050
+ const data = await response.json();
203051
+ const tips = data[tipCategory];
203052
+
203053
+ if (!tips || tips.length === 0) {
203054
+ console.warn(`No tips found for category '${tipCategory}' in ${tipsUrl}.`);
203055
+ return;
203056
+ }
203057
+
203058
+ this.#tips = tips;
203059
+ this.#currentTipIndex = 0;
203060
+ this.stopTips(); // Stop any existing intervals before starting new ones
203061
+
203062
+ this.showCurrentTip(); // Display the first tip immediately
203063
+
203064
+ // Start interval for cycling through tips
203065
+ this.#tipIntervalId = setInterval(() => {
203066
+ this.showNextTip();
203067
+ }, this.#tipDisplayDuration);
203068
+
203069
+ this.loadingAnimation.style.display = 'block'; // Show the loading spinner
203070
+ } catch (error) {
203071
+ console.error("Error loading tips:", error);
203072
+ this.stopTips(); // Stop intervals and hide animations on error
203073
+ if (this.tipElement) {
203074
+ this.tipElement.textContent = "팁을 불러오는 중 오류가 발생했습니다.";
203075
+ }
203076
+ }
203077
+ }
203078
+
203079
+ /**
203080
+ * Stops all tip and image display intervals and hides related UI elements.
203081
+ */
203082
+ stopTips() {
203083
+ if (this.#tipIntervalId) {
203084
+ clearInterval(this.#tipIntervalId);
203085
+ this.#tipIntervalId = null;
203086
+ }
203087
+ if (this.#imageIntervalId) {
203088
+ clearInterval(this.#imageIntervalId);
203089
+ this.#imageIntervalId = null;
203090
+ }
203091
+ this.loadingAnimation.style.display = 'none';
203092
+ this.tipImageElement.style.display = 'none'; // Hide image
203093
+ this.tipImageElement.src = ''; // Clear image source
203094
+ this.tipImageContainer.style.display = 'none'; // Hide image container
203095
+ }
203096
+
203097
+ /**
203098
+ * Advances to the next tip and calls showCurrentTip() to display it.
203099
+ */
203100
+ showNextTip() {
203101
+ this.#currentTipIndex = (this.#currentTipIndex + 1) % this.#tips.length;
203102
+ this.showCurrentTip();
203103
+ }
203104
+
203105
+ /**
203106
+ * Displays the current tip's text and manages its associated images.
203107
+ */
203108
+ showCurrentTip() {
203109
+ const currentTip = this.#tips[this.#currentTipIndex];
203110
+ if (this.tipElement && currentTip) {
203111
+ this.tipElement.textContent = currentTip.text;
203112
+
203113
+ // Clear any existing image cycling interval for the previous tip
203114
+ if (this.#imageIntervalId) {
203115
+ clearInterval(this.#imageIntervalId);
203116
+ this.#imageIntervalId = null;
203117
+ }
203118
+
203119
+ // Image handling logic
203120
+ if (currentTip.images && currentTip.images.length > 0) {
203121
+ this.#currentImageIndex = 0; // Reset image index for the new tip
203122
+ this.showCurrentImage(currentTip.images[this.#currentImageIndex]);
203123
+ this.tipImageElement.style.display = 'block'; // Show the image
203124
+ this.tipImageContainer.style.display = 'flex'; // Show the image container
203125
+
203126
+ if (currentTip.images.length > 1) {
203127
+ // If there's more than one image, start cycling through them
203128
+ this.#imageIntervalId = setInterval(() => {
203129
+ this.#currentImageIndex = (this.#currentImageIndex + 1) % currentTip.images.length;
203130
+ this.showCurrentImage(currentTip.images[this.#currentImageIndex]);
203131
+ }, this.#imageDisplayDuration);
203132
+ }
203133
+ } else {
203134
+ // If no images are provided for this tip, hide the image elements
203135
+ this.tipImageElement.style.display = 'none';
203136
+ this.tipImageContainer.style.display = 'none';
203137
+ this.tipImageElement.src = ''; // Clear image source
203138
+ }
203139
+ }
203140
+ }
203141
+
203142
+ /**
203143
+ * Sets the source of the image element to display the given image.
203144
+ * @param {string} imageUrl - The URL of the image to display.
203145
+ */
203146
+ showCurrentImage(imageUrl) {
203147
+ if (this.tipImageElement) {
203148
+ this.tipImageElement.src = imageUrl;
203149
+ }
203150
+ }
203151
+ }
203152
+
203153
+ // Define the custom element
203154
+ customElements.define("ide-loading-tips", IdeLoadingTips);
203155
+
203156
+ class IdeTipPopup extends HTMLElement {
203157
+ #ideLoadingTipsInstance = null; // aiLoadingTips 인스턴스를 저장할 변수
203158
+ #tipsUrl = '/data/tips.json'; // 팁 JSON 파일의 기본 경로 (public 폴더 내)
203159
+ #tipCategory = 'componentTips'; // 기본으로 표시할 팁 카테고리
203160
+
203161
+ constructor() {
203162
+ super();
203163
+ this.attachShadow({ mode: 'open' });
203164
+ }
203165
+
203166
+ connectedCallback() {
203167
+ this.shadowRoot.innerHTML = `
203168
+ <style>
203169
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideAssi.css";
203170
+ ${ninegrid.getCustomPath(this,"ideAssi.css")}
203171
+
203172
+ /* ide-tip-popup 전용 스타일 (필요시 추가) */
203173
+ .dialog-header {
203174
+ font-size: 1.2em;
203175
+ font-weight: bold;
203176
+ margin-bottom: 15px;
203177
+ text-align: center;
203178
+ color: #333;
203179
+ padding-top: 10px; /* 헤더 위 공간 */
203180
+ }
203181
+ .dialog-content {
203182
+ /* aiLoadingTips가 들어갈 컨테이너 */
203183
+ padding: 0 5px;
203184
+ }
203185
+ /* nx-dialog의 닫기 버튼과 겹치지 않도록 조정 */
203186
+ nx-dialog::part(close-button) { /* nx-dialog의 내부 닫기 버튼에 접근 */
203187
+ top: 10px;
203188
+ right: 10px;
203189
+ }
203190
+ </style>
203191
+
203192
+ <nx-dialog>
203193
+ <div slot="header" class="dialog-header">AI가 답변을 준비 중입니다...</div>
203194
+ <div class="dialog-content"></div>
203195
+ <div slot="footer" class="dialog-footer"></div>
203196
+ </nx-dialog>
203197
+ `;
202920
203198
 
202921
203199
  this.#init();
202922
203200
  }
202923
203201
 
202924
203202
  #init = () => {
202925
-
203203
+ // nx-dialog가 DOM에 추가된 후 내부 요소에 접근
203204
+ const dialog = this.shadowRoot.querySelector('nx-dialog');
203205
+ if (dialog) {
203206
+ // dialog가 닫힐 때 aiLoadingTips의 애니메이션 중지
203207
+ dialog.addEventListener('close', () => {
203208
+ if (this.#aiLoadingTipsInstance) {
203209
+ this.#aiLoadingTipsInstance.stopTips();
203210
+ // 팝업이 닫힐 때 aiLoadingTips 인스턴스 제거 (선택 사항)
203211
+ this.#aiLoadingTipsInstance.remove();
203212
+ this.#aiLoadingTipsInstance = null;
203213
+ }
203214
+ });
203215
+ }
202926
203216
  }
202927
203217
 
202928
- popup = () => {
203218
+ /**
203219
+ * 팁 팝업을 표시하고 aiLoadingTips를 시작합니다.
203220
+ * @param {string} [category='componentTips'] - 표시할 팁의 카테고리 ('componentTips' 또는 'generalAITips')
203221
+ * @param {string} [tipsUrl='/data/tips.json'] - 팁 JSON 파일의 URL
203222
+ */
203223
+ async popup(category = 'componentTips', tipsUrl = '/tips/tip.json') {
203224
+ this.#tipCategory = category;
203225
+ this.#tipsUrl = tipsUrl;
203226
+
203227
+ const dialogContent = this.shadowRoot.querySelector('.dialog-content');
203228
+ if (!dialogContent) {
203229
+ console.error("Popup content container not found.");
203230
+ return;
203231
+ }
203232
+
203233
+ // 기존 aiLoadingTips 인스턴스가 있다면 제거
203234
+ if (this.#ideLoadingTipsInstance) {
203235
+ this.#ideLoadingTipsInstance.stopTips();
203236
+ this.#ideLoadingTipsInstance.remove();
203237
+ this.#ideLoadingTipsInstance = null;
203238
+ }
203239
+
203240
+ // 새로운 aiLoadingTips 인스턴스 생성 및 추가
203241
+ this.#ideLoadingTipsInstance = document.createElement('ide-loading-tips');
203242
+ dialogContent.appendChild(this.#ideLoadingTipsInstance);
203243
+
203244
+ // 팁 로딩 시작
203245
+ await this.#ideLoadingTipsInstance.startTips(this.#tipsUrl, this.#tipCategory);
203246
+
203247
+ // nx-dialog 팝업 표시
202929
203248
  this.shadowRoot.querySelector('nx-dialog')?.showModal();
202930
203249
  };
202931
203250
 
203251
+ /**
203252
+ * 팁 팝업을 닫습니다.
203253
+ */
202932
203254
  close = () => {
202933
203255
  this.shadowRoot.querySelector('nx-dialog')?.close();
203256
+ // close 이벤트 리스너에서 aiLoadingTips 정리 로직이 실행될 것임
202934
203257
  };
202935
203258
  }
202936
203259
 
@@ -0,0 +1,259 @@
1
+ // aiLoadingTips.js
2
+ // This file contains the full source code for the nx-ai-loading-tips web component.
3
+
4
+ import ninegrid from "ninegrid2"; // Assuming ninegrid2 is available in your project
5
+
6
+ class IdeLoadingTips extends HTMLElement {
7
+ #tips = []; // Stores tip objects {text: string, images: string[]}
8
+ #currentTipIndex = 0; // Index of the currently displayed tip
9
+ #currentImageIndex = 0; // Index of the currently displayed image for the current tip
10
+ #tipIntervalId = null; // Interval ID for cycling through tips
11
+ #imageIntervalId = null; // Interval ID for cycling through images within a tip
12
+ #tipDisplayDuration = 5000; // How long each tip is displayed (5 seconds)
13
+ #imageDisplayDuration = 2000; // How long each image within a tip is displayed (2 seconds)
14
+
15
+ // DOM element references (cached for performance)
16
+ tipElement = null;
17
+ loadingAnimation = null;
18
+ tipImageElement = null;
19
+ tipImageContainer = null;
20
+
21
+ constructor() {
22
+ super();
23
+ this.attachShadow({ mode: 'open' });
24
+ }
25
+
26
+ connectedCallback() {
27
+ // Set up the initial structure of the component in its Shadow DOM
28
+ this.shadowRoot.innerHTML = `
29
+ <style>
30
+ /* Import ninegrid's base AI CSS */
31
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ai.css";
32
+ /* Import custom CSS specific to this component (adjust path as needed) */
33
+ ${ninegrid.getCustomPath(this, "ai.css")}
34
+
35
+ /* Component-specific styles */
36
+ :host {
37
+ display: flex;
38
+ justify-content: flex-start;
39
+ padding: 5px;
40
+ flex-direction: column;
41
+ }
42
+
43
+ .chat-message.loading-tips-message {
44
+ max-width: 80%;
45
+ border-radius: 8px;
46
+ font-size: 14px;
47
+ background-color: #fff;
48
+ color: black;
49
+ align-self: flex-start;
50
+ text-align: left;
51
+ position: relative;
52
+ box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.15);
53
+ padding: 12px 16px;
54
+ display: flex;
55
+ flex-direction: column;
56
+ align-items: flex-start;
57
+ padding-bottom: 8px; /* Adjusted for image container */
58
+ }
59
+
60
+ .loading-animation {
61
+ width: 20px;
62
+ height: 20px;
63
+ border: 3px solid #f3f3f3;
64
+ border-top: 3px solid #3498db;
65
+ border-radius: 50%;
66
+ animation: spin 1s linear infinite;
67
+ margin-bottom: 8px;
68
+ display: none; /* Controlled by JS */
69
+ }
70
+
71
+ .tip-content {
72
+ width: 100%;
73
+ }
74
+
75
+ .tip-label {
76
+ font-size: 0.85em;
77
+ color: #666;
78
+ margin: 0 0 5px 0;
79
+ font-weight: bold;
80
+ }
81
+
82
+ .current-tip {
83
+ font-size: 1em;
84
+ margin: 0;
85
+ color: #333;
86
+ line-height: 1.5;
87
+ margin-bottom: 10px; /* Space between text and image */
88
+ }
89
+
90
+ .tip-image-container {
91
+ width: 100%;
92
+ max-height: 150px; /* Max height for the image area */
93
+ overflow: hidden;
94
+ display: flex;
95
+ justify-content: center;
96
+ align-items: center;
97
+ background-color: #f0f0f0; /* Optional background for image area */
98
+ border-radius: 4px;
99
+ margin-top: 5px;
100
+ display: none; /* Controlled by JS */
101
+ }
102
+
103
+ .tip-image {
104
+ max-width: 100%;
105
+ max-height: 100%;
106
+ object-fit: contain; /* Ensures image fits without cropping, maintaining aspect ratio */
107
+ border-radius: 4px;
108
+ display: none; /* Controlled by JS */
109
+ }
110
+
111
+ @keyframes spin {
112
+ 0% { transform: rotate(0deg); }
113
+ 100% { transform: rotate(360deg); }
114
+ }
115
+ </style>
116
+ <div class="chat-message loading-tips-message">
117
+ <div class="loading-animation"></div>
118
+ <div class="tip-content">
119
+ <p class="tip-label">오늘의 AI 팁:</p>
120
+ <p class="current-tip"></p>
121
+ <div class="tip-image-container">
122
+ <img class="tip-image" src="" alt="팁 관련 이미지">
123
+ </div>
124
+ </div>
125
+ </div>
126
+ `;
127
+ // Cache DOM element references
128
+ this.tipElement = this.shadowRoot.querySelector('.current-tip');
129
+ this.loadingAnimation = this.shadowRoot.querySelector('.loading-animation');
130
+ this.tipImageElement = this.shadowRoot.querySelector('.tip-image');
131
+ this.tipImageContainer = this.shadowRoot.querySelector('.tip-image-container');
132
+ }
133
+
134
+ disconnectedCallback() {
135
+ // Clean up all intervals when the component is removed from the DOM
136
+ this.stopTips();
137
+ }
138
+
139
+ /**
140
+ * Loads tips asynchronously from a JSON URL and starts displaying them.
141
+ * @param {string} tipsUrl - The URL of the JSON file containing tip data.
142
+ * @param {string} tipCategory - The key in the JSON file's data that corresponds to the desired tip array (e.g., 'componentTips').
143
+ */
144
+ async startTips(tipsUrl, tipCategory) {
145
+ if (!tipsUrl || !tipCategory) {
146
+ console.error("Tips URL or category not provided for aiLoadingTips.");
147
+ return;
148
+ }
149
+
150
+ try {
151
+ const response = await fetch(tipsUrl);
152
+ if (!response.ok) {
153
+ throw new Error(`Failed to fetch tips: ${response.statusText}`);
154
+ }
155
+ const data = await response.json();
156
+ const tips = data[tipCategory];
157
+
158
+ if (!tips || tips.length === 0) {
159
+ console.warn(`No tips found for category '${tipCategory}' in ${tipsUrl}.`);
160
+ return;
161
+ }
162
+
163
+ this.#tips = tips;
164
+ this.#currentTipIndex = 0;
165
+ this.stopTips(); // Stop any existing intervals before starting new ones
166
+
167
+ this.showCurrentTip(); // Display the first tip immediately
168
+
169
+ // Start interval for cycling through tips
170
+ this.#tipIntervalId = setInterval(() => {
171
+ this.showNextTip();
172
+ }, this.#tipDisplayDuration);
173
+
174
+ this.loadingAnimation.style.display = 'block'; // Show the loading spinner
175
+ } catch (error) {
176
+ console.error("Error loading tips:", error);
177
+ this.stopTips(); // Stop intervals and hide animations on error
178
+ if (this.tipElement) {
179
+ this.tipElement.textContent = "팁을 불러오는 중 오류가 발생했습니다.";
180
+ }
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Stops all tip and image display intervals and hides related UI elements.
186
+ */
187
+ stopTips() {
188
+ if (this.#tipIntervalId) {
189
+ clearInterval(this.#tipIntervalId);
190
+ this.#tipIntervalId = null;
191
+ }
192
+ if (this.#imageIntervalId) {
193
+ clearInterval(this.#imageIntervalId);
194
+ this.#imageIntervalId = null;
195
+ }
196
+ this.loadingAnimation.style.display = 'none';
197
+ this.tipImageElement.style.display = 'none'; // Hide image
198
+ this.tipImageElement.src = ''; // Clear image source
199
+ this.tipImageContainer.style.display = 'none'; // Hide image container
200
+ }
201
+
202
+ /**
203
+ * Advances to the next tip and calls showCurrentTip() to display it.
204
+ */
205
+ showNextTip() {
206
+ this.#currentTipIndex = (this.#currentTipIndex + 1) % this.#tips.length;
207
+ this.showCurrentTip();
208
+ }
209
+
210
+ /**
211
+ * Displays the current tip's text and manages its associated images.
212
+ */
213
+ showCurrentTip() {
214
+ const currentTip = this.#tips[this.#currentTipIndex];
215
+ if (this.tipElement && currentTip) {
216
+ this.tipElement.textContent = currentTip.text;
217
+
218
+ // Clear any existing image cycling interval for the previous tip
219
+ if (this.#imageIntervalId) {
220
+ clearInterval(this.#imageIntervalId);
221
+ this.#imageIntervalId = null;
222
+ }
223
+
224
+ // Image handling logic
225
+ if (currentTip.images && currentTip.images.length > 0) {
226
+ this.#currentImageIndex = 0; // Reset image index for the new tip
227
+ this.showCurrentImage(currentTip.images[this.#currentImageIndex]);
228
+ this.tipImageElement.style.display = 'block'; // Show the image
229
+ this.tipImageContainer.style.display = 'flex'; // Show the image container
230
+
231
+ if (currentTip.images.length > 1) {
232
+ // If there's more than one image, start cycling through them
233
+ this.#imageIntervalId = setInterval(() => {
234
+ this.#currentImageIndex = (this.#currentImageIndex + 1) % currentTip.images.length;
235
+ this.showCurrentImage(currentTip.images[this.#currentImageIndex]);
236
+ }, this.#imageDisplayDuration);
237
+ }
238
+ } else {
239
+ // If no images are provided for this tip, hide the image elements
240
+ this.tipImageElement.style.display = 'none';
241
+ this.tipImageContainer.style.display = 'none';
242
+ this.tipImageElement.src = ''; // Clear image source
243
+ }
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Sets the source of the image element to display the given image.
249
+ * @param {string} imageUrl - The URL of the image to display.
250
+ */
251
+ showCurrentImage(imageUrl) {
252
+ if (this.tipImageElement) {
253
+ this.tipImageElement.src = imageUrl;
254
+ }
255
+ }
256
+ }
257
+
258
+ // Define the custom element
259
+ customElements.define("ide-loading-tips", IdeLoadingTips);