Compare commits

...

2 Commits

Author SHA1 Message Date
f319f2d772 Merge branch 'main' of https://git.byeori.cloud/admin/ocr-nextjs
merge
2026-03-25 23:17:14 +09:00
bc8dc79295 이미지 인풋박스 설정 2026-03-25 22:08:55 +09:00
2 changed files with 79 additions and 57 deletions

View File

@@ -1,59 +1,88 @@
.wrapper {
@apply w-full max-w-md mx-auto p-4;
}
.dropzone {
@apply border-2 rounded-lg p-4 flex flex-col items-center justify-center transition-colors duration-150;
}
.normal {
@apply border-dashed border-gray-300 bg-white;
}
.dragging {
@apply border-indigo-400 bg-indigo-50;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
min-height: 100vh;
width: 100%;
padding: 1rem;
}
.fileInput {
@apply hidden;
}
.previewBox {
@apply w-32 h-32 rounded-md overflow-hidden bg-gray-100 flex items-center justify-center mb-3;
}
.previewImg {
@apply object-cover w-full h-full cursor-pointer;
}
.placeholder {
@apply text-gray-400 text-center text-sm px-2;
display: none;
}
.row {
@apply w-full flex gap-2 items-center;
width: 100%;
max-width: 520px;
display: flex;
gap: 0.5rem;
align-items: center;
}
.textInput {
@apply flex-1 px-3 py-2 border rounded h-10 cursor-pointer bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500;
flex: 1;
height: 2.75rem;
padding: 0.65rem 0.75rem;
border: 1px solid #cbd5e1;
border-radius: 0.55rem;
background-color: white;
color: #334155;
font-size: 0.95rem;
outline: none;
}
.textInput:focus {
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);
border-color: #2563eb;
}
.btn {
@apply px-4 py-2 rounded text-white;
height: 2.75rem;
padding: 0.6rem 1rem;
border-radius: 0.55rem;
background-color: #6366F1;
color: #ffffff;
font-weight: 700;
cursor: pointer;
}
.btn:hover {
background-color: #4F46E5;
}
.btnLoading {
@apply bg-indigo-300;
background-color: #A5B4FC;
cursor: wait;
}
.btnPrimary {
@apply bg-indigo-600 hover:bg-indigo-700;
.messageArea {
width: 100%;
max-width: 520px;
margin-top: 0.75rem;
text-align: left;
}
.errorMsg {
@apply mt-3 text-sm text-red-600;
margin: 0.25rem 0 0;
color: #dc2626;
}
.successMsg {
@apply mt-3 text-sm text-green-600;
margin: 0.25rem 0 0;
color: #16a34a;
}
.previewContainer {
margin-bottom: 1.5rem;
display: flex;
justify-content: center;
}
.previewImage {
width: 200px;
height: 120px;
border-radius: 0.55rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
object-fit: cover;
}

View File

@@ -9,12 +9,14 @@ const ImgInputForm = () => {
const fileRef = useRef<HTMLInputElement | null>(null)
const [fileName, setFileName] = useState('')
const [preview, setPreview] = useState<string | null>(null)
const [showPreview, setShowPreview] = useState(false)
const [isDragging, setIsDragging] = useState(false)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [success, setSuccess] = useState<string | null>(null)
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:9001'
//process.env.NEXT_PUBLIC_API_URL ||
const API_BASE = 'http://localhost:9001'
useEffect(() => {
const checkAuth = async () => {
@@ -48,6 +50,7 @@ const ImgInputForm = () => {
setFileName(file.name)
setPreview(URL.createObjectURL(file))
setShowPreview(false)
// keep the selected file in the hidden input
if (fileRef.current) {
const dataTransfer = new DataTransfer()
@@ -93,6 +96,7 @@ const ImgInputForm = () => {
return
}
setLoading(true)
setShowPreview(false)
try {
const fd = new FormData()
fd.append('image', file)
@@ -103,6 +107,7 @@ const ImgInputForm = () => {
})
if (!res.ok) throw new Error('업로드 실패')
setSuccess('업로드 성공')
setShowPreview(true)
} catch (err) {
setError((err as Error).message || '업로드 중 오류가 발생했습니다')
} finally {
@@ -111,13 +116,8 @@ const ImgInputForm = () => {
}
return (
<div className={styles.wrapper}>
<div
className={`${styles.dropzone} ${isDragging ? styles.dragging : styles.normal}`}
onDrop={onDrop}
onDragOver={onDragOver}
onDragLeave={onDragLeave}
>
<>
<div className={styles.wrapper}>
<input
ref={fileRef}
type="file"
@@ -126,18 +126,11 @@ const ImgInputForm = () => {
onChange={onChange}
/>
<div className={styles.previewBox}>
{preview ? (
// preview kept modest in size
// eslint-disable-next-line @next/next/no-img-element
<img src={preview} alt="preview" className={styles.previewImg} onClick={onClickPick} />
) : (
<div className={styles.placeholder}>
<br />
</div>
)}
</div>
{preview && (
<div className={styles.previewContainer}>
<img src={preview} alt="selected preview" className={styles.previewImage} />
</div>
)}
<div className={styles.row}>
<input
@@ -150,17 +143,17 @@ const ImgInputForm = () => {
/>
<button
onClick={upload}
disabled={loading}
disabled={loading || !fileName}
className={`${styles.btn} ${loading ? styles.btnLoading : styles.btnPrimary}`}
>
{loading ? '업로드 중...' : '업로드'}
</button>
</div>
{error && <p className={styles.errorMsg}>{error}</p>}
{error && <p className={`${styles.errorMsg}`}>{error}</p>}
{success && <p className={styles.successMsg}>{success}</p>}
</div>
</div>
</>
)
}