sanity-plugin-seofields 1.8.0 → 1.9.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 (113) hide show
  1. package/README.md +437 -26
  2. package/dist/SeoHealthTool-2COI27KI.cjs +8 -0
  3. package/dist/SeoHealthTool-2COI27KI.cjs.map +1 -0
  4. package/dist/SeoHealthTool-CWI3KB2V.js +8 -0
  5. package/dist/SeoHealthTool-CWI3KB2V.js.map +1 -0
  6. package/dist/{SeoPreview-3EXR6FD4.cjs → SeoPreview-LMZAWWOE.cjs} +35 -38
  7. package/dist/SeoPreview-LMZAWWOE.cjs.map +1 -0
  8. package/dist/{SeoPreview-4PPAF4NO.js → SeoPreview-UNQBKTQO.js} +14 -11
  9. package/dist/SeoPreview-UNQBKTQO.js.map +1 -0
  10. package/dist/chunk-3OK3S2F7.cjs +673 -0
  11. package/dist/chunk-3OK3S2F7.cjs.map +1 -0
  12. package/dist/{chunk-B5IVI5LP.cjs → chunk-5XTQRILL.cjs} +286 -236
  13. package/dist/chunk-5XTQRILL.cjs.map +1 -0
  14. package/dist/{chunk-254YHUN3.cjs → chunk-7N4MLTMR.js} +8 -6
  15. package/dist/chunk-7N4MLTMR.js.map +1 -0
  16. package/dist/{chunk-DDAAVRWG.js → chunk-A57XNQC7.cjs} +9 -4
  17. package/dist/chunk-A57XNQC7.cjs.map +1 -0
  18. package/dist/chunk-BWLJDK5J.js +624 -0
  19. package/dist/chunk-BWLJDK5J.js.map +1 -0
  20. package/dist/chunk-FUUWBQE2.cjs +195 -0
  21. package/dist/chunk-FUUWBQE2.cjs.map +1 -0
  22. package/dist/{chunk-ZBHLMQTS.cjs → chunk-HHO2AKAP.js} +44 -17
  23. package/dist/chunk-HHO2AKAP.js.map +1 -0
  24. package/dist/chunk-KIEO6QG3.js +195 -0
  25. package/dist/chunk-KIEO6QG3.js.map +1 -0
  26. package/dist/chunk-R2U7JF7U.cjs +624 -0
  27. package/dist/chunk-R2U7JF7U.cjs.map +1 -0
  28. package/dist/{chunk-VR44E62I.js → chunk-XZKQWV2H.js} +204 -33
  29. package/dist/chunk-XZKQWV2H.js.map +1 -0
  30. package/dist/{chunk-HDZZQCH7.js → chunk-Y46ACXM4.cjs} +45 -5
  31. package/dist/chunk-Y46ACXM4.cjs.map +1 -0
  32. package/dist/chunk-Z5AOUU4H.js +673 -0
  33. package/dist/chunk-Z5AOUU4H.js.map +1 -0
  34. package/dist/cli.js +27 -27
  35. package/dist/{component-DEXwtemT.d.ts → component-CjT1hvxh.d.ts} +2 -2
  36. package/dist/{component-BzI-LHPw.d.cts → component-WYh0z8as.d.cts} +2 -2
  37. package/dist/define-cli.cjs +2 -4
  38. package/dist/define-cli.cjs.map +1 -1
  39. package/dist/define-cli.js +4 -4
  40. package/dist/define-cli.js.map +1 -1
  41. package/dist/head.cjs +14 -0
  42. package/dist/head.cjs.map +1 -0
  43. package/dist/head.d.cts +254 -0
  44. package/dist/head.d.ts +254 -0
  45. package/dist/head.js +14 -0
  46. package/dist/head.js.map +1 -0
  47. package/dist/index.cjs +978 -367
  48. package/dist/index.cjs.map +1 -1
  49. package/dist/index.d.cts +6 -374
  50. package/dist/index.d.ts +6 -374
  51. package/dist/index.js +920 -286
  52. package/dist/index.js.map +1 -1
  53. package/dist/next.cjs +204 -455
  54. package/dist/next.cjs.map +1 -1
  55. package/dist/next.d.cts +8 -206
  56. package/dist/next.d.ts +8 -206
  57. package/dist/next.js +181 -111
  58. package/dist/next.js.map +1 -1
  59. package/dist/plugin-DQdThyxG.d.ts +449 -0
  60. package/dist/plugin-DoGeZP79.d.cts +449 -0
  61. package/dist/schema/next.cjs +173 -327
  62. package/dist/schema/next.cjs.map +1 -1
  63. package/dist/schema/next.d.cts +4 -4
  64. package/dist/schema/next.d.ts +4 -4
  65. package/dist/schema/next.js +172 -8
  66. package/dist/schema/next.js.map +1 -1
  67. package/dist/schema.cjs +376 -517
  68. package/dist/schema.cjs.map +1 -1
  69. package/dist/schema.d.cts +5 -5
  70. package/dist/schema.d.ts +5 -5
  71. package/dist/schema.js +216 -11
  72. package/dist/schema.js.map +1 -1
  73. package/dist/server.cjs +149 -0
  74. package/dist/server.cjs.map +1 -0
  75. package/dist/server.d.cts +102 -0
  76. package/dist/server.d.ts +102 -0
  77. package/dist/server.js +149 -0
  78. package/dist/server.js.map +1 -0
  79. package/dist/{types-CW8qFdAn.d.ts → types-BAdN1RMu.d.ts} +2 -2
  80. package/dist/{types-B_vjMPtM.d.cts → types-C5i3KMgs.d.cts} +2 -2
  81. package/dist/{types-BXSCbl6p.d.cts → types-DP-DiW6f.d.cts} +2 -2
  82. package/dist/{types-C19cQx5D.d.ts → types-DRLUGLtX.d.ts} +2 -2
  83. package/dist/{types-yVmQfby9.d.cts → types-DxlPXihz.d.cts} +1 -1
  84. package/dist/{types-yVmQfby9.d.ts → types-DxlPXihz.d.ts} +1 -1
  85. package/package.json +25 -4
  86. package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js +0 -4
  87. package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js.map +0 -1
  88. package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs +0 -10
  89. package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs.map +0 -1
  90. package/dist/SeoHealthTool-2KKQJLJL.cjs +0 -11
  91. package/dist/SeoHealthTool-2KKQJLJL.cjs.map +0 -1
  92. package/dist/SeoHealthTool-3CUKGADZ.js +0 -5
  93. package/dist/SeoHealthTool-3CUKGADZ.js.map +0 -1
  94. package/dist/SeoPreview-3EXR6FD4.cjs.map +0 -1
  95. package/dist/SeoPreview-4PPAF4NO.js.map +0 -1
  96. package/dist/chunk-254YHUN3.cjs.map +0 -1
  97. package/dist/chunk-27XSYENH.js +0 -2215
  98. package/dist/chunk-27XSYENH.js.map +0 -1
  99. package/dist/chunk-B5IVI5LP.cjs.map +0 -1
  100. package/dist/chunk-BNXMFD3T.cjs +0 -431
  101. package/dist/chunk-BNXMFD3T.cjs.map +0 -1
  102. package/dist/chunk-DDAAVRWG.js.map +0 -1
  103. package/dist/chunk-HDZZQCH7.js.map +0 -1
  104. package/dist/chunk-P6IOWIO2.cjs +0 -480
  105. package/dist/chunk-P6IOWIO2.cjs.map +0 -1
  106. package/dist/chunk-UOCZFYYP.js +0 -407
  107. package/dist/chunk-UOCZFYYP.js.map +0 -1
  108. package/dist/chunk-VR44E62I.js.map +0 -1
  109. package/dist/chunk-WKXHX3GO.js +0 -424
  110. package/dist/chunk-WKXHX3GO.js.map +0 -1
  111. package/dist/chunk-XZDLJ2N6.cjs +0 -2224
  112. package/dist/chunk-XZDLJ2N6.cjs.map +0 -1
  113. package/dist/chunk-ZBHLMQTS.cjs.map +0 -1
@@ -1,2215 +0,0 @@
1
- import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
2
- import { useClient, useWorkspace } from 'sanity';
3
- import { useIntentLink } from 'sanity/router';
4
- import { usePaneRouter } from 'sanity/structure';
5
- import styled, { keyframes, css } from 'styled-components';
6
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
-
8
- // node_modules/seofields-pro/dist/chunk-CKPRJ6MG.js
9
- var __defProp = Object.defineProperty;
10
- var __defProps = Object.defineProperties;
11
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
12
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
13
- var __hasOwnProp = Object.prototype.hasOwnProperty;
14
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
15
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
16
- var __spreadValues = (a, b) => {
17
- for (var prop in b || (b = {}))
18
- if (__hasOwnProp.call(b, prop))
19
- __defNormalProp(a, prop, b[prop]);
20
- if (__getOwnPropSymbols)
21
- for (var prop of __getOwnPropSymbols(b)) {
22
- if (__propIsEnum.call(b, prop))
23
- __defNormalProp(a, prop, b[prop]);
24
- }
25
- return a;
26
- };
27
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
28
- var __objRest = (source, exclude) => {
29
- var target = {};
30
- for (var prop in source)
31
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
32
- target[prop] = source[prop];
33
- if (source != null && __getOwnPropSymbols)
34
- for (var prop of __getOwnPropSymbols(source)) {
35
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
36
- target[prop] = source[prop];
37
- }
38
- return target;
39
- };
40
- var themeVars = {
41
- light: {
42
- "--seo-bg": "#f0f2f5",
43
- "--seo-card-bg": "#ffffff",
44
- "--seo-text-primary": "#1f2937",
45
- "--seo-text-secondary": "#6b7280",
46
- "--seo-text-muted": "#9ca3af",
47
- "--seo-border": "#e5e7eb",
48
- "--seo-border-light": "#f3f4f6",
49
- "--seo-input-bg": "#f9fafb",
50
- "--seo-header-bg": "#f9fafb",
51
- "--seo-accent": "#6366f1",
52
- "--seo-accent-hover": "#4f46e5",
53
- "--seo-link": "#4f46e5",
54
- "--seo-link-hover": "#4338ca",
55
- "--seo-hover-bg": "#fafafa",
56
- "--seo-shadow": "rgba(0, 0, 0, 0.07)",
57
- "--seo-shadow-hover": "rgba(0, 0, 0, 0.1)",
58
- "--seo-focus-ring": "rgba(99, 102, 241, 0.1)",
59
- "--seo-issue-color": "#ef4444",
60
- "--seo-more-issues": "#6b7280",
61
- "--seo-more-issues-hover": "#374151",
62
- "--seo-popover-bg": "#1f2937",
63
- "--seo-popover-text": "#ffffff",
64
- "--seo-spinner-track": "#e5e7eb",
65
- "--seo-spinner-fill": "#6366f1",
66
- "--seo-btn-bg": "#ffffff",
67
- "--seo-btn-text": "#374151",
68
- "--seo-btn-border": "#d1d5db",
69
- "--seo-btn-hover-bg": "#f3f4f6",
70
- "--seo-btn-hover-border": "#9ca3af",
71
- "--seo-select-arrow": "%236b7280",
72
- "--seo-score-excellent-bg": "#d1fae5",
73
- "--seo-score-excellent-text": "#065f46",
74
- "--seo-score-good-bg": "#fef3c7",
75
- "--seo-score-good-text": "#92400e",
76
- "--seo-score-fair-bg": "#ffedd5",
77
- "--seo-score-fair-text": "#9a3412",
78
- "--seo-score-poor-bg": "#fee2e2",
79
- "--seo-score-poor-text": "#991b1b",
80
- "--seo-preview-bg": "#fef3c7",
81
- "--seo-preview-text": "#92400e",
82
- "--seo-deprecation-bg": "#fffbeb",
83
- "--seo-deprecation-border": "#fcd34d",
84
- "--seo-deprecation-text": "#78350f",
85
- "--seo-deprecation-link": "#92400e",
86
- "--seo-upgrade-bg": "#ffffff",
87
- "--seo-upgrade-border": "#e5e7eb",
88
- "--seo-upgrade-code-bg": "#f3f4f6",
89
- "--seo-upgrade-code-text": "#374151",
90
- "--seo-upgrade-code-border": "#e5e7eb",
91
- "--seo-warning-bg": "#fef3c7",
92
- "--seo-warning-border": "#fcd34d",
93
- "--seo-warning-text": "#92400e",
94
- "--seo-theme-picker-bg": "#ffffff",
95
- "--seo-theme-picker-border": "#e5e7eb",
96
- "--seo-theme-picker-active": "#f0f0ff",
97
- "--seo-theme-picker-active-border": "#6366f1"
98
- },
99
- dark: {
100
- "--seo-bg": "#1a1b1e",
101
- "--seo-card-bg": "#25262b",
102
- "--seo-text-primary": "#c9cdd3",
103
- "--seo-text-secondary": "#8b919a",
104
- "--seo-text-muted": "#6b7280",
105
- "--seo-border": "#373a40",
106
- "--seo-border-light": "#2c2e33",
107
- "--seo-input-bg": "#2c2e33",
108
- "--seo-header-bg": "#2c2e33",
109
- "--seo-accent": "#818cf8",
110
- "--seo-accent-hover": "#6366f1",
111
- "--seo-link": "#818cf8",
112
- "--seo-link-hover": "#a5b4fc",
113
- "--seo-hover-bg": "#2c2e33",
114
- "--seo-shadow": "rgba(0, 0, 0, 0.25)",
115
- "--seo-shadow-hover": "rgba(0, 0, 0, 0.35)",
116
- "--seo-focus-ring": "rgba(129, 140, 248, 0.15)",
117
- "--seo-issue-color": "#f87171",
118
- "--seo-more-issues": "#8b919a",
119
- "--seo-more-issues-hover": "#c9cdd3",
120
- "--seo-popover-bg": "#373a40",
121
- "--seo-popover-text": "#e5e7eb",
122
- "--seo-spinner-track": "#373a40",
123
- "--seo-spinner-fill": "#818cf8",
124
- "--seo-btn-bg": "#2c2e33",
125
- "--seo-btn-text": "#c9cdd3",
126
- "--seo-btn-border": "#373a40",
127
- "--seo-btn-hover-bg": "#373a40",
128
- "--seo-btn-hover-border": "#4b5058",
129
- "--seo-select-arrow": "%238b919a",
130
- "--seo-score-excellent-bg": "#064e3b",
131
- "--seo-score-excellent-text": "#6ee7b7",
132
- "--seo-score-good-bg": "#78350f",
133
- "--seo-score-good-text": "#fcd34d",
134
- "--seo-score-fair-bg": "#7c2d12",
135
- "--seo-score-fair-text": "#fdba74",
136
- "--seo-score-poor-bg": "#7f1d1d",
137
- "--seo-score-poor-text": "#fca5a5",
138
- "--seo-preview-bg": "#78350f",
139
- "--seo-preview-text": "#fcd34d",
140
- "--seo-deprecation-bg": "#422006",
141
- "--seo-deprecation-border": "#a16207",
142
- "--seo-deprecation-text": "#fcd34d",
143
- "--seo-deprecation-link": "#fbbf24",
144
- "--seo-upgrade-bg": "#25262b",
145
- "--seo-upgrade-border": "#373a40",
146
- "--seo-upgrade-code-bg": "#2c2e33",
147
- "--seo-upgrade-code-text": "#c9cdd3",
148
- "--seo-upgrade-code-border": "#373a40",
149
- "--seo-warning-bg": "#422006",
150
- "--seo-warning-border": "#a16207",
151
- "--seo-warning-text": "#fcd34d",
152
- "--seo-theme-picker-bg": "#25262b",
153
- "--seo-theme-picker-border": "#373a40",
154
- "--seo-theme-picker-active": "#2d2d44",
155
- "--seo-theme-picker-active-border": "#818cf8"
156
- }
157
- };
158
- var DashboardContainer = styled.div`
159
- width: 100%;
160
- min-height: 100%;
161
- background: var(--seo-bg);
162
- padding: 28px 32px;
163
- box-sizing: border-box;
164
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
165
- color: var(--seo-text-primary);
166
- `;
167
- var PageHeader = styled.div`
168
- display: flex;
169
- align-items: flex-start;
170
- justify-content: space-between;
171
- gap: 12px;
172
- margin-bottom: 28px;
173
- `;
174
- var PageTitle = styled.h1`
175
- margin: 0 0 6px 0;
176
- font-size: 22px;
177
- font-weight: 700;
178
- color: var(--seo-text-primary);
179
- letter-spacing: -0.3px;
180
- display: flex;
181
- align-items: center;
182
- gap: 10px;
183
- `;
184
- var PreviewBadge = styled.span`
185
- display: inline-block;
186
- background: var(--seo-preview-bg);
187
- color: var(--seo-preview-text);
188
- font-size: 11px;
189
- font-weight: 600;
190
- padding: 4px 8px;
191
- border-radius: 4px;
192
- text-transform: uppercase;
193
- letter-spacing: 0.5px;
194
- margin-left: 8px;
195
- `;
196
- var PageSubtitle = styled.p`
197
- margin: 0;
198
- font-size: 13px;
199
- color: var(--seo-text-secondary);
200
- `;
201
- var StatsGrid = styled.div`
202
- display: grid;
203
- grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
204
- gap: 14px;
205
- margin-bottom: 20px;
206
- `;
207
- var StatCard = styled.div`
208
- background: var(--seo-card-bg);
209
- border-radius: 10px;
210
- padding: 16px 18px;
211
- box-shadow:
212
- 0 1px 3px var(--seo-shadow),
213
- 0 1px 2px var(--seo-shadow);
214
- border-left: ${(p) => p.$accent ? `4px solid ${p.$accent}` : "4px solid transparent"};
215
- transition: box-shadow 0.15s ease;
216
-
217
- &:hover {
218
- box-shadow: 0 4px 12px var(--seo-shadow-hover);
219
- }
220
- `;
221
- var StatLabel = styled.div`
222
- font-size: 11px;
223
- font-weight: 500;
224
- color: var(--seo-text-muted);
225
- text-transform: uppercase;
226
- letter-spacing: 0.5px;
227
- margin-bottom: 8px;
228
- `;
229
- var StatValue = styled.div`
230
- font-size: 26px;
231
- font-weight: 700;
232
- color: var(--seo-text-primary);
233
- line-height: 1;
234
- `;
235
- var ControlsBar = styled.div`
236
- background: var(--seo-card-bg);
237
- border-radius: 10px;
238
- padding: 14px 18px;
239
- display: flex;
240
- align-items: center;
241
- gap: 12px;
242
- flex-wrap: wrap;
243
- margin-bottom: 20px;
244
- box-shadow: 0 1px 3px var(--seo-shadow);
245
- `;
246
- var SearchWrapper = styled.div`
247
- position: relative;
248
- flex: 1;
249
- min-width: 220px;
250
- `;
251
- var SearchIconSvg = styled.span`
252
- position: absolute;
253
- left: 11px;
254
- top: 50%;
255
- transform: translateY(-50%);
256
- color: var(--seo-text-muted);
257
- display: flex;
258
- align-items: center;
259
- pointer-events: none;
260
- `;
261
- var SearchInput = styled.input`
262
- width: 100%;
263
- height: 36px;
264
- padding: 0 12px 0 34px;
265
- border: 1px solid var(--seo-border);
266
- border-radius: 7px;
267
- font-size: 13px;
268
- color: var(--seo-text-primary);
269
- background: var(--seo-input-bg);
270
- box-sizing: border-box;
271
- outline: none;
272
- transition:
273
- border-color 0.15s,
274
- background 0.15s;
275
-
276
- &::placeholder {
277
- color: var(--seo-text-muted);
278
- }
279
-
280
- &:focus {
281
- border-color: var(--seo-accent);
282
- background: var(--seo-card-bg);
283
- box-shadow: 0 0 0 3px var(--seo-focus-ring);
284
- }
285
- `;
286
- var StyledSelect = styled.select`
287
- height: 36px;
288
- padding: 0 32px 0 12px;
289
- border: 1px solid var(--seo-border);
290
- border-radius: 7px;
291
- font-size: 13px;
292
- color: var(--seo-text-secondary);
293
- background: var(--seo-input-bg)
294
- url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E")
295
- no-repeat right 10px center;
296
- appearance: none;
297
- outline: none;
298
- cursor: pointer;
299
- transition: border-color 0.15s;
300
-
301
- &:focus {
302
- border-color: var(--seo-accent);
303
- background-color: var(--seo-card-bg);
304
- box-shadow: 0 0 0 3px var(--seo-focus-ring);
305
- }
306
- `;
307
- var TableCard = styled.div`
308
- background: var(--seo-card-bg);
309
- border-radius: 10px;
310
- box-shadow: 0 1px 3px var(--seo-shadow);
311
- overflow: hidden;
312
- `;
313
- var TableHeader = styled.div`
314
- display: flex;
315
- align-items: center;
316
- padding: 11px 20px;
317
- background: var(--seo-header-bg);
318
- border-bottom: 1px solid var(--seo-border);
319
- font-size: 11px;
320
- font-weight: 600;
321
- color: var(--seo-text-secondary);
322
- text-transform: uppercase;
323
- letter-spacing: 0.5px;
324
- gap: 12px;
325
- `;
326
- var TableRow = styled.div`
327
- display: flex;
328
- align-items: center;
329
- padding: 13px 20px;
330
- border-bottom: 1px solid var(--seo-border-light);
331
- gap: 12px;
332
- transition: background 0.1s;
333
-
334
- &:last-child {
335
- border-bottom: none;
336
- }
337
-
338
- &:hover {
339
- background: var(--seo-hover-bg);
340
- }
341
- `;
342
- var ColTitle = styled.div`
343
- flex: 2;
344
- min-width: 0;
345
- `;
346
- var TitleWrapper = styled.div`
347
- display: flex;
348
- align-items: center;
349
- gap: 4px;
350
- flex-wrap: wrap;
351
- min-width: 0;
352
- `;
353
- var TitleCell = styled.div`
354
- min-width: 0;
355
- overflow: hidden;
356
- flex: 1;
357
- `;
358
- var ColType = styled.div`
359
- flex: 0.8;
360
- min-width: 80px;
361
- `;
362
- var ColScore = styled.div`
363
- flex: 0.6;
364
- min-width: 70px;
365
- `;
366
- var ColIssues = styled.div`
367
- flex: 2;
368
- min-width: 0;
369
- `;
370
- var DocTitleLink = styled.a`
371
- font-size: 13px;
372
- font-weight: 600;
373
- color: var(--seo-link);
374
- white-space: nowrap;
375
- overflow: hidden;
376
- text-overflow: ellipsis;
377
- text-decoration: none;
378
- display: block;
379
- transition: color 0.15s;
380
-
381
- &:hover {
382
- color: var(--seo-link-hover);
383
- text-decoration: underline;
384
- }
385
- `;
386
- var DocId = styled.div`
387
- font-size: 11px;
388
- color: var(--seo-text-muted);
389
- margin-top: 2px;
390
- white-space: nowrap;
391
- overflow: hidden;
392
- text-overflow: ellipsis;
393
- `;
394
- var TypeBadge = styled.span`
395
- display: inline-block;
396
- padding: 3px 8px;
397
- border-radius: 5px;
398
- font-size: 11px;
399
- font-weight: 500;
400
- background: ${(p) => p.$bgColor || "#ede9fe"};
401
- color: ${(p) => p.$textColor || "#5b21b6"};
402
- `;
403
- var TypeText = styled.span`
404
- font-size: 12px;
405
- font-weight: 500;
406
- color: var(--seo-text-secondary);
407
- `;
408
- var CustomBadge = styled.span`
409
- display: inline-block;
410
- padding: 2px 6px;
411
- border-radius: 4px;
412
- font-size: ${(p) => p.$fontSize || "10px"};
413
- font-weight: 600;
414
- background: ${(p) => p.$bgColor || "#e0e7ff"};
415
- color: ${(p) => p.$textColor || "#3730a3"};
416
- white-space: nowrap;
417
- `;
418
- var ScoreBadge = styled.span`
419
- display: inline-block;
420
- padding: 4px 10px;
421
- border-radius: 6px;
422
- font-size: 12px;
423
- font-weight: 700;
424
- background: ${(p) => {
425
- if (p.$score >= 80) return "var(--seo-score-excellent-bg)";
426
- if (p.$score >= 60) return "var(--seo-score-good-bg)";
427
- if (p.$score >= 40) return "var(--seo-score-fair-bg)";
428
- return "var(--seo-score-poor-bg)";
429
- }};
430
- color: ${(p) => {
431
- if (p.$score >= 80) return "var(--seo-score-excellent-text)";
432
- if (p.$score >= 60) return "var(--seo-score-good-text)";
433
- if (p.$score >= 40) return "var(--seo-score-fair-text)";
434
- return "var(--seo-score-poor-text)";
435
- }};
436
- `;
437
- var IssueTag = styled.div`
438
- font-size: 11px;
439
- color: var(--seo-issue-color);
440
- line-height: 1.5;
441
- white-space: nowrap;
442
- overflow: hidden;
443
- text-overflow: ellipsis;
444
- `;
445
- var NonStringTitleWarning = styled.div`
446
- display: inline-flex;
447
- align-items: center;
448
- gap: 4px;
449
- margin-top: 4px;
450
- padding: 2px 7px;
451
- border-radius: 4px;
452
- background: var(--seo-warning-bg);
453
- border: 1px solid var(--seo-warning-border);
454
- font-size: 10px;
455
- font-weight: 600;
456
- color: var(--seo-warning-text);
457
- line-height: 1.4;
458
- cursor: default;
459
- white-space: normal;
460
- `;
461
- var MoreIssues = styled.div`
462
- font-size: 11px;
463
- color: var(--seo-more-issues);
464
- cursor: pointer;
465
- transition: color 0.15s;
466
-
467
- &:hover {
468
- color: var(--seo-more-issues-hover);
469
- }
470
- `;
471
- var MoreIssuesWrapper = styled.div`
472
- position: relative;
473
- display: inline-block;
474
- `;
475
- var IssuesPopover = styled.div`
476
- position: fixed;
477
- bottom: auto;
478
- left: 0;
479
- transform: translateY(calc(-100% - 14px));
480
- background: var(--seo-popover-bg);
481
- color: var(--seo-popover-text);
482
- padding: 12px;
483
- border-radius: 8px;
484
- font-size: 12px;
485
- z-index: 50;
486
- box-shadow: 0 10px 25px var(--seo-shadow-hover);
487
- width: 280px;
488
- word-break: break-word;
489
- line-height: 1.5;
490
-
491
- &::after {
492
- content: '';
493
- position: absolute;
494
- bottom: -6px;
495
- left: 12px;
496
- width: 0;
497
- height: 0;
498
- border-left: 6px solid transparent;
499
- border-right: 6px solid transparent;
500
- border-top: 6px solid var(--seo-popover-bg);
501
- }
502
- `;
503
- var PopoverIssueItem = styled.div`
504
- display: flex;
505
- gap: 6px;
506
- margin-bottom: 6px;
507
-
508
- &:last-child {
509
- margin-bottom: 0;
510
- }
511
- `;
512
- var UpgradeContainer = styled.div`
513
- display: flex;
514
- align-items: center;
515
- justify-content: center;
516
- min-height: 100%;
517
- padding: 60px 24px;
518
- `;
519
- var UpgradeBox = styled.div`
520
- background: var(--seo-upgrade-bg);
521
- border-radius: 16px;
522
- padding: 48px 40px;
523
- max-width: 480px;
524
- width: 100%;
525
- text-align: center;
526
- box-shadow:
527
- 0 4px 24px var(--seo-shadow),
528
- 0 1px 4px var(--seo-shadow);
529
- border: 1px solid var(--seo-upgrade-border);
530
- `;
531
- var UpgradeLock = styled.div`
532
- font-size: 40px;
533
- margin-bottom: 16px;
534
- `;
535
- var UpgradeTitle = styled.h2`
536
- margin: 0 0 10px;
537
- font-size: 20px;
538
- font-weight: 700;
539
- color: var(--seo-text-primary);
540
- `;
541
- var UpgradeText = styled.p`
542
- margin: 0 0 20px;
543
- font-size: 14px;
544
- color: var(--seo-text-secondary);
545
- line-height: 1.6;
546
- `;
547
- var UpgradeCode = styled.pre`
548
- background: var(--seo-upgrade-code-bg);
549
- border-radius: 8px;
550
- padding: 14px 16px;
551
- font-size: 12px;
552
- color: var(--seo-upgrade-code-text);
553
- text-align: left;
554
- margin: 0 0 24px;
555
- overflow-x: auto;
556
- line-height: 1.6;
557
- border: 1px solid var(--seo-upgrade-code-border);
558
- `;
559
- var UpgradeButton = styled.a`
560
- display: inline-block;
561
- background: var(--seo-accent);
562
- color: #ffffff;
563
- font-size: 14px;
564
- font-weight: 600;
565
- padding: 10px 24px;
566
- border-radius: 8px;
567
- text-decoration: none;
568
- transition: background 0.15s;
569
-
570
- &:hover {
571
- background: var(--seo-accent-hover);
572
- }
573
- `;
574
- var ReloadButton = styled.button`
575
- display: inline-block;
576
- background: transparent;
577
- color: var(--seo-text-secondary);
578
- font-size: 13px;
579
- font-weight: 500;
580
- padding: 8px 20px;
581
- border-radius: 8px;
582
- border: 1px solid var(--seo-btn-border);
583
- cursor: pointer;
584
- margin-top: 10px;
585
- transition:
586
- background 0.15s,
587
- color 0.15s,
588
- border-color 0.15s;
589
-
590
- &:hover {
591
- background: var(--seo-btn-hover-bg);
592
- color: var(--seo-text-primary);
593
- border-color: var(--seo-btn-hover-border);
594
- }
595
- `;
596
- var spin = keyframes`
597
- to { transform: rotate(360deg); }
598
- `;
599
- var DashboardRefreshButton = styled.button`
600
- display: inline-flex;
601
- align-items: center;
602
- gap: 6px;
603
- background: var(--seo-btn-bg);
604
- color: var(--seo-btn-text);
605
- font-size: 13px;
606
- font-weight: 500;
607
- padding: 8px 14px;
608
- border-radius: 8px;
609
- border: 1px solid var(--seo-btn-border);
610
- cursor: pointer;
611
- flex-shrink: 0;
612
- transition:
613
- background 0.15s,
614
- color 0.15s,
615
- border-color 0.15s,
616
- box-shadow 0.15s;
617
- box-shadow: 0 1px 2px var(--seo-shadow);
618
-
619
- svg {
620
- animation: ${(p) => p.$spinning ? css`
621
- ${spin} 0.7s linear infinite
622
- ` : "none"};
623
- }
624
-
625
- &:hover {
626
- background: var(--seo-btn-hover-bg);
627
- border-color: var(--seo-btn-hover-border);
628
- box-shadow: 0 2px 6px var(--seo-shadow);
629
- }
630
-
631
- &:disabled {
632
- opacity: 0.6;
633
- cursor: not-allowed;
634
- }
635
- `;
636
- var ThemeSwitcher = styled.div`
637
- display: inline-flex;
638
- align-items: center;
639
- gap: 3px;
640
- background: var(--seo-theme-picker-bg);
641
- border: 1px solid var(--seo-theme-picker-border);
642
- border-radius: 9px;
643
- padding: 3px;
644
- flex-shrink: 0;
645
- box-shadow: 0 1px 3px var(--seo-shadow);
646
- `;
647
- var getThemeButtonActiveStyles = (theme) => {
648
- switch (theme) {
649
- case "light":
650
- return css`
651
- background: #fff4ed;
652
- border: 1.5px solid #f97316;
653
- color: #ea6c0a;
654
- box-shadow:
655
- 0 0 0 2px rgba(249, 115, 22, 0.15),
656
- 0 1px 3px rgba(0, 0, 0, 0.08);
657
- `;
658
- case "dark":
659
- return css`
660
- background: #eff6ff;
661
- border: 1.5px solid #3b82f6;
662
- color: #2563eb;
663
- box-shadow:
664
- 0 0 0 2px rgba(59, 130, 246, 0.15),
665
- 0 1px 3px rgba(0, 0, 0, 0.08);
666
- `;
667
- case "system":
668
- return css`
669
- background: #f0fdf4;
670
- border: 1.5px solid #22c55e;
671
- color: #16a34a;
672
- box-shadow:
673
- 0 0 0 2px rgba(34, 197, 94, 0.15),
674
- 0 1px 3px rgba(0, 0, 0, 0.08);
675
- `;
676
- default:
677
- return css`
678
- background: #f0fdf4;
679
- border: 1.5px solid #22c55e;
680
- color: #16a34a;
681
- box-shadow:
682
- 0 0 0 2px rgba(34, 197, 94, 0.15),
683
- 0 1px 3px rgba(0, 0, 0, 0.08);
684
- `;
685
- }
686
- };
687
- var getThemeButtonHoverStyles = (theme) => {
688
- switch (theme) {
689
- case "light":
690
- return css`
691
- background: #fff4ed;
692
- border-color: rgba(249, 115, 22, 0.2);
693
- color: #ea6c0a;
694
- `;
695
- case "dark":
696
- return css`
697
- background: #eff6ff;
698
- border-color: rgba(59, 130, 246, 0.2);
699
- color: #2563eb;
700
- `;
701
- case "system":
702
- return css`
703
- background: #f0fdf4;
704
- border-color: rgba(34, 197, 94, 0.2);
705
- color: #16a34a;
706
- `;
707
- default:
708
- return css`
709
- background: #f0fdf4;
710
- border-color: rgba(34, 197, 94, 0.2);
711
- color: #16a34a;
712
- `;
713
- }
714
- };
715
- var ThemeButton = styled.button`
716
- display: inline-flex;
717
- align-items: center;
718
- justify-content: center;
719
- width: 32px;
720
- height: 28px;
721
- border-radius: 6px;
722
- position: relative;
723
- cursor: pointer;
724
- padding: 0;
725
- transition:
726
- background 0.18s,
727
- color 0.18s,
728
- border-color 0.18s,
729
- box-shadow 0.18s;
730
-
731
- /* Per-theme active colours */
732
- ${(p) => p.$active ? getThemeButtonActiveStyles(p.$theme) : css`
733
- background: transparent;
734
- border: 1.5px solid transparent;
735
- color: var(--seo-text-muted);
736
- `}
737
-
738
- &:hover {
739
- ${(p) => p.$active ? "" : getThemeButtonHoverStyles(p.$theme)}
740
- }
741
-
742
- svg {
743
- width: 14px;
744
- height: 14px;
745
- }
746
- `;
747
- var SunIcon = () => /* @__PURE__ */ jsxs(
748
- "svg",
749
- {
750
- viewBox: "0 0 24 24",
751
- fill: "none",
752
- stroke: "currentColor",
753
- strokeWidth: "2",
754
- strokeLinecap: "round",
755
- strokeLinejoin: "round",
756
- children: [
757
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "5" }),
758
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "1", x2: "12", y2: "3" }),
759
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "21", x2: "12", y2: "23" }),
760
- /* @__PURE__ */ jsx("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }),
761
- /* @__PURE__ */ jsx("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }),
762
- /* @__PURE__ */ jsx("line", { x1: "1", y1: "12", x2: "3", y2: "12" }),
763
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "23", y2: "12" }),
764
- /* @__PURE__ */ jsx("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }),
765
- /* @__PURE__ */ jsx("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })
766
- ]
767
- }
768
- );
769
- var MoonIcon = () => /* @__PURE__ */ jsx(
770
- "svg",
771
- {
772
- viewBox: "0 0 24 24",
773
- fill: "none",
774
- stroke: "currentColor",
775
- strokeWidth: "2",
776
- strokeLinecap: "round",
777
- strokeLinejoin: "round",
778
- children: /* @__PURE__ */ jsx("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
779
- }
780
- );
781
- var MonitorIcon = () => /* @__PURE__ */ jsxs(
782
- "svg",
783
- {
784
- viewBox: "0 0 24 24",
785
- fill: "none",
786
- stroke: "currentColor",
787
- strokeWidth: "2",
788
- strokeLinecap: "round",
789
- strokeLinejoin: "round",
790
- children: [
791
- /* @__PURE__ */ jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }),
792
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
793
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
794
- ]
795
- }
796
- );
797
- var DocTitleAnchor = ({
798
- id,
799
- type,
800
- structureTool,
801
- children
802
- }) => {
803
- const { basePath } = useWorkspace();
804
- const { onClick: intentOnClick, href: intentHref } = useIntentLink({
805
- intent: "edit",
806
- params: { id, type }
807
- });
808
- const href = structureTool ? `${basePath}/${structureTool}/intent/edit/id=${id};type=${type}/` : intentHref;
809
- const onClick = structureTool ? void 0 : intentOnClick;
810
- return /* @__PURE__ */ jsx(DocTitleLink, { href, onClick, title: "Open document", children });
811
- };
812
- var PaneLinkWrapper = styled.span`
813
- display: block;
814
- min-width: 0;
815
- overflow: hidden;
816
-
817
- a {
818
- font-size: 13px;
819
- font-weight: 600;
820
- color: var(--seo-link);
821
- white-space: nowrap;
822
- overflow: hidden;
823
- text-overflow: ellipsis;
824
- text-decoration: none;
825
- display: block;
826
- transition: color 0.15s;
827
-
828
- &:hover {
829
- color: var(--seo-link-hover);
830
- text-decoration: underline;
831
- }
832
- }
833
- `;
834
- var DocTitleAnchorPane = ({
835
- id,
836
- type,
837
- children
838
- }) => {
839
- const { ChildLink } = usePaneRouter();
840
- return /* @__PURE__ */ jsx(PaneLinkWrapper, { children: /* @__PURE__ */ jsx(ChildLink, { childId: id, childParameters: { type }, children }) });
841
- };
842
- var DocBadgeRenderer = ({
843
- doc,
844
- docBadge
845
- }) => {
846
- const badge = docBadge(doc);
847
- if (!badge) return null;
848
- return /* @__PURE__ */ jsx(CustomBadge, { $bgColor: badge.bgColor, $textColor: badge.textColor, $fontSize: badge.fontSize, children: badge.label });
849
- };
850
- var Spinner = styled.div`
851
- width: 28px;
852
- height: 28px;
853
- border: 3px solid var(--seo-spinner-track);
854
- border-top-color: var(--seo-spinner-fill);
855
- border-radius: 50%;
856
- animation: ${spin} 0.7s linear infinite;
857
- margin: 0 auto 12px;
858
- `;
859
- var LoadingState = styled.div`
860
- padding: 48px 24px;
861
- text-align: center;
862
- color: var(--seo-text-secondary);
863
- font-size: 13px;
864
- `;
865
- var EmptyState = styled.div`
866
- padding: 48px 24px;
867
- text-align: center;
868
- color: var(--seo-text-muted);
869
- font-size: 13px;
870
- `;
871
- var DeprecationBanner = styled.div`
872
- background: var(--seo-deprecation-bg);
873
- border: 1px solid var(--seo-deprecation-border);
874
- border-radius: 8px;
875
- padding: 10px 14px;
876
- font-size: 12px;
877
- color: var(--seo-deprecation-text);
878
- margin-bottom: 16px;
879
- line-height: 1.6;
880
- `;
881
- var DeprecationBannerLink = styled.a`
882
- color: var(--seo-deprecation-link);
883
- font-weight: 600;
884
- text-decoration: underline;
885
- &:hover {
886
- color: var(--seo-deprecation-text);
887
- }
888
- `;
889
- var ExportButton = styled.button`
890
- display: inline-flex;
891
- align-items: center;
892
- gap: 5px;
893
- background: var(--seo-btn-bg);
894
- color: var(--seo-btn-text);
895
- font-size: 12px;
896
- font-weight: 500;
897
- padding: 6px 11px;
898
- border-radius: 7px;
899
- border: 1px solid var(--seo-btn-border);
900
- cursor: pointer;
901
- flex-shrink: 0;
902
- transition:
903
- background 0.15s,
904
- color 0.15s,
905
- border-color 0.15s;
906
-
907
- &:hover {
908
- background: var(--seo-btn-hover-bg);
909
- border-color: var(--seo-btn-hover-border);
910
- }
911
- `;
912
- var PaginationBar = styled.div`
913
- display: flex;
914
- align-items: center;
915
- justify-content: space-between;
916
- flex-wrap: wrap;
917
- gap: 10px;
918
- background: var(--seo-card-bg);
919
- border-top: 1px solid var(--seo-border);
920
- padding: 10px 20px;
921
- font-size: 12px;
922
- color: var(--seo-text-secondary);
923
- `;
924
- var PaginationCenter = styled.div`
925
- display: flex;
926
- align-items: center;
927
- gap: 8px;
928
- `;
929
- var PaginationButton = styled.button`
930
- display: inline-flex;
931
- align-items: center;
932
- justify-content: center;
933
- width: 30px;
934
- height: 30px;
935
- border-radius: 6px;
936
- border: 1px solid var(--seo-border);
937
- background: var(--seo-btn-bg);
938
- color: var(--seo-btn-text);
939
- font-size: 13px;
940
- cursor: pointer;
941
- transition:
942
- background 0.15s,
943
- border-color 0.15s;
944
-
945
- &:disabled {
946
- opacity: 0.4;
947
- cursor: not-allowed;
948
- }
949
-
950
- &:not(:disabled):hover {
951
- background: var(--seo-btn-hover-bg);
952
- border-color: var(--seo-btn-hover-border);
953
- }
954
- `;
955
- var StatsRow = styled.div`
956
- display: flex;
957
- align-items: center;
958
- flex-wrap: wrap;
959
- gap: 6px;
960
- margin-bottom: 20px;
961
- `;
962
- var StatPill = styled.span`
963
- display: inline-flex;
964
- align-items: center;
965
- gap: 4px;
966
- padding: 8px 12px;
967
- border-radius: 10px;
968
- font-size: 12px;
969
- font-weight: 600;
970
- background: var(--seo-card-bg);
971
- border: 1px solid var(--seo-border);
972
- color: var(--seo-text-secondary);
973
- `;
974
- var TYPE_COLOR_PALETTE = [
975
- { bg: "#dbeafe", text: "#0c4a6e" },
976
- // Blue
977
- { bg: "#dcfce7", text: "#14532d" },
978
- // Green
979
- { bg: "#fce7f3", text: "#500724" },
980
- // Pink
981
- { bg: "#fed7aa", text: "#7c2d12" },
982
- // Orange
983
- { bg: "#e9d5ff", text: "#581c87" },
984
- // Purple
985
- { bg: "#f3e8ff", text: "#3f0f5c" },
986
- // Deep Purple
987
- { bg: "#ccfbf1", text: "#134e4a" },
988
- // Teal
989
- { bg: "#ddd6fe", text: "#3730a3" },
990
- // Indigo
991
- { bg: "#fca5a5", text: "#7f1d1d" },
992
- // Red
993
- { bg: "#a7f3d0", text: "#065f46" },
994
- // Emerald
995
- { bg: "#fbbf24", text: "#78350f" },
996
- // Amber
997
- { bg: "#c4b5fd", text: "#3b0764" },
998
- // Violet
999
- { bg: "#f0fdf4", text: "#15803d" },
1000
- // Light Green
1001
- { bg: "#fef2f2", text: "#991b1b" },
1002
- // Light Red
1003
- { bg: "#f5f3ff", text: "#5b21b6" },
1004
- // Light Purple
1005
- { bg: "#fffbeb", text: "#92400e" }
1006
- // Light Amber
1007
- ];
1008
- var getTypeColor = (type) => {
1009
- let hash = 0;
1010
- for (let i = 0; i < type.length; i += 1) {
1011
- const char = type.charCodeAt(i);
1012
- hash = Math.abs(hash * 31 + char);
1013
- }
1014
- const colorIndex = hash % TYPE_COLOR_PALETTE.length;
1015
- return TYPE_COLOR_PALETTE[colorIndex];
1016
- };
1017
- var getStatusCategory = (score) => {
1018
- if (score >= 80) return "excellent";
1019
- if (score >= 60) return "good";
1020
- if (score >= 40) return "fair";
1021
- if (score > 0) return "poor";
1022
- return "missing";
1023
- };
1024
- var RenderLicenseLoading = ({ text }) => /* @__PURE__ */ jsxs(LoadingState, { style: { padding: "80px 24px" }, children: [
1025
- /* @__PURE__ */ jsx(Spinner, {}),
1026
- text != null ? text : "Verifying license\u2026"
1027
- ] });
1028
- var RenderLicenseInvalid = ({ licenseKey, validateLicense }) => /* @__PURE__ */ jsx(UpgradeContainer, { children: /* @__PURE__ */ jsx(UpgradeBox, { children: licenseKey ? /* @__PURE__ */ jsxs(Fragment, { children: [
1029
- /* @__PURE__ */ jsx(UpgradeLock, { children: "\u274C" }),
1030
- /* @__PURE__ */ jsx(UpgradeTitle, { children: "Invalid License Key" }),
1031
- /* @__PURE__ */ jsx(UpgradeText, { children: "The license key you provided is invalid or has been revoked. Please check your key and update it in the plugin config." }),
1032
- /* @__PURE__ */ jsx(UpgradeCode, { children: `seofields({
1033
- healthDashboard: {
1034
- licenseKey: 'YOUR_LICENSE_KEY', // \u2190 replace with a valid key
1035
- },
1036
- })` }),
1037
- /* @__PURE__ */ jsx(
1038
- UpgradeButton,
1039
- {
1040
- href: "https://sanity-plugin-seofields.thehardik.in",
1041
- target: "_blank",
1042
- rel: "noopener noreferrer",
1043
- children: "Get a New License Key \u2192"
1044
- }
1045
- ),
1046
- /* @__PURE__ */ jsx("br", {}),
1047
- /* @__PURE__ */ jsx(ReloadButton, { onClick: () => validateLicense(true), children: "Click here If You Just Updated Your Key" })
1048
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1049
- /* @__PURE__ */ jsx(UpgradeLock, { children: "\u{1F512}" }),
1050
- /* @__PURE__ */ jsx(UpgradeTitle, { children: "SEO Health Dashboard" }),
1051
- /* @__PURE__ */ jsx(UpgradeText, { children: "This feature requires a license key. Add your key to the plugin config to unlock the full dashboard." }),
1052
- /* @__PURE__ */ jsx(UpgradeCode, { children: `// sanity.config.ts
1053
- import { seofields } from 'sanity-plugin-seofields'
1054
-
1055
- export default defineConfig({
1056
- plugins: [
1057
- seofields({
1058
- healthDashboard: {
1059
- licenseKey: 'SEOF-XXXX-XXXX-XXXX',
1060
- },
1061
- }),
1062
- ],
1063
- })` }),
1064
- /* @__PURE__ */ jsx(
1065
- UpgradeButton,
1066
- {
1067
- href: "https://sanity-plugin-seofields.thehardik.in",
1068
- target: "_blank",
1069
- rel: "noopener noreferrer",
1070
- children: "Get a License Key \u2192"
1071
- }
1072
- )
1073
- ] }) }) });
1074
- var LegacyBannerWrap = styled.div`
1075
- display: flex;
1076
- align-items: flex-start;
1077
- gap: 12px;
1078
- padding: 14px 20px;
1079
- margin-bottom: 20px;
1080
- background: #fffbeb;
1081
- border-bottom: 1px solid #fde68a;
1082
- color: #92400e;
1083
- font-size: 13px;
1084
- line-height: 1.5;
1085
- `;
1086
- var LegacyBannerLink = styled.a`
1087
- display: inline-block;
1088
- padding: 5px 14px;
1089
- background: #f59e0b;
1090
- color: #fff;
1091
- border-radius: 6px;
1092
- font-size: 12px;
1093
- font-weight: 600;
1094
- text-decoration: none;
1095
- &:hover {
1096
- background: #d97706;
1097
- }
1098
- `;
1099
- var ButtonWrapper = styled.div`
1100
- display: flex;
1101
- gap: 12px;
1102
- flex-wrap: wrap;
1103
- align-items: center;
1104
- margin-top: 6px;
1105
- `;
1106
- var VerifyButton = styled.button`
1107
- display: inline-block;
1108
- padding: 5px 14px;
1109
- background: #10b981;
1110
- color: #fff;
1111
- border-radius: 6px;
1112
- font-size: 12px;
1113
- font-weight: 600;
1114
- border: none;
1115
- cursor: pointer;
1116
- text-decoration: none;
1117
- &:hover {
1118
- background: #059669;
1119
- }
1120
- `;
1121
- var RenderLegacyBanner = ({ upgradeUrl, onVerifyUpgrade }) => {
1122
- return /* @__PURE__ */ jsxs(LegacyBannerWrap, { children: [
1123
- /* @__PURE__ */ jsx("span", { style: { fontSize: "18px", lineHeight: 1 }, children: "\u26A0\uFE0F" }),
1124
- /* @__PURE__ */ jsxs("div", { children: [
1125
- /* @__PURE__ */ jsx("strong", { children: "Legacy free access has ended \u2014 upgrades are no longer available" }),
1126
- /* @__PURE__ */ jsx("br", {}),
1127
- "Legacy free beta keys are no longer accepted. Please purchase a new license to use the SEO Health Dashboard.",
1128
- /* @__PURE__ */ jsx("br", {}),
1129
- /* @__PURE__ */ jsxs(ButtonWrapper, { children: [
1130
- /* @__PURE__ */ jsx(
1131
- LegacyBannerLink,
1132
- {
1133
- href: upgradeUrl != null ? upgradeUrl : "https://sanity-plugin-seofields.thehardik.in/get-license",
1134
- target: "_blank",
1135
- rel: "noopener noreferrer",
1136
- children: "Get a license \u2192"
1137
- }
1138
- ),
1139
- onVerifyUpgrade && /* @__PURE__ */ jsx(VerifyButton, { onClick: onVerifyUpgrade, children: "Already paid? Click here to verify your license \u2192" })
1140
- ] })
1141
- ] })
1142
- ] });
1143
- };
1144
- var scoreMetaTitle = (title) => {
1145
- const issues = [];
1146
- let score = 0;
1147
- if (title && title.length >= 50 && title.length <= 60) {
1148
- score = 15;
1149
- } else if (title && title.length > 0) {
1150
- score = 10;
1151
- if (title.length < 50) issues.push("Meta title too short (< 50 chars)");
1152
- if (title.length > 60) issues.push("Meta title too long (> 60 chars)");
1153
- } else {
1154
- issues.push("Missing meta title");
1155
- }
1156
- return { score, issues };
1157
- };
1158
- var scoreMetaDescription = (description) => {
1159
- const issues = [];
1160
- let score = 0;
1161
- if (description && description.length >= 120 && description.length <= 160) {
1162
- score = 15;
1163
- } else if (description && description.length > 0) {
1164
- score = 10;
1165
- if (description.length < 120) issues.push("Meta description too short (< 120 chars)");
1166
- if (description.length > 160) issues.push("Meta description too long (> 160 chars)");
1167
- } else {
1168
- issues.push("Missing meta description");
1169
- }
1170
- return { score, issues };
1171
- };
1172
- var scoreOpenGraph = (openGraph) => {
1173
- const issues = [];
1174
- let score = 0;
1175
- if (openGraph) {
1176
- if (openGraph.title) score += 6;
1177
- else issues.push("Missing OG title");
1178
- if (openGraph.description) score += 6;
1179
- else issues.push("Missing OG description");
1180
- if (openGraph.image) score += 6;
1181
- else issues.push("Missing OG image");
1182
- if (openGraph.type) score += 7;
1183
- else issues.push("Missing OG type");
1184
- } else {
1185
- issues.push("Open Graph not configured");
1186
- }
1187
- return { score, issues };
1188
- };
1189
- var scoreTwitterCard = (twitter) => {
1190
- const issues = [];
1191
- let score = 0;
1192
- if (twitter) {
1193
- if (twitter.title) score += 5;
1194
- else issues.push("Missing Twitter title");
1195
- if (twitter.description) score += 5;
1196
- else issues.push("Missing Twitter description");
1197
- if (twitter.image) score += 5;
1198
- else issues.push("Missing Twitter image");
1199
- } else {
1200
- issues.push("Twitter Card not configured");
1201
- }
1202
- return { score, issues };
1203
- };
1204
- var calculateHealthScore = (doc) => {
1205
- if (!doc.seo) {
1206
- return { score: 0, status: "missing", issues: ["SEO fields not configured"] };
1207
- }
1208
- const { title, description, keywords, robots, canonicalUrl, openGraph, twitter } = doc.seo;
1209
- let score = 0;
1210
- const issues = [];
1211
- const titleResult = scoreMetaTitle(title);
1212
- score += titleResult.score;
1213
- issues.push(...titleResult.issues);
1214
- const descResult = scoreMetaDescription(description);
1215
- score += descResult.score;
1216
- issues.push(...descResult.issues);
1217
- if (doc.seo.metaImage) score += 10;
1218
- else issues.push("Missing meta image");
1219
- if (keywords && keywords.length > 0) score += 10;
1220
- else issues.push("No keywords defined");
1221
- if (robots && !robots.noIndex) score += 5;
1222
- else if (!robots) score += 5;
1223
- if (canonicalUrl) score += 0;
1224
- const ogResult = scoreOpenGraph(openGraph);
1225
- score += ogResult.score;
1226
- issues.push(...ogResult.issues);
1227
- const twResult = scoreTwitterCard(twitter);
1228
- score += twResult.score;
1229
- issues.push(...twResult.issues);
1230
- const hasMetaImage = !!doc.seo.metaImage;
1231
- const hasOgImage = !!(openGraph && openGraph.image);
1232
- const hasTwitterImage = !!(twitter && twitter.image);
1233
- if (hasMetaImage && hasOgImage && hasTwitterImage) {
1234
- score += 5;
1235
- } else {
1236
- const missingImages = [];
1237
- if (!hasMetaImage) missingImages.push("meta image");
1238
- if (!hasOgImage) missingImages.push("OG image");
1239
- if (!hasTwitterImage) missingImages.push("Twitter image");
1240
- issues.push(`Missing images for full score: ${missingImages.join(", ")}`);
1241
- }
1242
- const status = getStatusCategory(score);
1243
- return { score, status, issues };
1244
- };
1245
- var resolveTypeLabel = (type, typeLabels) => {
1246
- var _a;
1247
- return (_a = typeLabels == null ? void 0 : typeLabels[type]) != null ? _a : type;
1248
- };
1249
- var buildTitleProjection = (titleField) => {
1250
- if (!titleField || titleField === "title") return "title";
1251
- if (typeof titleField === "string") return `"title": ${titleField}`;
1252
- const cases = Object.entries(titleField).map(([type, field]) => `_type == "${type}" => ${field}`).join(", ");
1253
- return `"title": select(${cases}, title)`;
1254
- };
1255
- var generateDummyData = () => {
1256
- const dummyDocs = [
1257
- {
1258
- _id: "preview-post-1",
1259
- _type: "post",
1260
- title: "Getting Started with SEO Best Practices",
1261
- slug: { current: "getting-started-seo" },
1262
- _updatedAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1e3).toISOString(),
1263
- seo: {
1264
- title: "Getting Started with SEO Best Practices | My Blog",
1265
- description: "Learn the fundamentals of SEO optimization to improve your website visibility and search rankings.",
1266
- keywords: ["seo", "best practices", "optimization"],
1267
- metaImage: { _type: "image", asset: { _ref: "image-123", _type: "reference" } },
1268
- openGraph: {
1269
- title: "SEO Best Practices Guide",
1270
- description: "Master SEO optimization",
1271
- image: { _type: "image", asset: { _ref: "image-123", _type: "reference" }, alt: "SEO Guide" },
1272
- type: "article"
1273
- },
1274
- twitter: {
1275
- title: "SEO Best Practices",
1276
- description: "Learn SEO optimization",
1277
- image: { _type: "image", asset: { _ref: "image-123", _type: "reference" }, alt: "Guide" },
1278
- card: "summary_large_image"
1279
- }
1280
- }
1281
- },
1282
- {
1283
- _id: "preview-post-2",
1284
- _type: "post",
1285
- title: "Advanced Analytics Strategy",
1286
- slug: { current: "advanced-analytics" },
1287
- _updatedAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1e3).toISOString(),
1288
- seo: {
1289
- title: "Advanced Analytics",
1290
- description: "Strategy tips",
1291
- keywords: ["analytics", "data"],
1292
- openGraph: {
1293
- title: "Analytics Guide"
1294
- }
1295
- }
1296
- },
1297
- {
1298
- _id: "preview-page-1",
1299
- _type: "page",
1300
- title: "About Us",
1301
- slug: { current: "about" },
1302
- _updatedAt: new Date(Date.now() - 10 * 24 * 60 * 60 * 1e3).toISOString(),
1303
- seo: {
1304
- title: "About",
1305
- keywords: ["company", "team"],
1306
- metaImage: { _type: "image", asset: { _ref: "image-456", _type: "reference" } }
1307
- }
1308
- },
1309
- {
1310
- _id: "preview-post-3",
1311
- _type: "post",
1312
- title: "Content Marketing Trends for 2024",
1313
- slug: { current: "content-marketing-trends" },
1314
- _updatedAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1e3).toISOString(),
1315
- seo: {
1316
- title: "Content Marketing Trends 2024",
1317
- description: "Discover the latest content marketing trends and strategies to engage your audience effectively.",
1318
- keywords: ["content marketing", "trends", "strategy", "engagement"],
1319
- metaImage: { _type: "image", asset: { _ref: "image-789", _type: "reference" } },
1320
- openGraph: {
1321
- title: "Content Marketing Trends 2024",
1322
- description: "Latest trends in content marketing",
1323
- image: { _type: "image", asset: { _ref: "image-789", _type: "reference" }, alt: "Trends" },
1324
- type: "article"
1325
- },
1326
- twitter: {
1327
- title: "Content Marketing Trends",
1328
- description: "Discover the latest trends",
1329
- card: "summary"
1330
- }
1331
- }
1332
- },
1333
- {
1334
- _id: "preview-post-4",
1335
- _type: "product",
1336
- title: "Pro Plan",
1337
- slug: { current: "pro-plan" },
1338
- _updatedAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1e3).toISOString(),
1339
- seo: {
1340
- title: "Pro",
1341
- keywords: ["pricing"]
1342
- }
1343
- },
1344
- {
1345
- _id: "preview-page-2",
1346
- _type: "page",
1347
- title: "Contact",
1348
- slug: { current: "contact" },
1349
- _updatedAt: new Date(Date.now() - 8 * 24 * 60 * 60 * 1e3).toISOString(),
1350
- seo: {
1351
- openGraph: {
1352
- title: "Get in Touch"
1353
- }
1354
- }
1355
- },
1356
- {
1357
- _id: "preview-post-5",
1358
- _type: "post",
1359
- title: "Mobile Optimization Guide",
1360
- slug: { current: "mobile-optimization" },
1361
- _updatedAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1e3).toISOString(),
1362
- seo: {
1363
- title: "Mobile Optimization Guide: Best Practices for Responsive Design",
1364
- description: "Complete guide to mobile optimization including responsive design, performance tips, and user experience best practices for modern web development.",
1365
- keywords: ["mobile", "optimization", "responsive", "performance"],
1366
- metaImage: { _type: "image", asset: { _ref: "image-mobile", _type: "reference" } },
1367
- openGraph: {
1368
- title: "Mobile Optimization Best Practices",
1369
- description: "Master mobile web optimization",
1370
- image: { _type: "image", asset: { _ref: "image-mobile", _type: "reference" }, alt: "Mobile" },
1371
- type: "article"
1372
- },
1373
- twitter: {
1374
- title: "Mobile Optimization Tips",
1375
- description: "Responsive design best practices",
1376
- image: { _type: "image", asset: { _ref: "image-mobile", _type: "reference" }, alt: "Mobile" },
1377
- card: "summary_large_image"
1378
- }
1379
- }
1380
- }
1381
- ];
1382
- return dummyDocs.map((doc) => __spreadProps(__spreadValues({}, doc), {
1383
- health: calculateHealthScore(doc)
1384
- }));
1385
- };
1386
- var VALIDATION_ENDPOINT = "https://sanity-plugin-seofields.thehardik.in/api/validate-license";
1387
- var CACHE_TTL_MS = 60 * 60 * 1e3;
1388
- var SeoHealthDashboard = ({
1389
- icon = "\u{1F4CA}",
1390
- title = "SEO Health Dashboard",
1391
- description = "Monitor and optimize SEO fields across all your documents",
1392
- showTypeColumn = true,
1393
- showDocumentId = true,
1394
- queryTypes,
1395
- queryRequireSeo = true,
1396
- customQuery,
1397
- apiVersion = "2023-01-01",
1398
- licenseKey,
1399
- typeDisplayLabels,
1400
- typeColumnMode = "badge",
1401
- titleField,
1402
- getDocumentBadge,
1403
- loadingLicense,
1404
- loadingDocuments,
1405
- noDocuments,
1406
- previewMode = false,
1407
- openInPane = false,
1408
- structureTool,
1409
- _deprecationWarnings,
1410
- exportEnabled = true,
1411
- exportFormats = ["csv", "json"],
1412
- compactStats = false
1413
- }) => {
1414
- const resolvedTypeLabels = typeDisplayLabels;
1415
- const resolvedDocBadge = getDocumentBadge;
1416
- const allDeprecationWarnings = useMemo(() => _deprecationWarnings != null ? _deprecationWarnings : [], [_deprecationWarnings]);
1417
- const deprecationGroups = useMemo(() => {
1418
- const groups = /* @__PURE__ */ new Map();
1419
- for (const w of allDeprecationWarnings) {
1420
- if (!groups.has(w.version)) {
1421
- groups.set(w.version, { version: w.version, changelogUrl: w.changelogUrl, keys: [] });
1422
- }
1423
- groups.get(w.version).keys.push(w.key);
1424
- }
1425
- return Array.from(groups.values());
1426
- }, [allDeprecationWarnings]);
1427
- const client = useClient({ apiVersion });
1428
- const [licenseStatus, setLicenseStatus] = useState(
1429
- "loading"
1430
- );
1431
- const [legacyInfo, setLegacyInfo] = useState({});
1432
- const [documents, setDocuments] = useState([]);
1433
- const [loading, setLoading] = useState(true);
1434
- const [isRefreshing, setIsRefreshing] = useState(false);
1435
- const [searchQuery, setSearchQuery] = useState("");
1436
- const [filterStatus, setFilterStatus] = useState(() => {
1437
- var _a;
1438
- try {
1439
- return (_a = localStorage.getItem("seo-dashboard-filter-status")) != null ? _a : "all";
1440
- } catch (e) {
1441
- return "all";
1442
- }
1443
- });
1444
- const [filterType, setFilterType] = useState(() => {
1445
- var _a;
1446
- try {
1447
- return (_a = localStorage.getItem("seo-dashboard-filter-type")) != null ? _a : "all";
1448
- } catch (e) {
1449
- return "all";
1450
- }
1451
- });
1452
- const [sortBy, setSortBy] = useState("score");
1453
- const [currentPage, setCurrentPage] = useState(1);
1454
- const [pageSize, setPageSize] = useState(() => {
1455
- try {
1456
- const stored = localStorage.getItem("seo-dashboard-page-size");
1457
- return stored ? Number(stored) : 25;
1458
- } catch (e) {
1459
- return 25;
1460
- }
1461
- });
1462
- const searchInputRef = useRef(null);
1463
- const [activePopover, setActivePopover] = useState(null);
1464
- const [themeMode, setThemeMode] = useState(() => {
1465
- try {
1466
- const saved = localStorage.getItem("seo-dashboard-theme");
1467
- if (saved === "light" || saved === "dark" || saved === "system") return saved;
1468
- } catch (e) {
1469
- }
1470
- return "system";
1471
- });
1472
- const [systemPrefersDark, setSystemPrefersDark] = useState(
1473
- () => {
1474
- var _a;
1475
- return typeof window !== "undefined" && ((_a = window.matchMedia) == null ? void 0 : _a.call(window, "(prefers-color-scheme: dark)").matches);
1476
- }
1477
- );
1478
- useEffect(() => {
1479
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
1480
- const handler = (e) => setSystemPrefersDark(e.matches);
1481
- mq.addEventListener("change", handler);
1482
- return () => mq.removeEventListener("change", handler);
1483
- }, []);
1484
- const resolvedTheme = (() => {
1485
- if (themeMode === "system") {
1486
- return systemPrefersDark ? "dark" : "light";
1487
- }
1488
- return themeMode;
1489
- })();
1490
- const currentVars = themeVars[resolvedTheme];
1491
- const handleThemeChange = useCallback((mode) => {
1492
- setThemeMode(mode);
1493
- try {
1494
- localStorage.setItem("seo-dashboard-theme", mode);
1495
- } catch (e) {
1496
- }
1497
- }, []);
1498
- const handleThemeChangeLight = useCallback(() => handleThemeChange("light"), [handleThemeChange]);
1499
- const handleThemeChangeDark = useCallback(() => handleThemeChange("dark"), [handleThemeChange]);
1500
- const handleThemeChangeSystem = useCallback(
1501
- () => handleThemeChange("system"),
1502
- [handleThemeChange]
1503
- );
1504
- const handleFilterStatusChange = useCallback((value) => {
1505
- setFilterStatus(value);
1506
- try {
1507
- localStorage.setItem("seo-dashboard-filter-status", value);
1508
- } catch (e) {
1509
- }
1510
- setCurrentPage(1);
1511
- }, []);
1512
- const handleFilterTypeChange = useCallback((value) => {
1513
- setFilterType(value);
1514
- try {
1515
- localStorage.setItem("seo-dashboard-filter-type", value);
1516
- } catch (e) {
1517
- }
1518
- setCurrentPage(1);
1519
- }, []);
1520
- const applyLicenseState = useCallback(
1521
- ({ valid, legacy = false, upgradeUrl, cutoffDate }) => {
1522
- if (legacy) {
1523
- setLegacyInfo({ upgradeUrl, cutoffDate });
1524
- setLicenseStatus("legacy");
1525
- return;
1526
- }
1527
- setLegacyInfo({});
1528
- setLicenseStatus(valid ? "valid" : "invalid");
1529
- },
1530
- []
1531
- );
1532
- const readCachedLicenseState = useCallback((cacheKey) => {
1533
- try {
1534
- const cached = sessionStorage.getItem(cacheKey);
1535
- if (!cached) return null;
1536
- const parsed = JSON.parse(cached);
1537
- return Date.now() - parsed.ts < CACHE_TTL_MS ? parsed : null;
1538
- } catch (e) {
1539
- return null;
1540
- }
1541
- }, []);
1542
- const validateLicense = useCallback(
1543
- async (forceRefresh = false) => {
1544
- var _a, _b;
1545
- if (previewMode) {
1546
- setLicenseStatus("valid");
1547
- return;
1548
- }
1549
- if (!licenseKey) {
1550
- setLicenseStatus("invalid");
1551
- return;
1552
- }
1553
- const projectId = (_a = client.config().projectId) != null ? _a : "";
1554
- const cacheKey = `seofields_license_${projectId}`;
1555
- if (forceRefresh) {
1556
- try {
1557
- sessionStorage.removeItem(cacheKey);
1558
- } catch (e) {
1559
- }
1560
- }
1561
- if (!forceRefresh) {
1562
- const cachedLicenseState = readCachedLicenseState(cacheKey);
1563
- if (cachedLicenseState) {
1564
- applyLicenseState(cachedLicenseState);
1565
- return;
1566
- }
1567
- }
1568
- setLicenseStatus("loading");
1569
- try {
1570
- const res = await fetch(VALIDATION_ENDPOINT, {
1571
- method: "POST",
1572
- headers: { "Content-Type": "application/json" },
1573
- body: JSON.stringify({ licenseKey, projectId })
1574
- });
1575
- const data = await res.json().catch(() => ({}));
1576
- const valid = res.ok;
1577
- const legacy = data.legacy === true;
1578
- applyLicenseState({ valid, legacy, upgradeUrl: data.upgradeUrl, cutoffDate: data.cutoffDate });
1579
- try {
1580
- sessionStorage.setItem(
1581
- cacheKey,
1582
- JSON.stringify({
1583
- valid,
1584
- legacy,
1585
- upgradeUrl: data.upgradeUrl,
1586
- cutoffDate: data.cutoffDate,
1587
- ts: Date.now()
1588
- })
1589
- );
1590
- } catch (e) {
1591
- }
1592
- } catch (e) {
1593
- const fallback = readCachedLicenseState(`seofields_license_${(_b = client.config().projectId) != null ? _b : ""}`);
1594
- if (fallback == null ? void 0 : fallback.valid) {
1595
- applyLicenseState(fallback);
1596
- } else {
1597
- setLicenseStatus("invalid");
1598
- }
1599
- }
1600
- },
1601
- // eslint-disable-next-line react-hooks/exhaustive-deps
1602
- [applyLicenseState, licenseKey, previewMode, readCachedLicenseState]
1603
- );
1604
- const handleVerifyUpgrade = useCallback(() => {
1605
- validateLicense(true);
1606
- }, [validateLicense]);
1607
- useEffect(() => {
1608
- validateLicense();
1609
- }, [licenseKey, previewMode]);
1610
- const handleMouseEnterIssues = (el, issues) => {
1611
- if (!el) return;
1612
- const rect = el.getBoundingClientRect();
1613
- const popoverWidth = 280;
1614
- const viewportWidth = window.innerWidth;
1615
- let left = rect.left;
1616
- if (left + popoverWidth > viewportWidth - 10) left = viewportWidth - popoverWidth - 10;
1617
- if (left < 10) left = 10;
1618
- setActivePopover({ top: rect.top, left, issues });
1619
- };
1620
- const JSONStringifiedQueryTypes = JSON.stringify(queryTypes);
1621
- const JSONStringifiedTitleField = JSON.stringify(titleField);
1622
- const fetchDocuments = useCallback(
1623
- async (isManualRefresh = false) => {
1624
- var _a, _b, _c;
1625
- try {
1626
- if (isManualRefresh) {
1627
- setIsRefreshing(true);
1628
- } else {
1629
- setLoading(true);
1630
- }
1631
- if (previewMode) {
1632
- setDocuments(generateDummyData());
1633
- return;
1634
- }
1635
- let groqQuery;
1636
- let params = {};
1637
- if (customQuery) {
1638
- groqQuery = customQuery;
1639
- } else if (queryTypes && queryTypes.length > 0) {
1640
- const seoFilter = queryRequireSeo ? " && seo != null" : "";
1641
- const titleProj = buildTitleProjection(titleField);
1642
- groqQuery = `*[_type in $types${seoFilter} && !(_id in path("drafts.**"))]{
1643
- _id,
1644
- _type,
1645
- ${titleProj},
1646
- slug,
1647
- seo,
1648
- _updatedAt
1649
- }`;
1650
- params = { types: queryTypes };
1651
- } else {
1652
- const titleProj = buildTitleProjection(titleField);
1653
- groqQuery = `*[seo != null && !(_id in path("drafts.**"))]{
1654
- _id,
1655
- _type,
1656
- ${titleProj},
1657
- slug,
1658
- seo,
1659
- _updatedAt
1660
- }`;
1661
- }
1662
- const result = await client.fetch(groqQuery, params, { perspective: "published" });
1663
- const docsWithHealth = result.map((doc) => __spreadProps(__spreadValues({}, doc), {
1664
- health: calculateHealthScore(doc)
1665
- }));
1666
- const titleCount = /* @__PURE__ */ new Map();
1667
- for (const doc of docsWithHealth) {
1668
- const t = (_b = (_a = doc.seo) == null ? void 0 : _a.title) == null ? void 0 : _b.trim();
1669
- if (t) titleCount.set(t, ((_c = titleCount.get(t)) != null ? _c : 0) + 1);
1670
- }
1671
- const duplicateTitles = /* @__PURE__ */ new Set();
1672
- titleCount.forEach((count, t) => {
1673
- if (count > 1) duplicateTitles.add(t);
1674
- });
1675
- const finalDocs = docsWithHealth.map((doc) => {
1676
- var _a2, _b2;
1677
- const t = (_b2 = (_a2 = doc.seo) == null ? void 0 : _a2.title) == null ? void 0 : _b2.trim();
1678
- if (!t || !duplicateTitles.has(t)) return doc;
1679
- const penalizedScore = Math.max(0, doc.health.score - 10);
1680
- return __spreadProps(__spreadValues({}, doc), {
1681
- health: __spreadProps(__spreadValues({}, doc.health), {
1682
- score: penalizedScore,
1683
- status: getStatusCategory(penalizedScore),
1684
- issues: ["Duplicate meta title \u2014 used by multiple documents", ...doc.health.issues]
1685
- })
1686
- });
1687
- });
1688
- setDocuments(finalDocs);
1689
- } catch (error) {
1690
- console.error("Error fetching documents:", error);
1691
- } finally {
1692
- setLoading(false);
1693
- setIsRefreshing(false);
1694
- }
1695
- },
1696
- // eslint-disable-next-line react-hooks/exhaustive-deps
1697
- [
1698
- client,
1699
- customQuery,
1700
- queryRequireSeo,
1701
- JSONStringifiedQueryTypes,
1702
- JSONStringifiedTitleField,
1703
- previewMode
1704
- ]
1705
- );
1706
- useEffect(() => {
1707
- fetchDocuments();
1708
- }, [
1709
- client,
1710
- customQuery,
1711
- queryRequireSeo,
1712
- JSONStringifiedQueryTypes,
1713
- JSONStringifiedTitleField,
1714
- previewMode
1715
- ]);
1716
- const handleRefresh = useCallback(() => {
1717
- fetchDocuments(true);
1718
- }, [fetchDocuments]);
1719
- const uniqueDocumentTypes = useMemo(() => {
1720
- const types = new Set(documents.map((doc) => doc._type));
1721
- return Array.from(types).sort();
1722
- }, [documents]);
1723
- const filteredAndSortedDocs = useMemo(() => {
1724
- let filtered = documents;
1725
- if (searchQuery) {
1726
- filtered = filtered.filter(
1727
- (doc) => {
1728
- var _a, _b;
1729
- return ((_a = doc.title) == null ? void 0 : _a.toLowerCase().includes(searchQuery.toLowerCase())) || ((_b = doc._id) == null ? void 0 : _b.toLowerCase().includes(searchQuery.toLowerCase()));
1730
- }
1731
- );
1732
- }
1733
- if (filterStatus !== "all") {
1734
- filtered = filtered.filter((doc) => doc.health.status === filterStatus);
1735
- }
1736
- if (filterType !== "all") {
1737
- filtered = filtered.filter((doc) => doc._type === filterType);
1738
- }
1739
- const sorted = [...filtered].sort((a, b) => {
1740
- if (sortBy === "score") {
1741
- return b.health.score - a.health.score;
1742
- }
1743
- return (a.title || "").localeCompare(b.title || "");
1744
- });
1745
- return sorted;
1746
- }, [documents, searchQuery, filterStatus, filterType, sortBy]);
1747
- const totalPages = Math.max(1, Math.ceil(filteredAndSortedDocs.length / pageSize));
1748
- const paginatedDocs = useMemo(() => {
1749
- const start = (currentPage - 1) * pageSize;
1750
- return filteredAndSortedDocs.slice(start, start + pageSize);
1751
- }, [filteredAndSortedDocs, currentPage, pageSize]);
1752
- const handleExportCSV = useCallback(() => {
1753
- const exportDocs = filteredAndSortedDocs;
1754
- const rows = exportDocs.map((doc) => ({
1755
- id: doc._id,
1756
- type: doc._type,
1757
- title: typeof doc.title === "string" ? doc.title : "",
1758
- score: doc.health.score,
1759
- status: doc.health.status,
1760
- issues: doc.health.issues.join(" | ")
1761
- }));
1762
- const header = "id,type,title,score,status,issues";
1763
- const csvRows = rows.map(
1764
- (r) => [
1765
- r.id,
1766
- r.type,
1767
- `"${r.title.replace(/"/g, '""')}"`,
1768
- r.score,
1769
- r.status,
1770
- `"${r.issues.replace(/"/g, '""')}"`
1771
- ].join(",")
1772
- );
1773
- const csv = [header, ...csvRows].join("\n");
1774
- const blob = new Blob([csv], { type: "text/csv" });
1775
- const url = URL.createObjectURL(blob);
1776
- const a = document.createElement("a");
1777
- a.href = url;
1778
- a.download = "seo-health-export.csv";
1779
- a.click();
1780
- URL.revokeObjectURL(url);
1781
- }, [filteredAndSortedDocs]);
1782
- const handleExportJSON = useCallback(() => {
1783
- const exportDocs = filteredAndSortedDocs;
1784
- const blob = new Blob([JSON.stringify(exportDocs, null, 2)], {
1785
- type: "application/json"
1786
- });
1787
- const url = URL.createObjectURL(blob);
1788
- const a = document.createElement("a");
1789
- a.href = url;
1790
- a.download = "seo-health-export.json";
1791
- a.click();
1792
- URL.revokeObjectURL(url);
1793
- }, [filteredAndSortedDocs]);
1794
- const stats = useMemo(() => {
1795
- const total = documents.length;
1796
- const excellent = documents.filter((d) => d.health.score >= 80).length;
1797
- const good = documents.filter((d) => d.health.score >= 60 && d.health.score < 80).length;
1798
- const fair = documents.filter((d) => d.health.score >= 40 && d.health.score < 60).length;
1799
- const poor = documents.filter((d) => d.health.score > 0 && d.health.score < 40).length;
1800
- const missing = documents.filter((d) => d.health.score === 0).length;
1801
- const avgScore = total > 0 ? Math.round(documents.reduce((sum, d) => sum + d.health.score, 0) / total) : 0;
1802
- return { total, excellent, good, fair, poor, missing, avgScore };
1803
- }, [documents]);
1804
- const handleMouseLeave = useCallback(() => {
1805
- setActivePopover(null);
1806
- }, []);
1807
- useEffect(() => {
1808
- setCurrentPage(1);
1809
- }, [searchQuery, filterStatus, filterType, sortBy]);
1810
- useEffect(() => {
1811
- const onKeyDown = (e) => {
1812
- var _a;
1813
- const target = e.target;
1814
- const isEditable = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
1815
- if (e.key === "/" && !isEditable) {
1816
- e.preventDefault();
1817
- (_a = searchInputRef.current) == null ? void 0 : _a.focus();
1818
- }
1819
- };
1820
- window.addEventListener("keydown", onKeyDown);
1821
- return () => window.removeEventListener("keydown", onKeyDown);
1822
- }, []);
1823
- const renderDashboardContent = () => /* @__PURE__ */ jsxs(Fragment, { children: [
1824
- /* @__PURE__ */ jsxs(PageHeader, { children: [
1825
- /* @__PURE__ */ jsxs("div", { children: [
1826
- /* @__PURE__ */ jsxs(PageTitle, { children: [
1827
- /* @__PURE__ */ jsxs("span", { children: [
1828
- icon,
1829
- " ",
1830
- title
1831
- ] }),
1832
- previewMode && /* @__PURE__ */ jsx(PreviewBadge, { children: "Preview Mode" })
1833
- ] }),
1834
- /* @__PURE__ */ jsx(PageSubtitle, { children: description })
1835
- ] }),
1836
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px", flexShrink: 0 }, children: [
1837
- /* @__PURE__ */ jsxs(ThemeSwitcher, { children: [
1838
- /* @__PURE__ */ jsx(
1839
- ThemeButton,
1840
- {
1841
- $theme: "light",
1842
- $active: themeMode === "light",
1843
- onClick: handleThemeChangeLight,
1844
- title: "Light theme",
1845
- children: /* @__PURE__ */ jsx(SunIcon, {})
1846
- }
1847
- ),
1848
- /* @__PURE__ */ jsx(
1849
- ThemeButton,
1850
- {
1851
- $theme: "dark",
1852
- $active: themeMode === "dark",
1853
- onClick: handleThemeChangeDark,
1854
- title: "Dark theme",
1855
- children: /* @__PURE__ */ jsx(MoonIcon, {})
1856
- }
1857
- ),
1858
- /* @__PURE__ */ jsx(
1859
- ThemeButton,
1860
- {
1861
- $theme: "system",
1862
- $active: themeMode === "system",
1863
- onClick: handleThemeChangeSystem,
1864
- title: "System default",
1865
- children: /* @__PURE__ */ jsx(MonitorIcon, {})
1866
- }
1867
- )
1868
- ] }),
1869
- /* @__PURE__ */ jsxs(
1870
- DashboardRefreshButton,
1871
- {
1872
- onClick: handleRefresh,
1873
- disabled: loading || isRefreshing,
1874
- $spinning: isRefreshing,
1875
- title: "Refresh documents",
1876
- children: [
1877
- /* @__PURE__ */ jsxs(
1878
- "svg",
1879
- {
1880
- width: "14",
1881
- height: "14",
1882
- viewBox: "0 0 24 24",
1883
- fill: "none",
1884
- stroke: "currentColor",
1885
- strokeWidth: "2.2",
1886
- strokeLinecap: "round",
1887
- strokeLinejoin: "round",
1888
- children: [
1889
- /* @__PURE__ */ jsx("polyline", { points: "23 4 23 10 17 10" }),
1890
- /* @__PURE__ */ jsx("polyline", { points: "1 20 1 14 7 14" }),
1891
- /* @__PURE__ */ jsx("path", { d: "M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" })
1892
- ]
1893
- }
1894
- ),
1895
- "Refresh"
1896
- ]
1897
- }
1898
- )
1899
- ] })
1900
- ] }),
1901
- deprecationGroups.length > 0 && /* @__PURE__ */ jsxs(DeprecationBanner, { children: [
1902
- /* @__PURE__ */ jsx("strong", { children: "\u26A0\uFE0F Deprecated config keys detected:" }),
1903
- " ",
1904
- deprecationGroups.map((group, gi) => /* @__PURE__ */ jsxs("span", { children: [
1905
- group.keys.map((w, i) => /* @__PURE__ */ jsxs("span", { children: [
1906
- /* @__PURE__ */ jsx("code", { style: { background: "#fef9c3", padding: "1px 4px", borderRadius: 3 }, children: w.split("\u2192")[0].trim() }),
1907
- " \u2192 ",
1908
- /* @__PURE__ */ jsx("code", { style: { background: "#dcfce7", padding: "1px 4px", borderRadius: 3 }, children: w.split("\u2192")[1].trim() }),
1909
- i < group.keys.length - 1 ? " \xB7 " : ""
1910
- ] }, w)),
1911
- " ",
1912
- "(",
1913
- /* @__PURE__ */ jsxs(
1914
- DeprecationBannerLink,
1915
- {
1916
- href: group.changelogUrl,
1917
- target: "_blank",
1918
- rel: "noopener noreferrer",
1919
- children: [
1920
- group.version,
1921
- " changelog"
1922
- ]
1923
- }
1924
- ),
1925
- ")",
1926
- gi < deprecationGroups.length - 1 ? " \xB7 " : ""
1927
- ] }, group.version)),
1928
- " ",
1929
- "\u2014 Please update your config."
1930
- ] }),
1931
- !loading && compactStats && /* @__PURE__ */ jsxs(StatsRow, { children: [
1932
- /* @__PURE__ */ jsxs(StatPill, { children: [
1933
- "\u{1F4CB} ",
1934
- stats.total
1935
- ] }),
1936
- /* @__PURE__ */ jsxs(StatPill, { children: [
1937
- "\u{1F7E2} Excellent: ",
1938
- stats.excellent
1939
- ] }),
1940
- /* @__PURE__ */ jsxs(StatPill, { children: [
1941
- "\u{1F7E1} Good: ",
1942
- stats.good
1943
- ] }),
1944
- /* @__PURE__ */ jsxs(StatPill, { children: [
1945
- "\u{1F7E0} Fair: ",
1946
- stats.fair
1947
- ] }),
1948
- /* @__PURE__ */ jsxs(StatPill, { children: [
1949
- "\u{1F534} Poor/Missing: ",
1950
- stats.poor + stats.missing
1951
- ] }),
1952
- /* @__PURE__ */ jsxs(StatPill, { children: [
1953
- "\u{1F4CA} Avg: ",
1954
- stats.avgScore,
1955
- "%"
1956
- ] }),
1957
- /* @__PURE__ */ jsxs(StatPill, { children: [
1958
- "\u{1F5C2}\uFE0F Types: ",
1959
- uniqueDocumentTypes.length
1960
- ] })
1961
- ] }),
1962
- !loading && !compactStats && /* @__PURE__ */ jsxs(StatsGrid, { children: [
1963
- /* @__PURE__ */ jsxs(StatCard, { children: [
1964
- /* @__PURE__ */ jsx(StatLabel, { children: "Total Docs" }),
1965
- /* @__PURE__ */ jsx(StatValue, { children: stats.total })
1966
- ] }),
1967
- /* @__PURE__ */ jsxs(StatCard, { children: [
1968
- /* @__PURE__ */ jsx(StatLabel, { children: "Avg Score" }),
1969
- /* @__PURE__ */ jsxs(StatValue, { children: [
1970
- stats.avgScore,
1971
- "%"
1972
- ] })
1973
- ] }),
1974
- /* @__PURE__ */ jsxs(StatCard, { $accent: "#10b981", children: [
1975
- /* @__PURE__ */ jsx(StatLabel, { children: "Excellent (80+)" }),
1976
- /* @__PURE__ */ jsx(StatValue, { children: stats.excellent })
1977
- ] }),
1978
- /* @__PURE__ */ jsxs(StatCard, { $accent: "#f59e0b", children: [
1979
- /* @__PURE__ */ jsx(StatLabel, { children: "Good (60\u201379)" }),
1980
- /* @__PURE__ */ jsx(StatValue, { children: stats.good })
1981
- ] }),
1982
- /* @__PURE__ */ jsxs(StatCard, { $accent: "#f97316", children: [
1983
- /* @__PURE__ */ jsx(StatLabel, { children: "Fair (40\u201359)" }),
1984
- /* @__PURE__ */ jsx(StatValue, { children: stats.fair })
1985
- ] }),
1986
- /* @__PURE__ */ jsxs(StatCard, { $accent: "#ef4444", children: [
1987
- /* @__PURE__ */ jsx(StatLabel, { children: "Poor / Missing" }),
1988
- /* @__PURE__ */ jsx(StatValue, { children: stats.poor + stats.missing })
1989
- ] })
1990
- ] }),
1991
- /* @__PURE__ */ jsxs(ControlsBar, { children: [
1992
- /* @__PURE__ */ jsxs(SearchWrapper, { children: [
1993
- /* @__PURE__ */ jsx(SearchIconSvg, { children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx(
1994
- "path",
1995
- {
1996
- fillRule: "evenodd",
1997
- d: "M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z",
1998
- clipRule: "evenodd"
1999
- }
2000
- ) }) }),
2001
- /* @__PURE__ */ jsx(
2002
- SearchInput,
2003
- {
2004
- ref: searchInputRef,
2005
- placeholder: "Search documents... (press / to focus)",
2006
- value: searchQuery,
2007
- onChange: (e) => setSearchQuery(e.currentTarget.value)
2008
- }
2009
- )
2010
- ] }),
2011
- /* @__PURE__ */ jsxs(
2012
- StyledSelect,
2013
- {
2014
- value: filterStatus,
2015
- onChange: (e) => handleFilterStatusChange(e.currentTarget.value),
2016
- children: [
2017
- /* @__PURE__ */ jsx("option", { value: "all", children: "All Status" }),
2018
- /* @__PURE__ */ jsx("option", { value: "excellent", children: "Excellent" }),
2019
- /* @__PURE__ */ jsx("option", { value: "good", children: "Good" }),
2020
- /* @__PURE__ */ jsx("option", { value: "fair", children: "Fair" }),
2021
- /* @__PURE__ */ jsx("option", { value: "poor", children: "Poor" }),
2022
- /* @__PURE__ */ jsx("option", { value: "missing", children: "Missing" })
2023
- ]
2024
- }
2025
- ),
2026
- uniqueDocumentTypes.length > 1 && /* @__PURE__ */ jsxs(
2027
- StyledSelect,
2028
- {
2029
- value: filterType,
2030
- onChange: (e) => handleFilterTypeChange(e.currentTarget.value),
2031
- children: [
2032
- /* @__PURE__ */ jsx("option", { value: "all", children: "All Types" }),
2033
- uniqueDocumentTypes.map((type) => /* @__PURE__ */ jsx("option", { value: type, children: resolveTypeLabel(type, resolvedTypeLabels) }, type))
2034
- ]
2035
- }
2036
- ),
2037
- /* @__PURE__ */ jsxs(
2038
- StyledSelect,
2039
- {
2040
- value: sortBy,
2041
- onChange: (e) => setSortBy(e.currentTarget.value),
2042
- children: [
2043
- /* @__PURE__ */ jsx("option", { value: "score", children: "Sort by Score" }),
2044
- /* @__PURE__ */ jsx("option", { value: "title", children: "Sort by Title" })
2045
- ]
2046
- }
2047
- ),
2048
- exportEnabled && exportFormats.includes("csv") && /* @__PURE__ */ jsx(ExportButton, { onClick: handleExportCSV, title: "Export all filtered as CSV", children: "\u2B07 CSV" }),
2049
- exportEnabled && exportFormats.includes("json") && /* @__PURE__ */ jsx(ExportButton, { onClick: handleExportJSON, title: "Export all filtered as JSON", children: "\u2B07 JSON" })
2050
- ] }),
2051
- /* @__PURE__ */ jsxs(TableCard, { children: [
2052
- loading && /* @__PURE__ */ jsxs(LoadingState, { children: [
2053
- /* @__PURE__ */ jsx(Spinner, {}),
2054
- loadingDocuments != null ? loadingDocuments : "Loading documents\u2026"
2055
- ] }),
2056
- !loading && (filteredAndSortedDocs.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { children: noDocuments != null ? noDocuments : "No documents found" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2057
- /* @__PURE__ */ jsxs(TableHeader, { children: [
2058
- /* @__PURE__ */ jsx(ColTitle, { children: "Title" }),
2059
- showTypeColumn && /* @__PURE__ */ jsx(ColType, { children: "Type" }),
2060
- /* @__PURE__ */ jsx(ColScore, { children: "Score" }),
2061
- /* @__PURE__ */ jsx(ColIssues, { children: "Top Issues" })
2062
- ] }),
2063
- paginatedDocs.map((doc) => {
2064
- return /* @__PURE__ */ jsxs(TableRow, { children: [
2065
- /* @__PURE__ */ jsx(ColTitle, { children: /* @__PURE__ */ jsx(TitleWrapper, { children: /* @__PURE__ */ jsxs(TitleCell, { children: [
2066
- doc.title !== null && typeof doc.title !== "string" ? /* @__PURE__ */ jsx(NonStringTitleWarning, { title: "title is not a string \u2014 use pt::text(title) in your query.groq projection to convert Portable Text to a plain string", children: "\u26A0 title is not a string \u2014 use pt::text(title) in query.groq" }) : /* @__PURE__ */ jsx(Fragment, { children: openInPane ? /* @__PURE__ */ jsx(DocTitleAnchorPane, { id: doc._id, type: doc._type, children: typeof doc.title === "string" ? doc.title || "Untitled" : "Untitled" }) : /* @__PURE__ */ jsx(
2067
- DocTitleAnchor,
2068
- {
2069
- id: doc._id,
2070
- type: doc._type,
2071
- structureTool,
2072
- children: typeof doc.title === "string" ? doc.title || "Untitled" : "Untitled"
2073
- }
2074
- ) }),
2075
- showDocumentId && /* @__PURE__ */ jsx(DocId, { children: doc._id }),
2076
- resolvedDocBadge && /* @__PURE__ */ jsx(
2077
- DocBadgeRenderer,
2078
- {
2079
- doc,
2080
- docBadge: resolvedDocBadge
2081
- }
2082
- )
2083
- ] }) }) }),
2084
- showTypeColumn && /* @__PURE__ */ jsx(ColType, { children: typeColumnMode === "text" ? /* @__PURE__ */ jsx(TypeText, { children: resolveTypeLabel(doc._type, resolvedTypeLabels) }) : (() => {
2085
- const typeColor = getTypeColor(doc._type);
2086
- return /* @__PURE__ */ jsx(TypeBadge, { $bgColor: typeColor.bg, $textColor: typeColor.text, children: resolveTypeLabel(doc._type, resolvedTypeLabels) });
2087
- })() }),
2088
- /* @__PURE__ */ jsx(ColScore, { children: /* @__PURE__ */ jsxs(ScoreBadge, { $score: doc.health.score, children: [
2089
- doc.health.score,
2090
- "%"
2091
- ] }) }),
2092
- /* @__PURE__ */ jsxs(ColIssues, { children: [
2093
- doc.health.issues.slice(0, 2).map((issue) => /* @__PURE__ */ jsxs(IssueTag, { children: [
2094
- "\u2022 ",
2095
- issue
2096
- ] }, `issue-${doc._id}-${issue}`)),
2097
- doc.health.issues.length > 2 && /* @__PURE__ */ jsx(
2098
- MoreIssuesWrapper,
2099
- {
2100
- onMouseEnter: function(e) {
2101
- handleMouseEnterIssues(
2102
- e.currentTarget,
2103
- doc.health.issues.slice(2)
2104
- );
2105
- },
2106
- onMouseLeave: handleMouseLeave,
2107
- children: /* @__PURE__ */ jsxs(MoreIssues, { children: [
2108
- "+",
2109
- doc.health.issues.length - 2,
2110
- " more issues"
2111
- ] })
2112
- }
2113
- )
2114
- ] })
2115
- ] }, doc._id);
2116
- }),
2117
- /* @__PURE__ */ jsxs(PaginationBar, { children: [
2118
- /* @__PURE__ */ jsxs("span", { children: [
2119
- "Showing ",
2120
- Math.min((currentPage - 1) * pageSize + 1, filteredAndSortedDocs.length),
2121
- "\u2013",
2122
- Math.min(currentPage * pageSize, filteredAndSortedDocs.length),
2123
- " of",
2124
- " ",
2125
- filteredAndSortedDocs.length,
2126
- " documents"
2127
- ] }),
2128
- /* @__PURE__ */ jsxs(PaginationCenter, { children: [
2129
- /* @__PURE__ */ jsx(
2130
- PaginationButton,
2131
- {
2132
- disabled: currentPage === 1,
2133
- onClick: () => setCurrentPage((p) => Math.max(1, p - 1)),
2134
- title: "Previous page",
2135
- children: "\u2039"
2136
- }
2137
- ),
2138
- /* @__PURE__ */ jsxs("span", { children: [
2139
- "Page ",
2140
- currentPage,
2141
- " of ",
2142
- totalPages
2143
- ] }),
2144
- /* @__PURE__ */ jsx(
2145
- PaginationButton,
2146
- {
2147
- disabled: currentPage >= totalPages,
2148
- onClick: () => setCurrentPage((p) => Math.min(totalPages, p + 1)),
2149
- title: "Next page",
2150
- children: "\u203A"
2151
- }
2152
- )
2153
- ] }),
2154
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
2155
- /* @__PURE__ */ jsx("span", { children: "Per page:" }),
2156
- /* @__PURE__ */ jsxs(
2157
- StyledSelect,
2158
- {
2159
- value: pageSize,
2160
- style: { height: 30, fontSize: 12, padding: "0 28px 0 8px" },
2161
- onChange: (e) => {
2162
- const size = Number(e.currentTarget.value);
2163
- setPageSize(size);
2164
- try {
2165
- localStorage.setItem("seo-dashboard-page-size", String(size));
2166
- } catch (e2) {
2167
- }
2168
- setCurrentPage(1);
2169
- },
2170
- children: [
2171
- /* @__PURE__ */ jsx("option", { value: 25, children: "25" }),
2172
- /* @__PURE__ */ jsx("option", { value: 50, children: "50" }),
2173
- /* @__PURE__ */ jsx("option", { value: 100, children: "100" }),
2174
- /* @__PURE__ */ jsx("option", { value: 200, children: "200" })
2175
- ]
2176
- }
2177
- )
2178
- ] })
2179
- ] })
2180
- ] }))
2181
- ] }),
2182
- activePopover && /* @__PURE__ */ jsx(
2183
- IssuesPopover,
2184
- {
2185
- style: {
2186
- top: activePopover.top,
2187
- left: activePopover.left,
2188
- transform: "translateY(calc(-100% - 10px))"
2189
- },
2190
- children: activePopover.issues.map((issue) => /* @__PURE__ */ jsxs(PopoverIssueItem, { children: [
2191
- "\u26A0\uFE0F ",
2192
- issue
2193
- ] }, issue))
2194
- }
2195
- )
2196
- ] });
2197
- return /* @__PURE__ */ jsxs(DashboardContainer, { style: currentVars, children: [
2198
- licenseStatus === "loading" && /* @__PURE__ */ jsx(RenderLicenseLoading, { text: loadingLicense }),
2199
- licenseStatus === "invalid" && /* @__PURE__ */ jsx(RenderLicenseInvalid, { licenseKey, validateLicense }),
2200
- licenseStatus === "legacy" && /* @__PURE__ */ jsx(
2201
- RenderLegacyBanner,
2202
- {
2203
- upgradeUrl: legacyInfo.upgradeUrl,
2204
- cutoffDate: legacyInfo.cutoffDate,
2205
- onVerifyUpgrade: handleVerifyUpgrade
2206
- }
2207
- ),
2208
- licenseStatus === "valid" && renderDashboardContent()
2209
- ] });
2210
- };
2211
- var SeoHealthDashboard_default = SeoHealthDashboard;
2212
-
2213
- export { SeoHealthDashboard_default, __objRest, __spreadProps, __spreadValues };
2214
- //# sourceMappingURL=chunk-27XSYENH.js.map
2215
- //# sourceMappingURL=chunk-27XSYENH.js.map