优化Modal弹框布局和尺寸控制
- 修复Modal组件尺寸类冲突问题,确保max-w-*正确生效 - 优化CreateDynamicModal表单布局,使其在小尺寸弹框中更紧凑 - 减少表单元素间距和内边距,提升视觉密度 - 优化图片预览、按钮等组件尺寸,适配sm尺寸弹框 - 移除CSS中可能干扰Tailwind尺寸类的样式设置 主要改进: - Modal组件getSizeClasses函数优化,确保w-full和max-w-*正确配合 - CreateDynamicModal表单元素紧凑化,提升小屏幕体验 - 统一弹框尺寸控制逻辑,解决宽度限制不生效问题
This commit is contained in:
parent
4da48c3281
commit
e7b48d0a7d
|
|
@ -120,7 +120,7 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
>
|
>
|
||||||
{/* 表单内容 */}
|
{/* 表单内容 */}
|
||||||
<form onSubmit={handleSubmit} className="flex flex-col h-full">
|
<form onSubmit={handleSubmit} className="flex flex-col h-full">
|
||||||
<div className="flex-1 p-6 space-y-6 overflow-y-auto">
|
<div className="flex-1 p-4 space-y-4 overflow-y-auto">
|
||||||
|
|
||||||
{/* 提示词 */}
|
{/* 提示词 */}
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -132,8 +132,8 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
value={formData.prompt}
|
value={formData.prompt}
|
||||||
onChange={(e) => handleInputChange('prompt', e.target.value)}
|
onChange={(e) => handleInputChange('prompt', e.target.value)}
|
||||||
placeholder="描述您希望生成的视频内容..."
|
placeholder="描述您希望生成的视频内容..."
|
||||||
rows={4}
|
rows={3}
|
||||||
className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 transition-colors resize-none ${errors.prompt ? 'border-red-300' : 'border-gray-300'
|
className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 transition-colors resize-none text-sm ${errors.prompt ? 'border-red-300' : 'border-gray-300'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
{errors.prompt && (
|
{errors.prompt && (
|
||||||
|
|
@ -147,18 +147,18 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
<PhotoIcon className="h-4 w-4" />
|
<PhotoIcon className="h-4 w-4" />
|
||||||
源图片 *
|
源图片 *
|
||||||
</label>
|
</label>
|
||||||
<div className="space-y-3">
|
<div className="space-y-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleImageSelect}
|
onClick={handleImageSelect}
|
||||||
className={`w-full p-4 border-2 border-dashed rounded-lg transition-colors ${errors.source_image_path
|
className={`w-full p-3 border-2 border-dashed rounded-lg transition-colors ${errors.source_image_path
|
||||||
? 'border-red-300 bg-red-50'
|
? 'border-red-300 bg-red-50'
|
||||||
: 'border-gray-300 hover:border-primary-400 hover:bg-primary-50'
|
: 'border-gray-300 hover:border-primary-400 hover:bg-primary-50'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col items-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
<PhotoIcon className="h-8 w-8 text-gray-400" />
|
<PhotoIcon className="h-5 w-5 text-gray-400" />
|
||||||
<span className="text-sm text-gray-600">点击选择图片</span>
|
<span className="text-sm text-gray-600">选择图片</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
@ -167,14 +167,14 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
<img
|
<img
|
||||||
src={formData.source_image_path}
|
src={formData.source_image_path}
|
||||||
alt="源图片预览"
|
alt="源图片预览"
|
||||||
className="w-full h-48 object-contain bg-gray-50 rounded-lg"
|
className="w-full h-32 object-contain bg-gray-50 rounded-lg"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleInputChange('source_image_path', '')}
|
onClick={() => handleInputChange('source_image_path', '')}
|
||||||
className="absolute top-2 right-2 p-1 bg-red-500 text-white rounded-full hover:bg-red-600 transition-colors"
|
className="absolute top-1 right-1 p-1 bg-red-500 text-white rounded-full hover:bg-red-600 transition-colors"
|
||||||
>
|
>
|
||||||
<XMarkIcon className="h-4 w-4" />
|
<XMarkIcon className="h-3 w-3" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -194,7 +194,7 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
<select
|
<select
|
||||||
value={formData.ai_model}
|
value={formData.ai_model}
|
||||||
onChange={(e) => handleInputChange('ai_model', e.target.value)}
|
onChange={(e) => handleInputChange('ai_model', e.target.value)}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 transition-colors"
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 transition-colors text-sm"
|
||||||
>
|
>
|
||||||
{aiModelOptions.map((option) => (
|
{aiModelOptions.map((option) => (
|
||||||
<option key={option.id} value={option.name} disabled={!option.is_available}>
|
<option key={option.id} value={option.name} disabled={!option.is_available}>
|
||||||
|
|
@ -210,7 +210,7 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
<VideoCameraIcon className="h-4 w-4" />
|
<VideoCameraIcon className="h-4 w-4" />
|
||||||
生成视频个数
|
生成视频个数
|
||||||
</label>
|
</label>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-3">
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
min="1"
|
min="1"
|
||||||
|
|
@ -219,9 +219,12 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
onChange={(e) => handleInputChange('video_count', parseInt(e.target.value))}
|
onChange={(e) => handleInputChange('video_count', parseInt(e.target.value))}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm font-medium text-gray-700 min-w-[2rem]">
|
<div className="flex items-center gap-1">
|
||||||
|
<span className="text-sm font-medium text-gray-700">
|
||||||
{formData.video_count}
|
{formData.video_count}
|
||||||
</span>
|
</span>
|
||||||
|
<span className="text-xs text-gray-500">个</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{errors.video_count && (
|
{errors.video_count && (
|
||||||
<p className="mt-1 text-sm text-red-600">{errors.video_count}</p>
|
<p className="mt-1 text-sm text-red-600">{errors.video_count}</p>
|
||||||
|
|
@ -230,18 +233,18 @@ const CreateDynamicModal: React.FC<CreateDynamicModalProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 底部按钮 */}
|
{/* 底部按钮 */}
|
||||||
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200">
|
<div className="flex items-center justify-end gap-3 p-4 border-t border-gray-200">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
className="px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-lg transition-colors"
|
className="px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="px-6 py-2 bg-gradient-to-r from-primary-500 to-primary-600 text-white rounded-lg hover:from-primary-600 hover:to-primary-700 transition-all duration-200 shadow-sm hover:shadow-md font-medium disabled:opacity-50 disabled:cursor-not-allowed"
|
className="px-4 py-2 text-sm bg-gradient-to-r from-primary-500 to-primary-600 text-white rounded-lg hover:from-primary-600 hover:to-primary-700 transition-all duration-200 shadow-sm hover:shadow-md font-medium disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{isSubmitting ? '生成中...' : '开始生成'}
|
{isSubmitting ? '生成中...' : '开始生成'}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,11 @@ export const Modal: React.FC<ModalProps> = ({
|
||||||
|
|
||||||
const getSizeClasses = () => {
|
const getSizeClasses = () => {
|
||||||
const sizeMap = {
|
const sizeMap = {
|
||||||
sm: 'max-w-md',
|
sm: 'w-full max-w-md',
|
||||||
md: 'max-w-lg',
|
md: 'w-full max-w-lg',
|
||||||
lg: 'max-w-2xl',
|
lg: 'w-full max-w-2xl',
|
||||||
xl: 'max-w-4xl',
|
xl: 'w-full max-w-4xl',
|
||||||
full: 'max-w-7xl',
|
full: 'w-full max-w-7xl',
|
||||||
};
|
};
|
||||||
return sizeMap[size];
|
return sizeMap[size];
|
||||||
};
|
};
|
||||||
|
|
@ -141,7 +141,7 @@ export const Modal: React.FC<ModalProps> = ({
|
||||||
{/* 弹框容器 */}
|
{/* 弹框容器 */}
|
||||||
<div
|
<div
|
||||||
ref={modalRef}
|
ref={modalRef}
|
||||||
className={`modal-container ${size === 'xl' || size === 'full' ? 'large' : ''} ${getSizeClasses()} w-full max-h-[90vh] animate-modal-scale-in relative z-10 ${className}`}
|
className={`modal-container ${size === 'xl' || size === 'full' ? 'large' : ''} ${getSizeClasses()} max-h-[90vh] animate-modal-scale-in relative z-10 ${className}`}
|
||||||
>
|
>
|
||||||
{/* 头部 */}
|
{/* 头部 */}
|
||||||
{(title || subtitle || icon || showCloseButton) && (
|
{(title || subtitle || icon || showCloseButton) && (
|
||||||
|
|
|
||||||
|
|
@ -907,7 +907,6 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transform-origin: center;
|
transform-origin: center;
|
||||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
max-width: 100%;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue