@pixelated-tech/components 3.4.3 → 3.5.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 (228) hide show
  1. package/README.md +12 -191
  2. package/dist/components/admin/componentusage/componentAnalysis.js +12 -4
  3. package/dist/components/admin/componentusage/componentDiscovery.js +20 -6
  4. package/dist/components/admin/site-health/site-health-accessibility.js +5 -1
  5. package/dist/components/admin/site-health/site-health-axe-core.js +4 -0
  6. package/dist/components/admin/site-health/site-health-cloudwatch.integration.js +0 -5
  7. package/dist/components/admin/site-health/site-health-cloudwatch.js +7 -1
  8. package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +4 -0
  9. package/dist/components/admin/site-health/site-health-github.js +6 -0
  10. package/dist/components/admin/site-health/site-health-google-analytics.js +6 -0
  11. package/dist/components/admin/site-health/site-health-google-search-console.js +6 -0
  12. package/dist/components/admin/site-health/site-health-on-site-seo.integration.js +128 -55
  13. package/dist/components/admin/site-health/site-health-on-site-seo.js +4 -0
  14. package/dist/components/admin/site-health/site-health-overview.js +11 -4
  15. package/dist/components/admin/site-health/site-health-performance.js +4 -0
  16. package/dist/components/admin/site-health/site-health-security.js +5 -1
  17. package/dist/components/admin/site-health/site-health-seo.js +5 -1
  18. package/dist/components/admin/site-health/site-health-template.js +19 -9
  19. package/dist/components/admin/site-health/site-health-uptime.js +4 -0
  20. package/dist/components/callout/callout.js +0 -10
  21. package/dist/components/carousel/carousel.js +15 -4
  22. package/dist/components/carousel/tiles.js +1 -1
  23. package/dist/components/cms/contentful.items.components.js +3 -4
  24. package/dist/components/cms/flickr.js +1 -1
  25. package/dist/components/cms/google.reviews.components.js +3 -3
  26. package/dist/components/cms/instagram.components.js +15 -5
  27. package/dist/components/cms/smartimage.js +2 -2
  28. package/dist/components/cms/wordpress.components.js +32 -6
  29. package/dist/components/cms/yelp.js +5 -0
  30. package/dist/components/config/config.server.js +7 -1
  31. package/dist/components/general/css.js +0 -1
  32. package/dist/components/general/image.js +0 -1
  33. package/dist/components/general/loading.js +2 -1
  34. package/dist/components/general/microinteractions.js +0 -1
  35. package/dist/components/general/modal.css +2 -4
  36. package/dist/components/general/modal.js +72 -30
  37. package/dist/components/general/sidepanel.js +16 -0
  38. package/dist/components/general/tab.js +1 -0
  39. package/dist/components/menu/menu-accordion.css +1 -1
  40. package/dist/components/menu/menu-accordion.js +15 -4
  41. package/dist/components/menu/menu-expando.js +21 -19
  42. package/dist/components/menu/menu-simple.js +14 -14
  43. package/dist/components/nerdjoke/nerdjoke.js +1 -1
  44. package/dist/components/seo/googlesearch.js +0 -1
  45. package/dist/components/seo/schema-blogposting.js +6 -1
  46. package/dist/components/seo/schema-recipe.js +34 -1
  47. package/dist/components/seo/schema-services.js +20 -2
  48. package/dist/components/shoppingcart/ebay.components.js +3 -3
  49. package/dist/components/shoppingcart/shoppingcart.components.js +76 -28
  50. package/dist/components/shoppingcart/shoppingcart.functions.js +4 -4
  51. package/dist/components/sitebuilder/config/CompoundFontSelector.js +13 -4
  52. package/dist/components/sitebuilder/config/ConfigBuilder.css +194 -5
  53. package/dist/components/sitebuilder/config/ConfigBuilder.js +183 -17
  54. package/dist/components/sitebuilder/config/FontSelector.js +13 -2
  55. package/dist/components/sitebuilder/config/routes-form.json +67 -0
  56. package/dist/components/sitebuilder/config/siteinfo-form.json +28 -14
  57. package/dist/components/sitebuilder/config/visualdesignform.json +4 -4
  58. package/dist/components/sitebuilder/form/formbuilder.js +1 -0
  59. package/dist/components/sitebuilder/form/formcomponents.js +2 -3
  60. package/dist/components/sitebuilder/form/formengine.js +6 -5
  61. package/dist/components/sitebuilder/form/formvalidator.js +5 -0
  62. package/dist/components/sitebuilder/page/components/PageBuilderUI.js +5 -1
  63. package/dist/components/structured/buzzwordbingo.css +0 -1
  64. package/dist/components/structured/recipe.js +1 -1
  65. package/dist/components/structured/socialcard.js +2 -2
  66. package/dist/components/utilities/functions.js +82 -1
  67. package/dist/components/utilities/gemini-api.client.js +76 -0
  68. package/dist/components/utilities/gemini-api.server.js +185 -0
  69. package/dist/data/routes.json +5 -5
  70. package/dist/index.adminclient.js +30 -0
  71. package/dist/index.adminserver.js +21 -0
  72. package/dist/index.js +4 -18
  73. package/dist/index.server.js +15 -28
  74. package/dist/types/components/admin/componentusage/componentAnalysis.d.ts.map +1 -1
  75. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts +1 -1
  76. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts.map +1 -1
  77. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts +7 -4
  78. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts.map +1 -1
  79. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts +7 -4
  80. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts.map +1 -1
  81. package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts +9 -6
  82. package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts.map +1 -1
  83. package/dist/types/components/admin/site-health/site-health-cloudwatch.integration.d.ts.map +1 -1
  84. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts +7 -4
  85. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts.map +1 -1
  86. package/dist/types/components/admin/site-health/site-health-github.d.ts +9 -6
  87. package/dist/types/components/admin/site-health/site-health-github.d.ts.map +1 -1
  88. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts +9 -6
  89. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts.map +1 -1
  90. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts +9 -6
  91. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts.map +1 -1
  92. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts +8 -3
  93. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts.map +1 -1
  94. package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts.map +1 -1
  95. package/dist/types/components/admin/site-health/site-health-overview.d.ts +7 -4
  96. package/dist/types/components/admin/site-health/site-health-overview.d.ts.map +1 -1
  97. package/dist/types/components/admin/site-health/site-health-performance.d.ts +7 -4
  98. package/dist/types/components/admin/site-health/site-health-performance.d.ts.map +1 -1
  99. package/dist/types/components/admin/site-health/site-health-security.d.ts +7 -4
  100. package/dist/types/components/admin/site-health/site-health-security.d.ts.map +1 -1
  101. package/dist/types/components/admin/site-health/site-health-seo.d.ts +7 -4
  102. package/dist/types/components/admin/site-health/site-health-seo.d.ts.map +1 -1
  103. package/dist/types/components/admin/site-health/site-health-template.d.ts +12 -10
  104. package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -1
  105. package/dist/types/components/admin/site-health/site-health-uptime.d.ts +7 -4
  106. package/dist/types/components/admin/site-health/site-health-uptime.d.ts.map +1 -1
  107. package/dist/types/components/callout/callout.d.ts +3 -3
  108. package/dist/types/components/callout/callout.d.ts.map +1 -1
  109. package/dist/types/components/carousel/carousel.d.ts +16 -7
  110. package/dist/types/components/carousel/carousel.d.ts.map +1 -1
  111. package/dist/types/components/carousel/tiles.d.ts +3 -6
  112. package/dist/types/components/carousel/tiles.d.ts.map +1 -1
  113. package/dist/types/components/cms/flickr.d.ts +3 -6
  114. package/dist/types/components/cms/flickr.d.ts.map +1 -1
  115. package/dist/types/components/cms/google.reviews.components.d.ts +1 -7
  116. package/dist/types/components/cms/google.reviews.components.d.ts.map +1 -1
  117. package/dist/types/components/cms/hubspot.components.d.ts +1 -2
  118. package/dist/types/components/cms/hubspot.components.d.ts.map +1 -1
  119. package/dist/types/components/cms/instagram.components.d.ts +14 -9
  120. package/dist/types/components/cms/instagram.components.d.ts.map +1 -1
  121. package/dist/types/components/cms/smartimage.d.ts +2 -28
  122. package/dist/types/components/cms/smartimage.d.ts.map +1 -1
  123. package/dist/types/components/cms/wordpress.components.d.ts +33 -14
  124. package/dist/types/components/cms/wordpress.components.d.ts.map +1 -1
  125. package/dist/types/components/cms/yelp.d.ts +9 -4
  126. package/dist/types/components/cms/yelp.d.ts.map +1 -1
  127. package/dist/types/components/config/config.server.d.ts +9 -6
  128. package/dist/types/components/config/config.server.d.ts.map +1 -1
  129. package/dist/types/components/general/loading.d.ts +5 -1
  130. package/dist/types/components/general/loading.d.ts.map +1 -1
  131. package/dist/types/components/general/microinteractions.d.ts +1 -3
  132. package/dist/types/components/general/microinteractions.d.ts.map +1 -1
  133. package/dist/types/components/general/modal.d.ts +11 -5
  134. package/dist/types/components/general/modal.d.ts.map +1 -1
  135. package/dist/types/components/general/semantic.d.ts +3 -3
  136. package/dist/types/components/general/sidepanel.d.ts +20 -13
  137. package/dist/types/components/general/sidepanel.d.ts.map +1 -1
  138. package/dist/types/components/general/tab.d.ts +1 -2
  139. package/dist/types/components/general/tab.d.ts.map +1 -1
  140. package/dist/types/components/menu/menu-accordion.d.ts +22 -9
  141. package/dist/types/components/menu/menu-accordion.d.ts.map +1 -1
  142. package/dist/types/components/menu/menu-expando.d.ts +14 -5
  143. package/dist/types/components/menu/menu-expando.d.ts.map +1 -1
  144. package/dist/types/components/menu/menu-simple.d.ts +4 -5
  145. package/dist/types/components/menu/menu-simple.d.ts.map +1 -1
  146. package/dist/types/components/nerdjoke/nerdjoke.d.ts +1 -1
  147. package/dist/types/components/nerdjoke/nerdjoke.d.ts.map +1 -1
  148. package/dist/types/components/seo/googleanalytics.d.ts.map +1 -1
  149. package/dist/types/components/seo/metadata.components.d.ts +2 -2
  150. package/dist/types/components/seo/metadata.components.d.ts.map +1 -1
  151. package/dist/types/components/seo/schema-blogposting.d.ts +7 -4
  152. package/dist/types/components/seo/schema-blogposting.d.ts.map +1 -1
  153. package/dist/types/components/seo/schema-recipe.d.ts +29 -30
  154. package/dist/types/components/seo/schema-recipe.d.ts.map +1 -1
  155. package/dist/types/components/seo/schema-services.d.ts +19 -9
  156. package/dist/types/components/seo/schema-services.d.ts.map +1 -1
  157. package/dist/types/components/shoppingcart/paypal.d.ts +1 -1
  158. package/dist/types/components/shoppingcart/paypal.d.ts.map +1 -1
  159. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +77 -28
  160. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
  161. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts +4 -23
  162. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts.map +1 -1
  163. package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts +10 -11
  164. package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts.map +1 -1
  165. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +41 -174
  166. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -1
  167. package/dist/types/components/sitebuilder/config/FontSelector.d.ts +12 -13
  168. package/dist/types/components/sitebuilder/config/FontSelector.d.ts.map +1 -1
  169. package/dist/types/components/sitebuilder/form/formbuilder.d.ts +7 -3
  170. package/dist/types/components/sitebuilder/form/formbuilder.d.ts.map +1 -1
  171. package/dist/types/components/sitebuilder/form/formcomponents.d.ts +1 -1
  172. package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -1
  173. package/dist/types/components/sitebuilder/form/formengine.d.ts +1 -2
  174. package/dist/types/components/sitebuilder/form/formengine.d.ts.map +1 -1
  175. package/dist/types/components/sitebuilder/form/formextractor.d.ts +5 -4
  176. package/dist/types/components/sitebuilder/form/formextractor.d.ts.map +1 -1
  177. package/dist/types/components/sitebuilder/form/formtypes.d.ts +3 -3
  178. package/dist/types/components/sitebuilder/form/formtypes.d.ts.map +1 -1
  179. package/dist/types/components/sitebuilder/form/formvalidator.d.ts +8 -3
  180. package/dist/types/components/sitebuilder/form/formvalidator.d.ts.map +1 -1
  181. package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts +2 -3
  182. package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts.map +1 -1
  183. package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts +2 -3
  184. package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts.map +1 -1
  185. package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts +2 -3
  186. package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts.map +1 -1
  187. package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts +8 -7
  188. package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts.map +1 -1
  189. package/dist/types/components/sitebuilder/page/components/PageEngine.d.ts.map +1 -1
  190. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts +2 -3
  191. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts.map +1 -1
  192. package/dist/types/components/sitebuilder/page/lib/componentMap.d.ts +1 -1
  193. package/dist/types/components/structured/markdown.d.ts +1 -3
  194. package/dist/types/components/structured/markdown.d.ts.map +1 -1
  195. package/dist/types/components/structured/recipe.d.ts +5 -32
  196. package/dist/types/components/structured/recipe.d.ts.map +1 -1
  197. package/dist/types/components/structured/socialcard.d.ts +4 -0
  198. package/dist/types/components/structured/socialcard.d.ts.map +1 -1
  199. package/dist/types/components/structured/timeline.d.ts +1 -3
  200. package/dist/types/components/structured/timeline.d.ts.map +1 -1
  201. package/dist/types/components/utilities/functions.d.ts +20 -0
  202. package/dist/types/components/utilities/functions.d.ts.map +1 -1
  203. package/dist/types/components/utilities/gemini-api.client.d.ts +38 -0
  204. package/dist/types/components/utilities/gemini-api.client.d.ts.map +1 -0
  205. package/dist/types/components/utilities/gemini-api.server.d.ts +17 -0
  206. package/dist/types/components/utilities/gemini-api.server.d.ts.map +1 -0
  207. package/dist/types/index.adminclient.d.ts +27 -0
  208. package/dist/types/index.adminclient.d.ts.map +1 -0
  209. package/dist/types/index.adminserver.d.ts +19 -0
  210. package/dist/types/index.adminserver.d.ts.map +1 -0
  211. package/dist/types/index.d.ts +4 -18
  212. package/dist/types/index.server.d.ts +5 -28
  213. package/dist/types/stories/general/sidepanel.stories.d.ts.map +1 -1
  214. package/dist/types/stories/general/smartimage.stories.d.ts +74 -2
  215. package/dist/types/stories/general/smartimage.stories.d.ts.map +1 -1
  216. package/package.json +19 -9
  217. package/README.COMPONENTS.md +0 -2310
  218. package/dist/components/cms/pixelated.linkedin.js +0 -180
  219. package/dist/components/cms/pixelated.linkedin1.js +0 -84
  220. package/dist/components/cms/pixelated.linkedin2.js +0 -92
  221. package/dist/types/components/cms/pixelated.linkedin.d.ts +0 -2
  222. package/dist/types/components/cms/pixelated.linkedin.d.ts.map +0 -1
  223. package/dist/types/components/cms/pixelated.linkedin1.d.ts +0 -2
  224. package/dist/types/components/cms/pixelated.linkedin1.d.ts.map +0 -1
  225. package/dist/types/components/cms/pixelated.linkedin2.d.ts +0 -2
  226. package/dist/types/components/cms/pixelated.linkedin2.d.ts.map +0 -1
  227. package/dist/types/tests/pixelated.menu-expando.test.d.ts +0 -2
  228. package/dist/types/tests/pixelated.menu-expando.test.d.ts.map +0 -1
@@ -361,36 +361,62 @@ function calculateFacetedNavigationScore(data) {
361
361
  /**
362
362
  * Browser Caching Data Collector
363
363
  */
364
- function collectBrowserCachingData(response) {
365
- // Get response headers from Puppeteer response object
366
- const headers = {};
364
+ async function collectBrowserCachingData(url) {
367
365
  try {
368
- const rawHeaders = response.headers();
369
- for (const [key, value] of Object.entries(rawHeaders)) {
370
- headers[key.toLowerCase()] = value;
366
+ const response = await fetch(url, {
367
+ method: 'HEAD', // Use HEAD to get headers without downloading the full content
368
+ headers: {
369
+ 'User-Agent': 'Mozilla/5.0 (compatible; SEO Analysis Bot)'
370
+ }
371
+ });
372
+ if (!response.ok) {
373
+ return {
374
+ cacheControl: '',
375
+ expires: '',
376
+ lastModified: '',
377
+ etag: '',
378
+ age: '',
379
+ hasCachingHeaders: false,
380
+ error: `HTTP ${response.status}: ${response.statusText}`
381
+ };
371
382
  }
383
+ const cacheControl = response.headers.get('cache-control') || '';
384
+ const expires = response.headers.get('expires') || '';
385
+ const lastModified = response.headers.get('last-modified') || '';
386
+ const etag = response.headers.get('etag') || '';
387
+ const age = response.headers.get('age') || '';
388
+ return {
389
+ cacheControl,
390
+ expires,
391
+ lastModified,
392
+ etag,
393
+ age,
394
+ hasCachingHeaders: !!(cacheControl || expires || lastModified || etag)
395
+ };
372
396
  }
373
- catch (error) {
374
- console.warn('Failed to get response headers:', error);
397
+ catch {
398
+ return {
399
+ cacheControl: '',
400
+ expires: '',
401
+ lastModified: '',
402
+ etag: '',
403
+ age: '',
404
+ hasCachingHeaders: false,
405
+ error: 'Could not access response headers - network error or server unavailable'
406
+ };
375
407
  }
376
- const cacheControl = headers['cache-control'] || '';
377
- const expires = headers['expires'] || '';
378
- const lastModified = headers['last-modified'] || '';
379
- const etag = headers['etag'] || '';
380
- const age = headers['age'] || '';
381
- return {
382
- cacheControl,
383
- expires,
384
- lastModified,
385
- etag,
386
- age,
387
- hasCachingHeaders: !!(cacheControl || expires || lastModified || etag)
388
- };
389
408
  }
390
409
  /**
391
410
  * Browser Caching Scorer
392
411
  */
393
412
  function calculateBrowserCachingScore(data) {
413
+ if (data.error) {
414
+ return {
415
+ score: 0,
416
+ displayValue: 'Requires server header analysis',
417
+ details: { error: data.error }
418
+ };
419
+ }
394
420
  let score = 0;
395
421
  let displayValue = 'No caching headers detected';
396
422
  const issues = [];
@@ -448,32 +474,55 @@ function calculateBrowserCachingScore(data) {
448
474
  /**
449
475
  * Gzip Compression Data Collector
450
476
  */
451
- function collectGzipCompressionData(response) {
452
- // Get response headers from Puppeteer response object
453
- const headers = {};
477
+ async function collectGzipCompressionData(url) {
454
478
  try {
455
- const rawHeaders = response.headers();
456
- for (const [key, value] of Object.entries(rawHeaders)) {
457
- headers[key.toLowerCase()] = value;
479
+ const response = await fetch(url, {
480
+ method: 'GET', // Changed from HEAD to GET to properly detect compression
481
+ headers: {
482
+ 'User-Agent': 'Mozilla/5.0 (compatible; SEO Analysis Bot)',
483
+ 'Accept-Encoding': 'gzip, deflate' // Added Accept-Encoding like browsers
484
+ }
485
+ });
486
+ if (!response.ok) {
487
+ return {
488
+ contentEncoding: '',
489
+ contentLength: '',
490
+ transferEncoding: '',
491
+ isCompressed: false,
492
+ error: `HTTP ${response.status}: ${response.statusText}`
493
+ };
458
494
  }
495
+ const contentEncoding = response.headers.get('content-encoding') || '';
496
+ const contentLength = response.headers.get('content-length') || '';
497
+ const transferEncoding = response.headers.get('transfer-encoding') || '';
498
+ return {
499
+ contentEncoding,
500
+ contentLength,
501
+ transferEncoding,
502
+ isCompressed: contentEncoding.includes('gzip') || contentEncoding.includes('deflate')
503
+ };
459
504
  }
460
- catch (error) {
461
- console.warn('Failed to get response headers:', error);
505
+ catch {
506
+ return {
507
+ contentEncoding: '',
508
+ contentLength: '',
509
+ transferEncoding: '',
510
+ isCompressed: false,
511
+ error: 'Could not access response headers - network error or server unavailable'
512
+ };
462
513
  }
463
- const contentEncoding = headers['content-encoding'] || '';
464
- const contentLength = headers['content-length'] || '';
465
- const transferEncoding = headers['transfer-encoding'] || '';
466
- return {
467
- contentEncoding,
468
- contentLength,
469
- transferEncoding,
470
- isCompressed: contentEncoding.includes('gzip') || contentEncoding.includes('deflate') || transferEncoding.includes('chunked')
471
- };
472
514
  }
473
515
  /**
474
516
  * Gzip Compression Scorer
475
517
  */
476
518
  function calculateGzipCompressionScore(data) {
519
+ if (data.error) {
520
+ return {
521
+ score: 0,
522
+ displayValue: 'Requires server header analysis',
523
+ details: { error: data.error }
524
+ };
525
+ }
477
526
  let score = 0;
478
527
  let displayValue = 'No compression detected';
479
528
  if (data.isCompressed) {
@@ -614,11 +663,16 @@ async function analyzeSinglePage(url) {
614
663
  // Navigate to the page with faster waiting strategy
615
664
  const response = await page.goto(url, {
616
665
  waitUntil: 'domcontentloaded', // Wait for DOM instead of all network requests
617
- timeout: 15000 // Reduced timeout
666
+ timeout: 10000 // Reduced timeout from 15000 to 10000
618
667
  });
668
+ // Check if navigation failed
669
+ if (!response) {
670
+ console.warn(`Failed to load page: ${url} - no response received`);
671
+ // Continue with analysis using available data, but mark header-dependent metrics as unavailable
672
+ }
619
673
  // Wait for H1 elements to be rendered (if any) with a short timeout
620
674
  try {
621
- await page.waitForSelector('h1', { timeout: 2000 });
675
+ await page.waitForSelector('h1', { timeout: 1000 }); // Reduced from 2000 to 1000
622
676
  }
623
677
  catch {
624
678
  // H1 not found within timeout, continue anyway
@@ -639,7 +693,8 @@ async function analyzeSinglePage(url) {
639
693
  });
640
694
  // Get the rendered HTML for other pattern-based checks
641
695
  const html = await page.content();
642
- await page.close();
696
+ // Don't close the page here - let it be reused or closed by caller
697
+ // await page.close();
643
698
  const audits = [];
644
699
  // Process on-page metrics from configuration
645
700
  const config = seoMetricsConfig;
@@ -653,10 +708,14 @@ async function analyzeSinglePage(url) {
653
708
  const collector = dataCollectors[metric.dataCollector];
654
709
  const scorer = scorers[metric.scorer];
655
710
  if (collector && scorer) {
656
- // Pass response object for collectors that need headers (like browser caching and gzip compression)
657
- const rawData = (metric.dataCollector === 'collectBrowserCachingData' || metric.dataCollector === 'collectGzipCompressionData')
658
- ? collector(html, pageData.title, response)
659
- : collector(html, pageData.title);
711
+ // Pass URL for collectors that need headers (like browser caching and gzip compression)
712
+ let rawData;
713
+ if (metric.dataCollector === 'collectBrowserCachingData' || metric.dataCollector === 'collectGzipCompressionData') {
714
+ rawData = await collector(url);
715
+ }
716
+ else {
717
+ rawData = collector(html, pageData.title);
718
+ }
660
719
  const result = scorer(rawData);
661
720
  score = result.score;
662
721
  displayValue = result.displayValue;
@@ -700,6 +759,8 @@ async function analyzeSinglePage(url) {
700
759
  details
701
760
  });
702
761
  }
762
+ // Close the page after analysis
763
+ await page.close();
703
764
  return {
704
765
  url,
705
766
  title: pageData.title,
@@ -719,11 +780,7 @@ async function analyzeSinglePage(url) {
719
780
  crawledAt: new Date().toISOString()
720
781
  };
721
782
  }
722
- finally {
723
- if (browser) {
724
- await browser.close();
725
- }
726
- }
783
+ // Don't close browser here - keep it alive for reuse
727
784
  }
728
785
  async function performSiteWideAudits(baseUrl) {
729
786
  const audits = [];
@@ -799,12 +856,28 @@ async function performSiteWideAudits(baseUrl) {
799
856
  }
800
857
  break;
801
858
  case 'gzip-compression':
802
- score = 0; // Placeholder - would need HTTP header analysis
803
- displayValue = 'Requires server header analysis';
859
+ try {
860
+ const gzipData = await collectGzipCompressionData(baseUrl);
861
+ const gzipResult = calculateGzipCompressionScore(gzipData);
862
+ score = gzipResult.score;
863
+ displayValue = gzipResult.displayValue;
864
+ }
865
+ catch {
866
+ score = 0;
867
+ displayValue = 'Error analyzing compression headers';
868
+ }
804
869
  break;
805
870
  case 'browser-caching':
806
- score = 0; // Placeholder - would need HTTP header analysis
807
- displayValue = 'Requires server header analysis';
871
+ try {
872
+ const cachingData = await collectBrowserCachingData(baseUrl);
873
+ const cachingResult = calculateBrowserCachingScore(cachingData);
874
+ score = cachingResult.score;
875
+ displayValue = cachingResult.displayValue;
876
+ }
877
+ catch {
878
+ score = 0;
879
+ displayValue = 'Error analyzing caching headers';
880
+ }
808
881
  break;
809
882
  case 'duplicate-content-detection':
810
883
  score = 0; // Placeholder - would need multi-page content analysis
@@ -889,7 +962,7 @@ export async function performOnSiteSEOAnalysis(baseUrl) {
889
962
  }
890
963
  else {
891
964
  // Fallback to crawling if sitemap not available
892
- pagesToAnalyze = await crawlSite(baseUrl, 5);
965
+ pagesToAnalyze = await crawlSite(baseUrl, 2); // Reduced from 5 to 2 pages
893
966
  }
894
967
  if (pagesToAnalyze.length === 0) {
895
968
  return {
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import PropTypes from 'prop-types';
3
4
  import { SiteHealthTemplate } from './site-health-template';
4
5
  import { getScoreIndicator } from './site-health-indicators';
5
6
  /**
@@ -91,6 +92,9 @@ async function fetchOnSiteSEOData(siteName) {
91
92
  };
92
93
  }
93
94
  }
95
+ SiteHealthOnSiteSEO.propTypes = {
96
+ siteName: PropTypes.string.isRequired,
97
+ };
94
98
  export function SiteHealthOnSiteSEO({ siteName }) {
95
99
  return (_jsx(SiteHealthTemplate, { siteName: siteName, title: "On-Site SEO", fetchData: fetchOnSiteSEOData, children: (data) => {
96
100
  if (!data)
@@ -1,8 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCallback } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { SiteHealthTemplate } from './site-health-template';
5
6
  import { getScoreIndicator } from './site-health-indicators';
7
+ SiteHealthOverview.propTypes = {
8
+ siteName: PropTypes.string.isRequired,
9
+ };
6
10
  export function SiteHealthOverview({ siteName }) {
7
11
  const fetchCWVData = useCallback(async (site) => {
8
12
  const response = await fetch(`/api/site-health/core-web-vitals?siteName=${encodeURIComponent(site)}`);
@@ -57,9 +61,12 @@ export function SiteHealthOverview({ siteName }) {
57
61
  };
58
62
  return (_jsxs(_Fragment, { children: [_jsx("h4", { className: "health-site-name", children: siteData.site.replace('-', ' ') }), _jsxs("p", { className: "health-site-url", children: ["URL: ", siteData.url] }), _jsx("div", { className: "health-score-container", children: Object.entries(siteData.scores)
59
63
  .filter(([, score]) => score !== null)
60
- .map(([category, score]) => (_jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: category.replace('-', ' ') }), _jsx("div", { className: "health-score-value", style: { color: getScoreColor(score) }, children: formatScore(score) }), _jsx("div", { className: "health-score-bar", children: _jsx("div", { className: "health-score-fill", style: {
61
- width: score !== null ? `${score * 100}%` : '0%',
62
- backgroundColor: score !== null ? getScoreColor(score) : '#6b7280'
63
- } }) })] }, category))) }), _jsxs("div", { style: { marginBottom: '1.5rem' }, children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "Core Web Vitals" }), _jsxs("div", { className: "health-cwv-grid", children: [_jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Cumulative Layout Shift:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.cls, { good: 0.1, poor: 0.25 })) }, children: formatMetric(siteData.metrics.cls, '') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "First Input Delay:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.fid, { good: 100, poor: 300 })) }, children: formatMetric(siteData.metrics.fid, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Largest Contentful Paint:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.lcp, { good: 2500, poor: 4000 })) }, children: formatMetric(siteData.metrics.lcp, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "First Contentful Paint:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.fcp, { good: 1800, poor: 3000 })) }, children: formatMetric(siteData.metrics.fcp, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Time to First Byte:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.ttfb, { good: 800, poor: 1800 })) }, children: formatMetric(siteData.metrics.ttfb, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Speed Index:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.speedIndex, { good: 3400, poor: 5800 })) }, children: formatMetric(siteData.metrics.speedIndex, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Time to Interactive:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.interactive, { good: 3800, poor: 7300 })) }, children: formatMetric(siteData.metrics.interactive, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Total Blocking Time:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.totalBlockingTime, { good: 200, poor: 600 })) }, children: formatMetric(siteData.metrics.totalBlockingTime, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "First Meaningful Paint:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.firstMeaningfulPaint, { good: 2000, poor: 4000 })) }, children: formatMetric(siteData.metrics.firstMeaningfulPaint, 'ms') })] })] })] }), _jsxs("p", { className: "health-timestamp", children: ["Last checked: ", new Date(siteData.timestamp).toLocaleString()] })] }));
64
+ .map(([category, score]) => {
65
+ const numScore = score;
66
+ return (_jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: category.replace('-', ' ') }), _jsx("div", { className: "health-score-value", style: { color: getScoreColor(numScore) }, children: formatScore(numScore) }), _jsx("div", { className: "health-score-bar", children: _jsx("div", { className: "health-score-fill", style: {
67
+ width: numScore !== null ? `${numScore * 100}%` : '0%',
68
+ backgroundColor: numScore !== null ? getScoreColor(numScore) : '#6b7280'
69
+ } }) })] }, category));
70
+ }) }), _jsxs("div", { style: { marginBottom: '1.5rem' }, children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "Core Web Vitals" }), _jsxs("div", { className: "health-cwv-grid", children: [_jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Cumulative Layout Shift:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.cls, { good: 0.1, poor: 0.25 })) }, children: formatMetric(siteData.metrics.cls, '') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "First Input Delay:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.fid, { good: 100, poor: 300 })) }, children: formatMetric(siteData.metrics.fid, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Largest Contentful Paint:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.lcp, { good: 2500, poor: 4000 })) }, children: formatMetric(siteData.metrics.lcp, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "First Contentful Paint:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.fcp, { good: 1800, poor: 3000 })) }, children: formatMetric(siteData.metrics.fcp, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Time to First Byte:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.ttfb, { good: 800, poor: 1800 })) }, children: formatMetric(siteData.metrics.ttfb, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Speed Index:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.speedIndex, { good: 3400, poor: 5800 })) }, children: formatMetric(siteData.metrics.speedIndex, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Time to Interactive:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.interactive, { good: 3800, poor: 7300 })) }, children: formatMetric(siteData.metrics.interactive, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "Total Blocking Time:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.totalBlockingTime, { good: 200, poor: 600 })) }, children: formatMetric(siteData.metrics.totalBlockingTime, 'ms') })] }), _jsxs("div", { className: "health-cwv-item", children: [_jsx("span", { className: "health-cwv-label", children: "First Meaningful Paint:" }), _jsx("span", { className: "health-cwv-value", style: { color: getStatusColor(getMetricStatus(siteData.metrics.firstMeaningfulPaint, { good: 2000, poor: 4000 })) }, children: formatMetric(siteData.metrics.firstMeaningfulPaint, 'ms') })] })] })] }), _jsxs("p", { className: "health-timestamp", children: ["Last checked: ", new Date(siteData.timestamp).toLocaleString()] })] }));
64
71
  } }));
65
72
  }
@@ -1,8 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCallback } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { SiteHealthTemplate } from './site-health-template';
5
6
  import { getScoreIndicator } from './site-health-indicators';
7
+ SiteHealthPerformance.propTypes = {
8
+ siteName: PropTypes.string.isRequired,
9
+ };
6
10
  export function SiteHealthPerformance({ siteName }) {
7
11
  const fetchCWVData = useCallback(async (site) => {
8
12
  const response = await fetch(`/api/site-health/core-web-vitals?siteName=${encodeURIComponent(site)}`);
@@ -1,8 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCallback } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { SiteHealthTemplate } from './site-health-template';
5
6
  import { getScoreIndicator } from './site-health-indicators';
7
+ SiteHealthSecurity.propTypes = {
8
+ siteName: PropTypes.string.isRequired,
9
+ };
6
10
  export function SiteHealthSecurity({ siteName }) {
7
11
  const fetchSecurityData = useCallback(async (site) => {
8
12
  // Fetch PSI data for best practices security audits
@@ -161,7 +165,7 @@ export function SiteHealthSecurity({ siteName }) {
161
165
  width: `${(psiData.scores['best-practices'] || 0) * 100}%`,
162
166
  backgroundColor: getScoreColor(psiData.scores['best-practices'])
163
167
  } }) })] }) })), psiData.categories['best-practices'] && psiData.categories['best-practices'].audits.length > 0 && (_jsxs("div", { children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "Security Best Practices" }), _jsx("div", { className: "space-y-2", children: psiData.categories['best-practices'].audits
164
- .filter(audit => audit.scoreDisplayMode !== 'notApplicable')
168
+ .filter((audit) => audit.scoreDisplayMode !== 'notApplicable')
165
169
  .sort((a, b) => (b.score || 0) - (a.score || 0))
166
170
  .slice(0, 20)
167
171
  .map((audit) => (_jsxs("div", { className: "health-audit-item", children: [_jsx("span", { className: "health-audit-icon", children: getAuditScoreIcon(audit.score) }), _jsxs("div", { className: "health-audit-content", children: [_jsxs("span", { className: "health-audit-title", children: ["(", Math.round((audit.score || 0) * 100), "%) ", audit.title] }), audit.displayValue && (_jsx("p", { className: "health-audit-description", children: audit.displayValue })), audit.details?.items && Array.isArray(audit.details.items) && audit.details.items.length > 0 && (audit.score || 0) < 0.9 && (_jsx("div", { className: "health-audit-details", children: _jsx("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: audit.details.items.map((item, idx) => (_jsx("div", { style: { marginBottom: '0.125rem' }, children: formatAuditItem(item, audit.title) }, idx))) }) }))] })] }, audit.id))) })] })), _jsxs("p", { className: "health-timestamp", children: ["Last checked: ", new Date(psiData.timestamp).toLocaleString()] })] }));
@@ -1,8 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCallback } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { SiteHealthTemplate } from './site-health-template';
5
6
  import { getScoreIndicator } from './site-health-indicators';
7
+ SiteHealthSEO.propTypes = {
8
+ siteName: PropTypes.string.isRequired,
9
+ };
6
10
  export function SiteHealthSEO({ siteName }) {
7
11
  const fetchSEOData = useCallback(async (site) => {
8
12
  const response = await fetch(`/api/site-health/core-web-vitals?siteName=${encodeURIComponent(site)}`);
@@ -116,7 +120,7 @@ export function SiteHealthSEO({ siteName }) {
116
120
  width: `${(siteData.scores.seo || 0) * 100}%`,
117
121
  backgroundColor: getScoreColor(siteData.scores.seo)
118
122
  } }) })] }) })), siteData.categories.seo && siteData.categories.seo.audits.length > 0 && (_jsxs("div", { children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "SEO Issues & Recommendations" }), _jsx("div", { className: "space-y-2", children: siteData.categories.seo.audits
119
- .filter(audit => audit.scoreDisplayMode !== 'notApplicable')
123
+ .filter((audit) => audit.scoreDisplayMode !== 'notApplicable')
120
124
  .sort((a, b) => (b.score || 0) - (a.score || 0))
121
125
  .slice(0, 20)
122
126
  .map((audit) => (_jsxs("div", { className: "health-audit-item", children: [_jsx("span", { className: "health-audit-icon", children: getAuditScoreIcon(audit.score) }), _jsxs("div", { className: "health-audit-content", children: [_jsxs("span", { className: "health-audit-title", children: ["(", Math.round((audit.score || 0) * 100), "%) ", audit.title] }), audit.displayValue && (_jsx("p", { className: "health-audit-description", children: audit.displayValue })), audit.details?.items && Array.isArray(audit.details.items) && audit.details.items.length > 0 && (audit.score || 0) < 1.0 && (_jsx("div", { className: "health-audit-details", children: _jsx("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: audit.details.items.map((item, idx) => (_jsx("div", { style: { marginBottom: '0.125rem' }, children: formatAuditItem(item, audit.title) }, idx))) }) }))] })] }, audit.id))) })] })), _jsxs("p", { className: "health-timestamp", children: ["Last checked: ", new Date(siteData.timestamp).toLocaleString()] })] }));
@@ -1,15 +1,25 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { PageGridItem } from '../../general/semantic';
5
- export function SiteHealthTemplate({ siteName, title, children, fetchData, enableCacheControl = false, columnSpan = 1 }) {
6
+ SiteHealthTemplate.propTypes = {
7
+ siteName: PropTypes.string.isRequired,
8
+ title: PropTypes.string,
9
+ children: PropTypes.func.isRequired,
10
+ fetchData: PropTypes.func.isRequired,
11
+ enableCacheControl: PropTypes.bool,
12
+ columnSpan: PropTypes.number,
13
+ };
14
+ export function SiteHealthTemplate(props) {
15
+ const typedProps = props;
6
16
  const [data, setData] = useState(null);
7
17
  const [loading, setLoading] = useState(false);
8
18
  const [error, setError] = useState(null);
9
19
  useEffect(() => {
10
20
  let isMounted = true;
11
21
  const loadData = async () => {
12
- if (!siteName) {
22
+ if (!typedProps.siteName) {
13
23
  if (isMounted) {
14
24
  setData(null);
15
25
  setLoading(false);
@@ -25,8 +35,8 @@ export function SiteHealthTemplate({ siteName, title, children, fetchData, enabl
25
35
  // Check for cache control from URL query parameters
26
36
  const urlParams = new URLSearchParams(window.location.search);
27
37
  const cacheParam = urlParams.get('cache');
28
- const useCache = enableCacheControl ? (cacheParam !== 'false') : true;
29
- const result = await fetchData(siteName, useCache);
38
+ const useCache = typedProps.enableCacheControl ? (cacheParam !== 'false') : true;
39
+ const result = await typedProps.fetchData(typedProps.siteName, useCache);
30
40
  if (isMounted) {
31
41
  setData(result);
32
42
  setError(null);
@@ -48,15 +58,15 @@ export function SiteHealthTemplate({ siteName, title, children, fetchData, enabl
48
58
  return () => {
49
59
  isMounted = false;
50
60
  };
51
- }, [siteName, fetchData]);
61
+ }, [typedProps.siteName, typedProps.fetchData]);
52
62
  // If no site selected, show nothing
53
- if (!siteName) {
63
+ if (!typedProps.siteName) {
54
64
  return null;
55
65
  }
56
66
  // If title is provided, render the complete card structure
57
- if (title) {
58
- return (_jsxs(PageGridItem, { className: "health-card", columnSpan: columnSpan, children: [_jsx("h2", { className: "health-card-title", children: title }), _jsx("div", { className: "health-card-content", children: loading ? (_jsxs("div", { className: "health-loading", children: [_jsx("div", { className: "health-loading-spinner" }), _jsx("p", { className: "health-loading-text", children: "Loading..." })] })) : error ? (_jsx("div", { className: "health-error", children: _jsxs("p", { className: "health-error-text", children: ["Error: ", error] }) })) : (children(data)) })] }));
67
+ if (typedProps.title) {
68
+ return (_jsxs(PageGridItem, { className: "health-card", columnSpan: typedProps.columnSpan, children: [_jsx("h2", { className: "health-card-title", children: typedProps.title }), _jsx("div", { className: "health-card-content", children: loading ? (_jsxs("div", { className: "health-loading", children: [_jsx("div", { className: "health-loading-spinner" }), _jsx("p", { className: "health-loading-text", children: "Loading..." })] })) : error ? (_jsx("div", { className: "health-error", children: _jsxs("p", { className: "health-error-text", children: ["Error: ", error] }) })) : (typedProps.children(data)) })] }));
59
69
  }
60
70
  // Legacy mode: render content directly without wrapper
61
- return (_jsx(_Fragment, { children: loading ? (_jsxs("div", { className: "health-loading", children: [_jsx("div", { className: "health-loading-spinner" }), _jsx("p", { className: "health-loading-text", children: "Loading..." })] })) : error ? (_jsx("div", { className: "health-error", children: _jsxs("p", { className: "health-error-text", children: ["Error: ", error] }) })) : (children(data)) }));
71
+ return (_jsx(_Fragment, { children: loading ? (_jsxs("div", { className: "health-loading", children: [_jsx("div", { className: "health-loading-spinner" }), _jsx("p", { className: "health-loading-text", children: "Loading..." })] })) : error ? (_jsx("div", { className: "health-error", children: _jsxs("p", { className: "health-error-text", children: ["Error: ", error] }) })) : (typedProps.children(data)) }));
62
72
  }
@@ -1,6 +1,10 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import PropTypes from 'prop-types';
3
4
  import { SiteHealthTemplate } from './site-health-template';
5
+ SiteHealthUptime.propTypes = {
6
+ siteName: PropTypes.string.isRequired,
7
+ };
4
8
  export function SiteHealthUptime({ siteName }) {
5
9
  const fetchUptimeData = async (site) => {
6
10
  const response = await fetch(`/api/site-health/uptime?siteName=${encodeURIComponent(site)}`);
@@ -89,16 +89,6 @@ CalloutButton.propTypes = {
89
89
  url: PropTypes.string.isRequired,
90
90
  target: PropTypes.string
91
91
  };
92
- /* export function CalloutButton( { title, url, target } : CalloutButtonType) {
93
- return (
94
- <div className="callout-button">
95
- { (url)
96
- ? <button type="button" className="callout-button"><a href={url || ""} target={target || ""} rel={target=="_blank" ? "noopener noreferrer" : ""}>{title}</a></button>
97
- : null
98
- }
99
- </div>
100
- );
101
- } */
102
92
  export function CalloutButton({ title, url, target }) {
103
93
  const handleClick = () => {
104
94
  if (target === '_blank') {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef } from 'react';
4
- import PropTypes /* , { InferProps } */ from 'prop-types';
4
+ import PropTypes from 'prop-types';
5
5
  import { SmartImage } from '../cms/smartimage';
6
6
  import { usePixelatedConfig } from '../config/config.client';
7
7
  import { DragHandler } from './carousel.drag';
@@ -11,11 +11,22 @@ function capitalize(str) {
11
11
  }
12
12
  /* ========== CAROUSEL ========== */
13
13
  Carousel.propTypes = {
14
- cards: PropTypes.array.isRequired,
14
+ cards: PropTypes.arrayOf(PropTypes.shape({
15
+ index: PropTypes.number.isRequired,
16
+ cardIndex: PropTypes.number.isRequired,
17
+ cardLength: PropTypes.number.isRequired,
18
+ link: PropTypes.string,
19
+ linkTarget: PropTypes.string,
20
+ image: PropTypes.string.isRequired,
21
+ imageAlt: PropTypes.string,
22
+ imgFit: PropTypes.oneOf(['contain', 'cover', 'fill']),
23
+ headerText: PropTypes.string,
24
+ subHeaderText: PropTypes.string,
25
+ bodyText: PropTypes.string,
26
+ })).isRequired,
15
27
  draggable: PropTypes.bool,
16
28
  imgFit: PropTypes.oneOf(['contain', 'cover', 'fill'])
17
29
  };
18
- // export type CarouselType = InferProps<typeof Carousel.propTypes>;
19
30
  export function Carousel(props) {
20
31
  const debug = false;
21
32
  let timer = useRef(null);
@@ -74,7 +85,7 @@ export function Carousel(props) {
74
85
  console.log('CarouselSimple: Dragging disabled');
75
86
  }
76
87
  if (props.cards && props.cards.length > 0) {
77
- return (_jsxs("div", { className: "carousel-container", children: [_jsx("div", { className: "carousel-cards-container", children: props.cards.map((card, i) => (_jsx(CarouselCard, { index: i, cardIndex: cardIndex, cardLength: props.cards.length, link: card.link, linkTarget: card.linkTarget || '_self', image: card.image, imageAlt: card.imageAlt, imgFit: props.imgFit ? props.imgFit : 'fill', headerText: card.headerText, subHeaderText: card.subHeaderText, bodyText: card.bodyText }, i))) }), _jsxs("div", { className: "carousel-buttons", children: [_jsx(CarouselButton, { clickFunction: previousCard, glyph: '\u25C0' }), _jsx(CarouselButton, { clickFunction: stopTimer, glyph: '\u23F8' }), _jsx(CarouselButton, { clickFunction: nextCard, glyph: '\u25B6' })] })] }));
88
+ return (_jsxs("div", { className: "carousel-container", children: [_jsx("div", { className: "carousel-cards-container", children: props.cards.map((card, i) => (_jsx(CarouselCard, { index: i, cardIndex: cardIndex, cardLength: props.cards.length, link: card.link, linkTarget: card.linkTarget || '_self', image: card.image, imageAlt: card.imageAlt, imgFit: (props.imgFit || 'fill'), headerText: card.headerText, subHeaderText: card.subHeaderText, bodyText: card.bodyText }, i))) }), _jsxs("div", { className: "carousel-buttons", children: [_jsx(CarouselButton, { clickFunction: previousCard, glyph: '\u25C0' }), _jsx(CarouselButton, { clickFunction: stopTimer, glyph: '\u23F8' }), _jsx(CarouselButton, { clickFunction: nextCard, glyph: '\u25B6' })] })] }));
78
89
  }
79
90
  else {
80
91
  return (_jsx("div", { className: 'section-container', children: _jsx("div", { className: "carousel-container", children: _jsx(CarouselLoading, {}) }) }));
@@ -7,7 +7,7 @@ import { usePixelatedConfig } from '../config/config.client';
7
7
  import "../../css/pixelated.grid.scss";
8
8
  import "./tiles.css";
9
9
  Tiles.propTypes = {
10
- cards: PropTypes.object.isRequired,
10
+ cards: PropTypes.array.isRequired,
11
11
  rowCount: PropTypes.number,
12
12
  };
13
13
  export function Tiles(props) {
@@ -5,7 +5,7 @@ import PropTypes from "prop-types";
5
5
  import { Carousel } from '../carousel/carousel';
6
6
  import { getContentfulEntriesByType, getContentfulEntryByEntryID } from "./contentful.delivery";
7
7
  import { usePixelatedConfig } from '../config/config.client';
8
- import { AddToShoppingCart } from "../shoppingcart/shoppingcart.functions";
8
+ import { addToShoppingCart } from "../shoppingcart/shoppingcart.functions";
9
9
  import { AddToCartButton, /* GoToCartButton */ ViewItemDetails } from "../shoppingcart/shoppingcart.components";
10
10
  import { getCloudinaryRemoteFetchURL as getImg } from "./cloudinary";
11
11
  // import { Loading, ToggleLoading } from "../general/pixelated.loading";
@@ -135,7 +135,7 @@ export function ContentfulListItem(props) {
135
135
  ? _jsx(ContentfulItemHeader, { url: itemURL, target: itemURLTarget, title: thisItem.fields.title })
136
136
  : _jsx(ContentfulItemHeader, { title: thisItem.fields.title }) }), _jsxs("div", { className: "contentful-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.sys.id] }), _jsxs("div", { children: [_jsx("b", { children: "UPC ID: " }), thisItem.fields.id] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.fields.quantity] }), _jsxs("div", { children: [_jsx("b", { children: "Brand / Model: " }), thisItem.fields.brand, " ", thisItem.fields.model] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.fields.date] })] }), _jsx("div", { className: "contentful-item-price", children: itemURL
137
137
  ? _jsxs("a", { href: itemURL, target: itemURLTarget, rel: "noreferrer", children: ["$", thisItem.fields.price, " USD"] })
138
- : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsxs("div", { className: "contentful-item-addtocart", children: [_jsx(ViewItemDetails, { href: "/store", itemID: thisItem.sys.id }), _jsx(AddToCartButton, { handler: AddToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id })] })] })] }));
138
+ : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsxs("div", { className: "contentful-item-addtocart", children: [_jsx(ViewItemDetails, { href: "/store", itemID: thisItem.sys.id }), _jsx(AddToCartButton, { handler: addToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id })] })] })] }));
139
139
  }
140
140
  /* ========== CONTENTFUL ITEM HEADER ========== */
141
141
  ContentfulItemHeader.propTypes = {
@@ -156,7 +156,6 @@ ContentfulItemDetail.propTypes = {
156
156
  };
157
157
  export function ContentfulItemDetail(props) {
158
158
  const [item, setItem] = useState({});
159
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
160
159
  const [assets, setAssets] = useState({});
161
160
  const [cards, setCards] = useState([]);
162
161
  const providerContentfulApiProps = usePixelatedConfig()?.contentful;
@@ -235,7 +234,7 @@ export function ContentfulItemDetail(props) {
235
234
  ? _jsx(ContentfulItemHeader, { url: itemURL, title: thisItem.fields.title })
236
235
  : _jsx(ContentfulItemHeader, { title: thisItem.fields.title }) }), _jsx("br", {}), _jsx("div", { className: "contentful-item-photo-carousel grid-s1-e7", children: _jsx(Carousel, { cards: cards, draggable: true, imgFit: "contain" }) }), _jsxs("div", { className: "grid-s7-e13", children: [_jsx("div", { className: "contentful-item-details grid12", children: _jsx("div", { dangerouslySetInnerHTML: { __html: thisItem.fields.description.replace(/(<br\s*\/?>\s*){2,}/gi, '') } }) }), _jsx("br", {}), _jsxs("div", { className: "contentful-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.sys.id] }), _jsxs("div", { children: [_jsx("b", { children: "UPC ID: " }), thisItem.fields.id] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.fields.quantity] }), _jsxs("div", { children: [_jsx("b", { children: "Brand / Model: " }), thisItem.fields.brand, " ", thisItem.fields.model] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.fields.date] }), _jsx("br", {})] }), _jsx("div", { className: "contentful-item-price", children: itemURL
237
236
  ? _jsxs("a", { href: itemURL, target: itemURLTarget, rel: "noreferrer", children: ["$", thisItem.fields.price, " USD"] })
238
- : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsx("div", { className: "contentful-item-addtocart", children: _jsx(AddToCartButton, { handler: AddToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id }) })] })] }) }));
237
+ : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsx("div", { className: "contentful-item-addtocart", children: _jsx(AddToCartButton, { handler: addToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id }) })] })] }) }));
239
238
  }
240
239
  else {
241
240
  return (_jsx(_Fragment, { children: _jsx("div", { id: "contentful-items", className: "contentful-items", children: _jsx("div", { className: "centered", children: "Loading..." }) }) }));
@@ -41,7 +41,7 @@ function getFlickrSize(size) {
41
41
  default: return '';
42
42
  }
43
43
  }
44
- GetFlickrData.PropTypes = {
44
+ GetFlickrData.propTypes = {
45
45
  flickr: PropTypes.object,
46
46
  config: PropTypes.object,
47
47
  };
@@ -22,9 +22,9 @@ export function GoogleReviewsCard(props) {
22
22
  try {
23
23
  const result = await getGoogleReviewsByPlaceId({
24
24
  placeId: props.placeId,
25
- language: props.language,
26
- maxReviews: props.maxReviews,
27
- proxyBase: props.proxyBase,
25
+ language: props.language ?? undefined,
26
+ maxReviews: props.maxReviews ?? undefined,
27
+ proxyBase: props.proxyBase ?? undefined,
28
28
  apiKey: props.apiKey || GOOGLE_MAPS_API_KEY,
29
29
  });
30
30
  setPlace(result.place);