@pixelated-tech/components 3.3.6 → 3.4.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.
- package/README.COMPONENTS.md +126 -0
- package/README.md +14 -7
- package/dist/components/admin/componentusage/componentAnalysis.js +144 -0
- package/dist/components/admin/componentusage/componentDiscovery.js +85 -0
- package/dist/components/admin/deploy/deployment.integration.js +170 -0
- package/dist/components/admin/site-health/google-api-auth.js +69 -0
- package/dist/components/admin/site-health/seo-metrics.config.json +265 -0
- package/dist/components/admin/site-health/site-health-accessibility.js +158 -0
- package/dist/components/admin/site-health/site-health-axe-core.integration.js +119 -0
- package/dist/components/admin/site-health/site-health-axe-core.js +53 -0
- package/dist/components/admin/site-health/site-health-cache.js +23 -0
- package/dist/components/admin/site-health/site-health-core-web-vitals.integration.js +208 -0
- package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +38 -0
- package/dist/components/admin/site-health/site-health-github.integration.js +81 -0
- package/dist/components/admin/site-health/site-health-github.js +34 -0
- package/dist/components/admin/site-health/site-health-google-analytics.integration.js +112 -0
- package/dist/components/admin/site-health/site-health-google-analytics.js +43 -0
- package/dist/components/admin/site-health/site-health-google-search-console.integration.js +118 -0
- package/dist/components/admin/site-health/site-health-google-search-console.js +43 -0
- package/dist/components/admin/site-health/site-health-indicators.js +71 -0
- package/dist/components/admin/site-health/site-health-on-site-seo.integration.js +578 -0
- package/dist/components/admin/site-health/site-health-on-site-seo.js +204 -0
- package/dist/components/admin/site-health/site-health-overview.js +65 -0
- package/dist/components/admin/site-health/site-health-performance.js +191 -0
- package/dist/components/admin/site-health/site-health-security.integration.js +109 -0
- package/dist/components/admin/site-health/site-health-security.js +169 -0
- package/dist/components/admin/site-health/site-health-seo.js +124 -0
- package/dist/components/admin/site-health/site-health-template.js +62 -0
- package/dist/components/admin/site-health/site-health-types.js +1 -0
- package/dist/components/admin/site-health/site-health-uptime.integration.js +29 -0
- package/dist/components/admin/site-health/site-health-uptime.js +30 -0
- package/dist/components/admin/site-health/site-health.css +427 -0
- package/dist/components/admin/sites/sites.integration.js +117 -0
- package/dist/components/cms/contentful.management.js +104 -0
- package/dist/components/shoppingcart/shipping.from.json +101 -0
- package/dist/components/shoppingcart/shipping.parcel.json +112 -0
- package/dist/components/shoppingcart/shipping.to.json +422 -0
- package/dist/components/shoppingcart/shoppingCartDiscountCodes.json +26 -0
- package/dist/components/shoppingcart/shoppingcart.components.js +1 -1
- package/dist/components/sitebuilder/config/ConfigBuilder.js +36 -140
- package/dist/components/sitebuilder/config/siteinfo-form.json +200 -0
- package/dist/components/sitebuilder/config/visualdesignform.json +244 -0
- package/dist/components/structured/buzzwordbingo.js +3 -2
- package/dist/data/404-data.json +128 -102
- package/dist/data/flickr.json +25 -0
- package/dist/data/form.json +368 -368
- package/dist/data/recipes.json +3251 -3251
- package/dist/data/references.json +138 -137
- package/dist/data/requestform.json +111 -0
- package/dist/data/requests.json +136 -135
- package/dist/data/resume.json +2573 -2575
- package/dist/data/routes.json +238 -238
- package/dist/data/routes2.json +141 -140
- package/dist/index.js +16 -3
- package/dist/index.server.js +36 -15
- package/dist/types/components/admin/componentusage/componentAnalysis.d.ts +35 -0
- package/dist/types/components/admin/componentusage/componentAnalysis.d.ts.map +1 -0
- package/dist/types/components/admin/componentusage/componentDiscovery.d.ts +10 -0
- package/dist/types/components/admin/componentusage/componentDiscovery.d.ts.map +1 -0
- package/dist/types/components/admin/deploy/deployment.integration.d.ts +26 -0
- package/dist/types/components/admin/deploy/deployment.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/google-api-auth.d.ts +37 -0
- package/dist/types/components/admin/site-health/google-api-auth.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-accessibility.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-accessibility.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-axe-core.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-axe-core.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-axe-core.integration.d.ts +63 -0
- package/dist/types/components/admin/site-health/site-health-axe-core.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-cache.d.ts +12 -0
- package/dist/types/components/admin/site-health/site-health-cache.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-core-web-vitals.integration.d.ts +3 -0
- package/dist/types/components/admin/site-health/site-health-core-web-vitals.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-github.d.ts +8 -0
- package/dist/types/components/admin/site-health/site-health-github.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-github.integration.d.ts +26 -0
- package/dist/types/components/admin/site-health/site-health-github.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts +8 -0
- package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts +26 -0
- package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts +8 -0
- package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts +46 -0
- package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-indicators.d.ts +73 -0
- package/dist/types/components/admin/site-health/site-health-indicators.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts +4 -0
- package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts +34 -0
- package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-overview.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-overview.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-performance.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-performance.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-security.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-security.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-security.integration.d.ts +29 -0
- package/dist/types/components/admin/site-health/site-health-security.integration.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-seo.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-seo.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-template.d.ts +12 -0
- package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-types.d.ts +186 -0
- package/dist/types/components/admin/site-health/site-health-types.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-uptime.d.ts +6 -0
- package/dist/types/components/admin/site-health/site-health-uptime.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-uptime.integration.d.ts +10 -0
- package/dist/types/components/admin/site-health/site-health-uptime.integration.d.ts.map +1 -0
- package/dist/types/components/admin/sites/sites.integration.d.ts +40 -0
- package/dist/types/components/admin/sites/sites.integration.d.ts.map +1 -0
- package/dist/types/components/cms/contentful.management.d.ts +41 -0
- package/dist/types/components/cms/contentful.management.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +4 -4
- package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -1
- package/dist/types/components/structured/buzzwordbingo.d.ts +1 -1
- package/dist/types/components/structured/buzzwordbingo.d.ts.map +1 -1
- package/dist/types/components/structured/buzzwordbingo.words.d.ts +2 -0
- package/dist/types/components/structured/buzzwordbingo.words.d.ts.map +1 -0
- package/dist/types/index.d.ts +16 -3
- package/dist/types/index.server.d.ts +36 -13
- package/dist/types/stories/admin/preview.d.ts +12 -0
- package/dist/types/stories/admin/preview.d.ts.map +1 -0
- package/dist/types/stories/admin/site-health.stories.d.ts +65 -0
- package/dist/types/stories/admin/site-health.stories.d.ts.map +1 -0
- package/dist/types/stories/structured/buzzword-bingo.stories.d.ts +1 -1
- package/dist/types/stories/structured/buzzword-bingo.stories.d.ts.map +1 -1
- package/dist/types/tests/site-health-axe-core.test.d.ts +2 -0
- package/dist/types/tests/site-health-axe-core.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-cache.test.d.ts +2 -0
- package/dist/types/tests/site-health-cache.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-indicators.test.d.ts +2 -0
- package/dist/types/tests/site-health-indicators.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-overview.test.d.ts +2 -0
- package/dist/types/tests/site-health-overview.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-template.test.d.ts +2 -0
- package/dist/types/tests/site-health-template.test.d.ts.map +1 -0
- package/dist/types/tests/sites.integration.test.d.ts +2 -0
- package/dist/types/tests/sites.integration.test.d.ts.map +1 -0
- package/package.json +14 -8
- package/dist/data/shipping.to.json +0 -422
- package/dist/data/siteinfo-form.json +0 -200
- package/dist/data/visualdesignform.json +0 -244
- package/dist/types/data/buzzwords.d.ts +0 -2
- package/dist/types/data/buzzwords.d.ts.map +0 -1
- /package/dist/{data/buzzwords.js → components/structured/buzzwordbingo.words.js} +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
{
|
|
2
|
+
"categories": {
|
|
3
|
+
"on-page": {
|
|
4
|
+
"name": "On-Page SEO",
|
|
5
|
+
"description": "Elements within individual page content",
|
|
6
|
+
"priority": 1,
|
|
7
|
+
"metrics": {
|
|
8
|
+
"semantic-tags": {
|
|
9
|
+
"id": "semantic-tags",
|
|
10
|
+
"title": "Semantic HTML Tags",
|
|
11
|
+
"description": "Checks for proper semantic HTML structure",
|
|
12
|
+
"scoreDisplayMode": "binary",
|
|
13
|
+
"dataCollector": "collectSemanticTagsData",
|
|
14
|
+
"scorer": "calculateSemanticTagsScore"
|
|
15
|
+
},
|
|
16
|
+
"title-tags": {
|
|
17
|
+
"id": "title-tags",
|
|
18
|
+
"title": "Title Tags",
|
|
19
|
+
"description": "Validates title tag presence and optimal length",
|
|
20
|
+
"scoreDisplayMode": "binary",
|
|
21
|
+
"dataCollector": "collectTitleTagsData",
|
|
22
|
+
"scorer": "calculateTitleTagsScore"
|
|
23
|
+
},
|
|
24
|
+
"meta-keywords": {
|
|
25
|
+
"id": "meta-keywords",
|
|
26
|
+
"title": "Meta Keywords",
|
|
27
|
+
"description": "Checks for meta keywords tag presence",
|
|
28
|
+
"scoreDisplayMode": "binary",
|
|
29
|
+
"dataCollector": "collectMetaKeywordsData",
|
|
30
|
+
"scorer": "calculateMetaKeywordsScore"
|
|
31
|
+
},
|
|
32
|
+
"meta-descriptions": {
|
|
33
|
+
"id": "meta-descriptions",
|
|
34
|
+
"title": "Meta Descriptions",
|
|
35
|
+
"description": "Validates meta description presence and length",
|
|
36
|
+
"scoreDisplayMode": "binary",
|
|
37
|
+
"dataCollector": "collectMetaDescriptionsData",
|
|
38
|
+
"scorer": "calculateMetaDescriptionsScore"
|
|
39
|
+
},
|
|
40
|
+
"content-type-charset": {
|
|
41
|
+
"id": "content-type-charset",
|
|
42
|
+
"title": "Content-Type and Charset",
|
|
43
|
+
"description": "Checks for proper content-type/charset declaration",
|
|
44
|
+
"scoreDisplayMode": "binary",
|
|
45
|
+
"pattern": "(<meta[^>]*http-equiv=[\"']content-type[\"'][^>]*>)|(<meta[^>]*charset=[\"'][^\"']*[\"'][^>]*>)",
|
|
46
|
+
"countLogic": "or",
|
|
47
|
+
"scoreLogic": "present",
|
|
48
|
+
"displayTemplate": "{{count}} content-type/charset declaration(s) found"
|
|
49
|
+
},
|
|
50
|
+
"viewport-tags": {
|
|
51
|
+
"id": "viewport-tags",
|
|
52
|
+
"title": "Viewport Tags",
|
|
53
|
+
"description": "Checks for viewport meta tag on mobile pages",
|
|
54
|
+
"scoreDisplayMode": "binary",
|
|
55
|
+
"pattern": "<meta[^>]*name=[\"']viewport[\"'][^>]*content=[\"'][^\"']*[\"'][^>]*>",
|
|
56
|
+
"countLogic": "count",
|
|
57
|
+
"scoreLogic": "present",
|
|
58
|
+
"displayTemplate": "{{count}} viewport tag(s) found"
|
|
59
|
+
},
|
|
60
|
+
"opengraph-tags": {
|
|
61
|
+
"id": "opengraph-tags",
|
|
62
|
+
"title": "OpenGraph Tags",
|
|
63
|
+
"description": "Checks for OpenGraph meta tags for social sharing",
|
|
64
|
+
"scoreDisplayMode": "binary",
|
|
65
|
+
"pattern": "<meta[^>]*property=[\"']og:[^\"']*[\"'][^>]*content=[\"'][^\"']*[\"'][^>]*>",
|
|
66
|
+
"countLogic": "count",
|
|
67
|
+
"scoreLogic": "present",
|
|
68
|
+
"displayTemplate": "{{count}} OpenGraph tag(s) found"
|
|
69
|
+
},
|
|
70
|
+
"preconnect-tags": {
|
|
71
|
+
"id": "preconnect-tags",
|
|
72
|
+
"title": "Preconnect Tags",
|
|
73
|
+
"description": "Checks for preconnect link tags for performance",
|
|
74
|
+
"scoreDisplayMode": "binary",
|
|
75
|
+
"pattern": "<link[^>]*rel=[\"']preconnect[\"'][^>]*>",
|
|
76
|
+
"countLogic": "count",
|
|
77
|
+
"scoreLogic": "present",
|
|
78
|
+
"displayTemplate": "{{count}} preconnect link(s) found"
|
|
79
|
+
},
|
|
80
|
+
"h1-tags": {
|
|
81
|
+
"id": "h1-tags",
|
|
82
|
+
"title": "H1 Tags",
|
|
83
|
+
"description": "Checks for proper H1 tag usage",
|
|
84
|
+
"scoreDisplayMode": "binary",
|
|
85
|
+
"pattern": "<h1[^>]*>[^<]*</h1>",
|
|
86
|
+
"countLogic": "exact",
|
|
87
|
+
"expectedCount": 1,
|
|
88
|
+
"scoreLogic": "exact",
|
|
89
|
+
"displayTemplate": "{{count}} H1 tag(s) found"
|
|
90
|
+
},
|
|
91
|
+
"h2-tags": {
|
|
92
|
+
"id": "h2-tags",
|
|
93
|
+
"title": "H2 Tags",
|
|
94
|
+
"description": "Checks for H2 tag usage",
|
|
95
|
+
"scoreDisplayMode": "binary",
|
|
96
|
+
"pattern": "<h2[^>]*>[^<]*</h2>",
|
|
97
|
+
"countLogic": "count",
|
|
98
|
+
"scoreLogic": "present",
|
|
99
|
+
"displayTemplate": "{{count}} H2 tag(s) found"
|
|
100
|
+
},
|
|
101
|
+
"canonical-urls": {
|
|
102
|
+
"id": "canonical-urls",
|
|
103
|
+
"title": "Canonical URLs",
|
|
104
|
+
"description": "Checks for canonical URL tags",
|
|
105
|
+
"scoreDisplayMode": "binary",
|
|
106
|
+
"pattern": "<link[^>]*rel=[\"']canonical[\"'][^>]*href=[\"'][^\"']*[\"'][^>]*>",
|
|
107
|
+
"countLogic": "count",
|
|
108
|
+
"scoreLogic": "present",
|
|
109
|
+
"displayTemplate": "{{count}} canonical URL(s) found"
|
|
110
|
+
},
|
|
111
|
+
"language-tags": {
|
|
112
|
+
"id": "language-tags",
|
|
113
|
+
"title": "Language Tags",
|
|
114
|
+
"description": "Checks for lang attribute on html element",
|
|
115
|
+
"scoreDisplayMode": "binary",
|
|
116
|
+
"pattern": "<html[^>]*lang=[\"'][^\"']*[\"'][^>]*>",
|
|
117
|
+
"countLogic": "count",
|
|
118
|
+
"scoreLogic": "present",
|
|
119
|
+
"displayTemplate": "{{count}} language tag(s) found"
|
|
120
|
+
},
|
|
121
|
+
"icon-tags": {
|
|
122
|
+
"id": "icon-tags",
|
|
123
|
+
"title": "Icon Tags",
|
|
124
|
+
"description": "Checks for icon link tags for browser tabs",
|
|
125
|
+
"scoreDisplayMode": "binary",
|
|
126
|
+
"pattern": "<link[^>]*rel=[\"']icon[\"'][^>]*>",
|
|
127
|
+
"countLogic": "count",
|
|
128
|
+
"scoreLogic": "present",
|
|
129
|
+
"displayTemplate": "{{count}} icon link(s) found"
|
|
130
|
+
},
|
|
131
|
+
"shortcut-icon-tags": {
|
|
132
|
+
"id": "shortcut-icon-tags",
|
|
133
|
+
"title": "Shortcut Icon Tags",
|
|
134
|
+
"description": "Checks for shortcut icon link tags for browser tabs",
|
|
135
|
+
"scoreDisplayMode": "binary",
|
|
136
|
+
"pattern": "<link[^>]*rel=[\"']shortcut icon[\"'][^>]*>",
|
|
137
|
+
"countLogic": "count",
|
|
138
|
+
"scoreLogic": "present",
|
|
139
|
+
"displayTemplate": "{{count}} shortcut icon link(s) found"
|
|
140
|
+
},
|
|
141
|
+
"manifest-tag": {
|
|
142
|
+
"id": "manifest-tag",
|
|
143
|
+
"title": "Manifest Tag",
|
|
144
|
+
"description": "Checks for manifest link tag to direct crawlers to WebManifest file",
|
|
145
|
+
"scoreDisplayMode": "binary",
|
|
146
|
+
"pattern": "<link[^>]*rel=[\"']manifest[\"'][^>]*href=[\"'][^\"']*[\"'][^>]*>",
|
|
147
|
+
"countLogic": "count",
|
|
148
|
+
"scoreLogic": "present",
|
|
149
|
+
"displayTemplate": "{{count}} manifest link(s) found"
|
|
150
|
+
},
|
|
151
|
+
"schema-markup": {
|
|
152
|
+
"id": "schema-markup",
|
|
153
|
+
"title": "Schema Markup",
|
|
154
|
+
"description": "Checks for structured data markup",
|
|
155
|
+
"scoreDisplayMode": "binary",
|
|
156
|
+
"pattern": "(<script[^>]*type=[\"']application/ld\\+json[\"'][^>]*>[^<]*</script>)|(<[^>]*itemtype=[\"'][^\"']*[\"'][^>]*>)",
|
|
157
|
+
"countLogic": "count",
|
|
158
|
+
"scoreLogic": "present",
|
|
159
|
+
"displayTemplate": "{{count}} schema markup element(s) found"
|
|
160
|
+
},
|
|
161
|
+
"twitter-cards": {
|
|
162
|
+
"id": "twitter-cards",
|
|
163
|
+
"title": "Twitter Cards",
|
|
164
|
+
"description": "Checks for Twitter Card meta tags",
|
|
165
|
+
"scoreDisplayMode": "binary",
|
|
166
|
+
"pattern": "<meta[^>]*name=[\"']twitter:[^\"']*[\"'][^>]*content=[\"'][^\"']*[\"'][^>]*>",
|
|
167
|
+
"countLogic": "count",
|
|
168
|
+
"scoreLogic": "present",
|
|
169
|
+
"displayTemplate": "{{count}} Twitter Card tag(s) found"
|
|
170
|
+
},
|
|
171
|
+
"image-alt-text": {
|
|
172
|
+
"id": "image-alt-text",
|
|
173
|
+
"title": "Image Alt Text",
|
|
174
|
+
"description": "Checks for alt text on images",
|
|
175
|
+
"scoreDisplayMode": "binary",
|
|
176
|
+
"pattern": "<img[^>]*alt=[\"'][^\"']*[\"'][^>]*>",
|
|
177
|
+
"countLogic": "count",
|
|
178
|
+
"scoreLogic": "present",
|
|
179
|
+
"displayTemplate": "{{count}} image(s) with alt text found"
|
|
180
|
+
},
|
|
181
|
+
"itemprop-tags": {
|
|
182
|
+
"id": "itemprop-tags",
|
|
183
|
+
"title": "ItemProp Tags",
|
|
184
|
+
"description": "Checks for ItemProp microdata tags for social media sharing",
|
|
185
|
+
"scoreDisplayMode": "binary",
|
|
186
|
+
"pattern": "<[^>]*itemprop=[\"'][^\"']*[\"'][^>]*>",
|
|
187
|
+
"countLogic": "count",
|
|
188
|
+
"scoreLogic": "present",
|
|
189
|
+
"displayTemplate": "{{count}} ItemProp tag(s) found"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"on-site": {
|
|
194
|
+
"name": "On-Site SEO",
|
|
195
|
+
"description": "Site-wide technical and structural elements",
|
|
196
|
+
"priority": 2,
|
|
197
|
+
"metrics": {
|
|
198
|
+
"https": {
|
|
199
|
+
"id": "https",
|
|
200
|
+
"title": "HTTPS",
|
|
201
|
+
"description": "Checks if site uses secure HTTPS protocol",
|
|
202
|
+
"scoreDisplayMode": "binary",
|
|
203
|
+
"dataCollector": null,
|
|
204
|
+
"scorer": null
|
|
205
|
+
},
|
|
206
|
+
"url-structure": {
|
|
207
|
+
"id": "url-structure",
|
|
208
|
+
"title": "URL Structure",
|
|
209
|
+
"description": "Checks for clean URL structure without excessive parameters",
|
|
210
|
+
"scoreDisplayMode": "binary",
|
|
211
|
+
"dataCollector": null,
|
|
212
|
+
"scorer": null
|
|
213
|
+
},
|
|
214
|
+
"robots-txt": {
|
|
215
|
+
"id": "robots-txt",
|
|
216
|
+
"title": "Robots.txt",
|
|
217
|
+
"description": "Checks for robots.txt file accessibility",
|
|
218
|
+
"scoreDisplayMode": "binary",
|
|
219
|
+
"dataCollector": null,
|
|
220
|
+
"scorer": null
|
|
221
|
+
},
|
|
222
|
+
"sitemap-xml": {
|
|
223
|
+
"id": "sitemap-xml",
|
|
224
|
+
"title": "Sitemap.xml",
|
|
225
|
+
"description": "Checks for sitemap.xml file accessibility",
|
|
226
|
+
"scoreDisplayMode": "binary",
|
|
227
|
+
"dataCollector": null,
|
|
228
|
+
"scorer": null
|
|
229
|
+
},
|
|
230
|
+
"internal-linking": {
|
|
231
|
+
"id": "internal-linking",
|
|
232
|
+
"title": "Internal Linking",
|
|
233
|
+
"description": "Checks for proper internal linking structure",
|
|
234
|
+
"scoreDisplayMode": "binary",
|
|
235
|
+
"dataCollector": null,
|
|
236
|
+
"scorer": null
|
|
237
|
+
},
|
|
238
|
+
"navigation": {
|
|
239
|
+
"id": "navigation",
|
|
240
|
+
"title": "Navigation",
|
|
241
|
+
"description": "Checks for proper navigation structure",
|
|
242
|
+
"scoreDisplayMode": "binary",
|
|
243
|
+
"dataCollector": null,
|
|
244
|
+
"scorer": null
|
|
245
|
+
},
|
|
246
|
+
"broken-links": {
|
|
247
|
+
"id": "broken-links",
|
|
248
|
+
"title": "Broken Links / 404s",
|
|
249
|
+
"description": "Checks for broken internal links",
|
|
250
|
+
"scoreDisplayMode": "binary",
|
|
251
|
+
"dataCollector": null,
|
|
252
|
+
"scorer": null
|
|
253
|
+
},
|
|
254
|
+
"manifest-file": {
|
|
255
|
+
"id": "manifest-file",
|
|
256
|
+
"title": "Manifest File",
|
|
257
|
+
"description": "Checks for manifest.webmanifest file accessibility",
|
|
258
|
+
"scoreDisplayMode": "binary",
|
|
259
|
+
"dataCollector": null,
|
|
260
|
+
"scorer": null
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { SiteHealthTemplate } from './site-health-template';
|
|
5
|
+
import { getScoreIndicator } from './site-health-indicators';
|
|
6
|
+
export function SiteHealthAccessibility({ siteName }) {
|
|
7
|
+
const fetchAccessibilityData = useCallback(async (site) => {
|
|
8
|
+
const response = await fetch(`/api/site-health/core-web-vitals?siteName=${encodeURIComponent(site)}`);
|
|
9
|
+
const result = await response.json();
|
|
10
|
+
if (!result.success) {
|
|
11
|
+
throw new Error(result.error || 'Failed to fetch accessibility data');
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
}, []);
|
|
15
|
+
return (_jsx(SiteHealthTemplate, { siteName: siteName, title: "PageSpeed - Accessibility", fetchData: fetchAccessibilityData, children: (data) => {
|
|
16
|
+
const getScoreColor = (score) => {
|
|
17
|
+
return getScoreIndicator(score).color;
|
|
18
|
+
};
|
|
19
|
+
const getAuditScoreIcon = (score) => {
|
|
20
|
+
return getScoreIndicator(score).icon;
|
|
21
|
+
};
|
|
22
|
+
// Helper function to display audit item details
|
|
23
|
+
const formatAuditItem = (item, auditTitle) => {
|
|
24
|
+
// Handle URLs
|
|
25
|
+
if (item.url && typeof item.url === 'string') {
|
|
26
|
+
return item.url;
|
|
27
|
+
}
|
|
28
|
+
// Handle sources (like JavaScript files)
|
|
29
|
+
if (item.source && typeof item.source === 'string') {
|
|
30
|
+
return item.source;
|
|
31
|
+
}
|
|
32
|
+
// Handle text descriptions
|
|
33
|
+
if (item.text && typeof item.text === 'string') {
|
|
34
|
+
return item.text;
|
|
35
|
+
}
|
|
36
|
+
// Handle entities (like "Google Tag Manager")
|
|
37
|
+
if (item.entity && typeof item.entity === 'string') {
|
|
38
|
+
return item.entity;
|
|
39
|
+
}
|
|
40
|
+
// Handle nodes with selectors
|
|
41
|
+
if (item.node && typeof item.node === 'object' && 'selector' in item.node) {
|
|
42
|
+
return `Element: ${item.node.selector}`;
|
|
43
|
+
}
|
|
44
|
+
// Handle nodes with snippets
|
|
45
|
+
if (item.node && typeof item.node === 'object' && 'snippet' in item.node) {
|
|
46
|
+
const snippet = item.node.snippet;
|
|
47
|
+
return `Element: ${snippet.length > 50 ? snippet.substring(0, 50) + '...' : snippet}`;
|
|
48
|
+
}
|
|
49
|
+
// Handle origins (like domains)
|
|
50
|
+
if (item.origin && typeof item.origin === 'string') {
|
|
51
|
+
return item.origin;
|
|
52
|
+
}
|
|
53
|
+
// Handle labels
|
|
54
|
+
if (item.label && typeof item.label === 'string') {
|
|
55
|
+
return item.label;
|
|
56
|
+
}
|
|
57
|
+
// Handle numeric values with units
|
|
58
|
+
if (item.value && typeof item.value === 'object' && 'type' in item.value && item.value.type === 'numeric') {
|
|
59
|
+
const value = item.value;
|
|
60
|
+
return `${value.value}${item.unit || ''}`;
|
|
61
|
+
}
|
|
62
|
+
// Handle statistics
|
|
63
|
+
if (item.statistic && typeof item.statistic === 'string' && item.value) {
|
|
64
|
+
if (typeof item.value === 'object' && 'type' in item.value && item.value.type === 'numeric') {
|
|
65
|
+
const value = item.value;
|
|
66
|
+
return `${item.statistic}: ${value.value}`;
|
|
67
|
+
}
|
|
68
|
+
return item.statistic;
|
|
69
|
+
}
|
|
70
|
+
// Handle timing data with audit context
|
|
71
|
+
if (typeof item === 'number') {
|
|
72
|
+
let context = '';
|
|
73
|
+
if (auditTitle) {
|
|
74
|
+
if (auditTitle.toLowerCase().includes('server') || auditTitle.toLowerCase().includes('backend')) {
|
|
75
|
+
context = ' server response';
|
|
76
|
+
}
|
|
77
|
+
else if (auditTitle.toLowerCase().includes('network') || auditTitle.toLowerCase().includes('request')) {
|
|
78
|
+
context = ' network request';
|
|
79
|
+
}
|
|
80
|
+
else if (auditTitle.toLowerCase().includes('render') || auditTitle.toLowerCase().includes('blocking')) {
|
|
81
|
+
context = ' render blocking';
|
|
82
|
+
}
|
|
83
|
+
else if (auditTitle.toLowerCase().includes('javascript') || auditTitle.toLowerCase().includes('js')) {
|
|
84
|
+
context = ' JavaScript';
|
|
85
|
+
}
|
|
86
|
+
else if (auditTitle.toLowerCase().includes('image') || auditTitle.toLowerCase().includes('media')) {
|
|
87
|
+
context = ' media resource';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return `${item.toFixed(2)}ms${context}`;
|
|
91
|
+
}
|
|
92
|
+
if (item.value && typeof item.value === 'number') {
|
|
93
|
+
const unit = item.unit || 'ms';
|
|
94
|
+
let context = '';
|
|
95
|
+
if (auditTitle && unit === 'ms') {
|
|
96
|
+
if (auditTitle.toLowerCase().includes('server')) {
|
|
97
|
+
context = ' server time';
|
|
98
|
+
}
|
|
99
|
+
else if (auditTitle.toLowerCase().includes('network')) {
|
|
100
|
+
context = ' network time';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return `${item.value.toFixed(2)}${unit}${context}`;
|
|
104
|
+
}
|
|
105
|
+
// If we can't find anything meaningful, show a generic message
|
|
106
|
+
return 'Details available';
|
|
107
|
+
};
|
|
108
|
+
if (!data?.data || data.data.length === 0) {
|
|
109
|
+
return (_jsx("p", { style: { color: '#6b7280' }, children: "No accessibility data available for this site." }));
|
|
110
|
+
}
|
|
111
|
+
const siteData = data.data[0];
|
|
112
|
+
if (siteData.status === 'error') {
|
|
113
|
+
return (_jsxs("p", { style: { color: '#ef4444', fontSize: '0.875rem' }, children: ["Error: ", siteData.error] }));
|
|
114
|
+
}
|
|
115
|
+
return (_jsxs(_Fragment, { children: [_jsx("h4", { className: "health-site-name", children: siteData.site.replace('-', ' ') }), _jsxs("p", { className: "health-site-url", children: ["URL: ", siteData.url] }), siteData.scores.accessibility !== null && (_jsx("div", { className: "health-score-container", children: _jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: "Accessibility Score" }), _jsxs("div", { className: "health-score-value", style: { color: getScoreColor(siteData.scores.accessibility) }, children: [Math.round((siteData.scores.accessibility || 0) * 100), "%"] }), _jsx("div", { className: "health-score-bar", children: _jsx("div", { className: "health-score-fill", style: {
|
|
116
|
+
width: `${(siteData.scores.accessibility || 0) * 100}%`,
|
|
117
|
+
backgroundColor: getScoreColor(siteData.scores.accessibility)
|
|
118
|
+
} }) })] }) })), siteData.categories.accessibility && siteData.categories.accessibility.audits.length > 0 && (_jsxs("div", { children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "Accessibility Issues & Recommendations" }), _jsx("div", { className: "space-y-2", children: siteData.categories.accessibility.audits
|
|
119
|
+
.filter(audit => audit.scoreDisplayMode !== 'notApplicable')
|
|
120
|
+
.sort((a, b) => {
|
|
121
|
+
// Prioritize specific important accessibility audits
|
|
122
|
+
const priorityAudits = [
|
|
123
|
+
'color-contrast',
|
|
124
|
+
'image-alt',
|
|
125
|
+
'label',
|
|
126
|
+
'button-name',
|
|
127
|
+
'link-name',
|
|
128
|
+
'heading-order',
|
|
129
|
+
'focusable-controls',
|
|
130
|
+
'interactive-element-affordance',
|
|
131
|
+
'logical-tab-order',
|
|
132
|
+
'focus-traps',
|
|
133
|
+
'bypass',
|
|
134
|
+
'landmark-one-main',
|
|
135
|
+
'meta-viewport',
|
|
136
|
+
'html-has-lang',
|
|
137
|
+
'html-lang-valid',
|
|
138
|
+
'video-caption',
|
|
139
|
+
'audio-caption'
|
|
140
|
+
];
|
|
141
|
+
const aPriority = priorityAudits.indexOf(a.id);
|
|
142
|
+
const bPriority = priorityAudits.indexOf(b.id);
|
|
143
|
+
// If both are priority audits, sort by priority order
|
|
144
|
+
if (aPriority !== -1 && bPriority !== -1) {
|
|
145
|
+
return aPriority - bPriority;
|
|
146
|
+
}
|
|
147
|
+
// If only one is priority, put it first
|
|
148
|
+
if (aPriority !== -1)
|
|
149
|
+
return -1;
|
|
150
|
+
if (bPriority !== -1)
|
|
151
|
+
return 1;
|
|
152
|
+
// Otherwise sort by score
|
|
153
|
+
return (b.score || 0) - (a.score || 0);
|
|
154
|
+
})
|
|
155
|
+
.slice(0, 20)
|
|
156
|
+
.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(siteData.timestamp).toLocaleString()] })] }));
|
|
157
|
+
} }));
|
|
158
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import puppeteer from 'puppeteer';
|
|
3
|
+
export async function performAxeCoreAnalysis(url) {
|
|
4
|
+
try {
|
|
5
|
+
// Run axe-core analysis
|
|
6
|
+
const axeResult = await runAxeCoreAnalysis(url);
|
|
7
|
+
// Calculate summary
|
|
8
|
+
const summary = {
|
|
9
|
+
violations: axeResult.violations.length,
|
|
10
|
+
passes: axeResult.passes.length,
|
|
11
|
+
incomplete: axeResult.incomplete.length,
|
|
12
|
+
inapplicable: axeResult.inapplicable.length,
|
|
13
|
+
critical: axeResult.violations.filter(v => v.impact === 'critical').length,
|
|
14
|
+
serious: axeResult.violations.filter(v => v.impact === 'serious').length,
|
|
15
|
+
moderate: axeResult.violations.filter(v => v.impact === 'moderate').length,
|
|
16
|
+
minor: axeResult.violations.filter(v => v.impact === 'minor').length,
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
site: '', // Will be set by the caller
|
|
20
|
+
url: url,
|
|
21
|
+
result: axeResult,
|
|
22
|
+
summary,
|
|
23
|
+
timestamp: new Date().toISOString(),
|
|
24
|
+
status: 'success',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error('Axe-core analysis failed:', error);
|
|
29
|
+
return {
|
|
30
|
+
site: '', // Will be set by the caller
|
|
31
|
+
url: url,
|
|
32
|
+
result: {
|
|
33
|
+
violations: [],
|
|
34
|
+
passes: [],
|
|
35
|
+
incomplete: [],
|
|
36
|
+
inapplicable: [],
|
|
37
|
+
testEngine: { name: 'axe-core', version: 'unknown' },
|
|
38
|
+
testRunner: { name: 'unknown' },
|
|
39
|
+
testEnvironment: {
|
|
40
|
+
userAgent: 'unknown',
|
|
41
|
+
windowWidth: 0,
|
|
42
|
+
windowHeight: 0,
|
|
43
|
+
},
|
|
44
|
+
timestamp: new Date().toISOString(),
|
|
45
|
+
url: url,
|
|
46
|
+
},
|
|
47
|
+
summary: {
|
|
48
|
+
violations: 0,
|
|
49
|
+
passes: 0,
|
|
50
|
+
incomplete: 0,
|
|
51
|
+
inapplicable: 0,
|
|
52
|
+
critical: 0,
|
|
53
|
+
serious: 0,
|
|
54
|
+
moderate: 0,
|
|
55
|
+
minor: 0,
|
|
56
|
+
},
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
status: 'error',
|
|
59
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred during axe-core analysis',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function runAxeCoreAnalysis(url) {
|
|
64
|
+
let browser;
|
|
65
|
+
try {
|
|
66
|
+
// Launch browser with options for better compatibility
|
|
67
|
+
browser = await puppeteer.launch({
|
|
68
|
+
headless: true,
|
|
69
|
+
args: [
|
|
70
|
+
'--no-sandbox',
|
|
71
|
+
'--disable-setuid-sandbox',
|
|
72
|
+
'--disable-dev-shm-usage',
|
|
73
|
+
'--disable-accelerated-2d-canvas',
|
|
74
|
+
'--no-first-run',
|
|
75
|
+
'--no-zygote',
|
|
76
|
+
'--single-process', // <- this one doesn't work in Windows
|
|
77
|
+
'--disable-gpu'
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
const page = await browser.newPage();
|
|
81
|
+
// Set viewport for consistent results
|
|
82
|
+
await page.setViewport({ width: 1280, height: 720 });
|
|
83
|
+
// Set user agent to avoid bot detection
|
|
84
|
+
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
|
|
85
|
+
// Navigate to the page with timeout
|
|
86
|
+
await page.goto(url, {
|
|
87
|
+
waitUntil: 'networkidle2',
|
|
88
|
+
timeout: 30000
|
|
89
|
+
});
|
|
90
|
+
// Wait a bit for dynamic content to load
|
|
91
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
92
|
+
// Inject axe-core by adding the script tag
|
|
93
|
+
await page.addScriptTag({
|
|
94
|
+
url: 'https://cdn.jsdelivr.net/npm/axe-core@4.8.2/axe.min.js'
|
|
95
|
+
});
|
|
96
|
+
// Wait a bit for axe to load
|
|
97
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
98
|
+
// Run axe-core analysis
|
|
99
|
+
const result = await page.evaluate(async () => {
|
|
100
|
+
// Check if axe is available
|
|
101
|
+
if (typeof window.axe === 'undefined') {
|
|
102
|
+
throw new Error('axe-core not loaded');
|
|
103
|
+
}
|
|
104
|
+
// Run axe with all rules enabled
|
|
105
|
+
const axeResults = await window.axe.run(document, {
|
|
106
|
+
rules: {}, // Run all rules
|
|
107
|
+
runOnly: undefined, // Don't restrict to specific rule sets
|
|
108
|
+
reporter: 'v2'
|
|
109
|
+
});
|
|
110
|
+
return axeResults;
|
|
111
|
+
});
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
if (browser) {
|
|
116
|
+
await browser.close();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { SiteHealthTemplate } from './site-health-template';
|
|
5
|
+
import { getImpactIndicator, getIncompleteIndicator, getPassingIndicator } from './site-health-indicators';
|
|
6
|
+
export function SiteHealthAxeCore({ siteName }) {
|
|
7
|
+
const fetchAxeCoreData = useCallback(async (site) => {
|
|
8
|
+
const response = await fetch(`/api/site-health/axe-core?siteName=${encodeURIComponent(site)}`);
|
|
9
|
+
const result = await response.json();
|
|
10
|
+
if (!result.success) {
|
|
11
|
+
throw new Error(result.error || 'Failed to fetch axe-core data');
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
}, []);
|
|
15
|
+
const getImpactColor = (impact) => {
|
|
16
|
+
return getImpactIndicator(impact).color;
|
|
17
|
+
};
|
|
18
|
+
const getImpactIcon = (impact) => {
|
|
19
|
+
return getImpactIndicator(impact).icon;
|
|
20
|
+
};
|
|
21
|
+
const formatNodeInfo = (node) => {
|
|
22
|
+
if (node.target && Array.isArray(node.target) && node.target.length > 0) {
|
|
23
|
+
// Return the CSS selector
|
|
24
|
+
return node.target.join(', ');
|
|
25
|
+
}
|
|
26
|
+
if (node.html) {
|
|
27
|
+
// Return a truncated version of the HTML
|
|
28
|
+
const html = node.html;
|
|
29
|
+
return html.length > 100 ? html.substring(0, 100) + '...' : html;
|
|
30
|
+
}
|
|
31
|
+
return 'Unknown element';
|
|
32
|
+
};
|
|
33
|
+
return (_jsx(SiteHealthTemplate, { siteName: siteName, title: "Axe-Core Accessibility", fetchData: fetchAxeCoreData, children: (data) => {
|
|
34
|
+
if (!data?.data || data.data.length === 0) {
|
|
35
|
+
return (_jsx("p", { style: { color: '#6b7280' }, children: "No axe-core data available for this site." }));
|
|
36
|
+
}
|
|
37
|
+
const siteData = data.data[0];
|
|
38
|
+
if (siteData.status === 'error') {
|
|
39
|
+
return (_jsxs("p", { style: { color: '#ef4444', fontSize: '0.875rem' }, children: ["Error: ", siteData.error] }));
|
|
40
|
+
}
|
|
41
|
+
const { result, summary } = siteData;
|
|
42
|
+
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: _jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: "Accessibility Summary" }), _jsxs("div", { className: "health-score-grid", children: [_jsxs("div", { className: "health-stat-item", children: [_jsx("span", { className: "health-stat-label", children: "Violations : " }), _jsx("span", { className: "health-stat-value", style: { color: summary.violations > 0 ? '#ef4444' : '#10b981' }, children: summary.violations })] }), _jsxs("div", { className: "health-stat-item", children: [_jsx("span", { className: "health-stat-label", children: "Passes : " }), _jsx("span", { className: "health-stat-value", style: { color: '#10b981' }, children: summary.passes })] }), _jsxs("div", { className: "health-stat-item", children: [_jsx("span", { className: "health-stat-label", children: "Incomplete : " }), _jsx("span", { className: "health-stat-value", style: { color: '#f59e0b' }, children: summary.incomplete })] })] })] }) }), summary.violations > 0 && (_jsx("div", { className: "health-score-container", children: _jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: "Violation Impact Levels" }), _jsxs("div", { className: "health-score-grid", children: [_jsxs("div", { className: "health-stat-item", children: [_jsx("span", { className: "health-stat-label", children: "Critical : " }), _jsx("span", { className: "health-stat-value", style: { color: getImpactColor('critical') }, children: summary.critical })] }), _jsxs("div", { className: "health-stat-item", children: [_jsx("span", { className: "health-stat-label", children: "Serious : " }), _jsx("span", { className: "health-stat-value", style: { color: getImpactColor('serious') }, children: summary.serious })] }), _jsxs("div", { className: "health-stat-item", children: [_jsx("span", { className: "health-stat-label", children: "Moderate : " }), _jsx("span", { className: "health-stat-value", style: { color: getImpactColor('moderate') }, children: summary.moderate })] }), _jsxs("div", { className: "health-stat-item", children: [_jsx("span", { className: "health-stat-label", children: "Minor : " }), _jsx("span", { className: "health-stat-value", style: { color: getImpactColor('minor') }, children: summary.minor })] })] })] }) })), result.violations.length > 0 && (_jsxs("div", { children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "Accessibility Violations" }), _jsx("div", { className: "space-y-2", children: result.violations
|
|
43
|
+
.sort((a, b) => {
|
|
44
|
+
const impactOrder = { critical: 4, serious: 3, moderate: 2, minor: 1 };
|
|
45
|
+
return impactOrder[b.impact] - impactOrder[a.impact];
|
|
46
|
+
})
|
|
47
|
+
.slice(0, 20)
|
|
48
|
+
.map((violation) => (_jsxs("div", { className: "health-audit-item", children: [_jsx("span", { className: "health-audit-icon", children: getImpactIcon(violation.impact) }), _jsxs("div", { className: "health-audit-content", children: [_jsxs("span", { className: "health-audit-title", children: [violation.help, " (", violation.impact, ")"] }), _jsx("p", { className: "health-audit-description", children: violation.description }), violation.nodes && violation.nodes.length > 0 && (_jsx("div", { className: "health-audit-details", children: _jsxs("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: ["Affected elements (", violation.nodes.length, "):", violation.nodes.map((node, idx) => (_jsx("div", { style: { marginBottom: '0.125rem' }, children: formatNodeInfo(node) }, idx)))] }) })), _jsx("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: _jsx("a", { href: violation.helpUrl, target: "_blank", rel: "noopener noreferrer", style: { color: '#3b82f6', textDecoration: 'underline' }, children: "Learn more about this rule" }) })] })] }, violation.id))) })] })), result.passes.length > 0 && result.violations.length === 0 && (_jsxs("div", { children: [_jsxs("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem', color: '#10b981' }, children: [getPassingIndicator().icon, " All Accessibility Checks Passed"] }), _jsxs("p", { style: { color: '#6b7280', fontSize: '0.875rem' }, children: [result.passes.length, " accessibility rules were successfully validated."] })] })), result.incomplete.length > 0 && (_jsxs("div", { style: { marginTop: '15px' }, children: [_jsxs("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem', color: '#f59e0b' }, children: ["Incomplete Tests (", result.incomplete.length, ")"] }), _jsx("div", { className: "space-y-2", children: result.incomplete
|
|
49
|
+
.sort((a, b) => a.id.localeCompare(b.id))
|
|
50
|
+
.slice(0, 10)
|
|
51
|
+
.map((incomplete) => (_jsxs("div", { className: "health-audit-item", children: [_jsx("span", { className: "health-audit-icon", children: getIncompleteIndicator().icon }), _jsxs("div", { className: "health-audit-content", children: [_jsx("span", { className: "health-audit-title", children: incomplete.help }), _jsx("p", { className: "health-audit-description", children: incomplete.description }), incomplete.nodes && incomplete.nodes.length > 0 && (_jsx("div", { className: "health-audit-details", children: _jsxs("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: ["Elements tested (", incomplete.nodes.length, "):", incomplete.nodes.slice(0, 3).map((node, idx) => (_jsx("div", { style: { marginBottom: '0.125rem' }, children: formatNodeInfo(node) }, idx))), incomplete.nodes.length > 3 && (_jsxs("div", { style: { marginTop: '0.25rem', fontStyle: 'italic' }, children: ["... and ", incomplete.nodes.length - 3, " more elements"] }))] }) })), _jsx("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: _jsx("a", { href: incomplete.helpUrl, target: "_blank", rel: "noopener noreferrer", style: { color: '#3b82f6', textDecoration: 'underline' }, children: "Learn more about this rule" }) })] })] }, incomplete.id))) })] })), _jsxs("div", { className: "health-timestamp", children: [_jsxs("div", { children: ["Tested with axe-core ", result.testEngine?.version || 'unknown'] }), _jsxs("div", { children: ["Last checked: ", new Date(siteData.timestamp).toLocaleString()] })] })] }));
|
|
52
|
+
} }));
|
|
53
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared caching utilities for Site Health components
|
|
3
|
+
*/
|
|
4
|
+
export class RouteCache {
|
|
5
|
+
cache = new Map();
|
|
6
|
+
duration;
|
|
7
|
+
constructor(durationMs = 60 * 60 * 1000) {
|
|
8
|
+
this.duration = durationMs;
|
|
9
|
+
}
|
|
10
|
+
get(key) {
|
|
11
|
+
const cached = this.cache.get(key);
|
|
12
|
+
if (cached && Date.now() - cached.timestamp < this.duration) {
|
|
13
|
+
return cached.data;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
set(key, data) {
|
|
18
|
+
this.cache.set(key, { data, timestamp: Date.now() });
|
|
19
|
+
}
|
|
20
|
+
clear() {
|
|
21
|
+
this.cache.clear();
|
|
22
|
+
}
|
|
23
|
+
}
|