@nuxtjs/sitemap 7.5.2 → 8.0.0

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.
Files changed (108) hide show
  1. package/README.md +8 -2
  2. package/dist/content.d.mts +62 -39
  3. package/dist/content.d.ts +62 -39
  4. package/dist/content.mjs +68 -38
  5. package/dist/devtools/200.html +1 -0
  6. package/dist/devtools/404.html +1 -0
  7. package/dist/devtools/_fonts/4ppnHhMi-pBsWSPo7mY0avYxlDoAg1N3PTzCwXLZ5rA-d9oibkGnTd1JL3tc_xnaVgBLYmOB8kjrK2cvZaqwj9s.woff2 +0 -0
  8. package/dist/devtools/_fonts/4qBuU9MRVUlPZNPSF7Xom_sK8RBEnfYu-9VXFrdq8A8-8TDwLE1HAj1sQn7XxVWtM_7sIaPM-DTdO3Pf8U2DF1U.woff2 +0 -0
  9. package/dist/devtools/_fonts/6dYsbWUd_BpKJ7mdDihgOcya1gHXLpJBuMYXux3WMjE-q3fYNS8YbW5n7ZeXI2vSNgkRWW5VDPKAl51SNTjG2qk.woff2 +0 -0
  10. package/dist/devtools/_fonts/Lr-hqqZZsYmCt0ITUlr1CUrWim9fsKvoDFZliMxgNHY-iTa_Yt_PzhOY9TX7ZXdSlEPim6iRt92xhECwaxWxd5w.woff2 +0 -0
  11. package/dist/devtools/_fonts/OknHvWI6KtYn1JQBzX7eSpNDBQ8520F9TvSUJYkVf6A-xeZn9253svK_8Q2LD0XEruY_MnEsuCRO5LenPoggC0Y.woff2 +0 -0
  12. package/dist/devtools/_fonts/PV2hrQG6wq5BlIPDjdL1IcOflycaghyt5MHzlBqZtlo-lb_WexLz3VZqfTN0oi554iBH5tT2j2UFEV-XErCAS3E.woff2 +0 -0
  13. package/dist/devtools/_fonts/UA7OtwYHwGN_HjcVGTdmiQxUit7FlqkCwxVUWSeXVnQ-B4OXCFOL_tWrYODpQTc07aMaj0c2cewTOmBRWR9tD-A.woff2 +0 -0
  14. package/dist/devtools/_fonts/VE4cDVCv5MxbFM7ZLoLCGbIpNd71zhp7MDI9lmN5Y7I-xZyDYCUVrd6LV8eVGF3Um3UZjBFuUtDGtvdyTBBRYBo.woff2 +0 -0
  15. package/dist/devtools/_fonts/fVoGbnMbBFd5L9BBp9fUPavUSkZ_EmsQNSyadkT-108-U4T0khaeLQSIhtt9eVvaCEKJjtWJ4ioRJOf8hvqkWY0.woff2 +0 -0
  16. package/dist/devtools/_fonts/lQAxeCEs1R0Lw-H9XRU1RlOARQN8J6npRsPjyEDMe5s-_DUSLEkO3tKTuun_gSnDLoQPVEnpOnyqZMOw0ByZ6PA.woff2 +0 -0
  17. package/dist/devtools/_fonts/lntlqNHKLV2n82yTwMde70QqOjcfLE2XJ5oKZ3vRPWc-z6TxpIZQdWXztWLr9_OFWqt_WJJoeGtuK_-XQMZGQwE.woff2 +0 -0
  18. package/dist/devtools/_fonts/qxAYvKsXWeYv731eb-h5TRurcdIP_W44mpNdX-HABAk-zUDeMEFlNtNbrwvT9JxLEBg0TphGy70O6RfIoIX_ZwU.woff2 +0 -0
  19. package/dist/devtools/_nuxt/6-8YL5RT.js +1 -0
  20. package/dist/devtools/_nuxt/B-CoxLn7.js +1 -0
  21. package/dist/devtools/_nuxt/BBg_LgdD.js +1 -0
  22. package/dist/devtools/_nuxt/BFP26XjE.js +1 -0
  23. package/dist/devtools/_nuxt/BFxFqELk.js +1 -0
  24. package/dist/devtools/_nuxt/BJ46vUgN.js +22 -0
  25. package/dist/devtools/_nuxt/BK43-3Xm.js +1 -0
  26. package/dist/devtools/_nuxt/BUgp7PK5.js +1 -0
  27. package/dist/devtools/_nuxt/BUwCbG2W.js +1 -0
  28. package/dist/devtools/_nuxt/BgUkVPML.js +1 -0
  29. package/dist/devtools/_nuxt/Bl-ESRhh.js +1 -0
  30. package/dist/devtools/_nuxt/BpntLhpu.js +1 -0
  31. package/dist/devtools/_nuxt/CMkTWvG2.js +1 -0
  32. package/dist/devtools/_nuxt/CdSSkj0j.js +6 -0
  33. package/dist/devtools/_nuxt/Cfg7NvvP.js +3 -0
  34. package/dist/devtools/_nuxt/Cq2IBCZt.js +1 -0
  35. package/dist/devtools/_nuxt/D56-uEuD.js +1 -0
  36. package/dist/devtools/_nuxt/D9eL2h5z.js +1 -0
  37. package/dist/devtools/_nuxt/DC83McAa.js +154 -0
  38. package/dist/devtools/_nuxt/DLfyhkbV.js +1 -0
  39. package/dist/devtools/_nuxt/DRdBN13f.js +1 -0
  40. package/dist/devtools/_nuxt/DevtoolsEmptyState.CPam6VsX.css +1 -0
  41. package/dist/devtools/_nuxt/DevtoolsSection.BeqVO-za.css +1 -0
  42. package/dist/devtools/_nuxt/DuYBAn1h.js +1 -0
  43. package/dist/devtools/_nuxt/Source.ChvNXxeG.css +1 -0
  44. package/dist/devtools/_nuxt/_hKGTbzI.js +1 -0
  45. package/dist/devtools/_nuxt/builds/latest.json +1 -0
  46. package/dist/devtools/_nuxt/builds/meta/8c443858-dba7-4dd0-b65e-6a31b3bbefed.json +1 -0
  47. package/dist/devtools/_nuxt/entry.DuwzcCXL.css +2 -0
  48. package/dist/devtools/_nuxt/error-404.CbnweSUu.css +1 -0
  49. package/dist/devtools/_nuxt/error-500.DrNDBqZi.css +1 -0
  50. package/dist/devtools/_nuxt/jxhrXVY1.js +1 -0
  51. package/dist/devtools/_nuxt/pages.CV7xHNff.css +1 -0
  52. package/dist/devtools/app-sources/index.html +1 -0
  53. package/dist/devtools/debug/index.html +1 -0
  54. package/dist/devtools/docs/index.html +1 -0
  55. package/dist/devtools/index.html +1 -0
  56. package/dist/devtools/user-sources/index.html +1 -0
  57. package/dist/module.d.mts +10 -1
  58. package/dist/module.d.ts +10 -1
  59. package/dist/module.json +1 -1
  60. package/dist/module.mjs +398 -432
  61. package/dist/runtime/server/composables/defineSitemapEventHandler.d.ts +1 -1
  62. package/dist/runtime/server/kit.d.ts +0 -1
  63. package/dist/runtime/server/kit.js +5 -7
  64. package/dist/runtime/server/plugins/warm-up.js +1 -1
  65. package/dist/runtime/server/robots-polyfill/getPathRobotConfig.d.ts +1 -1
  66. package/dist/runtime/server/robots-polyfill/getPathRobotConfig.js +1 -1
  67. package/dist/runtime/server/routes/__sitemap__/debug-production.d.ts +17 -0
  68. package/dist/runtime/server/routes/__sitemap__/debug-production.js +77 -0
  69. package/dist/runtime/server/routes/__sitemap__/debug.d.ts +2 -2
  70. package/dist/runtime/server/routes/__sitemap__/debug.js +23 -4
  71. package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v2.js +1 -1
  72. package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v3.d.ts +1 -3
  73. package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v3.js +24 -12
  74. package/dist/runtime/server/routes/sitemap.xsl.js +349 -153
  75. package/dist/runtime/server/sitemap/builder/sitemap-index.js +8 -7
  76. package/dist/runtime/server/sitemap/builder/sitemap.d.ts +1 -1
  77. package/dist/runtime/server/sitemap/builder/sitemap.js +24 -7
  78. package/dist/runtime/server/sitemap/builder/xml.js +55 -25
  79. package/dist/runtime/server/sitemap/event-handlers.js +15 -6
  80. package/dist/runtime/server/sitemap/nitro.js +17 -8
  81. package/dist/runtime/server/sitemap/urlset/normalise.d.ts +2 -1
  82. package/dist/runtime/server/sitemap/urlset/normalise.js +25 -1
  83. package/dist/runtime/server/sitemap/urlset/sources.js +3 -3
  84. package/dist/runtime/types.d.ts +14 -8
  85. package/dist/runtime/utils-pure.d.ts +3 -4
  86. package/dist/runtime/utils-pure.js +13 -41
  87. package/dist/shared/{sitemap.Bj0OAEtK.mjs → sitemap.B99ug6A9.mjs} +9 -5
  88. package/dist/utils.d.mts +21 -10
  89. package/dist/utils.d.ts +21 -10
  90. package/dist/utils.mjs +62 -8
  91. package/package.json +49 -49
  92. package/dist/client/200.html +0 -1
  93. package/dist/client/404.html +0 -1
  94. package/dist/client/__sitemap__/style.xsl +0 -190
  95. package/dist/client/_nuxt/CVDC-Ayb.js +0 -155
  96. package/dist/client/_nuxt/CVO1_9PV.js +0 -1
  97. package/dist/client/_nuxt/Cp-IABpG.js +0 -1
  98. package/dist/client/_nuxt/D0r3Knsf.js +0 -1
  99. package/dist/client/_nuxt/builds/latest.json +0 -1
  100. package/dist/client/_nuxt/builds/meta/1e2c692d-9f57-4b49-a518-f0dad9ea1e8b.json +0 -1
  101. package/dist/client/_nuxt/byQmnvHb.js +0 -1
  102. package/dist/client/_nuxt/cP7UVfHI.js +0 -1
  103. package/dist/client/_nuxt/entry.Ci1pP-eR.css +0 -1
  104. package/dist/client/_nuxt/error-404.DHoMe5Vi.css +0 -1
  105. package/dist/client/_nuxt/error-500.Da7n0rc6.css +0 -1
  106. package/dist/client/index.html +0 -1
  107. package/dist/client/sitemap.xml +0 -7
  108. package/virtual.d.ts +0 -15
@@ -1,8 +1,8 @@
1
- import { defineEventHandler, getHeader, setHeader, getQuery as h3GetQuery } from "h3";
1
+ import { getSiteConfig } from "#site-config/server/composables";
2
+ import { createSitePathResolver } from "#site-config/server/composables/utils";
3
+ import { defineEventHandler, getHeader, getQuery as h3GetQuery, setHeader } from "h3";
2
4
  import { getQuery, parseURL, withQuery } from "ufo";
3
5
  import { useSitemapRuntimeConfig, xmlEscape } from "../utils.js";
4
- import { useSiteConfig } from "#site-config/server/composables/useSiteConfig";
5
- import { createSitePathResolver } from "#site-config/server/composables/utils";
6
6
  export default defineEventHandler(async (e) => {
7
7
  const fixPath = createSitePathResolver(e, { absolute: false, withBase: true });
8
8
  const { sitemapName: fallbackSitemapName, cacheMaxAgeSeconds, version, xslColumns, xslTips } = useSitemapRuntimeConfig();
@@ -11,20 +11,18 @@ export default defineEventHandler(async (e) => {
11
11
  setHeader(e, "Cache-Control", `public, max-age=${cacheMaxAgeSeconds}, must-revalidate`);
12
12
  else
13
13
  setHeader(e, "Cache-Control", `no-cache, no-store`);
14
- const svgIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="icon" style="margin-right: 4px; font-size: 25px;" width="1em" height="1em" viewBox="0 0 32 32"><path fill="#93c5fd" d="M4 26h4v4H4zm10 0h4v4h-4zm10 0h4v4h-4zm1-10h-8v-2h-2v2H7a2.002 2.002 0 0 0-2 2v6h2v-6h8v6h2v-6h8v6h2v-6a2.002 2.002 0 0 0-2-2zM9 2v10h14V2zm2 2h2v6h-2zm10 6h-6V4h6z"></path></svg>`;
15
- const creditName = `<a href="https://github.com/nuxt-modules/sitemap" style="color: black; display: flex; align-items: center; font-weight: 500;" target="_blank" rel="noopener">${svgIcon} Nuxt Sitemap v${version}</a>`;
16
- const { name: siteName, url: siteUrl } = useSiteConfig(e);
14
+ const { name: siteName, url: siteUrl } = getSiteConfig(e);
17
15
  const referrer = getHeader(e, "Referer") || "/";
18
16
  const referrerPath = parseURL(referrer).pathname;
19
17
  const isNotIndexButHasIndex = referrerPath !== "/sitemap.xml" && referrerPath !== "/sitemap_index.xml" && referrerPath.endsWith(".xml");
20
18
  const sitemapName = parseURL(referrer).pathname.split("/").pop()?.split("-sitemap")[0] || fallbackSitemapName;
21
19
  const title = `${siteName}${sitemapName !== "sitemap.xml" ? ` - ${sitemapName === "sitemap_index.xml" ? "index" : sitemapName}` : ""}`.replace(/&/g, "&amp;");
20
+ const isIndexPage = referrerPath === "/sitemap.xml" || referrerPath === "/sitemap_index.xml";
22
21
  const canonicalQuery = getQuery(referrer).canonical;
23
22
  const isShowingCanonical = typeof canonicalQuery !== "undefined" && canonicalQuery !== "false";
24
- const conditionalTips = [
25
- 'You are looking at a <a href="https://developer.mozilla.org/en-US/docs/Web/XSLT/Transforming_XML_with_XSLT/An_Overview" style="color: #398465" target="_blank">XML stylesheet</a>. Read the <a href="https://nuxtseo.com/sitemap/guides/customising-ui" style="color: #398465" target="_blank">docs</a> to learn how to customize it. View the page source to see the raw XML.',
26
- `URLs missing? Check Nuxt Devtools Sitemap tab (or the <a href="${xmlEscape(withQuery("/__sitemap__/debug.json", { sitemap: sitemapName }))}" style="color: #398465" target="_blank">debug endpoint</a>).`
27
- ];
23
+ const debugUrl = xmlEscape(withQuery("/__sitemap__/debug.json", { sitemap: sitemapName }));
24
+ const devUrl = xmlEscape(referrerPath);
25
+ const prodUrl = xmlEscape(withQuery(referrerPath, { canonical: "" }));
28
26
  const fetchErrors = [];
29
27
  const xslQuery = h3GetQuery(e);
30
28
  if (xslQuery.error_messages) {
@@ -35,25 +33,20 @@ export default defineEventHandler(async (e) => {
35
33
  const urls = Array.isArray(errorUrls) ? errorUrls : errorUrls ? [errorUrls] : [];
36
34
  messages.forEach((msg, i) => {
37
35
  const errorParts = [xmlEscape(msg)];
38
- if (urls[i]) {
36
+ if (urls[i])
39
37
  errorParts.push(xmlEscape(urls[i]));
40
- }
41
- fetchErrors.push(`<strong style="color: #dc2626;">Error ${i + 1}:</strong> ${errorParts.join(" - ")}`);
38
+ fetchErrors.push(`<span class="error-item">${errorParts.join(" \u2014 ")}</span>`);
42
39
  });
43
40
  }
44
41
  }
45
- if (!isShowingCanonical) {
46
- const canonicalPreviewUrl = withQuery(referrer, { canonical: "" });
47
- conditionalTips.push(`Your canonical site URL is <strong>${xmlEscape(siteUrl)}</strong>.`);
48
- conditionalTips.push(`You can preview your canonical sitemap by visiting <a href="${xmlEscape(canonicalPreviewUrl)}" style="color: #398465; white-space: nowrap;">${xmlEscape(fixPath(canonicalPreviewUrl))}?canonical</a>`);
49
- } else {
50
- conditionalTips.push(`You are viewing the canonical sitemap. You can switch to using the request origin: <a href="${xmlEscape(fixPath(referrer))}" style="color: #398465; white-space: nowrap ">${xmlEscape(fixPath(referrer))}</a>`);
51
- }
52
42
  const hasRuntimeErrors = fetchErrors.length > 0;
53
- const showDevTips = import.meta.dev && xslTips !== false;
54
- const showSidebar = showDevTips || hasRuntimeErrors;
55
- const devTips = showDevTips ? conditionalTips.map((t) => `<li><p>${t}</p></li>`).join("\n") : "";
56
- const runtimeErrors = hasRuntimeErrors ? fetchErrors.map((t) => `<li><p>${t}</p></li>`).join("\n") : "";
43
+ const showDevTools = import.meta.dev && xslTips !== false;
44
+ const hints = [
45
+ `This is an XSL sitemap (CSS for XML). Disable with <code>xsl: false</code>`,
46
+ `View the raw XML by adding <code>?canonical</code> to the URL`,
47
+ `Check <code>/__sitemap__/debug.json</code> for full sitemap diagnostics`
48
+ ];
49
+ const hint = hints[Math.floor(Math.random() * hints.length)];
57
50
  let columns = [...xslColumns];
58
51
  if (!columns.length) {
59
52
  columns = [
@@ -77,176 +70,379 @@ export default defineEventHandler(async (e) => {
77
70
  <title>XML Sitemap</title>
78
71
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
79
72
  <style type="text/css">
73
+ :root {
74
+ --accent: #00dc82;
75
+ --accent-hover: #00b86b;
76
+ --bg: #0a0a0a;
77
+ --bg-elevated: #141414;
78
+ --bg-subtle: #1a1a1a;
79
+ --border: #262626;
80
+ --border-subtle: #1f1f1f;
81
+ --text: #e5e5e5;
82
+ --text-muted: #737373;
83
+ --text-faint: #525252;
84
+ --error: #ef4444;
85
+ --error-bg: rgba(239,68,68,0.1);
86
+ --warning: #f59e0b;
87
+ }
88
+ * { box-sizing: border-box; }
80
89
  body {
81
- font-family: Inter, Helvetica, Arial, sans-serif;
82
- font-size: 14px;
83
- color: #333;
90
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
91
+ font-size: 13px;
92
+ color: var(--text);
93
+ background: var(--bg);
94
+ margin: 0;
95
+ padding: 0;
96
+ line-height: 1.6;
97
+ -webkit-font-smoothing: antialiased;
84
98
  }
99
+ a { color: inherit; transition: color 0.15s; }
100
+ a:hover { color: var(--accent); }
85
101
 
86
- table {
87
- border: none;
88
- border-collapse: collapse;
102
+ /* Debug bar (dev only) */
103
+ .debug-bar {
104
+ position: fixed;
105
+ bottom: 0.75rem;
106
+ left: 50%;
107
+ transform: translateX(-50%);
108
+ width: 80%;
109
+ background: var(--bg-elevated);
110
+ border: 1px solid var(--border);
111
+ border-radius: 10px;
112
+ padding: 0 1rem;
113
+ height: 2.5rem;
114
+ display: flex;
115
+ align-items: center;
116
+ gap: 0.75rem;
117
+ z-index: 100;
118
+ font-size: 11px;
89
119
  }
90
-
91
- .bg-yellow-200 {
92
- background-color: #fef9c3;
120
+ .debug-bar-brand {
121
+ display: flex;
122
+ align-items: center;
123
+ gap: 0.5rem;
124
+ color: var(--text-muted);
125
+ text-decoration: none;
93
126
  }
94
-
95
- .p-5 {
96
- padding: 1.25rem;
127
+ .debug-bar-brand:hover { color: var(--text); }
128
+ .debug-bar-brand svg { flex-shrink: 0; }
129
+ .debug-bar-hint {
130
+ color: var(--text-faint);
131
+ margin-right: auto;
132
+ white-space: nowrap;
133
+ overflow: hidden;
134
+ text-overflow: ellipsis;
97
135
  }
98
-
99
- .rounded {
136
+ .debug-bar-hint code {
137
+ background: var(--bg-subtle);
138
+ padding: 0.1rem 0.3rem;
139
+ border-radius: 3px;
140
+ font-size: 10px;
141
+ }
142
+ .mode-badge {
143
+ font-size: 9px;
144
+ font-weight: 600;
145
+ text-transform: uppercase;
146
+ letter-spacing: 0.04em;
147
+ padding: 0.2rem 0.4rem;
148
+ border-radius: 3px;
149
+ }
150
+ .mode-dev { background: rgba(245,158,11,0.15); color: var(--warning); }
151
+ .mode-prod { background: rgba(0,220,130,0.12); color: var(--accent); }
152
+ .mode-toggle {
153
+ display: inline-flex;
100
154
  border-radius: 4px;
101
- }
102
-
103
- .shadow {
104
- box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
155
+ overflow: hidden;
156
+ background: var(--bg-subtle);
157
+ padding: 2px;
158
+ gap: 1px;
105
159
  }
106
-
107
- #sitemap tr:nth-child(odd) td {
108
- background-color: #f8f8f8 !important;
160
+ .mode-toggle a {
161
+ padding: 0.2rem 0.4rem;
162
+ font-size: 9px;
163
+ font-weight: 500;
164
+ text-decoration: none;
165
+ color: var(--text-muted);
166
+ border-radius: 2px;
167
+ transition: all 0.15s;
109
168
  }
110
-
111
- #sitemap tbody tr:hover td {
112
- background-color: #fff;
169
+ .mode-toggle a:hover { color: var(--text); }
170
+ .mode-toggle a.active {
171
+ background: var(--accent);
172
+ color: #0a0a0a;
113
173
  }
114
-
115
- #sitemap tbody tr:hover td, #sitemap tbody tr:hover td a {
116
- color: #000;
174
+ .btn {
175
+ display: inline-flex;
176
+ align-items: center;
177
+ gap: 0.25rem;
178
+ padding: 0.25rem 0.5rem;
179
+ border-radius: 4px;
180
+ text-decoration: none;
181
+ font-size: 10px;
182
+ font-weight: 500;
183
+ transition: all 0.15s;
117
184
  }
118
-
119
- .expl a {
120
- color: #398465;
121
- font-weight: 600;
185
+ .btn-primary {
186
+ background: var(--accent);
187
+ color: #0a0a0a;
122
188
  }
189
+ .btn-primary:hover { background: var(--accent-hover); color: #0a0a0a; }
190
+ .btn svg { width: 12px; height: 12px; }
123
191
 
124
- .expl a:visited {
125
- color: #398465;
192
+ /* Error banner */
193
+ .error-banner {
194
+ background: var(--error-bg);
195
+ border-bottom: 1px solid rgba(239,68,68,0.2);
196
+ padding: 0.75rem 1.5rem;
197
+ color: #fca5a5;
198
+ font-size: 12px;
126
199
  }
127
-
128
- a {
129
- color: #000;
200
+ .error-banner strong { color: var(--error); }
201
+ .error-item { display: block; margin-top: 0.375rem; color: #fca5a5; }
202
+ .error-debug-link {
203
+ display: inline-flex;
204
+ align-items: center;
205
+ gap: 0.25rem;
206
+ margin-top: 0.625rem;
207
+ padding: 0.25rem 0.5rem;
208
+ background: var(--error);
209
+ color: #fff;
210
+ border-radius: 4px;
211
+ font-size: 11px;
212
+ font-weight: 500;
130
213
  text-decoration: none;
214
+ transition: background 0.15s;
131
215
  }
216
+ .error-debug-link:hover { background: #dc2626; color: #fff; }
132
217
 
133
- a:visited {
134
- color: #777;
218
+ /* Main content */
219
+ .container {
220
+ max-width: 1200px;
221
+ margin: 0 auto;
222
+ padding: 1.5rem;
135
223
  }
136
-
137
- a:hover {
224
+ .header {
225
+ margin-bottom: 1.25rem;
226
+ }
227
+ .header h1 {
228
+ font-size: 1rem;
229
+ font-weight: 600;
230
+ margin: 0 0 0.25rem 0;
231
+ color: var(--text);
232
+ }
233
+ .header-meta {
234
+ color: var(--text-muted);
235
+ font-size: 12px;
236
+ }
237
+ .header-meta a {
238
+ color: var(--text-muted);
138
239
  text-decoration: underline;
240
+ text-decoration-color: var(--border);
241
+ text-underline-offset: 2px;
139
242
  }
243
+ .header-meta a:hover { color: var(--accent); text-decoration-color: var(--accent); }
140
244
 
245
+ /* Table */
246
+ .table-wrap {
247
+ border: 1px solid var(--border);
248
+ border-radius: 8px;
249
+ overflow: hidden;
250
+ background: var(--bg-elevated);
251
+ }
252
+ table {
253
+ width: 100%;
254
+ border-collapse: collapse;
255
+ }
256
+ th {
257
+ text-align: left;
258
+ padding: 0.625rem 1rem;
259
+ font-size: 10px;
260
+ font-weight: 600;
261
+ text-transform: uppercase;
262
+ letter-spacing: 0.05em;
263
+ color: var(--text-muted);
264
+ background: var(--bg-subtle);
265
+ border-bottom: 1px solid var(--border);
266
+ }
141
267
  td {
268
+ padding: 0.5rem 1rem;
269
+ border-bottom: 1px solid var(--border-subtle);
142
270
  font-size: 12px;
271
+ color: var(--text);
143
272
  }
273
+ tr:last-child td { border-bottom: none; }
274
+ tr:hover td { background: rgba(255,255,255,0.02); }
275
+ td a {
276
+ text-decoration: none;
277
+ word-break: break-all;
278
+ color: var(--text);
279
+ }
280
+ td a:hover { color: var(--accent); }
281
+ .inline-warning {
282
+ font-size: 11px;
283
+ color: var(--warning);
284
+ margin-top: 0.25rem;
285
+ line-height: 1.4;
286
+ }
287
+ .inline-warning::before {
288
+ content: "\u26A0 ";
289
+ }
290
+ .count {
291
+ display: inline-block;
292
+ min-width: 1.25rem;
293
+ padding: 0.125rem 0.375rem;
294
+ background: var(--bg-subtle);
295
+ border-radius: 4px;
296
+ text-align: center;
297
+ font-size: 11px;
298
+ color: var(--text-muted);
299
+ font-variant-numeric: tabular-nums;
300
+ }
301
+ .count:empty::before { content: "0"; }
144
302
 
145
- .text-2xl {
146
- font-size: 2rem;
147
- font-weight: 600;
148
- line-height: 1.25;
303
+ /* Light mode */
304
+ @media (prefers-color-scheme: light) {
305
+ :root {
306
+ --accent: #00a963;
307
+ --accent-hover: #008f54;
308
+ --bg: #ffffff;
309
+ --bg-elevated: #f5f5f5;
310
+ --bg-subtle: #ebebeb;
311
+ --border: #d4d4d4;
312
+ --border-subtle: #e5e5e5;
313
+ --text: #171717;
314
+ --text-muted: #525252;
315
+ --text-faint: #737373;
316
+ --error: #dc2626;
317
+ --error-bg: rgba(220,38,38,0.08);
318
+ --warning: #b45309;
319
+ }
320
+ tr:hover td { background: rgba(0,0,0,0.02); }
321
+ .btn-primary { color: #fff; }
322
+ .btn-primary:hover { color: #fff; }
323
+ .mode-toggle a.active { color: #fff; }
324
+ .error-banner { color: #991b1b; }
325
+ .error-item { color: #b91c1c; }
326
+ .error-debug-link { color: #fff; }
327
+ .error-debug-link:hover { color: #fff; }
149
328
  }
150
329
 
151
- th {
152
- text-align: left;
153
- padding-right: 30px;
154
- font-size: 12px;
330
+ .debug-bar-version {
331
+ color: var(--text-faint);
332
+ font-size: 10px;
155
333
  }
156
334
 
157
- thead th {
158
- border-bottom: 1px solid #000;
159
- }
160
- .fixed { position: fixed; }
161
- .right-2 { right: 2rem; }
162
- .top-2 { top: 2rem; }
163
- .w-30 { width: 30rem; }
164
- p { margin: 0; }
165
- li { padding-bottom: 0.5rem; line-height: 1.5; }
166
- h1 { margin: 0; }
167
- .mb-5 { margin-bottom: 1.25rem; }
168
- .mb-3 { margin-bottom: 0.75rem; }
335
+ /* Responsive */
336
+ @media (max-width: 640px) {
337
+ .debug-bar { padding: 0 0.75rem; gap: 0.5rem; width: 95%; }
338
+ .debug-bar-brand span { display: none; }
339
+ .debug-bar-hint { display: none; }
340
+ .debug-bar-version { display: none; }
341
+ .mode-badge { display: none; }
342
+ .container { padding: 1rem; }
343
+ th, td { padding: 0.5rem 0.75rem; }
344
+ }
345
+ ${showDevTools ? "body { padding-bottom: 3.5rem; }" : ""}
169
346
  </style>
170
347
  </head>
171
348
  <body>
172
- <div style="grid-template-columns: 1fr 1fr; display: grid; margin: 3rem;">
173
- <div>
174
- <div id="content">
175
- <h1 class="text-2xl mb-3">XML Sitemap</h1>
176
- <h2>${xmlEscape(title)}</h2>
177
- ${isNotIndexButHasIndex ? `<p style="font-size: 12px; margin-bottom: 1rem;"><a href="${xmlEscape(fixPath("/sitemap_index.xml"))}">${xmlEscape(fixPath("/sitemap_index.xml"))}</a></p>` : ""}
349
+ ${hasRuntimeErrors ? `<div class="error-banner">
350
+ <strong>Sitemap Generation Errors</strong>
351
+ ${fetchErrors.join("")}
352
+ <a href="${debugUrl}" target="_blank" class="error-debug-link">View Debug Info \u2192</a>
353
+ </div>` : ""}
354
+ <div class="container">
355
+ <div class="header">
356
+ <h1>${xmlEscape(title)}</h1>
357
+ <div class="header-meta">
358
+ ${isNotIndexButHasIndex ? `Part of <a href="${xmlEscape(fixPath("/sitemap_index.xml"))}">${xmlEscape(fixPath("/sitemap_index.xml"))}</a> \xB7 ` : ""}
359
+ <xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &gt; 0">
360
+ <xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/> sitemaps
361
+ </xsl:if>
362
+ <xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &lt; 1">
363
+ <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> URLs
364
+ </xsl:if>
365
+ </div>
366
+ </div>
178
367
  <xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &gt; 0">
179
- <p class="expl" style="margin-bottom: 1rem;">
180
- This XML Sitemap Index file contains
181
- <xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/> sitemaps.
182
- </p>
183
- <table id="sitemap" cellpadding="3">
184
- <thead>
185
- <tr>
186
- <th width="75%">Sitemap</th>
187
- <th width="25%">Last Modified</th>
188
- </tr>
189
- </thead>
190
- <tbody>
191
- <xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap">
192
- <xsl:variable name="sitemapURL">
193
- <xsl:value-of select="sitemap:loc"/>
194
- </xsl:variable>
368
+ <div class="table-wrap">
369
+ <table>
370
+ <thead>
195
371
  <tr>
196
- <td>
197
- <a href="{$sitemapURL}">
198
- <xsl:value-of select="sitemap:loc"/>
199
- </a>
200
- </td>
201
- <td>
202
- <xsl:value-of
203
- select="concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)),concat(' ', substring(sitemap:lastmod,20,6)))"/>
204
- </td>
372
+ <th style="width:70%">Sitemap</th>
373
+ <th style="width:30%">Last Modified</th>
205
374
  </tr>
206
- </xsl:for-each>
207
- </tbody>
208
- </table>
375
+ </thead>
376
+ <tbody>
377
+ <xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap">
378
+ <xsl:variable name="sitemapURL">
379
+ <xsl:value-of select="sitemap:loc"/>
380
+ </xsl:variable>
381
+ <tr>
382
+ <td>
383
+ <a href="{$sitemapURL}">
384
+ <xsl:value-of select="sitemap:loc"/>
385
+ </a>
386
+ </td>
387
+ <td>
388
+ <xsl:value-of
389
+ select="concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)),concat(' ', substring(sitemap:lastmod,20,6)))"/>
390
+ </td>
391
+ </tr>
392
+ </xsl:for-each>
393
+ </tbody>
394
+ </table>
395
+ </div>
209
396
  </xsl:if>
210
397
  <xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &lt; 1">
211
- <p class="expl" style="margin-bottom: 1rem;">
212
- This XML Sitemap contains
213
- <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> URLs.
214
- </p>
215
- <table id="sitemap" cellpadding="3">
216
- <thead>
217
- <tr>
218
- ${columns.map((c) => `<th width="${c.width}">${c.label}</th>`).join("\n")}
219
- </tr>
220
- </thead>
221
- <tbody>
222
- <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
223
- <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
224
- <xsl:for-each select="sitemap:urlset/sitemap:url">
398
+ <div class="table-wrap">
399
+ <table>
400
+ <thead>
225
401
  <tr>
226
- <td>
227
- <xsl:variable name="itemURL">
228
- <xsl:value-of select="sitemap:loc"/>
229
- </xsl:variable>
230
- <a href="{$itemURL}">
231
- <xsl:value-of select="sitemap:loc"/>
232
- </a>
233
- </td>
234
- ${columns.filter((c) => c.label !== "URL").map((c) => `<td>
235
- <xsl:value-of select="${c.select}"/>
236
- </td>`).join("\n")}
402
+ ${columns.map((c) => `<th style="width:${c.width}">${c.label}</th>`).join("\n")}
237
403
  </tr>
238
- </xsl:for-each>
239
- </tbody>
240
- </table>
404
+ </thead>
405
+ <tbody>
406
+ <xsl:for-each select="sitemap:urlset/sitemap:url">
407
+ <tr>
408
+ <td>
409
+ <xsl:variable name="itemURL">
410
+ <xsl:value-of select="sitemap:loc"/>
411
+ </xsl:variable>
412
+ <a href="{$itemURL}">
413
+ <xsl:value-of select="sitemap:loc"/>
414
+ </a>
415
+ ${showDevTools ? `<xsl:for-each select="comment()[starts-with(normalize-space(.), 'WARN:')]">
416
+ <div class="inline-warning">
417
+ <xsl:value-of select="substring-after(normalize-space(.), 'WARN:')"/>
418
+ </div>
419
+ </xsl:for-each>` : ""}
420
+ </td>
421
+ ${columns.filter((c) => c.label !== "URL").map((c) => `<td><span class="count"><xsl:value-of select="${c.select}"/></span></td>`).join("\n")}
422
+ </tr>
423
+ </xsl:for-each>
424
+ </tbody>
425
+ </table>
426
+ </div>
241
427
  </xsl:if>
242
428
  </div>
243
- </div>
244
- ${showSidebar ? `<div class="w-30 top-2 shadow rounded p-5 right-2" style="margin: 0 auto;">
245
- ${showDevTips ? `<div><p><strong>Development Tips</strong></p><ul style="margin: 1rem 0; padding: 0;">${devTips}</ul></div>` : ""}
246
- ${hasRuntimeErrors ? `<div${showDevTips ? ' style="margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid #e5e7eb;"' : ""}><p><strong style="color: #dc2626;">Runtime Errors</strong></p><ul style="margin: 1rem 0; padding: 0;">${runtimeErrors}</ul></div>` : ""}
247
- ${showDevTips ? `<p style="margin-top: 1rem;">${creditName}</p>` : ""}
248
- </div>` : ""}
249
- </div>
429
+ ${showDevTools ? `<div class="debug-bar">
430
+ <a href="${xmlEscape(fixPath("/sitemap_index.xml"))}" class="debug-bar-brand">
431
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 32 32"><path fill="#00dc82" d="M4 26h4v4H4zm10 0h4v4h-4zm10 0h4v4h-4zm1-10h-8v-2h-2v2H7a2 2 0 0 0-2 2v6h2v-6h8v6h2v-6h8v6h2v-6a2 2 0 0 0-2-2zM9 2v10h14V2zm2 2h2v6h-2zm10 6h-6V4h6z"/></svg>
432
+ <span>Sitemap Debug Bar</span>
433
+ </a>
434
+ <span class="debug-bar-version">v${version} \xB7 ${xmlEscape(siteUrl)}</span>
435
+ <span class="debug-bar-hint">Hint: ${hint}</span>
436
+ ${isIndexPage ? `<span class="mode-badge ${isShowingCanonical ? "mode-prod" : "mode-dev"}">${isShowingCanonical ? "Prod" : "Dev"}</span>
437
+ <div class="mode-toggle">
438
+ <a href="${isShowingCanonical ? devUrl : "#"}" class="${!isShowingCanonical ? "active" : ""}">Dev</a>
439
+ <a href="${!isShowingCanonical ? prodUrl : "#"}" class="${isShowingCanonical ? "active" : ""}">Prod</a>
440
+ </div>` : ""}
441
+ <a href="${debugUrl}" target="_blank" class="btn btn-primary">
442
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
443
+ Debug
444
+ </a>
445
+ </div>` : ""}
250
446
  </body>
251
447
  </html>
252
448
  </xsl:template>
@@ -1,12 +1,12 @@
1
1
  import { defu } from "defu";
2
- import { joinURL, withQuery } from "ufo";
3
- import { defineCachedFunction } from "nitropack/runtime";
4
2
  import { getHeader } from "h3";
3
+ import { defineCachedFunction, useRuntimeConfig } from "nitropack/runtime";
4
+ import { joinURL, withQuery } from "ufo";
5
5
  import { normaliseDate } from "../urlset/normalise.js";
6
- import { globalSitemapSources, childSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
7
6
  import { sortInPlace } from "../urlset/sort.js";
8
- import { escapeValueForXml } from "./xml.js";
7
+ import { childSitemapSources, globalSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
9
8
  import { resolveSitemapEntries } from "./sitemap.js";
9
+ import { escapeValueForXml } from "./xml.js";
10
10
  const buildSitemapIndexCached = defineCachedFunction(
11
11
  async (event, resolvers, runtimeConfig, nitro) => {
12
12
  return buildSitemapIndexInternal(resolvers, runtimeConfig, nitro);
@@ -47,7 +47,8 @@ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
47
47
  const chunks = {};
48
48
  const allFailedSources = [];
49
49
  for (const sitemapName in sitemaps) {
50
- if (sitemapName === "index" || sitemapName === "chunks") continue;
50
+ if (sitemapName === "index" || sitemapName === "chunks")
51
+ continue;
51
52
  const sitemapConfig = sitemaps[sitemapName];
52
53
  if (sitemapConfig.chunks || sitemapConfig._isChunking) {
53
54
  sitemapConfig._isChunking = true;
@@ -80,7 +81,7 @@ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
80
81
  event: resolvers.event
81
82
  };
82
83
  await nitro?.hooks.callHook("sitemap:input", resolvedCtx);
83
- const normalisedUrls = resolveSitemapEntries(sitemap, resolvedCtx.urls, { autoI18n, isI18nMapped }, resolvers);
84
+ const normalisedUrls = resolveSitemapEntries(sitemap, resolvedCtx.urls, { autoI18n, isI18nMapped }, resolvers, useRuntimeConfig().app.baseURL);
84
85
  const enhancedUrls = normalisedUrls.map((e) => defu(e, sitemap.defaults));
85
86
  const sortedUrls = maybeSort(enhancedUrls);
86
87
  sortedUrls.forEach((url, i) => {
@@ -129,7 +130,7 @@ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
129
130
  event: resolvers.event
130
131
  };
131
132
  await nitro?.hooks.callHook("sitemap:input", resolvedCtx);
132
- const normalisedUrls = resolveSitemapEntries(sitemapConfig, resolvedCtx.urls, { autoI18n, isI18nMapped }, resolvers);
133
+ const normalisedUrls = resolveSitemapEntries(sitemapConfig, resolvedCtx.urls, { autoI18n, isI18nMapped }, resolvers, useRuntimeConfig().app.baseURL);
133
134
  const totalUrls = normalisedUrls.length;
134
135
  const chunkCount = Math.ceil(totalUrls / chunkSize);
135
136
  sitemapConfig._chunkCount = chunkCount;
@@ -5,7 +5,7 @@ export interface NormalizedI18n extends ResolvedSitemapUrl {
5
5
  _locale: AutoI18nConfig['locales'][number];
6
6
  _index?: number;
7
7
  }
8
- export declare function resolveSitemapEntries(sitemap: SitemapDefinition, urls: SitemapUrlInput[], runtimeConfig: Pick<ModuleRuntimeConfig, 'autoI18n' | 'isI18nMapped'>, resolvers?: NitroUrlResolvers): ResolvedSitemapUrl[];
8
+ export declare function resolveSitemapEntries(sitemap: SitemapDefinition, urls: SitemapUrlInput[], runtimeConfig: Pick<ModuleRuntimeConfig, 'autoI18n' | 'isI18nMapped'>, resolvers?: NitroUrlResolvers, baseURL?: string): ResolvedSitemapUrl[];
9
9
  export declare function buildSitemapUrls(sitemap: SitemapDefinition, resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp): Promise<{
10
10
  urls: ResolvedSitemapUrl[];
11
11
  failedSources: Array<{