In connection with a job application I have to progress the following task:
Create a dynamic growing pyramid. The structure has to be sorted alphabetically (concerning the inserted values). It has to have the following controls:
Textbox for inserting texts (used by the blocks of the pyramid).
Button which adds the text to the list. Furthermore updates the pyramid.
Button which removes the last block of the pyramid. Furthermore updates the pyramid.
You are allowed to use HTML, CSS and JavaScript.
Here are screenshots for to demonstrate how it is meant:
Here the code I've written:
(function() {
var items = [];
var addNewItem = document.querySelector('#add-new-item');
var removeLastItem = document.querySelector('#remove-last-item');
var textbox = document.querySelector('#content-new-item');
var pyramidPanel = document.querySelector('#pyramid-panel');
var colors = ['orange', 'blue', 'red', 'green'];
function updateItems() {
var textboxContent = textbox.value
if (items.length < 5 && textboxContent.length) {
textbox.value = '';
items.push({
textboxContent,
color: ''
});
items.sort((a, b) => {
if (a.textboxContent > b.textboxContent) {
return 1;
} else if (a.textboxContent < b.textboxContent) {
return -1;
} else {
return 0;
}
});
setColors();
}
}
function setColors() {
items.forEach((item, index) => {
item.color = colors[index % colors.length];
});
}
function updateView() {
items.forEach((item, index) => {
let div = document.createElement('div');
let span = document.createElement('span');
let textNode = document.createTextNode(item.textboxContent);
div.setAttribute('class', 'pyramid-item');
span.setAttribute('class', 'pyramid-content');
div.style.borderRight = '75px solid transparent';
div.style.borderBottom = `50px solid ${item.color}`;
div.style.borderLeft = '75px solid transparent';
div.style.marginLeft = ((4 - index) * 75) + 'px';
div.style.width = (150 * index) + 'px';
span.appendChild(textNode);
div.appendChild(span);
pyramidPanel.appendChild(div);
});
}
function emptyPanel() {
while (pyramidPanel.firstChild) {
pyramidPanel.removeChild(pyramidPanel.lastChild);
}
}
addNewItem.addEventListener('click', () => {
updateItems();
emptyPanel();
updateView();
});
removeLastItem.addEventListener('click', () => {
items.pop();
emptyPanel();
updateView();
});
})();
body {
background-color: #ebebeb;
}
.pyramid-wrap {
margin: 20px auto;
max-width: 750px;
background-color: whitesmoke;
border-radius: 8px;
padding: 5px 10px;
}
.nav-item {
margin-bottom: 20px;
}
#content-new-item {
display: inline-block;
width: 300px;
}
.nav-item *:nth-child(n + 1) {
margin-right: 15px;
color: black;
}
.pyramid-item {
height: 0;
margin-bottom: 10px;
position: relative;
}
.pyramid-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, 70%);
font-weight: 800;
color: white;
letter-spacing: 2px;
}
.nav-item-control:focus {
box-shadow: 0 0 3px #555;
color: #555;
}
button.nav-item-control:hover {
background-color: #787878;
color: #eee;
border: 0;
}
input:hover::-webkit-input-placeholder {
color: #dedede;
}
input:hover::-moz-placeholder {
color: #dedede;
}
input:hover:-ms-input-placeholder {
color: #dedede;
}
button.nav-item-control:active {
color: #fff;
box-shadow: 0 0 6px white;
}
<div class="pyramid-wrap">
<div id="pyramid-panel"></div>
<nav>
<div class="nav-item">
<input class="nav-item-control" type="text" id="content-new-item" placeholder="Please enter the text content for next pyramid item ..." />
<button class="nav-item-control" id="add-new-item">Add new pyramid item</button>
</div>
<div class="nav-item">
<button class="nav-item-control" id="remove-last-item">Remove last pyramid item</button>
</div>
</nav>
</div>
What do you think about my idea of computing the margins and widths of each div?
An alternative would have been to write multiple CSS-classes and then adding the corresponding CSS-class.
Which approach is better and for what reason? Are there points which could be improved? Or done better some different way?