@@ -5,6 +5,7 @@ import { formatMs } from './timer'
55import { listen } from '@tauri-apps/api/event'
66
77function Stage ( ) {
8+
89 const [ data , setData ] = useState ( {
910 remainingMs : 15 * 60_000 ,
1011 color : 'green' ,
@@ -27,8 +28,15 @@ function Stage() {
2728 const [ branding , setBranding ] = useState ( {
2829 colors : { primary : '#3B82F6' , secondary : '#10B981' , background : '#1F2937' , accent : '#F59E0B' } ,
2930 logo : '' ,
30- showBranding : true
31+ showBranding : true ,
32+ logoSize : 80 ,
33+ blackBackground : false
3134 } )
35+
36+ // Update branding state when it changes
37+ useEffect ( ( ) => {
38+ // Any additional branding logic can go here if needed
39+ } , [ branding . logoSize , branding . logo , branding . showBranding ] )
3240 const prevColor = useRef ( 'green' )
3341 const [ blink , setBlink ] = useState ( false )
3442
@@ -60,23 +68,20 @@ function Stage() {
6068 // Emit to main window to request current data
6169 await emit ( 'stage:request-initial-data' , { } )
6270 } catch ( error ) {
63- console . log ( 'Could not request initial data:' , error )
71+ // Silently handle error - stage might not be ready yet
6472 }
6573 }
6674
6775 // Request initial data after a short delay to ensure everything is ready
68- // SOLO si no tenemos branding configurado
76+ // Only if we don't have custom branding configured
6977 const hasCustomBranding = branding . logo || branding . colors . primary !== '#3B82F6'
7078 if ( ! hasCustomBranding ) {
7179 setTimeout ( requestInitialData , 500 )
72- console . log ( 'Requesting initial data because no custom branding detected' )
73- } else {
74- console . log ( 'Skipping initial data request - custom branding already set' )
7580 }
7681
7782 listen ( 'stage:state' , ( ev ) => {
7883 const s = JSON . parse ( ev . payload )
79- // Preservar configuración de tiempo actual si no viene en el payload
84+ // Preserve current time configuration if not in payload
8085 setData ( prevData => {
8186 const newData = {
8287 ...s ,
@@ -89,52 +94,44 @@ function Stage() {
8994 }
9095 prevColor . current = s . color
9196 setBlink ( s . color === 'red' )
92- } ) . then ( u => unsubs . push ( u ) )
97+ } ) . then ( u => {
98+ unsubs . push ( u )
99+ } )
93100
94101 listen ( 'stage:message' , ( ev ) => {
95102 const { text, ttlMs = 4000 , fontSize = 200 , blinking = false , replaceTimer = false } = JSON . parse ( ev . payload )
96103 const until = Date . now ( ) + ttlMs
97- console . log ( 'Received message, current branding state:' , branding )
98104 setMsg ( { text, untilTs : until , fontSize, blinking, replaceTimer } )
99- } ) . then ( u => unsubs . push ( u ) )
105+ } ) . then ( u => {
106+ unsubs . push ( u )
107+ } )
100108
101109 listen ( 'stage:branding' , ( ev ) => {
102110 const brandingData = JSON . parse ( ev . payload )
103- console . log ( 'Received branding data:' , brandingData )
104111
105- // SOLO actualizar si realmente viene información nueva y válida
112+ // Apply branding data directly to state
106113 setBranding ( prevBranding => {
107- let hasChanges = false
108- const newBranding = { ...prevBranding }
109-
110- // Solo actualizar si hay cambios reales y válidos
111- if ( brandingData . colors && JSON . stringify ( brandingData . colors ) !== JSON . stringify ( prevBranding . colors ) ) {
112- newBranding . colors = brandingData . colors
113- hasChanges = true
114+ const newBranding = {
115+ colors : brandingData . colors || prevBranding . colors ,
116+ logo : brandingData . logo !== undefined ? brandingData . logo : prevBranding . logo ,
117+ logoSize : brandingData . logoSize !== undefined ? brandingData . logoSize : prevBranding . logoSize ,
118+ blackBackground : brandingData . blackBackground !== undefined ? brandingData . blackBackground : prevBranding . blackBackground ,
119+ showBranding : brandingData . showBranding !== undefined ? brandingData . showBranding : prevBranding . showBranding
114120 }
115121
116- if ( brandingData . logo !== undefined && brandingData . logo !== prevBranding . logo ) {
117- newBranding . logo = brandingData . logo
118- hasChanges = true
119- }
120-
121- if ( brandingData . showBranding !== undefined && brandingData . showBranding !== prevBranding . showBranding ) {
122- newBranding . showBranding = brandingData . showBranding
123- hasChanges = true
124- }
125-
126- // Solo actualizar si hay cambios reales
127- if ( hasChanges ) {
128- console . log ( 'Updating branding with changes:' , newBranding )
129- return newBranding
130- } else {
131- console . log ( 'No branding changes, keeping current state' )
132- return prevBranding
133- }
122+ return newBranding
134123 } )
135- } ) . then ( u => unsubs . push ( u ) )
124+ } ) . then ( u => {
125+ unsubs . push ( u )
126+ } )
136127
137- listen ( 'stage:hide-message' , ( ) => setMsg ( null ) ) . then ( u => unsubs . push ( u ) )
128+ listen ( 'stage:hide-message' , ( ) => {
129+ console . log ( '📥 RECEIVED stage:hide-message' )
130+ setMsg ( null )
131+ } ) . then ( u => {
132+ console . log ( '✅ stage:hide-message listener registered' )
133+ unsubs . push ( u )
134+ } )
138135
139136 return ( ) => { unsubs . forEach ( u => u ( ) ) ; }
140137 } , [ ] ) // NO dependencies - solo ejecutar una vez
@@ -242,9 +239,47 @@ function Stage() {
242239 const remainingPercent = ( remainingMs / totalMs ) * 100
243240 return { progressPercent, progressColor, remainingPercent }
244241 } , [ data . remainingMs , data . totalMs , data . colorInfo , branding . colors ] )
242+
243+ // Función para obtener color de texto legible para mensajes
244+ const getMessageTextColor = ( ) => {
245+ const bgColor = getBackgroundColor ( )
246+
247+ // Si el fondo es negro, usar blanco
248+ if ( bgColor === '#000000' ) {
249+ return '#FFFFFF'
250+ }
251+
252+ // Si el fondo es del mismo color que el progressColor, usar blanco para contraste
253+ if ( bgColor === progressData . progressColor ) {
254+ return '#FFFFFF'
255+ }
256+
257+ // Si el fondo es rojo (crítico), usar blanco para mejor contraste
258+ if ( bgColor === '#DC2626' || bgColor === '#EF4444' ) {
259+ return '#FFFFFF'
260+ }
261+
262+ // Si el fondo es verde, usar blanco para mejor contraste
263+ if ( bgColor === '#10B981' || bgColor === '#059669' ) {
264+ return '#FFFFFF'
265+ }
266+
267+ // Si el fondo es amarillo/naranja, usar blanco para mejor contraste
268+ if ( bgColor === '#F59E0B' || bgColor === '#EF4444' ) {
269+ return '#FFFFFF'
270+ }
271+
272+ // Para otros casos, usar blanco por defecto para máximo contraste
273+ return '#FFFFFF'
274+ }
245275
246276 // Usar colores del branding o colores avanzados
247277 const getBackgroundColor = ( ) => {
278+ // Si está activado el fondo negro, usarlo siempre
279+ if ( branding . blackBackground ) {
280+ return '#000000'
281+ }
282+
248283 // Si tenemos información detallada de color, usarla
249284 if ( data . colorInfo && data . colorInfo . bgColor ) {
250285 return data . colorInfo . bgColor
@@ -273,17 +308,16 @@ function Stage() {
273308 className = "w-screen h-screen text-white flex items-center justify-center relative overflow-hidden"
274309 style = { { backgroundColor : bgColor } }
275310 >
276- { /* Branding Header */ }
277- { branding . showBranding && (
311+ { /* Logo del usuario - Solo cuando esté activado y tenga logo */ }
312+ { branding . showBranding && branding . logo && (
278313 < div className = "absolute top-6 left-1/2 transform -translate-x-1/2 flex items-center justify-center z-10" >
279- { branding . logo && (
280- < img
281- src = { branding . logo }
282- alt = "Logo"
283- className = "h-12 w-auto object-contain"
284- onError = { ( e ) => e . target . style . display = 'none' }
285- />
286- ) }
314+ < img
315+ src = { branding . logo }
316+ alt = "Logo"
317+ className = "w-auto object-contain"
318+ style = { { height : branding . logoSize + 'px' } }
319+ onError = { ( e ) => e . target . style . display = 'none' }
320+ />
287321 </ div >
288322 ) }
289323
@@ -378,7 +412,7 @@ function Stage() {
378412 fontSize : `${ Math . max ( msg . fontSize , 24 ) } px` ,
379413 lineHeight : 1.2 ,
380414 textShadow : '3px 3px 6px rgba(0,0,0,0.5)' ,
381- color : branding . colors . primary
415+ color : getMessageTextColor ( )
382416 } }
383417 >
384418 { msg . text }
@@ -392,8 +426,8 @@ function Stage() {
392426 className = { `absolute bottom-12 left-1/2 -translate-x-1/2 px-6 py-4 rounded-2xl font-semibold backdrop-blur-sm max-w-[90vw] text-center border-2 ${ messageBlinking ? 'blink' : '' } ` }
393427 style = { {
394428 backgroundColor : `${ branding . colors . background } E6` , // 90% opacity
395- borderColor : branding . colors . primary ,
396- color : branding . colors . primary
429+ borderColor : getMessageTextColor ( ) ,
430+ color : getMessageTextColor ( )
397431 } }
398432 >
399433 < div
@@ -462,27 +496,25 @@ function Stage() {
462496 ) }
463497 </ div >
464498
465- { /* Footer con branding sutil */ }
466- { branding . showBranding && (
467- < div className = "absolute bottom-4 right-6 opacity-60" >
468- < div
469- className = "text-sm font-medium flex items-center gap-1"
470- style = { { color : 'white' } }
499+ { /* Footer con branding sutil - SIEMPRE VISIBLE */ }
500+ < div className = "absolute bottom-4 right-6 opacity-60" >
501+ < div
502+ className = "text-sm font-medium flex items-center gap-1"
503+ style = { { color : 'white' } }
504+ >
505+ Hecho con{ ' ' }
506+ < span
507+ className = "animate-pulse inline-block"
508+ style = { {
509+ animation : 'heartbeat 1.5s ease-in-out infinite' ,
510+ color : 'white'
511+ } }
471512 >
472- Hecho con{ ' ' }
473- < span
474- className = "animate-pulse inline-block"
475- style = { {
476- animation : 'heartbeat 1.5s ease-in-out infinite' ,
477- color : 'white'
478- } }
479- >
480- ♥
481- </ span >
482- { ' ' } por MateCode
483- </ div >
513+ ♥
514+ </ span >
515+ { ' ' } por MateCode
484516 </ div >
485- ) }
517+ </ div >
486518
487519 < style jsx > { `
488520 @keyframes heartbeat {
0 commit comments