Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

4.8 Creating the Chirp Box

At the end of our last lesson, we were successfully displaying chirps on our homepage. However, right now these chirps look a little bit spartan. Why don't we make them a little bit prettier? We'll put them in a box, we'll include the user's full name, maybe we can have the time since they've made this chirp. And of course we'll also include an avatar, which we can get from Gravatar. Now currently, we're displaying our chirps in our ChirpList here. We just have a very simple list item here. But since we're gonna be doing something a little more complex, why don't we create a component specifically for displaying chirps? So I'm going to create a component in the src/components directory, and why don't we call this ChirpBox. So we'll create a ChirpBox class, and since we can pass this ChirpBox, the chirp data through a property, we don't need to worry about state or anything. So let's jump right into the render function. We'll make the entire thing inside of a list item element and, of course, this list item will need to have a key, which will be this.props.chirp.cid. However, this .props.chirp is gonna be way too much to write for everything, so let's create a shorter variable, c, which will be this.props.chirp. Now, inside our property, we can just say c.cid. We also want to add a className here. We're going to make this chirp a row of its own and we're also gonna give it the chirp class, which is for some custom CSS that we are going to write. Now, inside our list item, the first thing we're going to include is an image, and the source here will go to the user's avatar. However, right now we don't have a way to get that avatar. We need to create the right Gravatar link, based on the user's email address, for that avatar image and we're going to do this in a utilities file. So inside the source directory, let's create utils.js, and we can just do exports.avatar, and this is going to be a function. This function will take an email address as a string, and it should return the URL to the user's image. So first let's just check to see if email is an empty string. If it is, that would be a falsely value so we can just reverse it to a true value and say, if there's no email then let's just return an empty string. Otherwise we can return the correct URL. So the beginning portion of the URL is pretty simple. It's http://www.gravatar.com/avatar/. Now at this point, we need to include the md5 hash of the user's email address. Now there's now native way to do an md5 hash in JavaScript in the browser, however because we're using browserify, we have access to the node libraries in the browser. So I'm gonna require that same crypto library that we used in the back end to encrypt the user's password. And what we can do here is, let's take the email address and let's say, this will be crypto.createHash and this is going to be an md5 hash. And then we can say, update it with the email address. And then we can say, digest, and get the hex digest of that email. So now, email will be the md5 hash of the email address that was passed in. So we can say Gravatar plus email and then we want to add a very short query string to the end of it, so we'll say question mark S equals. And the value of S here is the size of the image that we want. Now, I've experimented a bit and I think the best for what we're doing is 92 pixels. Excellent, so now this utils function should successfully return the URL to the user's avatar, if we pass it to e-mail. So back here in ChirpBox, we can start by requiring util, and then inside the source property of our image, we can say utils.avatar, and we can pass at c.email. Excellent. Now we want this image tag to be a link to the user's profile page. Now, remember we're using reactor router to do dynamic routing on our web application. So we can't just put a normal anchor tag here, because that would actually cause a page refresh. So what we have to do instead, is use the react router link element. So up at the top here, we will create var Link, and I can require react-router, and this is react-route.Link. All right, and so let's wrap our img tag here in a call to Link. We can give this Link a className of two columns, just so it's the right width in our page. And then we'll tell this link that we are linking to the user route. Now, this route hasn't been created yet. However, we'll still be able to create a link to it and this link is actually gonna need some params, because, of course, the user's profile link will have their ID on the end. And the way that params work, is we set it to an object and so there's, this is actually double set of curly braces here and in sub the object. We can say the ID should be c.userid. C of course is our chirp and user ID is the property, which is actually the ID of the user who made the chirp, which is of course the user that we're trying to link to here. All right, so underneath our link element, let's create a div and since our link is two columns wide, this div will be 10 columns wide. So it will take up the rest of the row that we're creating. And in here, we want to include two paragraphs. The second one is really easy. It's just c.text, the actual text of the chirp that the users created. However, the one above that has a little bit more content to it. The first thing we're gonna do is have a strong tag and in here, we're going to have chirp.fullName. This is of course the full name of the user who made the chirp. Underneath this, we're going to have a span and we're gonna give this span a className of timestamp, because we want it to be a little bit of a lighter gray. And as you might guess, it's going to include the timestamp. However, it's not going to start with that. It's going to start with an at sign and then chirp.username and then after that, we will include the timestamp. So we'll have space and then we'll have chirp.$created, which is the date time property that our database added to our chirp when we saved it. However, that's gonna give us a rather ugly date, so why don't we add the JavaScript library moment which allows us to easily format really nice dates. Let me quit the server for a moment and we'll do npm install Moment, and we want to install moment version two, and we cannot forget to save it to our package.json file. Okay, I'll restart the server, and now in chirp box, let's go ahead and pull in the moment library by requiring moment. And now, we can wrap chirp.$created in a call to moment. And then after that we can use the moment method fromNow to get a really nice relative date. So this will give us dates like one minute ago, ten minutes ago, two days ago. Some relative date that makes it easy for a person to see how long ago a chirp was made. So, let's go ahead and export this class. So we can do module.exports equals ChirpBox, and now let's flip back to ChirpList and let's require the ChirpBox module. And now instead of returning a list item from inside of our map function here, we can use ChirpBox and will pass of the chirp as a property. And then we'll use a self-closing tag here and it's that simple. So now, we should be able to go back to our browser. I'll refresh the page. Of course, because I restarted the server, I'm going to have to login again and you can see we have a bit of an error here. It says chirp is not defined. Chirp box line 15. So if we look at the chirp box file, oh, of course. I called my shorter variables c but after that I forgot to use c, I just used chirp. So I think I have three different usages of this, c.fullname, c.username and c.$created. Let me just see is there any other reference to chirp in here. None that we need to be worried about. Okay, let's refresh the page again. When we refresh the page, we actually get a different error this time. We cannot find a route named user. Oh yeah, and this is coming from our link element here. We asked it to link to the user route. However, that's not a route that we have. So, we can just kind of spoof this temporarily. Let's go back to source/main, and I'm just gonna duplicate the home route here, and I'll rename this as user, and I'll say the path equals /user/id. And we'll just leave the handler the same for now. And if I refresh the page, you can see things are showing up pretty nicely here. Notice we do have one more error here in our console and this is the warning about every element having a unique key property. The problem here is that in ChirpList, we aren't giving the ChirpBox element a unique property. And it's ChirpBox itself that is the array. It's not really these list items that are within it. So let's remove this key property from our list item element here. And let's actually add it to our ChirpBox itself. And that will keep react happy. So we can say chirp.cid. There we go. So with that in place, if we come back and refresh this page one more time, you can see we have no errors or warnings in the console. However, our styling is not looking that great. So, let's go ahead and write a little bit of CSS to make this work a little better. We already have a blank style sheet ready for us. We created that in public/style.CSS. So, for elements that have the chirp class, let's start by getting rid of their lists style type, so that we don't have the bullets. And then let's give them a little bit of padding. Let's say 6 pixels. The reason for the padding is because we're going to include a border. One pixel border, solid, and let's make this d1, which is a light shade of gray that will match some of the grays that skeleton uses. And finally, skeleton likes to round corners on things like buttons and input elements, so let's do a border-radius and we'll keep it small. We'll keep it to about four pixels. So that's a good start, let's see how that looks. Already things are starting to improve quite a bit. Next, I don't really like the extra margin that skeleton is adding to the bottom of these paragraph tags here. So lets go ahead and remove that. We'll say the chirp paragraphs should have a margin bottom of zero. Okay, that's a little bit better. Now we also have our timestamp here. Why don't we make that a little bit of a lighter color? So we can say .timestamp. Remember, that was the class that we gave that span, and we'll set its color equal to #d1d1d1, the same lighter shade of gray that we gave to the chirp border. And that's nice, I think. It's subtle but you can still see it very well. The last bit of styling I wanna do is for our image here. Right now, notice how the gap beneath the bottom of the image is actually a little more than what's on the top or the left? Well we can fix that if we say .chirp img needs to be display: block. Next thing is, we want it to have the same slightly rounded corners as the box that it is inside. I think that will kind of be a nice effect. So I'll just copy from border radius and I'll paste this down below, and you can see that looks a little bit better. Now the next thing about our image is actually related to skeleton's responsiveness. Right now, if I shrink our image like this, notice that our text actually shrinks behind the image. We can actually fix this if we set the image to a width of 100%. So let's say the width should be 100 percent. And now when I refresh the page, notice how our image has shrunk as well. So if I make the page bigger, the image grows, and if I shrink the page, it gets smaller. However, we have another problem here is we get too small. Because right now you can see skeleton is still displaying two columns side by side, our navigation column and our content column. However, at some point it gets too small for columns and it actually switches to Navigation above and content below. However, at this point 100% width for our image is just terrible. We can't have avatars that are taking up a mobile screen like that. So what we can do to fix this is at the width where skeletons, which is two columns on top instead of columns side by side, we actually just hide the image. Then the image won't display at all, and our text will look a little bit better. The user won't get the avatar, but it is much better than just throwing a full screen avatar in their face. So the way we can do this is with a media query. And what I'm actually going to do is wrap the styling for the image that we already have in the media query so we'll say @media and we'll say the minimum width, where this styling acceptable, is at 550 pixels. So anything smaller than that will not use this styling. Instead we'll say .chirp img and we can say display equals none. So now if I come back and refresh the page, when we're at desktop width here, everything looks good. As we get smaller, the image shrinks. However, when we hit 550 pixels, you can see now the avatar is gone and we just see the text, and I think this is much more acceptable than our full screen images. Excellent, so now we have successfully displayed our chirps in a really nice format.

Back to the top