JSFiddle - React, Tailwind, and code Playground

[ASSIGNMENT] Close Frontend Application Quiz

by philfreo

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

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}

.Selection {
  margin: 16px;
  display: flex;
  flex-flow: row wrap;
  height: 200px;
  align-content: baseline;
  overflow: scroll;
}

.Selection__item {
  font-size: 1.2em;
  padding: 4px;
  border: 2px solid rgba(55, 55, 55, 0.78);
  background-color: rgba(55, 55, 55, 0.05);
  margin: 0 8px 8px 0;
}

.Selection__item-empty {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5em;
  color: rgba(55, 55, 55, 0.78);
}

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

.List__item {
  color: white;
  text-shadow: 1px 1px rgba(0, 0, 0, 0.5);
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.05);
  border: 3px solid transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  position: relative;
  cursor: pointer;
}

.List__item:hover {
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
}

.List__item::before {
  content: " ";
  position: absolute;
  top: 0;
  right: 0;
  height: 0;
  width: 0;
  text-align: center;
  vertical-align: middle;
  display: flex;
  align-items: flex-end;
  justify-content: right;
  border: 15px solid transparent;
  background-color: transparent;
  opacity: 0;
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  text-shadow: none;
  color: rgba(255, 255, 255, 1);
}

.List__item-selected {
  border-color: rgba(68, 170, 221, 0.94);
  box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.24);
}

.List__item-selected::before {
  opacity: 1;
  content: "✔";
  border-color: rgba(68, 170, 221, 0.94) rgba(68, 170, 221, 0.94) transparent transparent;
}

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

.List__item--navy {
  background-color:...

React

const { Fragment, memo, useCallback, useMemo, useState } = React;


// 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. Currently selected items should be visually highlighted.
// 4. Currently selected items' names should be shown at the top of the page.
// 5. Make sure to avoid unnecessary re-renders.
const Item = memo(props => {
  const { onClick, name, color, isSelected } = props;
  const handleClick = () => {
    onClick(name);
  };
  return (
    <div
      className={`List__item List__item--${color} ${
        isSelected ? "List__item-selected" : ""
      }`}
      onClick={handleClick}
    >
      {name}
    </div>
  );
});

const List = ({ items }) => {
  const [selected, setSelected] = useState([]);
  const nameToColorMap = useMemo(() => {
    return items.reduce((acc, item) => {
      return {
        ...acc,
        [item.name]: item.color
      };
    }, {});
  }, [items]);
  const updateSelected = useCallback(
    name => {
      setSelected(oldSelected => {
        return oldSelected.includes(name)
          ? oldSelected.filter(s => s !== name)
          : [...oldSelected, name];
      });
    },
    [setSelected]
  );
  return (
    <Fragment>
      <div className="Selection">
        {selected.map(name => (
          <div
            className="Selection__item"
            key={name}
            style={{ borderColor: nameToColorMap[name] }}
          >
            {name}
          </div>
        ))}
        {selected.length === 0 && (
          <div className="Selection__item-empty">
            Your selection will appear here
          </div>
        )}
      </div>
      <div className="List">
        {items.map(item => (
          <Item
            key={item.name}
            name={item.name}
            color={item.color}
            isSelected={selected.includes(item.name)}
            onClick={updateSelected}
      ...