11import React , { useState , useEffect } from 'react' ;
22import { RotateCcw , X } from 'lucide-react' ;
33import PanelIconButton from './shared/PanelIconButton.jsx' ;
4- import { useTheme } from '../hooks/useTheme.js ';
4+ import './UpdateToast.css ';
55
66/**
77 * UpdateToast — bottom-right notification shown when an Electron auto-update
@@ -11,13 +11,12 @@ export default function UpdateToast() {
1111 const [ updateInfo , setUpdateInfo ] = useState ( null ) ;
1212 const [ dismissed , setDismissed ] = useState ( false ) ;
1313 const [ visible , setVisible ] = useState ( false ) ;
14- const theme = useTheme ( ) ;
14+ const [ dismissing , setDismissing ] = useState ( false ) ;
1515
1616 useEffect ( ( ) => {
1717 if ( ! window . electron ?. updater ?. onUpdateReady ) return ;
1818 window . electron . updater . onUpdateReady ( ( info ) => {
1919 setUpdateInfo ( info ) ;
20- // Trigger slide-in on next frame
2120 requestAnimationFrame ( ( ) => setVisible ( true ) ) ;
2221 } ) ;
2322 } , [ ] ) ;
@@ -29,69 +28,43 @@ export default function UpdateToast() {
2928 } ;
3029
3130 const handleDismiss = ( ) => {
31+ setDismissing ( true ) ;
3232 setVisible ( false ) ;
33- // Wait for slide-out animation before unmounting
3433 setTimeout ( ( ) => setDismissed ( true ) , 250 ) ;
3534 } ;
3635
37- const containerStyle = {
38- position : 'fixed' ,
39- bottom : 20 ,
40- right : 20 ,
41- zIndex : 99999 ,
42- display : 'flex' ,
43- alignItems : 'center' ,
44- gap : 10 ,
45- padding : '10px 14px' ,
46- borderRadius : 10 ,
47- backgroundColor : theme . darkMode ? '#1a1616' : '#f5f0f0' ,
48- border : `1px solid ${ theme . canvas . border } ` ,
49- boxShadow : theme . darkMode
50- ? '0 4px 20px rgba(0,0,0,0.5)'
51- : '0 4px 20px rgba(0,0,0,0.15)' ,
52- transform : visible ? 'translateY(0)' : 'translateY(calc(100% + 30px))' ,
53- opacity : visible ? 1 : 0 ,
54- transition : 'transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s ease' ,
55- fontFamily : "'EmOne', sans-serif" ,
56- pointerEvents : 'auto' ,
57- } ;
58-
59- const textStyle = {
60- fontSize : 13 ,
61- fontWeight : 600 ,
62- color : theme . canvas . textPrimary ,
63- whiteSpace : 'nowrap' ,
64- userSelect : 'none' ,
65- } ;
66-
67- const versionStyle = {
68- fontSize : 11 ,
69- color : theme . canvas . textSecondary ,
70- marginLeft : 2 ,
71- } ;
36+ const className = [
37+ 'update-toast' ,
38+ visible && 'visible' ,
39+ dismissing && 'dismissing' ,
40+ ] . filter ( Boolean ) . join ( ' ' ) ;
7241
7342 return (
74- < div style = { containerStyle } >
75- < span style = { textStyle } >
76- Restart to Update
77- { updateInfo . version && (
78- < span style = { versionStyle } > v{ updateInfo . version } </ span >
79- ) }
80- </ span >
81- < PanelIconButton
82- icon = { RotateCcw }
83- size = { 15 }
84- onClick = { handleRestart }
85- title = "Restart and install update"
86- variant = "outline"
87- />
88- < PanelIconButton
89- icon = { X }
90- size = { 15 }
91- onClick = { handleDismiss }
92- title = "Dismiss"
93- variant = "ghost"
94- />
43+ < div className = { className } >
44+ < div className = "update-toast-text" >
45+ < div className = "update-toast-title" >
46+ Version { updateInfo . version || 'update' } released
47+ </ div >
48+ < div className = "update-toast-subtitle" >
49+ Restart to update
50+ </ div >
51+ </ div >
52+ < div className = "update-toast-actions" >
53+ < PanelIconButton
54+ icon = { RotateCcw }
55+ size = { 15 }
56+ onClick = { handleRestart }
57+ title = "Restart and install update"
58+ variant = "outline"
59+ />
60+ < PanelIconButton
61+ icon = { X }
62+ size = { 15 }
63+ onClick = { handleDismiss }
64+ title = "Dismiss"
65+ variant = "ghost"
66+ />
67+ </ div >
9568 </ div >
9669 ) ;
9770}
0 commit comments