In this chapter I want to develop the responsive dialogue component simply so we save some time in the next chapter where we are actually going to focus on developing the new agent form and for that we're going to need a responsive dialogue. So I want to do a separate chapter in that to also add a responsive command dialog while we are here. So as always ensure that you're on your main branch and ensure that you have your changes synchronized. Also ensure that you have no active numbers here in the source control. Perfect.
So let's go ahead inside of the components here and let's create the responsive dialog.dsx like this. In here we are going to import everything from components UI dialog and everything from components UI drawer. We are also going to import everything from... I mean one thing from useIsMobile from useMobileHooks and let's mark this as useClient here. Now let's go ahead and let's write out the interface.
ResponsiveDialogProps Title, which is a required string. Description, which is a required string. Children, which are React node. Open, which is a Boolean. And onOpenChange, which is a toggle for that boolean.
Let's export const responsive dialogue here. Let's go ahead and use these props. And let's go ahead and let's destructure all of them. So title, description, children, open, and on open change. Let's define isMobile, useIsMobile.
If isMobile, we're going to go ahead and return the drawer component. Drawer component. Otherwise, we're going to return the dialogue component. So let's go ahead and do the following thing. Let's add two of the same props to it.
Open will be open and on open change will be on open change prop. Like this. And now for the drawer, let's add drawer content here. Drawer header, drawer title. Let's render the title.
Below it, description. But let's change this component to be drawer description. Outside of the header, add a div with a class name, adding a for, and inside, render the children. Now, for the dialogue, it's going to be quite similar. Open up the dialogue content here, add the dialogue header, add the dialogue title, which will render the title.
This one will render the description, but this one will be dialogue description and fix the closing back here. And one thing we don't have to do is add a div. So we can just add children here. That's because while they are almost identical, they briefly don't match in the body. So the footer, I mean the drawer, needs the padding, whereas the dialog doesn't.
So now let's go ahead and test this out. We can do it quite easily by visiting any page that you want. For example, let's do agents. And let's go inside of agents view. So it needs to be a client component.
And inside of here, you can just render the responsive dialogue, give it a title of responsive test, and a description of hello of responsive description. And it needs the children. So in here, you could add a button component, some action. So make sure you've imported this. Part code open.
And for on open change, just do this. There we go. So now let's go ahead in the agents here. And this is how it should look like on desktop. You should not be able to close it, right, because we hard-coded it to be open.
But if you switch to mobile, it should open a drawer. So when you refresh, there we go. It looks like you can actually force close it on mobile, but that's completely okay because obviously we want our models to be closeable. Great! So that's it for the responsive dialog.
So we can close this now. You can remove it from here. You no longer need it. You can remove the associated components. So what I want to do now is I want to do the same thing for this.
Because right now, this is what it looks like. So let's make it responsive. And the way I want to do this is just a little bit different. So I'm going to go, instead of source, components, UI. And I'm going to go directly inside of the command component, right?
Because when you go inside of your dashboard command, that's where you import from. So how about we invent a new component inside? So that's what ShadCN allows us to do. We should not be afraid of modifying these components. They are not maintained by some other author in your node module.
They are in your project. You can go inside, you can change the code and make it to your liking. So let's do exactly that. Go inside of the command here and find the command dialog like this. And let's go ahead and copy it entirely and let's paste it below like this.
And let's rename it to command responsive dialog. The title can stay the same and the description can stay the same as well. And then what we're going to do is the following. We're going to add const isMobile use isMobile from hooks useMobile, right? And then if isMobile, we are going to render, you guessed it, the drawer.
In order to do that, we need to import everything from the drawer so let's just add this and Let me just move the hook up here. There we go. Let's go to our command responsive dialog. Like that. So let's go ahead and render the drawer component.
And in here simply spread all props the same way we are doing for the dialog. Now let's add the drawer content and let's give it a class name overflow hidden and padding of zero. Instead of here, let's add a drawer header. And let's give it a class name, s are only which means screen reader only. Let's add a title here and render the title.
So this is only for accessibility, right? This will not be visible. Let's add a description here. And let's just fix this by using the proper drawer description component. And then in here, what you will do is you will copy the command and all of its classes.
Just like this. There we go. And let's see. Now we have command responsive dialog and we have to export it. So go all the way down here and export it like this.
And then when you go instead of your dashboard command, Replace the import to use command responsive dialog. And instead of using command dialog, use command responsive dialog. As simple as that. So now, when you try opening this up, let me try and zooming in a little bit. When you try opening this up, it should render in a drawer.
Looks like it's not rendering in a drawer. Let's see why. So I have set it to be a command responsive dialogue. I have set this to be isMobile. Oh, because I'm not using the return.
My apologies. Return. That's why. It never returned. The reason you don't see any errors for these kinds of things is because it's technically correct syntax.
You don't have to return, right? It's just never what you want, right? And there we go. Now it's a nice drawer. So that's exactly what I wanted.
So it's easier to use this global search on mobile. Perfect. And on desktop, it stays a dialogue. Amazing. So there will be, we will be coming back to this component later on when we actually implement the functionality of this, because maybe you've already guessed, but the way this works right now is by using filters, right?
So it's not actually doing any API calls here. It's simply filtering whatever we put inside, right? So for example, if I do test two here, and if I type two, it only filters test two. That's not what we want, because what we want is to do an API request on each keystroke, right? But we will worry about that later.
Perfect. So I think this is a great smaller chapter. So we fixed some of those things. And just one more thing that I kind of want to bring to your attention. You might have noticed that any of my buttons, which are not links, don't have the cursor pointer.
Instead, they look not exactly clickable. So that's a change in Tailwind version 4, right? Only links have the cursor pointer, but buttons don't have it. If you want to change that, there is a small snippet you can do. So what you have to do is go inside of your app folder, globals, and go all the way down here, and simply add this, another layer base.
And basically, you will find all elements which are either buttons which are not disabled, or are any other elements which have a role of button and are not disabled. And for them, add a cursor pointer. So just don't forget this little comma here if you are writing this out. I found this snippet from the actual Tailwind v4 documentation. So this is what they suggest if you want to reverse that effect.
So now buttons are clickable again. If you prefer it that way. If for whatever reason you don't want it that way, just remove this. But you can see that now this clearly indicates, hey I can click on this, right? And I can click on this and click on this and on this.
I prefer it this way. Great! So I think that wraps it up. We added the responsive dialog and responsive command dialog. Perfect.
So now let's create, review, and merge this pull request. So I'm gonna go ahead and go inside of my source control just to review. Okay, so I have four files changed. I'm going to create a new branch, 10 responsive dialogue. I'm going to stage all of my changes.
There we go. Add a commit message, 10 responsive dialogues, dialogue, and let's commit and publish the branch. There we go. Let's go to our GitHub, let's open a pull request, and let's get a review from our AI bot. So let's go through our code summary.
We have introduced a responsive dialog component that adapts its appearance for mobile and desktop devices. We have also added a responsive command palette dialog that adjusts its layout based on the device type. There we go. We have also added one more command option, And we improved cursor feedback for enabled buttons and interactive elements, ensuring a pointer cursor is displayed for better user experience. That's exactly the way I feel about it, right?
Great, and in here we have a whole sequence diagram explaining the device type detection and how we display a drawer or a dialogue depending on, well, device type. In here, it left some comments here. So this is pretty cool. It noticed the inconsistent padding between mobile and desktop implementation in the responsive dialogue component, right? Do you remember that?
And we know that that's okay, right? We know because drawer content behaves differently than dialogue content. So I told you that we need to add padding for the drawer, but CodeRabbit, you know, the AI can't really know that the same way You probably didn't know it, right? So it made a consideration for us here to remove that, to make it the same as for the dialogue. But since we know that's not the case, we can safely resolve this conversation, but pretty good catch by AI.
Obviously, all of the command items in the dashboard command are currently just for tests, so no need to do that. And this is interesting. So it noticed the props type inconsistency. Specifically, it noticed it in the command component, this one, command responsive dialogue. So in here, we share the component props type of dialogue.
And then we use those props to spread them to the drawer. So yeah, this is a pretty good catch because nothing is really ensuring to us that these props will be compatible or at least compatible forever. But in this case, you already noticed that the drawer component and the dialog component behave pretty much the same and I'm pretty sure have the exact same API. So that's open, default open, onOpenChange and model. All of those are supported in the drawer, so we don't have to add any explicit props here.
So it's very good that it noticed that, because I definitely didn't even think of that. So you can see the kinds of things it suggests you to refactor. So yeah, in case you're using some newer version of chat CN and you're having problems here, it might be because of that it might be because the dialogue and the drawer components API have diverged, and they are no longer in sync. But in my version of ChatCN, these components are exactly the same. These props have the exact same API.
So I will resolve this conversation as well and I'm going to merge this full request. There we go. Once we've done that, we can go ahead back inside of our main branch and we can click this little button here to synchronize the changes. Let's click OK. And that should bring back everything.
There we go. Amazing, amazing job. Confirm with your source control graph here that everything's okay. We 10. Number 10 responsive dialogue.
Amazing! See you in the next chapter!