-
-
- 파일 트리플 {index + 1}
- {triple.fileName && (
-
- ({triple.fileName})
-
- )}
-
- {uploadTriples.length > 1 && (
- removeTriple(triple.id)}
- className="text-red-600 hover:text-red-700"
- >
- 제거
-
- )}
-
-
-
- {/* SVG 파일 선택 */}
-
-
- SVG 파일 (UI용)
-
-
-
{
- const file = e.target.files?.[0];
- if (file) handleSvgSelect(triple.id, file);
- }}
- className="w-full p-2 border rounded-md text-sm"
- disabled={triple.uploading || triple.completed}
- />
- {triple.svgFile && (
-
-
- ✓ {triple.svgFile.name}
-
-
removeSvgFile(triple.id)}
- disabled={triple.uploading || triple.completed}
- className="text-red-500 hover:text-red-700 ml-2 disabled:opacity-50"
- >
-
-
-
-
-
- )}
-
-
-
- {/* XML 파일 상태 (자동 생성) */}
-
-
- XML 파일 (자동 변환)
-
-
-
- SVG에서 자동 생성됨
-
- {triple.xmlFile && (
-
-
-
- ✓ {triple.xmlFile.name}
-
- 자동 생성됨
-
-
-
-
- )}
-
-
-
- {/* 이미지 파일 선택 */}
-
-
- 이미지 파일 (PNG/JPG)
-
-
-
{
- const file = e.target.files?.[0];
- if (file) handleImageSelect(triple.id, file);
- }}
- className="w-full p-2 border rounded-md text-sm"
- disabled={triple.uploading || triple.completed}
- />
- {triple.imageFile && (
-
-
- ✓ {triple.imageFile.name}
-
-
removeImageFile(triple.id)}
- disabled={triple.uploading || triple.completed}
- className="text-red-500 hover:text-red-700 ml-2 disabled:opacity-50"
- >
-
-
-
-
-
- )}
-
-
-
-
- {/* 카테고리 및 추가 정보 입력 */}
-
- {/* 카테고리 선택 */}
-
-
- 카테고리 *
-
- {
- const selectedCategory = Number(
- e.target.value
- ) as FoodCategory;
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? { ...t, category: selectedCategory }
- : t
- )
- );
- }}
- disabled={triple.uploading || triple.completed}
- className="w-full p-2 border rounded-md text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
- >
- {FOOD_CATEGORY_OPTIONS.map((option) => (
-
- {option.label}
-
- ))}
-
-
-
- {/* 설명 입력 */}
-
-
- 설명 (선택사항)
-
- {
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? { ...t, content: e.target.value }
- : t
- )
- );
- }}
- disabled={triple.uploading || triple.completed}
- className="text-sm"
- />
-
-
-
- {/* 태그 입력 */}
-
-
- 태그 (선택사항)
-
-
{
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? { ...t, tagInput: e.target.value }
- : t
- )
- );
- }}
- onCompositionStart={() => {
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id ? { ...t, isComposing: true } : t
- )
- );
- }}
- onCompositionEnd={() => {
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? { ...t, isComposing: false }
- : t
- )
- );
- }}
- onKeyDown={(e) => {
- // composition 중이면 태그 추가하지 않음
- if (triple.isComposing) return;
-
- if (e.key === "Enter" || e.key === ",") {
- e.preventDefault();
- const newTag = triple.tagInput.trim();
- if (newTag && !triple.tags.includes(newTag)) {
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? {
- ...t,
- tags: [...t.tags, newTag],
- tagInput: "",
- }
- : t
- )
- );
- } else if (newTag) {
- // 이미 존재하는 태그인 경우 입력 필드만 초기화
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id ? { ...t, tagInput: "" } : t
- )
- );
- }
- } else if (
- e.key === "Backspace" &&
- triple.tagInput === "" &&
- triple.tags.length > 0
- ) {
- // 입력 필드가 비어있고 백스페이스를 누르면 마지막 태그 삭제
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? {
- ...t,
- tags: t.tags.slice(0, -1),
- }
- : t
- )
- );
- }
- }}
- onBlur={() => {
- // 포커스를 잃을 때도 태그 추가 (composition 중이 아닐 때만)
- if (!triple.isComposing) {
- const newTag = triple.tagInput.trim();
- if (newTag && !triple.tags.includes(newTag)) {
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? {
- ...t,
- tags: [...t.tags, newTag],
- tagInput: "",
- }
- : t
- )
- );
- }
- }
- }}
- disabled={triple.uploading || triple.completed}
- className="text-sm"
- />
-
- {/* 태그 표시 */}
- {triple.tags.length > 0 && (
-
- {triple.tags.map((tag, tagIndex) => (
-
- {tag}
- {
- setUploadTriples((prev) =>
- prev.map((t) =>
- t.id === triple.id
- ? {
- ...t,
- tags: t.tags.filter(
- (_, i) => i !== tagIndex
- ),
- }
- : t
- )
- );
- }}
- disabled={triple.uploading || triple.completed}
- className="ml-1 text-blue-600 hover:text-blue-800 disabled:opacity-50"
- >
- ×
-
-
- ))}
-
- )}
-
- {/* 태그 입력 도움말 */}
-
- • Enter 키나 쉼표로 태그 추가 • 백스페이스로 마지막 태그
- 삭제 • 중복 태그는 자동으로 제거됩니다
-
-
-
- {/* 파일명 불일치 에러 메시지 */}
- {triple.nameMatchError && (
-
-
-
-
-
- 파일명이 일치하지 않습니다. SVG와 이미지 파일의
- 이름(확장자 제외)이 동일해야 합니다.
-
-
- )}
-
- {/* 업로드 상태 */}
- {triple.uploading && (
-
-
-
- 업로드 중...
-
-
- {triple.progress}%
-
-
-
-
- )}
-
- {/* 완료 상태 */}
- {triple.completed && (
-
- )}
-
- {/* 에러 상태 */}
- {triple.error && (
-
- )}
-
- {/* 개별 업로드 버튼 */}
- {triple.imageFile &&
- triple.xmlFile &&
- triple.svgFile &&
- !triple.completed && (
-
- uploadTriple(triple)}
- disabled={triple.uploading || triple.nameMatchError}
- className="w-full"
- >
- {triple.uploading
- ? "업로드 중..."
- : triple.nameMatchError
- ? "파일명 불일치"
- : "이 트리플 업로드"}
-
-
- )}
-