Revert "Broken animation changes but ill fix it"

This reverts commit e29f44bbd5.
This commit is contained in:
Tickbase
2025-05-18 03:12:18 +02:00
parent 03f00e5b09
commit 19087c00da
5 changed files with 121 additions and 213 deletions

View File

@@ -137,29 +137,31 @@ function App() {
instructions?: InstructionInfo
}
// Always update progress dialog
if (complete && !show_instructions) {
// Hide dialog when complete if no instructions
setTimeout(() => {
setProgressDialog((prev) => ({ ...prev, visible: false }))
// Only refresh games list if dialog is closing without instructions
if (!refreshInProgress.current) {
refreshInProgress.current = true
setTimeout(() => {
loadGames().then(() => {
refreshInProgress.current = false
})
}, 100)
}
}, 1000)
} else {
// Update progress dialog
setProgressDialog({
visible: true, // Always set to visible - our ProgressDialog component handles exit animation
visible: true,
title,
message,
progress,
showInstructions: show_instructions || false,
instructions,
})
// If complete and no instructions, we need to schedule a game list refresh
// The dialog will auto-close with animation, but we still need to refresh the games
if (complete && !show_instructions) {
// Schedule a refresh for after the dialog closes
if (!refreshInProgress.current) {
refreshInProgress.current = true
// Wait for dialog animation + close delay (about 1.2s total)
setTimeout(() => {
loadGames().then(() => {
refreshInProgress.current = false
})
}, 1300)
}
}
})
@@ -377,7 +379,7 @@ function App() {
}, [])
const handleCloseProgressDialog = () => {
// Set dialog to not visible - animation is handled by the component
// Just hide the dialog without refreshing game list
setProgressDialog((prev) => ({ ...prev, visible: false }))
// Only refresh if we need to (instructions didn't trigger update)
@@ -665,14 +667,13 @@ function App() {
dlcFetchController.current = null
}
// Close dialog - animation is handled in DlcSelectionDialog
// Close dialog
setDlcDialog((prev) => ({ ...prev, visible: false }))
}
// Handle DLC selection confirmation
const handleDlcConfirm = async (selectedDlcs: DlcInfo[]) => {
// The dialog has already started its exit animation
// Just make sure it's marked as invisible
// Close the dialog first
setDlcDialog((prev) => ({ ...prev, visible: false }))
const gameId = dlcDialog.gameId
@@ -711,11 +712,9 @@ function App() {
progress: 100,
}))
// The ProgressDialog component will now handle the exit animation
// when progress reaches 100% after a delay
// But we still need to reset installing state with a delay
// Hide dialog after a delay
setTimeout(() => {
setProgressDialog((prev) => ({ ...prev, visible: false }))
// Reset installing state
setGames((prevGames) =>
prevGames.map((g) => (g.id === gameId ? { ...g, installing: false } : g))
@@ -760,7 +759,10 @@ function App() {
prevGames.map((g) => (g.id === gameId ? { ...g, installing: false } : g))
)
// ProgressDialog will handle exit animation automatically
// Hide dialog after a delay
setTimeout(() => {
setProgressDialog((prev) => ({ ...prev, visible: false }))
}, 3000)
}
}

View File

@@ -31,13 +31,10 @@ const DlcSelectionDialog: React.FC<DlcSelectionDialogProps> = ({
estimatedTimeLeft = '',
}) => {
const [selectedDlcs, setSelectedDlcs] = useState<DlcInfo[]>([])
// Use a simple string for animation state - keep it simple
const [animationState, setAnimationState] = useState('closed')
const [showContent, setShowContent] = useState(false)
const [searchQuery, setSearchQuery] = useState('')
const [selectAll, setSelectAll] = useState(true)
const [initialized, setInitialized] = useState(false)
// Track previous visibility to detect changes
const [prevVisible, setPrevVisible] = useState(false)
// Initialize selected DLCs when DLC list changes
useEffect(() => {
@@ -53,33 +50,19 @@ const DlcSelectionDialog: React.FC<DlcSelectionDialogProps> = ({
}
}, [visible, dlcs, initialized])
// Handle animations on visibility changes
// Handle visibility changes
useEffect(() => {
// Only respond to actual changes in visibility
if (visible !== prevVisible) {
if (visible) {
// Show animation
setAnimationState('visible')
} else {
// Hide animation - but only if we're currently visible
if (animationState === 'visible') {
setAnimationState('hiding')
// After animation completes, set to closed
// Show content immediately for better UX
const timer = setTimeout(() => {
setAnimationState('closed')
// Also reset initialization when fully closed
if (!visible) {
setInitialized(false)
}
}, 200) // Match animation duration
setShowContent(true)
}, 50)
return () => clearTimeout(timer)
} else {
setShowContent(false)
setInitialized(false) // Reset initialized state when dialog closes
}
}
// Update previous visibility
setPrevVisible(visible)
}
}, [visible, prevVisible, animationState])
}, [visible])
// Memoize filtered DLCs to avoid unnecessary recalculations
const filteredDlcs = useMemo(() => {
@@ -132,11 +115,10 @@ const DlcSelectionDialog: React.FC<DlcSelectionDialogProps> = ({
}
const handleConfirm = () => {
// Just call onConfirm directly
onConfirm(selectedDlcs)
}
// Handle overlay click
// Modified to prevent closing when loading
const handleOverlayClick = (e: React.MouseEvent<HTMLDivElement>) => {
// Prevent clicks from propagating through the overlay
e.stopPropagation()
@@ -147,11 +129,6 @@ const DlcSelectionDialog: React.FC<DlcSelectionDialogProps> = ({
}
}
// Handle the close button click
const handleClose = () => {
onClose()
}
// Count selected DLCs
const selectedCount = selectedDlcs.filter((dlc) => dlc.enabled).length
@@ -165,19 +142,14 @@ const DlcSelectionDialog: React.FC<DlcSelectionDialogProps> = ({
return ''
}
// Don't render anything if we're in closed state
if (animationState === 'closed') return null
// Generate appropriate classes based on animation state
const dialogClasses = `dlc-dialog-overlay ${animationState === 'hiding' ? 'exiting' : 'visible'}`
const contentClasses = `dlc-selection-dialog dialog-${animationState === 'hiding' ? 'exiting' : 'visible'}`
if (!visible) return null
return (
<div
className={dialogClasses}
className={`dlc-dialog-overlay ${showContent ? 'visible' : ''}`}
onClick={handleOverlayClick}
>
<div className={contentClasses}>
<div className={`dlc-selection-dialog ${showContent ? 'dialog-visible' : ''}`}>
<div className="dlc-dialog-header">
<h3>{isEditMode ? 'Edit DLCs' : 'Select DLCs to Enable'}</h3>
<div className="dlc-game-info">
@@ -250,7 +222,7 @@ const DlcSelectionDialog: React.FC<DlcSelectionDialogProps> = ({
<div className="dlc-dialog-actions">
<button
className="cancel-button"
onClick={handleClose}
onClick={onClose}
disabled={isLoading && loadingProgress < 10} // Briefly disable to prevent accidental closing at start
>
Cancel

View File

@@ -27,55 +27,23 @@ const ProgressDialog: React.FC<ProgressDialogProps> = ({
onClose,
}) => {
const [copySuccess, setCopySuccess] = useState(false)
// Use a simple string for animation state - keep it simple
const [animationState, setAnimationState] = useState('closed')
// Track previous visibility to detect changes
const [prevVisible, setPrevVisible] = useState(false)
const [showContent, setShowContent] = useState(false)
// Handle animations on visibility changes
// Reset copy state when dialog visibility changes
useEffect(() => {
// Only respond to actual changes in visibility
if (visible !== prevVisible) {
if (visible) {
// Show animation
setAnimationState('visible')
if (!visible) {
setCopySuccess(false)
setShowContent(false)
} else {
// Hide animation - but only if we're currently visible
if (animationState === 'visible') {
setAnimationState('hiding')
// After animation completes, set to closed
// Add a small delay to trigger the entrance animation
const timer = setTimeout(() => {
setAnimationState('closed')
}, 200) // Match animation duration
setShowContent(true)
}, 50)
return () => clearTimeout(timer)
}
}
// Update previous visibility
setPrevVisible(visible)
}
}, [visible, prevVisible, animationState])
}, [visible])
// Auto-close on progress completion
useEffect(() => {
// Only auto-close if showing and progress reaches 100% and not showing instructions
if (visible && progress >= 100 && !showInstructions && animationState === 'visible') {
// Wait a moment before closing
const timer = setTimeout(() => {
// Only proceed if we're still in visible state
if (animationState === 'visible' && onClose) {
onClose() // Call the onClose function directly
}
}, 1000) // Wait 1 second after completion
return () => clearTimeout(timer)
}
}, [progress, showInstructions, animationState, visible, onClose])
// Don't render if state is closed
if (animationState === 'closed') {
return null
}
if (!visible) return null
const handleCopyCommand = () => {
if (instructions?.command) {
@@ -90,10 +58,13 @@ const ProgressDialog: React.FC<ProgressDialogProps> = ({
}
const handleClose = () => {
// If we can close, just call onClose directly
setShowContent(false)
// Delay closing to allow exit animation
setTimeout(() => {
if (onClose) {
onClose()
}
}, 300)
}
// Prevent closing when in progress
@@ -175,17 +146,13 @@ const ProgressDialog: React.FC<ProgressDialogProps> = ({
// Determine if close button should be enabled
const isCloseButtonEnabled = showInstructions || progress >= 100
// Generate appropriate classes based on animation state
const dialogClasses = `progress-dialog-overlay ${animationState === 'hiding' ? 'exiting' : 'visible'}`
const contentClasses = `progress-dialog ${showInstructions ? 'with-instructions' : ''} dialog-${animationState === 'hiding' ? 'exiting' : 'visible'}`
return (
<div
className={dialogClasses}
className={`progress-dialog-overlay ${showContent ? 'visible' : ''}`}
onClick={handleOverlayClick}
>
<div
className={contentClasses}
className={`progress-dialog ${showInstructions ? 'with-instructions' : ''} ${showContent ? 'dialog-visible' : ''}`}
>
<h3>{title}</h3>
<p>{message}</p>

View File

@@ -1,29 +1,6 @@
@use '../variables' as *;
@use '../mixins' as *;
// Shared keyframes for both enter and exit animations
@keyframes modal-appear {
0% {
opacity: 0;
transform: scale(0.95);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@keyframes modal-disappear {
0% {
opacity: 1;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(0.95);
}
}
// Progress Dialog
.progress-dialog-overlay {
position: fixed;
@@ -36,19 +13,22 @@
@include flex-center;
z-index: var(--z-modal);
opacity: 0;
animation: modal-appear 0.2s ease-out;
cursor: pointer;
pointer-events: auto; // Ensure clicks work
// When visible, fade in
&.visible {
opacity: 1;
animation: modal-appear 0.2s ease-out forwards;
}
// When exiting, fade out
&.exiting {
animation: modal-disappear 0.2s ease-out forwards;
pointer-events: none; // Prevent clicks during exit animation
@keyframes modal-appear {
0% {
opacity: 0;
transform: scale(0.95);
}
100% {
opacity: 1;
transform: scale(1);
}
}
}
@@ -56,31 +36,32 @@
background-color: var(--elevated-bg);
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.3);
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.3); // shadow-glow
width: 450px;
max-width: 90vw;
border: 1px solid var(--border-soft);
opacity: 0;
transform: scale(0.95);
cursor: default;
// When visible, show the dialog
&.dialog-visible {
opacity: 1;
transform: scale(1);
transition: transform 0.2s var(--easing-bounce), opacity 0.2s ease-out;
}
// When exiting, hide the dialog
&.dialog-exiting {
opacity: 0;
transform: scale(0.95);
transition: transform 0.2s ease-in, opacity 0.2s ease-in;
opacity: 1;
}
&.with-instructions {
width: 500px;
}
h3 {
font-weight: 700;
margin-bottom: 1rem;
color: var(--text-primary);
}
p {
margin-bottom: 1rem;
color: var(--text-secondary);
}
}
// Progress bar

View File

@@ -13,18 +13,10 @@
z-index: var(--z-modal);
opacity: 0;
cursor: pointer;
pointer-events: auto; // Ensure clicks work
// When visible, fade in
&.visible {
opacity: 1;
animation: modal-appear 0.2s ease-out forwards;
}
// When exiting, fade out
&.exiting {
animation: modal-disappear 0.2s ease-out forwards;
pointer-events: none; // Prevent clicks during exit animation
animation: modal-appear 0.2s ease-out;
}
}
@@ -42,18 +34,12 @@
opacity: 0;
transform: scale(0.95);
// When visible, show the dialog
&.dialog-visible {
opacity: 1;
transform: scale(1);
transition: transform 0.2s var(--easing-bounce), opacity 0.2s ease-out;
}
// When exiting, hide the dialog
&.dialog-exiting {
opacity: 0;
transform: scale(0.95);
transition: transform 0.2s ease-in, opacity 0.2s ease-in;
opacity: 1;
transition:
transform 0.2s var(--easing-bounce),
opacity 0.2s ease-out;
}
}