Transcript from the "Create Pages with Custom Data Manually" Lesson
>> The first thing that we're gonna do if we want to get a book listing because we've got a cover, I want these two, I don't want them to just be big spaghetti things. So I'm gonna add a little bit of styling in here. And we're gonna create a new folder called styles.
[00:00:14] And we'll call this book.module.css. We're using the CSS module approach because it gives a scoped styles without having to install a CSS and JS library or learn some specialty syntax of CSS. This is just plain old CSS, what you've always used, we just get to trust that it's gonna be scoped because of the way that CSS modules are implemented.
[00:00:33] So in here, I've got a listing, that's gonna be the actual book wrapper. We want that to be display flex because I want the cover and the details to live side by side. And we'll give it a gap of 2 RAM and a margin, bottom of 2 RAM.
[00:00:54] Then we want a heading. And the heading, I'm just gonna set a margin of 0 because. Otherwise, what will happen is the heading will get bumped below the book cover and it'll have this kind of weird offset, and I don't wanna deal with that. So we're going to do that.
[00:01:09] And that's good enough all I want is for this to just not be completely unstyled. So then I can create a template for this because remember we do use that Create Page API, we need to have a template to use. So I'm going to create a template called book.
[00:01:26] And in this, we're going to import everything as react from react. And then we're going to import graph QL. And my god, stop helping, and link from Gatsby. And finally, we're gonna use that Gatsby image, that we set up. So let's import Gatsby image, and get image, from a Gatsby plugin image.
[00:01:59] And then I am also going to import those styles we just created so listing and heading from our styles. So let's get the book.module.css. And if we wanna get a query so this one is gonna be a query because it includes the book ID. So we're gonna have our graph QL.
[00:02:21] And inside of that, let's go out here and build a query for this. So this is running so I can come over here. And I wanna get a book so let's close up author and instead we're gonna get book. And I want my book to come in with a I don't need the ISPI, do I?
[00:02:42] I want a name. I want the author name and slug. I want the series and the series order. And then I want the cover. And I want the cover to have a child image sharp. And get the image data, and we can set this to be whatever, am just gonna leave all the defaults because it's fine.
[00:03:07] But I am gonna restrict the width to 150, because I want the cover to be pretty small on the page. And so once we've set that I can change this over to like say book will get the ID equal string and then we would wanna filter by the ID as well.
[00:03:28] So I have this and we wanna it to equal and we'll say it's gonna equal the ID. So I can copy this. Bring it over here. In this is going to get us all the details about our book. And while I'm thinking about it, let's also get our biolink in here.
[00:03:46] So now I have my data we're going to get the individual book that we're trying to query for, and we can build our components. So export default function, book page, and we'll get data from our graph qL query. Here, let's extract the book out of that data so data.book, and then we can return a whole bunch of markup.
[00:04:14] So let's get a fragment setup. And then we will set the class name to be our listing, because that's the book listing. And then we are going to use this Gatsby image and we'll pass in the image of from the book cover. And so this get images a helper from Gatsby to like dive in and get the image sharp and the Gatsby image data and all the things that it needs so that we don't have to remember to type all that out.
[00:04:43] And then we can set the alt. I'm going to cop out a little bit here and call it the book name. Probably better alt text should be written and we can set the h1 I'm going to set this needs a class name Of heading. Otherwise, we'll get that awkward top margin that I don't want and we'll use the book.name as our h1.
[00:05:09] Let's set the author here. And we're going to link to our author. So in here, we're going to link to book.author.slug. And then we wanna do book.author.name, right? So we're just going to using this data, nothing too out of the ordinary here, and then we're going to link through the book.
[00:05:36] Series, if there is a book series, we're going to add some extra information. So if there's a book series, we'll say this is book series order. Don't need that dollar sign there. This is book series order of the book series. And then finally below that, we can just start closing things up.
[00:06:06] So let's close up that div. That one's already closed, okay? And then we'll take them back to a yet to be created all books listing. And we'll just do the same thing, a left arrow, HTML entity and back to all books. Okay, so now that this is created, we can actually use it.
[00:06:29] So let's get into Gatsby node. And let's make this thing work. So what we're going to have to do is pull in, in create pages I'm gonna start collapsing these so that it's a little easier to see what we're working on. There's another helper that you get in create pages called graph QL.
[00:06:48] And this allows us to make a query against our graph QL data layer while we are inside of the create pages API. So by doing this, that means I can make a query down here. Now this is a little bit unintuitive because in Gatsby components, it's a template tag.
[00:07:09] In create pages, it's a function. So it's otherwise exactly the same. We're just going to get query for all of our books. And what I want in this is all book. We'll get the nodes. We will get the ID, the series, and the name. All right, and I'm going to get the result of that we need to await this or else would get a promise.
[00:07:37] And that means I need to make this async. This is a cool thing about Gatsby is the API is can be run synchronously or asynchronously. So if you ever want to await something, you can just toss that async in front of it, and you'll be able to do that instead of having to do promise juggling.
[00:07:53] Once we've got that result, we can set up a little bit of logic to determine our books. So let's get the books themselves out of here. And that's going to be result.data.allbook.nodes. Okay, then let's loop through them so books for each. And we're using for each year because we don't return anything, right?
[00:08:14] That's when you would use for each book. All right, so we've got our books, we're looping and I'm gonna start by getting the book slug. So as you identified, whoever asked that question, we do indeed need to make that easier. Why is that? That's not what we want at all.
[00:08:37] We just wants liquify like that. Let's put that up here. So we've got slugify and we're going to slugify the book.name. And again, we're gonna go lower, true. And if we have a book series If it is, no, then we can create a page and that will be a path, it's gonna be book slug.
[00:09:13] We're going to set the component to be required.resolve. And we'll do source templates, book.js. And for the context, we're going to include the ID of book.id and that so that we can look up the book when we get into that template. Remember we needed to have this variable.
[00:09:41] That's how we're getting it in we pass that ID as context and now we actually have it available to us. So that will create our pages in that place. Then, if we do have a series I'm going to create a series slug, and we'll slugify the book.series. And again, we'll go lower through and we can create the page.
[00:10:11] And I'm realizing now that this is ripe for refactoring. So this one would go series slug. And then again, it's the template in the book and again, it's the context ID. So I don't know why I didn't just check for the slug or something, but it's okay, me being good at this type of code is not the point of this work.
[00:10:39] [LAUGH] But we are going to get what we need here of creating the page and we'll get the right template and the books get created at the right slug, no matter what we are doing there. And I caught a typo before it broke everything, what a great day?
[00:10:58] So let's stop and restart because we just updated our Gatsby node. And that's going to take us out to local host here. And what I want to be able to do is to get to all of my books. So what should happen is once this reloads, I should be able to click into one of these books and see it.
[00:11:20] So let's see how that goes, I'm going to click in. And we're just waiting for this to finish. There it goes. All right, we refresh. And there is our book. Okay, I can see something I screwed up. I needed to put all of this into a div so that it floats properly.
[00:11:48] So let's do that. There we got that looks better, that's more like what we want. So now we have the ability to display our books. They're sort of styled so that they look at least somewhat legible. And then we come back to this slash books page, which is not yet created.
[00:12:06] So I'm going to create one more page here and this one can just be a regular old listing of books. So we're going to import everything as react from react. We're going to import, graph qL and link. From Gatsby, we're gonna import slugify. I'm really, now that it's been pointed out to me I'm feeling very foolish about having duplicated all this slugify work.
[00:12:35] And we're gonna do this as a static query again so let's export default function books page. And let's get the useStaticQuery in here again. So I'm gonna get data out of useStaticQuery. That's gonna be our tag to graphql template. And inside of it, I wanna get all books.
[00:13:07] So we're gonna run a query for all book nodes and then inside I want the ID, the name, the author, the name and slug of the author, and the series name. And that's our graph QL query. Typos all over the place. Let's make that better. Okay, then down here I can get the book out so let's get books equals data.allbook.nodes, and then we can do our markup.
[00:13:46] So what I wanna do for this is again, we just wrap it in a fragment. We will stand up a heading, says books. And then we'll list through our books. So we'll say book stop map book and for each of these we are going to do a little bit of logic.
[00:14:08] And that logic is gonna be to create a book slug. So again, we will slugify the book.name lower true. Then we're gonna do this whole thing about generating the path again. So if book.series Then we wanna create the series slug. And that's gonna be slugify book.series, lower true.
[00:14:48] And then we'll set the path to be book, series slug, book slug, or else we will set it to be path equals book slug. Okay, once we've got that, we can return our actual markup which will be a list item with a key, that'll be the book ID.
[00:15:28] And then we're gonna set a link to the path and that's gonna be the book name. And then we also want to say by link to, and that's going to be too. We want to make this forces to the root because the author slug isn't a path. It's just the author slug so if we only put an author slug what would happen is it would make the links relative.
[00:16:00] So we're going to link to the author's page with book.author.name. And that reminds me that we need to go book.author.slug. Okay, so you save all that and now, assuming I did all this right, which I think we did, I should be able to reload and get our books.
[00:16:22] Okay, so let's do a quick check. We're on the books page, I click into a given book back to all books I go to an author page, I get a list of their books go to all authors. And here we are. Okay, so we're authors nk jemisin, click to a book.
[00:16:38] We get the book, we go back to all books. We get a list. Click to an author. This is wonderful. Look how great this is. We have built ourselves a book club website.