From 64c3bbb1d7fd58b2a692e814e1a5d6b26c0b1d8d Mon Sep 17 00:00:00 2001 From: Hanzo_dev <2002samudiojohan@gmail.com> Date: Sat, 21 Mar 2026 15:08:05 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20optimizaci=C3=B3n=20de=20im=C3=A1genes?= =?UTF-8?q?=20(WebP=20y=20AppImage),=20Lazy=20Load=20y=20LCP=20(Fase=201?= =?UTF-8?q?=20y=202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/index.html | 1 + frontend/package-lock.json | 16 ++++ frontend/package.json | 1 + frontend/src/components/AppImage.vue | 88 ++++++++++++++++++++++ frontend/src/views/AdminBusinessEditor.vue | 22 +++++- frontend/src/views/CouponsView.vue | 11 +-- frontend/src/views/FavoritesView.vue | 16 ++-- frontend/src/views/LandingView.vue | 2 +- 8 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 frontend/src/components/AppImage.vue diff --git a/frontend/index.html b/frontend/index.html index a572ac0..09c3543 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -20,6 +20,7 @@ + SIB - Sistema de Transporte diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 326ed49..fae051e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,6 +15,7 @@ "@googlemaps/js-api-loader": "^2.0.2", "@supabase/supabase-js": "^2.97.0", "@tailwindcss/vite": "^4.2.0", + "browser-image-compression": "^2.0.2", "chart.js": "^4.5.1", "html2canvas": "^1.4.1", "jspdf": "^4.1.0", @@ -4016,6 +4017,15 @@ "node": "18 || 20 || >=22" } }, + "node_modules/browser-image-compression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/browser-image-compression/-/browser-image-compression-2.0.2.tgz", + "integrity": "sha512-pBLlQyUf6yB8SmmngrcOw3EoS4RpQ1BcylI3T9Yqn7+4nrQTXJD4sJDe5ODnJdrvNMaio5OicFo75rDyJD2Ucw==", + "license": "MIT", + "dependencies": { + "uzip": "0.20201231.0" + } + }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", @@ -8230,6 +8240,12 @@ "base64-arraybuffer": "^1.0.2" } }, + "node_modules/uzip": { + "version": "0.20201231.0", + "resolved": "https://registry.npmjs.org/uzip/-/uzip-0.20201231.0.tgz", + "integrity": "sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng==", + "license": "MIT" + }, "node_modules/vite": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index f5f2174..524fd2e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "@googlemaps/js-api-loader": "^2.0.2", "@supabase/supabase-js": "^2.97.0", "@tailwindcss/vite": "^4.2.0", + "browser-image-compression": "^2.0.2", "chart.js": "^4.5.1", "html2canvas": "^1.4.1", "jspdf": "^4.1.0", diff --git a/frontend/src/components/AppImage.vue b/frontend/src/components/AppImage.vue new file mode 100644 index 0000000..4e1a4d8 --- /dev/null +++ b/frontend/src/components/AppImage.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/frontend/src/views/AdminBusinessEditor.vue b/frontend/src/views/AdminBusinessEditor.vue index d30aac1..557498d 100644 --- a/frontend/src/views/AdminBusinessEditor.vue +++ b/frontend/src/views/AdminBusinessEditor.vue @@ -4,6 +4,22 @@ import { useRouter, useRoute } from 'vue-router'; import { businessService } from '@/services/businessService'; import type { Business } from '@/types'; import { useAuthStore } from '@/stores/auth'; +import imageCompression from 'browser-image-compression'; + +async function compressImage(file: File) { + const options = { + maxSizeMB: 0.5, + maxWidthOrHeight: 1200, + useWebWorker: true, + fileType: 'image/webp' + }; + try { + return await imageCompression(file, options); + } catch (err) { + console.error('Error compressing image', err); + return file; // fallback to original + } +} const router = useRouter(); const route = useRoute(); @@ -145,7 +161,8 @@ async function saveBusiness() { if (galleryFiles.value.length > 0) { const uploadedUrls: string[] = []; for (const gFile of galleryFiles.value) { - const url = await businessService.uploadImage(gFile); + const compressedFile = await compressImage(gFile) as File; + const url = await businessService.uploadImage(compressedFile); uploadedUrls.push(url); } // Combinar las URL existentes ya serializadas + las nuevas subidas @@ -154,7 +171,8 @@ async function saveBusiness() { } if (selectedFile.value) { - formData.append('image', selectedFile.value); + const compressedMain = await compressImage(selectedFile.value) as File; + formData.append('image', compressedMain); } if (isEditing.value && businessForm.value.id) { diff --git a/frontend/src/views/CouponsView.vue b/frontend/src/views/CouponsView.vue index e53011d..7120e48 100644 --- a/frontend/src/views/CouponsView.vue +++ b/frontend/src/views/CouponsView.vue @@ -1,10 +1,10 @@ -