Build a Portfolio and Blog website using Next.js, GraphCMS(HeadlessCMS) and Tailwindcss - Part 2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay so i've quickly quickly had a look um at the syntax a quick had a look at the syntax for our graphql query so what we need to do is we can query our portfolios like this and we say where and where it's going wrong is we need this object where the slug is going to equal um and then you know let's do this work hard anywhere like so and then we pass that in and then we're back to title description and then what we need to do to make this work for dynamically is add these variables so i think we can add a slog variable like this um so we'll just do the same thing work hard anywhere and then if we do like this variable slug is not defined so let's have a quick look at this i don't need to i know we need to define it so yeah actually let's do it well yeah if we do query uh where's it going query well so we give the query a name query get part four leos like support folios let's have a look query get portfolios we're gonna say it's gonna take in a slug variable which is a string like this then we want to return portfolio portfolios like this where and then we can say slug can we do it like this or sluggish slug i don't know and then we want to get no variables are about jason ah yeah cross errors line to expected name this is not to expect a name but found that why is it not liking this so i query array title is it that wire syntax i don't need the wire syntax so let's just take that let's just take this let's just steal it and um see where we get to so query get portfolio we've got the slug which is a string we want the portfolios where the slug equals slug and then we want to return the id and the title unknown argument slug on field query dot portfolios why on an argument so is that why we do this where and is this not just where we were before okay perfect so i'm not sure what i had wrong with my syntax but um we've we've got it now so then we just want to get so let's copy these across but then i also want the content so okay so we now have this query so let's see what that looks like in the front end so yeah sorry about that i'm still figuring this uh this graphql stuff out as we go the syntax is a little bit strange when you don't use it a lot um okay so we need in our folder let's do um a portfolio folder and then we're going to need a slug dynamic route like so so we're just going to have the word slug wrapped in square brackets dot js um and then you know let's just copy this index page for now to give us something so we don't want we are going to want that so let me just make we just want to get portfolio items because what we're going to do is inside of get static paths we're going to find all of our portfolio items so in we don't have an api folder we don't need that where is it going lib here we go so inside of here let's um let's just make another called get port folio items like so everything's gonna stay the same we're just not gonna have these posts yeah so get portfolio items we're literally doing the exact same thing um except we're not having posts and then what we can do on here is get posts and we're just gonna have the the post and not the not the portfolio items like so so we've got now get post and get portfolio items so for this one we want get port folio items like this and then i believe i've got the file slash.lab there like so so we want to get part follow items and then we can return props portfolio items is going to be there like that i'm going to take in here portfolio items now this is a we're not actually going to we're not actually gonna yeah what am i doing i don't want the all these items get portfolio items i want them i get static paths so what we want is query now for um okay let's do this so we'll get get part folio item which is going to take in a slug like so and then the query here is going to be this and then we're gonna do variables like this so that we're gonna say slug is gonna be slug so we can just do that constant so it comes to variables and i believe we just pass the variables in there like so so get portfolio item yeah so on here let's do get portfolio item so we do const portfolio item equals the word get portfolio item and then that needs to take in the params.slug and then we can take the params from here and then we can just return this portfolio item okay and then we do want to pass this portfolio item like so and then let's console like that so we can get rid of this and then you know let's do a h1 and just say you know portfolio item dot tail so where we are awesome portfolio if we click on that then nothing happens that's not good facebook arc landing page so we need our get static paths so what i'm gonna do right now is let me just so if we do get static paths equals this and then we want to return i think paths is an empty array we'll do fallback for true and then hopefully i'm in the right place did i is that a portfolio i am yeah get started paths yeah we've gotta get started paths oh that is not the right page sorry okay let's take paths okay can i read property title of undefined so what we can do um we're going to import the use router hook use router and i'm only doing this we're not actually going to use this from next router down here we're just going to say router equals use router so we're going to get the router and then we're just going to say if router dot is fallback and then i want to return um a div which just says loading like that okay perfect so essentially let me let me explain kind of what i've just fumbled my way through so we're using the get stack props function which is allowing us to statically generate these pages now because we have a dynamic route you know if we have an index page this is a static page right now um but there's only one page you know and it's right here it knows it exists if we created an about page and we did some more stack we use get static props again there's only the the one singular about page and that's going to be statically generated on build time but next gs doesn't know by default where all of our portfolio items are or where all of our posts are you know it doesn't know about them so you know what do we do in that instance so you can take two main approaches the first one which we're gonna take today um because i think it's good so you can see how it's done is we're actually going to tell nextgs where all of our um where all of our posts and portfolios are so we can statically generate them a build time for us we're gonna declare that in this get static paths function and the second approach would be if you had you know if you had 20 000 blog posts then to go and do a data fetch 20 000 times and build that page it's going to take some time you probably don't want to be um to be doing that so then what we could do is we could do where we've got a fallback mod so what that means is if when you rebuild your website you're not going to build any of these paths in advance but then when someone navigates to the page which you can see here it's going to it's going to attempt to um it's going to attempt to find the thing that you're looking for and if it's there then that's great it will display the content if it's not there then it will fall or fall um but that just means that there's going to be a load instead so this is why we do this if the router is in fallback mode as in it hasn't found the it hasn't found the the page i need to go and find it and then build it um if it's in fallback mode then we're going to return this loading and that's kind of what you can see happening so cool so this portfolio item.title welcome to our awesome portfolio did i do that title for everything oh yes we're not actually displaying a h1 anywhere so we got an object portfolios i see what's happening so what we need to do here so we've got in our get static props we're returning this portfolio item which has got portfolios and then zero so we're going to say portfolio item is portfolio item dot portfolios portfolios um zero like that there's no e in portfolios and then let me console like this portfolio item okay perfect so we've now got our title display and then underneath welcome to our awesome portfolio but that's for the home page so we can see now dot facebook app landing page slack app design concept work hard anywhere and you can see when we navigate into those pages it's it's fetching that data so yeah the next thing so it's working the next thing that i want to do though is to actually get all of these things and generate all of the paths in advance so if we go to the next js docs next just org docks get static just type paths so we need every every path so we've got an array of paths but everyone needs to be an object which has got params and then this is going to be our slug so essentially inside of these paths we need to have an object which says like params like so and then we're going to have slug and then we'll have our slug goes here and we want to generate an array of those um so this is why i want to get all of these portfolio items so we've got get portfolio items um and then what we can do let me just again just to be as efficient as possible what if i just done to be as efficient as possible let's do get portfolio like so and then we can just get all of the slugs like so so we're genuinely just going to return this portfolios object with the slug and that is it so get portfolio slugs so let's get portfolio slugs like so so in our get static paths i'm going to make this an async function and i'm going to do const slopes equals await get portfolio slugs and then i'll say console.log slugs let's just leave this empty again for now and then let's refresh our page so then we've got portfolios and that is actually almost where we want it to be so let's just say now um const oh slugs response is that and i'll guess slugs equals slugsresponse.portfolio just so it makes a bit of sense slugsresponse.portfolios like that so then inside of our paths let's see if we can do this so let's just say so you don't need that array slugs dot map and then for each slug we want to return and then let's just check that syntax again so we want to return an object that says params and then the slug is going to be slug dot slug right i know params center slug is going to be slug dots look that fallback should be false so let's see if we've broken it no and of course it's still going to in development mode it's still going to um rebuild on every refresh but if i now just do npm run build you're going to see what happens so instead of like it will know about all of these portfolio pages now so what i'm expecting to see is you know it's going to statically build those pages which it has so it's statically built these three slog pages for our portfolio so yeah they're they're there they exist and the yeah we're never gonna have fallbacks so if someone goes to a url which is not um already built well then it's going to 404 straight away because you have this fallback mode to false so yeah when you when you don't have you know thousands and thousands of items then it's it's good to just actually generate them all on build time um certainly for a portfolio website and a blog you know that's um that's a good way to go about doing it so let's um let's continue on so you can see if we do a slack app design concept with an s we're gonna excuse me we're gonna 404. um as opposed to this cool so we've now got our index page done we've got our portfolio route done we now just need to do the blog so what i'm actually going to do i'm going to create a new folder inside pages called blog and then we're going to have a new file called slug and let's copy all of this and then let's um let's see what we need so in our data file we're going to need portfolio slugs let's do get blog slugs and then we can change that to posts like so and that should work and then we've got our get posts which yeah i don't think we need that anymore because we're just using our get slug one but then we will need the portfolio item so we'll need to get post so we're gonna have the same slug variable um but let's change the instead of getting a portfolio we want to get a post get post and then we want to say a post or a sluggish slug um take this stuff here is that working so we need a post slog and so let's add in the post log here yep so we've got the post and then what else do we need so we've got the author name and image tiles look so we need the content and i don't think there is anything else we need so if i copy this query oh didn't mean to do that so we copy this query here we've got our get post variables is a slug get post okay and then let me just get rid of that error for a minute okay so in get static paths we're gonna want to get get posts slugs did i not do that i get blog slugs okay get blog slugs get blog slugs slice response dot posts like that i believe uh that should be good portfolio so it comes post equals await get post so we're going to import that as well we're passing in the slug and then we're going to return the post it's going to be post art posts and it's going to be the zero as well we want here so returning a post so we're going to take that post let's can select the post we don't actually need this now because we're not using fallback and then post our title and yeah we're not using the router so let me just clean this up and then let me go clean the other one up as well we don't need this we don't need that we don't need that i don't need that okay so let's see what we're up to perfect so that is working welcome to our awesome portfolio we don't need that either okay so pretty um pretty good progress we have now got that working and just to verify that the paths are working we can do npm run builds and like i said we're expecting to build you know nine pages now because we also declared our blog post in advance which we have and then if you do um npr's npm start our development server now becomes a production server and you can see how quickly things are running because yeah we're not fetching that data in advance we've statically generated all of this um so yeah you can see that that is working so okay cool now it's time to sort of flesh this out and make it look nice all right so let's um let's just get all of our content on the page and then we can worry about making it look nice after that so let me close all of this stuff let's get organized so let's first of all we'll do our index page last so for our portfolio let's start the dev server and let me bring it over here okay so on our portfolio items we're gonna want we've got the title but then let's counter log out this portfolio item and then we can just start getting these fields so let's do um so we do a p tag why can i not type so then we want portfolio item dot description let's do the tags so let's add a div um then we'll say portfolio item dot tags dot map and we'll say for each tag let's return um i don't want to pee doug let me just do a span for this um the key is just gonna be the tag itself that should be unique um at least for this use case and then i want to do the tag is that um that's good so then we have got the cover image so let's import image from next image like so and then let's just chuck in here the image component is going to have the source which should be portfolio item.cover image dot url the width is going to be dot width and then the height is going to be dot height okay so we need to add this url to our next config so with next image essentially next image is automatic image optimization it's going to allow us to just chuck in this um pretty much throw any image at it and it's going to serve it with the right size set on the page and it's also going to serve it in you know the best formats so more than likely webp for most browsers so do next.config.js and what are we doing so module.export we want to do images and i believe we do domains and then we need to do it like that and we need to restart our dev server for the changes to take effect and hopefully we should see an image yep we see an image and if you look at the um the network tab we've got this image it's a 56 kilobytes and it's served as a webp as opposed to if we go into our content portfolio this is the workout anywhere this is a png image um and if we inspect here i'm not sure yeah you get my point it's a png and it's probably significantly significantly bigger than the one that we have now so that's a jpeg 220 kilobytes um so yeah okay so let's um let's continue on the next thing what is the next thing we want to add so we've got a title we want to do the author do we have the author title description slog tags so let's just have a look so what we're doing get portfolio item okay portfolio item we don't so let's just go and edit this query um so if i just copy that and let's just make sure we do the right stuff so i want to get the author all right no sorry this is a portfolio item there is no author that's why um so we got title tags the slug is fine we've got the description we want the date so let's get the date so we might do that somewhere near the top um let's just do a p tag let's do portfolio item let's just do new date which takes a portfolio item dot dead dot to death string it's cool and i think that is it so the last thing we're going to need is our content so we're going to be using um next mdx remote this values for my blog and there's actually an example of how to use this um specifically from the graph cms api so we're going to need next mdx remote and i'm going to use this he library which i've never used before until i looked at this example earlier but it's a robust entity encoder decoder um so we're gonna use that as well so let's just kill the dev server so we're gonna npm install next mdx remote hg um and then we're gonna want these three things like so so let's pull that in and then as you can see they're doing a similar thing so you've got a guest like props we've got the query in there get static paths they are doing a similar thing um i think the thing to know in the get started props function we are returning a product prop here um and we're aware in this render to string method which is taken in the markdown but it's also being decoded you can also declare components so again if you look on you know my blog for example um we might have an image component yes like this is a next image component this is a custom component um which we can pass into the markdown i'm not going to get into doing custom components i um we're just going to stick to regular old markdown however it is relatively simple you can see the example here you have got a component here so a h2 component which you're passing in these components here so if if in the markdown text you had a h2 it would um it would change it like this and what what we can do we can use this for our images as well so let's um let's do this so we want to within our get static props um we've got the portfolio item but then we're also going to return the content like this and then we're going to do um so content and then we're going to await render to oh what's it just brought in there some render no render to string and we're going to pass that in um the content but we're going to do he dot decode and that's where we're going to give the the content so it's portfolio item dot dot portfolios records 0 dot content like that i believe um and then of course we want to bring in that content here and we're gonna need to so you'll see how it's done so they use the hydrate which is going to um if we do declare components which we're not going to so we're just going to pass in so if we do what's uh just uh yeah we can do a p tag now we're not going to do a p tag let's just do another div and then we can call hydrate and we want to pass in that content like so so if we run the dev server again when this reloads hopefully we're gonna see some content okay perfect so it's not looking great but this is markdown content that you can see right here okay so hopefully that makes sense now we need to go do the same on the blog so let's uh we don't have image so let's do let's take those while we have it there and then let's start just spitting out all of our blog content here and we'll get into style on that afterwards so if it's a little bit slow sometimes in development oh can i find files okay and i think that could be a a caching issue um can't resolve f s i don't have f s normalize file is this lip balm okay let me restart my dev server i'm not sure what is causing that error because i'm not using that anymore all i do believe i've had this um this error before now that i think about it can't resolve fs level next jazz [Music] i think add in confidence empty angela means you're important a service server only depends on code that will be shipped ah okay i see the problem so because we're importing these um and we're not using them within our get started props i think it's yeah it's it's bundling those for a client side um which is obviously not good um because that's not what they're intended for so you see in in our portfolio we are using this next mdx remote render to string we're using that on the server because we're doing it within get static props and hydra has been used on the client so this render to string method it's not been shipped to it's not been built for the for the client side of the application because we're only using it in get style props but whereas in this file we weren't using anywhere so it was being built into the client um so let's um apparently so yeah let's try it now and i'm sure it will work that makes sense okay perfect so let's start and get this stuff onto the page so we've got an object here so we've got an author content select to date description so i should be able to copy some of this stuff over um yeah i don't want that image within that same div actually work out that just on its own so yeah we can take these two um so it's going to be a post dot dot and then a post a description let's take this i don't want that inside that divider so let's take this div and we've got the paused dot tags like so we don't necessarily have an image um i want to do div and let's do like post.author posterauthor.name and then and then we can do an image like this and then yeah let's just copy this one post dot post dot author dot image was it poster author image yeah sets import image from next image okay [Music] and then let's make that a lot smaller and we'll format this correctly using css so there we've got the title date description author name author image tags and then yeah let's do this content stuff now so if we go back we have got this content so from our get static props content oh we need to import this um so we want post dot pause zero dot content and then we can take that um so beneath the tags then we want the content as well can i access property compile sales params is undefined content aware rendered stream post dot pass zero dot is it called content yeah that content through other content hydra content okay as you can see i couldn't see any couldn't see any problems with it all right so now we have our blog post so moving on we've got i think everything we need so we're going to format out a header a footer for the site and yeah we're going to continue flashing out and making it making it look nice so let's get into making this look presentable um like i said i'm not going to focus on doing anything too fancy you can go away and make of this whatever you like at this point where you have all your data um yeah it's really in your hands with with what you do with that data but for now let's let's start by making a components folder and we're going to do um what are we gonna do let's do a header um so xbar default function header um and then within the header we're gonna return um a div i'm gonna have a div that just contains you know awesome portfolio and then we're gonna have a ul which contains um i don't know let's do a times three so we want to get rid of these hairdressers because these are going to be links um let's actually i have messed this up i want to wrap these let's just do it like this so we want an ally within that we want a link it's going to be a next link um we're just going to hard code these so we've got an ally a link and then with inside that link we want just a regular old a tag with no href like so and the first one we're going to call home um i don't know why it's done that let's import link from the next link and then we can copy this down so let's do a home we can do an about page like so let's do um portfolio page and then let's do a blog page we could add a contact page if if we wanted to portfolio and then slash blog like that and then let's get to styling this so i want the header to appear everywhere so i'm just going to i'm just going to do this let's add in a fragment like so and then above that let's bring in that header component like this so we've got our header now and that will appear on all pages so let's get to styling this so the first thing i want to do on the very top one i want to yeah actually i want to make this have a div underneath add an extra layer of dibs so on this one the very outer one i'm not going to do anything for now let's just see what i get to so class name let's flex this one and justify between and then i also want to do a max width let's do 3xl and mxr and that should why is that working do we break something hmm why is none of that working did we do the whole tailwind thing in our app so we've got television css header div so with full so i'm not sure why this isn't working uh let's inspect that so the classes are applying but it's not flexing is that css even working no okay okay okay okay why is that css not working ah did i install what version of tailwind did i install turn css 2.1.2 i'm not sure if that is the one with uh just in time mode let's see if that makes a difference okay so it's already up to date so you have tailwind installed we've got the modus just in time we don't really need to purge for this chip mod but i don't think that's going to make a difference mpn run dev um this is tailwind ui and not tell one css i was contemplating using some tailwind ui components but i decided against it for now for now maybe i will um maybe i will change my mind on that one but um okay yeah so none of the styles are being applied mode that should take a minute to compile now so it's really basically the just in time mode for tailwind it um as you add the utility classes to your html it will only generate the css for that whereas when we disable the the just in time mode it's using our tailwind config to you know generate one css style sheet so to speak um so yeah our style sheet for this application now it will be um it will be pretty large in development as opposed to being pretty small so let me see if i can um let's see if i can add this mode just in time and if it recompiles okay so this is confusing me did something 10 change just in time mode mode just in time since your generalize is crucial that you configure the purge option with all of your template files otherwise it will be empty okay it's crucially considered okay so then if i do next js again and i add in this purge again like surely that is going to okay okay so back to where we started but it's working now so that is good sorry about that so let's continue on with our um with our stuff so this ul let's add a class name here of flex um and i don't want that text for excel on everything on this portfolio let's do you know like text to excel font dash semi bold and then i need this one i want to do items center on this url let's do text large maybe um and then i'm just going to manually add some margin to all of these allies we can do like a space between them but we can just do it manually and maybe just on this one i can add some padding like that one thing that i do want to do is i don't really want this to be light although do i do i know i'm just considering do we do light mode do we do dark mode do we do both um okay i will decide in a minute okay but i mean as far as it goes like that looks just fine and then what we can do so for all of these air tags let me just do this so we'll do text gray 900 and then on hover we're going to do text gray 700 like that um so i'm going to copy that for the air tags you know we could absolutely make components from this a lot a lot of components but um yeah i don't really want to do that in the config though i just want to do cons colors equals require um turn css four slash colors and then just want to make sure that um colors gray is going to be colors dot blue gray like this um why is that got that weird little color we don't want that okay so we have a header i think that text could probably be a bit a bit smaller so if we just do like nothing yeah that is absolutely fine so yeah let's um let's have a look at what we got so i have this on our index page and then we need a way to we need a way to display this stuff quite nicely i think i'm going to start with the blog so what we can do now is if i go to the because we can reuse this one um the index page let's just let's do a div to wrap this and then we can give it the same max width 3xl mx auto treatment like so and then what i'm going to do i'm going to just add some padding padding 4 sm px-6 and then all large screens all the extra large screens let's do like px of 0. so basically we're gonna have padding um padding on the sides yes we're gonna have padding on the sides up until like this point so actually let's do that large because i don't really care for the padding unless because i don't want to ever to be like touching the side of the screen on a mobile um and then let's give the so pretty much gonna give everything that treatment so let's give the header that treatment so that it will it will line up nicely and then what i want to do is for our blog posts so we've got a div with a class name there and then we've got this div so margin top of 10 that one's fine so if i do this as a grid um and then let's do grid calls and then within this let's return actually let's see if this works i don't think i've ever done this before if we return a fragment can we then return two devs in a grid fetching youtube no grid calls for and then on this div let's do class name equals call dash span one and this div let's just do whatever and then we'll say call class name equals calls span three okay great so that's working so then in that span three that's where our first one i have the title and this one let's just do so let's just add we want the date so we're going to say pause the dot so we're going to actually say new date pause dot dot today string like so okay great um so we've got that link and if you remember we just want to have a an air tag to surround the link like that just to make sure that is recognized correctly by the browser and then let's do something like text dash 3xl from semi bold text gray 900 everyone that's too big pick 2xl and we can do you know on hover we want to do text gray 700 um and then we can do like transition colors and duration or something and it will just make it appear a bit cleaner a bit slower and then on this date let's do text gray 600 like so perfect so underneath the link let's add in here a post dot description and we can give that the same treatment so we do like maybe text gray 600 as well we'll leave the text the same size let's just see what that looks like that's a bit light texture 700 just trying to create a little bit of hierarchy um obviously the size and boldness of the title does a good job in that um you know what maybe it's going to be easier if we do this for every oh how's it doing why is he doing that takes gray 700. if we make that into a div and we just do class name equals and then we do it just like that um i didn't like that and then we need the key on there so yeah it's going to look the same um we can then do like py let's set trifall 2x8 let's go with six somewhere in the middle [Music] on this description we can maybe increase the line height so if we do lead in let's try that too big so you can be like quite scientific with that um but i just want to do it leading relaxed well let's do lead in loose i think it just makes it a bit more readable but that's might be a bit too much so let's do it relaxed and i think that is looking pretty good maybe that day is a little bit big so we'll do like text small um yeah okay i think that is looking just about fine we could in that column now let's do the author just underneath so let's just do just do a div and we'll do author no poster author name and then what we can do with that we can do text sm text gray 900 font dash semi bold or something yeah i think that looks just fine maybe a tiny bit of margin on the top separate i kind of want it to be grouped though okay so i think that looks fine clearly when we when we get to about here we want it to be smaller so let's have a look where we want to stop it so right at 770 pixels so if we just look up the tailwind breakpoints perfect some medium so what i'm gonna do with this grid stuff um so i'm going to say grid calls for medium um medium coil span one and medium coil span three otherwise if we do like grid calls one you can see there it goes down to one column and then on this date so we're doing this one so we maybe want to have um some margin bottom like this and on medium screens we'll do a matching bottom of zero okay fine fine fine fine that looks that looks pretty good i would say on mobile screens i know it's it's fine you know i think one thing that we didn't do yet is we didn't do the the author pitch um that'll be an interesting one to add in so we can click on an author and it will go to the author page and show their bio and things so that is that is our portfolio blog kind of done right there and you can see it's ordering them by the date created um by default so let's um yeah let's move on to styling these portfolio items
Info
Channel: Adam Richardson
Views: 1,643
Rating: undefined out of 5
Keywords: nextjs, graphcms, graphql, tailwindcss, headlesscms
Id: oK6BP5uQwKs
Channel Id: undefined
Length: 71min 7sec (4267 seconds)
Published: Sun May 02 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.