loading words...

May 29, 2019 23:46:32

My draft

by @swizecteller | 868 words | 🐣 | 105💌

Swizec Teller

Current day streak: 0🐣
Total posts: 105💌
Total words: 29304 (117 pages 📄)

wrote this today


# Session 3 – The UI comes together

https://www.youtube.com/watch?v=aAGpDO8-yic

Session 3, we gave the WidgetBuilder better looks, added an export button, and shopped around for a good toast library.

![](https://i.imgur.com/IAmmWzE.gif)

We started this session with some UI tweaks. What we had before worked, but the spacings were off and it wasn't a joy to use.

## 1) Make it prettier so it's a joy to use

Added a CSS grid to the `<WidgetBuilder />` component and that made all the difference. I'd still consider our UI a mockup, but mockups should look good too 👨‍🎨

Adding the export button we realized that Reakit really absolutely has no more default styling. The button looked bad.

So we shopped around for a UI kit with some more default styling. Still looking for something built on top of styled components that's easy to theme and style, but with prettier defaults.

After checking out Material UI and some others, we settled on [Rebass](https://rebassjs.org/). As Brent suggested. Thanks Brent ❤️

Rebass gave us that pretty magenta button with rounded borders and bold fonts 👇

```javascript

// src/components/WidgetBuilder.js

<Button bg="primary" onClick={exportWidget}>

Export

</Button>

```

With this, we started moving color definitions into our global theme. This is going to make styling easier later.

```javascript

// src/components/theme.js

colors: {

primary: 'magenta'

}

```

We're gonna keep adding colors there and Rebass's built-in color props, like `bg`, will pick up on them and use those definitions everywhere. Great for consistency 👌

At some point, because we're not designers, we're gonna use a color picker tool to choose a complimentary set of colors that work well together. But right now we're in mockup land.

## 2) Adding the export functionality

Our widget export needs to take that widget and export as plain HTML. That way it works in all contexts that render HTML, like an email or a blogpost.

```javascript

// src/components/WidgetBuilder.js

function exportWidget() {

const widget = <Widget value={typeOfJoy} />

const el = document.createElement("div")

ReactDOM.render(widget, el)

const html = copyToClipboard(el.innerHTML)

ButterToast.raise({

content: (

<Cinnamon.Crisp

scheme={Cinnamon.Crisp.SCHEME_BLUE}

title="Copied to clipboard!"

content={() => <div>👍 Paste HTML into your favorite editor</div>}

/>

),

})

}

```

We had to split our WidgetBuilder into two areas:

- the widget

- the builder

The widget component knows how to render the question and thumbs up/down buttons in editable or non-editable mode. The builder handles state, the export button, and the export itself.

Exporting works with a little old school JavaScript trickery 👇

- create an empty DOM node

- render `<Widget />` into that node

- get innerHTML

Your browser is *excellent* at translating DOM to HTML and back.

https://twitter.com/Swizec/status/1132812504248094725

Where we got stuck was styling. That export produces something like this:

```html

<div class="WidgetBuilder__WidgetLayout-bvrvTX ismVIA"><h1 class="styles__Heading-dvvLln WidgetBuilder__Question-jtCCPt gKkkpo">Did this app spark joy?</h1><div class="styles__Flex-cJfIMr bXtVYe"><button class="WidgetBuilder__RoundButton-kniuTE boTmdH">👎</button><button class="WidgetBuilder__RoundButton-kniuTE boTmdH">👍</button></div></div>

```

Works great in our app, won't work in an email. There's no styling.

It looks terrible in fact

![](https://i.imgur.com/jb7Ziyj.png)

That won't work at all 🤦‍♂️

Decided to research that one offline and we'll use the solution this Thursday.

## 3) The toast

Toasts are a great UI to tell users *Hey this thing happened*. In our case that's putting stuff in your clipboard.

Without a toast how are you to know the export button did anything? 🤷‍♀️

Since this is a common piece of UI and absolutely tedious to build ourselves, we looked at a bunch of React toast libraries. [Butter Toast](github:butter-toast) won the popular vote so that's what we used.

It looks good, works great, and doesn't require complex setup to use. In fact we had to change just two files

1. Where we invoke it

2. The main Layout where it renders

Starting with the invocation inside WidgetBuilder 👇

```javascript

// src/components/WidgetBuilder.js

ButterToast.raise({

content: (

<Cinnamon.Crisp

scheme={Cinnamon.Crisp.SCHEME_BLUE}

title="Copied to clipboard!"

content={() => <div>👍 Paste HTML into your favorite editor</div>}

/>

),

})

```

Call `ButterToast.raise`, define its content, 🍞.

We used `Cinnamon.Crisp` which is a built-in toast component and what the Readme uses. There must be others, but this one looks good so we didn't look around.

Give it a `title` and a `content` render prop and that's about it.

![](https://i.imgur.com/I8iVvBN.png)

Toasts work via [React portals](https://reactjs.org/docs/portals.html) so we had to add a Toast renderer to our main `<Layout />` component. That makes toasts available on every page of our app.

```javascript

src/components/layout.js

<ButterToast

position={{ vertical: POS_TOP, horizontal: POS_RIGHT }}

/>

```

<ButterToast /> is a placeholder where toasts render into. Tell it where it sits on the page and that's all. ✌️

![](https://i.imgur.com/IAmmWzE.gif)

## Coming next

Thursday 10pm Pacific, we're gonna start making that widget work to collect feedback. Set up a serverless backend, save widget IDs, stuff like that.

It's gonna be great, hope you make it :)

As always: Hit reply if you have any questions.

Cheers,<br>

~Swizec

contact: email - twitter / Terms / Privacy