JSFiddle - React, Tailwind, and code Playground

[ASSIGNMENT] Close Frontend Application Quiz

by Rykus0

HTML

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

CSS

.List {
  margin: 16px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  grid-auto-rows: 60px;
  grid-gap: 16px;
}

.List__item {
  height: 60px;
  text-align: center;
  color: white;
  text-shadow: 1px 1px rgba(0, 0, 0, 0.5);
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.05);
  position: relative;
}

.List__item__checkbox:not(:checked) {
  clip: rect(0 0 0 0); 
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap; 
  width: 1px;
}

.List__item__checkbox:checked {
  position: absolute;
  top: 0;
  left: 0;
}


.List__item__checkbox:focus + .List__item__label {
  outline: 2px solid red;
}

.List__item__checkbox:checked + .List__item__label {
  box-shadow: 0 0 8px black;
}

.List__item__label {
  display: flex;
  height: 100%;
  width: 100%;    
  align-items: center;
  justify-content: center;
}

.Selected {
  background: white;
  
  margin: 16px;
  padding: .5em;
  border: 1px solid;
  
  position: sticky;
  top: 0;
  left: 0;
  z-index: 10;
}

/* Taken from https://clrs.cc/ */

.List__item--navy {
  background-color: #001f3f;
}

.List__item--blue {
  background-color: #0074d9;
}

.List__item--aqua {
  background-color: #7fdbff;
}

.List__item--teal {
  background-color: #39cccc;
}

.List__item--olive {
  background-color: #3d9970;
}

.List__item--green {
  background-color: #2ecc40;
}

.List__item--lime {
  background-color: #01ff70;
}

.List__item--yellow {
  background-color: #ffdc00;
}

.List__item--orange {
  background-color: #ff851b;
}

.List__item--red {
  background-color: #ff4136;
}

.List__item--maroon {
  background-color: #85144b;
}

.List__item--fuchsia {
  background-color: #f012be;
}

.List__item--purple {
  background-color: #b10dc9;
}

.List__item--black {
  background-color: #111111;
}

.List__item--gray {
  background-color: #aaaaaa;
}

.List__item--silver {
  background-color: #dddddd;
}

React

const { useState, memo } = React;

// for what it's worth - I spent around 30 minutes on this (about all the time I had)


// Implement a feature to allow item selection with the following requirements:
// 1. Clicking an item selects/unselects it.
// 2. Multiple items can be selected at a time.
// 3. Make sure to avoid unnecessary re-renders of each list item in the big list (performance).
// 4. Currently selected items should be visually highlighted.
// 5. Currently selected items' names should be shown at the top of the page.
//
// Feel free to change the component structure at will.

function List ({ items }) {
  const [selectedApples, setSelectedApples] = useState([])
  
  function toggleApple(e) {
  	const name = e.target.value;
    
  	if (e.target.checked) {
    	setSelectedApples((prev) => [...prev, name])
    } else {
    	setSelectedApples((prev) => removeItem(prev,name))
    }
  }
  
  return (
    <fieldset>
      <legend>Select an apple</legend>
      <div className="Selected">
        <strong>Selected apples:</strong>
        <div>{selectedApples.join(', ')}</div>
      </div>
      
      <div  className="List">
        {items.map(item => (
          <Item key={item.name} name={item.name} color={item.color} onChange={toggleApple} />
        ))}
      </div>
    </fieldset>
  )
}

function ItemEl({name, color, onChange}) {
	const checkboxId = `${name}-${color}-checkbox`;
  
	return (
    <span className={`List__item List__item--${color}`}>
      <input id={checkboxId} type="checkbox" onChange={onChange} className="List__item__checkbox" name="apple" value={name} />
      <label htmlFor={checkboxId} className={`List__item__label List__item--${color}`}>
        {name}
      </label>
    </span>
  )
}
const Item = memo(ItemEl);

function removeItem(list, item) {
  const newList = [...list];
  const index = newList.indexOf(item);
  
  if (index > -1) { // only splice array when item is found
    newList.splice(index, 1); // 2nd parameter means remove one...