Skip to content

Commit

Permalink
draft: first draft of cdn path block
Browse files Browse the repository at this point in the history
  • Loading branch information
fkakatie committed Mar 14, 2024
1 parent 71eab85 commit c1a1a09
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 0 deletions.
120 changes: 120 additions & 0 deletions blocks/cdn-path/cdn-path.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
.cdn-path form {
display: grid;
gap: 1rem;
}

.cdn-path label {
position: relative;
display: flex;
align-items: center;
gap: 1rem;
border-radius: var(--image-border-radius-m);
padding: 1rem;
padding-left: calc((2 * 1rem) + var(--circular-icon-tag-size));
cursor: pointer;
user-select: none;
transition: border-radius 2s, background-color .2s;
}

@media (min-width: 900px) {
.cdn-path label {
min-height: calc((2 * 1rem) + var(--circular-icon-tag-size));
}
}

.cdn-path label:hover {
background-color: var(--bg-color-lightgrey);
}

.cdn-path input,
.cdn-path span {
display: block;
position: absolute;
top: 50%;
left: 1rem;
transform: translateY(-50%);
margin: 0;
width: var(--circular-icon-tag-size);
height: var(--circular-icon-tag-size);
border-radius: 50%;
}

.cdn-path span,
.cdn-path span::after {
transition: background-color .2s, opacity .2s;
}

.cdn-path span::after {
content: "";
position: absolute;
top: 7px;
left: 11px;
display: block;
width: 5px;
height: 10px;
transform: rotate(45deg);
border: solid var(--color-accent-lightgreen-content);
border-width: 0 3px 3px 0;
opacity: 0;
transition: background-color .4s, opacity .4s;
}

@media (min-width: 900px) {
.cdn-path span::after {
top: 10px;
left: 19px;
width: 10px;
height: 20px;
border-width: 0 4px 4px 0;
}
}

.cdn-path input {
appearance: none;
opacity: 0;
}

.cdn-path span {
box-sizing: border-box;
background-color: var(--bg-color-grey);
}

.cdn-path input:checked ~ span {
background-color: var(--color-accent-lightgreen-bg);
}

.cdn-path input:checked ~ span::after {
opacity: 1;
}

.cdn-path label:hover input ~ span::after {
opacity: .5;
}

.cdn-path button {
display: inline-block;
width: max-content;
height: fit-content;
margin: 0 auto;
padding: 5px 1.2em 6px;
border: 2px solid;
border-color: var(--spectrum-blue);
border-radius: var(--image-border-radius-xxl);
background-color: var(--spectrum-blue);
color: var(--color-white);
font-family: inherit;
font-size: var(--type-body-s-size);
font-weight: 600;
line-height: var(--body-line-height);
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
cursor: pointer;
transition: background-color 0.3s, color 0.3s
}

.cdn-path button:hover {
background-color: var(--dark-spectrum-blue);
border-color: var(--dark-spectrum-blue);
}
92 changes: 92 additions & 0 deletions blocks/cdn-path/cdn-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { createTag } from '../../scripts/scripts.js';
import { toClassName } from '../../scripts/lib-franklin.js';

function toCamelCase(string) {
return toClassName(string).replace(/-([a-z])/g, (s) => s[1].toUpperCase());
}

async function fetchQuestionnaire(source) {
const { pathname } = new URL(source);
if (pathname) {
const req = await fetch(pathname);
const res = await req.json();
const questionnaire = { questions: res.data };
if (questionnaire.questions.length) {
questionnaire.choices = Object.keys(res.data[0]).slice(1);
}
return questionnaire;
}
return {};
}

function buildQuestion(q) {
const name = toClassName(q.Question);
const label = createTag('label', { for: name }, q.Question);
const input = createTag('input', { type: 'checkbox', name, id: name });
Object.keys(q).forEach((choice) => {
// eslint-disable-next-line eqeqeq
if (q[choice] == parseInt(q[choice], 10)) {
input.dataset[toCamelCase(choice)] = q[choice];
}
});
const span = createTag('span', { class: 'checkbox' });
label.append(input, span);
return label;
}

function findPaths(e) {
const checked = e.target.querySelectorAll('input:checked');
const results = {};
checked.forEach((check) => {
Object.keys(check.dataset).forEach((choice) => {
const value = parseInt(check.dataset[choice], 10);
if (results[choice]) {
results[choice] += value;
} else {
results[choice] = value;
}
});
});
const sorted = Object.entries(results).sort((a, b) => b[1] - a[1]);
const topMatches = [];
let count = 0;
while (count < 3 && sorted[0] && sorted[0][1] && sorted[0][1] > 0) {
const [choice] = sorted;
topMatches.push(choice);
sorted.shift();
count += 1;
}
return topMatches;
}

function displayPaths(e, el, choices) {
e.preventDefault();
el.innerHTML = '';
const paths = findPaths(e);
paths.forEach((path) => {
const choice = choices.find((c) => toCamelCase(c) === path[0]);
const li = createTag('li', {}, choice);
// TODO: actually present results in a useful way
el.append(li);
});
}

export default async function decorate(block) {
const source = block.querySelector('a[href]');
block.innerHTML = '';
if (source) {
const data = await fetchQuestionnaire(source);
// build questionnaire
const form = createTag('form');
const results = createTag('ol', { class: 'cdn-path-results' });
form.addEventListener('submit', (e) => displayPaths(e, results, data.choices));
data.questions.forEach((d) => {
const q = buildQuestion(d);
form.append(q);
});
// TODO: move string out of code
const button = createTag('button', { type: 'submit' }, 'Find Your Path');
form.append(button);
block.append(form, results);
}
}

0 comments on commit c1a1a09

Please sign in to comment.