Create a Coffee Name Generator
June 29, 2020
On a whim, I decided to create a random Coffee Name generator. Althought there isn't a lot of code, I thought there were a few features (Web Animations API and Intl.ListFormat().format
) that I thought were interesting and wanted to share.
Code Sandbox
You can browse and experiment with the code in the following CodeSandbox embed.
JavaScript Generator
Let's first start with the JavaScript generator that builds the coffee names. I'll break it apart below and identify two parts that I found interesting.
Setup
The only external dependency I used was lodash
for the sample
and random
functions. I could have written them from scratch, but they are pretty handy tools to grab when you need them. Data-wise, I have lists of coffee sizes, types, add-ins, toppings, and flavors that are used to build the coffee name. You can customize these arrays to include your favorite items.
import { sample, random } from 'lodash';
const sizes = ['Short', 'Tall', 'Grande', 'Venti'];
const coffeeTypes = [
'Cappuccino',
'Espresso',
'Caffè Latte',
'Caffè Mocha',
];
const addIns = ['1% Milk', '2% Milk', 'Almondmilk', 'Cream'];
const toppings = [
'Caramel Drizzel',
'Chocolate Powder',
'Vanilla Powder',
'Whipped Cream',
];
const flavors = [
'Caramel Syrup',
'Hazelnut Syrup',
'Vanilla Syrup',
'Mocah Sauce',
];
Generate Add-ons
The generateAddons
function is split into two main sections:
- Building a random array of add-ons
- Converting an array into words
export const generateAddons = () => {
const additions = [
random(0, 1) && sample(addIns),
random(0, 1) && sample(toppings),
random(0, 1) && sample(flavors),
].filter(Boolean);
return `${
additions.length ? 'with' : ''
} ${new Intl.ListFormat().format(additions)}`;
};
1. Random Add-ons
The first part of generateAddons
randomly builds the set of add-ons for the drink. There may be one add-on, two, or all three. Each entry uses the random
function and if it's truthy then it picks an item from that array, otherwise it's value will be undefined
. The filter at the end will only keep those items that are truthy, which removes any entry that had an undefined
value.
2. Array to Words
The second part of the generateAddons
function converts the array (of 0 to 3 items) into an English string (example: ["apple", "pear", "orange"]
to "apple, pear, and orange"
). When I first started making this function I wrote my own algorithm, but then started to see if I could pull in an external node module. To my surprise, I found that there's a native Intl.ListFormat().format
browser API.
NOTE: Unfortunatley the support for
Intl: ListFormat: format
isn't the greatest at the moment. Thankfully though, there is a polyfill if you really want to use it in currently unsupported browsers (@formatjs/intl-listformat
).
React Code
The following code is for the App
React component that displays the generated coffee name and will animate
the inner coffee liquid when the name
changes.
export default function App() {
const [name, setName] = useState(generateCoffee());
const coffeeRef = useRef(null);
useEffect(() => {
coffeeRef.current.animate(
[
{
top: '15rem',
transform: 'translateX(-50%) rotate(0deg)',
},
{
top: '-5rem',
transform: 'translateX(-50%) rotate(360deg)',
},
],
{
duration: 3000,
fill: 'forwards',
},
);
}, [name]);
return (
<div className="App">
<Title>Coffee Name Generator</Title>
<Coffee ref={coffeeRef} />
<Generate onClick={() => setName(generateCoffee())}>
Generate
</Generate>
<CoffeeName>{name}</CoffeeName>
</div>
);
}
The parts I'd like to highlight are the coffeeRef
(created and assigned to the Coffee
component) and the animate
method called inside the React.useEffect
. Each time the coffee name
is generated the useEffect
will get invoked. Since we are dealing with a ref
, we need to access the current
property to get at the underlying DOM element. From there, we can call the animate
method passing the states we'd like to animate and additional metadata.
Thankfully the browser support for Web Animations API
is better than what we saw above with Intl: ListFormat: format
.
Conclusion
I enjoyed putting this demo together and I hope you either learned something or found the experience enjoyable 😀 Have a great day and wonderful rest of the week!
Tweet about this post and have it show up here!