- Read Tutorial
- Watch Guide Video
I'm gonna show you my personal vision for this and you can follow along if you'd like to or you can simply watch and see what I implemented. I'm not gonna work with any kinds of tools or skills or anything that we have not already covered, so I'm gonna try to go through this one pretty quickly, more than anything simply to give you an idea of how I chose to do it and also just help with your reinforcement learning.
So, let's get started, on the Portfolio Detail page right here, right now we're only showing the title and then the summary, so I'm going to start building that out. I'm going to create a dedicated style file for our portfolio-detail, so if I go to main here and inside of where I have my portfolio styles listed, I'm gonna create a new file that's called portfolio-detail.
Then I will make sure to save this and as one note, one thing you may have noticed is we have all of our style files listed in a single directory, the larger your application gets, typically the best process that you're gonna follow is to create directories inside of your style directory so that you can organize that, so if we were gonna build this application out even further, I'd create a directory called portfolio and then all of the portfolio styles would go inside of that. So you could have more nested directories, kind of like what we've done with our components directory, so just a little side note on code organization. Now that we have that, I can hit save and so, I'm gonna be able to close out of main.
Now let's talk about the structure that I'm going to implement here. I'm gonna get rid of all of the divs so I can just start from scratch and I'm gonna start with a wrapper div, so I'm gonna give a wrapper div of a className of portfolio-detail-wrapper and just so I don't forget the names as I write them, I'm going to put them into our new portfolio-detail style file, so that's gonna be the very first one. I'm not gonna worry about adding styles to it yet, I'm gonna first start off by just picking out the code that I wanna slide onto the page and render onto the page.
So, now with that in place, the next thing I'm gonna create is what I will call a banner, so my vision for this is I wanna take that banner URL, 'cause we have that nice big image and I'd like to take that and stretch it all the way from side to side and it'll be different for each one of the portfolio items, so I'm going to create this banner div here and for this, I'm gonna slide in some styles but I'm not gonna put all of them in the portfolio-detail page.
I'm gonna use some in-line styles because we want this to be dynamic, so I want the banner for DailySmarty to be different than the banner for Crondos and I'm guessing you're probably gonna be the same way. So, I'm not gonna add any styles here and I'm not gonna add any classes besides just that banner class and now inside of here, I'm going to place an image tag and this is where I'm gonna place the logo.
So, I can say src and then just the logo_url and then close this off, I'll also need to add a few styles to this as well. So now with that banner in place, I can add the description. That's gonna be relatively straightforward, so I'll say div className equals portfolio-detail-description-wrapper
and then once again I'm going to take that className and put it inside of our portfolio-detail just so I have it and so, I'm not having to go back and forth checking out those names to make sure I don't have a typo or a slightly different name.
Now, inside of here, I am going to create a div with a className of description and this description is simply going to render out the description that we're getting from the API, so that is all gonna be inside of that wrapper and then lastly, I want to link out to this portfolio item, so I'm gonna create a div, give a className here of bottom-content-wrapper in case I ever wanna put anything else besides the link here and now inside of this, I can give an a tag.
So I'm gonna say a tag href equals and then the url and that is the URL for the site itself, so each one of the portfolio items, if you do have a URL for them, then this is where it'll get rendered out and I'll give this a className of site-link and then I'm gonna use the target equals underscore and this is gonna be a string, so not a curly bracket and then that's gonna be blank and so, what that's going to do is it's gonna make it so that if someone clicks on one of these portfolio links, it'll open up a new tab and it won't take them away from the portfolio itself. Then inside of here, I'll say I want you to visit the name.
portfolio-detail.js
return ( <div className="portfolio-detail-wrapper"> <div className="banner"> <img src={logo_url} /> </div> <div className="portfolio-detail-description-wrapper"> <div classNaem="description">{description}</div> </div> <div className="bottom-content-wrapper"> <a href={url} className="site-link" target="_blank"> Visit {name} </a> </div> </div> );
Okay, let's test this out and let's see it, also hit save here for the portfolio-detail styles, not that we have any yet. And now if you hit Refresh right here, you can see we have some different content.
Our logos are white, so you're not gonna be able to see them but we can see they are taking up some space. We have our description and then we have our link, if you click on it, you'll see that that is working. So, everything that is function based is in place, so now that we have that, we can add some styles, so in the portfolio-detail-wrapper, I'm gonna first start off by saying that I want to use 100% of the view width, so we want it to go from side to side and now let's add some of our banner styles, so this banner I want to go from side to side.
I need to give a predefined height and we're going to slide the background image in within in-line styles but here I can at least establish the height, so I'm gonna give it a height of 300 pixels, display: flex because I want the items inside of it, in this case it's just going to be the logo. I wanna be able to control those and manage those, so I'm gonna say flex, justify-content is gonna be center, align-items is also going to be center and then let's give it a box-shadow just so it has a shadow underneath the banner, so with box-shadow, I'm going to give it 0 pixels, 15 pixels, 20 pixels, and then rgba and 0, 0, 0 and then 0.3 for the opacity.
portfolio-detail.scss
.portfolio-detail-wrapper { width: 100vw; .banner{ height: 300px; display: flex; justify-content: center; align-items: center; box-shadow: 0px 15px 20px rgba(0, 0, 0, 0.3); } .portfolio-detail-description-wrapper { } }
Okay, so those are our banner styles. It's just a banner, that stretches from side to side, and any thing inside of it in this case just a logo is gonna be centered horizontally and vertically, okay, so that's our banner style.
Now let's go down and let's add some description styles. So, I want to say the text-align here is gonna be center so that our text is centered right in the middle and let's give a little bit of margin to the top of 42px, and we want display flex, and then let's say justify-content is going to be center and then let's select the description.
So if you remember, we have this portfolio-detail-description-wrapper and then we have a description inside of it, so let's select this description class and inside of here I'm going to give it a predefined width of 700 pixels. If you're building this for mobile responsiveness, then you'll be able to select this in a media query and then when you access it on a phone, you can dynamically change the width but for all desktop usage, then 700 pixels is good. The font-size I want to be pretty big, so I'll say 2em and then let's give a little bit of margin on the bottom and let's just say 50 pixels.
.portfolio-detail-description-wrapper { text-align: center; margin-top: 42px; display: flex; justify-content: center; .description { width: 700px; font-size: 2em; margin-bottom: 50px; } }
Okay, let's hit save, let's just kind of see where we're at right now and see where everything is looking and wow, that actually is looking good.
We can see our shadow looks good. We don't have an image here. The logo is in the center but this is the layout that I was wanting to go with and then also we have our nice big summary text on what the portfolio is right in the center, so so far, so good.
So, now that we have the wrapper styles complete, let's come here and I'm gonna add the styles for our bottom-content-wrapper and for that, let's go with a width of 100% and then display will be flex, and justify-content: center and align-items is also going to be center, and then we have that site-link class, so site-link and here we actually are selecting the link itself.
I'm gonna kinda make this look like a button, it's not gonna be a button but it's gonna kinda look like one. And the way you can do that is you can give the link and give some space for the button itself, so for that I'm gonna say we want padding of 15 pixels, I want a background-color of teal from one of our variables, then I want to have a border-radius of 3 pixels and then text-decoration: none since it's a link by default, it would have that.
Let me fix that border-radius and then after text-decoration, we want the color to be white and then we want a little animation here, so I'll say transition, if I can spell it correctly, there we go, transition, half a second ease-in ease-out and then a font-size of 1.2em and so that's going to make our link actually look more like a button, so let's take a look at that, and there you go, yeah, that looks really good.
portfolio-detail.scss
.bottom-content-wrapper { width: 100%; display: flex; justify-content: }
Now let's add our hover effect, so inside of site-link, I'll say I want to select the hover and all we're going to change here is the background-color, so background-color now can be dark-teal, hit save and now when you hover over it, that changes and the link is still fully functional even though it looks like a button.
.site-link { padding: 15px; background-color: $teal; border-radius: 3px; text-decoration: none; color: white; transition: 0.5s ease-in-out; font-size: 1.2em; &:hover { background-color: $dark-teal; } }
So, that is all looking great.
We only have one more thing to do which is to populate our image and to add some in-line styles here, so let's come up top here and I'm going to right underneath where we're grabbing all of those data attributes, I'm going to create an in-line style, so I'm gonna create a variable here called const and then bannerStyles.
That's gonna be an object and I'm going to give a backgroundImage and we're going to do our same string concatenation here, so backgroundImage is gonna start off with a url and then we're gonna add on the banner_image_url and then we're going to add in the closing parens for that url and because this is an object, it's not CSS, so make sure you don't type a semicolon there or else you'll get an error.
This is an object, you're simply listing out key and value pairs for your styles and so, the backgroundSize for here is gonna be cover, make sure you write it as a string, and then backgroundRepeat is going to be no-repeat. You could also put that at the end here but I just wanted to show you both ways of doing that, and then lastly backgroundPosition, this is going to be center center. Okay, so so far, so good.
portfolio-detail.js
const bannerStyles = { backgroundImage: "url(" + banner_image_url + ")", backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center center" }
Let's test this out, I'm gonna call our banner styles from our div of className banner and so, we can say style equals the curly brackets and then we're gonna pass the actual styles inside of here.
return ( <div className="portfolio-detail-wrapper"> <div className="banner" style={bannerStyles}> <img src={logo_url} /> </div>
Now you can see that is looking really good, I like that. It's kind of minimalistic but it is my personal style, I like things that are nice and simple like that.
Let's go and test this out with a few other ones, so if I click on Edutechnical, that one's looking really good.
The only difference is I'd like to kinda shrink up this image just a little bit, so what we can do here is we can just create another variable, so I can say const imgStyles or actually let's call it logoStyles to be more explicit, and this is going to be an object as well, just a regular style object and for this I'll say I want the width to be 200 pixels as a string and now inside of our image tag, we can add a style attribute, a style prop really, and then pass in logoStyles.
const logoStyles = { width: "200px" }; return ( <div className="portfolio-detail-wrapper"> <div className="banner" style={bannerStyles}> <img src={logo_url} style={logoStyles} /> </div>
So, now if you come back here, and click on any of those, you can see the logo is trunked just a little bit and I think that it looks a little bit better. We don't want that looking too big, so yeah, if you click on each one of 'em, now they're more universal, they're all gonna be the exact same size, so I think that looks excellent.
I'm excited with how that all turned out, so great job if you went through that, especially if you built out your own layout, you now really have the majority of all the UI portions completed, so excellent job. In the next guide, we'll walk through some of our final items we need to do before deploying this to the web.