arreglado la generacion de pdfs

master
dev 1 year ago
parent bf5dafda2d
commit 74ce9edfa9

@ -6,14 +6,17 @@ import {normalizeModuleId} from "vite/module-runner";
export const proyecto : Proyecto = { export const proyecto : Proyecto = {
nombre : 'Quaddro2', nombre : 'Quaddro2',
urlProyecto: 'https://www.ebrosa.com/obra-nueva/madrid/madrid-ensanche-vallecas/quaddro-2-ensanche-vallecas',
imagesEstancias : './imgs/quaddro2/est/', imagesEstancias : './imgs/quaddro2/est/',
logos : { logos : {
'default' : "./imgs/quaddro2/logo_default.png" 'default' : "./imgs/quaddro2/logo_default.png"
}, },
textos : { textos : {
'slogan' : 'Living', 'slogan' : 'Living',
'nombre_pdf' : 'mi_quaddro2.pdf',
'descripcion' : 'Esto es la descripción', 'descripcion' : 'Esto es la descripción',
'aviso_suelo' : 'Tenga en cuenta que el pavimento es uniforme en toda la vivienda. La selección que realice para el salón será la misma para todas las demás estancias. La imagen mostrada es únicamente a título ilustrativo.', 'aviso_suelo' : 'Tenga en cuenta que el pavimento es uniforme en toda la vivienda. La selección que realice para el salón será la misma para todas las demás estancias. La imagen mostrada es únicamente a título ilustrativo.',
'aviso_abierta' : 'La opción de cocina abierta solo está disponible en determinadas tipologías de vivienda, consulte la suya',
'aviso_puerta' : 'La opción de puerta corredera solo está disponible en determinadas tipologías de vivienda, consulte la suya', 'aviso_puerta' : 'La opción de puerta corredera solo está disponible en determinadas tipologías de vivienda, consulte la suya',
'aviso_lavadora': 'La opción de Lavadora integrable Balay esta disponible en determinadas tipologías, consulte la suya', 'aviso_lavadora': 'La opción de Lavadora integrable Balay esta disponible en determinadas tipologías, consulte la suya',
@ -154,7 +157,7 @@ export const proyecto : Proyecto = {
adds : { adds : {
'abr' : { 'abr' : {
nombre : 'Cocina abierta', nombre : 'Cocina abierta',
hideImg: true filtro : 'abierta'
}, },
'led' : { 'led' : {
nombre : 'Tira led encimera', nombre : 'Tira led encimera',

@ -76,7 +76,9 @@ export interface ProyectoImagenes {
export interface Proyecto { export interface Proyecto {
nombre : string; nombre : string;
urlProyecto: string;
imagesEstancias : string; imagesEstancias : string;
logos : Record<string, string>; logos : Record<string, string>;
textos : Record<string, string>; textos : Record<string, string>;
imagenes : ProyectoImagenes imagenes : ProyectoImagenes

@ -4,9 +4,7 @@
import {dataApp} from "../../data/data_app"; import {dataApp} from "../../data/data_app";
import { sectionState, type ActiveSection } from "../stores/router.svelte"; import { sectionState, type ActiveSection } from "../stores/router.svelte";
import { modalWindow } from "../stores/modal.svelte"; import { modalWindow } from "../stores/modal.svelte";
import {imagesNames, imageSrc} from "../stores/sel.svelte"; import PdfBoton from "./PdfBoton.svelte";
import ImagenEstancia from "./ImagenEstancia.svelte";
import {generatePdf} from "../utils/pdfGenerador";
@ -25,9 +23,7 @@
function createPdf () {
generatePdf(imagesNames());
}
</script> </script>
@ -82,11 +78,7 @@
</button> </button>
{/if} {/if}
{/each} {/each}
<button type="button" <PdfBoton />
class="px-3 lg:px-4 py-2 rounded-md text-base font-medium transition-colors duration-200 text-white bg-green-900 hover:bg-green-700 cursor-pointer "
onclick={createPdf }>
Descargar Selección
</button>
</div> </div>
<div class="md:hidden"> <div class="md:hidden">

@ -0,0 +1,118 @@
<script lang="ts">
import type {PdfEstado} from "../../types/pdf_types";
import PdfPopup from "./PdfPopup.svelte";
import { jsPDF} from "jspdf";
import { pdfImages } from "../../data/data_pdfs_b64";
import { renderImages } from "../../data/data_images.b64";
import {imagesNames} from "../stores/sel.svelte";
let pdfEstado : PdfEstado = 'idle';
let pdfVisible = false;
let pdfMensaje = '';
async function generatePdf() {
pdfVisible = true;
pdfEstado = 'uploading';
const imageNames = imagesNames();
try {
const pdfDoc = new jsPDF({
orientation: 'landscape',
unit: 'mm',
format: 'a4',
});
const pageWidth = pdfDoc.internal.pageSize.getWidth();
const pageHeight = pdfDoc.internal.pageSize.getHeight();
const margin = 15;
// === Portada ===
const ini = pdfImages['pdf_quaddro_ini'];
if (ini) {
const iniFormat = ini.includes('jpeg') ? 'JPEG' : 'PNG';
pdfDoc.addImage(ini, iniFormat, 0, 0, pageWidth, pageHeight, '', 'FAST');
pdfDoc.addPage();
}
// === Imágenes del array ===
imageNames.forEach((name, index) => {
const base64 = renderImages[name];
if (!base64) {
console.log('no existe la imagen ', name)
return;
}
// Datos de la imagen original
const imgPixelWidth = 1500;
const imgPixelHeight = 1500;
const pageRatio = pageWidth / pageHeight;
const imgRatio = imgPixelWidth / imgPixelHeight;
// Calcular tamaño para que mantenga proporción y ajuste a la altura de página
let renderWidth: number;
let renderHeight: number;
if (imgRatio > pageRatio) {
// Imagen más ancha que alta → ajustamos al alto
renderHeight = pageHeight - 2 * margin;
renderWidth = renderHeight * imgRatio;
} else {
// Imagen más alta → también ajustamos al alto
renderHeight = pageHeight - 2 * margin;
renderWidth = renderHeight * imgRatio;
}
// Posición alineada a la izquierda con margen de 15 mm
const x = margin;
const y = (pageHeight - renderHeight) / 2;
pdfDoc.addImage(base64, 'JPEG', x, y, renderWidth, renderHeight, '', 'FAST');
// Añadir nueva página excepto en la última
if (index < imageNames.length - 1) pdfDoc.addPage();
});
// === Página final ===
pdfDoc.addPage();
const fin = pdfImages['pdf_quaddro_fin'];
if (fin) {
const finFormat = fin.includes('jpeg') ? 'JPEG' : 'PNG';
pdfDoc.addImage(fin, finFormat, 0, 0, pageWidth, pageHeight, '', 'FAST');
}
//pdfDoc.save(proyecto.textos.nombre_pdf ?? 'mi_seleccion.pdf');
pdfEstado = 'success'
} catch (err: any) {
pdfEstado = 'error';
pdfMensaje = err?.message || 'Error desconocido';
} finally {
setTimeout(() => {
pdfVisible = false;
pdfEstado = 'idle';
}, 2500);
}
}
</script>
<button type="button"
class="px-3 lg:px-4 py-2 rounded-md text-base font-medium transition-colors duration-200 text-white bg-green-900 hover:bg-green-700 cursor-pointer transition"
onclick={() => generatePdf()}>
Descargar Selección
</button>
<PdfPopup {pdfVisible} {pdfMensaje} {pdfEstado} />

@ -0,0 +1,48 @@
<script lang="ts">
import { fade, scale } from 'svelte/transition';
import type {PdfEstado} from "../../types/pdf_types";
import {cubicOut} from "svelte/easing";
let { pdfVisible, pdfEstado, pdfMensaje } = $props< {
pdfEstado: PdfEstado;
pdfVisible: boolean;
pdfMensaje: string ;
}> ();
console.log('Pdf Poop',pdfVisible);
</script>
{#if pdfVisible}
<!-- Fondo oscuro con fundido -->
<div
transition:fade={{ duration: 200, easing: cubicOut }}
class="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
>
<!-- Contenedor del popup con entrada tipo zoom -->
<div
transition:scale={{ duration: 250, easing: cubicOut }}
class="bg-white rounded-2xl p-8 w-100 text-center shadow-xl"
>
{#if pdfEstado === 'loading'}
<div class="flex flex-col items-center space-y-4">
<div class="w-10 h-10 border-4 border-gray-300 border-t-blue-500 rounded-full animate-spin"></div>
<p class="text-gray-700">Generando PDF...</p>
</div>
{:else if pdfEstado === 'success'}
<div class="text-green-600 text-lg font-semibold">
✅ PDF generado correctamente
</div>
{:else if pdfEstado === 'error'}
<div class="text-red-600 text-lg font-semibold">
❌ Error al generar PDF
</div>
<p class="text-gray-600 text-sm mt-2">{pdfMensaje}</p>
{/if}
</div>
</div>
{/if}

@ -38,5 +38,11 @@ export const filtros : Record <string, Filtro> = {
tipo: 'notify', tipo: 'notify',
txt : proyecto.textos.aviso_puerta, txt : proyecto.textos.aviso_puerta,
check : (value : string) : boolean => true, check : (value : string) : boolean => true,
},
'abierta': {
tipo : 'notify',
txt : 'proyecto.textos.aviso_puerta',
check : (value : string) : boolean => true,
} }
} }

@ -0,0 +1,4 @@
export type PdfEstado = 'idle' | 'uploading' | 'success' | 'error'

@ -1,13 +1,14 @@
import {defineConfig} from 'vite' import {defineConfig} from 'vite'
import tailwindcss from "@tailwindcss/vite"; import tailwindcss from "@tailwindcss/vite";
import {svelte} from '@sveltejs/vite-plugin-svelte'; import {svelte} from '@sveltejs/vite-plugin-svelte';
import {viteSingleFile} from "vite-plugin-singlefile";
//import { viteSingleFile } from 'vite-plugin-singlefile'; //import { viteSingleFile } from 'vite-plugin-singlefile';
export default defineConfig({ export default defineConfig({
base: './', base: './',
plugins: [svelte(),tailwindcss()/*,viteSingleFile()*/], plugins: [svelte(),tailwindcss(),viteSingleFile()],
css: { css: {
/* transformer: 'lightningcss' // Opcional, pero recomendado en v4 para mejor rendimiento */ /* transformer: 'lightningcss' // Opcional, pero recomendado en v4 para mejor rendimiento */
}, },

Loading…
Cancel
Save

Powered by TurnKey Linux.