JSFiddle - React, Tailwind, and code Playground
[ASSIGNMENT] Close Frontend Application Quiz
by Matthew Marcus
HTML
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/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 {
line-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);
cursor: pointer;
transition: box-shadow 0.15s ease, filter 0.15s ease;
user-select: none;
}
.List__item--selected {
box-shadow: inset 0 0 0 4px rgba(237, 24, 24, 0.75);
filter: brightness(1.2);
}
.SelectedItems {
padding: 16px;
border-bottom: 2px solid rgba(0, 0, 0, 0.1);
margin-bottom: 8px;
}
.SelectedItems__heading {
margin: 0 0 12px;
font-family: sans-serif;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: #555;
}
/* 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 { Fragment, useState, useCallback, useMemo, memo } = React
const Item = memo(({ name, color, isSelected, onToggle }) => (
<li
className={`List__item List__item--${color}${isSelected ? ' List__item--selected' : ''}`}
onClick={() => onToggle(name)}
>
{name}
</li>
))
const SelectedItems = ({ items, onToggle }) => {
if (items.length === 0) return null
return (
<div className="SelectedItems">
<p className="SelectedItems__heading">Selected</p>
<ul className="List">
{items.map(item => (
<Item
key={item.name}
name={item.name}
color={item.color}
isSelected={true}
onToggle={onToggle}
/>
))}
</ul>
</div>
)
}
// 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.
const List = ({ items }) => {
const [selectedNames, setSelectedNames] = useState(new Set())
const handleToggle = useCallback((name) => {
setSelectedNames(prev => {
const next = new Set(prev)
next.has(name) ? next.delete(name) : next.add(name)
return next
})
}, [])
const selectedItems = useMemo(
() => items.filter(item => selectedNames.has(item.name)),
[items, selectedNames]
)
return (
<Fragment>
<SelectedItems items={selectedItems} onToggle={handleToggle} />
<ul className="List">
{items.map(item => (
<Item
key={item.name}
name={item.name}
color={item.color}
...