libreria-astro-lefebvre 0.1.38 → 0.1.39
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 +1 -1
- package/src/carbins/SEO_Schema_Page.ts +8 -0
- package/src/components/Astro/Card_2025_Malta.astro +3 -2
- package/src/components/Astro/Contenido_2026_Cabra.astro +4 -2
- package/src/components/Astro/Contenido_2026_Estocolmo.astro +4 -2
- package/src/components/Astro/Contenido_2026_Michigan.astro +3 -2
- package/src/components/Astro/Contenido_2026_Orcasitas.astro +3 -2
- package/src/components/Astro/Contenido_2026_Oslo.astro +3 -1
- package/src/components/Astro/Contenido_2026_Ubeda.astro +3 -2
- package/src/components/Astro/Contenido_2026_Yakarta.astro +3 -2
- package/src/components/Astro/Galeria_2026_Segorbe.astro +3 -2
- package/src/components/Astro/Indice_2025_Taiwan.astro +3 -2
- package/src/components/Astro/SEO_Schema_Page.astro +7 -1
- package/src/components/Astro/Tabla_2026_Cadiz.astro +7 -4
- package/src/components/Astro/Video_2025_Valencia.astro +3 -2
- package/src/lib/functions.js +5 -0
package/package.json
CHANGED
|
@@ -165,6 +165,14 @@ export const metadata: ComponentMetadata = {
|
|
|
165
165
|
mandatory: false,
|
|
166
166
|
example_value: ''
|
|
167
167
|
},
|
|
168
|
+
{
|
|
169
|
+
name: 'mainEntityId',
|
|
170
|
+
type: 'text',
|
|
171
|
+
help: '@id del nodo principal de la página (la "entidad principal"), p. ej. el ItemList de un listado (#itemlist). Si se proporciona, el WebPage/CollectionPage añade mainEntity: { "@id": ... }. Solo aplica a tipos NO artículo/FAQ/ProfilePage (esos ya fijan su propio mainEntity). Usar @id relativo para que funcione también vía render API.',
|
|
172
|
+
label: '@id de la entidad principal (mainEntity)',
|
|
173
|
+
mandatory: false,
|
|
174
|
+
example_value: '#itemlist'
|
|
175
|
+
},
|
|
168
176
|
{
|
|
169
177
|
name: 'keywords',
|
|
170
178
|
type: 'text',
|
|
@@ -12,14 +12,15 @@ const {
|
|
|
12
12
|
}: { items?: MaltaItem[] } = Astro.props;
|
|
13
13
|
|
|
14
14
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
15
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
15
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
16
16
|
|
|
17
17
|
const escapeJson = (s = "") => String(s).replace(/<[^>]*>/g, '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/[\n\r\t]+/g, ' ');
|
|
18
18
|
|
|
19
19
|
const structuredData = `<script type="application/ld+json">
|
|
20
20
|
{
|
|
21
21
|
"@context": "https://schema.org",
|
|
22
|
-
"@type": "ItemList",${
|
|
22
|
+
"@type": "ItemList",${itemListId ? `
|
|
23
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
23
24
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
24
25
|
"numberOfItems": ${items.length},
|
|
25
26
|
"itemListElement": [${items.map((item: MaltaItem, i: number) => `{
|
|
@@ -9,7 +9,8 @@ const {
|
|
|
9
9
|
} = Astro.props;
|
|
10
10
|
|
|
11
11
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
12
|
-
|
|
12
|
+
// itemListId opcional: @id del ItemList (para ser mainEntity de la CollectionPage).
|
|
13
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
13
14
|
|
|
14
15
|
type TabPoint = { title: string; description: string; icon: string; showIco: boolean };
|
|
15
16
|
type Tab = { name: string; buttonUrl: string; image: string; points: TabPoint[] };
|
|
@@ -41,7 +42,8 @@ const structuredData = `<script type="application/ld+json">
|
|
|
41
42
|
"@type": "WebPageElement",
|
|
42
43
|
"name": "${escapeJson(tabs.map((t: Tab) => t.name).filter(Boolean).join(' · '))}",
|
|
43
44
|
"mainEntity": {
|
|
44
|
-
"@type": "ItemList",${
|
|
45
|
+
"@type": "ItemList",${itemListId ? `
|
|
46
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
45
47
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
46
48
|
"numberOfItems": ${tabs.length},
|
|
47
49
|
"itemListElement": [${tabs.map((tab: Tab, index: number) => `{
|
|
@@ -24,14 +24,16 @@ const {
|
|
|
24
24
|
}: { items?: MontevideoItem[]; etiquetaVisible?: "fecha" | "keywords"; showAutor?: boolean } = Astro.props;
|
|
25
25
|
|
|
26
26
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
27
|
-
|
|
27
|
+
// itemListId opcional: si se pasa, el ItemList lleva ese @id (para ser mainEntity de la CollectionPage).
|
|
28
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
28
29
|
|
|
29
30
|
const escapeJson = (s = "") => String(s).replace(/<[^>]*>/g, '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/[\n\r\t]+/g, ' ');
|
|
30
31
|
|
|
31
32
|
const structuredData = `<script type="application/ld+json">
|
|
32
33
|
{
|
|
33
34
|
"@context": "https://schema.org",
|
|
34
|
-
"@type": "ItemList",${
|
|
35
|
+
"@type": "ItemList",${itemListId ? `
|
|
36
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
35
37
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
36
38
|
"numberOfItems": ${items.length},
|
|
37
39
|
"itemListElement": [${items.map((item: MontevideoItem, i: number) => `{
|
|
@@ -13,14 +13,15 @@ const {
|
|
|
13
13
|
} = Astro.props;
|
|
14
14
|
|
|
15
15
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
16
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
16
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
17
17
|
|
|
18
18
|
const randomId = Math.floor(Math.random() * 1000);
|
|
19
19
|
|
|
20
20
|
const structuredData = `<script type="application/ld+json">
|
|
21
21
|
{
|
|
22
22
|
"@context": "https://schema.org",
|
|
23
|
-
"@type": "ItemList",${
|
|
23
|
+
"@type": "ItemList",${itemListId ? `
|
|
24
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
24
25
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
25
26
|
"numberOfItems": ${items.length},
|
|
26
27
|
"itemListElement": [
|
|
@@ -22,7 +22,7 @@ const {
|
|
|
22
22
|
}: { loadScript?: boolean; items?: OrcasitasItem[]; slidesToShow?: number; slidesToScroll?: number } = Astro.props;
|
|
23
23
|
|
|
24
24
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
25
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
25
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
26
26
|
|
|
27
27
|
const carouselId = "glider-carousel-"+Math.floor(Math.random()*1000);
|
|
28
28
|
const buttonsId = "glider-carousel-buttons-"+Math.floor(Math.random()*1000);
|
|
@@ -59,7 +59,8 @@ const buildImageItem = (item: OrcasitasItem) => {
|
|
|
59
59
|
const structuredData = items.length > 0 ? `<script type="application/ld+json">
|
|
60
60
|
{
|
|
61
61
|
"@context": "https://schema.org",
|
|
62
|
-
"@type": "ItemList",${
|
|
62
|
+
"@type": "ItemList",${itemListId ? `
|
|
63
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
63
64
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
64
65
|
"numberOfItems": ${items.length},
|
|
65
66
|
"itemListElement": [${items.map((item: OrcasitasItem, index: number) => `{
|
|
@@ -6,13 +6,15 @@ const {
|
|
|
6
6
|
} = Astro.props;
|
|
7
7
|
|
|
8
8
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
9
|
-
|
|
9
|
+
// itemListId opcional: @id del ItemList (para ser mainEntity de la CollectionPage).
|
|
10
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
10
11
|
|
|
11
12
|
const randomId = Math.floor(Math.random() * 1000);
|
|
12
13
|
|
|
13
14
|
const structuredData = JSON.stringify({
|
|
14
15
|
"@context": "https://schema.org",
|
|
15
16
|
"@type": "ItemList",
|
|
17
|
+
...(itemListId ? { "@id": itemListId } : {}),
|
|
16
18
|
...(pageId ? { isPartOf: { "@id": pageId } } : {}),
|
|
17
19
|
"numberOfItems": items.length,
|
|
18
20
|
"itemListElement": items.map((item, index) => ({
|
|
@@ -6,12 +6,13 @@ const {
|
|
|
6
6
|
} = Astro.props;
|
|
7
7
|
|
|
8
8
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
9
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
9
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
10
10
|
|
|
11
11
|
const structuredData = `<script type="application/ld+json">
|
|
12
12
|
{
|
|
13
13
|
"@context": "https://schema.org",
|
|
14
|
-
"@type": "ItemList",${
|
|
14
|
+
"@type": "ItemList",${itemListId ? `
|
|
15
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
15
16
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
16
17
|
"numberOfItems": ${items.length},
|
|
17
18
|
"itemListElement": [
|
|
@@ -18,7 +18,7 @@ const {
|
|
|
18
18
|
}: { items?: VideoItem[] } = Astro.props;
|
|
19
19
|
|
|
20
20
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
21
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
21
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
22
22
|
|
|
23
23
|
const idAccordion = 'js-acordeon-' + Math.random().toString(36).substring(2, 15);
|
|
24
24
|
|
|
@@ -27,7 +27,8 @@ const escapeJson = (s = "") => String(s).replace(/<[^>]*>/g, '').replace(/\\/g,
|
|
|
27
27
|
const structuredData = items.length > 0 ? `<script type="application/ld+json">
|
|
28
28
|
{
|
|
29
29
|
"@context": "https://schema.org",
|
|
30
|
-
"@type": "ItemList",${
|
|
30
|
+
"@type": "ItemList",${itemListId ? `
|
|
31
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
31
32
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
32
33
|
"numberOfItems": ${items.length},
|
|
33
34
|
"itemListElement": [${items.map((item: VideoItem, index: number) => `{
|
|
@@ -12,7 +12,7 @@ const {
|
|
|
12
12
|
}: { columns?: string; items?: GaleriaItem[] } = Astro.props;
|
|
13
13
|
|
|
14
14
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
15
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
15
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
16
16
|
|
|
17
17
|
const lgColsClass = {
|
|
18
18
|
'2': 'lg:columns-2',
|
|
@@ -27,7 +27,8 @@ const escapeJson = (s = '') => String(s).replace(/<[^>]*>/g, '').replace(/\\/g,
|
|
|
27
27
|
const structuredData = `<script type="application/ld+json">
|
|
28
28
|
{
|
|
29
29
|
"@context": "https://schema.org",
|
|
30
|
-
"@type": "ItemList",${
|
|
30
|
+
"@type": "ItemList",${itemListId ? `
|
|
31
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
31
32
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
32
33
|
"numberOfItems": ${visibleItems.length},
|
|
33
34
|
"itemListElement": [${visibleItems.map((item: GaleriaItem, i: number) => `{
|
|
@@ -9,7 +9,7 @@ const {
|
|
|
9
9
|
} = Astro.props;
|
|
10
10
|
|
|
11
11
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
12
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
12
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
13
13
|
|
|
14
14
|
interface IndiceItem {
|
|
15
15
|
enlace: string;
|
|
@@ -31,7 +31,8 @@ const baseUrl = new URL(subdirectory + Astro.url.pathname, origin).href.split('#
|
|
|
31
31
|
const structuredData = `<script type="application/ld+json">
|
|
32
32
|
{
|
|
33
33
|
"@context": "https://schema.org",
|
|
34
|
-
"@type": "ItemList",${
|
|
34
|
+
"@type": "ItemList",${itemListId ? `
|
|
35
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
35
36
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
36
37
|
"name": "${escapeJson(titulo)}",
|
|
37
38
|
"numberOfItems": ${indiceItems.length},
|
|
@@ -35,6 +35,7 @@ interface Props {
|
|
|
35
35
|
publisherId?: string;
|
|
36
36
|
websiteId?: string;
|
|
37
37
|
breadcrumbId?: string;
|
|
38
|
+
mainEntityId?: string;
|
|
38
39
|
keywords?: string;
|
|
39
40
|
inLanguage?: string;
|
|
40
41
|
articleSection?: string;
|
|
@@ -64,6 +65,7 @@ const {
|
|
|
64
65
|
publisherId,
|
|
65
66
|
websiteId,
|
|
66
67
|
breadcrumbId,
|
|
68
|
+
mainEntityId,
|
|
67
69
|
keywords,
|
|
68
70
|
inLanguage = 'es',
|
|
69
71
|
articleSection,
|
|
@@ -181,7 +183,11 @@ if (pageType === 'ProfilePage' && (authorName || authorId)) {
|
|
|
181
183
|
// (p. ej. la Organization global #organization del Layout) → no se redeclara aquí.
|
|
182
184
|
}
|
|
183
185
|
|
|
184
|
-
// ---
|
|
186
|
+
// --- mainEntity explícito (p. ej. CollectionPage → ItemList): se aplica solo si el tipo no la fija
|
|
187
|
+
// ya (artículo/FAQ/Profile). El consumidor pasa el @id del nodo principal (relativo, p. ej. "#itemlist").
|
|
188
|
+
if (mainEntityId && !webPage.mainEntity) {
|
|
189
|
+
webPage.mainEntity = { '@id': mainEntityId };
|
|
190
|
+
}
|
|
185
191
|
|
|
186
192
|
const schema: Record<string, unknown> = {
|
|
187
193
|
'@context': 'https://schema.org',
|
|
@@ -11,7 +11,9 @@ const {
|
|
|
11
11
|
} = Astro.props;
|
|
12
12
|
|
|
13
13
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
14
|
-
|
|
14
|
+
// itemListId opcional: se aplica SOLO a la lista izquierda/principal (la derecha nunca lleva @id,
|
|
15
|
+
// para no duplicar el mismo @id en la página).
|
|
16
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
15
17
|
|
|
16
18
|
const hasLeft = leftTitle || leftItems.length > 0;
|
|
17
19
|
const hasRight = rightTitle || rightItems.length > 0;
|
|
@@ -21,10 +23,11 @@ type Item = { text: string; link?: string; target?: string };
|
|
|
21
23
|
|
|
22
24
|
const escapeJson = (s = "") => String(s).replace(/<[^>]*>/g, '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/[\n\r\t]+/g, ' ');
|
|
23
25
|
|
|
24
|
-
const buildItemListScript = (listName: string, listItems: Item[]) => `<script type="application/ld+json">
|
|
26
|
+
const buildItemListScript = (listName: string, listItems: Item[], listId = '') => `<script type="application/ld+json">
|
|
25
27
|
{
|
|
26
28
|
"@context": "https://schema.org",
|
|
27
|
-
"@type": "ItemList",${
|
|
29
|
+
"@type": "ItemList",${listId ? `
|
|
30
|
+
"@id": "${listId}",` : ''}${pageId ? `
|
|
28
31
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
29
32
|
"name": "${escapeJson(listName)}",
|
|
30
33
|
"numberOfItems": ${listItems.length},
|
|
@@ -38,7 +41,7 @@ const buildItemListScript = (listName: string, listItems: Item[]) => `<script ty
|
|
|
38
41
|
</script>`;
|
|
39
42
|
|
|
40
43
|
const structuredData = [
|
|
41
|
-
hasLeft ? buildItemListScript(leftTitle, leftItems) : '',
|
|
44
|
+
hasLeft ? buildItemListScript(leftTitle, leftItems, itemListId) : '',
|
|
42
45
|
hasRight ? buildItemListScript(rightTitle, rightItems) : '',
|
|
43
46
|
].filter(Boolean).join('\n');
|
|
44
47
|
---
|
|
@@ -18,7 +18,7 @@ const {
|
|
|
18
18
|
}: { items?: VideoItem[]; iframeSrc?: string } = Astro.props;
|
|
19
19
|
|
|
20
20
|
// isPartOf hacia el nodo de página (#webpage por defecto). Genérico: opt-out con pageId="".
|
|
21
|
-
const { pageId = PAGE_ENTITY_ID } = Astro.props;
|
|
21
|
+
const { pageId = PAGE_ENTITY_ID, itemListId = '' } = Astro.props;
|
|
22
22
|
|
|
23
23
|
const idAccordion = 'js-acordeon-' + Math.random().toString(36).substring(2, 15);
|
|
24
24
|
|
|
@@ -27,7 +27,8 @@ const escapeJson = (s = "") => String(s).replace(/<[^>]*>/g, '').replace(/\\/g,
|
|
|
27
27
|
const structuredData = items.length > 0 ? `<script type="application/ld+json">
|
|
28
28
|
{
|
|
29
29
|
"@context": "https://schema.org",
|
|
30
|
-
"@type": "ItemList",${
|
|
30
|
+
"@type": "ItemList",${itemListId ? `
|
|
31
|
+
"@id": "${itemListId}",` : ''}${pageId ? `
|
|
31
32
|
"isPartOf": { "@id": "${pageId}" },` : ''}
|
|
32
33
|
"numberOfItems": ${items.length},
|
|
33
34
|
"itemListElement": [${items.map((item: VideoItem, index: number) => `{
|
package/src/lib/functions.js
CHANGED
|
@@ -9,6 +9,11 @@ import { components } from '../generated/componentRegistry.ts';
|
|
|
9
9
|
// isPartOf: { "@id": PAGE_ENTITY_ID } sin necesidad de conocer la URL/canonical.
|
|
10
10
|
export const PAGE_ENTITY_ID = '#webpage';
|
|
11
11
|
|
|
12
|
+
// @id RELATIVO del ItemList principal de una página. Convención: el listado principal lleva este @id
|
|
13
|
+
// y la CollectionPage (vía SEO_Schema_Page mainEntityId) lo referencia como mainEntity. Relativo →
|
|
14
|
+
// resuelve contra la página, así que vale tanto para el front como para el render API del CMS.
|
|
15
|
+
export const MAIN_ITEMLIST_ID = '#itemlist';
|
|
16
|
+
|
|
12
17
|
// ============================================================================
|
|
13
18
|
// 🎯 Utilidades de Imagen para Limbo
|
|
14
19
|
// ============================================================================
|