libreria-astro-lefebvre 0.1.83 → 0.1.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "libreria-astro-lefebvre",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.85",
|
|
4
4
|
"description": "Librería de componentes Astro, React y Vue para Lefebvre",
|
|
5
5
|
"author": "Equipo web desarrollo Lefebvre",
|
|
6
6
|
"type": "module",
|
|
@@ -42,4 +42,3 @@
|
|
|
42
42
|
"typescript": "^5.8.3"
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
|
|
@@ -36,7 +36,7 @@ export const metadata: ComponentMetadata = {
|
|
|
36
36
|
{
|
|
37
37
|
name: 'imageAlt',
|
|
38
38
|
type: 'text',
|
|
39
|
-
help: 'Texto alternativo de la imagen de fondo
|
|
39
|
+
help: 'Texto alternativo de la imagen de fondo. Al ser una imagen decorativa detrás del texto, lo recomendable es dejarlo VACÍO (el lector de pantalla la ignorará). Rellenar solo si la imagen aporta información que no está en el título ni en la descripción',
|
|
40
40
|
label: 'Alt de la imagen',
|
|
41
41
|
mandatory: false,
|
|
42
42
|
example_value: 'Dos profesionales revisando documentación en una tablet'
|
|
@@ -44,7 +44,7 @@ export const metadata: ComponentMetadata = {
|
|
|
44
44
|
{
|
|
45
45
|
name: 'ctaText',
|
|
46
46
|
type: 'text',
|
|
47
|
-
help: 'Texto del botón CTA. El botón SOLO se muestra en móvil (en escritorio el diseño no lo incluye). Si se deja vacío, no aparece ningún botón',
|
|
47
|
+
help: 'Texto del botón CTA. El botón SOLO se muestra en móvil (en escritorio el diseño no lo incluye). Si se deja vacío el texto o la URL, no aparece ningún botón',
|
|
48
48
|
label: 'Texto del botón (solo móvil)',
|
|
49
49
|
mandatory: false,
|
|
50
50
|
example_value: 'Pruébalo ya'
|
|
@@ -52,7 +52,7 @@ export const metadata: ComponentMetadata = {
|
|
|
52
52
|
{
|
|
53
53
|
name: 'ctaUrl',
|
|
54
54
|
type: 'text',
|
|
55
|
-
help: 'URL de destino del botón CTA móvil.
|
|
55
|
+
help: 'URL de destino del botón CTA móvil. Obligatoria para que el botón se muestre: sin URL no se renderiza el botón aunque tenga texto',
|
|
56
56
|
label: 'URL del botón',
|
|
57
57
|
mandatory: false,
|
|
58
58
|
example_value: 'https://www.lefebvre.es/tienda/apuntes-y-consejos'
|
|
@@ -16,13 +16,18 @@ const {
|
|
|
16
16
|
fontSize = 'base',
|
|
17
17
|
alignItems = 'center',
|
|
18
18
|
h2Size = 'default',
|
|
19
|
+
h2SizeBreakpoint = 'lg',
|
|
19
20
|
h2MarginBottom = 'mb-8',
|
|
20
21
|
h2AlignClass = 'text-center lg:text-left',
|
|
21
22
|
h2TrackingClass = '',
|
|
22
|
-
imageAspectClass = '',
|
|
23
|
+
imageAspectClass = 'h-auto',
|
|
23
24
|
imageSizeClass = 'md:max-w-xl w-full md:w-[75%]',
|
|
24
25
|
columnGapClass = 'gap-6',
|
|
25
26
|
contentPaddingClass = 'p-4 pr-4',
|
|
27
|
+
rowBreakpoint = 'md',
|
|
28
|
+
contentWidthBreakpoint = 'lg',
|
|
29
|
+
outerPaddingClass = '',
|
|
30
|
+
rowMaxWidthClass = '',
|
|
26
31
|
loading = 'lazy' as 'lazy' | 'eager',
|
|
27
32
|
|
|
28
33
|
showBtn = false,
|
|
@@ -41,6 +46,23 @@ const {
|
|
|
41
46
|
const imageModalUrl = extractImageUrl(imageModal);
|
|
42
47
|
const randomId = Math.floor(Math.random() * 1000);
|
|
43
48
|
|
|
49
|
+
// Tailwind necesita ver cada clase completa de forma literal en el código para
|
|
50
|
+
// generarla — no puede resolver un prefijo de breakpoint interpolado en runtime
|
|
51
|
+
// (`${breakpoint}:utilidad`). Por eso aquí se enumeran las dos combinaciones
|
|
52
|
+
// posibles (md/lg) en vez de construir el prefijo dinámicamente.
|
|
53
|
+
const rowFlexClass = rowBreakpoint === 'lg' ? 'lg:flex' : 'md:flex';
|
|
54
|
+
const rowWidthClass = rowBreakpoint === 'lg' ? 'lg:w-4/5' : 'md:w-4/5';
|
|
55
|
+
const rowFlex1Class = rowBreakpoint === 'lg' ? 'lg:flex-1' : 'md:flex-1';
|
|
56
|
+
const rowMinW0Class = rowBreakpoint === 'lg' ? 'lg:min-w-0' : 'md:min-w-0';
|
|
57
|
+
const contentFlex1Class = contentWidthBreakpoint === 'lg' ? 'lg:flex-1' : 'md:flex-1';
|
|
58
|
+
const contentMinW0Class = contentWidthBreakpoint === 'lg' ? 'lg:min-w-0' : 'md:min-w-0';
|
|
59
|
+
const h2AltSizeClass = h2SizeBreakpoint === 'lg' ? 'lg:text-[40px]' : 'md:text-[40px]';
|
|
60
|
+
const h2AltLeadingClass = h2SizeBreakpoint === 'lg' ? 'lg:leading-[48px]' : 'md:leading-[48px]';
|
|
61
|
+
const h2IcoSizeClass = h2SizeBreakpoint === 'lg' ? 'lg:text-[46px]' : 'md:text-[46px]';
|
|
62
|
+
const h2IcoLeadingClass = h2SizeBreakpoint === 'lg' ? 'lg:leading-[54px]' : 'md:leading-[54px]';
|
|
63
|
+
const h2LargeSizeClass = h2SizeBreakpoint === 'lg' ? 'lg:text-[56px]' : 'md:text-[56px]';
|
|
64
|
+
const h2LargeLeadingClass = h2SizeBreakpoint === 'lg' ? 'lg:leading-[64px]' : 'md:leading-[64px]';
|
|
65
|
+
|
|
44
66
|
// Extraer todos los crops definidos en el carbin (base, skyscraper)
|
|
45
67
|
// Funciona igual con JSON de PageBuilder o con objeto simple { base: "url", skyscraper: "url" }
|
|
46
68
|
const crops = extractAllCrops(image) as Record<string, string>;
|
|
@@ -63,7 +85,7 @@ const videoUrl = iframeSrc || '';
|
|
|
63
85
|
<section class="w-full flex items-center justify-center">
|
|
64
86
|
{showImage ? (
|
|
65
87
|
<article class={`w-${width} flex flex-col items-center justify-center py-6`}>
|
|
66
|
-
<div class={`flex-col
|
|
88
|
+
<div class={`flex-col ${rowFlexClass} ${orientation === 'left' ? 'flex-row' : 'flex-row-reverse'} w-full ${rowWidthClass} ${rowMaxWidthClass} items-${alignItems} ${columnGapClass} ${outerPaddingClass}`}>
|
|
67
89
|
{showIco ? (
|
|
68
90
|
<div class={`flex ${flexOrientation === 'row' ? 'flex-row' : 'flex-col'} w-full md:w-1/2 gap-6 p-4`}>
|
|
69
91
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="w-[30px]">
|
|
@@ -76,7 +98,7 @@ const videoUrl = iframeSrc || '';
|
|
|
76
98
|
</svg>
|
|
77
99
|
<div class={`w-full ${orientation === 'left' ? `pl-[${paddingLeft}px]` : `pr-[${paddingLeft}px]`}`}>
|
|
78
100
|
{title && <h1 class="font-poppins text-[#262626] text-center lg:text-left text-base font-normal leading-6 rounded bg-[#F2F3F8] mb-8 w-fit py-2 px-3 mx-auto lg:mx-0" set:html={title}></h1>}
|
|
79
|
-
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ?
|
|
101
|
+
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ? `${h2AltSizeClass} leading-[44px] ${h2AltLeadingClass}` : `${h2IcoSizeClass} leading-[44px] ${h2IcoLeadingClass}`}`} set:html={subtitle}></h2>
|
|
80
102
|
|
|
81
103
|
<div
|
|
82
104
|
class={`text-[#363942] font-inter font-normal text-${fontSize} not-italic leading-6 flex flex-col gap-4 mb-8`}
|
|
@@ -110,10 +132,10 @@ const videoUrl = iframeSrc || '';
|
|
|
110
132
|
}
|
|
111
133
|
}
|
|
112
134
|
</style>
|
|
113
|
-
<div class={`w-full
|
|
135
|
+
<div class={`w-full ${contentFlex1Class} ${contentMinW0Class} ${contentPaddingClass} ${orientation === 'left' ? 'css-mq-pl-767' : 'pr-[var(--padding-left)] pl-0' }`}
|
|
114
136
|
style={{ 'padding-left': `${paddingLeft}px` }}>
|
|
115
137
|
{title && <h1 class="font-poppins text-[#262626] text-center lg:text-left text-base font-normal leading-6 rounded bg-[#F2F3F8] mb-8 w-fit py-2 px-3 mx-auto lg:mx-0" set:html={title}></h1>}
|
|
116
|
-
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ?
|
|
138
|
+
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ? `${h2AltSizeClass} leading-[44px] ${h2AltLeadingClass}` : `${h2LargeSizeClass} leading-[44px] ${h2LargeLeadingClass}`}`} set:html={subtitle}></h2>
|
|
117
139
|
<div
|
|
118
140
|
class={`text-[#363942] font-inter font-normal text-${fontSize} not-italic leading-6 flex flex-col gap-4 mb-8`}
|
|
119
141
|
set:html={description}
|
|
@@ -134,13 +156,13 @@ const videoUrl = iframeSrc || '';
|
|
|
134
156
|
|
|
135
157
|
)}
|
|
136
158
|
|
|
137
|
-
<div class={`w-full
|
|
159
|
+
<div class={`w-full ${rowFlex1Class} ${rowMinW0Class} p-4 flex items-center ${orientation === 'left' ? 'justify-end' : 'justify-start'} aspect-auto`}>
|
|
138
160
|
{videoUrl ? (
|
|
139
161
|
<video autoplay loop muted playsinline preload="metadata" width="600" height="450" class="md:max-w-xl w-full md:w-[75%] h-auto object-cover rounded-lg m-auto">
|
|
140
162
|
<source src={videoUrl} type="video/mp4" />
|
|
141
163
|
</video>
|
|
142
164
|
) : (
|
|
143
|
-
<img src={imageUrl} alt={title} width="600" height="450" class={`${imageSizeClass}
|
|
165
|
+
<img src={imageUrl} alt={title} width="600" height="450" class={`${imageSizeClass} object-cover rounded-lg m-auto ${imageAspectClass}`} loading={loading} />
|
|
144
166
|
)}
|
|
145
167
|
</div>
|
|
146
168
|
|
|
@@ -165,7 +187,7 @@ const videoUrl = iframeSrc || '';
|
|
|
165
187
|
|
|
166
188
|
<div class="w-1/2 p-4 flex flex-col flex-wrap ">
|
|
167
189
|
{title && <h1 class="font-poppins text-[#262626] text-center lg:text-left text-base font-normal leading-6 rounded bg-[#F2F3F8] mb-8 w-fit py-2 px-3 mx-auto lg:mx-0" set:html={title}></h1>}
|
|
168
|
-
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ?
|
|
190
|
+
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ? `${h2AltSizeClass} leading-[44px] ${h2AltLeadingClass}` : `${h2LargeSizeClass} leading-[44px] ${h2LargeLeadingClass}`}`} set:html={subtitle}></h2>
|
|
169
191
|
<div
|
|
170
192
|
class="text-[#363942] font-inter font-normal text-base not-italic leading-6 flex flex-col gap-4 mb-8"
|
|
171
193
|
set:html={description}
|
|
@@ -188,7 +210,7 @@ const videoUrl = iframeSrc || '';
|
|
|
188
210
|
) : (
|
|
189
211
|
<div class="w-1/2 p-4 flex flex-col flex-wrap ">
|
|
190
212
|
{title && <h1 class="font-poppins text-[#262626] text-center lg:text-left text-base font-normal leading-6 rounded bg-[#F2F3F8] mb-8 w-fit py-2 px-3 mx-auto lg:mx-0" set:html={title}></h1>}
|
|
191
|
-
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ?
|
|
213
|
+
<h2 class={`font-poppins text-[#262626] font-normal ${h2AlignClass} ${h2TrackingClass} pr-6 ${h2MarginBottom} mx-auto lg:mx-0 text-[36px] ${h2Size === '40px' ? `${h2AltSizeClass} leading-[44px] ${h2AltLeadingClass}` : `${h2LargeSizeClass} leading-[44px] ${h2LargeLeadingClass}`}`} set:html={subtitle}></h2>
|
|
192
214
|
<div
|
|
193
215
|
class="text-[#363942] font-inter font-normal text-base not-italic leading-6 flex flex-col gap-4 mb-8"
|
|
194
216
|
set:html={description}
|
|
@@ -5,33 +5,42 @@ const {
|
|
|
5
5
|
title,
|
|
6
6
|
description,
|
|
7
7
|
image,
|
|
8
|
-
imageAlt
|
|
8
|
+
imageAlt,
|
|
9
9
|
ctaText,
|
|
10
|
-
ctaUrl
|
|
10
|
+
ctaUrl
|
|
11
11
|
} = Astro.props;
|
|
12
|
+
|
|
13
|
+
// ACCESIBILIDAD Imagen de fondo: si no llega alt (undefined o null desde Mecano) forzamos alt="" para que el lector de pantalla no anuncie el nombre del fichero.
|
|
14
|
+
const safeImageAlt = imageAlt ?? '';
|
|
15
|
+
|
|
16
|
+
// ACCESIBILIDAD El CTA solo se renderiza si hay texto Y URL; evita enlaces "#" que solo saltan al inicio de la página.
|
|
17
|
+
const showCta = Boolean(ctaText && ctaUrl);
|
|
18
|
+
|
|
19
|
+
// ACCESIBILIDAD Id único por instancia para enlazar la sección con su h1 (aria-labelledby) sin colisionar si hay varios heros.
|
|
20
|
+
const titleId = 'hero-title-' + Math.random().toString(36).substring(2, 10);
|
|
12
21
|
---
|
|
13
22
|
|
|
14
|
-
<section class="relative w-full overflow-hidden bg-gray-100">
|
|
23
|
+
<section class="relative w-full overflow-hidden bg-gray-100" aria-labelledby={title ? titleId : undefined}>
|
|
15
24
|
<LimboImage
|
|
16
25
|
src={image}
|
|
17
|
-
alt={
|
|
26
|
+
alt={safeImageAlt}
|
|
18
27
|
class="absolute inset-0 w-full h-full object-cover object-left md:object-center"
|
|
19
28
|
loading="eager"
|
|
20
29
|
/>
|
|
21
30
|
<div class="relative max-w-7xl w-full mx-auto flex items-center min-h-[600px] px-8 md:px-0">
|
|
22
|
-
<div class="w-full md:w-1/2 flex flex-col items-start gap-8 py-8 md:py-20 md:pr-16">
|
|
31
|
+
<div class="w-full md:w-1/2 flex flex-col items-start gap-8 pl-8 py-8 md:pl-6 md:py-20 md:pr-16">
|
|
23
32
|
<div class="flex flex-col gap-4 w-full">
|
|
24
33
|
{title && (
|
|
25
|
-
<h1 class="font-poppins text-[#262626] text-4xl leading-[44px] tracking-[-0.5px] font-semibold md:text-[56px] md:leading-[64px] md:tracking-[-1px] md:font-normal" set:html={title}></h1>
|
|
34
|
+
<h1 id={titleId} class="font-poppins text-[#262626] text-4xl leading-[44px] tracking-[-0.5px] font-semibold md:text-[56px] md:leading-[64px] md:tracking-[-1px] md:font-normal" set:html={title}></h1>
|
|
26
35
|
)}
|
|
27
36
|
{description && (
|
|
28
37
|
<p class="font-poppins text-[#262626] text-[28px] leading-9 md:text-[32px] md:leading-10 font-normal" set:html={description}></p>
|
|
29
38
|
)}
|
|
30
39
|
</div>
|
|
31
|
-
{
|
|
40
|
+
{showCta && (
|
|
32
41
|
<a
|
|
33
42
|
href={ctaUrl}
|
|
34
|
-
class="md:hidden inline-flex items-center justify-center w-fit h-
|
|
43
|
+
class="md:hidden inline-flex items-center justify-center w-fit min-h-11 h-11 px-4 rounded-lg bg-[#00092CE5] text-white font-inter text-base font-semibold leading-6 shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[#00092C]"
|
|
35
44
|
>
|
|
36
45
|
{ctaText}
|
|
37
46
|
</a>
|