libreria-astro-lefebvre 0.1.75 → 0.1.77

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.75",
3
+ "version": "0.1.77",
4
4
  "description": "Librería de componentes Astro, React y Vue para Lefebvre",
5
5
  "author": "Equipo web desarrollo Lefebvre",
6
6
  "type": "module",
@@ -19,7 +19,7 @@ export const metadata: ComponentMetadata = {
19
19
  },
20
20
  {
21
21
  name: 'description',
22
- type: 'text',
22
+ type: 'textArea',
23
23
  help: 'Descripción que aparece debajo del título. Admite HTML. Alineada a la izquierda',
24
24
  label: 'Texto de la descripción',
25
25
  mandatory: false,
@@ -0,0 +1,31 @@
1
+ import type { ComponentMetadata } from '../interfaces/types';
2
+
3
+ export const metadata: ComponentMetadata = {
4
+ component_name: 'Contenido_2026_Estepona',
5
+ category: 'Contenido con listas',
6
+ name: 'Sección de tabs interactivas con contenido y miniatura lateral, nombre de pestaña opcional 2026',
7
+ description: 'Sección con pestañas horizontales en la parte superior que, al hacerse click, muestran un panel con título grande, listado de ítems (icono + texto) a la izquierda e imagen a la derecha. Incluye script inline que gestiona la conmutación entre pestañas y resalta la activa. La primera pestaña es la que se muestra al cargar la página. El nombre de la pestaña es opcional: los elementos sin nombre se agrupan en un único panel sin título, y si solo existe una pestaña no se muestra la barra de botones. Incluye structured data schema.org (WebPageElement con mainEntity ItemList de las pestañas)',
8
+ framework: 'Astro',
9
+ priority: 1,
10
+ tags: ['contenido'],
11
+ fields: [
12
+ {
13
+ name: 'items',
14
+ type: 'list',
15
+ help: 'Listado de pestañas del tab. Cada pestaña tiene su nombre (opcional), contenido (items internos con icono y texto) e imagen. Los elementos con el mismo nombre de pestaña se agrupan en la misma pestaña; los elementos sin nombre se agrupan en un único panel sin título. Si solo hay una pestaña, no se muestra la barra de botones. La primera pestaña se muestra al cargar; las demás arrancan ocultas y se activan al hacer click en su botón',
16
+ label: 'Listado de pestañas',
17
+ mandatory: false,
18
+ items: {
19
+ type: 'object',
20
+ fields: [
21
+ { name: 'name', type: 'text', help: 'Introduce el nombre de la pestaña (opcional). Los elementos sin nombre se agrupan en un único panel sin título de pestaña', label: 'Nombre de la pestaña', example_value: 'Pestaña 1' },
22
+ { name: 'title', type: 'text', help: 'Título del elemento (h4)', label: 'Título', example_value: 'Redacción de contratos' },
23
+ { name: 'description', type: 'textArea', help: 'Descripción del elemento', label: 'Descripción', example_value: 'Genera borradores de contratos a partir de plantillas personalizables en segundos' },
24
+ { name: 'icon', type: 'text', help: 'Nombre del icono a mostrar junto al elemento. Consulta los valores aceptados en el componente Contenido_2026_Menorca', label: 'Icono', example_value: 'edit' },
25
+ { name: 'buttonUrl', type: 'text', help: 'Introduce la URL de destino del botón (Solo es necesario completar este campo en uno de los elementos de la misma pestaña)', label: 'URL del botón', example_value: 'https://lefebvre.es' },
26
+ { name: 'image', type: 'image', help: 'Introduce la URL de la imagen de la pestaña (Solo es necesario completar este campo en uno de los elementos de la misma pestaña)', label: 'Imagen', example_value: 'https://assets.lefebvre.es/media/img/preview-comp/comp-16-9.png' }
27
+ ]
28
+ }
29
+ }
30
+ ]
31
+ };
@@ -0,0 +1,175 @@
1
+ ---
2
+
3
+ import Contenido_2026_Menorca from './Contenido_2026_Menorca.astro';
4
+ import Titulo_2025_Algeciras from './Titulo_2025_Algeciras.astro';
5
+ import { extractImageUrl, PAGE_ENTITY_ID } from '../../lib/functions.js';
6
+
7
+ const {
8
+ items = [],
9
+ } = Astro.props;
10
+
11
+ // isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
12
+ // itemListId opcional: @id del ItemList (para ser mainEntity de la CollectionPage).
13
+ const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
14
+
15
+ type TabPoint = { title: string; description: string; icon: string; showIco: boolean };
16
+ type Tab = { name: string; buttonUrl: string; image: string; points: TabPoint[] };
17
+
18
+ // El nombre de pestaña es opcional: los items sin nombre se normalizan a '' y agrupan juntos.
19
+ const tabs = items.reduce((acc: Tab[], item: any) => {
20
+ const name = item.name || '';
21
+ const existing = acc.find((t: Tab) => t.name === name);
22
+ if (existing) {
23
+ if (!existing.buttonUrl && item.buttonUrl) existing.buttonUrl = item.buttonUrl;
24
+ if (!existing.image && item.image) existing.image = item.image;
25
+ existing.points.push({ title: item.title, description: item.description, icon: item.icon, showIco: !!item.icon });
26
+ } else {
27
+ acc.push({
28
+ name,
29
+ buttonUrl: item.buttonUrl || '',
30
+ image: item.image || '',
31
+ points: [{ title: item.title, description: item.description, icon: item.icon, showIco: !!item.icon }]
32
+ });
33
+ }
34
+ return acc;
35
+ }, []);
36
+
37
+ // Con una única pestaña no hay nada que conmutar: se omite la barra de botones.
38
+ const showTabBar = tabs.length > 1;
39
+ const tabNames = tabs.map((t: Tab) => t.name).filter(Boolean).join(' · ');
40
+
41
+ const identifier = 'js-megablock'+ Math.random().toString(36).substring(2, 15);
42
+
43
+ const escapeJson = (s = "") => String(s).replace(/<[^>]*>/g, '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/[\n\r\t]+/g, ' ');
44
+
45
+ const structuredData = `<script type="application/ld+json">
46
+ {
47
+ "@context": "https://schema.org",
48
+ "@type": "WebPageElement",${tabNames ? `
49
+ "name": "${escapeJson(tabNames)}",` : ''}
50
+ "mainEntity": {
51
+ "@type": "ItemList",${itemListId ? `
52
+ "@id": "${itemListId}",` : ''}${pageId ? `
53
+ "isPartOf": { "@id": "${pageId}" },` : ''}
54
+ "numberOfItems": ${tabs.length},
55
+ "itemListElement": [${tabs.map((tab: Tab, index: number) => `{
56
+ "@type": "ListItem",
57
+ "position": ${index + 1}${tab.name ? `,
58
+ "name": "${escapeJson(tab.name)}"` : ''}${tab.image ? `,
59
+ "image": "${escapeJson(extractImageUrl(tab.image))}"` : ''}${tab.buttonUrl ? `,
60
+ "url": "${escapeJson(tab.buttonUrl)}"` : ''}${tab.points && tab.points.length ? `,
61
+ "description": "${escapeJson(tab.points.map((p: TabPoint) => p.title).filter(Boolean).join(' · '))}"` : ''}
62
+ }`).join(',')}]
63
+ }
64
+ }
65
+ </script>`;
66
+
67
+ ---
68
+
69
+
70
+ <section class="w-full flex items-center justify-center">
71
+ <article class="w-full flex flex-col items-center justify-center">
72
+ {showTabBar && (
73
+ <div class="w-full flex justify-center items-center relative text-[56px] text-center font inter leading-[64px] mt-10">
74
+ <!-- <div class="flex bg-transparent md:bg-gray-50 md:border md:border-[#B6B7BB] rounded-lg"> -->
75
+ <div class="flex gap-1 md:gap-8 items-center">
76
+ {tabs.map((tab: Tab, index: number) => (
77
+ <p class="text-base">
78
+ <button data-linkedto={`${identifier}${index + 1}`}
79
+ class={`
80
+ btn py-3.5 px-5 font-inter
81
+ cursor-pointer border border-[#b6b7bb]
82
+ hover:border hover:border-[#5F6168] hover:!bg-[#ffffff] rounded-lg ${identifier}button
83
+ ${index === 0 ? 'active' : ''}
84
+ bg-F2F3F8 text-gray-100 max-w-10 max-h-5 text-[0px] md:w-[150px]
85
+ md:bg-gray-50 md:text-black md:max-w-none md:max-h-none md:text-[16px]
86
+ `}
87
+ >{tab.name || `Pestaña ${index + 1}`}</button>
88
+ </p>
89
+ ))}
90
+ </div>
91
+ </div>
92
+ )}
93
+ <div class="lg:max-w-7xl md:w-full px-6 md:w-4/5 md:px-0 col my-10">
94
+ {tabs.map((tab: Tab, index: number) => (
95
+ <div id={`${identifier}${index + 1}`} class={`${index === 0 ? '' : 'hidden'} collapse-arrow ${identifier}item`}>
96
+
97
+ <div class="w-full flex-col flex md:flex-row gap-4 md:gap-12">
98
+ <div class="w-full md:w-1/2">
99
+ <Contenido_2026_Menorca
100
+ flexOrientationIcoText="flex-row"
101
+ flexOrientationBlockIcoText="flex-col"
102
+ positionFlex="items-start"
103
+ positionBtnFlex="justify-start"
104
+ items={tab.points}
105
+ headingType="h4"
106
+ showBtn={false}
107
+ btnLabel="Ver experiencias de uso"
108
+ buttonUrl={tab.buttonUrl}
109
+ widthArticle="w-4/5"
110
+ />
111
+ </div>
112
+ <div class="w-full md:w-1/2 p-0 md:pr-2">
113
+ <img src={extractImageUrl(tab.image)} alt={tab.name || 'Imagen de sección'} width="600" height="450" loading="lazy" class="w-full min-h-auto lg:min-h-full object-cover rounded-xl" />
114
+ </div>
115
+ </div>
116
+
117
+ </div>
118
+ ))}
119
+ </div>
120
+ </article>
121
+ </section>
122
+
123
+
124
+
125
+ <style>
126
+ .bg-F2F3F8 {
127
+ background-color: #F2F3F8;
128
+ }
129
+ .active{
130
+ background-color: #ffffff;
131
+ border: 1px solid #5F6168;
132
+ color: black;
133
+ max-width: none;
134
+ max-height: none;
135
+ font-size: 16px;
136
+
137
+ &:hover{
138
+ background-color: #ffffff;
139
+ border: 1px solid #5F6168;
140
+ }
141
+ }
142
+ </style>
143
+
144
+ <script is:inline define:vars={{ identifier }}>
145
+
146
+ document.querySelectorAll(`.${identifier}button`).forEach(btn => {
147
+
148
+ btn.addEventListener('click', (e) => {
149
+ const linkedId = btn.getAttribute('data-linkedto');
150
+ const targetItem = document.getElementById(linkedId);
151
+ if (targetItem) {
152
+
153
+ const collapseCount = document.querySelectorAll(`.${identifier}item.collapse`).length;
154
+ const hiddenCount = document.querySelectorAll(`.${identifier}item.hidden`).length;
155
+ const desiredClass = collapseCount > hiddenCount ? 'collapse' : 'hidden';
156
+
157
+ document.querySelectorAll(`.${identifier}item`).forEach(item => {
158
+ if (item === targetItem) return;
159
+ if (item.classList.contains(desiredClass)) return;
160
+ item.classList.add(desiredClass);
161
+ });
162
+ targetItem.classList.toggle(desiredClass);
163
+
164
+
165
+ document.querySelectorAll(`.${identifier}button`).forEach(item => {
166
+ if (item === btn) return;
167
+ item.classList.remove('active');
168
+ });
169
+ btn.classList.toggle('active');
170
+ }
171
+ });
172
+ });
173
+ </script>
174
+
175
+ <Fragment set:html={structuredData} />
@@ -21,8 +21,8 @@ const videoUrl = iframeSrc || '';
21
21
  const randomId = Math.floor(Math.random() * 1000);
22
22
  ---
23
23
 
24
- <section class="w-full flex justify-center [background:conic-gradient(from_180deg_at_50%_44.39%,rgba(33,52,241,0.01)_0.07096946937963367deg,rgba(255,255,255,0.17)_177.9798674583435deg),var(--Background-Base,#FFF)]" id={`comp-ContHuesca-${randomId}`}>
25
- <article class="w-full max-w-7xl flex flex-col py-6 px-4">
24
+ <section class="w-full max-w-7xl flex justify-center [background:conic-gradient(from_180deg_at_50%_44.39%,rgba(33,52,241,0.01)_0.07096946937963367deg,rgba(255,255,255,0.17)_177.9798674583435deg),var(--Background-Base,#FFF)]" id={`comp-ContHuesca-${randomId}`}>
25
+ <article class="w-full justify-center max-w-7xl flex flex-col py-6 px-4">
26
26
  {tag && (
27
27
  <span class="text-[#363942] text-center font-inter text-base not-italic font-normal leading-6 flex items-center justify-center gap-2.5 w-fit py-2 px-3 rounded bg-[#001772]/10 mb-8">{tag}</span>
28
28
  )}
@@ -17,6 +17,7 @@ import * as Contenido_2025_Montevideo from '../carbins/Contenido_2025_Montevideo
17
17
  import * as Contenido_2026_Cabra from '../carbins/Contenido_2026_Cabra.ts';
18
18
  import * as Contenido_2026_Denia from '../carbins/Contenido_2026_Denia.ts';
19
19
  import * as Contenido_2026_Dubai from '../carbins/Contenido_2026_Dubai.ts';
20
+ import * as Contenido_2026_Estepona from '../carbins/Contenido_2026_Estepona.ts';
20
21
  import * as Contenido_2026_Estocolmo from '../carbins/Contenido_2026_Estocolmo.ts';
21
22
  import * as Contenido_2026_Huesca from '../carbins/Contenido_2026_Huesca.ts';
22
23
  import * as Contenido_2026_Jaen from '../carbins/Contenido_2026_Jaen.ts';
@@ -109,6 +110,7 @@ export const components = [
109
110
  {component: Contenido_2026_Cabra},
110
111
  {component: Contenido_2026_Denia},
111
112
  {component: Contenido_2026_Dubai},
113
+ {component: Contenido_2026_Estepona},
112
114
  {component: Contenido_2026_Estocolmo},
113
115
  {component: Contenido_2026_Huesca},
114
116
  {component: Contenido_2026_Jaen},
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import Contenido_2025_Montevideo from './components/Astro/Contenido_2025_Montevi
22
22
  import Contenido_2026_Cabra from './components/Astro/Contenido_2026_Cabra.astro';
23
23
  import Contenido_2026_Denia from './components/Astro/Contenido_2026_Denia.astro';
24
24
  import Contenido_2026_Dubai from './components/Astro/Contenido_2026_Dubai.astro';
25
+ import Contenido_2026_Estepona from './components/Astro/Contenido_2026_Estepona.astro';
25
26
  import Contenido_2026_Estocolmo from './components/Astro/Contenido_2026_Estocolmo.astro';
26
27
  import Contenido_2026_Huesca from './components/Astro/Contenido_2026_Huesca.astro';
27
28
  import Contenido_2026_Jaen from './components/Astro/Contenido_2026_Jaen.astro';
@@ -100,7 +101,7 @@ import ReactButton from './components/React/ReactButton.jsx';
100
101
  // Exporta todos los componentes uno a uno para que puedan ser usados directamente.
101
102
 
102
103
 
103
- export { VueButton, Author_2025_Algarve, Button, CTA_2025_Formentera, Cabecera_2025_Barcelona, Cabecera_2025_Madrid, Cabecera_2026_Bilbao, Cabecera_2026_Dakota, Cabecera_2026_Madrid, Calculadora_2026_Lisboa, Card_2025_Malta, Contenido_2025_Alcorcon, Contenido_2025_Cordoba, Contenido_2025_Granada, Contenido_2025_Malaga, Contenido_2025_Montevideo, Contenido_2026_Cabra, Contenido_2026_Denia, Contenido_2026_Dubai, Contenido_2026_Estocolmo, Contenido_2026_Huesca, Contenido_2026_Jaen, Contenido_2026_Leon, Contenido_2026_Mallorca, Contenido_2026_Marruecos, Contenido_2026_Menorca, Contenido_2026_Michigan, Contenido_2026_Moraira, Contenido_2026_Mostoles, Contenido_2026_Orcasitas, Contenido_2026_Oslo, Contenido_2026_Quito, Contenido_2026_Seattle, Contenido_2026_Sevilla, Contenido_2026_Tokyo, Contenido_2026_Ubeda, Contenido_2026_Yakarta, CorpFooter, CorpHero, CorpNavigation, Enlace_2025_Venecia, FAQ_2025_Hiroshima, Footer_2025_Napoles, Formulario_2025_Nara, Formulario_2025_Seul, Formulario_2025_Teruel, Formulario_2026_Carabanchel, Formulario_2026_Wichita, Galeria_2026_Segorbe, GeometricShape, GeometricShapeCard, HeaderCorporativo, Hero_2025_Benidorm, Hero_2026_Benidorm, ImageTextSimple, Imagen_2025_Bogota, Imagen_2025_Fukushima, Imagen_2026_Algar, Indice_2025_Taiwan, Mapa_2026_Girona, Modal_2025_Sagunto, Modal_2026_Almeria, Paginacion_2025_Paris, RRSS_2025_Pisa, SEO_Head_Section, SEO_Schema_Page, Separador_2025_Reinosa, Separador_2025_Toledo, Share_2025_Florencia, SpectrumSeparator, Sumario_2025_Beijing, Tabla_2025_Fuenlabrada, Tabla_2026_Cadiz, Tag_2025_Bolonia, TestHijo, TestPadre, Test_2026_Gaza, TextBox, TextImageBackground, TextImageBlock, TextImageCard, TextImageHeader, Texto_2025_Kyoto, Texto_2026_Alicante, Texto_2026_Castellon, Tiempo_2025_Londres, Titulo_2025_Algeciras, Titulo_2025_Santorini, VideoAutoplay, Video_2025_Polop, Video_2025_Valencia, Video_2026_Andujar, ReactButton };
104
+ export { VueButton, Author_2025_Algarve, Button, CTA_2025_Formentera, Cabecera_2025_Barcelona, Cabecera_2025_Madrid, Cabecera_2026_Bilbao, Cabecera_2026_Dakota, Cabecera_2026_Madrid, Calculadora_2026_Lisboa, Card_2025_Malta, Contenido_2025_Alcorcon, Contenido_2025_Cordoba, Contenido_2025_Granada, Contenido_2025_Malaga, Contenido_2025_Montevideo, Contenido_2026_Cabra, Contenido_2026_Denia, Contenido_2026_Dubai, Contenido_2026_Estepona, Contenido_2026_Estocolmo, Contenido_2026_Huesca, Contenido_2026_Jaen, Contenido_2026_Leon, Contenido_2026_Mallorca, Contenido_2026_Marruecos, Contenido_2026_Menorca, Contenido_2026_Michigan, Contenido_2026_Moraira, Contenido_2026_Mostoles, Contenido_2026_Orcasitas, Contenido_2026_Oslo, Contenido_2026_Quito, Contenido_2026_Seattle, Contenido_2026_Sevilla, Contenido_2026_Tokyo, Contenido_2026_Ubeda, Contenido_2026_Yakarta, CorpFooter, CorpHero, CorpNavigation, Enlace_2025_Venecia, FAQ_2025_Hiroshima, Footer_2025_Napoles, Formulario_2025_Nara, Formulario_2025_Seul, Formulario_2025_Teruel, Formulario_2026_Carabanchel, Formulario_2026_Wichita, Galeria_2026_Segorbe, GeometricShape, GeometricShapeCard, HeaderCorporativo, Hero_2025_Benidorm, Hero_2026_Benidorm, ImageTextSimple, Imagen_2025_Bogota, Imagen_2025_Fukushima, Imagen_2026_Algar, Indice_2025_Taiwan, Mapa_2026_Girona, Modal_2025_Sagunto, Modal_2026_Almeria, Paginacion_2025_Paris, RRSS_2025_Pisa, SEO_Head_Section, SEO_Schema_Page, Separador_2025_Reinosa, Separador_2025_Toledo, Share_2025_Florencia, SpectrumSeparator, Sumario_2025_Beijing, Tabla_2025_Fuenlabrada, Tabla_2026_Cadiz, Tag_2025_Bolonia, TestHijo, TestPadre, Test_2026_Gaza, TextBox, TextImageBackground, TextImageBlock, TextImageCard, TextImageHeader, Texto_2025_Kyoto, Texto_2026_Alicante, Texto_2026_Castellon, Tiempo_2025_Londres, Titulo_2025_Algeciras, Titulo_2025_Santorini, VideoAutoplay, Video_2025_Polop, Video_2025_Valencia, Video_2026_Andujar, ReactButton };
104
105
 
105
106
 
106
107
  // Exporta la función listComponents para que sea usado en el Pagebuilder en Vue.
@@ -134,6 +135,7 @@ export const components = {
134
135
  Contenido_2026_Cabra: Contenido_2026_Cabra,
135
136
  Contenido_2026_Denia: Contenido_2026_Denia,
136
137
  Contenido_2026_Dubai: Contenido_2026_Dubai,
138
+ Contenido_2026_Estepona: Contenido_2026_Estepona,
137
139
  Contenido_2026_Estocolmo: Contenido_2026_Estocolmo,
138
140
  Contenido_2026_Huesca: Contenido_2026_Huesca,
139
141
  Contenido_2026_Jaen: Contenido_2026_Jaen,