Skip to content

Commit 8f98d87

Browse files
authored
Merge pull request #133 from adobe/migrate-powerscore
Migrate powerscore
2 parents e645c72 + 03525ee commit 8f98d87

39 files changed

+2891
-407
lines changed

blocks/analyze/analyze.css

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
main .analyze-container {
2+
/* avoid layout shift when results block is added */
3+
min-height: 80vh;
4+
}
5+
6+
main .analyze-container .button-wrapper:has(a[title='Docs']) {
7+
justify-content: flex-end;
8+
}
9+
10+
main .analyze form {
11+
display: grid;
12+
gap: 1rem;
13+
grid-template-columns: 4fr 1fr;
14+
justify-content: center;
15+
align-items: center;
16+
max-width: 800px;
17+
margin-inline: auto;
18+
19+
label {
20+
margin: 0;
21+
}
22+
23+
.input-field-wrapper {
24+
display: flex;
25+
justify-content: start;
26+
align-items: center;
27+
gap: 1rem;
28+
position: relative;
29+
30+
label, input {
31+
margin: 0;
32+
flex: 1;
33+
}
34+
35+
label {
36+
max-width: max-content;
37+
}
38+
39+
input {
40+
padding: 0 16px;
41+
height: 48px;
42+
margin: 2px;
43+
font-size: var(--body-font-size-s);
44+
font-family: inherit;
45+
46+
&.visited:invalid {
47+
outline: 2px solid var(--error-color);
48+
49+
+ .input-error {
50+
display: block;
51+
}
52+
}
53+
}
54+
55+
/* stylelint-disable-next-line no-descending-specificity */
56+
.input-error {
57+
display: none;
58+
position: absolute;
59+
bottom: -2.25rem;
60+
left: 1rem;
61+
62+
> p {
63+
font-size: .75rem;
64+
color: var(--error-color);
65+
}
66+
}
67+
}
68+
69+
.force-wrapper {
70+
display: flex;
71+
flex-direction: row-reverse;
72+
justify-content: start;
73+
align-items: center;
74+
gap: 1rem;
75+
font-size: var(--body-font-size-xs);
76+
}
77+
78+
79+
.submit-wrapper {
80+
/* stylelint-disable-next-line no-descending-specificity */
81+
> button {
82+
border-radius: 4px;
83+
font-weight: 500;
84+
height: 48px;
85+
font-size: 1rem;
86+
}
87+
}
88+
89+
.advanced-settings {
90+
position: relative;
91+
grid-column: 1 / -1;
92+
display: grid;
93+
grid-template-rows: 0fr;
94+
transition: grid-template-rows 0.5s 0s ease-in-out, border-bottom-width 0.2s 0s ease-in-out, border-right-width 0.1s 0.2s ease-in-out, border-left-width 0.1s 0.2s ease-in-out, border-top-width 0.2s 0.3s ease-in-out;
95+
padding: 1rem;
96+
margin: 0;
97+
border: 0 groove #dfdfdf;
98+
border-radius: 4px;
99+
100+
legend {
101+
position: relative;
102+
cursor: pointer;
103+
display: flex;
104+
justify-content: center;
105+
align-items: center;
106+
gap: .5rem;
107+
margin-inline-start: 1rem;
108+
padding-inline: 8px 2rem;
109+
110+
&::after {
111+
position: absolute;
112+
right: 1rem;
113+
top: 50%;
114+
transform: translateY(-50%) rotate(-135deg);
115+
transform-origin: center;
116+
transition: transform 0.5s ease-in-out;
117+
content: "";
118+
width: 8px;
119+
height: 8px;
120+
border: 1px solid currentcolor;
121+
border-top: 0;
122+
border-right: 0;
123+
}
124+
}
125+
126+
.input-field-wrapper {
127+
font-size: var(--body-font-size-xs);
128+
width: 100%;
129+
130+
input {
131+
height: 32px;
132+
}
133+
}
134+
135+
.settings-wrapper {
136+
display: flex;
137+
flex-direction: column;
138+
gap: .5rem;
139+
justify-content: center;
140+
align-items: flex-start;
141+
overflow: hidden;
142+
padding: 0;
143+
transition: padding 0.2s ease-in-out;
144+
}
145+
146+
&[aria-expanded="true"] {
147+
grid-template-rows: 1fr;
148+
border-width: 2px;
149+
transition-property: grid-template-rows, border-top-width, border-right-width, border-left-width, border-bottom-width, padding;
150+
151+
legend::after {
152+
transform: translateY(-50%) rotate(-45deg);
153+
}
154+
155+
.settings-wrapper {
156+
padding: 2px;
157+
}
158+
}
159+
}
160+
}

blocks/analyze/analyze.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import {
2+
buildBlock, decorateBlock, decorateIcons, loadBlock,
3+
} from '../../scripts/aem.js';
4+
5+
const createResults = async (block) => {
6+
const section = block.closest('.section');
7+
if (section.querySelector('.results-wrapper')) {
8+
section.querySelector('.results-wrapper').remove();
9+
}
10+
11+
const v = block.querySelector('.analyze-box').value;
12+
const a = document.createElement('a');
13+
a.textContent = v;
14+
a.href = v;
15+
const results = buildBlock('results', a);
16+
results.dataset.forceUpdate = block.querySelector('.force-update').checked;
17+
results.dataset.sitemapUrl = block.querySelector('.sitemap-box').value;
18+
results.dataset.filterPath = block.querySelector('.path-box').value;
19+
const wrapper = document.createElement('div');
20+
wrapper.style.display = 'none';
21+
wrapper.append(results);
22+
section.append(wrapper);
23+
decorateBlock(results);
24+
await loadBlock(results);
25+
wrapper.style.display = null;
26+
};
27+
28+
function restoreFormState(form, powerScoreParams) {
29+
const analyzeBox = form.querySelector('#analyze-box');
30+
analyzeBox.value = powerScoreParams.origin;
31+
32+
const forceCbox = form.querySelector('#force-cbox');
33+
forceCbox.checked = powerScoreParams.forceUpdate;
34+
const sitemapBox = form.querySelector('#sitemap-box');
35+
sitemapBox.value = powerScoreParams.sitemapUrl;
36+
const pathBox = form.querySelector('#path-box');
37+
pathBox.value = powerScoreParams.path;
38+
39+
if (powerScoreParams.forceUpdate || powerScoreParams.sitemapUrl || powerScoreParams.path) {
40+
const settings = form.querySelector('.advanced-settings');
41+
settings.setAttribute('aria-expanded', true);
42+
}
43+
}
44+
45+
function restoreState(form) {
46+
const urlParams = new URLSearchParams(window.location.search);
47+
const powerScoreUrl = urlParams.get('powerScoreUrl');
48+
if (powerScoreUrl) {
49+
const powerScoreParams = {
50+
origin: powerScoreUrl,
51+
sitemapUrl: urlParams.get('sitemapUrl'),
52+
forceUpdate: urlParams.get('forceUpdate') === 'true',
53+
path: urlParams.get('filterPath'),
54+
};
55+
restoreFormState(form, powerScoreParams);
56+
57+
// start if query parameter
58+
if (powerScoreUrl) {
59+
setTimeout(() => {
60+
form.submit();
61+
}, 500);
62+
}
63+
return;
64+
}
65+
66+
const sessionStorageState = sessionStorage.getItem('powerScoreParams');
67+
if (sessionStorageState) {
68+
const powerScoreParams = JSON.parse(sessionStorageState);
69+
restoreFormState(form, powerScoreParams);
70+
}
71+
}
72+
73+
/**
74+
* decorate the block
75+
* @param {Element} block the block element
76+
*/
77+
export default function decorate(block) {
78+
block.innerHTML = `
79+
<form id="analyze-url-form">
80+
<div class="field-wrapper input-field-wrapper analyze-box-wrapper">
81+
<input id="analyze-box" aria-label="URL" class="analyze-box" type="url" required placeholder="Enter site root URL"></input>
82+
<div class="input-error">
83+
<p>Please enter a valid URL</p>
84+
</div>
85+
</div>
86+
<div class="field-wrapper submit-wrapper">
87+
<button type="submit">Analyze</button>
88+
</div>
89+
<fieldset class="advanced-settings" aria-expanded="false">
90+
<legend><span class="icon icon-settings"></span><span>Settings</span></legend>
91+
<div class="settings-wrapper">
92+
<div class="field-wrapper force-wrapper">
93+
<label for="force-cbox">Force Update?</label>
94+
<input id="force-cbox" class="force-update" type="checkbox"></input>
95+
</div>
96+
<div class="field-wrapper input-field-wrapper sitemap-box-wrapper">
97+
<label for="sitemap-box">Custom Sitemap URL</label>
98+
<input id="sitemap-box" class="sitemap-box" type="url" placeholder="enter sitemap url if not mentioned in robots.txt"></input>
99+
</div>
100+
<div class="field-wrapper input-field-wrapper path-box-wrapper">
101+
<label for="path-box">Filter Path</label>
102+
<input id="path-box" class="path-box" type="text" placeholder="e.g. /blog"></input>
103+
</div>
104+
</div>
105+
</fieldset>
106+
</div>
107+
108+
</form>
109+
`;
110+
const form = block.querySelector('form');
111+
const analyzeBox = form.querySelector('#analyze-box');
112+
const settings = form.querySelector('.advanced-settings');
113+
const sitemapBox = form.querySelector('#sitemap-box');
114+
115+
decorateIcons(form);
116+
settings.querySelector('legend').addEventListener('click', () => {
117+
const expanded = settings.getAttribute('aria-expanded') === 'true';
118+
settings.setAttribute('aria-expanded', !expanded);
119+
});
120+
121+
const urlBoxBlur = (e) => {
122+
const box = e.target;
123+
if (
124+
box.value && box.value.trim()
125+
&& !(
126+
box.value.startsWith('http://')
127+
|| box.value.startsWith('https://')
128+
)
129+
) {
130+
box.value = `https://${box.value}`;
131+
}
132+
box.classList.add('visited');
133+
};
134+
analyzeBox.addEventListener('blur', urlBoxBlur);
135+
sitemapBox.addEventListener('blur', urlBoxBlur);
136+
analyzeBox.addEventListener('keyup', (e) => {
137+
if (e.code === 'Enter') {
138+
urlBoxBlur(e);
139+
}
140+
});
141+
142+
form.addEventListener('submit', (e) => {
143+
e.preventDefault();
144+
if (form.checkValidity()) {
145+
createResults(block);
146+
}
147+
});
148+
restoreState(form);
149+
block.scrollIntoView();
150+
}

0 commit comments

Comments
 (0)