feat: added customization options
This commit is contained in:
+21
-1
@@ -68,6 +68,10 @@
|
|||||||
<span class="text-sm">Color del texto</span>
|
<span class="text-sm">Color del texto</span>
|
||||||
<input id="page-text-color" type="color" value="#000000">
|
<input id="page-text-color" type="color" value="#000000">
|
||||||
</label>
|
</label>
|
||||||
|
<label class="flex flex-col gap-1">
|
||||||
|
<span class="text-sm">Color de acento (títulos)</span>
|
||||||
|
<input id="page-accent-color" type="color" value="#1d4ed8">
|
||||||
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1">
|
||||||
<span class="text-sm">Color de fondo</span>
|
<span class="text-sm">Color de fondo</span>
|
||||||
<input id="page-bg-color" type="color" value="#ffffff">
|
<input id="page-bg-color" type="color" value="#ffffff">
|
||||||
@@ -82,6 +86,22 @@
|
|||||||
<option value="'Courier New', monospace">Monoespaciada</option>
|
<option value="'Courier New', monospace">Monoespaciada</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="flex flex-col gap-1">
|
||||||
|
<span class="text-sm">Tamaño de letra</span>
|
||||||
|
<select id="page-font-size-select" class="select select-bordered select-sm">
|
||||||
|
<option value="0.875rem">Pequeño</option>
|
||||||
|
<option value="1rem" selected>Normal</option>
|
||||||
|
<option value="1.25rem">Grande</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="flex flex-col gap-1">
|
||||||
|
<span class="text-sm">Alineación del texto</span>
|
||||||
|
<select id="page-align-select" class="select select-bordered select-sm">
|
||||||
|
<option value="left" selected>Izquierda</option>
|
||||||
|
<option value="center">Centrado</option>
|
||||||
|
<option value="justify">Justificado</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1">
|
||||||
<span class="text-sm">Tamaño de página</span>
|
<span class="text-sm">Tamaño de página</span>
|
||||||
<select id="page-size-select" class="select select-bordered select-sm">
|
<select id="page-size-select" class="select select-bordered select-sm">
|
||||||
@@ -145,7 +165,7 @@
|
|||||||
|
|
||||||
<section id="panel-output" class="w-full md:w-1/2 border border-base-300 rounded-box p-4 panel-hidden-mobile">
|
<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 no-print">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"
|
<div id="panel-output-text"
|
||||||
data-empty-message="Añade una sección para ver aquí el resultado."></div>
|
data-empty-message="Añade una sección para ver aquí el resultado."></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ export const panelOutput = document.getElementById('panel-output');
|
|||||||
export const pageTitleInput = document.getElementById('page-title-input');
|
export const pageTitleInput = document.getElementById('page-title-input');
|
||||||
export const pageAuthorInput = document.getElementById('page-author-input');
|
export const pageAuthorInput = document.getElementById('page-author-input');
|
||||||
export const pageTextColorInput = document.getElementById('page-text-color');
|
export const pageTextColorInput = document.getElementById('page-text-color');
|
||||||
|
export const pageAccentColorInput = document.getElementById('page-accent-color');
|
||||||
export const pageBgColorInput = document.getElementById('page-bg-color');
|
export const pageBgColorInput = document.getElementById('page-bg-color');
|
||||||
export const pageFontSelect = document.getElementById('page-font-select');
|
export const pageFontSelect = document.getElementById('page-font-select');
|
||||||
|
export const pageFontSizeSelect = document.getElementById('page-font-size-select');
|
||||||
|
export const pageAlignSelect = document.getElementById('page-align-select');
|
||||||
export const pageSizeSelect = document.getElementById('page-size-select');
|
export const pageSizeSelect = document.getElementById('page-size-select');
|
||||||
export const pageOrientationSelect = document.getElementById('page-orientation-select');
|
export const pageOrientationSelect = document.getElementById('page-orientation-select');
|
||||||
export const pageSizeStyle = document.getElementById('page-size-style');
|
export const pageSizeStyle = document.getElementById('page-size-style');
|
||||||
|
|||||||
+47
-12
@@ -1,31 +1,44 @@
|
|||||||
// Personalización de página: título, autor, color de texto y de fondo,
|
// Personalización de página: título, autor, color de texto/acento/fondo,
|
||||||
// tipografía y tamaño/orientación del PDF. A diferencia de las secciones,
|
// tipografía, tamaño y alineación de letra, y tamaño/orientación del PDF.
|
||||||
// es única para todo el documento (no se repite, reordena ni duplica), así
|
// A diferencia de las secciones, es única para todo el documento (no se
|
||||||
// que no pasa por serializeSections()/buildSectionsFrom(): se guarda
|
// repite, reordena ni duplica), así que no pasa por
|
||||||
// aparte (ver storage.js) y se aplica directamente sobre #panel-output.
|
// serializeSections()/buildSectionsFrom(): se guarda aparte (ver
|
||||||
|
// storage.js) y se aplica directamente sobre #panel-output.
|
||||||
|
|
||||||
import {
|
import {
|
||||||
panelOutput,
|
panelOutput,
|
||||||
|
outputText,
|
||||||
pageTitleInput,
|
pageTitleInput,
|
||||||
pageAuthorInput,
|
pageAuthorInput,
|
||||||
pageTextColorInput,
|
pageTextColorInput,
|
||||||
|
pageAccentColorInput,
|
||||||
pageBgColorInput,
|
pageBgColorInput,
|
||||||
pageFontSelect,
|
pageFontSelect,
|
||||||
|
pageFontSizeSelect,
|
||||||
|
pageAlignSelect,
|
||||||
pageSizeSelect,
|
pageSizeSelect,
|
||||||
pageOrientationSelect,
|
pageOrientationSelect,
|
||||||
pageSizeStyle,
|
pageSizeStyle,
|
||||||
} from './dom-refs.js';
|
} from './dom-refs.js';
|
||||||
|
|
||||||
// Aplica a #panel-output el color de texto/fondo y la tipografía elegidos,
|
// Aplica a #panel-output el color de texto/fondo, la tipografía, el
|
||||||
// el tamaño de página al diálogo de impresión (a través de un <style>
|
// tamaño de letra y la alineación elegidos, el tamaño de página al diálogo
|
||||||
// propio, ya que @page no se puede tocar como una propiedad normal desde
|
// de impresión (a través de un <style> propio, ya que @page no se puede
|
||||||
// JS), y el título del patrón como título de la pestaña del navegador (que
|
// tocar como una propiedad normal desde JS), y el título del patrón como
|
||||||
// de paso el propio navegador suele usar como nombre sugerido al exportar
|
// título de la pestaña del navegador (que de paso el propio navegador
|
||||||
// a PDF).
|
// suele usar como nombre sugerido al exportar a PDF).
|
||||||
export function renderPageMeta() {
|
export function renderPageMeta() {
|
||||||
panelOutput.style.color = pageTextColorInput.value;
|
panelOutput.style.color = pageTextColorInput.value;
|
||||||
panelOutput.style.backgroundColor = pageBgColorInput.value;
|
panelOutput.style.backgroundColor = pageBgColorInput.value;
|
||||||
panelOutput.style.fontFamily = pageFontSelect.value;
|
panelOutput.style.fontFamily = pageFontSelect.value;
|
||||||
|
panelOutput.style.textAlign = pageAlignSelect.value;
|
||||||
|
// En #panel-output-text (no en #panel-output): los títulos/notas/etc. ya
|
||||||
|
// usan sus propios tamaños relativos en "em" (ver render.js y
|
||||||
|
// section-types.js) para escalar junto con este valor. `rem` (lo que usan
|
||||||
|
// las clases normales de Tailwind, como "text-lg") ignora el font-size de
|
||||||
|
// cualquier ancestro y solo mira el de <html>, así que aplicar esto más
|
||||||
|
// arriba (o dejar clases en rem por debajo) no tenía ningún efecto.
|
||||||
|
outputText.style.fontSize = pageFontSizeSelect.value;
|
||||||
pageSizeStyle.textContent = `@page { size: ${pageSizeSelect.value} ${pageOrientationSelect.value}; }`;
|
pageSizeStyle.textContent = `@page { size: ${pageSizeSelect.value} ${pageOrientationSelect.value}; }`;
|
||||||
document.title = pageTitleInput.value.trim() || 'Crochet';
|
document.title = pageTitleInput.value.trim() || 'Crochet';
|
||||||
|
|
||||||
@@ -37,6 +50,13 @@ export function renderPageMeta() {
|
|||||||
// pinta nada por sí sola en pantalla, solo la consume la regla @media
|
// pinta nada por sí sola en pantalla, solo la consume la regla @media
|
||||||
// print de más abajo.
|
// print de más abajo.
|
||||||
document.documentElement.style.setProperty('--print-page-bg-color', pageBgColorInput.value);
|
document.documentElement.style.setProperty('--print-page-bg-color', pageBgColorInput.value);
|
||||||
|
|
||||||
|
// El color de acento se expone igual, como variable CSS, para que
|
||||||
|
// section-types.js pueda usarlo en el título/subtítulo (con una clase
|
||||||
|
// Tailwind `text-[var(--accent-color)]`) sin que ese módulo tenga que
|
||||||
|
// importar nada de aquí: ambos solo necesitan estar de acuerdo en el
|
||||||
|
// nombre de la variable.
|
||||||
|
document.documentElement.style.setProperty('--accent-color', pageAccentColorInput.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function serializePageSettings() {
|
export function serializePageSettings() {
|
||||||
@@ -44,8 +64,11 @@ export function serializePageSettings() {
|
|||||||
title: pageTitleInput.value,
|
title: pageTitleInput.value,
|
||||||
author: pageAuthorInput.value,
|
author: pageAuthorInput.value,
|
||||||
textColor: pageTextColorInput.value,
|
textColor: pageTextColorInput.value,
|
||||||
|
accentColor: pageAccentColorInput.value,
|
||||||
bgColor: pageBgColorInput.value,
|
bgColor: pageBgColorInput.value,
|
||||||
font: pageFontSelect.value,
|
font: pageFontSelect.value,
|
||||||
|
fontSize: pageFontSizeSelect.value,
|
||||||
|
align: pageAlignSelect.value,
|
||||||
pageSize: pageSizeSelect.value,
|
pageSize: pageSizeSelect.value,
|
||||||
orientation: pageOrientationSelect.value,
|
orientation: pageOrientationSelect.value,
|
||||||
};
|
};
|
||||||
@@ -55,15 +78,27 @@ export function applyPageSettings(settings = {}) {
|
|||||||
pageTitleInput.value = settings.title || '';
|
pageTitleInput.value = settings.title || '';
|
||||||
pageAuthorInput.value = settings.author || '';
|
pageAuthorInput.value = settings.author || '';
|
||||||
pageTextColorInput.value = settings.textColor || '#000000';
|
pageTextColorInput.value = settings.textColor || '#000000';
|
||||||
|
pageAccentColorInput.value = settings.accentColor || '#1d4ed8';
|
||||||
pageBgColorInput.value = settings.bgColor || '#ffffff';
|
pageBgColorInput.value = settings.bgColor || '#ffffff';
|
||||||
pageFontSelect.value = settings.font || 'sans-serif';
|
pageFontSelect.value = settings.font || 'sans-serif';
|
||||||
|
pageFontSizeSelect.value = settings.fontSize || '1rem';
|
||||||
|
pageAlignSelect.value = settings.align || 'left';
|
||||||
pageSizeSelect.value = settings.pageSize || 'A4';
|
pageSizeSelect.value = settings.pageSize || 'A4';
|
||||||
pageOrientationSelect.value = settings.orientation || 'portrait';
|
pageOrientationSelect.value = settings.orientation || 'portrait';
|
||||||
renderPageMeta();
|
renderPageMeta();
|
||||||
}
|
}
|
||||||
|
|
||||||
[pageTitleInput, pageAuthorInput].forEach(el => el.addEventListener('input', renderPageMeta));
|
[pageTitleInput, pageAuthorInput].forEach(el => el.addEventListener('input', renderPageMeta));
|
||||||
[pageTextColorInput, pageBgColorInput, pageFontSelect, pageSizeSelect, pageOrientationSelect].forEach(el => {
|
[
|
||||||
|
pageTextColorInput,
|
||||||
|
pageAccentColorInput,
|
||||||
|
pageBgColorInput,
|
||||||
|
pageFontSelect,
|
||||||
|
pageFontSizeSelect,
|
||||||
|
pageAlignSelect,
|
||||||
|
pageSizeSelect,
|
||||||
|
pageOrientationSelect,
|
||||||
|
].forEach(el => {
|
||||||
el.addEventListener('input', renderPageMeta);
|
el.addEventListener('input', renderPageMeta);
|
||||||
el.addEventListener('change', renderPageMeta);
|
el.addEventListener('change', renderPageMeta);
|
||||||
});
|
});
|
||||||
|
|||||||
+5
-2
@@ -15,8 +15,11 @@ export function renderOutput() {
|
|||||||
// Título y autor del patrón (ver "Personalización de página"): son
|
// Título y autor del patrón (ver "Personalización de página"): son
|
||||||
// configuración de todo el documento, no una sección más, así que se
|
// configuración de todo el documento, no una sección más, así que se
|
||||||
// pintan siempre delante, haya o no secciones añadidas.
|
// pintan siempre delante, haya o no secciones añadidas.
|
||||||
appendOutputLine(outputText, 'h1', pageTitleInput.value.trim(), 'text-2xl font-bold mb-1');
|
// Tamaños en "em" (no las clases normales de Tailwind, en "rem") para que
|
||||||
appendOutputLine(outputText, 'p', pageAuthorInput.value.trim(), 'text-sm opacity-70 mb-2');
|
// escalen con el "Tamaño de letra" de #panel-output-text (ver
|
||||||
|
// page-settings.js): "rem" ignora el font-size de cualquier ancestro.
|
||||||
|
appendOutputLine(outputText, 'h1', pageTitleInput.value.trim(), 'text-[1.5em] font-bold mb-1');
|
||||||
|
appendOutputLine(outputText, 'p', pageAuthorInput.value.trim(), 'text-[0.875em] opacity-70 mb-2');
|
||||||
|
|
||||||
// Si aún no se ha añadido ninguna sección, avisar en vez de dejar el
|
// Si aún no se ha añadido ninguna sección, avisar en vez de dejar el
|
||||||
// resultado vacío.
|
// resultado vacío.
|
||||||
|
|||||||
+7
-3
@@ -135,8 +135,12 @@ const SECTION_TYPES = [
|
|||||||
create: (sectionData, container) => addTitleSection(addTitleBtn.dataset, sectionData?.text, container),
|
create: (sectionData, container) => addTitleSection(addTitleBtn.dataset, sectionData?.text, container),
|
||||||
matches: (section) => section.querySelector('.title-input'),
|
matches: (section) => section.querySelector('.title-input'),
|
||||||
serialize: (section, titleInput) => ({ type: 'title', text: getTranslations(titleInput) }),
|
serialize: (section, titleInput) => ({ type: 'title', text: getTranslations(titleInput) }),
|
||||||
|
// 'text-[var(--accent-color)]' lee la variable CSS que expone
|
||||||
|
// page-settings.js: así el título usa el color de acento elegido en
|
||||||
|
// "Personalización de página" sin que este módulo tenga que importar
|
||||||
|
// nada de allí, solo coincidir en el nombre de la variable.
|
||||||
render: (section, titleInput, target) =>
|
render: (section, titleInput, target) =>
|
||||||
appendOutputLine(target, 'h3', titleInput.value.trim(), 'text-lg font-bold mt-2 mb-1'),
|
appendOutputLine(target, 'h3', titleInput.value.trim(), 'text-[1.125em] font-bold mt-2 mb-1 text-[var(--accent-color)]'),
|
||||||
getName: (titleInput) => titleInput.value.trim(),
|
getName: (titleInput) => titleInput.value.trim(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -146,7 +150,7 @@ const SECTION_TYPES = [
|
|||||||
matches: (section) => section.querySelector('.subtitle-input'),
|
matches: (section) => section.querySelector('.subtitle-input'),
|
||||||
serialize: (section, subtitleInput) => ({ type: 'subtitle', text: getTranslations(subtitleInput) }),
|
serialize: (section, subtitleInput) => ({ type: 'subtitle', text: getTranslations(subtitleInput) }),
|
||||||
render: (section, subtitleInput, target) =>
|
render: (section, subtitleInput, target) =>
|
||||||
appendOutputLine(target, 'h4', subtitleInput.value.trim(), 'text-base font-semibold mt-1 mb-1'),
|
appendOutputLine(target, 'h4', subtitleInput.value.trim(), 'text-[1em] font-semibold mt-1 mb-1 text-[var(--accent-color)]'),
|
||||||
getName: (subtitleInput) => subtitleInput.value.trim(),
|
getName: (subtitleInput) => subtitleInput.value.trim(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -183,7 +187,7 @@ const SECTION_TYPES = [
|
|||||||
const text = noteInput.value.trim();
|
const text = noteInput.value.trim();
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
const note = document.createElement('div');
|
const note = document.createElement('div');
|
||||||
note.className = 'alert text-sm my-2';
|
note.className = 'alert text-[0.875em] my-2';
|
||||||
const textColorInput = section.querySelector('.note-text-color');
|
const textColorInput = section.querySelector('.note-text-color');
|
||||||
const bgColorInput = section.querySelector('.note-bg-color');
|
const bgColorInput = section.querySelector('.note-bg-color');
|
||||||
if (textColorInput) note.style.color = textColorInput.value;
|
if (textColorInput) note.style.color = textColorInput.value;
|
||||||
|
|||||||
Reference in New Issue
Block a user