Let's continue developing our Lingo app and what I want to build next is the layout for this 404 page. So I finally want to get rid of this error and start working on the reusable layout. So what I'm going to do is I'm going to create a new route group similar to this marketing one. And we're going to go ahead and call this main in parentheses. So I don't want main to be a part of the URL.
I just want to visually separate this from everything else that's going on inside of the app folder. So inside of here I'm gonna go ahead and create a new layout file and I'm gonna go ahead and create a folder called learn because that is where we redirect the user after they log in. So because this is a route I need a page.tsx inside. So if I save these files and refresh we no longer have 404 but we do have an error because we need a default export. So if we just go ahead and do this, so if I do a write learn page here and a div learn page, make sure you do a default export, it still won't get rid of the error because we are also missing the layout export.
So we have to go inside of the layout here and let's go ahead and simply do const, sorry, type props children react react node and Let's just go ahead and do the same thing I just did inside the main layout. And let's return a div which renders the children. And we have to destructure the children from the props. There we go. And now we should get rid of the error and we should see the text which says learn page if you are on localhost 3000 slash learn.
So now when you click continue learning it should redirect you to here and just confirm that the same thing works if you are logged out. So I'm going to go ahead and log in and see if it will redirect me to that page. And there we go. Once I logged in, it redirects me here. So just confirm that you have the necessary redirects on your marketing page.
Great so now that we have this layout let's go ahead and actually structure this a bit better so first of all this layout is going to be a fragment. And then I'm going to go ahead and wrap this in a main like this. And I'm going to go ahead and give this main a PL of 256 pixels. Like this. So I want this to be moved from the side here because this is where we're gonna add our sidebar next.
So let's just keep this thing separated. I'm gonna give this a background color of red 500 and let me give it a full height and see if this will add something to it. It looks like it didn't add anything so let me just see how we can improve this. I'm not going to add the background color here. Instead, I'm going to do the following.
I'm going to add a div here. And the class name of BGRed500. There we go. So this is what I wanted to showcase. I just want to showcase that this is the part that we have to work with, right?
So that included the color but this is what I wanted to demonstrate. But one thing that seems to not be working as it should is our H full line. So let's go inside of the app folder, globals.css and let's add the following HTML body and colon root and Let's go ahead and add at apply h-full. So this is the equivalent of adding a height 100% but since we're using Tailwind, we can use at apply and write a Tailwind class name. And there we go.
You can see the moment I added that in our globals, we now have the full height of our Learn page here. So let's go back inside of this layout here and let's actually create a little sidebar component or at least prepare it so that we can see what we are working with. So I'm gonna go inside of this, well we can actually keep this inside of Learn or actually this is going to be reusable. So I'm thinking where we should put the sidebar. I was thinking I can do the same way I just did in the marketing folder but then I remembered that the sidebar is going to be reused for the mobile drawer as well so perhaps it's better to think of it as a reusable component.
So that's what I'm gonna do. I'm gonna go ahead and create this in the components folder but not inside of the UI folder because that's where I want to keep my chat C and UI components. So my custom components are gonna go to the root of the components folder. So I'm gonna create sidebar.csx right here. And let's go ahead just very simply and export const sidebar.
So no default export because this is just a component. And let's just return a div which says sidebar. And I'm gonna give it a class name bgBlue500 full height and let me also give it a fixed width of 256 pixels. And now I'm gonna go back to my layout file and just above the main I'm going to import that sidebar from add slash components sidebar. So let's see what did we achieve here.
So it looks like we have this set up, right? But they are not aligned next to each other. So you can only now see the learn page if you scroll down. So somewhere in one of our layouts, we have to resolve this so they can actually be next to each other. So there are obviously multiple ways we can resolve this.
As I said we can go in one of the layouts and we can apply a flex row to this, right? We could do that. Or we could go inside of the sidebar and we could give it a fixed position. Which in my case suits me better because I never want that to scroll with the rest of the page. So I want my sidebar to always have its own position.
So that's what I'm gonna do. I'm gonna go ahead and give it a fixed position. And you can see that already this resolved our scroll issues and now you can see the sidebar takes its width and because we added a PL this learn page is pushed exactly for the content of this sidebar. So this obviously looks fine for a web screen, but we need to do the same thing for mobile. And for mobile specifically, I want the sidebar to collapse once it breaks a certain viewport.
So let's go ahead and do that next. I'm gonna go ahead and give this a couple of more class names here. So I'm gonna give it a flex class name. I'm gonna go ahead and mark this with an LG prefix. So I only want it to be here visible on desktop, right?
And the same thing I want to do for the fixed. Like this, right? So on mobile I want it to take a hundred percent of its width which it will do automatically because we are not limiting it like we used to and I'm also removing the fixed position because it's going to be used in a drawer which is fixed in itself. You're gonna see what I'm talking about in a second once we implement the mobile view from it. So only you can see that when I expand or zoom out it shows them next to each other as they should be on desktop but once I break it goes into a tablet or mobile mode.
Obviously it would not collapse into the sidebar itself but I'm just confirming that this works as expected. Great, So we now have this and let me just add a couple of more positioning fields here. So I want to give it a specific left 0 and top 0. I'm going to prepare PX4 here, border R2 and flex call for all the items inside. There we go.
So now you can see how I have a little border here as well. Great. Now that we've prepared this, let's go and give this sidebar component a type of class name, sorry a prop of class name. So an optional prop which can come from outside wherever it's being reused, right? And what I'm gonna do is I'm gonna use our CNUtil which we've gotten once we've installed chat CNUI.
So you can import that CNUtil from atlib utils. It's a very simple function which will help us merge Tailwind classes without causing any additional conflicts. And I'm very simply going to pass that class name here. And what I can do now is I can optionally, where I want to, add a class name to this sidebar without hard coding it inside of here because sometimes I don't want it to behave a specific way. But here's what I want to do.
So inside of my main layout here, I want to ensure that this class name, Sorry, this sidebar is hidden on mobile devices and only visible on desktop. So when I expand, there we go. You can see how only then it appears, but on mobile it doesn't appear. And then we have to do the same thing for this learn page. We have to ensure that this padding here only shows if we are on desktop.
So I'm gonna add LG prefix here. There we go. So on mobile, the learn page will take the entire content, but when I expand, the sidebar will appear. Great. And now I wanna add something that will enable the users to trigger the sidebar when they are on mobile mode.
So in order to do that we're gonna do the following. So first of all, let's prepare a padding top of 50 pixels here. So that should push this learn page, as you can see, even on desktop. But I only want it on mobile because on mobile we're gonna have a little header which will serve to open the sidebar. So let's go ahead and just ensure that this only happens on mobile.
So we're gonna write it like this and then once we reach a large breakpoint we're gonna give it a zero. So if I go ahead and expand, there we go. Once the sidebar appears back, the learn page does not have that padding anymore. But on tablets and mobile devices they appear. Great!
So what we have to do now is we have to create a mobile header. So let's go ahead and create a mobile header component. So we don't have it yet, but we're gonna go ahead and do that in a second. So I'm also gonna create that in here, keep it reusable. So mobile-header.tsx and very simply I'm going to export const mobile-header and I'm going to return a nav element and I'm going to give this nav element a hidden value on large devices.
I'm going to give it a Px of 4. I'm going to give it a fixed height of 50 pixels. Flex, item center. I'm going to give it a BG. Let's use yellow 500.
Border bottom, fixed position, top 0, full width. And let's give it a Z index of 50. And I'm simply going to write mobile header here. So I'm going to use this color here. Let me just disable the copilot.
I'm going to use this color here. So we indicate and it's easier to see where it's actually appearing. So let's import this mobile header from components mobile header the same way we did the sidebar and there we go We now have a mobile header here. But when I expand the mobile header should completely disappear Perfect. So what I want to do now is I want to create a component called mobile sidebar But before I can do that, I need to add a component from ShadCNUI.
So let me open a new terminal besides my npm run here and do npm shadcnui add latest add a sheet component. So let's wait a few seconds for this to install and then we're gonna use this as a drawer which will open the sidebar on mobile devices. So after you have this you're gonna go ahead and do the following. So instead of having this text mobile header, we're gonna have a mobile sidebar being rendered here. So I'm gonna create a new component in the components folder, mobile sidebar and in here what I'm going to do is I'm going to import the sheet component, the sheet content and the sheet trigger so from add components UI sheet component and let's go ahead and do the following.
We can now import our reusable sidebar component from add-components-sidebar or ./.sidebar because they are in the same components folder, but I prefer explicit way like this. And let's do export const mobile sidebar. And let's very simply render these components. So we need a trigger here and the trigger is going to be a menu icon from Lucid React. So let me just move this Lucid React import to the top here and let's give it a class name of...
Well, very simple, let's give it text white. Everything else is pretty much okay. And let's write sheet content here. And inside we're going to render our sidebar component. So now let's go inside of the mobile header and import the mobile sidebar.
We should get rid of the error now and if I click here, there we go. That opens a drawer and you can see our sidebar here. But obviously it's not as perfect. So first things first, I want this to be on the left side and I also want the sidebar to take the full height and width without any padding here. So that's why I'm using this bright color so we can clearly indicate how this is supposed to look like.
So let's go back inside of the mobile sidebar and find the content component and let's give it the following class names. I'm going to give it a padding of 0. I'm going to give it a direct z-index of 100 and I'm going to give it a side of left. And now if I try this again, there we go. This is exactly how I want my sidebar to behave on mobile devices.
Perfect. So on desktop, this is going to be quite nice to look at. We have a sidebar and we have the learn page. And then when we collapse, when we have too many elements, we're going to collapse to mobile mode. So if you're wondering how come I'm using the large viewport and not the medium viewport for collapsing to the mobile, well, that's because we're gonna have another sticky sidebar on desktop here.
So it simply doesn't look good when collapsed, right? So That's why we simply have to fall back to mobile mode once we don't have enough space to work with. At least that's the solution that I found. Great, and just to wrap this layout up, let's do one thing that we can already finish, which is go inside of this mobile header and let's give it a proper color. So it's not going to be yellow, it's going to be green.
There we go. So this is going to be the proper color for our header here, which is going to be used in the final version as well. So we can already prepare that. And obviously the sidebar and the learn page are not gonna have colors, but I just want to leave them here so they can indicate for us what's going on. Great!
So we just reused a layout once again. We learned how that works. And you're gonna see how powerful this layout component is now because in our marketing, it's not that visible because we only have one page, right? We kind of try to demonstrate it with frequently asked questions and with the docs page. But here in the main route group, you're clearly gonna see how useful this is because we're gonna have a lot of routes.
Besides learn, we're gonna have quests and leaderboard and a ton of other things and you're gonna see how useful it is that we don't have to write the mobile header every time or this entire sidebar functionality. Great, great job.