66 */
77
88import { getAvailableModes , getAvailableEffects } from "./config.js" ;
9+ import { loadFavoriteVersions , toggleFavoriteVersion } from "./mode-favorites.js" ;
910import { formatModeName } from "./utils.js" ;
1011
1112export default class ModeDisplay {
@@ -18,6 +19,9 @@ export default class ModeDisplay {
1819 ...config ,
1920 } ;
2021
22+ /** @type {string[] } */
23+ this . favoriteVersions = [ ...( this . config . favoriteVersions ?? loadFavoriteVersions ( getAvailableModes ( ) ) ) ] ;
24+
2125 this . element = null ;
2226 this . isVisible = false ;
2327 this . isMouseOverPanel = false ;
@@ -57,6 +61,7 @@ export default class ModeDisplay {
5761 */
5862 setModeManager ( modeManager ) {
5963 this . modeManager = modeManager ;
64+ this . modeManager . updateConfig ( { favoriteVersions : [ ...this . favoriteVersions ] } ) ;
6065 this . updateModeInfo ( ) ;
6166
6267 // Listen for mode changes
@@ -73,14 +78,14 @@ export default class ModeDisplay {
7378 * Create the UI element
7479 */
7580 createElement ( ) {
81+ this . injectModeDisplayStyles ( ) ;
7682 this . element = document . createElement ( "div" ) ;
7783 this . element . className = "mode-display" ;
7884 this . element . style . cssText = this . getBaseStyles ( ) ;
7985
80- const availableVersions = getAvailableModes ( ) ;
8186 const availableEffects = getAvailableEffects ( ) ;
8287
83- const versionOptions = availableVersions . map ( ( v ) => `<option value=" ${ v } "> ${ formatModeName ( v ) } </option>` ) . join ( "" ) ;
88+ const versionOptions = this . buildVersionSelectInnerHtml ( ) ;
8489 const effectOptions = availableEffects . map ( ( e ) => `<option value="${ e } ">${ formatModeName ( e ) } </option>` ) . join ( "" ) ;
8590
8691 this . element . innerHTML = `
@@ -91,14 +96,17 @@ export default class ModeDisplay {
9196 <div class="mode-content" style="display: none;">
9297 <div class="current-mode" style="margin-bottom: 10px; padding: 5px 0;">
9398 <div class="mode-version" style="font-weight: bold; margin-bottom: 5px;">
94- <label style="display: block; font-size: 10px; margin-bottom: 2px;">Version:</label>
95- <select class="version-select" style="width: 100%; background: rgba(0, 255, 0, 0.1); border: 1px solid rgba(0, 255, 0, 0.3); color: #00ff00; font-family: monospace; font-size: 10px; padding: 3px; border-radius: 3px;">
99+ <div style="display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-bottom: 2px;">
100+ <label style="display: block; font-size: 10px; margin: 0; flex: 1;">Version:</label>
101+ <button type="button" class="version-favorite-btn" title="Add to favorites" aria-label="Toggle favorite for selected version" aria-pressed="false">☆</button>
102+ </div>
103+ <select class="version-select matrix-select" style="width: 100%; font-size: 10px; padding: 3px;">
96104 ${ versionOptions }
97105 </select>
98106 </div>
99107 <div class="mode-effect" style="margin-bottom: 5px;">
100108 <label style="display: block; font-size: 10px; margin-bottom: 2px;">Effect:</label>
101- <select class="effect-select" style="width: 100%; background: rgba(0, 255, 0, 0.1); border: 1px solid rgba(0, 255, 0, 0.3); color: #00ff00; font-family: monospace; font- size: 10px; padding: 3px; border-radius : 3px;">
109+ <select class="effect-select matrix-select " style="width: 100%; font-size: 10px; padding: 3px;">
102110 ${ effectOptions }
103111 </select>
104112 </div>
@@ -112,7 +120,7 @@ export default class ModeDisplay {
112120 <div class="auto-switch-interval" style="margin-left: 20px; margin-bottom: 5px; font-size: 10px;">
113121 <label style="display: block;">
114122 Interval:
115- <select class="interval-select" style="margin-left: 5px; background: rgba(0, 255, 0, 0.1); border: 1px solid rgba(0, 255, 0, 0.3); color: #00ff00; font-family: monospace ; font-size: 9px; padding: 2px;">
123+ <select class="interval-select matrix-select " style="margin-left: 5px; font-size: 9px; padding: 2px;">
116124 <option value="600000">10 min</option>
117125 <option value="1200000">20 min</option>
118126 <option value="1800000">30 min</option>
@@ -149,6 +157,97 @@ export default class ModeDisplay {
149157 ` ;
150158
151159 document . body . appendChild ( this . element ) ;
160+ this . updateFavoriteButton ( ) ;
161+ }
162+
163+ /**
164+ * Dark dropdown styling so native option lists are readable (esp. Windows/Chrome).
165+ */
166+ injectModeDisplayStyles ( ) {
167+ if ( document . getElementById ( "mode-display-styles" ) ) return ;
168+ const style = document . createElement ( "style" ) ;
169+ style . id = "mode-display-styles" ;
170+ style . textContent = `
171+ .mode-display select.matrix-select {
172+ color-scheme: dark;
173+ background-color: #0a140a;
174+ color: #b6f7b6;
175+ border: 1px solid rgba(0, 255, 0, 0.45);
176+ font-family: monospace;
177+ border-radius: 3px;
178+ }
179+ .mode-display select.matrix-select option {
180+ background-color: #050805;
181+ color: #d4ffd4;
182+ }
183+ .mode-display select.matrix-select option:checked,
184+ .mode-display select.matrix-select option:hover {
185+ background-color: #145a20;
186+ color: #ffffff;
187+ }
188+ .mode-display .version-favorite-btn {
189+ flex-shrink: 0;
190+ min-width: 28px;
191+ padding: 2px 6px;
192+ font-size: 14px;
193+ line-height: 1;
194+ cursor: pointer;
195+ background: rgba(0, 255, 0, 0.12);
196+ border: 1px solid rgba(0, 255, 0, 0.35);
197+ border-radius: 3px;
198+ color: #9ff59f;
199+ }
200+ .mode-display .version-favorite-btn:hover {
201+ background: rgba(0, 255, 0, 0.22);
202+ }
203+ ` ;
204+ document . head . appendChild ( style ) ;
205+ }
206+
207+ /**
208+ * Build version <select> HTML: favorites group first, then remaining modes.
209+ */
210+ buildVersionSelectInnerHtml ( ) {
211+ const availableVersions = getAvailableModes ( ) ;
212+ const favSet = new Set ( this . favoriteVersions ) ;
213+ const favList = this . favoriteVersions . filter ( ( f ) => availableVersions . includes ( f ) ) ;
214+ const rest = availableVersions . filter ( ( v ) => ! favSet . has ( v ) ) ;
215+ let html = "" ;
216+ if ( favList . length > 0 ) {
217+ html += `<optgroup label="★ Favorites">` ;
218+ for ( const v of favList ) {
219+ html += `<option value="${ v } ">${ formatModeName ( v ) } </option>` ;
220+ }
221+ html += `</optgroup>` ;
222+ }
223+ html += `<optgroup label="All modes">` ;
224+ for ( const v of rest ) {
225+ html += `<option value="${ v } ">${ formatModeName ( v ) } </option>` ;
226+ }
227+ html += `</optgroup>` ;
228+ return html ;
229+ }
230+
231+ rebuildVersionSelect ( ) {
232+ const versionSelect = this . element . querySelector ( ".version-select" ) ;
233+ if ( ! versionSelect ) return ;
234+ const current = versionSelect . value ;
235+ versionSelect . innerHTML = this . buildVersionSelectInnerHtml ( ) ;
236+ versionSelect . value = current ;
237+ if ( versionSelect . value !== current && versionSelect . options . length ) {
238+ versionSelect . selectedIndex = 0 ;
239+ }
240+ }
241+
242+ updateFavoriteButton ( ) {
243+ const btn = this . element ?. querySelector ( ".version-favorite-btn" ) ;
244+ const versionSelect = this . element ?. querySelector ( ".version-select" ) ;
245+ if ( ! btn || ! versionSelect ) return ;
246+ const v = versionSelect . value ;
247+ const isFav = this . favoriteVersions . includes ( v ) ;
248+ btn . textContent = isFav ? "★" : "☆" ;
249+ btn . setAttribute ( "aria-pressed" , isFav ? "true" : "false" ) ;
250+ btn . title = isFav ? "Remove from favorites" : "Add to favorites" ;
152251 }
153252
154253 /**
@@ -227,9 +326,23 @@ export default class ModeDisplay {
227326 // Version dropdown change
228327 const versionSelect = this . element . querySelector ( ".version-select" ) ;
229328 versionSelect . addEventListener ( "change" , ( e ) => {
329+ this . updateFavoriteButton ( ) ;
230330 this . emit ( "versionChange" , e . target . value ) ;
231331 } ) ;
232332
333+ const favoriteBtn = this . element . querySelector ( ".version-favorite-btn" ) ;
334+ favoriteBtn . addEventListener ( "click" , ( e ) => {
335+ e . preventDefault ( ) ;
336+ e . stopPropagation ( ) ;
337+ const v = versionSelect . value ;
338+ this . favoriteVersions = toggleFavoriteVersion ( v , getAvailableModes ( ) ) ;
339+ if ( this . modeManager ) {
340+ this . modeManager . updateConfig ( { favoriteVersions : [ ...this . favoriteVersions ] } ) ;
341+ }
342+ this . rebuildVersionSelect ( ) ;
343+ this . updateFavoriteButton ( ) ;
344+ } ) ;
345+
233346 // Effect dropdown change
234347 const effectSelect = this . element . querySelector ( ".effect-select" ) ;
235348 effectSelect . addEventListener ( "change" , ( e ) => {
@@ -416,6 +529,7 @@ export default class ModeDisplay {
416529 effectSelect . value = modeInfo . effect ;
417530 }
418531
532+ this . updateFavoriteButton ( ) ;
419533 this . updateNextSwitchTime ( ) ;
420534 }
421535
0 commit comments