feat: improved printing settings

This commit is contained in:
2026-07-14 10:16:47 +02:00
parent 8d9d95ddf5
commit c1afd5a6d4
5 changed files with 71 additions and 25 deletions
+46 -18
View File
@@ -38,44 +38,72 @@
}
/* Al exportar/imprimir, solo se muestra #panel-output (y no sus propios
controles, marcados con .no-print), ocultando el resto de la página. */
controles, ni el resto de la página), todo ello marcado con .no-print
(#panel-top, la cabecera, las pestañas, "Personalización de página",
el título "Vista previa"...).
Se usa display:none (no visibility:hidden) para ocultarlo: un elemento
en visibility:hidden sigue ocupando su espacio en el documento, así que
con eso todo el contenido oculto (secciones, botones...) seguía
contando para la altura total y generaba varias páginas en blanco de
más al imprimir. */
@media print {
body * {
visibility: hidden;
.no-print {
display: none;
}
@page { margin: 0; }
/* Pinta toda la hoja (no solo la caja de #panel-output, que puede
quedarse más corta que la página) con el color de fondo elegido en
"Personalización de página". La variable la actualiza
page-settings.js; aquí no se toca nada más de <html>/<body> para no
afectar a la pantalla de edición, solo a la impresión. */
html,
body,
#panel-output,
#panel-output * {
visibility: visible;
/* Los navegadores no imprimen colores de fondo por defecto (dependen de
la opción "Gráficos de fondo" del diálogo de impresión, que el
usuario puede tener desmarcada); esto fuerza a respetar los colores
elegidos en una sección de "Nota" aunque esa opción esté desactivada. */
elegidos en una sección de "Nota" (y el fondo de página) aunque esa
opción esté desactivada. */
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
#panel-output .no-print {
display: none;
html,
body {
/* Si no queda un poco de espacio en blanco al final del documento
cuando el contenido no llena una página entera: <html> es el
elemento "raíz" y su fondo (si lo tiene) es el que se usa para
rellenar toda la hoja (por delante del de <body>), así que Tailwind
o daisyUI podían estar aplicándole ya un color propio con más peso
que esta regla; !important fuerza a que gane siempre el elegido
aquí, tanto en <html> como en <body>. */
background-color: var(--print-page-bg-color, #ffffff) !important;
}
/* Firefox no siempre extiende el fondo de <html>/<body> más allá de su
contenido cuando este no llena una página entera (a diferencia de
Chrome, que sí lo hace); para no depender de eso, se fuerza a que la
propia caja de #panel-output mida al menos una página de alto, así su
propio fondo (el mismo color, ya aplicado en JS) cubre ese hueco
también en Firefox. */
#panel-output {
position: absolute;
top: 0;
left: 0;
min-height: 100vh;
width: 100%;
border: none;
/* @page tiene margin: 0 (ver más abajo), así que sin esto el contenido
llegaría hasta el borde físico de la hoja. Se pone aquí (como
padding del propio contenido) en vez de en @page porque el soporte
de "margin" en @page es más inconsistente entre navegadores. */
/* Por defecto el padding de una caja que ocupa varias páginas solo se
aplica una vez, al principio y al final de toda la caja (no en cada
página); box-decoration-break: clone hace que cada fragmento (cada
página) se trate como una caja independiente con su propia copia del
padding, así el hueco queda igual en todas las páginas. Se hace así
(en vez de con @page margin) porque @page margin puede quedar
invalidado por el propio ajuste de "Márgenes" del diálogo de
impresión del navegador si el usuario no lo deja en "Predeterminado".*/
padding: 2cm;
box-sizing: border-box;
}
#preview-title {
display: none;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
}
+2 -2
View File
@@ -110,7 +110,7 @@
<div class="flex flex-col md:flex-row gap-4">
<section id="panel-top" class="w-full md:w-1/2 border border-base-300 rounded-box p-4">
<section id="panel-top" class="w-full md:w-1/2 border border-base-300 rounded-box p-4 no-print">
<div class="flex items-center justify-between mb-2">
<h2 class="text-lg font-semibold">Secciones</h2>
<button id="toggle-collapse-all" type="button" class="btn btn-xs btn-outline"
@@ -144,7 +144,7 @@
</section>
<section id="panel-output" class="w-full md:w-1/2 border border-base-300 rounded-box p-4 panel-hidden-mobile">
<h2 id="preview-title" class="text-lg font-semibold mb-2">Vista previa</h2>
<h2 id="preview-title" class="text-lg font-semibold mb-2 no-print">Vista previa</h2>
<div id="panel-output-text" class="text-sm"
data-empty-message="Añade una sección para ver aquí el resultado."></div>
</section>
+9
View File
@@ -28,6 +28,15 @@ export function renderPageMeta() {
panelOutput.style.fontFamily = pageFontSelect.value;
pageSizeStyle.textContent = `@page { size: ${pageSizeSelect.value} ${pageOrientationSelect.value}; }`;
document.title = pageTitleInput.value.trim() || 'Crochet';
// El color de fondo también se guarda en una variable CSS en :root, para
// que css/main.css pueda pintar con él toda la hoja al imprimir (no solo
// la caja de #panel-output, que puede quedarse más corta que la página).
// Se hace así, en vez de aplicar el color directamente a <body>, para no
// cambiar también el fondo de toda la pantalla de edición: la variable no
// pinta nada por sí sola en pantalla, solo la consume la regla @media
// print de más abajo.
document.documentElement.style.setProperty('--print-page-bg-color', pageBgColorInput.value);
}
export function serializePageSettings() {
+6 -1
View File
@@ -250,7 +250,7 @@ const SECTION_TYPES = [
if (!img.src || img.classList.contains('hidden')) return;
const clone = document.createElement('img');
clone.src = img.src;
clone.className = 'max-w-full max-h-48 object-contain rounded-box my-2';
clone.className = 'max-w-full max-h-96 object-contain rounded-box my-2';
target.appendChild(clone);
},
},
@@ -357,8 +357,13 @@ export function buildSectionsFrom(sectionsData, container = sectionsContainer) {
// mismo mecanismo que restaura un patrón guardado.
const DEFAULT_SECTIONS = [
{ type: 'image', dataUrl: '' },
{
type: 'group',
children: [
{ type: 'title', text: {} },
{ type: 'materials', materials: [] },
]
},
{
type: 'group',
children: [
+6 -2
View File
@@ -97,7 +97,11 @@ export function createSectionShell(typeLabel) {
// un nombre derivado del contenido ("Título: Bufanda de lana") sin perder
// de vista cuál es la etiqueta de tipo original.
const badge = document.createElement('span');
badge.className = 'section-badge badge badge-sm badge-outline select-none';
// 'min-w-0 truncate': por defecto un elemento flex no encoge por debajo
// del tamaño de su contenido, así que un nombre largo (p.ej. una lista de
// materiales) desbordaba la cabecera en pantallas estrechas en vez de
// recortarse con "…".
badge.className = 'section-badge badge badge-sm badge-outline select-none min-w-0 truncate';
badge.textContent = typeLabel;
badge.dataset.typeLabel = typeLabel;
@@ -318,7 +322,7 @@ export function addImageSection(data, dataUrl = '', container = sectionsContaine
fileInput.className = 'file-input file-input-bordered w-full mb-2';
const img = document.createElement('img');
img.className = 'max-w-full max-h-48 object-contain rounded-box hidden';
img.className = 'max-w-full max-h-96 object-contain rounded-box hidden';
if (dataUrl) {
img.src = dataUrl;