libreria-astro-lefebvre 0.0.170 → 0.0.172

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.0.170",
3
+ "version": "0.0.172",
4
4
  "description": "Librería de componentes Astro, React y Vue para Lefebvre",
5
5
  "author": "Equipo web desarrollo Lefebvre",
6
6
  "type": "module",
@@ -7,7 +7,7 @@ export const metadata: ComponentMetadata = {
7
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 pestaña marcada como "default" es la que se muestra al cargar la página. Incluye structured data schema.org (ItemList + InteractionCounter)',
8
8
  framework: 'Astro',
9
9
  priority: 1,
10
- tags: ['contenido', 'tabs', 'acordeon', 'imagen', 'interactivo', 'seo'],
10
+ tags: ['contenido', 'genial'],
11
11
  fields: [
12
12
  {
13
13
  name: 'items',
@@ -18,18 +18,12 @@ export const metadata: ComponentMetadata = {
18
18
  items: {
19
19
  type: 'object',
20
20
  fields: [
21
- { name: 'name', type: 'text', help: 'Nombre de la pestaña que aparece en el botón superior y como título dentro del panel. También se usa como alt de la imagen si no hay otro texto', label: 'Nombre de la pestaña', example_value: 'Automatización jurídica' },
22
- { name: 'default', type: 'boolean', help: 'Si está activado, esta pestaña se muestra al cargar la página y su botón aparece resaltado. Solo debería haber UNA pestaña con "default: true"; si hay varias, se mostrarán todas a la vez al inicio', label: '¿Pestaña por defecto?', options: ['false', 'true'], options_labels: ['Falso', 'Verdadero'], example_value: true },
23
- { name: 'buttonUrl', type: 'text', help: 'URL de destino del botón "Ver experiencias de uso" que aparece dentro del panel de la pestaña. Si se deja vacía, el botón no tiene destino', label: 'URL del botón', example_value: '/genia-l/experiencias/automatizacion' },
24
- { name: 'image', type: 'image', help: 'URL de la imagen que se muestra a la derecha del contenido de la pestaña. Si se deja vacía, aparece imagen rota', label: 'Imagen de la pestaña', example_value: 'https://assets.lefebvre.es/media/img/preview-comp/comp-16-9.png' },
25
- { name: 'items', type: 'list', help: 'Sub-listado de elementos con icono y texto que se muestran dentro de la pestaña. Cada elemento se pasa al componente Repetidor_2025_Menorca para renderizarse con el formato estándar de listado con iconos', label: 'Items de la pestaña', items: {
26
- type: 'object',
27
- fields: [
28
- { name: 'title', type: 'text', help: 'Título del elemento (h4)', label: 'Título', example_value: 'Redacción de contratos' },
29
- { 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' },
30
- { name: 'icon', type: 'text', help: 'Nombre del icono a mostrar junto al elemento. Consulta los valores aceptados en el componente Repetidor_2025_Menorca', label: 'Icono', example_value: 'edit' }
31
- ]
32
- } }
21
+ { name: 'name', type: 'text', help: 'Introduce el nombre de la 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 Repetidor_2025_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' }
33
27
  ]
34
28
  }
35
29
  }
@@ -1,12 +1,33 @@
1
1
  ---
2
2
 
3
- import Repetidor_2025_Menorca from './Repetidor_2025_Menorca.astro';
3
+ import Contenido_2026_Menorca from './Contenido_2026_Menorca.astro';
4
4
  import Titulo_2025_Algeciras from './Titulo_2025_Algeciras.astro';
5
+ import { extractImageUrl } from '../../lib/functions.js';
5
6
 
6
7
  const {
7
8
  items = [],
8
9
  } = Astro.props;
9
10
 
11
+ type TabPoint = { title: string; description: string; icon: string; showIco: boolean };
12
+ type Tab = { name: string; buttonUrl: string; image: string; points: TabPoint[] };
13
+
14
+ const tabs = items.reduce((acc: Tab[], item: any) => {
15
+ const existing = acc.find((t: Tab) => t.name === item.name);
16
+ if (existing) {
17
+ if (!existing.buttonUrl && item.buttonUrl) existing.buttonUrl = item.buttonUrl;
18
+ if (!existing.image && item.image) existing.image = item.image;
19
+ existing.points.push({ title: item.title, description: item.description, icon: item.icon, showIco: !!item.icon });
20
+ } else {
21
+ acc.push({
22
+ name: item.name,
23
+ buttonUrl: item.buttonUrl || '',
24
+ image: item.image || '',
25
+ points: [{ title: item.title, description: item.description, icon: item.icon, showIco: !!item.icon }]
26
+ });
27
+ }
28
+ return acc;
29
+ }, []);
30
+
10
31
  const identifier = 'js-megablock'+ Math.random().toString(36).substring(2, 15);
11
32
 
12
33
  const structuredData = `<script type="application/ld+json">
@@ -17,22 +38,22 @@ const structuredData = `<script type="application/ld+json">
17
38
  "description": "Interactive tabbed content component with multiple sections",
18
39
  "mainEntity": {
19
40
  "@type": "ItemList",
20
- "numberOfItems": ${items.length},
41
+ "numberOfItems": ${tabs.length},
21
42
  "itemListElement": [
22
- ${items.map((item, index) => `{
43
+ ${tabs.map((tab: Tab, index: number) => `{
23
44
  "@type": "ListItem",
24
45
  "position": ${index + 1},
25
- "name": "${item.name}",
46
+ "name": "${tab.name}",
26
47
  "description": "Interactive content section",
27
- ${item.image ? `"image": "${item.image}",` : ''}
28
- ${item.buttonUrl ? `"url": "${item.buttonUrl}"` : ''}
48
+ ${tab.image ? `"image": "${tab.image}",` : ''}
49
+ ${tab.buttonUrl ? `"url": "${tab.buttonUrl}"` : ''}
29
50
  }`).join(',\n ')}
30
51
  ]
31
52
  },
32
53
  "interactionStatistic": {
33
54
  "@type": "InteractionCounter",
34
55
  "interactionType": "https://schema.org/ClickAction",
35
- "userInteractionCount": "${items.length}"
56
+ "userInteractionCount": "${tabs.length}"
36
57
  }
37
58
  }
38
59
  </script>`;
@@ -42,53 +63,51 @@ const structuredData = `<script type="application/ld+json">
42
63
 
43
64
  <section class="w-full flex items-center justify-center">
44
65
  <article class="w-full flex flex-col items-center justify-center">
45
- <div class="w-full flex justify-center items-center relative text-[56px] text-center font-inter leading-[64px] mt-10">
66
+ <div class="w-full flex justify-center items-center relative text-[56px] text-center font inter leading-[64px] mt-10">
46
67
  <!-- <div class="flex bg-transparent md:bg-gray-50 md:border md:border-[#B6B7BB] rounded-lg"> -->
47
68
  <div class="flex gap-1 md:gap-8 items-center">
48
- {items.map((item, index) => (
69
+ {tabs.map((tab: Tab, index: number) => (
49
70
  <p class="text-base">
50
- {/* <a href={`#accordion${index + 1}`} class="btn py-[20px] px-[16px]">{item}</a> */}
51
- <button data-linkedto={`${identifier}${index + 1}`}
71
+ <button data-linkedto={`${identifier}${index + 1}`}
52
72
  class={`
53
73
  btn py-3.5 px-5 font-inter
54
74
  cursor-pointer border border-[#b6b7bb]
55
- hover:border hover:border-[#5F6168] hover:!bg-[#ffffff] rounded-lg ${identifier}button
56
- ${item.default ? 'active' : ''}
75
+ hover:border hover:border-[#5F6168] hover:!bg-[#ffffff] rounded-lg ${identifier}button
76
+ ${index === 0 ? 'active' : ''}
57
77
  bg-F2F3F8 text-gray-100 max-w-10 max-h-5 text-[0px] md:w-[150px]
58
78
  md:bg-gray-50 md:text-black md:max-w-none md:max-h-none md:text-[16px]
59
79
  `}
60
- >{item.name}</button>
80
+ >{tab.name}</button>
61
81
  </p>
62
82
  ))}
63
83
  </div>
64
84
  </div>
65
85
  <div class="lg:max-w-7xl md:w-full px-6 md:w-4/5 md:px-0 col my-10">
66
- {items.map((item, index) => (
67
- <div id={`${identifier}${index + 1}`} class={`${item.default ? '' : 'hidden'} collapse-arrow ${identifier}item`}>
68
-
86
+ {tabs.map((tab: Tab, index: number) => (
87
+ <div id={`${identifier}${index + 1}`} class={`${index === 0 ? '' : 'hidden'} collapse-arrow ${identifier}item`}>
69
88
 
70
89
  <div class="w-full flex-col flex md:flex-row gap-4 md:gap-12">
71
- <div class="w-full md:w-1/2">
72
- <Titulo_2025_Algeciras
73
- title={item.name}
90
+ <div class="w-full md:w-1/2">
91
+ <Titulo_2025_Algeciras
92
+ title={tab.name}
74
93
  tipo="h3-40-left"
75
94
  flexJustify="justify-start"
76
95
  />
77
- <Repetidor_2025_Menorca
78
- flexOrientationIcoText = "flex-row"
79
- flexOrientationBlockIcoText = "flex-col"
80
- positionFlex = 'items-start'
81
- positionBtnFlex = 'justify-start'
82
- items = {item.items}
83
- headingType = 'h4'
84
- showBtn = {true}
85
- btnLabel = "Ver experiencias de uso"
86
- buttonUrl={item.buttonUrl}
87
- widthArticle = "w-4/5"
96
+ <Contenido_2026_Menorca
97
+ flexOrientationIcoText="flex-row"
98
+ flexOrientationBlockIcoText="flex-col"
99
+ positionFlex="items-start"
100
+ positionBtnFlex="justify-start"
101
+ items={tab.points}
102
+ headingType="h4"
103
+ showBtn={true}
104
+ btnLabel="Ver experiencias de uso"
105
+ buttonUrl={tab.buttonUrl}
106
+ widthArticle="w-4/5"
88
107
  />
89
108
  </div>
90
109
  <div class="w-full md:w-1/2 p-0 md:pr-2">
91
- <img src={item.image} alt={item.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" />
110
+ <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" />
92
111
  </div>
93
112
  </div>
94
113