libreria-astro-lefebvre 0.1.20 → 0.1.22

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.20",
3
+ "version": "0.1.22",
4
4
  "description": "Librería de componentes Astro, React y Vue para Lefebvre",
5
5
  "author": "Equipo web desarrollo Lefebvre",
6
6
  "type": "module",
@@ -18,8 +18,13 @@ const {
18
18
  subdirectory = '',
19
19
  loading = 'eager' as 'lazy' | 'eager',
20
20
  categories: categoriesProp = undefined as MenuItem[] | undefined,
21
+ siteUrl = '' as string,
21
22
  } = Astro.props;
22
23
 
24
+ // Origen absoluto para el JSON-LD de navegación. En SSR tras un proxy, Astro.url resuelve al
25
+ // host interno (localhost), así que se prioriza `siteUrl` (prop) y `Astro.site` (config).
26
+ const origin = (siteUrl || Astro.site?.href || Astro.url.origin).replace(/\/+$/, '');
27
+
23
28
  const FALLBACK_CATEGORIES = [
24
29
  {
25
30
  name: 'Cómo funciona',
@@ -70,11 +75,11 @@ const categories: MenuItem[] = (categoriesProp && categoriesProp.length > 0)
70
75
  "@context": "https://schema.org",
71
76
  "@type": "SiteNavigationElement",
72
77
  "name": "Main Navigation",
73
- "url": "${Astro.url.origin}${subdirectory}",
78
+ "url": "${origin}${subdirectory}",
74
79
  "hasPart": [${categories.map(category => `{
75
80
  "@type": "SiteNavigationElement",
76
81
  "name": "${category.name}",
77
- "url": "${Astro.url.origin}${category.link}"
82
+ "url": "${origin}${category.link}"
78
83
  }`).join(',')}]
79
84
  }
80
85
  </script>`;
@@ -3,30 +3,54 @@ const {
3
3
  title,
4
4
  description,
5
5
  robots = 'index, follow',
6
- canonical = Astro.url.href.endsWith('/') ? Astro.url.href : Astro.url.href + '/',
6
+ canonical,
7
7
  shareImgSrc,
8
8
  subdirectory = '',
9
+ siteUrl,
9
10
  } = Astro.props;
10
11
 
11
- const currentUrl = Astro.url.href.replace(/^(https?:\/\/[^\/]+)/, `$1${subdirectory}`);
12
- const normalizedUrl = currentUrl.endsWith('/') ? currentUrl : currentUrl + '/';
13
-
12
+ // Origen absoluto del sitio, en orden de preferencia:
13
+ // 1. `siteUrl` (prop explícita): imprescindible en SSR tras un proxy inverso, donde
14
+ // `Astro.url` resuelve al host interno (p. ej. http://localhost).
15
+ // 2. `Astro.site`: el valor de `site` en astro.config.mjs.
16
+ // 3. `Astro.url.origin`: el de la petición (correcto en sitios estáticos o sin proxy).
17
+ const origin = (siteUrl || Astro.site?.href || Astro.url.origin).replace(/\/+$/, '');
18
+
19
+ // Resuelve a URL absoluta: si ya es absoluta se respeta; si es relativa se cuelga del origen.
20
+ const toAbsolute = (value: string) =>
21
+ /^https?:\/\//.test(value) ? value : `${origin}/${value.replace(/^\/+/, '')}`;
22
+
23
+ // URL canónica:
24
+ // - Si el consumidor pasa `canonical`, se respeta (un canónico es definitivo; NO se le
25
+ // inyecta el subdirectorio, que es justo lo que causaba duplicados como /sub/sub/).
26
+ // - Si no, se compone con origen + subdirectorio + ruta actual.
27
+ const resolvedCanonical = canonical
28
+ ? toAbsolute(String(canonical))
29
+ : `${origin}${subdirectory}${Astro.url.pathname}`;
30
+
31
+ // Barra final salvo que la URL lleve query o fragmento.
32
+ const canonicalUrl = /[?#]/.test(resolvedCanonical) || resolvedCanonical.endsWith('/')
33
+ ? resolvedCanonical
34
+ : `${resolvedCanonical}/`;
35
+
36
+ // og:image debe ser absoluta para que las plataformas sociales la resuelvan.
37
+ const ogImage = shareImgSrc ? toAbsolute(String(shareImgSrc)) : undefined;
14
38
  ---
15
39
  <title>{title}</title>
16
40
  <meta name="description" content={description} />
17
41
  <meta name="robots" content={robots} />
18
- <link rel="canonical" href={canonical.replace(/^(https?:\/\/[^\/]+)/, `$1${subdirectory}`)} />
19
-
42
+ <link rel="canonical" href={canonicalUrl} />
43
+
20
44
  <!-- Open Graph / Facebook -->
21
45
  <meta property="og:type" content="website" />
22
- <meta property="og:url" content={normalizedUrl} />
46
+ <meta property="og:url" content={canonicalUrl} />
23
47
  <meta property="og:title" content={title} />
24
48
  <meta property="og:description" content={description} />
25
- {shareImgSrc && <meta property="og:image" content={shareImgSrc} />}
26
-
49
+ {ogImage && <meta property="og:image" content={ogImage} />}
50
+
27
51
  <!-- Twitter -->
28
52
  <meta property="twitter:card" content="summary_large_image" />
29
- <meta property="twitter:url" content={normalizedUrl} />
53
+ <meta property="twitter:url" content={canonicalUrl} />
30
54
  <meta property="twitter:title" content={title} />
31
55
  <meta property="twitter:description" content={description} />
32
- {shareImgSrc && <meta property="twitter:image" content={shareImgSrc} />}
56
+ {ogImage && <meta property="twitter:image" content={ogImage} />}