| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- import React, { useCallback, useState } from 'react';
- import { Upload as UploadIcon, FileText, Image as ImageIcon, Folder } from 'lucide-react';
- import { useLanguage } from '../contexts/LanguageContext';
- import { GROUP_ALLOWED_EXTENSIONS, IMAGE_MIME_TYPES } from '../constants/fileSupport';
- interface NotebookDragDropUploadProps {
- onFilesSelected: (files: FileList) => void;
- isAdmin: boolean;
- globalMode?: boolean;
- }
- export const NotebookDragDropUpload: React.FC<NotebookDragDropUploadProps> = ({ onFilesSelected, isAdmin, globalMode = false }) => {
- const { t } = useLanguage();
- const [isDragging, setIsDragging] = useState(false);
- const handleDragEnter = useCallback((e: React.DragEvent) => {
- e.preventDefault();
- e.stopPropagation();
- if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
- setIsDragging(true);
- }
- }, []);
- const handleDragLeave = useCallback((e: React.DragEvent) => {
- e.preventDefault();
- e.stopPropagation();
- // マウスが実際にドラッグ領域を離れた場合のみfalseに設定
- setTimeout(() => setIsDragging(false), 100);
- }, []);
- const handleDragOver = useCallback((e: React.DragEvent) => {
- e.preventDefault();
- e.stopPropagation();
- e.dataTransfer.dropEffect = 'copy';
- }, []);
- const handleDrop = useCallback((e: React.DragEvent) => {
- e.preventDefault();
- e.stopPropagation();
- setIsDragging(false);
- if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
- onFilesSelected(e.dataTransfer.files);
- e.dataTransfer.clearData();
- }
- }, [onFilesSelected]);
- const handleFileInput = (e: React.ChangeEvent<HTMLInputElement>) => {
- if (e.target.files && e.target.files.length > 0) {
- onFilesSelected(e.target.files);
- // Reset the input so the same file can be selected again
- e.target.value = '';
- }
- };
- if (!isAdmin) {
- return null;
- }
- // モードに応じてCSSクラスを決定
- const containerClass = globalMode
- ? `fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 transition-opacity duration-300 ${isDragging ? 'opacity-100' : 'opacity-0 pointer-events-none'}`
- : `border-2 border-dashed rounded-xl p-8 text-center transition-all duration-200 cursor-pointer ${isDragging
- ? 'border-blue-500 bg-blue-50 scale-[1.02] shadow-lg'
- : 'border-slate-300 bg-slate-50 hover:border-blue-400 hover:bg-blue-25'
- }`;
- const contentClass = globalMode
- ? "w-3/4 max-w-2xl"
- : "";
- return (
- <div className={containerClass}>
- <div className={contentClass}>
- <div
- className={`border-2 border-dashed rounded-xl p-8 text-center transition-all duration-200 cursor-pointer ${isDragging
- ? 'border-blue-500 bg-blue-50 scale-[1.02] shadow-lg'
- : 'border-slate-300 bg-slate-50 hover:border-blue-400 hover:bg-blue-25'
- }`}
- onDragEnter={handleDragEnter}
- onDragOver={handleDragOver}
- onDragLeave={handleDragLeave}
- onDrop={handleDrop}
- onClick={() => document.getElementById('notebook-file-upload-input')?.click()}
- >
- <div className="flex flex-col items-center justify-center gap-6">
- <div className="p-4 bg-blue-100 rounded-full">
- <UploadIcon className="w-10 h-10 text-blue-600" />
- </div>
- <div className="space-y-2">
- <h3 className="text-lg font-semibold text-slate-700">
- {t('dragDropUploadTitle')}
- </h3>
- <p className="text-sm text-slate-500">
- {t('dragDropUploadDesc')}
- </p>
- </div>
- <div className="flex items-center gap-6 mt-2">
- <div className="flex items-center gap-2 text-xs text-slate-500 bg-white px-3 py-1.5 rounded-full border border-slate-200">
- <FileText className="w-4 h-4" />
- <span>{t('supportedFormats')}</span>
- </div>
- <div className="flex items-center gap-2 text-xs text-slate-500 bg-white px-3 py-1.5 rounded-full border border-slate-200">
- <ImageIcon className="w-4 h-4" />
- <span>{GROUP_ALLOWED_EXTENSIONS.slice(0, 10).join(', ').toUpperCase()}...</span>
- </div>
- </div>
- <div className="pt-2">
- <button
- type="button"
- className="flex items-center gap-2 px-5 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium shadow-sm"
- >
- <Folder className="w-4 h-4" />
- {t('browseFiles')}
- </button>
- <input
- type="file"
- multiple
- onChange={handleFileInput}
- className="hidden"
- id="notebook-file-upload-input"
- accept={GROUP_ALLOWED_EXTENSIONS.map(ext => `.${ext}`).join(',') + ',' + IMAGE_MIME_TYPES.join(',')}
- />
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- };
|