60 lines
2.7 KiB
TypeScript
60 lines
2.7 KiB
TypeScript
'use client'
|
||
|
||
import { useRef } from 'react'
|
||
import Image from 'next/image'
|
||
import { Plus } from 'lucide-react'
|
||
import { dropZoneIdleClass, fieldHintClass, fieldLabelClass, uploadAreaAddTileClass, uploadAreaEmptyButtonClass, uploadAreaTileClass } from './upload-field-styles'
|
||
|
||
interface ModelImagesUploadProps {
|
||
modelImageUrls: string[]
|
||
onModelImagesChange: (e: React.ChangeEvent<HTMLInputElement>) => void
|
||
onRemoveModelImage: (index: number) => void
|
||
disabled?: boolean
|
||
}
|
||
|
||
export default function ModelImagesUpload({
|
||
modelImageUrls,
|
||
onModelImagesChange,
|
||
onRemoveModelImage,
|
||
disabled = false,
|
||
}: ModelImagesUploadProps) {
|
||
const inputRef = useRef<HTMLInputElement>(null)
|
||
|
||
return (
|
||
<div>
|
||
<label className={fieldLabelClass}>模特展示图片 *(可上传多张)</label>
|
||
<div className={`p-3 ${dropZoneIdleClass} ${disabled ? 'cursor-not-allowed opacity-60' : ''}`}>
|
||
<input ref={inputRef} type="file" accept="image/*" multiple onChange={onModelImagesChange} className="hidden" disabled={disabled} />
|
||
<div className={modelImageUrls.length > 0 ? 'flex flex-wrap gap-2' : ''}>
|
||
{modelImageUrls.map((url, index) => (
|
||
<div key={index} className="group relative">
|
||
<div className={uploadAreaTileClass}>
|
||
<Image src={url} alt={`模特图 ${index + 1}`} fill unoptimized className="object-cover" />
|
||
{index === 0 && <span className="absolute inset-x-0 bottom-0 bg-[#1a1c1d]/80 py-0.5 text-center text-xs text-white">主图</span>}
|
||
</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => onRemoveModelImage(index)}
|
||
disabled={disabled}
|
||
aria-label={`移除模特图 ${index + 1}`}
|
||
className="absolute right-1 top-1 flex h-7 w-7 items-center justify-center rounded-[6px] bg-[#1a1c1d]/80 text-white opacity-100 transition-opacity sm:opacity-0 sm:group-hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff]"
|
||
>×</button>
|
||
</div>
|
||
))}
|
||
<button
|
||
type="button"
|
||
onClick={() => inputRef.current?.click()}
|
||
disabled={disabled}
|
||
aria-label="添加模特图片"
|
||
className={modelImageUrls.length > 0 ? uploadAreaAddTileClass : uploadAreaEmptyButtonClass}
|
||
>
|
||
<Plus className="h-5 w-5" aria-hidden="true" />
|
||
{modelImageUrls.length === 0 && '添加模特图片'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<p className={`mt-1.5 ${fieldHintClass}`}>可一次选择多张 · 首张为预览图,高图会自动切片</p>
|
||
</div>
|
||
)
|
||
}
|