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}
...