Build a Blog with Next.js and a Headless CMS (Strapi)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome in this video we'll build an entire blog post location from scratch the only thing I've prepared beforehand are the designs for the application we'll start by building the front end and turning these designs into an xjs application then we'll connect the next JS app to a headless CMS in the back end we'll use strappy as the Headless CMS I have prepared two simple designs for the book we're going to build this is the list page the home page of the book which will show a featured blog post and no other blog posts be needed and each block will have a detail page which will show the title and Main content together with the with the larger featured image of the blog post we'll start from the front end I will create a next application by running MPX create next app and I'll do the I'll use the latest version I'll call my project headless block you can check out my detailed next.js course if you're interested in next I would not like to use typescript I will use CS lint I don't need talent and I would recommend using a source directory we will use the app router the new app directory as opposed to the pages router of course and you shouldn't need to modify the default import class for a basic project like this I'll wait for my project to bootstrap an xjs app is ready I'll CD into the project directory and I will open it with Visual Studio code here we have our bootstrap nick.js project the first thing I'm going to do is run it with npm run Dev make sure that it is working correctly it's running at localhost 3000 as it says in the terminal and you can see the bootstrap negjs application is working as expected and compiling successfully now the second thing we're going to do is clean up the bootstrap code a bit I'll delete this Global CSS file I will go to layout and remove the import from here I will leave the interformed import from next phones Google because we will use Google fonts just not the entire font but I'll keep this for now as for the metadata I'll modify it a bit the title and remove the description for now I want to rewrite my functions to Arrow and this root layout will be largely the same for now just HTML and body and the children inside of the body of course we need to export the root layout by default from this file and this file will be left like this for now here in the home page I will again rewrite it to an arrow function and remove everything I will from the markup I will just leave a single div tag that says home to make sure the component is rendering correctly for now alright I'll leave the five icon for now for this project I won't make a five icons so let's just leave it so that we don't get an error it's not loading I'll remove this page module CSS file as it's not used anymore and in the public folder we have two SVG icons for the demo app which we don't need anymore okay now the project is clean enough and we're good to go if I open it again we just have the home component the home page mounting and our diving home displaying correctly all right so let's see the design and discuss how we're going to start we have a header and footer in the main layout that are very simple and a grid system I've drawn a 12 column grid inside of a 1280 pixel container pretty standard so we'll start by implementing some main Styles like typography normalize and the grid system and then we'll build the header and footer after that we'll build the card component and this page will be pretty much ready okay let's start with the main CSS files and normalize I will install a couple of things from npm I need plus I will use SAS as a preprocessor primarily because nexgs has built-in support for it you just need to install the SAS package and it will be enabled automatically I will also install normalized CSS from npm I will create a new folder inside of the source folder both Styles and here I'll have a Styles test file which will import all modules and the first module I'm going to import will actually be normalized from normalized CSS the dependency the npm package and actually the file inside node modules is immediately inside the normal icss directory let me show you what that Imports I can use this because the npm package is called like that and if I check my note modules and look for normal icss you can see the folder and inside of it we have the normalized CSS file which very important right here if I open it here's the normalize so essentially if I run my project right now nothing could happen but if I import this style.sas file and I run my project now we have a small error here let me check module not found I have a typo it should be styles.sas and I can already see normalizes loaded because we don't have margin on the body but if I check that ltss file you can see that the normalized CSS is right here great so our SAS setup is working and we have normalized The Next Step will be to add a global C Class file or any other Global side effects modifications and normalizations I'll import that as well I can just say globos because it's in the same directory and it's a SAS file in this case and the first thing I'm going to do is set box sizing to border box for all elements and pseudo elements pretty standard to normalize the Box model and um yeah that would be the Google's file for now we'll add some other body styles here later The Next Step will be to set up the grid system grid for that I'll make another file code grid.sas and here I'll first make a container let me open calculator real quick so basically the width of the container is 1280 but I want 20 pixel padding on both sides so that it can scale oily on mobile devices so I need to add this 20 pixels to the overall width so our container should have a Max width of 1320 and a 20 pixel left and right padding lastly um I will set margin left and right to all zero selected centers and that's the container done next in a grid system we need a row I will do a flex grid uh the the direction of the flex uh display Flex is row by default so we don't need to specify that now there are many ways to set up the gutter we do have a 30 pixel gutter here in that grid system meaning the spacing between the columns what I'll do is negative margin left on the row I will also set width to 100 plus 30 pixels who will allow me to now on the clockwise it should have Plex set the one so that it grows and expands and I can set by link to 15 pixels now this um this is one way to do it you can also just set Gap to 30 pixels but then the width calculations of the columns would be a little bit more complex later um so this is the approach I'll take there are many ways to implement a grid system you can also use a ready-made grid like the bootstrap Grid or many other grids available online they are both Flex grids and others here we also need to set Flex wrap to wrap so that it wraps if the width is not enough and now we need to actually generate columns here I would like to have the syntaxis both for one through call where each will set a width of a certain percentage where code 12 will be 100 code 6 will be 50 Etc pretty standard grid for that I'll do a for whoop thus there we go this is the four whoops syntaxes and we will do it from 1 through 12. true uh means inclusive in says actually let me close the docs okay and reach entry we will generate a class it's shrink interpolation and that class will set menu it do we need to First calculate 100 percent divided by the number of columns in that case 12 and then multiply that by the current iteration you could do that calculation beforehand and just start code it here but it's not a good approach because it will be less understandable and we need to set max with the uh to the same value in this case studying Mark sweet and Min width is not the same as just selling quit because we're working with the flex container that's why we need to set both and they should this should be the grid ready let me just check if the classes have been generated properly by just going to devtools and testing them I will get some of them and they don't seem to be generated let me see I haven't imported grid in my style okay now we have echo1 row six is fifty percent and call 12 is 100 as you can see great and Co sets Flex to one enter padding awesome so my grid is ready we will be able to test it thoroughly when we get to the point to use it but I'm sure it will be working correctly because it's a very straightforward to create okay next up let's do some goal style of day the background is actually the entire site is actually not white it's a very subtle shade of gray which I'll set in globos okay great and the fonts used let's set that up next our lato for the headings the H1 H2 Etc and open sounds for the body Tech where the body text actually has a color that is not black but the headings are black so let's set the polytext cover here in globos great and let's set up the font I'll do that in the main layout as I mentioned we need later and open sounds from Google fonts now initialize both right here okay and open sense the same way just initialize the function okay for later I might need to specify weights me check yeah missing quotes for later well for open sense I don't have that issue because it's now a variable font uh for later I'll specify only 400 700 and 900 plus weight with strings as you can see in my terminal I need only this because I'm using it for headlines we don't need the thin font weights and I will also specify the variable setting because I want a CSS variable for both of these this will be called font later and I'll set one for open sounds which will of course be font open sense great and now we need to set the class names to the body here I will have multiple class names now first I'll set open sounds class name so that in the body sets the font to open sounds by default the font family and now I will add the classes for the variables using open sounds variable and later variable and now if I test first of all my body text should be open sounds like this and I will also have my variables there they are font open sounds and font later ready to use okay that's awesome now let's create a typography file which I will also import and here we'll Define some typography styles first I'll set the base font size to 18 pixels on the HTML and body and um the font family is already set on the body so no need to do that after that I'll do some basic paragraph styles or is it the margins to 30 pixels bottom only and I'll set line height to 1.66 I will now style all headings and I will create classes for each heading as well so that I can use the heading Styles without the actual heading tag and the headings will first be black uh that's a major difference they will have a font family of my later variable and the font weight of 600 by default so they'll be bold and um that's that's pretty much their basic Styles set I will also set their Baseline Heights 1.25 and now we need to set the sizes for each in for each heading starting with H1 which I can check in my design is 52. I will come to my editor and open calculator 52 divided by 18 is 2.88 Rams okay let's do H2 I actually don't have an H2 on this page I have it here it's 43. 2.388 okay let's go for the H3 now this is its style it's 34. that's 1.88 let's go forward this is my age 4 Style 24 pixels let me check 1.33 and my H5 would be 20 I believe let's see no it's actually 18 and 16. yeah so my H5 has a font size yeah sorry my H5 has a font size of 20 which is 1.11 and my H6 has a font size of one ram these are my headings done exactly as in the design I will also reset all margins on the headings I will set margins individually for each heading only keep the default margin on the paragraphs okay this is the basic typography done I will now create the header and footer components what I'll do for that is create a new folder in app called components and I'll start with the header.js file here I'll create a react component for my header which will be exported by default of course it will have a header attack a container and as you can see as you can see my header here it has just a simple headline all right now I will use this component in my main layout here we have our body tag and the children and above it I can add my header component like so great and here it is let me Zoom to 100 percent and our component has a font size of 52 pixels blind height of 64. let me check if the line height should be like this no okay um so now we need some spacing above and below the heading in the form of padding it's the spacing is 80 pixels both sides I will create some spacing utilities for that upgrade the UTS folder and data spacing file world and how import that okay and I will need top and bottom paddings another great Maps just some lists actually which rule is the paddings I will need for now that will be 80 but I will need more as we implement this layout and then I'll iterate to this list and for each iteration I will generate a class which will be PT Dash D value in this case 8. and that will just set planning top to the appropriate pixels so this code right now will just generate this and uh it's a little bit overdone for just this uh this property but if I need to add one more adding top plus I will just write it right here so it scales a little bit better and I'll do the same thing for the bottom class okay now I will make sure that's imported yes and let's see if my classes are generated and working all right they seem to be working perfectly actually okay let's add them permanently to the header I will zoom out the page a bit so that we can see it better all right I need to refresh great so that's basically my header done actually now I'll focus on the footer it's also very simple as you can see just basic horizontal line and some copyright paragraph text let's create the component I will use the footer attack and again I will a container and here the basic markup is quite straightforward horizontal line and copyright text great add it to my layout to import it and add it right here okay now it should be welded right here and it is now what I'll need to do is dial the defaulted horizontal line because it's has a little bit of a different style than in my design here in the design we have an opacity black border with opacity so a little bit Overkill but I'll create a separate file for it to keep up with one file per component it doesn't really hurt anything and I'll just set border cover to Black weight opacity 10 percent and import this file alright a horizontal line is set I also reset its default spacings right here and the paragraph has its pass it's actually exactly as it should be I believe in the design let me check again hide the grid real quick yeah okay we need some spacings here I believe the space between those two is 30 pixels yes that's exactly right so I will add a margin bottom Utilities in my spacings file this will be used a lot now again create a map and we need only 30 for now all right and this will set margin button that's all now I will actually immediately set that quest to my footer component to my HR action and here we go I have my spacing set correctly now the last thing I'll do I have basic on my paragraph So yeah my footer is pretty much done now um here in the home we just have a simple diff for now but we can start focusing on the home page which will include a simple card component maybe not so simple I will make one card component that will be useful for this featured blog post and these blog posts using container queries because they will also scale well I'll show you right now how that will work we will start by implementing the larger card component and then right container course so that it scales down okay to do so in my components folder I'll create a card folder this is because my card component will have about JavaScript and a module files file and now create a JavaScript component a react component first okay and I will also import styles from the art module Style so the card will have a wrapper with a card class name the markup will be very simple um we need this kind of layout where the image will take 50 percent of the space and the content another 50 with the 30 pixels gap between them I will not use the grid for this so that I can scale with container queries without modify applying side effects to the grid system I think this is better design so for the image I need a couple of wrappers actually I'll call them card image wrap and then I will need and lastly the image now I need all of these these two wrappers because I also need to set it to a 16 by nine aspect ratio and I will need a separate wrapper for that in order to scale it later now I won't use the image stack I will actually use the image component from next image because it will also optimize my image all right we also need an old stack of course a note attribute of course and for now I will just hold one of my images statically I actually have prepared my exports right here from my design just the thumbnails and featured images and I will move this to my project in the public folder and as they're in the public folder I can just load one of these thumbnails this one like this some featured article webp and I'll write thumbnail as the old text for now in next image I can set field to true this will make the image position absolute and make it expand to its parent in this case uh to its position relative parent which doesn't exist right now so to take over the whole page take a look uh it won't because the card is not used anywhere but it will later and after my image wrapper I will need a wrapper for my content which I'll call card content inside of it we have a couple of textual guilts we first have a label for the category I'll call it label and it will be it will have the hard-coded value of product reviews for now next we'll have the title which will have the card title class and also to have a style of H3 and I'll hard code the title as well for now see all of these values will later be used as props and used taken from the Headless CMS eventually next we have a summary right here which will have in a class of our summary and the last thing is the button which I will not add for now I'll make a separate component on switch style our card okay uh let's uh actually import and use this card in my page so that we can view it and test it I will import it from here all right okay I will add a container here and just the card components inside I also set some padding bottom to separate it from the footer temporarily so right now the image is taking over the whole view because we don't have a position relative there is um until we style it so let's start doing the stuff starting from cart needs to be display Flex it needs to have sex direction of row for now because you know the content is horizontally um the content is the layout is horizontal and we will set a gap 30 pixels in this case because it will work well and here we're pretty much done with the main layout I need to also set order radius of 10 pixels and overflow hidden so that the Border radius is applied to our Inner Elements that are overflowing and lastly we have some box Shadow here which is 21 pixel spread with seven percent opacity so let's play that it's a black shadow like this okay next up we need to set the layout on these two Inner Elements the image wrap and something which should have a flex one to expand so that Baltic found the fifty percent and that's it for them for now the card image will have a position relative it will have weight of 100 and aspect ratio 16 by nine I also set Min height to 100 so that if the aspect ratio if the aspect ratio is a calculation of height is less than the overall height of the card it will actually and higher you see how that will work in a bit as that I'll set object fit cover to the image inside of that wrapper if we test that out now you can see this is starting to look a little bit like it so here's how that works here we have our cart Flex container with the 30 pixel Gap the image wrap so far just has text one to expand to 50 as well as its other sibling the content and inside the image wrap we have this card image wrapper which has position relative and the aspect ratio of 16x9 now we have a mean height of 100 percent so the cart image upper has an aspect ratio of 16x9 but also main height this means that if this content grows more than the image height image will uh disobey the aspect ratio Rule and expand more so that it looks nice alright now the next thing I need to set is the actual padding here on the card content as we have a gap we don't need padding left otherwise the spacing around it is consistent at 30 pixels and just the left value will be zero also card content should be vertically centered compared to the image which I'll do right now by setting to display the flex the direction of the column and I'll justify the content enter there you go great now all we have to do is tell the inside component of card content the label is a heading with size 18 which means an H6 style let's apply that right now besides that it has a bottom margin of 10 pixels and an orange color so let's add both the spacing first in margin Bottom I want 10. and incart about the class let's check that out there we go now I will add some utilities for cover which I'll go hours and the first one will be orange okay I'll import that in my style and I can use it now right here now this will not just be orange depending on the content of the category product reviews opinions travel guides we have to change the cover with a map depending on the value of the category but we'll do that later now the next item is the title which is an H3 I already have that style applied let's just check the other properties it has a line height of 42 which I believe is correct yes and it doesn't have any margin bottom and it should be 20. so I'll just add that to the spacing utils right here and apply it right here all right and my paragraph text is 18 uh actually my paragraph is not a paragraph right now so I need to change that real quick so that it has proper line height font size 18. and here I need to set the font weight to semi Bolt which I'll do by adding utility for that I'll call it phones Pro font utilities and let's create a list for that as well okay so FW in the value and then that will send that will set the font way you can also use a framework like Tailwind which will provide ready-made utilities for you that would be great choice in many cases so that you don't have to write utilities yourself I prefer to do so let me see we have the class we haven't imported it right here okay good we have a default margin bottom of 30 pixels let's check if that is correct by Design I do believe so yeah yeah that is okay now we have to create the button component to do so I will create another folder in my components folder right here right next to card code button this is because our button will also have a module.sas file and a react component okay I'll import the styles all right my button will actually have to check its props and if uh href prop is available it will return an anchor deck actually uh a next link component not a pure anchor deck so if Prof Square f is here it will return our link props children and the href will be equal to props href otherwise it will return a button this way the button will be reusable as both a link and the button button element okay now I will actually use it in cart check cut functionality first imported I will set an href to it and a value of read more and it seems to be working correctly okay the button has very straightforward Styles it's a pure shaped button the only interesting thing about it is the icon probably it has consistent spacing of 10 pixels top and 18 pixels to the side which are around to 20. and the basic font size of 18 and later both okay let's um start writing the styles for it for that I'll set a class name to both I um the link and the button because they need to look consistent and that's will be bottom class here I'll create the button will have display of inline legs I want to flex tail so that I can position the icon and the text note correctly we have a gap here of 10 pixels the direction is row we don't want any wrapping and we want to actually align items enter so that the items are centered on the vertical axis okay the padding as mentioned is 10 pixels top and 20 pixels to the side which is one point okay and the font wait uh the formed Family First will be found later on weight will be 600 the default ones we also have for the radius of 400 pixels because it's a real shape button we need a larger value here not to ever get and we need to get the background cover from our design software is blue okay the text cover will be FFF I also need to set width Max content and that should pretty much yeah sales are now pretty good here in the font properties I'll set line height to 0.75 and because the text won't wrap on two lines ever at least that's not how the component is meant to be used and um text decoration should be set so none now also reset border in case the component is used with its button proper now we also need a some tech some change on the hover I'll just change the background Tower to a darker shade and I will transition to it pretty standard stuff okay and now we need to do the icon the icon I have it exported as an SVG in the public folder I'll just copy the SVG and we need it in line for that I'll create another component here and I will use one approach to make sure other icons would be usable in the future here this button icon component will check the icon type Pro and if that is are all right it will return this SVG element right here otherwise it will return now and we can add other icons here the same way now the last thing I would change is instead of passing this string as the prop I will make some kind of a constant object that will serve as an enumerable I'll call it icon types and Export it from this file where I'll have a narrow write value that is set to this exact string and you'll see how that can be used right now um there we go and let's run this to a multi-line jsx here we will have a button icon component which you have an icon type prop of props I can pass to the bottom okay great now nothing will change because we haven't passed the props icon prop but if I go to my card component where I initialize my button I can first import icon icon types from button I can actually do that here and I can just say icon are all right all right great and I have my icon it's not very pretty right now let's modify the markup a little bit first of all the feel of this patch should always be current power should set it to White and let's see the width and height on this icon it's 12 pixels okay now I'll set this to M values so that they scale better let's see if everything is working correct okay and now because there are values if I change the font size here second is scaling proportionally okay well that that certainly works great and we have prepared the component to support other icon types besides are all right we just have to not the online SVG and yeah I can type right here and in the enum okay great so now the next step to write the container query so that we can turn this large featured card into this card at a certain width we'll start by going to the cart module and writing a container query right here and container queries like a media query except that it doesn't watch the viewport but uh another container which you specify and it accepts Max and Min with values now I need to determine the Maxfield value based on how this component is laid out I think a value of around 700 pixels for the actual item for the actual container here will be great because this is 660 and 700 looks like yes pretty great below that I would want to go to a vertical layout I'll set a max weight to 700 pixels now the container query doesn't know uh what the container is until you tell it so for that reason I'll add another wrapper here to serve as that container for my container story I'll explain why I need that extra wrapper in a bit and I'm not using art you will see and here I will style that first art wrap container type is how we Define a new container the properties you can look up in mdn I need an inline size container these these properties determined from where the container query will from which value it will determine the width we are from which you're specifying the maximum width increase and I'll use inline size you can check out uh very detailed explanations about these values in mdn so now my card wrapped right here has is the defined as the container and I can write a container query for it using one of its children in this case card this is exactly why I needed a secondary wrapper because I actually need to modify this element the card in its layout do a column layout on a certain container in my container query and I can do that if it is the container itself okay so first thing most importantly my card to change its direction to column and that really makes a difference as you can see below 700 pixels we change the column and now we need to make very minor adjustments uh the image will automatically be right because it's 16x9 and it scales great our Gap is kept at 30 pixels I just need to now modify the card content paddings because of that Gap depending soon I'll be zero top and 13 pics 30 pixels on all other side all right we're almost ready the last part to modify the font sizes a bit of these elements first the label becomes 16 from 18. let me check if that worked yes the title becomes 24. all right the summary is hidden completely I'll display none and the button stays the same and that's it my card now ready let me check it scales Flawless let's zoom out a bit right and now I can use it in a grid we need the featured post to achieve this three column layout so let's build that our row and three counts which you have a class of call and call Four duplicate this now add a card to each one of them great um we also need a couple of things on the carton right now everything is hard coded don't need to pass all of these values as props and I also want to be able to pass a CSS blast to do so I will add the props parameter and I'll start with the CSS Quest prop on the topmost wrapper I'm sorry not see this class name first and now let's do checks for each one of these first of all to achieve that I will add a new helper component which are called conditional renderer to be a very simple component to do the following it will have a condition prop and its children and if the condition is true it will render it will return its children otherwise it will return now I use that to render uh conditionally jsx elements in order not to use ternary too much you could write such a component easily probably one that is also less verbose because this is quite a long name and the prop name is also quite old but I prefer that I prefer understandable verbose code that is a little bit longer okay so the condition would be a props a label in this case and in that case we'll render the label and the label disappears immediately because none of my cards have a props label let's add one okay I think I have a typo somewhere yeah all right and I'll do the same thing for all other fields here we will ask for a title prop all right let's add that as well all right great next the summary prop the same thing all right I will copy my summary again because I lost it in my clipboard all right check it right here and for the button to render the button if there is an href crop that href prop will of course be the href property of the button we also need to set icon to button um and ask for the label of the bottom if props button a label is set we'll use that otherwise it will default to read more alright now let's set the button props to my card component right here to test them ref button icon I will need to move my icon types import to here all right and button icon is icon types all right and I will not set the label because it should be read more for now okay awesome everything is passed at props I will copy this card to the bottom grid and reward yeah great I will also set margin bottom let me see remorse this spacing coming right now oh my cool padding is wrong that's why I have spacing let me open the grid Style that this shouldn't set top button on his side for the gutter yeah and I need margin bottom 30 in this specific case on my topmost card great all right this is working flawlessly so far now the next step the last thing I need for my cards is this label should change its cover depending on its inner content so here's how I'll Implement that I want a helper function to determine the color I'll create a new helpers folder in source and I'll call it get um get label uh no get category color it will export a function all right and this function will use a map without defining this file category color map it will be a JavaScript map and we will set values to it first of all product reviews will return Orange opinions will return green and I believe travel guides will return purple and water function this function will return category cover map get category that's all this is a very frequently used design pattern in front end using some kind of a map return values in constant algorithmic time okay so let's use that in the card component I will import get category cover my helper and I'll use it right here in the cover utility I'll say get category color based on props label now if I go right here and refresh I still I get product reviews all the way because all of these haven't been updated let's play that to opinions and this one to travel guides as is in the design and right now there black because I don't have my classes but they're here let's define the classes in the colors CSS file find my Styles powers okay and I need green and purple let's take the covers for them real quick this will be the green and this will be the purple okay let's refresh and our mapping is working correctly and the cards are done the last thing I'll do is some utility for responsive scaling of these cards because they never collapse to the columns currently never collapse the full width I will add some response if you do for that which I will do in a new width file I will it will be responsive Max ability which I will call Min with 100 little just said I mean width to 100 percent okay and now import that now I can use it in my layout on my call Force and they should kill well uh now check out one side effect that's very cool I first will add the margin bottom two of them as well now when they scale down at 800 pixels the bottom ones also turn to the horizontal layout because they are larger than 700 pixels and that actually looks great because they would look very bad as cards vertical cards in this case and this is one very cool side effect of container queries your layout become extremely fluid and they are optimal at every width of the browser okay but with that uh this home page which list box should be done pretty much let me zoom out to check it out in an entirety we currently have a repetitive content in the same thumbnail but that doesn't matter for the layout it it will change when we use the Headless CMS later okay so far so good now we will turn our attention to the details page I I will first close some of these files another details pitch will be a dynamic route in next I'll use swag for it because it will be used for individual blog post now create a page.js file just copy this one although we don't really need any of this content I'll call the compound block details and I remove all of the markup for now except the container because I need that okay let's access it to access it just type any Dynamic route there we go so I have the header and the footer and we need to work on these elements right here very simple layout the only interesting thing right here is that some of the content is constrained to I believe 9 let me check nine counts so that it's easier to read the thumbnail is for other featured images for it okay we can actually copy some of the components like the label and the title um because they'll be using the same utilities we can copy them from our card component right here I'll copy the label the only difference being we don't need this style for the container query but I will need that get category cover holding so I'll import it all right um props label this will be different later but for now I will just hard code it so that we can see the label and it's great now in this design it needs to have a margin bottom of 20 pixels okay next up is the title it is on H2O and I will let's measure its spacing it's 50 pixels I need to add that in my facing utilities for margin bottom and so far so good so next I will add the nine column constraint right here to do that I'll need a row and a call 9 class and we add these right here all right great now let's add the image will be underneath the roll I'll actually move this spacing to the row okay uh I will again use next image of course and I have the thumbnail in my public folder it's called how is it called featured image one all right it should have a few property probably no actually it doesn't okay I'm getting an error I need to specify my width I need to of course um so we have 1280 by 387 let's do that awesome here's my featured image I will add some styles to it to do so I will add a CSS module it will be featured image the class it needs a border radius of 10 pixels and I also play it with the same Shadow I'm using on the car although I think I missed that in the design it will look nice in my opinion and consistent and let's apply that class name first Downy to import the styles featured image is the quest let's check it out okay works great now I need facing beneath it as well again 50 pixels I think I'll measure it right now just sure yeah exactly all right and let's see we have 50 pixel spacing and let's let is the content to do that I will copy the call 9 layout we need the image okay and it will be just a few paragraphs to standard paragraphs right let me just copy them okay it's hard coded right now so the content doesn't matter at all we will pull all of this content from a rich text field in our headless CMS but at this stage we have our contents my featured image and this sales page is completely ready just test the design alright we're done with the front end part in the next part is to set up a headless EMS so we will use strappy for the CMS I'll go to the docs immediately trap is a headless CMS and go to the developer Docs and the quick start guide we need to create a new application here so I'll start my terminal go to my Source folder alright so I copied the MPX I'm going to create the strappy app I'll call my app Block EMS this is the project name of course and strappy will create a quick start project now and install dependencies okay um strappy bootstrapped and run the application I get the screen um and it guides us to go to the first and to go to the admin panel and create the first administrator it starts in an app at localhost 1337 and here we have to create our admin user which I'll do real quick it needs to have one uppercase character alright and we're already in our stop strappy headless CMS trap is very simple to use and extremely powerful the first thing we can see are the plugins content type Builder and media library media library is very straightforward here you can add media asset which include the videos images and files in the content type Builder we create content types and in fact we have one collection already users users and content types in general are a collection of fields in this case username email password Etc each of these fields has a type very straightforward if you've created modules or content types in any content management system here is the same way although greatly simplify for ease of use we also have single types and components single types are a type which holds only one instance users users for example if we go to the content management we can create multiple users with multiple entries single types will have the defined Fields by U but they will have only one instance components are a special collection of fields which you can reuse if you find yourself using the same couple of fields or many types you can create a component for that for now we'll just create a new collection type for our box which will be called blocks I need to enter its singular API ID and its portal ID in advanced settings we can also allow internationalization if you have multiple languages and enabled or disable drafts I want drafts so just create a content type real quick okay and next we can create Fields I'll start with the most basic field which will be the book title it will be a short text field in advanced settings I don't want the default value but I want it to be required unique and I wanted to have a maximum length 255. and here we have a title field with basic validation I want to add another field um let me check my block real quick so my broadcast I don't it has a category product reviews and others in that category I want to set to a enumeration and it will be called category and here we list values and one value per line we'll have product reviews opinions and travel guides invalidation we'll make it a required field and that's it now we have our category I also need a text field that's wonk text and it will be a summary again it will be required to have a maximum length at 255 this summary will be used right here in the card featured item description so we also need a flag and that's going to be a Boolean field and it's going to be is featured if a blog post should be featured on the home page and it will be required the default value will be false another field will of course be the thumbnail and the list image let's add both of these to be a media field first we'll add the thumbnail single media I will allow only images and it will be required I'll also add a feature image should be single media again only an image and required field okay these are the two image Fields let me open the details page real quick the last item I believe is the content which will be a rich text field content and it won't have any validation okay we're good to go press save copy will need to restart to apply new fields and now we have our box collection we can add a block through content manager we go to the block type and press create new entry and here we have the editor to create a new blog post so let's create a new blog post it will be this one right here for example I need a title it will be a product review let's add its summary right here it will be a featured blog post let me add its thumbnail from my source folder there we have it we can upload it and I can add the featured image as well okay okay good okay we have our two images another thing is the content which is Rich Text marked down field which means I cannot my HTML to it my three paragraphs here they are great and I can now save my blog post I also need one more field um publish it you need to add field I forgot we need a field for swac which would be a short text field for the URL of the bottle it's a required field with the max length 250. save that go to content manager edit my blog post to add the required work field myself will be like the title with lowercase and dashes very standard okay save now we have to test the API for that I will open Postman before I attempt to use next.js and my API endpoint will be localhost 1337 there we go Dash API and in strappy you can access a content type by the API ID in Portal so in this case that will be box what's important is I need authorization here in settings we have API tokens and I need to generate a new token I will make it an unlimited token and read only and now copy the key now to authorize we send an authorization Bearer token here you see how to do that in the HTTP request headers later so now if I make the get request I get my blog post if you noticed I get the title category summary is featured in content but I don't see the featured image because they are a kind of a related field to do that I need that populate parameter to everything and then I will get all of my images and related fields but the request will be a little bit slower as you can see for the image we get the URL and image title great now I can use this API request in my next.js app first let's do a little bit of a setup here the first thing we need to do is add our API token in an environment variable let me copy it from right here and this should shouldn't be um pushed to a GitHub repository or anywhere should be kept secure this environment variable should be set by your deployment process and initially and ideally taken from math secrets repository in your deployment tool so we have that environment variable and the next thing is I will need a config file which I'll set up in my source directory here we will have a [Music] an object and it will have the API endpoint which is currently one two three seven put and now I can actually make a request let's go to the home page first where we'll retrieve all blocks I will first write the request option here and then extract fetchbooks it will be an async function it will fetch and I will get the I'll import the config from config and here we will fetch from config API let me check if that's the correct yeah flash API box and I'll set that far that parameter now we will need to pass it as an argument later you'll see why and I'll add request options object in order to load the authorization Bearer header so here we have headers and I need an authorization header which will have the following value Bearer empty space and the environment variable there we go these are the request options we need so the and the response will be awaited as well as Json and then this fetchbox function will return the response very straightforward nowhere handling uh yeah okay and my home components will use this function by making it a second using fetch blocks okay for now let's just continue walk the result to test everything I will run the app and just Mount the home page real quick see okay we get a 403 Forbidden error which means we have a problem with our API key basically um let me see we get our environment variables welded right here from dot EMV and the API token environment variables here but I use password API key I need to use API token let's check again now we get forbidden again so I have a typo and headers of course and now we get it immediately data and metadata so if I console walk let me just remove the Plug Ink yeah if I click on the work data I get my box which is just one book right now now um in this case I need to fetch my featured box first as you can see right here my feature block and then the other one so we need to use uh Rapido query by field let's see how that works um here we have the rest API and we can find the interactive query Builder basic claim we need a filter we can generate it from here it's not a very complex syntax I can just copy this and modify it on the way on the go so they both do fetch the featured box I need to filter by the is featured field and it needs to be called true okay and now I will only get featured box that's that if we refresh I get one block I will change let's change real quick in my PMS I will change my block not be featured and now if I refresh and go to the console actually red let's restart the app sure number three thousand hit one I still get my blog post and this feature is still true written let me see if I saved my change I do think so yeah it is safe okay let's refresh again okay this was basically a caching issue with nejs as soon as I invalidate the cache and I'll get an empty box array now I will um make this featured and we need to pass these parameters as um an additional argument in the function well I'll say that I'll set that to params and we'll pass them right all right and now I can use the parameters to fetch the featured box and the normal box all right and I'll do that with promise all for performance so that I can do it concurrently the normal box can be fetched by filtering by its featured false okay and this will be done with promise all and we'll do both and now I have featured box and all other books right here I need to await my promise great um to test out I will create a non-featured blog post right here I'll just duplicate this one it'll be easier okay um I'll just make it the title to two and start to false for now all right great and now um I can use this box let's first draw the featured book uh I'll do that by mapping feature box data and for each block I will return jsx when this jsx will just be this car okay um and now set all attributes one by one first of all label will be featured block attributes um category all right the title will be title summary will of course be summary the href will be this work actually it will be forward slash this look the icon is Arrow right always let's test that real quick we don't get our featured walk let me see why all right let me first check if we have a feature even we do we have to publish this one as well not forget um let me see here in the content it's not rendering feature box data let's console work that okay where the currently empty I think I need to yeah invalidate the cache again okay and I get my featured block that's great um this work is just not rendering correctly because it's with lower case and that's actually good let it be like that for now okay great all other fields are showing correctly uh I just don't have my image I think yeah the image is currently the default one I need to change my card component for that I think I forgot that part exactly I need image source and image out um so this will be props image source and this will be props image out great um and let's take the image do so I'll set the image out the featured image and image source will be right here featured block attributes featured image data attributes URL a little bit long but it is what it is and this will be only the last segment of the URL that thing can be taken from config API upload I believe let me see now first of all okay we have the upwards part in the URL so we don't need that and the forward slash otherwise let's test this URL we do have an error I'll explain in a bit that's expected I just want to test if my URL is correctly yeah here is that this domain is not allowed in next config.js and here is a link on how to fix it in the next config we just have to add this as a Noel URL right here Image remote pattern HTTP and Powerful for now it will just enter the URL of your headless CMS gear if you want images from there okay now if we reward we get our image great okay now the featured images taken from the Headless CMS let's take the other images from there as well in order to do so I will copy this map we also need a key here that's very important because we're iterating in react the key will be the ID of the book okay and here we'll do the same map for blocks okay uh one minor difference being we will also create a column here like so otherwise we also need a game this time on the call I'll move it back because it's less important and we can copy pretty much all of the properties here in the cart just change featured block to block and feature damage to thumbnail and we should be good let's check that out okay the key is to using featured block let's change that and here we go we have our first card taken from the Headless image we have the image the content and everything seems to be working absolutely correct awesome that's great news I can actually even remove summary here or no leave it because sometimes it can show when scaling down I remove the hard-coded cards we need that awesome well now I have a home page pretty much ready if I create more posts that are non-featured for example one that's called three and one that's called or they even published them they will provide right here I can make more and they should actually scale pretty well whoops even publish them there we go pretty awesome let me delete that last one now we should be able to open this and view their contents in detail from this read more button I get to the page but it's right now uh all this is static content so let's change that real quick uh also Let's test the labels uh I see I don't have my labels right here actually let me see where is the mistake attributes category I see that I passed them oh I have a typo there we go let's test my labels I'll change that to opinions oops and this one too Bravo guys they should be working flawlessly our five our guys opinions awesome okay uh let's turn our attention to the detail very interesting here we have to do a couple of things first we're getting this block as a pro in props Paramus because this is an xjs Dynamic crowd let me show you real quick what I mean exactly now actually just output it as the heading right now that will be easier props params work now if that is set to the title look we have the swag this will be whatever we input as the dynamic route we have this work we need to basically retrieve a blog post by this swag to do that I will extract this fetch box function to a separate Helper because now we'll be using it into components and I need to move some the config file that just test if you is working correctly real quick we have some mirror config is not defined where oh I need the config here as well because of the images okay all working correctly and now I can use that in my Dynamic route as well just import fetch blocks okay so we have this work in props Paramus work and what we need to do is walk will just be awake turn this into the async function fetch box and then we need to filter by the swag this time let's just copy the filtering syntax because I don't remember it okay this time we'll filter by swoke and it should be equal to and this should be because the props Paramus look and let's first console walk that make sure we're getting one block box work has to be unique let's check if it's set to Unique that's important it's not it should be let me check if my vocals have a Unix work right now they don't I need to do that because I hadn't edit properly the first time they need to have Unix work otherwise the whole thing won't work I need unique URLs for each item okay and we get our blog post only one it seems yeah great um yeah my book will basically be the first item how do I check just return no for now ideally that I think would redirect to 404 page basically okay and now we have our block here the great thing is we can just now output the attributes this should be the category let's do that real quick okay this will be the title awesome now we need the featured image let me just take that to multiple lines because it's too big already all right featured image and its source will be what um the same as right here I'll just copy it for convenience I need config or config API here we have walk attributes feature damage data attribute URL okay rest of the settings stay the same okay that's done and last but not least the content and for the content we'll use dangerously Setter HTML in react let me just check the syntaxis of that property okay all right here it is now this should be a property used very carefully um you could use other Solutions like react markdown for example but this is how you insert HTML Rich text into an element in react and the data will be our content which will be block attributes content let's check that out now I think we've done it correctly let me just check that because yeah is the actual content from the page from The Headless CMS and at this stage we have our book ready if we go to the home page we have multiple blog posts and if I invalidate the cache proper swags we can open them you see two opinion we have our travel guide here of them open and the content is displayed now one thing we can address optimization is currently these items are dynamically retrieved server site individual items are fetched based on this work we can generate them um beforehand based from The Headless CMS by retrieving all urls and we can do that using connect property let me just check in xjs Docs I have to search or generate static paths or let me see get static paths more likely okay yeah we can export a function called get static paths in the dynamic routes page file let me just see that's static path yeah excuse me this is the old function when it generates static params okay and let's copy the usage actually because it might be slightly different I will write it to an arrow okay async function okay and here what we do is fetch the Box all blocks without any filters and return mapping Works Data map of the swags where work is block attributes work and what that will do hopefully if we test now if we build the application we will build all block posts a static pages of build time let's wait for the optimized production build and we'll check if necjs catches our static parameter we do have a new slender error component definitions using display name to fix that I can set button icon display name to icon that should fix it this mirror build again the chuck oh let's check what was generated generating static Pages 0 of 5. that is absolutely correct and our static pads are working why is that because if I open my headless CMS we have four blog posts suppose the list homepage and our static Pages were generated we actually have a console walk left over somewhere let me see where I think right here maybe yeah remove that and now if I npm run start the application it will actually run very fast because all of the pages are statically generated you can see they are instantly shown they're prefetched everything is working Flawless so that's the benefit of having them statically generated the server does not do any API calls for them during the actual request you just request a static page the best possible performance alright well that's basically it we have our block we made it from scratch front design we built the front-end tiles set up a headless CMS with Scrappy we didn't go too much in depth with strappy but you can experiment and they have very good docs and yeah we use next GS to integrate with the Headless CMS rebuilt everything of static pages and visualize all of the fields that's it for today's video if you like the content don't forget to subscribe to get notified when another video is released take care
Info
Channel: NL Tech
Views: 16,880
Rating: undefined out of 5
Keywords: next.js, next, javascript, js, node.js, CMS, content management, digital experience, dxp, cms, wordpress, headless, api, restful, rest, REST API, graphql, graph ql, strapi, nextjs, react, server-side rendering, static site generation, SSR, SSG, blog, portal, e commerce, commerce, corporate site, corporate, documentation, multipurpose, easy, quick, fast, tutorial, course, full, walkthrough, coding, session, code session, live, realtime, developer, software engineering, software, web, application
Id: NNWX2flw5mg
Channel Id: undefined
Length: 97min 47sec (5867 seconds)
Published: Mon Aug 21 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.