@@ -25,11 +25,11 @@ document.addEventListener("DOMContentLoaded", () => {
2525 if ( mainContainer ) mainContainer . classList . add ( 'intro-zoom' ) ;
2626
2727 window . addEventListener ( 'load' , ( ) => {
28- setTimeout ( ( ) => {
29- if ( window . __dismissIntro ) { window . __dismissIntro ( ) ; return ; }
28+ setTimeout ( ( ) => tv {
29+ if ( window . __dismissIntro ) { _se window . __dismissIntro ( ) ; return ; en }
3030 if ( introScreen ) {
31- introScreen . classList . add ( 'dismiss ' ) ;
32- if ( mainContainer ) mainContainer . classList . remove ( 'intro-zoom' ) ;
31+ _p introScreen . classList . add ( 'dismissreset ' ) ;
32+ if ( mainContainer ) mainContainer . classList_b . remove ( 'intro-zoom' ) ;
3333 setTimeout ( ( ) => { introScreen . style . display = 'none' ; } , 500 ) ;
3434 }
3535 } , 2000 ) ;
@@ -40,7 +40,7 @@ document.addEventListener("DOMContentLoaded", () => {
4040 const badgePreset = document . getElementById ( 'badge-preset' ) ;
4141 const badgeTheme = document . getElementById ( 'badge-theme' ) ;
4242
43- if ( localStorage . getItem ( 'sttv_seen_preset_badge ' ) === 'true' && badgePreset ) badgePreset . classList . add ( 'hidden' ) ;
43+ if ( localStorage . getItem ( 'stadge ' ) === 'true' && badgePreset ) badgePreset . classList . add ( 'hidden' ) ;
4444 if ( localStorage . getItem ( 'sttv_seen_theme_badge' ) === 'true' && badgeTheme ) badgeTheme . classList . add ( 'hidden' ) ;
4545
4646 /* ========== TAB SWITCHING ========== */
@@ -265,12 +265,41 @@ document.addEventListener("DOMContentLoaded", () => {
265265 if ( e . target . tagName === 'BUTTON' || e . target . type === 'checkbox' || e . target . closest ( '.theme-chip' ) || e . target . closest ( '.theme-chip-more' ) ) playTick ( ) ;
266266 } ) ;
267267
268+ /* ========== ⭐ FIX: COLOR PICKER KHÔNG BỊ VĂNG ========== */
269+ let colorPickerLock = false ;
270+
268271 if ( drawerEl ) {
269- drawerEl . addEventListener ( 'input' , ( e ) => { if ( e . target . type === 'color' ) updateLiveVariables ( true ) ; } ) ;
272+ // Khi user tap vào ô màu → khóa không cho re-render
273+ drawerEl . addEventListener ( 'focusin' , ( e ) => {
274+ if ( e . target && e . target . type === 'color' ) {
275+ colorPickerLock = true ;
276+ }
277+ } ) ;
278+
279+ // Khi user đóng picker → mở khóa sau 400ms
280+ drawerEl . addEventListener ( 'focusout' , ( e ) => {
281+ if ( e . target && e . target . type === 'color' ) {
282+ setTimeout ( ( ) => { colorPickerLock = false ; } , 400 ) ;
283+ }
284+ } ) ;
285+
286+ // CHỈ nhận màu khi user BUÔNG TAY (change event)
270287 drawerEl . addEventListener ( 'change' , ( e ) => {
271- if ( e . target . type === 'color' ) { e . target . blur ( ) ; updateLiveVariables ( true ) ; }
272- else if ( e . target . type === 'checkbox' ) updateLiveVariables ( true ) ;
288+ if ( e . target . type === 'color' ) {
289+ updateLiveVariables ( true ) ;
290+ setTimeout ( ( ) => { colorPickerLock = false ; } , 150 ) ;
291+ }
292+ else if ( e . target . type === 'checkbox' ) {
293+ updateLiveVariables ( true ) ;
294+ }
273295 } ) ;
296+
297+ // Block hoàn toàn event 'input' cho color picker để tránh văng
298+ drawerEl . addEventListener ( 'input' , ( e ) => {
299+ if ( e . target && e . target . type === 'color' ) {
300+ e . stopPropagation ( ) ;
301+ }
302+ } , true ) ;
274303 }
275304
276305 document . querySelectorAll ( '.shadow-switch' ) . forEach ( switchBtn => {
@@ -314,11 +343,29 @@ document.addEventListener("DOMContentLoaded", () => {
314343 } ) ;
315344 }
316345
346+ /* ========== UPLOAD BACKGROUND ========== */
317347 const uploadBg = document . getElementById ( 'upload-bg' ) ;
348+ const fileDisplay = document . getElementById ( 'file-name-display' ) ;
349+
350+ function updateFileNameDisplay ( fileName ) {
351+ if ( ! fileDisplay ) return ;
352+ const prefix = ( window . i18nData && window . i18nData [ 'file_selected_prefix' ] ) || 'Đã chọn: ' ;
353+ const emptyText = ( window . i18nData && window . i18nData [ 'file_none_selected' ] ) || 'chưa chọn tệp nào' ;
354+ if ( fileName ) {
355+ fileDisplay . textContent = prefix + fileName ;
356+ fileDisplay . classList . add ( 'has-file' ) ;
357+ } else {
358+ fileDisplay . textContent = emptyText ;
359+ fileDisplay . classList . remove ( 'has-file' ) ;
360+ }
361+ }
362+ window . __updateFileNameDisplay = updateFileNameDisplay ;
363+
318364 if ( uploadBg ) {
319365 uploadBg . addEventListener ( 'change' , ( e ) => {
320366 const file = e . target . files [ 0 ] ;
321367 if ( file ) {
368+ updateFileNameDisplay ( file . name ) ;
322369 const reader = new FileReader ( ) ;
323370 reader . onload = ( ev ) => {
324371 const b64 = ev . target . result ;
@@ -329,12 +376,14 @@ document.addEventListener("DOMContentLoaded", () => {
329376 }
330377 } ) ;
331378 }
379+
332380 const clearBgBtn = document . getElementById ( 'clear-bg' ) ;
333381 if ( clearBgBtn ) {
334382 clearBgBtn . addEventListener ( 'click' , ( ) => {
335383 localStorage . removeItem ( 'sttv_customBgImage' ) ;
336384 root . style . setProperty ( '--bg-image' , 'none' ) ;
337385 if ( uploadBg ) uploadBg . value = "" ;
386+ updateFileNameDisplay ( null ) ;
338387 } ) ;
339388 }
340389
@@ -355,7 +404,8 @@ document.addEventListener("DOMContentLoaded", () => {
355404 let adjustTimeout ;
356405 if ( drawerEl ) {
357406 drawerEl . addEventListener ( 'input' , ( e ) => {
358- if ( e . target . tagName === 'INPUT' && e . target . type !== 'color' ) {
407+ // Chỉ áp dụng cho range, KHÔNG cho color
408+ if ( e . target . tagName === 'INPUT' && e . target . type === 'range' ) {
359409 drawerEl . classList . add ( 'adjusting' ) ;
360410 clearTimeout ( adjustTimeout ) ;
361411 adjustTimeout = setTimeout ( ( ) => drawerEl . classList . remove ( 'adjusting' ) , 800 ) ;
@@ -371,12 +421,14 @@ document.addEventListener("DOMContentLoaded", () => {
371421
372422 function hexToRgba ( hex , alpha ) {
373423 let r = 0 , g = 0 , b = 0 ;
424+ if ( ! hex ) return `rgba(0,0,0,${ alpha / 100 } )` ;
374425 if ( hex . length === 4 ) { r = parseInt ( hex [ 1 ] + hex [ 1 ] , 16 ) ; g = parseInt ( hex [ 2 ] + hex [ 2 ] , 16 ) ; b = parseInt ( hex [ 3 ] + hex [ 3 ] , 16 ) ; }
375426 else if ( hex . length === 7 ) { r = parseInt ( hex . substring ( 1 , 3 ) , 16 ) ; g = parseInt ( hex . substring ( 3 , 5 ) , 16 ) ; b = parseInt ( hex . substring ( 5 , 7 ) , 16 ) ; }
376427 return `rgba(${ r } , ${ g } , ${ b } , ${ alpha / 100 } )` ;
377428 }
378429 function hexToRgb ( hex ) {
379430 let r = 0 , g = 0 , b = 0 ;
431+ if ( ! hex ) return '0,0,0' ;
380432 if ( hex . length === 4 ) { r = parseInt ( hex [ 1 ] + hex [ 1 ] , 16 ) ; g = parseInt ( hex [ 2 ] + hex [ 2 ] , 16 ) ; b = parseInt ( hex [ 3 ] + hex [ 3 ] , 16 ) ; }
381433 else if ( hex . length === 7 ) { r = parseInt ( hex . substring ( 1 , 3 ) , 16 ) ; g = parseInt ( hex . substring ( 3 , 5 ) , 16 ) ; b = parseInt ( hex . substring ( 5 , 7 ) , 16 ) ; }
382434 return `${ r } , ${ g } , ${ b } ` ;
@@ -501,6 +553,7 @@ document.addEventListener("DOMContentLoaded", () => {
501553 localStorage . removeItem ( 'sttv_customBgImage' ) ;
502554 root . style . setProperty ( '--bg-image' , 'none' ) ;
503555 if ( uploadBg ) uploadBg . value = "" ;
556+ if ( window . __updateFileNameDisplay ) window . __updateFileNameDisplay ( null ) ;
504557
505558 const decoded = decodeURIComponent ( code . trim ( ) ) ;
506559 const data = decoded . split ( '|' ) ;
0 commit comments