add by files

This commit is contained in:
2026-05-01 22:47:49 +01:00
parent 47b674c949
commit d3b8eb3036

View File

@@ -707,6 +707,44 @@ export default function App() {
reader.readAsDataURL(file); reader.readAsDataURL(file);
}; };
const handleItemImageUpload = (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const MAX_SIZE = 800; // Tamanho maior para roupas
let width = img.width;
let height = img.height;
if (width > height) {
if (width > MAX_SIZE) {
height *= MAX_SIZE / width;
width = MAX_SIZE;
}
} else {
if (height > MAX_SIZE) {
width *= MAX_SIZE / height;
height = MAX_SIZE;
}
}
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);
const base64Data = canvas.toDataURL('image/jpeg', 0.8);
setImageUrlDraft(base64Data);
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
};
const saveProfile = async (e) => { const saveProfile = async (e) => {
e.preventDefault(); e.preventDefault();
setSavingProfile(true); setSavingProfile(true);
@@ -1011,7 +1049,7 @@ export default function App() {
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent opacity-0 group-hover:opacity-100 transition-all duration-300 flex flex-col justify-end p-6 pb-[136px] text-white z-10 pointer-events-none"> <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent opacity-0 group-hover:opacity-100 transition-all duration-300 flex flex-col justify-end p-6 pb-[136px] text-white z-10 pointer-events-none">
<div className="grid grid-cols-2 gap-2 pointer-events-auto"> <div className="grid grid-cols-2 gap-2 pointer-events-auto">
<button onClick={() => { setEditingItem(item); setImageUrlDraft(''); setView('edit'); }} className="py-3 px-2 bg-white text-primary-600 rounded-xl font-black text-[9px] uppercase flex items-center justify-center gap-1.5 hover:bg-primary-50"><Edit2 size={14} /> {t('edit')}</button> <button onClick={() => { setEditingItem(item); setImageUrlDraft(item.imageUrl || ''); setView('edit'); }} className="py-3 px-2 bg-white text-primary-600 rounded-xl font-black text-[9px] uppercase flex items-center justify-center gap-1.5 hover:bg-primary-50"><Edit2 size={14} /> {t('edit')}</button>
<button onClick={() => handleItemAction('laundry', item)} className="py-3 px-2 bg-blue-600 text-white rounded-xl font-black text-[9px] uppercase flex items-center justify-center gap-1.5 hover:bg-blue-700"><Droplets size={14} /> {t('makeDirty')}</button> <button onClick={() => handleItemAction('laundry', item)} className="py-3 px-2 bg-blue-600 text-white rounded-xl font-black text-[9px] uppercase flex items-center justify-center gap-1.5 hover:bg-blue-700"><Droplets size={14} /> {t('makeDirty')}</button>
<button onClick={() => handleItemAction('trash', item)} className="py-3 px-2 bg-red-600/20 text-red-100 backdrop-blur-md rounded-xl font-black text-[9px] uppercase hover:bg-red-600 transition-colors col-span-2">{t('moveToTrash')}</button> <button onClick={() => handleItemAction('trash', item)} className="py-3 px-2 bg-red-600/20 text-red-100 backdrop-blur-md rounded-xl font-black text-[9px] uppercase hover:bg-red-600 transition-colors col-span-2">{t('moveToTrash')}</button>
</div> </div>
@@ -1289,8 +1327,8 @@ export default function App() {
<div className="space-y-8"> <div className="space-y-8">
<h3 className="text-5xl font-black tracking-tighter text-inherit">{editingItem ? t('edit') : t('newItem')}</h3> <h3 className="text-5xl font-black tracking-tighter text-inherit">{editingItem ? t('edit') : t('newItem')}</h3>
<Card className="aspect-[3/4] overflow-hidden shadow-2xl relative" darkMode={darkMode}> <Card className="aspect-[3/4] overflow-hidden shadow-2xl relative" darkMode={darkMode}>
{editingItem?.imageUrl || imageUrlDraft.startsWith('http') ? ( {imageUrlDraft ? (
<img src={imageUrlDraft || editingItem?.imageUrl} className="w-full h-full object-cover" alt="" /> <img src={imageUrlDraft} className="w-full h-full object-cover" alt="" />
) : ( ) : (
<div className="h-full flex flex-col items-center justify-center opacity-10"> <div className="h-full flex flex-col items-center justify-center opacity-10">
<ImageIcon size={100} /> <ImageIcon size={100} />
@@ -1336,7 +1374,29 @@ export default function App() {
<input type="hidden" name="color" value={itemColors.join(', ')} /> <input type="hidden" name="color" value={itemColors.join(', ')} />
{itemColors.length === 0 && <p className="text-[10px] text-red-500 uppercase tracking-widest font-black mt-2">Selecione pelo menos uma cor</p>} {itemColors.length === 0 && <p className="text-[10px] text-red-500 uppercase tracking-widest font-black mt-2">Selecione pelo menos uma cor</p>}
</div> </div>
<Input label={t('imageUrl')} name="imageUrl" defaultValue={editingItem?.imageUrl} onChange={(v) => setImageUrlDraft(v)} /> <div className="space-y-4">
<label className="text-[10px] font-black uppercase opacity-40 tracking-widest ml-1 text-inherit flex items-center gap-2"><ImageIcon size={12}/> {t('imageUrl')} ou Upload</label>
<div className="flex flex-col gap-3">
<input
type="text"
name="imageUrl"
value={imageUrlDraft}
onChange={(e) => setImageUrlDraft(e.target.value)}
placeholder="https://..."
className={`w-full p-5 rounded-2xl border-none outline-none focus:ring-4 focus:ring-primary-500/10 font-bold transition-all ${darkMode ? 'bg-gray-700 text-white' : 'bg-gray-100 text-gray-900'}`}
/>
<div className="flex items-center gap-4">
<div className="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
<span className="text-[10px] font-black uppercase tracking-widest opacity-30">OU</span>
<div className="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
</div>
<label className={`flex items-center justify-center gap-3 p-5 rounded-2xl cursor-pointer transition-all font-black text-[10px] uppercase tracking-widest border-2 border-dashed ${darkMode ? 'bg-gray-800 border-gray-700 hover:border-primary-500 hover:text-primary-400' : 'bg-gray-50 border-gray-200 hover:border-primary-400 hover:text-primary-600'}`}>
<ImageIcon size={16} />
<span>Upload da Galeria / Ficheiros</span>
<input type="file" accept="image/*" className="hidden" onChange={handleItemImageUpload} />
</label>
</div>
</div>
{/* Campo de Secções */} {/* Campo de Secções */}
<div className="space-y-3"> <div className="space-y-3">