mirror of
https://github.com/GSManagerXZ/GameServerManager.git
synced 2026-06-06 05:19:49 +08:00
完善动画
This commit is contained in:
@@ -19,29 +19,34 @@ export const ConfirmDeleteDialog: React.FC<ConfirmDeleteDialogProps> = ({
|
||||
const [deleteDirectory, setDeleteDirectory] = React.useState(false)
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const [isAnimating, setIsAnimating] = useState(false)
|
||||
const [isClosing, setIsClosing] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setIsClosing(false)
|
||||
setIsVisible(true)
|
||||
setTimeout(() => setIsAnimating(true), 10)
|
||||
} else {
|
||||
setIsAnimating(false)
|
||||
setTimeout(() => setIsVisible(false), 200)
|
||||
setIsClosing(true)
|
||||
setTimeout(() => setIsVisible(false), 300)
|
||||
}
|
||||
}, [isOpen])
|
||||
|
||||
const handleCancel = () => {
|
||||
setIsAnimating(false)
|
||||
setIsClosing(true)
|
||||
setTimeout(() => {
|
||||
onCancel()
|
||||
}, 200)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
setIsAnimating(false)
|
||||
setIsClosing(true)
|
||||
setTimeout(() => {
|
||||
onConfirm(deleteDirectory)
|
||||
}, 200)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
if (!isVisible) return null
|
||||
@@ -52,15 +57,15 @@ export const ConfirmDeleteDialog: React.FC<ConfirmDeleteDialogProps> = ({
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
{/* 背景遮罩 */}
|
||||
<div
|
||||
className={`absolute inset-0 bg-black transition-opacity duration-200 ${
|
||||
isAnimating ? 'bg-opacity-50' : 'bg-opacity-0'
|
||||
className={`absolute inset-0 bg-black/50 ${
|
||||
isClosing ? 'animate-fade-out' : isAnimating ? 'animate-fade-in' : 'opacity-0'
|
||||
}`}
|
||||
onClick={handleCancel}
|
||||
/>
|
||||
|
||||
{/* 对话框内容 */}
|
||||
<div className={`relative bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full mx-4 p-6 transform transition-all duration-200 ${
|
||||
isAnimating ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
|
||||
<div className={`relative bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full mx-4 p-6 ${
|
||||
isClosing ? 'animate-scale-out' : isAnimating ? 'animate-scale-in' : 'opacity-0 scale-95'
|
||||
}`}>
|
||||
{/* 关闭按钮 */}
|
||||
<button
|
||||
|
||||
@@ -315,6 +315,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scaleOut {
|
||||
from {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fade-in {
|
||||
animation: fadeIn 0.2s ease-out forwards;
|
||||
}
|
||||
@@ -323,6 +343,14 @@
|
||||
animation: scaleIn 0.3s ease-out forwards;
|
||||
}
|
||||
|
||||
.animate-fade-out {
|
||||
animation: fadeOut 0.2s ease-in forwards;
|
||||
}
|
||||
|
||||
.animate-scale-out {
|
||||
animation: scaleOut 0.3s ease-in forwards;
|
||||
}
|
||||
|
||||
/* 游戏字体 - 使用系统字体 */
|
||||
.font-game {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
@@ -40,6 +40,7 @@ const GameDeploymentPage: React.FC = () => {
|
||||
const [games, setGames] = useState<Games>({})
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [showInstallModal, setShowInstallModal] = useState(false)
|
||||
const [installModalAnimating, setInstallModalAnimating] = useState(false)
|
||||
const [selectedGame, setSelectedGame] = useState<{ key: string; info: GameInfo } | null>(null)
|
||||
const [installPath, setInstallPath] = useState('')
|
||||
const [installing, setInstalling] = useState(false)
|
||||
@@ -64,6 +65,7 @@ const GameDeploymentPage: React.FC = () => {
|
||||
const [downloadComplete, setDownloadComplete] = useState(false)
|
||||
const [downloadResult, setDownloadResult] = useState<any>(null)
|
||||
const [showCreateInstanceModal, setShowCreateInstanceModal] = useState(false)
|
||||
const [createInstanceModalAnimating, setCreateInstanceModalAnimating] = useState(false)
|
||||
const [instanceName, setInstanceName] = useState('')
|
||||
const [instanceDescription, setInstanceDescription] = useState('')
|
||||
const [creatingInstance, setCreatingInstance] = useState(false)
|
||||
@@ -544,7 +546,7 @@ const GameDeploymentPage: React.FC = () => {
|
||||
message: `Minecraft实例 "${instanceName}" 创建成功!`
|
||||
})
|
||||
|
||||
setShowCreateInstanceModal(false)
|
||||
handleCloseCreateInstanceModal()
|
||||
|
||||
// 重置表单
|
||||
setSelectedCategory('')
|
||||
@@ -609,6 +611,23 @@ const GameDeploymentPage: React.FC = () => {
|
||||
setInstanceName(gameInfo.game_nameCN)
|
||||
setInstallPath('')
|
||||
setShowInstallModal(true)
|
||||
setTimeout(() => setInstallModalAnimating(true), 10)
|
||||
}
|
||||
|
||||
// 关闭安装对话框
|
||||
const handleCloseInstallModal = () => {
|
||||
setInstallModalAnimating(false)
|
||||
setTimeout(() => {
|
||||
setShowInstallModal(false)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// 关闭创建实例对话框
|
||||
const handleCloseCreateInstanceModal = () => {
|
||||
setCreateInstanceModalAnimating(false)
|
||||
setTimeout(() => {
|
||||
setShowCreateInstanceModal(false)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// 开始安装游戏
|
||||
@@ -642,7 +661,7 @@ const GameDeploymentPage: React.FC = () => {
|
||||
const fullCommand = `steamcmd +${loginCommand} +${installCommand} +quit`
|
||||
|
||||
// 关闭对话框
|
||||
setShowInstallModal(false)
|
||||
handleCloseInstallModal()
|
||||
|
||||
// 调用后端API开始游戏安装
|
||||
const response = await apiClient.installGame({
|
||||
@@ -1076,6 +1095,7 @@ const GameDeploymentPage: React.FC = () => {
|
||||
setInstanceName(`${selectedServer}-${selectedVersion}`)
|
||||
setInstanceDescription(`Minecraft ${selectedServer} ${selectedVersion} 服务器`)
|
||||
setShowCreateInstanceModal(true)
|
||||
setTimeout(() => setCreateInstanceModalAnimating(true), 10)
|
||||
}}
|
||||
className="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors flex items-center justify-center space-x-2"
|
||||
>
|
||||
@@ -1264,14 +1284,18 @@ const GameDeploymentPage: React.FC = () => {
|
||||
|
||||
{/* 安装配置对话框 */}
|
||||
{showInstallModal && selectedGame && (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 animate-fade-in">
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md mx-4 transform transition-all duration-300 animate-scale-in">
|
||||
<div className={`fixed inset-0 bg-black/50 flex items-center justify-center z-50 transition-opacity duration-300 ${
|
||||
installModalAnimating ? 'opacity-100' : 'opacity-0'
|
||||
}`}>
|
||||
<div className={`bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md mx-4 transform transition-all duration-300 ${
|
||||
installModalAnimating ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
|
||||
}`}>
|
||||
<div className="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
安装 {selectedGame.info.game_nameCN}
|
||||
</h3>
|
||||
<button
|
||||
onClick={() => setShowInstallModal(false)}
|
||||
onClick={handleCloseInstallModal}
|
||||
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
@@ -1380,7 +1404,7 @@ const GameDeploymentPage: React.FC = () => {
|
||||
|
||||
<div className="flex justify-end space-x-3 p-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<button
|
||||
onClick={() => setShowInstallModal(false)}
|
||||
onClick={handleCloseInstallModal}
|
||||
className="px-4 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-600 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-500 transition-colors"
|
||||
>
|
||||
取消
|
||||
@@ -1404,14 +1428,18 @@ const GameDeploymentPage: React.FC = () => {
|
||||
|
||||
{/* 创建Minecraft实例对话框 */}
|
||||
{showCreateInstanceModal && downloadResult && (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 animate-fade-in">
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md mx-4 transform transition-all duration-300 animate-scale-in">
|
||||
<div className={`fixed inset-0 bg-black/50 flex items-center justify-center z-50 transition-opacity duration-300 ${
|
||||
createInstanceModalAnimating ? 'opacity-100' : 'opacity-0'
|
||||
}`}>
|
||||
<div className={`bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md mx-4 transform transition-all duration-300 ${
|
||||
createInstanceModalAnimating ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
|
||||
}`}>
|
||||
<div className="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
创建Minecraft实例
|
||||
</h3>
|
||||
<button
|
||||
onClick={() => setShowCreateInstanceModal(false)}
|
||||
onClick={handleCloseCreateInstanceModal}
|
||||
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
@@ -1463,7 +1491,7 @@ const GameDeploymentPage: React.FC = () => {
|
||||
|
||||
<div className="flex space-x-3 p-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<button
|
||||
onClick={() => setShowCreateInstanceModal(false)}
|
||||
onClick={handleCloseCreateInstanceModal}
|
||||
className="flex-1 px-4 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-600 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-500 transition-colors"
|
||||
>
|
||||
取消
|
||||
|
||||
@@ -50,7 +50,9 @@ const InstanceManagerPage: React.FC = () => {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [marketLoading, setMarketLoading] = useState(false)
|
||||
const [showCreateModal, setShowCreateModal] = useState(false)
|
||||
const [createModalAnimating, setCreateModalAnimating] = useState(false)
|
||||
const [showInstallModal, setShowInstallModal] = useState(false)
|
||||
const [installModalAnimating, setInstallModalAnimating] = useState(false)
|
||||
const [selectedMarketInstance, setSelectedMarketInstance] = useState<MarketInstance | null>(null)
|
||||
const [editingInstance, setEditingInstance] = useState<Instance | null>(null)
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false)
|
||||
@@ -125,8 +127,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
title: '创建成功',
|
||||
message: `实例 "${formData.name}" 已创建`
|
||||
})
|
||||
setShowCreateModal(false)
|
||||
resetForm()
|
||||
handleCloseCreateModal()
|
||||
fetchInstances()
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -160,8 +161,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
title: '更新成功',
|
||||
message: `实例 "${formData.name}" 已更新`
|
||||
})
|
||||
setEditingInstance(null)
|
||||
resetForm()
|
||||
handleCloseCreateModal()
|
||||
fetchInstances()
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -214,9 +214,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
title: '安装成功',
|
||||
message: `实例 "${selectedMarketInstance.name}" 已安装`
|
||||
})
|
||||
setShowInstallModal(false)
|
||||
setSelectedMarketInstance(null)
|
||||
setInstallFormData({ workingDirectory: '' })
|
||||
handleCloseInstallModal()
|
||||
fetchInstances()
|
||||
setActiveTab('instances')
|
||||
}
|
||||
@@ -242,6 +240,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
const handleOpenInstallModal = (marketInstance: MarketInstance) => {
|
||||
setSelectedMarketInstance(marketInstance)
|
||||
setShowInstallModal(true)
|
||||
setTimeout(() => setInstallModalAnimating(true), 10)
|
||||
}
|
||||
|
||||
// 启动实例
|
||||
@@ -420,6 +419,26 @@ const InstanceManagerPage: React.FC = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭创建/编辑模态框
|
||||
const handleCloseCreateModal = () => {
|
||||
setCreateModalAnimating(false)
|
||||
setTimeout(() => {
|
||||
setShowCreateModal(false)
|
||||
setEditingInstance(null)
|
||||
resetForm()
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// 关闭安装模态框
|
||||
const handleCloseInstallModal = () => {
|
||||
setInstallModalAnimating(false)
|
||||
setTimeout(() => {
|
||||
setShowInstallModal(false)
|
||||
setSelectedMarketInstance(null)
|
||||
setInstallFormData({ workingDirectory: '' })
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// 编辑实例
|
||||
const handleEditInstance = (instance: Instance) => {
|
||||
setEditingInstance(instance)
|
||||
@@ -432,6 +451,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
stopCommand: instance.stopCommand
|
||||
})
|
||||
setShowCreateModal(true)
|
||||
setTimeout(() => setCreateModalAnimating(true), 10)
|
||||
}
|
||||
|
||||
// 获取状态图标
|
||||
@@ -488,6 +508,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
setEditingInstance(null)
|
||||
resetForm()
|
||||
setShowCreateModal(true)
|
||||
setTimeout(() => setCreateModalAnimating(true), 10)
|
||||
}}
|
||||
className="flex items-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
@@ -546,6 +567,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
setEditingInstance(null)
|
||||
resetForm()
|
||||
setShowCreateModal(true)
|
||||
setTimeout(() => setCreateModalAnimating(true), 10)
|
||||
}}
|
||||
className="inline-flex items-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
@@ -742,8 +764,12 @@ const InstanceManagerPage: React.FC = () => {
|
||||
|
||||
{/* 创建/编辑实例模态框 */}
|
||||
{showCreateModal && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 animate-fade-in">
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg p-6 w-full max-w-md mx-4 max-h-[90vh] overflow-y-auto transform transition-all duration-300 animate-scale-in">
|
||||
<div className={`fixed inset-0 z-50 flex items-center justify-center bg-black/50 transition-opacity duration-300 ${
|
||||
createModalAnimating ? 'opacity-100' : 'opacity-0'
|
||||
}`}>
|
||||
<div className={`bg-white dark:bg-gray-800 rounded-lg p-6 w-full max-w-md mx-4 max-h-[90vh] overflow-y-auto transform transition-all duration-300 ${
|
||||
createModalAnimating ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
|
||||
}`}>
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
{editingInstance ? '编辑实例' : '创建实例'}
|
||||
</h2>
|
||||
@@ -832,11 +858,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
|
||||
<div className="flex items-center justify-end space-x-3 mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowCreateModal(false)
|
||||
setEditingInstance(null)
|
||||
resetForm()
|
||||
}}
|
||||
onClick={handleCloseCreateModal}
|
||||
className="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors"
|
||||
>
|
||||
取消
|
||||
@@ -855,8 +877,12 @@ const InstanceManagerPage: React.FC = () => {
|
||||
|
||||
{/* 安装实例模态框 */}
|
||||
{showInstallModal && selectedMarketInstance && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 animate-fade-in">
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg p-6 w-full max-w-md mx-4 transform transition-all duration-300 animate-scale-in">
|
||||
<div className={`fixed inset-0 z-50 flex items-center justify-center bg-black/50 transition-opacity duration-300 ${
|
||||
installModalAnimating ? 'opacity-100' : 'opacity-0'
|
||||
}`}>
|
||||
<div className={`bg-white dark:bg-gray-800 rounded-lg p-6 w-full max-w-md mx-4 transform transition-all duration-300 ${
|
||||
installModalAnimating ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
|
||||
}`}>
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
安装实例: {selectedMarketInstance.name}
|
||||
</h2>
|
||||
@@ -914,11 +940,7 @@ const InstanceManagerPage: React.FC = () => {
|
||||
|
||||
<div className="flex items-center justify-end space-x-3 mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowInstallModal(false)
|
||||
setSelectedMarketInstance(null)
|
||||
setInstallFormData({ workingDirectory: '' })
|
||||
}}
|
||||
onClick={handleCloseInstallModal}
|
||||
className="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors"
|
||||
>
|
||||
取消
|
||||
|
||||
@@ -43,6 +43,7 @@ const ScheduledTasksPage: React.FC = () => {
|
||||
const [instances, setInstances] = useState<Instance[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [modalAnimating, setModalAnimating] = useState(false)
|
||||
const [editingTask, setEditingTask] = useState<ScheduledTask | null>(null)
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
@@ -160,9 +161,7 @@ const ScheduledTasksPage: React.FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
setShowModal(false)
|
||||
setEditingTask(null)
|
||||
resetForm()
|
||||
handleCloseModal()
|
||||
fetchTasks()
|
||||
} catch (error: any) {
|
||||
console.error('保存定时任务失败:', error)
|
||||
@@ -186,6 +185,7 @@ const ScheduledTasksPage: React.FC = () => {
|
||||
enabled: task.enabled
|
||||
})
|
||||
setShowModal(true)
|
||||
setTimeout(() => setModalAnimating(true), 10)
|
||||
}
|
||||
|
||||
const handleDelete = async (taskId: string) => {
|
||||
@@ -251,9 +251,12 @@ const ScheduledTasksPage: React.FC = () => {
|
||||
}
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setShowModal(false)
|
||||
setEditingTask(null)
|
||||
resetForm()
|
||||
setModalAnimating(false)
|
||||
setTimeout(() => {
|
||||
setShowModal(false)
|
||||
setEditingTask(null)
|
||||
resetForm()
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const getActionIcon = (action: string) => {
|
||||
@@ -308,7 +311,10 @@ const ScheduledTasksPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
onClick={() => {
|
||||
setShowModal(true)
|
||||
setTimeout(() => setModalAnimating(true), 10)
|
||||
}}
|
||||
className="flex items-center space-x-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
@@ -325,7 +331,10 @@ const ScheduledTasksPage: React.FC = () => {
|
||||
<h3 className="text-lg font-medium text-black dark:text-white mb-2">暂无定时任务</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-4">创建您的第一个定时任务</p>
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
onClick={() => {
|
||||
setShowModal(true)
|
||||
setTimeout(() => setModalAnimating(true), 10)
|
||||
}}
|
||||
className="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
新建任务
|
||||
@@ -390,8 +399,12 @@ const ScheduledTasksPage: React.FC = () => {
|
||||
|
||||
{/* 新建/编辑任务模态框 */}
|
||||
{showModal && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 animate-fade-in">
|
||||
<div className="w-full max-w-md glass rounded-lg border border-white/20 dark:border-gray-700/30 transform transition-all duration-300 animate-scale-in">
|
||||
<div className={`fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 transition-opacity duration-300 ${
|
||||
modalAnimating ? 'opacity-100' : 'opacity-0'
|
||||
}`}>
|
||||
<div className={`w-full max-w-md glass rounded-lg border border-white/20 dark:border-gray-700/30 transform transition-all duration-300 ${
|
||||
modalAnimating ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
|
||||
}`}>
|
||||
<div className="p-6">
|
||||
<h2 className="text-xl font-bold text-black dark:text-white mb-4">
|
||||
{editingTask ? '编辑任务' : '新建任务'}
|
||||
|
||||
Reference in New Issue
Block a user