This content is a comprehensive tutorial on building a Notion clone application called "Jan" using Next.js 13, TypeScript, Tailwind CSS, and Convex for the backend and real-time database. It covers frontend development, backend integration, authentication, and deployment.
Key Points
Mind Map
点击展开
点击探索完整互动思维导图
hey there my name is Antonio and welcome
to the newest video on my channel in
this tutorial you're going to learn how
to build a beautiful notion clone which
we are going to call Jan as you can see
we're going to have a beautiful landing
page with a knv bar with a footer and
some nice images right here we're also
going to have a toggle of light and dark
mode which is going to reflect the
entire application as well so without
further Ado let's see exactly what this
application will be capable of so I'm
going to go ahead and click on get Jan
free right here and I'm going to sign it
using my GitHub once I authorize the
sign in I'm going to get redirected back
to the landing page and you can see now
it says enter Jan once I'm inside of
here we have a nice message welcome to
Antonio's Jan and we have a big button
to create our first note so let's go
ahead and do exactly that as you can see
it's created in real real time it's
added to the sidebar right here and
guess what we can rename it in real time
as you can see it's been renamed right
here in the toolbar above as well as in
the file explorer on the left and I can
also do it from here just like that but
now it's looking a little Bland so let
me rename this to my first note and let
me add a little icon to it for example
let's use this rocket right here as you
can see this has immediately been
reflected it here in the Novar and right
here in the file explorer I can also add
a cover image using Edge store so let me
add a beautiful image here from unsplash
and once it's loaded you can see how it
takes a nice little space here from here
I can change the cover or I can
completely remove it besides the icon
and the cover image we're going to have
a notion style editor which means we can
write commands with a slash I can select
the heading and I can write subtitle
like that I can also go ahead and select
a smaller heading and write a
description or I can just write regular
text besides text I can also embed an
image in the editor itself I can either
use the embed by URL option or I can
upload an any any image I want so let me
pick another image from unsplash right
here and as you can see I can also
resize it so it fits exactly what I need
besides text and images I can also
answer their bullet list like this I can
also select a specific item I can make
it bold italic I can underline it or I
can strike through it I can also give it
a background color like this besides
bullet list we also have numbered lists
one two and three like that now let's
explore what else can we do with this
application as you can see in the
sidebar right here I have a little plus
icon which means that I can add a
children in inside of this note and I
can as well rename it in real time
perfect and I can go ahead and delete it
as well and we can do that as many times
as we want now you might be thinking
well with all of this infinite children
at some point we're going to run out of
space here right well don't worry just
like in real notion we can expand the
Side Bar and make it fit our content so
we have room in our file explorer now
you might might be wondering what these
three buttons do well I can select and
delete the entire note and all of its
children and if I take a look at my
trash right here you can see that all of
that is here I can now go ahead and
filter by my first note and you can see
that I can go ahead and click on that
note this is the first note that we
created and now it has a banner saying
this page is in trash I have an option
to restore the entire page or to delete
it forever so first let's try restoring
the page
and as you can see this is a smart
restore meaning that it also restored
everything else in the trash which was
uh children of this note beautiful but
what happens if I delete partially like
this well as you can see only that part
has been deleted and if I go ahead and
randomly revert these items back you can
see that they become Standalone items
because they no longer have a reverted
parent so we have a very smart
implementation here besides this we can
also collapse the entire sidebar like
that we can also publish the note so I'm
going to pick this first note which we
created and I'm going to click publish
right here so right now our work is
private and only we can see it but once
we publish the note it's publicly
visible on the web so I'm going to copy
this link right here and I'm going to go
ahead and paste it in incognito mode
right here and as you can see I can now
preview this note as a guest but I
cannot edit the icon the cover image the
subtitle nothing I can just look at this
and let's see what happens once I click
on publish as you can see now it says an
error something went wrong and we can go
back to the landing page as I guessed so
we're going to have beautiful error
messages we're going to have loading
skeletons and much more and just as I've
shown you on the landing page we can
click on settings right here and we can
change this to dark mode as well and it
fits beautifully in this application but
just right now I'm going to change it
back to light mode I can also search
through all of my documents I can find
my first note and I can click on it I
can also use a shortcut command key like
this and I can then go ahead and find
another note and enter it just like this
so that's going to be our project I
think this is a very exciting project we
have a lot of new technologies to learn
and a lot to do but we are not done here
this entire application is also going to
be fully responsive as you can see right
right here I'm uh on a mobile mode here
and I have a collapsible Navar and from
here I can switch to my first note like
that I can open popups I can do
everything I want from here I can visit
the trash I can revert notes back and I
can visit them again beautiful so I hope
you're excited for this project because
I sure am and without further Ado let's get
get
started so let's get started by
configuring our next3 project so here on
the left side I have my visual studio
code and I've prepared my terminal you
can use any terminal you want if you
want to access the one in Visual Studio
code like I have I pressed on this
little problems tab right here and then
I pressed on the terminal option like
that so the command I'm going to run is npx
npx
create-- apppp at latest meaning that
we're going to use whatever is the
latest version of the create next app
and then we're going to give our project
a name in my case that's going to be be
a notion dclone and you can just go
ahead and press enter it's asking us
whether we want to use typescript for
this tutorial I'm going to use
typescript so you can select yes for the
Sint option you can select yes as well
for Tailwind CSS select yes as well
Source directory leave it at no or
select no yourself because we're not
going to use the source directory in
this tutorial for the app rowter this is
very important make sure you select yes
because we're going to be working with
the new app router here and we're not
going to be working with the pages
folder as in the previous versions of
nex1 13 so make sure you select yes for
this option it's asking us whether we
want to customize the default import
alas so the default import alas is going
to be an alas inside of our Imports so
that we don't have to write all of those
long relative Imports if we are in a
deeply nested folder you're going to see
that in action once we start tutorial
but what I recommend you choose for this
option is no so leave it as it is the
default one is the add sign and we're
going to be using that in this tutorial
so just select no for this option and
there we go you can sit back relax and
wait for this to
install great so now that we have our
next project configured what I want to
do is I want to open this folder where
it says that it created the notion clone
project so I'm going to go ahead and
find the open button right here and I'm
going to select notion clone because
that's the name of my project if you get
this prompt feel free to just say yes I
trust the authors like this great so
just make sure you're inside of your new
notion clone to confirm that You'
installed it correctly you should have
the app folder with the favicon with the
globals layout and page. ESX you should
also have the public folder the node
module folders some slin configuration
and a a tailwind and typescript
configuration because we chose those
options initially when we created the
project what I want to now is initialize
a Shaden UI inside of the project that
is a library which is built on top of a
radic UI and we're going to use it to
style our entire project and it works
very well with Tailwind so it's perfect
for our use case so let's head back
inside of our
terminal right
here and I'm just getting a little
update here so let me pause the screen
and update my shell you don't have to do
this of course all right sorry for that
and now you can just go ahead and write
npx shat cn- at latest in it like this
which is short for initialize and go
ahead and press enter and now it's
asking us a couple of questions so let's
look at the first question it's asking
us whether we are using typescript
remember we initialized our entire
project with with typescript that means
we also want typescript components so
select yes for this one for the style go
ahead and select
default for the color it doesn't really
matter but if you wanted to look the
closest to my tutorial go ahead and
choose neutral you can of course play
around and select your own dark color
but neutral in my case kind of gives me
the best looking app similar to notion
so select neutral for this option now
it's asking where is your global. CSS
file well just a moment ago we opened
the app folder and we confirmed that it
is there so you can just press enter now
it's asking us if we want to use CSS
variables for colors and you can freely
select yes for that option now this is a
tricky part so in my case it's asking me
where is your Tailwind doc config.js
config.js
located but let's take a look in my
browser right here so don't close the
terminal I'm taking a look at my browser
here and notice that I don't have
Tailwind doc config.js instead I have TS
so if you have the same thing if you
have a file called Tailwind doc config
dots instead of JS then you need to
modify this command so all that it's
important is that it doesn't create two
Tailwind files for you don't worry if
you mess this up you can still work and
your project will work and your Styles
will work and your Tailwind will work
even with two different config files but
let's do this properly so go in your
file browser and confirm whether you
have a DOT typescript or a JavaScript
version of the Tailwind config then go
back inside and what you can do here is
you can press the Tab Key and then you
can manually edit from JS to TS or if
you actually have ajs file you can just
leave it at JS in my case I need a TS
file so I'm going to change it tots and
press enter remember I pressed the tab
button to edit this placeholder which
was hardcoded in this interface go ahead
and press enter now it's asking us to
configure the import alas for components
remember when we configured our project
we set the default import Alias to be an
add sign meaning that this placeholder
is going to work so we can safely press
enter here same is true for our lib and
utils and it's asking us what we are
using server components that is
referring to the question in next 13
initialization where we selected the app
router since we selected yes there that
means that we're also selecting yes here
and go ahead and confirm this
configuration by pressing enter or the y
letter and now just sit back relax and
wait for this to
finish and now that you finally set up
the shaten UI you can go ahead and run
mpm run Dev inside of this repository
and that is going to start the nextjs
project on Local Host 3000 so I'm going
to go ahead in my browser now and I'm
going to refresh this screen and you
should be seeing something similar to
this great so we're now going to modify
this so it's actually more suitable for
the project that we need so let's go
ahead inside of our app folder and let's
see what we have here
so first we have the layout. DSX file so
layout files are kind of like group
files which reflect the entire project
they can be Global like this one which
is reflecting every single route and
every single component inside of our
nextjs project or they can also be
grouped inside a specific folder but
we're going to come to that a bit later
so layout is not the file which you
would technically use to render
something of course you can but it's
more of a file which you would where you
would put for example a reusable layout
like a sidebar and a navigation bar
right whereas the page. DSX would be the
one where you want your user to do
something like a form or something like
that so first thing I want to do is go
inside of page. TSX file right here and
I want to remove everything inside of
this return function so let's go ahead
and remove everything here and let's go
ahead and write a paragraph saying hello
notion clone and save this and now you
should get all of that removed and
instead you're going to have a nice
little text probably much smaller for
you so I just zoomed in a lot saying
hello notion clone and now what I want
to do is I want to try out our CSS right
so one thing that I want to show you is
that I'm using an extension called
Tailwind CSS so I'm going to write
Tailwind here
and there it is it's the first option
right here and let me just close this so
it's the first option here and it's
called Tailwind CSS intellisense make
sure you install this package because
writing Tailwind is going to be much
much easier with that for example you
can now open a class name here and you
can see that when I write font for
example well not always but it's very
helpful when it comes to colors for
example text-
r-500 like this and you can see that now
I have a little box here showing what
color the text should be all thanks to
that extension I can also do a font Dash
and there we go now I I told you
sometimes it works sometimes it doesn't
you don't even have to use this out
complete but sometimes it's very helpful
when you want to confirm that the class
you're writing actually exists so let's
go ahead and let's select font bold like
this and save and there we go you can
see how in my uh screen on the right
here I have Hello notion clone in bold
red color and with this extension you
can also hover over to confirm the CSS
is actually what you think it is inside
of that uh class name great excellent
one more thing I want to show you is how
to install a shaten UI package so for
example let's say we want a button
component from the shat cnii package all
you have to do is go back inside of your
terminal and for now I'm just going to
shut down this Local Host 3000 and I'm
going to write npx
shaten shn n-i at latest and I'm going
to go ahead and just expand this even a
bit more and I'm going to write add
button like this and go ahead and just
press enter and that is going to install
the button component inside of your
project so you can now mpm run Dev your project
project
again and let me just zoom back in and
now if you take a look at your
components folder you're going to notice
that you have a new folder called UI and
inside of it a button DSX and in here
you have a production ready uh
accessibility compatible uh button
component all thanks to shatan UI and
the best part of it all it is fully
customizable so you have a lot of useful
variants here like a destructive variant
of it outline variant of it just like in
any other component Library which you
would use but what shatan offers us is
to go directly inside of the source code
and change it to our liking so let's try
that out go back inside of page. TSX
where you wrote the hello notion clone
and for now you can remove this
paragraph here and instead open a div
and now you can go ahead and add the
button from add/ components UI button
like this and you can remove this image
import we no longer need it so just add
a button from add/ components UI button
of course make sure that you confirm
that the button exists and that you run
that shatan command which we did just a
moment ago and now you can probably
notice that my Local Host did not hot
reload why is that happening well a
little tip for you every time you shut
down your terminal like I did in order
to install a button with this command
and you then run it again make sure you
refresh your Local Host because the hot
reload was broken for a second great and
as you can see we have a little button
here so what I'm going to do now is I'm
not going to do a self closing tag
instead I'm going to write click me like
this and below that I'm going to end the
button and there we go now we have a
nice button which says click me and if
you saw the source code and we just did
a moment ago together you know that you
can give it a variant prop and you can
for example mark it as destructive right
this would be something like trash or
delete something like that a destructive
icon right or you can also make it
outline like this whoops and you can see
that when you write something that
doesn't exist you get a typescript error
so let's actually fix it and write
outline there we go now you can see a
brief little border around it or it can
be secondary like that and now you can
see it's not as noticeable perfect so we
have a very nice button which we can
easily customize to fit our notion clone
besides this we can also give it a size
like a default icon large small stuff
like that and the best part of it all is
that we can always directly go inside of
button like this so either uh the way I
did this is I hold the control or the
command key and then I press on the
component that I want to visit and then
I have a little popup here showing me
the definitions of that and inside of
here there is a button. TSX file and I
can click here and that's going to open
that file directly or if you want to do
it easier you can just visit the
components folder UI and find the button
so remember we can always visit this
component file ourselves and we can
change whatever we want want for example
you don't have to do this I just want to
show you how easy it is to add a new
variant let's say we want a variant that
our button is purple for whatever reason
so we can add that purple I'm going to
write text- white BG Das Indigo
-500 like that and then I can go back
here and guess what I can now give my
button a
variant of purple like this and look at
it it's purple now and I can reuse this
as many times as I want but one cool
thing that I can also do if it's not
something I want to reuse if it is just
a onetime thing I can always pass a
class name with BG Das Emerald for
example 500 and
text- white so you can see now I did not
pass a variant because this is only
going to be one time right we're not
going to reuse this perfect so that's
why I like shats and so much because it
fits so well with tailwind and because
it allows us to customize it all the way
way to how rounded the borders are
directly in the source code so if you
added this purple the same way I did you
can now safely remove it because we are
not going to need it and you can just
leave the component as it is perfect and
we're going to leave it like this for
now in the next part we're going to go
ahead and further explore the nextjs
structure excellent
job so now that we've set up our project
I want to show you a cool little
extension that is able to go through
your entire project and all the files
and decide what lters you need to ensure
the best code quality and standards in
your project so let's take a look right
now in this component if I add a random
space here nothing is happening well
this is technically called a trailing
space and if I had a linter like get div
check or prettier or something like that
I'm most likely to get a little little
underlined red error here saying that I
have a trailing space here that I don't
need and you're going to see this in
most Real World Companies the companies
you're going to work in in the future or
maybe you are already working at usually
in my projects I don't Focus so much on
lters but it is good to know that there
are a practice that should be used
inside of your projects so what I'm
going to do next is completely optional
but I think it's a very very useful
extension which can help you improve the
quality of your code and gain a better
understanding of which linters you need
for your project you can maybe even
recommend it inside of your company if
you're having trouble deciding between
some so I'm going to save this like this
for now remember I added a little space
here just a trailing space and what I'm
going to do is I'm going to go inside of
my extensions here and I'm going to
search for an extension called
trunk go ahead and select the first one
it's it's called trunk check and go
ahead and click install once you've
installed it leave it like this and
you're going to have a terminal popup
this terminal is right now looking
through your entire project and all the
files and it added all the necessary
linters inside of it config file for
your project so after it's done you're
going to get redirected to this trunk.
yaml file or the config file and you can
see that you can press any key to close
the terminal so just go ahead and press
any key to close it let's take a look at
this trunk yaml file as you can see it
scanned throughout our repository and it
decided that we need two runtimes node
and python it also decided that we need
this linters to ensure the code uh
quality and standard of the project and
if you want to you can even go further
ahead with this and you can go back
inside of your terminal I'm going to
open a new terminal for now and since
you have trunk installed what you can do
is you can write trunk login like this
and this is going to give you a login
link and you can then open that inside
of your browser and if you want to you
can continue with
GitHub after that you might have seen a
little authorized button here so just
press on it and you're going to have a
message you successfully signed into
trunk CLI of course this is not required
for this project right and you don't
even have to log in to use trunk so all
that you need is is an extension but I
want to show you the website because if
you want you can visit the documentation
and in here you can read about
everything the trunk can do regarding
this check linter so it has a lot more
options CI debugger CR analytics even
some merge queue right here but we're
only going to focus on the check uh
functionality of trunk and as you can
see trunk check runs more than 80 Tools
in your repositories which allow you to
prevent anti patterns and bugs prevent
misconfiguration or infrastructure code
and enforce code formatting and style
and much more and you can follow this
documentation if you want to add it to
your repository and you can configure
trunk. yaml to whatever you want so let
me show you how this now looks inside of
the code so if you want to you can play
around with trunk you can enable them uh
inside of your repository and you can
even add GitHub actions which are going
to fire on every pool request to ensure
that it can be merged according to the
code standard and quality to prevent any
buck so this is really good for
production uh ready websites if you want
them perfect so now that I've explained
that I'm going to close these tabs right
here and I'm going to go back inside of
my page. vsx file and as you can see now
I have an error here trailing whes space
exactly what I told you before so in
order to fix this I can just go ahead
and remove that and save it like that
and now that I installed the package
trunk sorry the extension trunk you can
see that I also have it right here in my
sidebar in your case it might be on this
side and if you can't see it you might
have three little dots here which will
allow you to see hidden extensions so
when you click on this here you can also
look that you have some hidden issues
here like incorrect formatting you can
also play around with actions and run
the following actions if you want I'm
not going to do all of that for this
tutorial but I just want to show you how
cool this extension is so let's see what
incorrect formatting we actually have
here and how we can format it well what
we can do is run command shift p or
control shift B and run format document
width like that and select trunk
check and as you can see now it added
double quotes and it added semicolons at
the end of my functions and now if I
save this file and go back you can see
that it has zero issues inside so you
can can use trunk every now and then
just to see the quality of your code and
if there is anything you can improve in
your production code perfect so you can
save that now and what I want to talk
about now is how routing Works in
nextjs so let's go inside of this app
folder here and let's create a new
folder called test like that and inside
let's create a new page called page.
TSX and let's go ahead and this is what
you're going to see me do a lot of times
in the project I'm going to write sfc
I'm going to press Tab and all of a
sudden I'm going to have this code
snippet so if you're wondering how I
have that it's another extension called
Simple react Snippets so go ahead and
install simple react Snippets if you
want that so let me show you again all I
do is write sfc and press Tab and then I
can give my component name test page
then I can press tab again and now I am
focused on the props but we're not going
to need them and if I press tab one more
time I'm focused on the return function
and inside I can just write a div and I
can write hello test page like that
perfect and you might be wondering all
right so why did they do this well we
are learning how routing Works in next
13 so right now I created a test folder
inside of the app folder and the test
folder has a page. DSX file inside of it
that means that that page is accessible
now so I can go to slash test now and as
you can see I'm going to see hello test
page right here so that is how routing
Works in next 13 and one trick I
immediately want to warn you of every
folder that you create inside of the app
folder can potentially become a route
for example let's say that you want to
create a very simple components folder
right like we like the one we have out
side of the app folder but let's say for
any reason you want to create it inside
technically you can do that but watch
what happens if inside you accidentally
have a a component called page so I'm
going to do a very same thing I'm going
to write
component so some component thing like
that and I'm just going to a div this is
supposed to be a component right so if I
created a components folder obviously
this is my page component right what
well guess what you can technically go
to SL components
now uh like this and look at this it's
rendered as a route that's not something
you want to happen so now you learn that
every folder you create inside of the
components folder is going to become a
route so here are a couple of ways to
prevent that so we're going to learn
some new types of folder inside of the
app folder if you want this to not be
routable what you can do is rename this
to underscore components like this and
as you can see now I have a 404 page
here right so for now we can delete this
underscore components folder like that
and if you have this error right here in
page. CS that is just cache so you can
just save this file and close it all
right and now I want to show you
something else so I'm going to go back
here to the test page so go to slash
test here and I want to show you how to
create uh route groups so route groups
are another type of folder which you can
write inside of the app folder which
will have no effect on the URL and Route
folders are for example parentheses like
root for example as you can see I
created a new folder inside but if I
create so what I'm actually going to do
is I'm going to move this main page. DSX
well we have the delete button and I'm
going to move it inside of root right
here and I'm going to save the file like
that and if I go back to Local Host 3000
you can see that I still have that page
as my root page so why is this working
and what happens if I go to slash root
for example as you can see it's 404 it's
not found that's because the root folder
is an organizational folder meaning that
it will not affect the URL but one thing
that it can do is have its own layout
which can then affect all the other
routes inside of that component so I'm
going to keep this as it is now and I'm
going to delete this test page for
example and I want to show you for
example let's create a new
organizational folder called out like
this and inside of it I'm going to
create another organizational folder called
called
routes and then inside I'm going to
create two routes they're going to be
login and they're going to be register
like this I'm going to create page. vsx
in both of them so this is just going to
be login page and let me just return a
div saying login page like that I'm
going to copy that and I'm going to
create a new page inside of register I'm
going to paste it here and rename it to register
register
page and now how do you think we access
this routes so we have login and
register well remember what I just
explained you with the root folder so
when folder is inside of parenthesis
inside of the app folder that means it
has no effect on the URL it is purely
organizational right so the way we can
access those routes now are simply by
writing slash login like this or slash
register like this so you're probably
wondering all right well what's the
difference between the underscore folder
and the parenthesis folder well the
underscore folder completely eliminates
the entire entire route and all of its
content from the router but the
organizational folder with parenthesis
is just not part of the URL until it
reaches a normal folder and you might be
wondering well why did I create two
organizational folders here well because
that's what I'm trying to do I'm trying
to organize my f my structure in a
better way because this organizational
folder can also have another file inside
of it called layout. TSX like this and
as you can see now I have an error here
so let's quickly fix by the error by
going inside of layout. vsx and let's
write root layout and now let's extract
the children from the props because
every layout component has
children and just mark it as react.
react node like this and inside write a
div and render children inside and once
you save the file you're probably going
to notice well our register page looks
the same same my login page also looks
the same what's the difference well
nothing but if you take a look at the
HTML structure you're going to notice
that we now have one extra HTML right
and to make this more noticeable let's
give this div a class name of h- full BG D
D
r-500 text- white like this there we go
look at now so as you can see now my
login page has a red background and it
has white text and same is true for my
register page why is that happening well
that's why organizational folders are
useful so a you can use them to organize
your files in a better way if you don't
want them to just be thrown around and B
you can create layouts inside of
organizational folders and this layout
is going to reflect all the routes
inside so both login and register now
have a BG red and text white so we are
going to use this throughout the project
to create separate layouts for example
when we uh when we do a landing page we
don't want to have a Navar and a sidebar
right but when we are inside of our
notion clone we want to have a sidebar
and a nov bar if we open the specific
document well we can leverage
organizational routes and layout files
in order to achieve that great so we
have now prepared this little structure
here you don't have to worry about this
too much we're going to remove these
folders but I just want to practice with
you a little bit so what I encourage you
to do now is to try and understand how
these folders work so it's important
that you understand when you see a
folder in parenthesis it's not part of
the URL until it reaches a normal folder
and then this is reachable at just slash
login same is true if I just have root
and inside page. TSX right so this is
now accessible at just a slash it
doesn't matter what the organizational
folder is named the only thing that
matters it that it is an organizational
folder and you can notice that using the
parenthesis so I just wanted to cover
different types of folders inside of the
app folder we covered the uncore folder
which we're going to use throughout this
project when we want to add components
which are not reusable so all reusable
components are going to be inside of our
components folder where our shat CN
button is right now but for example if I
only want to create a component like a
nvar in the landing page right there's
no point in making that reusable so what
we're going to do is we're going to
create the underscore components folder
and put Navar inside of there that way
we're going to ensure that that folder
is nowhere rendered inside of our routes
but we can still use it as a component I
hope I made this clear enough if you're
confused don't worry we're going to go
slowly and I'm going to explain it once
again while I'm doing that but for now
this is perfect great great
job so what I want to do now is create
our marketing page or as we're going to
refer to it landing page before we do
that I quickly want to address that I
added a class h- full in this root
layout right here and the background
color of red but if you look at the
browser it seems like this is not taking
up the entire space as you would might
expect with this H full class right here
and that's because we're missing one
thing inside of our app folder global.
CSS right here we're missing a class
name which is going to add height 100 to
HTML element to the body element and to
the root element so write HTML comma
body and comma column root like this and
go ahead and write height
100% like that and let's refresh and
there we go now you can see that our H
full class which we've given inside of
this out layout right here is working
and it's taking up the entire space so
what I want to do now is I want to go
ahead and remove everything we don't
need in here so we created some folders
to explain all the types of folders
which we're going to work work with but
we can for now remove the out folder
entirely we don't need it so you should
get a 404 if you go to/ register or/
login so you can just go to plain local
Hill 3000 where we have our delete
button and instead of calling this
whoops instead of calling this a root
folder instead I'm going to reame this to
to
marketing right so remember what I said
when a folder is in parentheses it
doesn't matter what it's called it's not
going to be the part of URL so you can
safely save this and once you do these
changes with the root Pages you're often
going to get this weird unsaved change
inside of the next folder which is the
cache right so you can fix this very
easily just click inside of the file and
save it just like that if you mess it up
you can always completely remove this uh
next document so if you think you're
having some problems with the cache let
me show you how you can fix that so you
don't have to do this if everything is
working correctly for you but I just
want to uh show you a quick fix for it
so I'm just going to close this terminal
so if you Contour an error with the
cache you think you've messed it up no
worries you can just do this you can do
RM rf. nextt so just remove the next
folder or if you're using Windows and
this command doesn't work for you you
could also just right click on it and
delete right uh and then what you're
going to do is just mpm runev that's it
and take a look now you're going to see
that I have a new next folder generated
right here so it's that simple to fix
that if you think you've messed it up so
no worries just remember refresh your
local close to once you do this uh great
so what I want to do now make sure you
rename this to marketing and we're going
to leave it like that for now and
instead uh let's go inside of our
layout. DSX and what I want to do is I
want to change this metadata as you can
see now my tab has a title of create
next app and I want to change that so it
actually uh uses the name of the app we
are going to create which we're going to
call Josan so let's give it a type of
Jan like this that's going to be the
title let's give it a description well
you can do what ever you want but uh for
example an app like this would have
something like the connected workspace
where better comma faster work happens
something like that it really doesn't
matter great and what I want to do now
is I want to show you uh how to add uh
how to change this little icon that we
have right here also called a favicon as
you can see right now it's showing a
versel icon here and the reason it's
showing that is because you have a
favicon.ico in side right here so if you
technically remove this icon and refresh
your page as you can see now it's gone
because it cannot read any favicon but
you don't have to always put a
favicon.ico inside of the app folder to
add a favicon you can also keep it
wherever you want for example in the
public folder but you do have to tell
layout metadata where it's located if
it's not inside of the app folder so
that's exactly what I want to do now so
I want you to go inside of my GitHub
where I have my Logos and images right
or you can of course find any logo
online you want so go inside of my
GitHub and go inside of the public
folder and you see I have a lot of
images here which you are going to use
but the ones I want to focus on now are
the logo. SVG and Logo Das dark. SVG so
I'm going to copy log logo. SVG and I'm
going to click download row file like
that and I'm going to go ahead and drag
and drop that file inside of my public
folder so I open the public folder here
and through Chrome I'm just dragging
dropping it into the public right here
and I have a little extension which
previews that logo here so it's just an
SVG file and go ahead and do the same
thing still inside of my public folder
with logo D dark so this is a logo which
we're going to use if we are in dark
mode right so let's go ahead now and
let's drag and drop that as well in the
public folder here so logo D dark and
drag it in the public folder so it's the
together with
logo.svg perfect now that we have that
I'm going to go back inside of my app
folder layout right here and I'm going
to add icons
object and I'm going to write icon to be
an array like that object
media and we're going to write if in
parenthesis refers Das color- scheme to
be light so if we are in light mode the
URL is going to be slash
logo.svg and the HRA it's also going to
be/ logo.svg so when things are in the
public folder you don't have to write
public they are immediately under the
slash right so the reason I added two
icons is because as you can see in my
tab I'm using dark mode on my Chrome and
it would be weird if the icon was dark
as well right it would barely be visible
so I want to use light icon if I am uh
on dark mode but a dark icon if I am on
light mode so that's we going to add an
array of icons here so you can just copy
and paste this below and change this one
to be prefers color scheme to be dark so
if we are on dark mode in that case
we're going to use logo D dark. SVG and
there we go look at my browser now see
how it says Jos and see how I have a
nice little icon which is right this one
it's using the dark one right now
because I'm in dark mode by default but
if I if I switch my Chrome to light mode
it's going to be using this one so it's
going to look better because the tabs
are going to be white perfect so we have
that solved so I just wanted to do that
and what I want to do now is I want to
go inside of the marketing and I
actually want to start uh creating the
marketing page so let's go inside of
marketing page. vsx here and I want to
go ahead and change this to be constant
marketing page like
that and I want to export
default marketing page so I just change
the way I export default it doesn't
really matter and let's see the mistake
I made marketing oh I missed an page all
right so marketing page make sure you
don't have any typos and what I'm going
to do now is uh modify this so we don't
need the button at this moment instead
let's add a a div with a class name of
Min dh- full Flex
flex-all like this so we're creating our
outmost div which has a minan height of
100% And we already prepare that this is
going to be a flex box the reason we
prepare that it's going to be a flex box
is because we're also going to have a
footer which we want to keep all the
times at the bottom and the way we can
do that is by using Flex box so when we
create our footer element we can just
push it all the way to the bottom using
Flex perfect so what I want to do now is
a div inside with some other class names
so let's go ahead and let's write class
name to be Flex flex-all items d Center
justify Das Center on medium devices
it's going to be justify Das start text
is going to be centered gap of each item
inside of this div is going to be
separated by the value of eight which is
two Ram or 38 pixels Flex is going to be
one so this is what I was talking about
so this div is going to take majority of
the screen and then below that we're
going to add a footer so the footer is
always going to be at the bottom because
of this Flex one option right here and
because the outer div has the flex
layout perfect and let's also give it
some padding so from both sides padding
six and from the bottom padding 10
perfect and inside first thing I want to
add is a heading component so if you
save you're going to get an error
because heading component does not exist
yet so let's go ahead and let's see how
we're going to do this so let's go
inside of the marketing folder and
remember what I told you we could
technically create the components folder
just by writing components but remember
that is going to be part of the URL and
we don't want that so what we're going
to do is create it with underscore
components like that and you might be
wondering well why not just reuse this
components folder outside of the app
folder well I want to keep that
components folder for reusable
components like buttons and dialogues
models other stuff we're going to have
but whatever I write in this components
folder it's only going to be for the
marketing or for the landing page so it
doesn't make sense to share it with the
other files so let's go inside and let's
add our heading. DSX component and let's
go ahead and let's mark this as use
client so this is not going to be a
server component it's going to be a
client component because we're going to
have some actions uh in on our buttons
inside great so let's go right let's go
ahead and write export const heading like
like
this and let's go ahead and let's return
a div with a class name of Max W3 EXL so
we limit how wide this uh heading can go
and let's give it a space- y-4 so all
elements inside are evenly spaced out
perfect now let's write an H1 element
and we're going to write your ideas
ideas
documents and
plans unified welcome to and then we're
going to write a span element and we're
going to write
Josan and let's give this span element a
class name of
underline now let's give this well
before we do anything let's actually go
back to our page. TSX and let's import
this heading so we can actually see what
we're doing so make sure you import
heading from slore components slhe
heading like this and go ahead and save
this and there we go you can see how I
have this text right here in the center
now and now let's go ahead back to this
H1 element and let's go ahead and let's
give it a class name of text Dash
3 Excel on small devices is going to be
text- 5
Excel and on medium devices is going to
be text- 6 Excel so we're going to have
different size of text depending on how
wide our screen is and we're also going
to give it a font bold on all devices
like this so currently we are on mobile
mode right but if I expand you can see
that it looks much different great and
let me just reset my zoom so it's in
something uh expected like this there we
go so it's uh like that now below the H1
element let's add an H3 element and
inside we're going to write Josan is
the connected workspace where and let's
manually add a little break here better
faster work happens like that so you can
see we have a much smaller text below
this H1 element and let's give this H3
element a class name of
text-base let's give it a small device
of text- XL let's give it a medium
device of txt-2
XL and let's write font Das
medium great and now what I want to do
uh well we can actually leave it like
this for now below this H3 element the
only thing we can actually do is add a
little button here so we can already
prepare so just add a button and import
that from button and/ components UI
button and we're going to to write enter
Jan like that and let's also write a
little arrow right icon from Lucid react
so you already have lucid react
installed when you installed shat CN UI
so make sure you import error right from
Lucid react and let's go ahead and give
it a class name of h-4 W-4 and
ml-2 like that great so you can see that
now we have a little uh heading here we
have the description and we have a
button here of course this is later
going to become Dynamic depending if we
are logged in or not all right so now
that we have our heading we can go back
inside of the marketing page and below
the heading we can now add a new
component called
Heroes and inside of Heroes we're
actually going to add all of our uh nice
images so let's go ahead and create the
heroes component the same way we did
with the heading component so instead of
the underscore components create
heroes. DSS X and let's go ahead and
let's import image from next SL image
Heroes and we can just do a quick little
return function with a div saying Heroes
like that go inside of page. vsx and
import Heroes the same way you did The
Heading and go ahead and save this now
and now we have a text here which says
Heroes what I want to do now is I want
to add the images we need inside of
these Heroes so prepare your public
folder the same way we did with the
logos right and go back inside of my
GitHub and go inside of my public folder
and the ones we need right now are
documents documents DD
dark.png and we also need reading and
reading D dark.png so first let's do the
documents so documents. PNG right here
and let me just expand this so I can
find find the download
button like that and I will drag and
drop it inside of my public folder so
now I have documents and now let's use
the documents Das dark the same way you
can see how this one is white so it can
be so it can look good against a black
uh background and do the same thing with
reading so reading. PNG here let's
download that as well let's uh pass it
inside of the public folder and let's
also copy the reading dark.png
dark.png
like that and let's move it inside of
our public folder perfect so just make
sure that you have the document the do
sorry the documents documents dark and
that you have the reading dark and
reading great you can go back inside of
your page now and I'm going to expand my
code screen here and I'm going to go
back inside of my uh Heroes component
which I just created inside of the
marketing undor components Heroes right
here let's give this div a class name of flex
flex
flex-all items D Center justify Das
Center Max dw5 Exel and inside of that
create another div with a class name of
flex items Das Center and inside create
a div which is going to hold our image
so class name relative W open square
brackets 300 pixels h- square brackets
300 pixels as well on small devices the
width is going to be 350
pixels and on small height is going to
be uh 350 pixels as well on medium
devices height is going to be 400 pixels
and on medium devices width is going to
be 400 pixels as well and inside you can
now render image component which we
imported above from next slash image and
give it a source of Slash documents. PNG
give it a property of fill and give it
an ALT of
documents and let's also give it a class
name of object Das
contain like that there we go so you can
see how we have a nice little uh
documents image Here and Now what I'm
going to do is I'm going to go outside
of this div which is wrapping this image
component and create a new div like that
and let's go ahead and write a class name
name
here relative h- 400 pixels W
Das 400 pixels as well and inside render
another image
component with a source of SL reading.
PNG a fill property and a class name of
object D
contain so you might be wondering well
this looks a bit weird well I only want
to show you how this will look because
now we're going to go back inside of
this let's just see what's missing for
the image sorry oh we are missing an ALT
property so let's give it an ALT
property of
reading there we go and now go back
inside of this div which is
encapsulating the reading image and hide
it on mobile devices so hidden by
default but when it reaches a medium
it's going to be blocked so you can see
on mobile we're not going to render it
because we don't have that much space to
work with but when we expand you can see
that it's going to go uh it's going to
come back to life here so that's what we
want all right uh and now what I want to
do is I want to go back inside of page.
vsx our marketing page. TSX where we
have heading and the heroes and below
that let's add a footer component so the
same way uh we did with the heading and
the heroes and now let's go back inside
of the components folder and create a
new file footer.
PSX and go ahead and Export con
footer and return a div saying
footer go back inside of page. DSX and
render the footer from _ components
footer and you can see all the way at
the bottom here we have our footer text
we can now go back inside of the footer
component let's give it a class name of
flex items Das Center w- full padding of
six let's give it a BG of
background and let's give it a z- 50 so
we have a z index Here and Now I want to
create a logo component so you can see
when I save now we're going to get an
error because it doesn't exist but we're
going to create a logo component which
is going to be shared across the footer
and across the nav bar which we are yet
to create so let's go and inside of this
component folder where we have the
footer The Heading and the heroes create
a new file called logo. DSX go ahead and
import image from next slash image and
go ahead and import popins from next SL
font SLG Google so our logo is going to
have a special font and go ahead and
import CN from s/ Li utils so you got
this when you installed chat CN UI and
the CN library is going to be used to
dynamically append classes to our our
Tailwind uh elements uh without the fear
of overriding or incorrect merging so
yes you could technically do it with
template literals but using this library
is a better and the proper way of doing
it you're going to see what I'm talking
about in a second but before we get
there let's actually Define this Poppins
font so cons font is equal
Poppins open an object subsets open an
array and write Latin and give it a
weight or
400 and
600 and now export const
logo and return a div with a class name
of hidden so on mobile devices is going
to be hidden on medium it's going to
turn into Flex items is going to be
Center and gap between the two items is
going to be two and now let's add the
image component and let's write source
to be/ logo. SVG which we already have
let's give it a
height of 40 let's give it a width of 40
as well and let's give it an ALT of logo
like this and what I want to do is go
back inside the footer and you can now
import that from do/ logo because they
are in the same folder and if you now
expand your screen you can see little
logo here at the bottom on mobile
devices it's hidden because we don't
have that much room to work with but on
large devices it's right here
invisible great so let's go back inside
of this logo because we're not done here
and let's add a paragraphs here saying
Jan and let's go ahead and let's give
this paragraph a class name and it's
actually going to be dynamic class name
so go ahead and write
CN and let's write font semibold and
then let's append this Dynamic class
from this font so font. class name and
now if you expand your screen you can
see how we have a nice little Jan here
so if you cannot see this make sure you
expand your screen or you zoom out to a
specific level so you can see it all
right so now that we have this uh what I
want to do uh is I want to go back
inside of the footer
component below the logo here create
another dip the class name of MD ml- AO
W-4 full justify Das between MD justify
Das and flex items D Center Gap dx-2 and text-
flex items D Center Gap dx-2 and text- muted D
muted D foreground and inside we're going to
foreground and inside we're going to render two button elements so import
render two button elements so import button from at/ components UI Button as
button from at/ components UI Button as I did right here at the top and I'm just
I did right here at the top and I'm just going to keep these two
going to keep these two separated and in here I'm going to write
separated and in here I'm going to write privacy policy
privacy policy see I'm going to give it a variant of
see I'm going to give it a variant of Ghost and the size of small and you can
Ghost and the size of small and you can copy and paste this and you can change
copy and paste this and you can change this one to be terms and
this one to be terms and conditions and there we go now you have
conditions and there we go now you have two little uh items here of course we
two little uh items here of course we don't actually have privacy policy in
don't actually have privacy policy in terms and conditions but if you want to
terms and conditions but if you want to use this for your real website I just
use this for your real website I just prepared this for you here and you can
prepared this for you here and you can see that when you collapse they are each
see that when you collapse they are each on its own side and we don't have the
on its own side and we don't have the logo but when we are on desktop mode
logo but when we are on desktop mode they are all the way to the right here
they are all the way to the right here perfect so now that we have this done we
perfect so now that we have this done we are finally ready to create our
are finally ready to create our navbar so let's go and create a layout
navbar so let's go and create a layout for our marketing page so I'm going to
for our marketing page so I'm going to go inside of the app folder inside of
go inside of the app folder inside of this marketing folder right here let me
this marketing folder right here let me just expand my screen a bit so I can
just expand my screen a bit so I can resize the Navar here and besides the
resize the Navar here and besides the components and page. DSX I'm going to
components and page. DSX I'm going to create a new file called layout. DSX
create a new file called layout. DSX because remember each organizational
because remember each organizational folder can have its own layout and in
folder can have its own layout and in this case our marketing layout is going
this case our marketing layout is going to have a nov bar so let's go ahead and
to have a nov bar so let's go ahead and let's write marketing layout let's
let's write marketing layout let's extract the
extract the children let's give this children a type
children let's give this children a type of react. react
of react. react node and let's go ahead and let's return
node and let's go ahead and let's return a div the class name of h- full and
a div the class name of h- full and let's go ahead and return a main element
let's go ahead and return a main element where we're going to render the children
where we're going to render the children and in the main element add a class name
and in the main element add a class name of h- full and padding top of 40 and
of h- full and padding top of 40 and above that add a navbar component which
above that add a navbar component which if you save right now is going to give
if you save right now is going to give you an error so let's go inside of our
you an error so let's go inside of our components folder and create a new file
components folder and create a new file nvb bar. DSX and let's go ahead and Mark
nvb bar. DSX and let's go ahead and Mark this as use client and let's export cont
this as use client and let's export cont Novar and let's return a div saying
Novar and let's return a div saying Novar and let's go back inside of
Novar and let's go back inside of layout. DSX and let's import it from do/
layout. DSX and let's import it from do/ components Novar like this so we no
components Novar like this so we no longer have that error great now we can
longer have that error great now we can go back instead of navb bar. DSX and
go back instead of navb bar. DSX and what I want to do is I want to create a
what I want to do is I want to create a hook called use scroll top so I want our
hook called use scroll top so I want our navb bar to not have any border while we
navb bar to not have any border while we are not on the top but if we are zoomed
are not on the top but if we are zoomed in like this and if we scroll down I
in like this and if we scroll down I want the Novar to follow that and add a
want the Novar to follow that and add a little border to it you're going to see
little border to it you're going to see in a second what I'm talking about so
in a second what I'm talking about so let's go ahead and let's create uh that
let's go ahead and let's create uh that hook so we are going to create a new
hook so we are going to create a new folder called hooks at the root of our
folder called hooks at the root of our application so you can just click on a
application so you can just click on a random file like this just make sure
random file like this just make sure it's not a folder click on a random file
it's not a folder click on a random file outside of any folder here and then you
outside of any folder here and then you can create a new folder at the root
can create a new folder at the root called hooks like this go inside and
called hooks like this go inside and create a new file called use- scroll dt.
create a new file called use- scroll dt. DSX and let's go ahead and let's import
DSX and let's go ahead and let's import use State and use effect from
use State and use effect from react let's export con use scroll top
react let's export con use scroll top let's give it a uh
let's give it a uh threshold to be a default value of 10
threshold to be a default value of 10 let's add a state scrolled set scrolled
let's add a state scrolled set scrolled so we're going to detect whether the
so we're going to detect whether the user scrolled or not and use state by
user scrolled or not and use state by default is going to be false and now
default is going to be false and now let's add a use
let's add a use effect which is going to have a listener
effect which is going to have a listener here so we're going to write uh
here so we're going to write uh window. addevent listener on
window. addevent listener on scroll and we're going to pass in a
scroll and we're going to pass in a handle scroll function which we don't
handle scroll function which we don't have now but we're going to have in a
have now but we're going to have in a moment and we also have to write a
moment and we also have to write a return function which is unmount where
return function which is unmount where we remove the event listener so window.
we remove the event listener so window. remove event listener scroll and the
remove event listener scroll and the same one handle scroll which we don't
same one handle scroll which we don't have yet and then go inside of use
have yet and then go inside of use effect and write const handle scroll
effect and write const handle scroll like that and write if window. scroll y
like that and write if window. scroll y position is larger than threshold we're
position is larger than threshold we're going to assume that user has scrolled
going to assume that user has scrolled so we're going to set the state of
so we're going to set the state of scroll to True otherwise if user goes
scroll to True otherwise if user goes back to the top we're going to set set
back to the top we're going to set set the state of scroll to false so this is
the state of scroll to false so this is going to be just a little trick so we
going to be just a little trick so we have better user experience and let's
have better user experience and let's also pass in the threshold prop in the
also pass in the threshold prop in the dependency array and let's go ahead and
dependency array and let's go ahead and let's return
let's return scrolled so this state value right here
scrolled so this state value right here great and now we can go back inside of
great and now we can go back inside of our app marketing components nvb bar.
our app marketing components nvb bar. DSX and let's go ahead and let's add
DSX and let's go ahead and let's add that scrolled so
that scrolled so scrolled is going to be use scroll top
scrolled is going to be use scroll top from at/ hooks use scroll top and now in
from at/ hooks use scroll top and now in this div we're going to add a class name
this div we're going to add a class name which is going to be dynamic using the
which is going to be dynamic using the CN library from s/ li/
CN library from s/ li/ utils and let's go ahead and first let's
utils and let's go ahead and first let's give it some default classes which are
give it some default classes which are not going to be dynamic so Z of Z index
not going to be dynamic so Z of Z index of 50 BG
of 50 BG background
background fixed top zero plus FX items D Center w-
fixed top zero plus FX items D Center w- full and padding of six great and then
full and padding of six great and then inside sorry uh then after this default
inside sorry uh then after this default classes add a comma and if we have
classes add a comma and if we have scrolled away from the top only then are
scrolled away from the top only then are we're going to add a border bottom and a
we're going to add a border bottom and a shadow like this so only when we scroll
shadow like this so only when we scroll we're going to have a little uh border
we're going to have a little uh border so let's see if we can already do that
so let's see if we can already do that when I scroll there we go you can see
when I scroll there we go you can see how I have nice little Shadow here but
how I have nice little Shadow here but when I'm up to the top you cannot even
when I'm up to the top you cannot even distinct that this is a separate
distinct that this is a separate component from the background but when
component from the background but when you scroll see how you have a nice
you scroll see how you have a nice little effect here so it's details like
little effect here so it's details like this that make the landing page better
this that make the landing page better great so now that we have that I'm going
great so now that we have that I'm going to replace this navbar with a logo
to replace this navbar with a logo component from do/ logo which we
component from do/ logo which we created like that perfect uh and let's
created like that perfect uh and let's just see uh okay so it's right here here
just see uh okay so it's right here here perfect great and now besides the logos
perfect great and now besides the logos I'm just going to zoom this out so I'm
I'm just going to zoom this out so I'm in desktop mode make sure you are in
in desktop mode make sure you are in desktop mode as well so you can see your
desktop mode as well so you can see your logos and beside the logo here I'm going
logos and beside the logo here I'm going to go below it and add a new div with a
to go below it and add a new div with a class name of MD ml- AO MD justify Das
class name of MD ml- AO MD justify Das and justify Das between on mobile
and justify Das between on mobile devices of course w- full Flex items D
devices of course w- full Flex items D Center and GAP
Center and GAP dx-2 and all I'm going to write here for
dx-2 and all I'm going to write here for now is going to be um login like this so
now is going to be um login like this so we don't have the button for that yet
we don't have the button for that yet but I just want to show you that it's
but I just want to show you that it's going to be here or on mobile it's going
going to be here or on mobile it's going to move to this side perfect so now that
to move to this side perfect so now that we have that uh what I actually want to
we have that uh what I actually want to do is I want to enable light and dark
do is I want to enable light and dark mode for this landing
mode for this landing page so in order to add dark mode I'm
page so in order to add dark mode I'm actually going to go ahead and follow
actually going to go ahead and follow the shat instructions for it so go to
the shat instructions for it so go to shaten website and click on components
shaten website and click on components here and then you can find this tab
here and then you can find this tab which says dark mode go ahead and select
which says dark mode go ahead and select nextjs and let's now follow the steps
nextjs and let's now follow the steps which we need to do so first one is to
which we need to do so first one is to install next themes package so I'm going
install next themes package so I'm going to copy this for npn because that's what
to copy this for npn because that's what we are using and let's go inside of the
we are using and let's go inside of the terminal here I'm going to open a new
terminal here I'm going to open a new terminal and I'm going to paste npm
terminal and I'm going to paste npm install next- themes and let's go ahead
install next- themes and let's go ahead and do that perfect and then what we're
and do that perfect and then what we're going to have to do is create a theme
going to have to do is create a theme provider so that is step two so go ahead
provider so that is step two so go ahead and copy this entire code if you for any
and copy this entire code if you for any reason cannot find it on the shatan
reason cannot find it on the shatan website you can always find it in my
website you can always find it in my GitHub so I'm actually going to put it
GitHub so I'm actually going to put it in a different uh space so I'm going to
in a different uh space so I'm going to go inside of components and I'm going to
go inside of components and I'm going to create a new folder called providers so
create a new folder called providers so I just want to separate the providers
I just want to separate the providers from the rest of the components and
from the rest of the components and inside I'm going to create a new file
inside I'm going to create a new file team- provider. DSX and go ahead and
team- provider. DSX and go ahead and paste everything inside so if for any
paste everything inside so if for any reason you cannot find this on the
reason you cannot find this on the shatan documentation you can just visit
shatan documentation you can just visit my GitHub and go ahead and find the
my GitHub and go ahead and find the components providers tee provider and
components providers tee provider and just copy it from there perfect so now
just copy it from there perfect so now that you have that the step three is to
that you have that the step three is to wrap the team provider inside of our
wrap the team provider inside of our layout so let's go ahead uh and let's do
layout so let's go ahead uh and let's do that so we're going to be doing that
that so we're going to be doing that inside of the root layout so let's go
inside of the root layout so let's go inside of the app folder layout. DSX so
inside of the app folder layout. DSX so not the marketing layout the app folder
not the marketing layout the app folder layout. DSX where we have our title
layout. DSX where we have our title description and dynamic icons here and
description and dynamic icons here and let's go ahead and let's just collapse
let's go ahead and let's just collapse this children
this children inside and let's just wrap this in theme
inside and let's just wrap this in theme provider and now we can see that there
provider and now we can see that there are two Imports you can either import it
are two Imports you can either import it from next SL themes or from s/
from next SL themes or from s/ components providers theme provider you
components providers theme provider you have to use this at/ components
have to use this at/ components providers theme provider the one we just
providers theme provider the one we just created otherwise it's not going to work
created otherwise it's not going to work so go ahead and copy that and save it
so go ahead and copy that and save it like this and make sure you have the
like this and make sure you have the team Provider from as/ components
team Provider from as/ components providers team provider and what we have
providers team provider and what we have to do now is we have to give it some
to do now is we have to give it some attributes so go ahead and give it an
attributes so go ahead and give it an attribute of
attribute of class let's give it a default theme of
class let's give it a default theme of whatever is the system
whatever is the system theme let's give it enable system option
theme let's give it enable system option as well let's give it disable transition
as well let's give it disable transition on change prop and storage key is going
on change prop and storage key is going to be Jan Das theme like this so you can
to be Jan Das theme like this so you can do whatever uh you can write whatever
do whatever uh you can write whatever you want this for example you can put-
you want this for example you can put- two it doesn't really matter just make
two it doesn't really matter just make sure it's Unique uh and I think that
sure it's Unique uh and I think that should actually be it one more thing I
should actually be it one more thing I want to do is go to the HTML and I want
want to do is go to the HTML and I want to add suppress hydration warning like
to add suppress hydration warning like that because changing the theme can
that because changing the theme can cause some hydration warnings which are
cause some hydration warnings which are not really important to us so we can
not really important to us so we can suppress them with this prop to the HTML
suppress them with this prop to the HTML tag great so now as you can see when I
tag great so now as you can see when I refresh my dark mode is activated for
refresh my dark mode is activated for you that might not be the case so don't
you that might not be the case so don't worry if it's not I use dark mode on my
worry if it's not I use dark mode on my system by default and since we added the
system by default and since we added the default them to be system and enabled
default them to be system and enabled the system and I added a storage key
the system and I added a storage key that used my system theme so don't worry
that used my system theme so don't worry if yours is not working at the moment
if yours is not working at the moment because now we're going to add a button
because now we're going to add a button in the nav bar so that user can click
in the nav bar so that user can click and change the theme that they want so
and change the theme that they want so we have to do that by going back inside
we have to do that by going back inside the shats in UI we just did the step
the shats in UI we just did the step three right here and now we have to do
three right here and now we have to do the step four add a mod toggle so let's
the step four add a mod toggle so let's go ahead and let's click on code so this
go ahead and let's click on code so this is what it's going to look like right
is what it's going to look like right and now let's go ahead and go inside of
and now let's go ahead and go inside of code here and just copy this entire
code here and just copy this entire thing and go inside of your components
thing and go inside of your components folder right here and create a new file
folder right here and create a new file mode Das toogle do vsx so let me show
mode Das toogle do vsx so let me show you exactly so I just created it inside
you exactly so I just created it inside of the components folder so not inside
of the components folder so not inside of UI but inside of mode that toggle and
of UI but inside of mode that toggle and just paste the entire thing inside and
just paste the entire thing inside and as you can see now we have an error here
as you can see now we have an error here because we cannot find this drop-down
because we cannot find this drop-down menu that means we have to install the
menu that means we have to install the drop down menu from shat CM so let's
drop down menu from shat CM so let's quickly go back inside of our terminal
quickly go back inside of our terminal here and let's go ahead uh and I'm just
here and let's go ahead uh and I'm just going to uh zoom out actually I'm not
going to uh zoom out actually I'm not going to zoom out I'm going to close
going to zoom out I'm going to close this terminal and I will shut this down
this terminal and I will shut this down and go ahead and uh write the following
and go ahead and uh write the following npx shat cnsi at latest at dropdown-menu
npx shat cnsi at latest at dropdown-menu like this so we have to install that
like this so we have to install that package in order to have our mod toggle
package in order to have our mod toggle working so now it's installing the drop
working so now it's installing the drop down menu let's give it a couple of
down menu let's give it a couple of seconds and once it's done you can see
seconds and once it's done you can see that you're no longer going to have the
that you're no longer going to have the error inside of the mod toggle so I'm
error inside of the mod toggle so I'm just going to run my app again and there
just going to run my app again and there we go you can see that now there are no
we go you can see that now there are no errors here because this exists so so if
errors here because this exists so so if I go inside you can see that I have all
I go inside you can see that I have all the drop down code here but this is what
the drop down code here but this is what we are focusing on The Mod toggle make
we are focusing on The Mod toggle make sure you save this file make sure it's
sure you save this file make sure it's named mod toggle make sure ins it is
named mod toggle make sure ins it is inside of the components folder and now
inside of the components folder and now what you can do is go back inside of
what you can do is go back inside of marketing components nvb bar. vsx right
marketing components nvb bar. vsx right here and instead of uh this login text
here and instead of uh this login text add a mod
add a mod toggle from add/ components mod Das
toggle from add/ components mod Das toggle like this perfect and I'm just
toggle like this perfect and I'm just going to move it to the top with the
going to move it to the top with the others great and now if you go back
others great and now if you go back inside of your application and
inside of your application and refresh instead of this there we go I
refresh instead of this there we go I have a little Moon icon and I can change
have a little Moon icon and I can change this to light mode now or I can change
this to light mode now or I can change it to system so now we have enabled
it to system so now we have enabled light and dark mode but we're obviously
light and dark mode but we're obviously missing something when we switch to dark
missing something when we switch to dark mode we cannot see our pictures and some
mode we cannot see our pictures and some things just seems weird right so let's
things just seems weird right so let's go ahead and let's resolve that now
go ahead and let's resolve that now first thing I want to resolve this is
first thing I want to resolve this is this logo right here in the navbar and
this logo right here in the navbar and in the footer so we have to find that
in the footer so we have to find that component let's go and close everything
component let's go and close everything and let's go inside of the app folder
and let's go inside of the app folder marketing components logo. DSX right
marketing components logo. DSX right here and what I'm going to do is I'm
here and what I'm going to do is I'm going to add give this image a class
going to add give this image a class name of dark hidden so on dark mode the
name of dark hidden so on dark mode the logo is going to be hidden and then I'm
logo is going to be hidden and then I'm going to copy and paste this
going to copy and paste this just below like this and I'm going to
just below like this and I'm going to change this source to be logo Das dark
change this source to be logo Das dark but this one is going to have a
but this one is going to have a different class name it's going to be
different class name it's going to be hidden by default but if it's on dark
hidden by default but if it's on dark mode it's going to be block like this
mode it's going to be block like this and let's take a look at it now and
and let's take a look at it now and there we go you can see how now on dark
there we go you can see how now on dark mode we have the opposite white logo
mode we have the opposite white logo right here both in the footer and in the
right here both in the footer and in the nav bar here great but now let's just go
nav bar here great but now let's just go ahead and quickly revisit our nav bar
ahead and quickly revisit our nav bar here and I want to give it a different
here and I want to give it a different background if we are on dark mode so
background if we are on dark mode so let's go ahead and let's give it a dark
let's go ahead and let's give it a dark property so if we are on dark mode let's
property so if we are on dark mode let's give it a background of open square
give it a background of open square brackets and write a hex code of uh
brackets and write a hex code of uh whoops just a second my apologies 1 f 1
whoops just a second my apologies 1 f 1 f 1 F like this and there we go you can
f 1 F like this and there we go you can see that now our Navar has a slightly
see that now our Navar has a slightly different color then the rest of the
different color then the rest of the page so we're going to reuse this you
page so we're going to reuse this you can actually copy it like this and now
can actually copy it like this and now we're going to add it to some other
we're going to add it to some other stuff that we need like our layout so
stuff that we need like our layout so let's go inside of our layout but only
let's go inside of our layout but only the layout for the marketing so go
the layout for the marketing so go inside of this layout we have the h-
inside of this layout we have the h- full right here and go ahead and also
full right here and go ahead and also paste the dark background to be 1 f 1 F
paste the dark background to be 1 f 1 F 1f there we go now you can see that the
1f there we go now you can see that the nov bar matches the background of the
nov bar matches the background of the layout and now we have to do that same
layout and now we have to do that same thing but for our footer so inside of
thing but for our footer so inside of components go inside of the footer here
components go inside of the footer here and just add this to the end and there
and just add this to the end and there we go now our footer matches the color
we go now our footer matches the color perfect and you can already see how the
perfect and you can already see how the images are becoming a bit more clearer
images are becoming a bit more clearer but that's not what we want to do what
but that's not what we want to do what we want to do is we want to use
we want to do is we want to use different images depending on the light
different images depending on the light and dark mode the same way we did with
and dark mode the same way we did with our logos so what we have to do is we
our logos so what we have to do is we have to go inside of our heroes
have to go inside of our heroes component so go inside of underscore
component so go inside of underscore components heroes. DSX right here and
components heroes. DSX right here and let's find this first documents. PNG and
let's find this first documents. PNG and besides the object Das contain class I'm
besides the object Das contain class I'm also going to give it a dark whoops dark
also going to give it a dark whoops dark hidden
hidden class like that and then I'm going to go
class like that and then I'm going to go ahead and copy this below and I'm going
ahead and copy this below and I'm going to change this one to be hidden by
to change this one to be hidden by default but on dark mode it's going to
default but on dark mode it's going to be block and instead I'm going to use
be block and instead I'm going to use document
document dark.png and now as you can see this
dark.png and now as you can see this color matches the is more visible in
color matches the is more visible in dark mode now and if I switch to light
dark mode now and if I switch to light mode you can see how it reverts back to
mode you can see how it reverts back to the dark one so let's continue working
the dark one so let's continue working in dark mode and let's fix the issue for
in dark mode and let's fix the issue for this icon right
this icon right here so below that we have the reading.
here so below that we have the reading. PNG let's go ahead and let's copy and
PNG let's go ahead and let's copy and paste this let's change this to be
paste this let's change this to be reading do dark.png let's give this
reading do dark.png let's give this first one a class name of dark hidden
first one a class name of dark hidden and let's give this one Default hidden
and let's give this one Default hidden and dark to be block and now if you go
and dark to be block and now if you go ahead and expand your screen there we go
ahead and expand your screen there we go you can see how better this looks now
you can see how better this looks now and if you switch back to light mode
and if you switch back to light mode there we go all of it looks beautiful as
there we go all of it looks beautiful as well great great
well great great job so now that our landing page is
job so now that our landing page is almost finished what I want to do is
almost finished what I want to do is connect it to our back and then our
connect it to our back and then our database and I also want to add
database and I also want to add authentication in order to achieve those
authentication in order to achieve those two things we're going to be using
two things we're going to be using convex as our backend and as our
convex as our backend and as our realtime database and we're going to be
realtime database and we're going to be using Clerk and connect it with convex
using Clerk and connect it with convex for our authentication so what I want
for our authentication so what I want you to do first is create an account
you to do first is create an account with conx so go ahead and find the login
with conx so go ahead and find the login button right here and just click log in
button right here and just click log in with GitHub like this so make sure you
with GitHub like this so make sure you create an account and then you're going
create an account and then you're going to be redirected to the dashboard as you
to be redirected to the dashboard as you can see right now I already have a
can see right now I already have a project here which I've used to develop
project here which I've used to develop this application but what we're actually
this application but what we're actually going to do is we're going to create a
going to do is we're going to create a new project so you can try and click
new project so you can try and click here but you're just going to get a
here but you're just going to get a popup to follow how to create a project
popup to follow how to create a project in one of the quick starts right here so
in one of the quick starts right here so you can either click on link like this
you can either click on link like this or if you having trouble finding this
or if you having trouble finding this don't worry so I'm going to show you how
don't worry so I'm going to show you how to do it from their website so you can
to do it from their website so you can just go ahead and go on developer go on
just go ahead and go on developer go on documentation right here and find the
documentation right here and find the quick starts right here and once you're
quick starts right here and once you're in the quick starts go ahead and select
in the quick starts go ahead and select nextjs as your language so we already
nextjs as your language so we already have created our app so no need to do
have created our app so no need to do this step what we have to do is npm
this step what we have to do is npm install convex so let's do that first
install convex so let's do that first I'm going to go inside of my terminal
I'm going to go inside of my terminal here and let me just go ahead and clear
here and let me just go ahead and clear everything and I'm going to go ahead and
everything and I'm going to go ahead and run mpm install convex like this and
run mpm install convex like this and after convex has been installed in our
after convex has been installed in our Pro project we're going to run a command
Pro project we're going to run a command npx convex Dev and as you can see this
npx convex Dev and as you can see this will prompt you to log in with GitHub
will prompt you to log in with GitHub and also to create a project and it's
and also to create a project and it's also going to add some stuff in our
also going to add some stuff in our environment variable so we don't have to
environment variable so we don't have to do that ourselves so copy this command
do that ourselves so copy this command npx convex Dev and go ahead and paste it
npx convex Dev and go ahead and paste it here so npx convex Dev and for you it
here so npx convex Dev and for you it might be a little bit different I'm not
might be a little bit different I'm not sure if you're going to get this
sure if you're going to get this question immediately perhaps you're
question immediately perhaps you're first going to need to log in using
first going to need to log in using GitHub so if you see any links inside of
GitHub so if you see any links inside of your terminal just click on it and log
your terminal just click on it and log in with GitHub if not if you're seeing
in with GitHub if not if you're seeing this what I'm seeing just go ahead and
this what I'm seeing just go ahead and choose new project so this pre-selected
choose new project so this pre-selected option now it's asking us for a name and
option now it's asking us for a name and you can see that it already prefilled
you can see that it already prefilled the name with the name of my folder so
the name with the name of my folder so it's notion clone correct and now just
it's notion clone correct and now just press enter and there we go it created
press enter and there we go it created an entire project for us and now you can
an entire project for us and now you can see that you can just follow this link
see that you can just follow this link right here so just click it and open it
right here so just click it and open it and it's going to open that dashboard
and it's going to open that dashboard which you just saw a moment ago so now
which you just saw a moment ago so now if you take a look in your team you're
if you take a look in your team you're going to have one project so this is my
going to have one project so this is my old project and this is the new one
old project and this is the new one which I just created and as you can see
which I just created and as you can see from this dashboard you're going to be
from this dashboard you're going to be able to see all of your data all of your
able to see all of your data all of your files your functions your logs your
files your functions your logs your history everything and your schema once
history everything and your schema once we create it so it's going to be very
we create it so it's going to be very useful to follow this dashboard along
useful to follow this dashboard along what I want to show you now is what this
what I want to show you now is what this npx Con conx Dev command so this which
npx Con conx Dev command so this which we just run right here which created our
we just run right here which created our project you actually don't have to stop
project you actually don't have to stop this terminal right uh in order to use
this terminal right uh in order to use convex you're going to have to keep this
convex you're going to have to keep this running alongside your uh mpm runev but
running alongside your uh mpm runev but we're going to get to that later so for
we're going to get to that later so for now just keep this running in your
now just keep this running in your terminal and let's take a look at
terminal and let's take a look at everything new we have now as you can
everything new we have now as you can see we have a new convex folder and we
see we have a new convex folder and we have environment. loal so inside of this
have environment. loal so inside of this environment. local as you can see we
environment. local as you can see we have the convex deployment ID right here
have the convex deployment ID right here and we have the next public convex URL
and we have the next public convex URL and we also have a convex folder inside
and we also have a convex folder inside and inside of it we have some configs we
and inside of it we have some configs we have some generated stuff but we're not
have some generated stuff but we're not going to worry about that too much what
going to worry about that too much what you need to know that inside of this
you need to know that inside of this convex we're going to create our API
convex we're going to create our API functions our queries and our mutations
functions our queries and our mutations perfect so now that we have this set up
perfect so now that we have this set up what I actually want to do is go back uh
what I actually want to do is go back uh inside of the convex page go inside of
inside of the convex page go inside of the documentation here and if you want
the documentation here and if you want to you can explore for yourself how to
to you can explore for yourself how to set up a clerk authentication but don't
set up a clerk authentication but don't worry we're going to do it together so
worry we're going to do it together so what I want you to do is go to clerk.com
what I want you to do is go to clerk.com or use the link in the description and
or use the link in the description and just go ahead and log in after you're
just go ahead and log in after you're here just go ahead and create a new
here just go ahead and create a new application in my case this is going to
application in my case this is going to be notion Das tututorial like this and
be notion Das tututorial like this and you can play around with how you want
you can play around with how you want your users to sign in in my case I'm
your users to sign in in my case I'm going to disable the email I'm going to
going to disable the email I'm going to disable Google and instead I'm just
disable Google and instead I'm just going to select GitHub if you want to
going to select GitHub if you want to you can do it ex exactly like that or of
you can do it ex exactly like that or of course you can select whatever you want
course you can select whatever you want and just click create an application
and just click create an application like this and now that you have these
like this and now that you have these two items right here go ahead and
two items right here go ahead and immediately copy them and while we are
immediately copy them and while we are in this environment file let's also
in this environment file let's also paste them just below this next Publix
paste them just below this next Publix convex URL so make sure you have the
convex URL so make sure you have the next Publix uh next public clerk
next Publix uh next public clerk publishable key and clerk secret key
publishable key and clerk secret key like this um
like this um great what we have to do next is go back
great what we have to do next is go back and just revisit the convex
and just revisit the convex documentation so where am I right here
documentation so where am I right here so convex with clerk so we signed up for
so convex with clerk so we signed up for clerk we created an application in Clerk
clerk we created an application in Clerk and now we have to create a jvt template
and now we have to create a jvt template so let's go ahead and do that so go
so let's go ahead and do that so go inside of clerk right here and as you
inside of clerk right here and as you can see here in the sidebar I have jvt
can see here in the sidebar I have jvt templates like this and let's go ahead
templates like this and let's go ahead and let's create a new template and
and let's create a new template and select convex right here because that's
select convex right here because that's what we're using
what we're using uh leave it a name to be convex like
uh leave it a name to be convex like this and you can uh let's just see if we
this and you can uh let's just see if we have to modify anything I think we can
have to modify anything I think we can just leave it right here so in the jbd
just leave it right here so in the jbd SE okay no not just new template and
SE okay no not just new template and choose convex and we have to copy the
choose convex and we have to copy the ISS URL all right so let's go ahead and
ISS URL all right so let's go ahead and do that let's go inside of our Clerk and
do that let's go inside of our Clerk and we have the issuer right here and just
we have the issuer right here and just go ahead and copy this so find the
go ahead and copy this so find the issuer input and click copy and then
issuer input and click copy and then click apply changes like this and there
click apply changes like this and there we go now as you can see you have a new
we go now as you can see you have a new convex jbt template right here and let's
convex jbt template right here and let's see what we have to do next so we have
see what we have to do next so we have to create out. config.js inside of our
to create out. config.js inside of our convex
convex file so let's go ahead inside of our
file so let's go ahead inside of our convex folder and create a new file out.
convex folder and create a new file out. config.js and let's go ahead and let's
config.js and let's go ahead and let's export default
export default providers
providers like this domain and in the domain let's
like this domain and in the domain let's paste our issuer URL which we just
paste our issuer URL which we just copied from the clerk JT template and
copied from the clerk JT template and our application
our application ID is going to be
ID is going to be convex so just make sure you don't
convex so just make sure you don't misspell any of this stuff if you want
misspell any of this stuff if you want to you can copy it from here as well so
to you can copy it from here as well so it needs to be providers which is an
it needs to be providers which is an array which has an object the domain is
array which has an object the domain is our clerk issuer which we copied from
our clerk issuer which we copied from here
here right and our application ID is the name
right and our application ID is the name of uh is the name of our jvt template
of uh is the name of our jvt template which we left to be conx so it needs to
which we left to be conx so it needs to match application ID make sure both I
match application ID make sure both I and D are capital like this and you can
and D are capital like this and you can just save out. config.js
just save out. config.js so now that we have this out. config.js
so now that we have this out. config.js just make sure that inside of your
just make sure that inside of your terminal you have this running right so
terminal you have this running right so as you can see for a second I had an
as you can see for a second I had an invalid out convi I think that's because
invalid out convi I think that's because I misspelled application ID but after
I misspelled application ID but after that it looks like everything is okay so
that it looks like everything is okay so if you want to you can shut down the app
if you want to you can shut down the app and run npx convex Dev again so after
and run npx convex Dev again so after you've created this out. config.js file
you've created this out. config.js file just run npx convex Dev again and
just run npx convex Dev again and confirm that there are no errors in this
confirm that there are no errors in this function there we go everything seems
function there we go everything seems okay and that means it successfully
okay and that means it successfully connected to convex no errors perfect
connected to convex no errors perfect now we can close clerk we can close this
now we can close clerk we can close this dashboard and let's go ahead and see
dashboard and let's go ahead and see what we have to do now so as you can see
what we have to do now so as you can see we deployed our changes right now by
we deployed our changes right now by using this we confirm that there are no
using this we confirm that there are no errors and now we have to install clerk
errors and now we have to install clerk so let's go ahead and open a new
so let's go ahead and open a new terminal now so make sure you have the
terminal now so make sure you have the npx convex running and now let's go
npx convex running and now let's go ahead and let's do npm install at clerk
ahead and let's do npm install at clerk SL clerk Das react like this and go
SL clerk Das react like this and go ahead and press enter and once that is
ahead and press enter and once that is finished we're going to go ahead and
finished we're going to go ahead and we're going to create our convex
we're going to create our convex provider and we're going to combine it
provider and we're going to combine it with clerk provider so let's go ahead
with clerk provider so let's go ahead and let's close
and let's close this just make sure you have npx convex
this just make sure you have npx convex Dev running in the other terminal go
Dev running in the other terminal go inside of the components folder
inside of the components folder providers and create a new file called
providers and create a new file called convex
convex provider. DSX so let me just expand this
provider. DSX so let me just expand this so you can see convex D provider . DSX
so you can see convex D provider . DSX mark this as use client like that go
mark this as use client like that go ahead and import react node from react
ahead and import react node from react go ahead and import convex react
go ahead and import convex react client from convex SL react go ahead and
client from convex SL react go ahead and import convex provider with clerk from
import convex provider with clerk from convex SL react Das
convex SL react Das clerk go ahead and import clerk provider
clerk go ahead and import clerk provider and use out
and use out from at clerk SL clerk react like that
from at clerk SL clerk react like that now Define the convex constant so const
now Define the convex constant so const convex is going to be new convex react
convex is going to be new convex react client and inside passing process.
client and inside passing process. environment. nextore public convex URL
environment. nextore public convex URL so if you check your environment. loal
so if you check your environment. loal you have that right here nextore undor
you have that right here nextore undor convex URL you can copy it from here and
convex URL you can copy it from here and paste it it again here to confirm that
paste it it again here to confirm that you didn't do any misspellings and we
you didn't do any misspellings and we have a little error here so you can just
have a little error here so you can just put an exclamation point at the end for
put an exclamation point at the end for it to go away great and now let's export
it to go away great and now let's export const convex client provider like that
const convex client provider like that let's go ahead uh and
let's go ahead uh and whoops let's go ahead and let's extract
whoops let's go ahead and let's extract the children from here so the children
the children from here so the children are a
are a type of react
type of react node and let's go ahead and let's return
node and let's go ahead and let's return a clerk
a clerk provider and let's give it a prop
provider and let's give it a prop publishable key to be process.
publishable key to be process. environment. nextext corpu clerk
environment. nextext corpu clerk unpublishable uncore key and the same
unpublishable uncore key and the same thing you can go ahead and inside of
thing you can go ahead and inside of your environment. local and just confirm
your environment. local and just confirm that you have that here nextore public
that you have that here nextore public undor clerk publishable key you can copy
undor clerk publishable key you can copy it from here and paste pasted here to
it from here and paste pasted here to confirm and just put an exclamation
confirm and just put an exclamation point at the end so there are no errors
point at the end so there are no errors and if you don't have this well you
and if you don't have this well you should just get it from clerk.com
should just get it from clerk.com so go inside of clerk.com go inside of
so go inside of clerk.com go inside of your dashboard go ahead and select the
your dashboard go ahead and select the application which we just created and
application which we just created and there we go next public clerk
there we go next public clerk publishable key so just make sure you
publishable key so just make sure you have that in your environment variables
have that in your environment variables great and now that you have that let's
great and now that you have that let's go back inside of the convex
go back inside of the convex provider and let's go ahead and let's
provider and let's go ahead and let's give it a children of convex provider
give it a children of convex provider with clerk like
with clerk like this let's give it a prop use out to be
this let's give it a prop use out to be use out which we imported right here
use out which we imported right here from clerk react let's give it a client
from clerk react let's give it a client of convex which is this constant which
of convex which is this constant which we defined right here and then inside of
we defined right here and then inside of that we can just render the children and
that we can just render the children and now our entire application is going to
now our entire application is going to use authentication using convex as a
use authentication using convex as a database and clerk as the out provider
database and clerk as the out provider and now what we have to do is go inside
and now what we have to do is go inside of app folder layout. TSX right here and
of app folder layout. TSX right here and just above the theme provider you're
just above the theme provider you're going to go ahead and import that convex
going to go ahead and import that convex client Provider from at/ components
client Provider from at/ components provider convex provider and just wrap
provider convex provider and just wrap the entire team provider inside of it
the entire team provider inside of it like this so make sure you have this
like this so make sure you have this imported and there we go so now uh if
imported and there we go so now uh if you refresh you should not see anything
you refresh you should not see anything because we have never started the app so
because we have never started the app so inside of my terminal I have one
inside of my terminal I have one terminal which is running npx convex Dev
terminal which is running npx convex Dev and in my another terminal I'm going to
and in my another terminal I'm going to run mpm run Dev so I can finally see my
run mpm run Dev so I can finally see my application so let's just refresh this
application so let's just refresh this to confirm that we don't have any errors
to confirm that we don't have any errors and there we go seems like we don't have
and there we go seems like we don't have any errors and what we can do now is we
any errors and what we can do now is we can finally use some hooks to check
can finally use some hooks to check whether we are authenticated or not and
whether we are authenticated or not and we can also fire models to actually log
we can also fire models to actually log in using GitHub in my case or whatever
in using GitHub in my case or whatever you selected in your case so let's go
you selected in your case so let's go ahead and do that
ahead and do that now so first place I want to add
now so first place I want to add authentication check to is the nov bar
authentication check to is the nov bar right here so let's go ahead and let's
right here so let's go ahead and let's find our app folder marketing uncore
find our app folder marketing uncore components navb bar. TSX right here and
components navb bar. TSX right here and besides using the use scroll top hook
besides using the use scroll top hook we're also going to be using const use
we're also going to be using const use convex out like this and you can import
convex out like this and you can import use convex out
use convex out from use convex out from convex SL react
from use convex out from convex SL react like this and I'm just going to separate
like this and I'm just going to separate this import great so now we have used
this import great so now we have used convex out here and from here we can
convex out here and from here we can extract is authenticated and is
extract is authenticated and is loading so now what I want to do is I
loading so now what I want to do is I want to go outside Above This mod toggle
want to go outside Above This mod toggle right here and I'm going to add if is
right here and I'm going to add if is loading in that case I'm just going to
loading in that case I'm just going to go ahead and render a paragraph saying
go ahead and render a paragraph saying loading like this and below that I'm
loading like this and below that I'm going to go ahead and I'm going to write
going to go ahead and I'm going to write if we are not authenticated by adding
if we are not authenticated by adding the exclamation point at the end of the
the exclamation point at the end of the Boolean and if we're not
Boolean and if we're not loading in that case I'm going to render
loading in that case I'm going to render a fragment like this and I'm going to
a fragment like this and I'm going to render sign in
render sign in button which you can import from CL uh
button which you can import from CL uh from clerk react so go ahead to the top
from clerk react so go ahead to the top and let's go ahead and let's import sign
and let's go ahead and let's import sign in button from add clerk clerk react so
in button from add clerk clerk react so we have the sign in button now like this
we have the sign in button now like this and inside of it we're going to render
and inside of it we're going to render our button from s/ components UI button
our button from s/ components UI button so make sure you added the button from
so make sure you added the button from m/ component UI button I'm just going to
m/ component UI button I'm just going to move it here all right and inside of
move it here all right and inside of here I'm going to write log in like this
here I'm going to write log in like this and I'm also going to give it a variant
and I'm also going to give it a variant of Ghost and the size of small and I'm
of Ghost and the size of small and I'm going to give this signin button a mod
going to give this signin button a mod of model like that perfect and then
of model like that perfect and then below that I'm going to copy uh and
below that I'm going to copy uh and paste
paste this so inside of this fragment I just
this so inside of this fragment I just copied and paste this entire signing
copied and paste this entire signing button and we're going to do the very
button and we're going to do the very same thing but this one is going to say
same thing but this one is going to say get Jan three like
get Jan three like that and it's not going to have a
that and it's not going to have a variant
variant ghost like this and now if you click on
ghost like this and now if you click on this you should have as you can see a
this you should have as you can see a GitHub uh login model open perfect so we
GitHub uh login model open perfect so we have that working now and as you can see
have that working now and as you can see this is how it looks like on mobile
this is how it looks like on mobile perfect so what I want to do now is I
perfect so what I want to do now is I want to modify this loading a little bit
want to modify this loading a little bit so if you you refresh you can see how I
so if you you refresh you can see how I have a loading text here for a couple of
have a loading text here for a couple of seconds instead of having that loading I
seconds instead of having that loading I actually want to have a little spinner
actually want to have a little spinner here so let's go ahead inside of our
here so let's go ahead inside of our Global components folder and let's
Global components folder and let's create a new file spinner. DSX like this
create a new file spinner. DSX like this and I want to import
and I want to import loader from Lucid react and I want to
loader from Lucid react and I want to import
import CVA and type variant props from class
CVA and type variant props from class variance
variance Authority and I also want to import CN
Authority and I also want to import CN library from lib utils so the reason I'm
library from lib utils so the reason I'm importing the CVA from class variance
importing the CVA from class variance Authority is because I want to create uh
Authority is because I want to create uh some different variants for this spinner
some different variants for this spinner right I'm going to reuse this spinner A
right I'm going to reuse this spinner A lot of times in the project sometimes
lot of times in the project sometimes I'm going to want it to be a little bit
I'm going to want it to be a little bit bigger sometimes I'm going to want it to
bigger sometimes I'm going to want it to be a little bit smaller so the best way
be a little bit smaller so the best way to do that is using class variance
to do that is using class variance Authority so let's write const spinner
Authority so let's write const spinner variance
variance to be
to be CVA and let's first give it some default
CVA and let's first give it some default classes so that's going to be text muted
classes so that's going to be text muted foreground and animate Das spin so
foreground and animate Das spin so that's going to be the default classes
that's going to be the default classes of this spinner and then we're going to
of this spinner and then we're going to open an object and write
open an object and write Varian like
Varian like this and we're going to add size as a
this and we're going to add size as a variant default is going to be h-4 and
variant default is going to be h-4 and W-4 below that we're going to add a
W-4 below that we're going to add a small option for it so this one is going
small option for it so this one is going to be h-2
to be h-2 W-2 below that we're going to create a
W-2 below that we're going to create a large
large option which is going to be h-6 and
option which is going to be h-6 and w-6 and below that we're going to add an
w-6 and below that we're going to add an icon which is going to be h-10 and
icon which is going to be h-10 and w-10 now we're going to Define which one
w-10 now we're going to Define which one of these is default and well you can
of these is default and well you can already guess by name but we have to
already guess by name but we have to manually select that by adding default
manually select that by adding default variance size and it's going to choose
variance size and it's going to choose default so this is going to be the
default so this is going to be the default size of our spinner whenever we
default size of our spinner whenever we add it so we don't have to uh manually
add it so we don't have to uh manually add the spinner variant every single
add the spinner variant every single time and now let's create an interface
time and now let's create an interface spinner
spinner props to be
props to be extends variant props like this open
extends variant props like this open this pointy brackets and write type of
this pointy brackets and write type of let me just expand this it's going to be
let me just expand this it's going to be type of spinner variance constant which
type of spinner variance constant which we have defined right here above great
we have defined right here above great and you can just go ahead and open an
and you can just go ahead and open an empty object at the end and now go ahead
empty object at the end and now go ahead whoops where did I go and
whoops where did I go and now go ahead and Export const
now go ahead and Export const spinner which will take the size as a
spinner which will take the size as a prop from spinner
prop from spinner props like that and go ahead and return
props like that and go ahead and return a loader which we imported from Lucid
a loader which we imported from Lucid rea act and give it a class name to be
rea act and give it a class name to be CN spinner variance and pass in this
CN spinner variance and pass in this size object there we go so we have a
size object there we go so we have a nice little modular spinner component
nice little modular spinner component here save this file and now we're going
here save this file and now we're going to go back here where we currently have
to go back here where we currently have the loading and instead we're going to
the loading and instead we're going to render that spinner from add/ components
render that spinner from add/ components spinner like this so just make sure you
spinner like this so just make sure you imported the spinner I'm going to move
imported the spinner I'm going to move it with the others and now uh if you
it with the others and now uh if you take a look when I refresh here you can
take a look when I refresh here you can see how I have a nice little spinner
see how I have a nice little spinner here for a second instead of that uh
here for a second instead of that uh weird instead of that weird um loading
weird instead of that weird um loading text great so what I want to do now is I
text great so what I want to do now is I want to display a different state if we
want to display a different state if we are actually logged in right so let's go
are actually logged in right so let's go outside of this if Clause right here so
outside of this if Clause right here so at the bottom just above mod toggle and
at the bottom just above mod toggle and let's write if we are authenticated so
let's write if we are authenticated so this time without an exclamation mark if
this time without an exclamation mark if we are authenticated and if we are not
we are authenticated and if we are not loading in that case go ahead and open a
loading in that case go ahead and open a fragment again and let's just add a
fragment again and let's just add a button element inside let's give it a
button element inside let's give it a variant of ghost a size of SM and as
variant of ghost a size of SM and as child prop and pass in a link from next
child prop and pass in a link from next slash link so just make sure you
slash link so just make sure you imported next slash link like I did
imported next slash link like I did right here I'm just going to move it to
right here I'm just going to move it to the top and go ahead and give this an
the top and go ahead and give this an hre of Slash documents which is a site
hre of Slash documents which is a site we don't have yet but we're going to
we don't have yet but we're going to have in the future and just write enter
have in the future and just write enter Jan like that and outside of this button
Jan like that and outside of this button we're also going to have user
we're also going to have user button so we don't have this user button
button so we don't have this user button yet so let's go right here where we have
yet so let's go right here where we have the sign in button and let's add user
the sign in button and let's add user Button as well and one important thing
Button as well and one important thing is that in this user button you give it
is that in this user button you give it a prop after sign out URL to be a slash
a prop after sign out URL to be a slash and save this document and go ahead and
and save this document and go ahead and refresh this one more time and now let's
refresh this one more time and now let's try our login here so I'm going to
try our login here so I'm going to continue with GitHub like this all
continue with GitHub like this all right and there we go as you can see I'm
right and there we go as you can see I'm right here and I have my user button
right here and I have my user button from here and now it says enter Jan
from here and now it says enter Jan perfect so what I want to do now is I
perfect so what I want to do now is I want to modify this Hero action uh here
want to modify this Hero action uh here as well to also tell me different things
as well to also tell me different things depending on whether I'm logged in or
depending on whether I'm logged in or not so before we do that I just want to
not so before we do that I just want to show you that from here you can sign out
show you that from here you can sign out for example example you can log in back
for example example you can log in back again with GitHub right or you can also
again with GitHub right or you can also go ahead and manage your entire account
go ahead and manage your entire account change your picture log out add
change your picture log out add different accounts delete your entire
different accounts delete your entire account modify some security and stuff
account modify some security and stuff like that so for now what I want to do
like that so for now what I want to do is I want to go back inside of the
is I want to go back inside of the heading component so heading. CSX inside
heading component so heading. CSX inside of marketing folder undor components
of marketing folder undor components right here and let's go ahead and let's
right here and let's go ahead and let's add our hook use convex app out so we
add our hook use convex app out so we need to import that from convex react
need to import that from convex react import use convex out from convex SL
import use convex out from convex SL react all right and let's go ahead and
react all right and let's go ahead and let's extract is authenticated and is
let's extract is authenticated and is loading perfect and now let's go ahead
loading perfect and now let's go ahead and let's wrap this button inside of if
and let's wrap this button inside of if we are not authenticated sorry if we are
we are not authenticated sorry if we are authenticated so remove this exclamation
authenticated so remove this exclamation point F if we are not
point F if we are not loading only then do you render this
loading only then do you render this button to actually enter Jo right
button to actually enter Jo right otherwise we're going to go ahead and
otherwise we're going to go ahead and check for is
check for is loading and we're going to render the
loading and we're going to render the spinner from at/ components spinner
spinner from at/ components spinner which we created recently so make sure
which we created recently so make sure you have that imported and give it a
you have that imported and give it a size of large like this and now if you
size of large like this and now if you refresh you can see how for a second you
refresh you can see how for a second you have a little uh spinner here and let's
have a little uh spinner here and let's go ahead and wrap this inside of a
div and let's give it a class name of w- full Flex items D Center and justify Das
full Flex items D Center and justify Das Center and now if you try again there we
Center and now if you try again there we go now it's in the center perfect so
go now it's in the center perfect so exactly as we want and now what I want
exactly as we want and now what I want to do is do uh just modify this to
to do is do uh just modify this to actually lead you to uh the documents
actually lead you to uh the documents page because this is a case if we are
page because this is a case if we are authenticated so mark this button uh to
authenticated so mark this button uh to be as child and inside add a link
be as child and inside add a link component from next SL link so make sure
component from next SL link so make sure you imported
you imported that make sure you added link from next
that make sure you added link from next SL link as I did right
SL link as I did right here and give this an HRA of SL
here and give this an HRA of SL documents like this and nothing much
documents like this and nothing much should change here except now it should
should change here except now it should lead to slash documents which if you
lead to slash documents which if you click it's a 404 page it doesn't exist
click it's a 404 page it doesn't exist yet and now let's add if we are not
yet and now let's add if we are not authenticated and if we're not loading
authenticated and if we're not loading in that
in that case go ahead and render the sign in
case go ahead and render the sign in button which you can import from clerk
button which you can import from clerk uh clerk react so import sign in button
uh clerk react so import sign in button from add clerk clerk
from add clerk clerk react like that give it a mode of model
react like that give it a mode of model like this and just go ahead and add a
like this and just go ahead and add a little button inside get
little button inside get Jan three and also add an arrow right
Jan three and also add an arrow right which you already have imported in here
which you already have imported in here with a class name of h-4 W-4 and
with a class name of h-4 W-4 and ml-2 and there we go so if you try and
ml-2 and there we go so if you try and click on enter J we redirected to a 404
click on enter J we redirected to a 404 page but if you go ahead and log
page but if you go ahead and log out as you can see now this button as
out as you can see now this button as well opens a GitHub so exactly what we
well opens a GitHub so exactly what we wanted and if we log in from anywhere
wanted and if we log in from anywhere everything refreshes and as you can see
everything refreshes and as you can see now we have both redirects to currently
now we have both redirects to currently non-existing page great great
non-existing page great great job so now that we have our database and
job so now that we have our database and our authentication set up let's go ahead
our authentication set up let's go ahead and let's create this page which
and let's create this page which currently yields a 404 so let's just
currently yields a 404 so let's just recap what we have to have running for
recap what we have to have running for this application so let me remind you of
this application so let me remind you of my terminals so in one terminal I have
my terminals so in one terminal I have npx convex Dev running which is my back
npx convex Dev running which is my back end and in the other one I have mpm run
end and in the other one I have mpm run Dev running so make sure you have two of
Dev running so make sure you have two of those running refresh your page confirm
those running refresh your page confirm everything is working great so what we
everything is working great so what we have to do now is we have to create an
have to do now is we have to create an organizational folder which is going to
organizational folder which is going to help our documents page which is
help our documents page which is currently a 404 so let's go inside of
currently a 404 so let's go inside of the app folder and the same way we
the app folder and the same way we created this marketing route group let's
created this marketing route group let's go ahead and let's create a new route
go ahead and let's create a new route Group which we are going to call Main so
Group which we are going to call Main so main application is going to want to go
main application is going to want to go inside and let's go ahead and let's
inside and let's go ahead and let's create another folder inside called
create another folder inside called routes like that and then inside of it
routes like that and then inside of it create a new folder
create a new folder documents and inside our file page. TSX
documents and inside our file page. TSX and then you can go ahead and create
and then you can go ahead and create documents page with a div this is a
documents page with a div this is a protected page so only logged in users
protected page so only logged in users should see this page and once you save
should see this page and once you save that you should no longer get a 404
that you should no longer get a 404 error if you're still getting a 404
error if you're still getting a 404 error make sure that you are on SL
error make sure that you are on SL documents and make sure that all of your
documents and make sure that all of your links uh inside of this Landing screen
links uh inside of this Landing screen lead to SL documents so now let's try
lead to SL documents so now let's try and log out and let's see if we can
and log out and let's see if we can manually go to slash documents and it
manually go to slash documents and it looks like we still can so that's not
looks like we still can so that's not good if we are logged out I want to get
good if we are logged out I want to get redirected so if the user manually goes
redirected so if the user manually goes here I want to bring them back to the
here I want to bring them back to the landing page to log in so so in order to
landing page to log in so so in order to do that we can either use the middleware
do that we can either use the middleware or we can simply create a layout inside
or we can simply create a layout inside of this main folder and let's go ahead
of this main folder and let's go ahead and create a layout. vsx inside of the
and create a layout. vsx inside of the main organizational folder so layout.
main organizational folder so layout. vsx so it is inside of the main folder
vsx so it is inside of the main folder not inside of the routes so it's
not inside of the routes so it's separated like this and now let's go
separated like this and now let's go ahead and let's write sfc documents
ahead and let's write sfc documents sorry main
sorry main layout let's extract the children let's
layout let's extract the children let's give the children a type of react. react
give the children a type of react. react node and let's go ahead and let's return
node and let's go ahead and let's return a div which is just rendering the
a div which is just rendering the children so nothing should change much
children so nothing should change much for now but what I want to do now is add
for now but what I want to do now is add some hooks here so in order to do that
some hooks here so in order to do that we're going to have to map this entire
we're going to have to map this entire thing as use client and that is okay so
thing as use client and that is okay so usually I would avoid use clients
usually I would avoid use clients because I want to leverage server
because I want to leverage server components but this time we are working
components but this time we are working with a real-time database which shines
with a real-time database which shines in in client components it is not a
in in client components it is not a mistake or an anti- pattern to work with
mistake or an anti- pattern to work with client components inside next3 next 13
client components inside next3 next 13 just gives you an option to work with
just gives you an option to work with server components if that's what your
server components if that's what your application needs but since this is a
application needs but since this is a heavily real-time application it makes
heavily real-time application it makes sense that we use a lot of client
sense that we use a lot of client components great so now that we marked
components great so now that we marked our layout as use client let's go ahead
our layout as use client let's go ahead and let's extract is
authenticated authenticated and is loading from use convex out and we can
loading from use convex out and we can import use convex
out from convex SL react like that perfect and now let's check if we are
perfect and now let's check if we are loading we're going to return a div
loading we're going to return a div which is going to render our spinner
which is going to render our spinner component which we created in the
component which we created in the previous parts of the tutorial so make
previous parts of the tutorial so make sure you import that and let's give it a
sure you import that and let's give it a size of large and let's give it a class
size of large and let's give it a class name of h- full Flex items D Center and
name of h- full Flex items D Center and justify Das Center so it's centered in
justify Das Center so it's centered in the middle of the screen so if you try
the middle of the screen so if you try and click on documents now I'm actually
and click on documents now I'm actually going to go manually to SL documents you
going to go manually to SL documents you can see how for a second I have a
can see how for a second I have a loading indicator in the middle of my
loading indicator in the middle of my screen great and now we're going to
screen great and now we're going to check if we're not authenticated so if
check if we're not authenticated so if we are not
we are not authenticated so if not is authenticated
authenticated so if not is authenticated in that case we're going to return
in that case we're going to return a redirect from next SL navigation so
a redirect from next SL navigation so make sure you add this import redirect
make sure you add this import redirect from next SL navigation and we're going
from next SL navigation and we're going to lead the user back to our landing
to lead the user back to our landing page and there we go now that I Sav the
page and there we go now that I Sav the file I'm immediately redirected so if I
file I'm immediately redirected so if I go ahead and manually go to SL documents
go ahead and manually go to SL documents you can see how it doesn't let me go
you can see how it doesn't let me go there I'm immediately redirected back
there I'm immediately redirected back here and since we did this logic inside
here and since we did this logic inside of the layout file and not inside of a
of the layout file and not inside of a specific page that means that every
specific page that means that every single route that we create inside of
single route that we create inside of our main application is now officially
our main application is now officially out protected perfect so that's exactly
out protected perfect so that's exactly what we wanted to do here so now what I
what we wanted to do here so now what I want to do is I want to style this div a
want to do is I want to style this div a little bit so let's go ahead and give it
little bit so let's go ahead and give it a class name of h- full flex and let's
a class name of h- full flex and let's give it a special background if we are
give it a special background if we are on dark mode so if we are on dark mode
on dark mode so if we are on dark mode the background we're going to use is a
the background we're going to use is a specific hex color 1f 1 f one F like
specific hex color 1f 1 f one F like that and let's go ahead and let's wrap
that and let's go ahead and let's wrap these children inside of a main
element just like that and let's give this main element a class name of flex
this main element a class name of flex D1 h- full and overflow-y D aouto great
D1 h- full and overflow-y D aouto great and
and now let's go ahead and in here render
now let's go ahead and in here render navigation component and if you save
navigation component and if you save well you will not see an error unless
well you will not see an error unless you log in so let me just sign in with
you log in so let me just sign in with my GitHub now so I can go to that slash
my GitHub now so I can go to that slash documents page and and there we go now I
documents page and and there we go now I have an error here great so let's go
have an error here great so let's go ahead now and inside uh of this main
ahead now and inside uh of this main folder go ahead and create another
folder go ahead and create another folder underscore components and inside
folder underscore components and inside of it create a new file navigation. vsx
of it create a new file navigation. vsx let's go ahead and Mark this as use
let's go ahead and Mark this as use client and let's export con navigation
client and let's export con navigation just like that and return a div saying
just like that and return a div saying navigation and save the file now go back
navigation and save the file now go back to your main layout and import that
to your main layout and import that navigation from slore components SL
navigation from slore components SL navigation and I'm just going to
navigation and I'm just going to separate this Imports and there we go we
separate this Imports and there we go we no longer have any errors and you can
no longer have any errors and you can see how navigation is at this side of
see how navigation is at this side of the page and now what we're going to do
the page and now what we're going to do is we're going to slowly create this
is we're going to slowly create this navigation page so let's go inside uh
navigation page so let's go inside uh and let's prepare everything we need so
and let's prepare everything we need so first thing I want to do is I want to
first thing I want to do is I want to wrap this entire thing in a fragment of
wrap this entire thing in a fragment of of its own like this and I want to
of its own like this and I want to change this to not be a div instead
change this to not be a div instead we're going to use an aside element
we're going to use an aside element great and now what I want to do is give
great and now what I want to do is give this a class name so class name is going
this a class name so class name is going to be
to be group group
group group slidebar h- full vg-
slidebar h- full vg- secondary like this overflow-y Das AO
secondary like this overflow-y Das AO relative Flex W D60 like that is uh and
relative Flex W D60 like that is uh and uh sorry w- 60 uh
uh sorry w- 60 uh flex-all and Z index is going to be
flex-all and Z index is going to be 99999 so five9 like this because we're
99999 so five9 like this because we're going to have uh notion style block
going to have uh notion style block editor which takes a lot of Z index
editor which takes a lot of Z index space so we are going to move it this to
space so we are going to move it this to the top great so as you can see now we
the top great so as you can see now we have uh a template for our sidebar right
have uh a template for our sidebar right here you can see how it takes this
here you can see how it takes this entire space and everything else is
entire space and everything else is moved to this side
moved to this side perfect now let's go ahead and let's
perfect now let's go ahead and let's fill this side element with some
fill this side element with some placeholder items so what I want to do
placeholder items so what I want to do now is I want to create a div here and I
now is I want to create a div here and I just want to add a paragraph inside
just want to add a paragraph inside action items like this so we're going to
action items like this so we're going to have action items then go ahead below
have action items then go ahead below that and create another div and give it
that and create another div and give it a class name of margin top 4 and inside
a class name of margin top 4 and inside we're going to create a paragraph and
we're going to create a paragraph and we're just going to write
we're just going to write documents like this so first we're going
documents like this so first we're going to have some action items then we're
to have some action items then we're going to have some documents and then go
going to have some documents and then go ahead and create another
ahead and create another div right here and this one it's going
div right here and this one it's going to be a bit different in fact it's going
to be a bit different in fact it's going to be a self closing div like that and
to be a self closing div like that and give it a class name of opacity Das Z
give it a class name of opacity Das Z like this and then what we're going to
like this and then what we're going to do is we're going to leverage this group
do is we're going to leverage this group SL sidebar so in Tailwind there is a
SL sidebar so in Tailwind there is a class name called group usually you
class name called group usually you write it just like this so group right
write it just like this so group right and then what you can do is you can do
and then what you can do is you can do group- hover opacity D100 that means
group- hover opacity D100 that means that this element is going to be hidden
that this element is going to be hidden in our case it's going to have opacity
in our case it's going to have opacity of zero but when we hover on the entire
of zero but when we hover on the entire as side element it's going to change to
as side element it's going to change to 100 so why did I write group / sidebar
100 so why did I write group / sidebar here well I wrote that because that's a
here well I wrote that because that's a way you can differentiate between
way you can differentiate between different groups so inside of this
different groups so inside of this sidebar component we're going to have
sidebar component we're going to have different groups which we're going to
different groups which we're going to use that trick on but we can do group SL
use that trick on but we can do group SL sidebar so we tell it okay this is only
sidebar so we tell it okay this is only supposed to be active on group SL
supposed to be active on group SL sidebar and if you change group SL
sidebar and if you change group SL sidebar here you also have to change it
sidebar here you also have to change it here but it's not going to be group
here but it's not going to be group slidebar like this instead it's going to
slidebar like this instead it's going to be group- hover
be group- hover slidebar like this and you can see when
slidebar like this and you can see when I hover over this class it's a
I hover over this class it's a completely valid class it's working
completely valid class it's working great so now now that we have that let's
great so now now that we have that let's continue adding some classes to this
continue adding some classes to this element so we're also going to give it a
element so we're also going to give it a transition class we're going to give it
transition class we're going to give it a
a cursor Das ew- resize an absolute h-
cursor Das ew- resize an absolute h- full
full w-1 vg- primary sl10 so we're going to
w-1 vg- primary sl10 so we're going to give it some opacity wr-0 and top- z and
give it some opacity wr-0 and top- z and now if you take a look when I hover over
now if you take a look when I hover over my sidebar I have a little bar here
my sidebar I have a little bar here which is going to be used you guessed it
which is going to be used you guessed it to expand our sidebar as needed so let
to expand our sidebar as needed so let me try and zoom in so you can see you
me try and zoom in so you can see you can see when I hover anywhere on the
can see when I hover anywhere on the sidebar I have this opened to me so it
sidebar I have this opened to me so it indicates to the user okay there's
indicates to the user okay there's something I can do with this and that's
something I can do with this and that's exactly uh what we
exactly uh what we want now I want to go back inside of
want now I want to go back inside of this as side action right here above
this as side action right here above this div where we wrote the action items
this div where we wrote the action items and let's go ahead and add a new div
and let's go ahead and add a new div here which is going to render
chevron's left icon from Lucid react it's a self-closing tag just make sure
it's a self-closing tag just make sure you import Chevron left from Lucid react
you import Chevron left from Lucid react and let's go ahead and let's give this a
and let's go ahead and let's give this a class
class name of h-6 and
name of h-6 and w-6 and let's give this
w-6 and let's give this div a roll of button and let's give it a
div a roll of button and let's give it a class last name of
class last name of h-6 w-6 text- muted D
h-6 w-6 text- muted D foreground like
foreground like that rounded Das small hover vg- neutral
that rounded Das small hover vg- neutral D300 on dark mode hover is going to be
D300 on dark mode hover is going to be vg- neutral
vg- neutral D600 absolute
D600 absolute top-3 right -2 to opacity Das 0 and
top-3 right -2 to opacity Das 0 and we're also going to modify it when we
we're also going to modify it when we hover so on group Das hover slidebar
hover so on group Das hover slidebar we're going to change the opacity to 100
we're going to change the opacity to 100 and we're going to add a transition
and we're going to add a transition class great so you can see that now when
class great so you can see that now when I hover we have a nice little icon here
I hover we have a nice little icon here but only when we hover so it's not
but only when we hover so it's not visible it's not visible right now but
visible it's not visible right now but when I hover you can see that I have
when I hover you can see that I have this little icon which you guessed it is
this little icon which you guessed it is going to be used to collapse the Entre
going to be used to collapse the Entre sidebar as we need it perfect so now
sidebar as we need it perfect so now that we have this I think we ready to
that we have this I think we ready to create uh some refs here so let's go
create uh some refs here so let's go ahead and let's go here and let's write
ahead and let's go here and let's write const is
const is resizing ref we use
resizing ref we use ref and give it a false value then const
ref and give it a false value then const sidebar
sidebar ref is going to be use ref and it's
ref is going to be use ref and it's going to have a type of
going to have a type of element ref from react so make sure you
element ref from react so make sure you import that open another pair of pointy
import that open another pair of pointy brackets and go ahead and write an
brackets and go ahead and write an element called a side and let's give it
element called a side and let's give it a default value of
a default value of now B below that we're going to have a
now B below that we're going to have a con Novar ref which is going to be use
con Novar ref which is going to be use ref again it's going to be an element
ref again it's going to be an element ref with a type of div inside and a
ref with a type of div inside and a default value of
default value of null great and now let's also just add
null great and now let's also just add const is resetting set is resetting to
const is resetting set is resetting to be use state from react and give it a
be use state from react and give it a false default value and const is
false default value and const is collapsed set is
collapsed set is collapsed to be use State false as well
collapsed to be use State false as well great so now that we have that I want to
great so now that we have that I want to go ahead and install a package called
go ahead and install a package called use hooks so let's go inside of our
use hooks so let's go inside of our terminal I'm just going to open a new
terminal I'm just going to open a new terminal and I'm going to write mpm
terminal and I'm going to write mpm install use hooks DTS so a very cool
install use hooks DTS so a very cool package uh if you want to you can also
package uh if you want to you can also search for a specific hook which we're
search for a specific hook which we're going to use outside of this package and
going to use outside of this package and just create that hook but for a tutorial
just create that hook but for a tutorial is just simple for me to install the
is just simple for me to install the entire package so import use media query
entire package so import use media query from use hooks
from use hooks DTS and so the reason I'm not using
DTS and so the reason I'm not using Tailwind break points for this is
Tailwind break points for this is because it's quite complex to do that
because it's quite complex to do that especially with the fact that our
especially with the fact that our sidebar is going to be resizable on drag
sidebar is going to be resizable on drag as you saw in the demo right so it's
as you saw in the demo right so it's quite hard to do that using just
quite hard to do that using just Tailwind so we're going to have to use
Tailwind so we're going to have to use some tricks with refs and other stuff
some tricks with refs and other stuff and we're going to need to use media
and we're going to need to use media query to manually Define in JavaScript
query to manually Define in JavaScript what's considered mobile and what's
what's considered mobile and what's considered desktop using breakpoints so
considered desktop using breakpoints so I'm going to go above all of this and
I'm going to go above all of this and I'm going to write const is mobile to be
I'm going to write const is mobile to be use media query and I'm going to go
use media query and I'm going to go ahead and open a string and write Max
ahead and open a string and write Max Das width is going to be 7 68 pixels so
Das width is going to be 7 68 pixels so this is the same breako for medium
this is the same breako for medium inside of tailwind and then we can
inside of tailwind and then we can change this is collapsed use State
change this is collapsed use State default value to be is mobile so if we
default value to be is mobile so if we are on mobile our sidebar is going to be
are on mobile our sidebar is going to be automatically collapsed but if we are on
automatically collapsed but if we are on desktop we're going to have an option to
desktop we're going to have an option to collapse it once we click on this item
collapse it once we click on this item right here and while we are here let's
right here and while we are here let's also go ahead and let's add uh params
also go ahead and let's add uh params here so const sorry path name it's going
here so const sorry path name it's going to be used path name from next l
to be used path name from next l navigation because if we are on mobile I
navigation because if we are on mobile I also want to manually collapse the
also want to manually collapse the sidebar every time we click on a
sidebar every time we click on a different uh item right I don't want our
different uh item right I don't want our sidebar to stay open because it's going
sidebar to stay open because it's going to take the full screen so I want when
to take the full screen so I want when user clicks on a specific document to
user clicks on a specific document to collapse the entire sidebar and that's
collapse the entire sidebar and that's why we're going to use this Pat name
why we're going to use this Pat name inside of a use effect so we know when
inside of a use effect so we know when that happens so now that we have that
that happens so now that we have that we're ready to start writing some
we're ready to start writing some functions here so let's go ahead and
functions here so let's go ahead and let's first
let's first um well let's define uh some functions
um well let's define uh some functions actually but before we actually can
actually but before we actually can Define any functions we have to assign
Define any functions we have to assign these refs which we just created I
these refs which we just created I completely forgot about them my
completely forgot about them my apologies so let's go inside the asside
apologies so let's go inside the asside element right here and let's give it a
element right here and let's give it a ref of sidebar ref like that great and
ref of sidebar ref like that great and now that we have this as well let's
now that we have this as well let's change this into curly brackets like
change this into curly brackets like this and let's add a CN library from at/
this and let's add a CN library from at/ lib util so just make sure you import CN
lib util so just make sure you import CN from lib utils I'm just going to
from lib utils I'm just going to separate this import and once you have
separate this import and once you have that CN right here go ahead and wrap
that CN right here go ahead and wrap this entire class name inside of
this entire class name inside of parenthesis like that and you can press
parenthesis like that and you can press enter like whoops and you can just press
enter like whoops and you can just press enter like this so it's in the first
enter like this so it's in the first line and then in the second line so add
line and then in the second line so add a comma after this entire string ends
a comma after this entire string ends and let's add some conditional classes
and let's add some conditional classes here so if is
here so if is setting
setting resetting which we defined as a a
resetting which we defined as a a constant here in that case we're going
constant here in that case we're going to add a transition to it so transition
to add a transition to it so transition Das all e- in- out duration
Das all e- in- out duration D300 and let's also add if is Mobile in
D300 and let's also add if is Mobile in that case width is zero by default and
that case width is zero by default and don't forget to add a comma here and as
don't forget to add a comma here and as you can see now I don't I no longer have
you can see now I don't I no longer have uh my sidebar here I refresh that's
uh my sidebar here I refresh that's because the is uh is mobile right here
because the is uh is mobile right here is true and we wrote a class name here
is true and we wrote a class name here if we are on mobile the default width of
if we are on mobile the default width of the sidebar is zero but only you can see
the sidebar is zero but only you can see even when I expand only then it's
even when I expand only then it's visible right perfect so what I
visible right perfect so what I recommend you do is just zoom out so you
recommend you do is just zoom out so you can actually see the sidebar that you're
can actually see the sidebar that you're working with great so we just assigned
working with great so we just assigned the sidebar ref here now let's go ahead
the sidebar ref here now let's go ahead to this button here and let's go ahead
to this button here and let's go ahead and do the same thing with the classes
and do the same thing with the classes so I'm going to go ahead and open this
so I'm going to go ahead and open this wrap this in curly brackets at the CN
wrap this in curly brackets at the CN Library wrap the entire thing inside of
Library wrap the entire thing inside of CN like this and let's go ahead and add
CN like this and let's go ahead and add conditional one if is Mobile in that
conditional one if is Mobile in that case opacity is going to be 100 by
case opacity is going to be 100 by default right so if we are on mobile
default right so if we are on mobile we're not going to do this trick that
we're not going to do this trick that only when we hover on something does a
only when we hover on something does a button appear That's okay for desktop
button appear That's okay for desktop but on mobile we want it to always be
but on mobile we want it to always be visible so user know knows that they can
visible so user know knows that they can collapse the sidebar because there is no
collapse the sidebar because there is no well there probably is some kind of
well there probably is some kind of hover on mobile but it's not the same
hover on mobile but it's not the same user experience as on desktop so if it's
user experience as on desktop so if it's mobile we're not going to do this whole
mobile we're not going to do this whole on Hover change the opacity it's just
on Hover change the opacity it's just going to be visible all the time great
going to be visible all the time great and now that we have this let's go ahead
and now that we have this let's go ahead uh all the way to the bottom here
uh all the way to the bottom here outside of this aide element and let's
outside of this aide element and let's go ahead and let's create a div here
go ahead and let's create a div here where we're going to have a ref of
where we're going to have a ref of navbar ref and we're going to have a
navbar ref and we're going to have a class name to be
class name to be CN default classes are going to be
CN default classes are going to be absolute top- z z index of 1 2 3 4 5 so
absolute top- z z index of 1 2 3 4 5 so five nines like this left is going to be
five nines like this left is going to be 60 and width is going to be a
60 and width is going to be a calculation of 100% meus 240 pixels
calculation of 100% meus 240 pixels because that's the value of this left 60
because that's the value of this left 60 right here so 240 pixels great and then
right here so 240 pixels great and then we're going to add some conditional
we're going to add some conditional classes so if is
classes so if is resetting in that case we're going to
resetting in that case we're going to add a little transition here so
add a little transition here so transition D all is- in- out and
transition D all is- in- out and duration
duration -300 and we're also and just make sure
-300 and we're also and just make sure you don't misspell resetting and we're
you don't misspell resetting and we're also going to have another condition if
also going to have another condition if is Mobile in that case left is going to
is Mobile in that case left is going to be zero and W is going to be full so
be zero and W is going to be full so what we did here is is our uh position
what we did here is is our uh position for the Novar which is going to be right
for the Novar which is going to be right here where it currently says this is a
here where it currently says this is a protected in documents page so this knv
protected in documents page so this knv bar is going to have to follow the width
bar is going to have to follow the width and the collaps m and everything that
and the collaps m and everything that the sidebar does it's going to have to
the sidebar does it's going to have to be in sync with the nov bar so that's
be in sync with the nov bar so that's why we need this a bit of a complex
why we need this a bit of a complex logic here to watch for all of those
logic here to watch for all of those actions to happen great so now that we
actions to happen great so now that we have that uh let's go ahead inside and
have that uh let's go ahead inside and let's add uh a little nav element
let's add uh a little nav element here like this and let's just write if
here like this and let's just write if is
is collapsed in that case add a menu icon
collapsed in that case add a menu icon from Lucid react so make sure you import
from Lucid react so make sure you import menu icon from Lucid react and go ahead
menu icon from Lucid react and go ahead and give it a class name of
and give it a class name of h-6 w-6 and text- muted D
h-6 w-6 and text- muted D foreground let's also give it a roll off
foreground let's also give it a roll off button like this and you can see that
button like this and you can see that now when I zoom in I should have there
now when I zoom in I should have there we go so you can see it's it's
we go so you can see it's it's overlapping the text currently so it
overlapping the text currently so it doesn't make much sense but as you can
doesn't make much sense but as you can see right here there is a little icon
see right here there is a little icon here you can see how it's over my text
here you can see how it's over my text now let's go ahead to this no element
now let's go ahead to this no element and let's give it a class name of B-
and let's give it a class name of B- transparent
transparent bx-3 like this py D2 and
bx-3 like this py D2 and w- full like that great so that's enough
w- full like that great so that's enough for us uh for now and now what I want to
for us uh for now and now what I want to do is I can finally go ahead and create
do is I can finally go ahead and create some actions so let's go ahead and let's
some actions so let's go ahead and let's find uh this div right here so this is
find uh this div right here so this is the div which appears when we hover on
the div which appears when we hover on our uh sidebar this little uh bold line
our uh sidebar this little uh bold line right here that is this div so let's go
right here that is this div so let's go ahead uh and let's modify it a little
ahead uh and let's modify it a little bit by giving it an on on Mouse down
bit by giving it an on on Mouse down option let's just put that as an empty
option let's just put that as an empty function and on click option which is
function and on click option which is also going to be an empty function so
also going to be an empty function so first res resolve this uh on Mouse down
first res resolve this uh on Mouse down option right here so let's go ahead and
option right here so let's go ahead and let's create that function here const
let's create that function here const handle Mouse down is going to accept an
handle Mouse down is going to accept an event which is a type of react.
event which is a type of react. mouseevent HTML div element
mouseevent HTML div element and mouse event like that and it's an
and mouse event like that and it's an arrow function and the first thing we're
arrow function and the first thing we're going to do is we're going to prevent
going to do is we're going to prevent default and then we're going to stop
default and then we're going to stop propagation from this event and then
propagation from this event and then we're going to set is resizing ref.
we're going to set is resizing ref. current to be
current to be true and we're going to add an event
true and we're going to add an event listener so document.
listener so document. add event listener
whoops listener all right and event listener is going to be Mouse move and
listener is going to be Mouse move and it's going to uh it's going to trigger
it's going to uh it's going to trigger handle Mouse move like this and go ahead
handle Mouse move like this and go ahead and copy the ad event listener and let's
and copy the ad event listener and let's just not misspell this so add
just not misspell this so add event listener okay I made a typo here
event listener okay I made a typo here so ad event listener like this and this
so ad event listener like this and this one is going to be not Mouse move but
one is going to be not Mouse move but Mouse up and the function it's going to
Mouse up and the function it's going to call is handle Mouse up like this so now
call is handle Mouse up like this so now obviously we're going to get some errors
obviously we're going to get some errors because none of this exists right now
because none of this exists right now but let's just go ahead and assign this
but let's just go ahead and assign this handle Mouse down to this on Mouse down
handle Mouse down to this on Mouse down uh empty Arrow function which we created
uh empty Arrow function which we created right now and let me just see if I
right now and let me just see if I refresh if I immediately get an error I
refresh if I immediately get an error I don't but I think that when I try and
don't but I think that when I try and move this uh looks like I'm not getting
move this uh looks like I'm not getting any errors but I think I am getting them
any errors but I think I am getting them in the console nevertheless let's go
in the console nevertheless let's go ahead and let's create this handle Mouse
ahead and let's create this handle Mouse move and handle Mouse up so handle Mouse
move and handle Mouse up so handle Mouse move is going to be used to prise our uh
move is going to be used to prise our uh sidebar but when we leave the mouse when
sidebar but when we leave the mouse when we put a finger above our cursor that
we put a finger above our cursor that means we are done with resizing and we
means we are done with resizing and we can stop resizing right so first let's
can stop resizing right so first let's do the handle Mouse move so let's go
do the handle Mouse move so let's go below that and write con handle Mouse
below that and write con handle Mouse move is going to accept an event to be a
move is going to accept an event to be a mouse
mouse event like that and first thing you're
event like that and first thing you're going to check if we have uh there is
going to check if we have uh there is resizing ref uh inactive so if there is
resizing ref uh inactive so if there is no is in
no is in ref do current in that case we can just
ref do current in that case we can just break the entire function no need to go
break the entire function no need to go further and then let's assign the new
further and then let's assign the new width to the client x value of this
width to the client x value of this event so let new width is going to be
event so let new width is going to be event. client X like that actually it's
event. client X like that actually it's not let's just rename this to event like
not let's just rename this to event like that there we go and now let's add some
that there we go and now let's add some limits to how how much the user can
limits to how how much the user can resize the the uh the sidebar to and how
resize the the uh the sidebar to and how much they can collapse the sidebar so if
much they can collapse the sidebar so if new width is less than 240 in that case
new width is less than 240 in that case new width is going to be 240 so we canot
new width is going to be 240 so we canot go lower than that and then in the same
go lower than that and then in the same way we're going to limit how wide it can
way we're going to limit how wide it can go if new width is larger than
go if new width is larger than 480 then new width is simply going to be
480 then new width is simply going to be 480 we're not going to let them go above
480 we're not going to let them go above that value and now that we have that
that value and now that we have that let's check if we have both the sidebar
let's check if we have both the sidebar ref and the navbar ref so if we have
ref and the navbar ref so if we have sidebar ref.
sidebar ref. current and if we have navbar ref.
current and if we have navbar ref. current because we need to animate both
current because we need to animate both of them now in that case let's give the
of them now in that case let's give the sidebar ref. current. style. width open
sidebar ref. current. style. width open back TI add an object inside new width
back TI add an object inside new width with pixels like this and then let's
with pixels like this and then let's also add the navbar ref. current. style
also add the navbar ref. current. style do set
do set property like that we're going to set
property like that we're going to set the property left to be
the property left to be moved let's just open backs again to new
moved let's just open backs again to new with
with PX like that so let me just expand this
PX like that so let me just expand this a little bit there we go okay uh one
a little bit there we go okay uh one more time there we go so we uh moved the
more time there we go so we uh moved the naar left property but by the same
naar left property but by the same amount and now we also have to move its
amount and now we also have to move its width so nabar ref. current.
width so nabar ref. current. style do set
style do set property with is going to be open btic
property with is going to be open btic again
again calculate Open brackets 100% minus open
calculate Open brackets 100% minus open the special object new width and add
the special object new width and add pixels inside of these brackets right
pixels inside of these brackets right here so let me try if I can expand even
here so let me try if I can expand even more so you can see this in one line so
more so you can see this in one line so this is how it's supposed to look like
this is how it's supposed to look like navbar ref. current style set property
navbar ref. current style set property width open back tick and calculate 100%
width open back tick and calculate 100% minus the new width to which we just
minus the new width to which we just expanded pixels and then end the bracket
expanded pixels and then end the bracket and end the backtick Great so now that
and end the backtick Great so now that we have all of those we are ready to
we have all of those we are ready to create this handle Mouse up function you
create this handle Mouse up function you can see we no longer have an error for
can see we no longer have an error for this one but we have the handle Mouse up
this one but we have the handle Mouse up error so let's go below this and let's
error so let's go below this and let's create a constant handle Mouse up which
create a constant handle Mouse up which all is going to do it's not even going
all is going to do it's not even going to have to take any events all it's
to have to take any events all it's going to do is set the is resizing graph
going to do is set the is resizing graph do current to be
do current to be false and document. remove event
false and document. remove event listener Mouse move from handle Mouse
listener Mouse move from handle Mouse move and document. remove event listener
move and document. remove event listener Mouse
Mouse up from handle Mouse
up from handle Mouse up like that then if we did everything
up like that then if we did everything correctly I think let's just confirm so
correctly I think let's just confirm so there are no errors perfect if we did
there are no errors perfect if we did this correctly I think we should be able
this correctly I think we should be able to move our sidebar now so let me try
to move our sidebar now so let me try and expand this now and there we go you
and expand this now and there we go you can see how I have a limit to how much I
can see how I have a limit to how much I can expand and collapse my sidebar and I
can expand and collapse my sidebar and I can leave it like this and you can see
can leave it like this and you can see how it's no longer following my mouse
how it's no longer following my mouse but if I hold on this it's following my
but if I hold on this it's following my mouse to a specific break point which
mouse to a specific break point which we've given it and because of all the
we've given it and because of all the flex properties we've given inside of
flex properties we've given inside of our layout you can see how the entire
our layout you can see how the entire content is moving with it as well and
content is moving with it as well and you can see it right now but in the
you can see it right now but in the future we're also going to have a enough
future we're also going to have a enough bar here which is just as well going to
bar here which is just as well going to follow the transition of this sidebar
follow the transition of this sidebar perfect so now what we have to do is we
perfect so now what we have to do is we have to create this functionality that
have to create this functionality that collapses the entire navigation bar and
collapses the entire navigation bar and we also have to create uh this that when
we also have to create uh this that when you click here it actually opens the
you click here it actually opens the sidebar great so first thing I want to
sidebar great so first thing I want to do is this button right
do is this button right here so let's create the functions to
here so let's create the functions to handle that so I'm just going to expand
handle that so I'm just going to expand my entire screen here because we're
my entire screen here because we're going to focus on the code now and let's
going to focus on the code now and let's go below this handle Mouse up and let's
go below this handle Mouse up and let's create a constant which is going to be
create a constant which is going to be reset width so reset width is going to
reset width so reset width is going to reset the sidebar width to its original
reset the sidebar width to its original width so it's not going to collapse it
width so it's not going to collapse it it's going to be used if we expand too
it's going to be used if we expand too much and the user wishes to go back to
much and the user wishes to go back to the original position without dragging
the original position without dragging they can just click on that line they
they can just click on that line they use to drag and then it's going to be
use to drag and then it's going to be reset to 240 pixels so let's go ahead
reset to 240 pixels so let's go ahead and first let's check if we have the
and first let's check if we have the sidebar ref. current and if we have the
sidebar ref. current and if we have the navbar ref. current if we have both of
navbar ref. current if we have both of those we can continue so set is
those we can continue so set is collapsed is now going to be false set
collapsed is now going to be false set is resetting is going to be false as
is resetting is going to be false as well my apologies is going to be true
well my apologies is going to be true because we want to animate uh the uh the
because we want to animate uh the uh the uh the resetting of the width you're
uh the resetting of the width you're going to see that in a second and now
going to see that in a second and now let's write sidebar
let's write sidebar ref do current. style.
ref do current. style. width and first let's check if is
width and first let's check if is mobile we're going to reset it to a
mobile we're going to reset it to a 100% otherwise to 240 pixels because on
100% otherwise to 240 pixels because on mobile remember we take the entire
mobile remember we take the entire screen with a sidebar and now let's
screen with a sidebar and now let's write navbar ref. current. style. set
write navbar ref. current. style. set property so with Navar we work with the
property so with Navar we work with the property width and with property left so
property width and with property left so first let's assign the width property
first let's assign the width property and let me just do this in two line so
and let me just do this in two line so you don't have to do it in two lines I
you don't have to do it in two lines I just want you to be able to read what
just want you to be able to read what I'm writing so the property is going to
I'm writing so the property is going to check if is Mobile in that case it's
check if is Mobile in that case it's going to be zero otherwise it's going to
going to be zero otherwise it's going to be a
be a calculation of 100% minus 240 pixels
calculation of 100% minus 240 pixels like this and below that let's do the
like this and below that let's do the same same thing but for the left
same same thing but for the left property so nav ref. current. style do
property so nav ref. current. style do set
set property the property we're going to
property the property we're going to modify is left and the value is also
modify is left and the value is also going to be dependent on the is mobile
going to be dependent on the is mobile uh Boolean so if it's mobile 100%
uh Boolean so if it's mobile 100% otherwise 240 pixels great so now we
otherwise 240 pixels great so now we have that and now let's just write a set
have that and now let's just write a set time out here which is going to set is
time out here which is going to set is resetting to f so you might be confused
resetting to f so you might be confused by this action why are we doing this why
by this action why are we doing this why this 300 milliseconds here what is this
this 300 milliseconds here what is this set setting even used for well if you
set setting even used for well if you take a look at our code when the isra
take a look at our code when the isra setting is active we add a little
setting is active we add a little transition to it with a duration of 300
transition to it with a duration of 300 so that's why we use the timeout to be
so that's why we use the timeout to be 300 as well we use it here on the
300 as well we use it here on the sidebar itself which is the aside
sidebar itself which is the aside element and we also use it for the Novar
element and we also use it for the Novar duration 300 and transition when we are
duration 300 and transition when we are resetting so we are using that because
resetting so we are using that because this is not going to be a drag and hold
this is not going to be a drag and hold like when we are expanding this is going
like when we are expanding this is going to be when we click just reset the
to be when we click just reset the entire thing so we want to show just a
entire thing so we want to show just a little nice animation for it and we have
little nice animation for it and we have to use this timeout trick for it great
to use this timeout trick for it great uh and if you're wondering well why not
uh and if you're wondering well why not just um where is it why not just use
just um where is it why not just use this in the main classes why do we even
this in the main classes why do we even need it in a Boolean well that's because
need it in a Boolean well that's because if you add transition all uh and if you
if you add transition all uh and if you add this class to the main classes here
add this class to the main classes here it's also going to be visible when you
it's also going to be visible when you drag and resize and it just looks very
drag and resize and it just looks very off it looks weird and there's no way to
off it looks weird and there's no way to limit it to a specific action in
limit it to a specific action in Tailwind besides using uh a combination
Tailwind besides using uh a combination of JavaScript with it as well uh great
of JavaScript with it as well uh great so now that we have uh the reset width
so now that we have uh the reset width option let's go ahead and let's assign
option let's go ahead and let's assign it to this div there we go we have this
it to this div there we go we have this on click which is an empty Arrow
on click which is an empty Arrow function and let's now give it the reset
function and let's now give it the reset width option like this and now let me
width option like this and now let me expand my screen and let me just
expand my screen and let me just refresh and now we can see when I expand
refresh and now we can see when I expand this and then when I click on this oh
this and then when I click on this oh looks like it's not is it working or not
looks like it's not is it working or not let's just see there we goes It's
let's just see there we goes It's Working uh as you can see when you
Working uh as you can see when you expand just go ahead and click on this
expand just go ahead and click on this element and as you can see how it nicely
element and as you can see how it nicely creates a little animation here to
creates a little animation here to collapse back to its original position
collapse back to its original position and it also moves the entire content
and it also moves the entire content with it as well in a nice anim way
with it as well in a nice anim way perfect so that's what we wanted to
perfect so that's what we wanted to achieve with that uh reset width
achieve with that uh reset width function but now we have to create the
function but now we have to create the collapse function which is going to be
collapse function which is going to be similar to this reset width function so
similar to this reset width function so let's go ahead and let's write const
let's go ahead and let's write const collapse let's check if we have the
collapse let's check if we have the sidebar ref.
sidebar ref. current and if we have nbar ref.
current and if we have nbar ref. current and let's set is collapsed to
current and let's set is collapsed to true and set is resetting to true as
true and set is resetting to true as well and then let's do sidebar ref.
well and then let's do sidebar ref. current. style. width is simply going to
current. style. width is simply going to be
be zero like
zero like that and
that and Navar do current. set
Navar do current. set property sorry do style. set
property sorry do style. set property the property withth is simply
property the property withth is simply going to be
going to be 100% And nvar f. current. style. set
100% And nvar f. current. style. set property left is simply going to be
property left is simply going to be zero and set timeout at the end where we
zero and set timeout at the end where we just change the set is resetting to
just change the set is resetting to false after a 300 millisecond delay and
false after a 300 millisecond delay and now we're going to assign this collapse
now we're going to assign this collapse function uh to the onclick of this
function uh to the onclick of this button right here where is it there we
button right here where is it there we go this roll button right here which
go this roll button right here which we've given let's give it an on click
we've given let's give it an on click off uh
off uh collapse like this so it's this div just
collapse like this so it's this div just inside of the aside which holds the
inside of the aside which holds the chevron's left icon and now let's try
chevron's left icon and now let's try that out so I'm going to refresh again
that out so I'm going to refresh again I'm going to zoom out just a bit and you
I'm going to zoom out just a bit and you can see when I click here you can see
can see when I click here you can see how it entirely collapses and when we
how it entirely collapses and when we click on this one well I think we can
click on this one well I think we can already reuse the reset width on that
already reuse the reset width on that one and that's going to work let me just
one and that's going to work let me just confirm uh if that is the case uh so
confirm uh if that is the case uh so let's go ahead now yes we can just do
let's go ahead now yes we can just do that so let's go all the way to the
that so let's go all the way to the bottom and find this menu icon where we
bottom and find this menu icon where we have the roll button and let's give it
have the roll button and let's give it an on click of reset withd like this and
an on click of reset withd like this and let's try this out now so I'm going to
let's try this out now so I'm going to refresh this I'm going to try and
refresh this I'm going to try and collapse this I'm going to go ahead and
collapse this I'm going to go ahead and click this and there we go you can see
click this and there we go you can see how I can now entirely collapse my
how I can now entirely collapse my sidebar and I can expand it perfect so
sidebar and I can expand it perfect so now what I want to do is I want to write
now what I want to do is I want to write some use effects which are going to
some use effects which are going to detect whether we are on mobile or not
detect whether we are on mobile or not as you can see now I switched to mobile
as you can see now I switched to mobile mode but I can still very much Vis it uh
mode but I can still very much Vis it uh and you can see how yeah on mobile when
and you can see how yeah on mobile when I expand it takes up the whole screen
I expand it takes up the whole screen but still uh what I want to do now is
but still uh what I want to do now is you can see when I expand to desktop it
you can see when I expand to desktop it doesn't really work well right when I
doesn't really work well right when I when I have a sidebar now and if I
when I have a sidebar now and if I switch to mobile mode I expect this
switch to mobile mode I expect this sidebar to disappear right to be hidden
sidebar to disappear right to be hidden well we can do that using use effects
well we can do that using use effects because we have all the necessary
because we have all the necessary functions here so let's go to the top of
functions here so let's go to the top of everything here and let's write
everything here and let's write use effect from
react so just make sure you imported use effect from react where we have the ref
effect from react where we have the ref and the state and for the first one
and the state and for the first one we're going to check if is mobile so if
we're going to check if is mobile so if we suddenly turn to mobile collapse the
we suddenly turn to mobile collapse the entire sidebar otherwise we're going to
entire sidebar otherwise we're going to use reset width like this and the only
use reset width like this and the only thing we're going to add inside is is
thing we're going to add inside is is mobile like this uh you don't have to
mobile like this uh you don't have to worry about the warning for set with
worry about the warning for set with because we know that it's going to work
because we know that it's going to work we know we are working with refs here
we know we are working with refs here which are not reactive in a way that use
which are not reactive in a way that use effect expects it so you don't have to
effect expects it so you don't have to add reset width inside this is going to
add reset width inside this is going to work just fine and below that let's go
work just fine and below that let's go ahead and add another use
ahead and add another use effect which is going to work on the
effect which is going to work on the path name change so let's go ahead and
path name change so let's go ahead and add if is mobile here collapse again and
add if is mobile here collapse again and Trigger this on path name and is mobile
Trigger this on path name and is mobile like this uh and we don't have the path
like this uh and we don't have the path name so let's go ahead and add it uh
name so let's go ahead and add it uh path name perhaps I misspelled it yes
path name perhaps I misspelled it yes path name great uh and there we go no
path name great uh and there we go no warnings here now and as you can see now
warnings here now and as you can see now when I expand my screen I have a sidebar
when I expand my screen I have a sidebar when I Collapse I don't have a sidebar
when I Collapse I don't have a sidebar when I click on mobile it takes up the
when I click on mobile it takes up the whole screen but if I go ahead and
whole screen but if I go ahead and expand and try then it doesn't it does
expand and try then it doesn't it does just what we want it to do if we try
just what we want it to do if we try from here it works exactly the same
from here it works exactly the same perfect so we have entirely finished our
perfect so we have entirely finished our animations of the sidebar and now we are
animations of the sidebar and now we are finally ready to start giving it some
finally ready to start giving it some items inside uh great great
items inside uh great great job all right so now that we have our
job all right so now that we have our navigation working what I want to create
navigation working what I want to create is this uh this is a protected documents
is this uh this is a protected documents page so currently that's the only thing
page so currently that's the only thing it says when I'm in this slash documents
it says when I'm in this slash documents route so now I want to create a little
route so now I want to create a little picture here and a little button which
picture here and a little button which is telling the user that they can now
is telling the user that they can now create their first note so in order to
create their first note so in order to do that first thing I want to do is
do that first thing I want to do is prepare the images we're going to need
prepare the images we're going to need for that so I'm going to go ahead and
for that so I'm going to go ahead and prepare my public folder like I did for
prepare my public folder like I did for the hero images for the landing page and
the hero images for the landing page and let's go ahead and go inside of my
let's go ahead and go inside of my GitHub right here and just go ahead and
GitHub right here and just go ahead and find the public folder which I have and
find the public folder which I have and go ahead and download empty and empty
go ahead and download empty and empty dark so I'm going to go ahead and
dark so I'm going to go ahead and download this one and I'm going to go
download this one and I'm going to go ahead and drag and drop it inside of the
ahead and drag and drop it inside of the public folder and then I'm going to go
public folder and then I'm going to go ahead and download empty dark download
ahead and download empty dark download that as well and drag and drop it inside
that as well and drag and drop it inside of the public folder great so let's see
of the public folder great so let's see if I have to rename them there we go so
if I have to rename them there we go so it looks like I have to rename this
it looks like I have to rename this empty it shouldn't have any numbers in
empty it shouldn't have any numbers in it so I'm just going to rename it to
it so I'm just going to rename it to empty.png so make sure you have empty
empty.png so make sure you have empty dark and empty.png like this great so
dark and empty.png like this great so now that we have that let's head back
now that we have that let's head back inside of our app folder main folder
inside of our app folder main folder routes documents page. vsx so here where
routes documents page. vsx so here where we say this is a protected document page
we say this is a protected document page and what I want to do is add a class
and what I want to do is add a class name to this
name to this div with h- full Flex
div with h- full Flex flex-all item D Center justify Das
flex-all item D Center justify Das Center and space- y-4 so we now Center
Center and space- y-4 so we now Center this text right here and let's go ahead
this text right here and let's go ahead and let's mark this entire thing as used
and let's mark this entire thing as used client because we're going to have some
client because we're going to have some hooks inside and let's remove this text
hooks inside and let's remove this text from here and instead let's render an
from here and instead let's render an image element from next SL image let's
image element from next SL image let's go ahead and give it a source of/
.png let's give it a height of 300 a width of 300 as well and ALT of
width of 300 as well and ALT of empty and now now let's give it a class
empty and now now let's give it a class name of dark hidden like that and now
name of dark hidden like that and now let's copy and paste this just above
let's copy and paste this just above just below this one and let's change
just below this one and let's change this one to be empty Das dark and let's
this one to be empty Das dark and let's give this one to be uh hidden on default
give this one to be uh hidden on default but when we switch to dark mode we are
but when we switch to dark mode we are in Block perfect so you can't really see
in Block perfect so you can't really see that now because we don't have the
that now because we don't have the functionality to switch light and dark
functionality to switch light and dark mode inside of this main page but as you
mode inside of this main page but as you can see we have an empty little uh image
can see we have an empty little uh image right here perfect and now below that uh
right here perfect and now below that uh I want to render welcome to uh your
I want to render welcome to uh your name's potion uh sorry your name's Jan
name's potion uh sorry your name's Jan that's what we're going to call the app
that's what we're going to call the app right so let's go ahead and let's import
right so let's go ahead and let's import use user from clerk react so import use
use user from clerk react so import use user from at clerk clerk react like that
user from at clerk clerk react like that and let's go ahead and let's extract the
and let's go ahead and let's extract the user from use user like this and now
user from use user like this and now just below this image right here what
just below this image right here what we're going to do is we're going to add
we're going to do is we're going to add an H2 element where we're going to say
an H2 element where we're going to say welcome to and go ahead and write user
welcome to and go ahead and write user question mark. first name and then add a
question mark. first name and then add a special character apples like this so
special character apples like this so this is a way to escape the actual uh
this is a way to escape the actual uh this is the sign we're trying to write
this is the sign we're trying to write but as you can see I have an error that
but as you can see I have an error that it can be escaped so that's why I'm
it can be escaped so that's why I'm writing apples like this uh so welcome
writing apples like this uh so welcome to your
to your names Joan like that now it says welcome
names Joan like that now it says welcome to Antonio's Joan in my case and now
to Antonio's Joan in my case and now let's go ahead and give this heading
let's go ahead and give this heading element a class name of text- large and
element a class name of text- large and font Das
font Das medium great and below that let's add a
medium great and below that let's add a button Element Make sure you import that
button Element Make sure you import that from as/ components UI button and inside
from as/ components UI button and inside of that element go ahead and add a plus
of that element go ahead and add a plus Circle icon from Lucid react so again
Circle icon from Lucid react so again make sure you have uh that imported
make sure you have uh that imported let's give this plus Circle a class name
let's give this plus Circle a class name of h-4 W-4 and margin right of two and
of h-4 W-4 and margin right of two and let's write create a note text like this
let's write create a note text like this perfect so we have now finished our
perfect so we have now finished our empty screen right here and it looks
empty screen right here and it looks much better than what it previously
much better than what it previously was what I want to work on now is the
was what I want to work on now is the back in the navigation bar right here so
back in the navigation bar right here so I'm just going to expand my screen a bit
I'm just going to expand my screen a bit because I want to work in desktop sub
because I want to work in desktop sub mode for now and we're going to go ahead
mode for now and we're going to go ahead and replace these action items with our
and replace these action items with our actual first item which we're going to
actual first item which we're going to use to sign out and to see the currently
use to sign out and to see the currently logged in user of this uh Jan right so
logged in user of this uh Jan right so let's go ahead and let's go back inside
let's go ahead and let's go back inside of our app folder main components
of our app folder main components navigation. vsx so here where we wrote
navigation. vsx so here where we wrote all of that logic on how the navigation
all of that logic on how the navigation bar should behave and now let's go the
bar should behave and now let's go the way down and let's find this first div
way down and let's find this first div where we wrote a paragraph with action
where we wrote a paragraph with action items and now let's remove that and
items and now let's remove that and instead let's render the user item
instead let's render the user item component like this if you save of
component like this if you save of course we're going to get an error
course we're going to get an error because user item is not defined so
because user item is not defined so inside of that underscore components
inside of that underscore components folder create a user- item. DSX file and
folder create a user- item. DSX file and let's go ahead and let's mark this is
let's go ahead and let's mark this is use client like that and let's export
use client like that and let's export const user
const user item
item user item and just return a simple div
user item and just return a simple div user item so now we can go back inside
user item so now we can go back inside of navigation and import that user item
of navigation and import that user item from do/ user item because they are in
from do/ user item because they are in the same folder like this and there we
the same folder like this and there we go we no longer have an error and
go we no longer have an error and instead we have a little text here
instead we have a little text here saying user item so let's go back inside
saying user item so let's go back inside of this user item and before we continue
of this user item and before we continue let's go ahead and install a couple of
let's go ahead and install a couple of shats and packages which we're going to
shats and packages which we're going to need to develop this to the end so I'm
need to develop this to the end so I'm going to go ahead and write npx shat CN
going to go ahead and write npx shat CN UI at latest add Avatar so that's the
UI at latest add Avatar so that's the first one we're going to add so go ahead
first one we're going to add so go ahead and click y if you get this if not
and click y if you get this if not you're just going to get it install and
you're just going to get it install and besides the Avatar we also need a
besides the Avatar we also need a drop-down menu so let's just wait a
drop-down menu so let's just wait a second for this to
second for this to install and after this is installed we
install and after this is installed we run a similar command npx shat cn- at
run a similar command npx shat cn- at latest add drop drop down Dash menu like
latest add drop drop down Dash menu like this so just go ahead uh looks like it
this so just go ahead uh looks like it says the drop down menu already exists
says the drop down menu already exists oh so we already installed that I
oh so we already installed that I believe when we created the mod toggle
believe when we created the mod toggle button right so you can just uh press no
button right so you can just uh press no on this one it doesn't really matter uh
on this one it doesn't really matter uh Great Looks like we already have this my
Great Looks like we already have this my apologies if you don't have it by any
apologies if you don't have it by any chance feel free to add it using this
chance feel free to add it using this command so let me just confirm inside of
command so let me just confirm inside of the code that I actually have the drop
the code that I actually have the drop down menu so go inside of your
down menu so go inside of your components folder instead of the UI and
components folder instead of the UI and there we go it's right here drop down
there we go it's right here drop down Dash menu perfect so we can now uh work
Dash menu perfect so we can now uh work with that but I think we have a problem
with that but I think we have a problem here and the problem is that inside of
here and the problem is that inside of our
our navigation if you remember we added a z
navigation if you remember we added a z index of a lot right and let's look at
index of a lot right and let's look at our drop down menu here I think that in
our drop down menu here I think that in here our Z index is much lower it's 50
here our Z index is much lower it's 50 meaning that it's not going to be
meaning that it's not going to be rendered in here so let's go ahead and
rendered in here so let's go ahead and resolve that so find the drop- down menu
resolve that so find the drop- down menu uh first let's find the drop- down menu
uh first let's find the drop- down menu content let's see drop- down menu
content let's see drop- down menu content so find constant drop down menu
content so find constant drop down menu content like this and find where it says
content like this and find where it says zindex 50 and change this to zindex
zindex 50 and change this to zindex 99999 like this and besides drop- down
99999 like this and besides drop- down menu content one more thing that we also
menu content one more thing that we also have to change is sub content so let's
have to change is sub content so let's go ahead and find the sub content it's
go ahead and find the sub content it's right here and let's write
right here and let's write 9999 like this so here I wrote 49 and
9999 like this so here I wrote 49 and here I wrote 59 I don't think it really
here I wrote 59 I don't think it really matters but I'm trying to stay true to
matters but I'm trying to stay true to my source code uh I think I just played
my source code uh I think I just played around with this until it matched what I
around with this until it matched what I needed all right so we have the sub
needed all right so we have the sub content we have the content and let's
content we have the content and let's see if we have any more Z indexes here I
see if we have any more Z indexes here I think that should be it uh if not we're
think that should be it uh if not we're going to go back and resolve this don't
going to go back and resolve this don't worry if you're having trouble finding
worry if you're having trouble finding this you can always just copy it
this you can always just copy it directly from my GitHub we didn't write
directly from my GitHub we didn't write this anyway it's just from shaty and UI
this anyway it's just from shaty and UI great so now we can go back inside of
great so now we can go back inside of the user item right here and let's go
the user item right here and let's go ahead and import everything we need from
ahead and import everything we need from these newly installed packages so let's
these newly installed packages so let's go ahead and let's import Avatar and
go ahead and let's import Avatar and Avatar
Avatar image from at SL components ui/ Avatar
image from at SL components ui/ Avatar like this and let's go ahead and let's
like this and let's go ahead and let's import from components UI drop down menu
import from components UI drop down menu we need the drop down menu itself we
we need the drop down menu itself we need a drop-down menu
need a drop-down menu content we need the
content we need the item like this we need the
item like this we need the label and we need a separator
label and we need a separator whoops where is it so separator and we
whoops where is it so separator and we need a
need a trigger there we go so we need all of
trigger there we go so we need all of these items from here and while we're
these items from here and while we're writing import let's also import an icon
writing import let's also import an icon we're going to need which is chevron's
we're going to need which is chevron's Left Right from Lucid react great so now
Left Right from Lucid react great so now that we have that go inside of user item
that we have that go inside of user item and go ahead and extract
and go ahead and extract user from use user which if you remember
user from use user which if you remember we can get from clerk so use
we can get from clerk so use user not user user but use user from
user not user user but use user from add/ CL at clerk clerk react great so
add/ CL at clerk clerk react great so now we have the currently logged in user
now we have the currently logged in user and now let's replace This Ti with a
and now let's replace This Ti with a drop- down menu now let's write the drop
drop- down menu now let's write the drop down menu trigger so we have all of this
down menu trigger so we have all of this imported let's give this drop down menu
imported let's give this drop down menu trigger an as child prop and now let's
trigger an as child prop and now let's write a div with a roll of button and
write a div with a roll of button and let's give it a class name of flex items
let's give it a class name of flex items D Center text- small padding -3 w- full
D Center text- small padding -3 w- full and hover BG D primary with an opacity
and hover BG D primary with an opacity background opacity of .5 inside of it
background opacity of .5 inside of it open another div with a class name of
open another div with a class name of Gap dx-2 Flex items Das Center and a Max
Gap dx-2 Flex items Das Center and a Max width of 150
width of 150 pixels inside of that div it's time to
pixels inside of that div it's time to render our Avatar which we imported
render our Avatar which we imported recently and give this Avatar a class
recently and give this Avatar a class name of h-5 and
name of h-5 and w-5 and let's render an avatar image
w-5 and let's render an avatar image inside with a source of user question
inside with a source of user question mark. image URL great so now that we
mark. image URL great so now that we have that let's go below this Alor and
have that let's go below this Alor and render a span element and go ahead and
render a span element and go ahead and write user question mark full name and
write user question mark full name and write our appost trick Josan so in my
write our appost trick Josan so in my case it's going to be a my name my
case it's going to be a my name my surname aposto s
surname aposto s Joan like that and give this class name
Joan like that and give this class name give this span a class name of text
give this span a class name of text start font D medium and line- clamp D1
start font D medium and line- clamp D1 so it truncates the line if it's too
so it truncates the line if it's too long and let's say if we can already see
long and let's say if we can already see that and there we go you can see it
that and there we go you can see it right here you can see how it truncated
right here you can see how it truncated uh the lines right here perfect so now
uh the lines right here perfect so now we want to add a little Chevron here so
we want to add a little Chevron here so it indicates that we can click on that
it indicates that we can click on that and open our dialogue
and open our dialogue great so let's go ahead now and let's go
great so let's go ahead now and let's go outside of this drop down menu trigger
outside of this drop down menu trigger actually no sorry we are still inside of
actually no sorry we are still inside of here so find this div which encapsu is
here so find this div which encapsu is the Avatar and the span and go outside
the Avatar and the span and go outside of it and add a chevron's left right
of it and add a chevron's left right icon with a class name of rotate 90 like
icon with a class name of rotate 90 like that margin left of two text- muted D
that margin left of two text- muted D foreground and h-4 n W-4 and if you
foreground and h-4 n W-4 and if you revisit your side right now there we go
revisit your side right now there we go you can see how you have a nice little
you can see how you have a nice little up and down shivon right here and now
up and down shivon right here and now let's actually write the content for
let's actually write the content for this drop down menu so let's go ahead
this drop down menu so let's go ahead and let's write dropdown menu
and let's write dropdown menu content let's give it some props so
content let's give it some props so class name is going to be
class name is going to be W8 let's also give it an Aline of start
W8 let's also give it an Aline of start a line
a line offset of
offset of 11 and let's give it Force amount option
11 and let's give it Force amount option inside of it let's write a div element
inside of it let's write a div element which is going to have a class name of
which is going to have a class name of flex flex-all space- y-4 so everything
flex flex-all space- y-4 so everything inside is evenly spaced and let's add a
inside is evenly spaced and let's add a padding so we have a bit more room to
padding so we have a bit more room to work with and now we're going to have a
work with and now we're going to have a paragraph here where we're going to say
paragraph here where we're going to say user question mark email addresses
user question mark email addresses z. email
z. email address like like this and let's write a
address like like this and let's write a class
class name text- extra small f- medium leading
name text- extra small f- medium leading dnone and text- muted D
dnone and text- muted D foreground great so now if you take a
foreground great so now if you take a look and if you click here you're going
look and if you click here you're going to see your email address right here
to see your email address right here perfect so let's go ahead and let's
perfect so let's go ahead and let's continue and let's write uh some actions
continue and let's write uh some actions inside so what I want to do is go
inside so what I want to do is go outside this paragraph here and open a
outside this paragraph here and open a div and give this div a class name of
div and give this div a class name of flex items D Center and GAP
flex items D Center and GAP dx-2 and now let's go ahead and write a
dx-2 and now let's go ahead and write a div class name rounded DMD BG D
div class name rounded DMD BG D secondary and ping of
secondary and ping of one inside let's render an avatar with
one inside let's render an avatar with an avatar image again and let's give it
an avatar image again and let's give it a source of user. image URL and and
a source of user. image URL and and let's give this Avatar a class name of
let's give this Avatar a class name of h-8 and
h-8 and w-8 so let's see how that looks
w-8 so let's see how that looks now there we go so we have our little
now there we go so we have our little image here perfect and
image here perfect and now let's go ahead outside of this
now let's go ahead outside of this Avatar outside of this div encapsulating
Avatar outside of this div encapsulating the Avatar and let's add a new div with
the Avatar and let's add a new div with a class name of space- Y whoops space-
a class name of space- Y whoops space- y- z-1 my apologies and and inside just
y- z-1 my apologies and and inside just open a paragraph with a class name of
open a paragraph with a class name of text small and line- clamp D1 and just
text small and line- clamp D1 and just render user question mark. full name
render user question mark. full name appus add an S Jo like this and now it
appus add an S Jo like this and now it should have a little more options here
should have a little more options here so we have my email and my name and that
so we have my email and my name and that this is my Jan right and now we're going
this is my Jan right and now we're going to add a little log out button from here
to add a little log out button from here so let's go ahead uh outside of this div
so let's go ahead uh outside of this div which is en
which is en encapsulating uh the uh the paragraph
encapsulating uh the uh the paragraph and outside of this div as
and outside of this div as well actually we can go outside of all
well actually we can go outside of all divs all the way here at the bottom but
divs all the way here at the bottom but still inside of the drop down menu
still inside of the drop down menu content and just add a drop-down menu
content and just add a drop-down menu separator which is a self closing tag
separator which is a self closing tag and then a drop down menu item which is
and then a drop down menu item which is going to have a sign out button well
going to have a sign out button well first let's add the closing one for this
first let's add the closing one for this one like this and then inside we're
one like this and then inside we're going to have a sign out button and we
going to have a sign out button and we can get the sign out button from the
can get the sign out button from the same place we got use user right here
same place we got use user right here from clerk clerk react and let's go
from clerk clerk react and let's go ahead and
ahead and oops and let's go ahead now uh and let's
oops and let's go ahead now uh and let's just render log out and give this drop
just render log out and give this drop down menu item a class name w-o cursor
down menu item a class name w-o cursor Das pointer text- muted D
Das pointer text- muted D foreground and let's also give it an as
foreground and let's also give it an as child option great so now if we take a
child option great so now if we take a look one more time when I click on here
look one more time when I click on here here's my email here's my name and I can
here's my email here's my name and I can click log out and I am back on the
click log out and I am back on the landing page and let's go ahead and log
landing page and let's go ahead and log in with GitHub
in with GitHub again there we go I can now enter Jan
again there we go I can now enter Jan and there we go so this is fully working
and there we go so this is fully working great and now we're finally ready to
great and now we're finally ready to create our first action which is going
create our first action which is going to create our first
to create our first document so now that we have some items
document so now that we have some items inside of our sidebar it's time to
inside of our sidebar it's time to enable this button that when we click on
enable this button that when we click on create a note we actually create a new
create a note we actually create a new note so let's prepare a couple of things
note so let's prepare a couple of things first what I want to do before we start
first what I want to do before we start anything is install a package called
anything is install a package called soner so npm install soner like this and
soner so npm install soner like this and this is going to install soner and now
this is going to install soner and now you can go ahead inside of your app
you can go ahead inside of your app folder layout. TSX and go ahead and
folder layout. TSX and go ahead and import so let me just do this at the
import so let me just do this at the top import
top import poster from soner like this and you can
poster from soner like this and you can just put it inside of this layout server
just put it inside of this layout server component inside of the theme provider
component inside of the theme provider like this it's a self closing tag and
like this it's a self closing tag and give it a position of bottom center like
give it a position of bottom center like this you can of course play around and
this you can of course play around and modify it to what you like but this is
modify it to what you like but this is the one I prefer great so now that we
the one I prefer great so now that we have this let's go ahead and let's
have this let's go ahead and let's create our schema but before we do that
create our schema but before we do that just confirm that inside of your
just confirm that inside of your terminal you have let me see this one is
terminal you have let me see this one is this okay you should have the MPX convex
this okay you should have the MPX convex Dev running and you should have the mpm
Dev running and you should have the mpm Run Dev running so just make sure you
Run Dev running so just make sure you have both of those on and what we're
have both of those on and what we're going to create now is our schema so
going to create now is our schema so let's go ahead inside of the convex
let's go ahead inside of the convex folder right here and create a new file
folder right here and create a new file called schema. DS like that and go ahead
called schema. DS like that and go ahead and import Define schema and Define
and import Define schema and Define table from convex SLS server and go
table from convex SLS server and go ahead and import V from convex SL values
ahead and import V from convex SL values and now expert default Define
and now expert default Define schema and let's define our t which is
schema and let's define our t which is going to be documents so write
going to be documents so write Define
Define table open an object and let's give it
table open an object and let's give it an option of title which is a type of
an option of title which is a type of string like that a user ID which is also
string like that a user ID which is also a type of string this is where we're
a type of string this is where we're going to pass in the clerk user ID below
going to pass in the clerk user ID below the user ID at a Boolean is
the user ID at a Boolean is archive so v.
archive so v. Boolean we're going to use this for soft
Boolean we're going to use this for soft deleting of the documents go ahead and
deleting of the documents go ahead and add a parent
add a parent document this is going to be optional so
document this is going to be optional so v. optional like this and v. ID is going
v. optional like this and v. ID is going to refer to documents itself so we are
to refer to documents itself so we are going to create a relation with the very
going to create a relation with the very same document that we are creating so
same document that we are creating so every document is going to be able to
every document is going to be able to have its own parent document if we
have its own parent document if we create recursive documents inside as you
create recursive documents inside as you saw in the demonstration or they can
saw in the demonstration or they can just be all parent documents now we're
just be all parent documents now we're going to have content which is going to
going to have content which is going to be the actual value written inside of
be the actual value written inside of the written inside of the uh specific
the written inside of the uh specific document and that's going to be an
document and that's going to be an optional v. string like
optional v. string like this and let's use cover image that's
this and let's use cover image that's also going to be v. optional also a type
also going to be v. optional also a type of v. string besides cover image we're
of v. string besides cover image we're going to have an icon which is again an
going to have an icon which is again an optional
optional string and lastly we're going to have a
string and lastly we're going to have a Boolean is published
Boolean is published which is going to be v.
which is going to be v. Boolean so published is going to me is
Boolean so published is going to me is going to mean visible to outside of uh
going to mean visible to outside of uh to any guest right so you can share the
to any guest right so you can share the URL as you saw in the demo if it's not
URL as you saw in the demo if it's not published it's just private to you and
published it's just private to you and now let's create some indexes for faster
now let's create some indexes for faster querying so index by user so we can
querying so index by user so we can query by the currently logged in user
query by the currently logged in user and we're going to use the field user ID
and we're going to use the field user ID for that and let's also create an index
for that and let's also create an index a combination of user and a parent
a combination of user and a parent document we're going to use this in our
document we're going to use this in our sidebar so by user undor parent and the
sidebar so by user undor parent and the values which we're going to work with
values which we're going to work with our user ID and parent
our user ID and parent document there we go so we just defined
document there we go so we just defined our schema and now if you want to you
our schema and now if you want to you can go ahead and visit convex dodev and
can go ahead and visit convex dodev and log in here go inside of your
log in here go inside of your dashboard and just select uh the project
dashboard and just select uh the project you're working with so notion clone in
you're working with so notion clone in my case right here and I think you
my case right here and I think you should already have a way to find a
should already have a way to find a schema here uh if there we go so it says
schema here uh if there we go so it says documents right here as you can see and
documents right here as you can see and I can click show schema and there we go
I can click show schema and there we go this is the code that I've just written
this is the code that I've just written here and I can see it in my browser
here and I can see it in my browser that's really really cool so that's how
that's really really cool so that's how you know that uh your code from convex
you know that uh your code from convex right here thanks to this terminal which
right here thanks to this terminal which is running as you can see for a second I
is running as you can see for a second I had a wrong schema here but it doesn't
had a wrong schema here but it doesn't matter like you can just keep npx convex
matter like you can just keep npx convex Dev running and it's going to watch all
Dev running and it's going to watch all the changes you write and as you can see
the changes you write and as you can see it added table indexes and invalidated
it added table indexes and invalidated my schema and then I have that schema
my schema and then I have that schema right here in my browser so I can see
right here in my browser so I can see exactly this is correct and the convex
exactly this is correct and the convex server is working perfect so if you want
server is working perfect so if you want to keep this open because now I'm going
to keep this open because now I'm going to show you how this data will appear
to show you how this data will appear here and you can of course play around
here and you can of course play around and run some functions from here but we
and run some functions from here but we don't have any API functions yet and
don't have any API functions yet and that's what we're going to create now so
that's what we're going to create now so let's go ahead inside of the conx folder
let's go ahead inside of the conx folder and create a new file called
and create a new file called documents. and let's go ahead inside and
documents. and let's go ahead inside and first let's go ahead and let's import V
first let's go ahead and let's import V from convex SL
from convex SL values and let's go ahead and let's
values and let's go ahead and let's import mutation and query from do/
import mutation and query from do/ generated server and let's also import
generated server and let's also import Dot and ID from do/ generated slata
Dot and ID from do/ generated slata model great so now that we have this we
model great so now that we have this we are ready to create our first mutation
are ready to create our first mutation so let's write export const create to be
so let's write export const create to be a type of
a type of mutation and let's go ahead and give the
mutation and let's go ahead and give the arguments for this function so the
arguments for this function so the arguments are going to be a title which
arguments are going to be a title which is a. string so when we create a new
is a. string so when we create a new document we're going to have to pass in
document we're going to have to pass in the title of that document and we're
the title of that document and we're also going to have uh an optional parent
also going to have uh an optional parent document so we're going to reuse this
document so we're going to reuse this function if we are creating a child of
function if we are creating a child of another document or it can just be a
another document or it can just be a completely new parent document so that's
completely new parent document so that's why we're going to write v. optional
why we're going to write v. optional like this and then v. ID
like this and then v. ID documents great besides this we're going
documents great besides this we're going to have a Handler
to have a Handler function and that Handler is going to be
function and that Handler is going to be an asynchronous function which is going
an asynchronous function which is going to have the context and the arguments
to have the context and the arguments like this and then we can fetch the
like this and then we can fetch the currently logged in user using context
currently logged in user using context so con
so con identity is going to be await context.
identity is going to be await context. out.get user identity and if we don't
out.get user identity and if we don't have the identity that means we are not
have the identity that means we are not logged in so an unlogged in
logged in so an unlogged in unauthenticated user is trying to create
unauthenticated user is trying to create a new document we won't allow that so
a new document we won't allow that so throw new error not
throw new error not authenticated there we go and now let's
authenticated there we go and now let's extract the user ID from the identity so
extract the user ID from the identity so const user ID is equal to
const user ID is equal to Identity do
Identity do subject and now let's finally create our
subject and now let's finally create our document so const document is equal to
document so const document is equal to await context. database. insert and we
await context. database. insert and we are inserting documents and now let's
are inserting documents and now let's define exactly what we're inserting so
define exactly what we're inserting so the title is going to be arguments. tile
the title is going to be arguments. tile which we defined right here to be a type
which we defined right here to be a type of string but we are missing a couple of
of string but we are missing a couple of stuff so we need a parent document if it
stuff so we need a parent document if it exists ar. parent document if it doesn't
exists ar. parent document if it doesn't exist this is just going to be undefined
exist this is just going to be undefined and that's completely fine because in
and that's completely fine because in our schema we said that parent document
our schema we said that parent document is optional and as you can say one of
is optional and as you can say one of the options of that is undefined so this
the options of that is undefined so this is completely working and we can reuse
is completely working and we can reuse it and we're going to have to pass in
it and we're going to have to pass in the user ID which is user ID or you can
the user ID which is user ID or you can just write a short hand like this and
just write a short hand like this and let's set is archived to be false and is
let's set is archived to be false and is published to be false as well and there
published to be false as well and there we go no more errors and now we can just
we go no more errors and now we can just return the document from here and go
return the document from here and go ahead and save this and you can always
ahead and save this and you can always check your terminal to see if there are
check your terminal to see if there are any mistakes as you can see it's
any mistakes as you can see it's checking everything and there we go
checking everything and there we go convex functions are ready so we
convex functions are ready so we successfully wrote this function and now
successfully wrote this function and now let me just refresh my dashboard here
let me just refresh my dashboard here and I think that you should already see
and I think that you should already see your functions here there we go
your functions here there we go documents create so click on the
documents create so click on the functions here and as you can see this
functions here and as you can see this is your code and you can see how many
is your code and you can see how many invocations you have how many errors it
invocations you have how many errors it has and how long it takes to execute
has and how long it takes to execute that so that's why this convex is really
that so that's why this convex is really cool because it almost breaks the
cool because it almost breaks the barrier between what you write here and
barrier between what you write here and what you write in this little interface
what you write in this little interface they have here really really cool and it
they have here really really cool and it makes it so easier to test it out
makes it so easier to test it out whether it's working or not great so now
whether it's working or not great so now that we have this it's finally time to
that we have this it's finally time to for me to show you how you can actually
for me to show you how you can actually add this uh inside a react component
add this uh inside a react component right and as you can see we are
right and as you can see we are currently not using this but it's going
currently not using this but it's going to come in handy later great so make
to come in handy later great so make sure you save this make sure you confirm
sure you save this make sure you confirm that you have that in your
that you have that in your functions and now let's go ahead and
functions and now let's go ahead and let's go inside of the app folder inside
let's go inside of the app folder inside of the main folder routes documents
of the main folder routes documents page. TSX right here so we have this
page. TSX right here so we have this button which says create a note so first
button which says create a note so first let's check if we have used client we do
let's check if we have used client we do great and now what we can do is ADD our
great and now what we can do is ADD our create method so const create is equal
create method so const create is equal to use
to use mutation and now let's go ahead and
mutation and now let's go ahead and let's import this use
let's import this use mutation so import use
mutation so import use mutation from convex SL react and while
mutation from convex SL react and while we are here and it's not user mutation
we are here and it's not user mutation it's use mutation like a hook and while
it's use mutation like a hook and while we are here let's also import our API
we are here let's also import our API and we get our API from at/ convex
and we get our API from at/ convex generat
generat API there we go so now that we have that
API there we go so now that we have that let's go inside of this create mutation
let's go inside of this create mutation and let's write API and as you can see
and let's write API and as you can see we have type safety here so do documents
we have type safety here so do documents dot create exactly what we've written in
dot create exactly what we've written in our documents page and let me just
our documents page and let me just revisit it right here so it's exactly
revisit it right here so it's exactly this documents and if I renamed this
this documents and if I renamed this file uh where is it my convex if I
file uh where is it my convex if I rename this documents file into
rename this documents file into something else then the API would change
something else then the API would change it would be API do something else do
it would be API do something else do create and same thing if I rename create
create and same thing if I rename create so you don't have to follow this exactly
so you don't have to follow this exactly as I'm doing it you just make sure that
as I'm doing it you just make sure that you know it's the same logic behind it
you know it's the same logic behind it and now that we have this create we can
and now that we have this create we can directly add that on click here if we
directly add that on click here if we want to but what I want to do is I want
want to but what I want to do is I want to create a little Handler so I can do
to create a little Handler so I can do additional actions on it like fire a
additional actions on it like fire a toast unsuccessful creation and maybe
toast unsuccessful creation and maybe redirect the user to that newly created
redirect the user to that newly created note so let's write const on
note so let's write const on create
create like that which is going to be an arrow
like that which is going to be an arrow function and now let's write const
function and now let's write const promise to be create and as you can see
promise to be create and as you can see it's expecting an argument and that
it's expecting an argument and that argument is an object of our uh of uh
argument is an object of our uh of uh our arguments and as you can see parent
our arguments and as you can see parent document is optional but title is
document is optional but title is required exactly as we've written in the
required exactly as we've written in the arguments right here and that means we
arguments right here and that means we just have to pass in the title and for
just have to pass in the title and for my code what I'm going to do is I'm
my code what I'm going to do is I'm going to pass in the title Untitled for
going to pass in the title Untitled for every new one like this great now that I
every new one like this great now that I have this promise what I'm going to do
have this promise what I'm going to do is I'm going to add the toast from the
is I'm going to add the toast from the toaster from sonar so let's go ahead to
toaster from sonar so let's go ahead to the top here and let's import toast from
the top here and let's import toast from soner like that and let's go ahead and
soner like that and let's go ahead and let's write post. promise let's pass in
let's write post. promise let's pass in that promise and let's define the states
that promise and let's define the states so if we are loading we're going to
so if we are loading we're going to write creating a
write creating a new creating a new
new creating a new note if we have have succeeded so
note if we have have succeeded so success we're going to say new note
success we're going to say new note created and if we fail if we get an
created and if we fail if we get an error we're going to write failed to
error we're going to write failed to create a new note all right so now that
create a new note all right so now that we have this let's go ahead and let's
we have this let's go ahead and let's add this on click to this function sorry
add this on click to this function sorry to this button right here so button now
to this button right here so button now is going to have on click on
is going to have on click on create great so let's go ahead and
create great so let's go ahead and expand this screen here let's see our
expand this screen here let's see our data here in the conx so currently have
data here in the conx so currently have nothing in the documents table Let me
nothing in the documents table Let me refresh this and when I click create
refresh this and when I click create note you can see how it says new note
note you can see how it says new note created and let's revisit and there we
created and let's revisit and there we go we have a new document is archived is
go we have a new document is archived is false is published is false title is
false is published is false title is Untitled and we have a matching user ID
Untitled and we have a matching user ID inside we also have creation time made
inside we also have creation time made for us and we also have the ID so great
for us and we also have the ID so great we successfully created our first API
we successfully created our first API route so now I want to show show you how
route so now I want to show show you how you can actually load this information
you can actually load this information now I showed you how to create it in
now I showed you how to create it in react components but how do you load it
react components but how do you load it well very simply let's go ahead and
well very simply let's go ahead and let's revisit our convex right here so
let's revisit our convex right here so where is it it's convex folder go inside
where is it it's convex folder go inside the documents. DS and just for fun let's
the documents. DS and just for fun let's go ahead and let's add a new API
go ahead and let's add a new API endpoint here export const get and it's
endpoint here export const get and it's going to be uh a
going to be uh a query and let's go ahead and for now we
query and let's go ahead and for now we can just do a Handler I believe like
can just do a Handler I believe like this it's going to be an asynchronous
this it's going to be an asynchronous function which is going to have the
function which is going to have the context it's not going to have the
context it's not going to have the arguments because we didn't pass it and
arguments because we didn't pass it and let's go ahead and let's do this thing
let's go ahead and let's do this thing so we're just going to go ahead and get
so we're just going to go ahead and get the identity to make sure we're logged
the identity to make sure we're logged in and then what we're going to do is
in and then what we're going to do is we're just going to write const
documents to be await DB sorry context. db. query like
context. db. query like this sorry context.
this sorry context. dbquery
dbquery documents and we can just leave it like
documents and we can just leave it like this for now and return documents so
this for now and return documents so this is a very simplified function of
this is a very simplified function of course we are not actually checking
course we are not actually checking whether the logged in user is quaring
whether the logged in user is quaring its own documents we're just loading all
its own documents we're just loading all documents but I just wanted to repeat
documents but I just wanted to repeat how we do authentication here and later
how we do authentication here and later we're going to add the index here so
we're going to add the index here so great now that we have this let's go
great now that we have this let's go ahead and let's go into inside of our
ahead and let's go into inside of our navigation so inside of main components
navigation so inside of main components navigation right here and let's go all
navigation right here and let's go all the way to the top here we're going to
the way to the top here we're going to remove this later but just for now I
remove this later but just for now I want to show you so let's go ahead and
want to show you so let's go ahead and write con documents to be uh used
write con documents to be uh used query and we have to import use Query
query and we have to import use Query from the same place we imported uh use
from the same place we imported uh use mutation so use Query from convex SL
mutation so use Query from convex SL react and let's go ahead and pass in the
react and let's go ahead and pass in the API which we get from at SLC convex
API which we get from at SLC convex generated API and let's pass in the api.
generated API and let's pass in the api. documents and as you can see it
documents and as you can see it autocompletes the get function and there
autocompletes the get function and there are no errors because we don't have to
are no errors because we don't have to pass in any arguments and now that we
pass in any arguments and now that we have these documents right here let's go
have these documents right here let's go ahead and let's find the div where we
ahead and let's find the div where we actually wrote the paragraph documents
actually wrote the paragraph documents and instead let's go ahead and write
and instead let's go ahead and write documents question mark. map because
documents question mark. map because they have to load right but we are not
they have to load right but we are not going to do loading States now and let's
going to do loading States now and let's get the individual
get the individual document and let's go ahead and
document and let's go ahead and return uh let me just see I think I made
return uh let me just see I think I made a mistake here uh just a
a mistake here uh just a second let's just go ahead and let's see
second let's just go ahead and let's see what we'll end up with here so let's
what we'll end up with here so let's just add a paragraph see here with a
just add a paragraph see here with a document dot title like this and let's
document dot title like this and let's see if this is going to break anything
see if this is going to break anything or not all right so return value is a
or not all right so return value is a query oh yes I think I forgot to
query oh yes I think I forgot to actually uh write my uh write my entire
actually uh write my uh write my entire query here so go back to documents doget
query here so go back to documents doget and we have to write collect at the end
and we have to write collect at the end I forgot to do that and now right here
I forgot to do that and now right here there we go you can see no more errors
there we go you can see no more errors regarding the query instead it's missing
regarding the query instead it's missing a key which is document doore
a key which is document doore ID and now there we go no more errors
ID and now there we go no more errors perfect so just make sure that in your
perfect so just make sure that in your documents in this get function you add
documents in this get function you add collect at the end perfect and now you
collect at the end perfect and now you can just leave the query as it is so
can just leave the query as it is so this is where we defined the query so
this is where we defined the query so cons documents use Query API the
cons documents use Query API the documents get that is fine and then in
documents get that is fine and then in the documents we just iterate over them
the documents we just iterate over them perfect and now in your sidebar there we
perfect and now in your sidebar there we go it says entitled and look at this
go it says entitled and look at this when I click create a new note instantly
when I click create a new note instantly I have a new one so this is a realtime
I have a new one so this is a realtime database meaning that this use Query
database meaning that this use Query function which we defined in the sidebar
function which we defined in the sidebar is also uh watching in real time all of
is also uh watching in real time all of the changes we have perfect so that's
the changes we have perfect so that's what I wanted to demonstrate you so now
what I wanted to demonstrate you so now that we have this functionality to
that we have this functionality to create a new note it's time for us to
create a new note it's time for us to also create the same button inside of
also create the same button inside of this uh sideb bar and it's time for us
this uh sideb bar and it's time for us to also render these items in a nicer
to also render these items in a nicer way and let me show you how you can
way and let me show you how you can clear your entire schema from here so
clear your entire schema from here so you can just click right here and click
you can just click right here and click clear table and just confirm and there
clear table and just confirm and there we go instantly everything is gone and
we go instantly everything is gone and you can start all over again great great
you can start all over again great great job all right so now let's go ahead and
job all right so now let's go ahead and let's add this create a note button
let's add this create a note button right here in the sidebar as well so
right here in the sidebar as well so first thing I'm going to do is go back
first thing I'm going to do is go back inside of my convex dashboard and I'm
inside of my convex dashboard and I'm just going to clear my entire table so I
just going to clear my entire table so I don't want to have anything in my
don't want to have anything in my sidebar like this so completely empty
sidebar like this so completely empty make sure you do that and now let's go
make sure you do that and now let's go ahead and let's go back inside of our
ahead and let's go back inside of our navigation right here and let's go ahead
navigation right here and let's go ahead and let's find uh our div where we have
and let's find uh our div where we have the user item right right here so find
the user item right right here so find the div which is encapsulating the user
the div which is encapsulating the user item go below that and go ahead and
item go below that and go ahead and write an item element which is not
write an item element which is not defined so if you save you're going to
defined so if you save you're going to get an error but I already want to give
get an error but I already want to give it some props so we're going to have an
it some props so we're going to have an on click option which is just going to
on click option which is just going to be an empty Arrow function and we're
be an empty Arrow function and we're also going to have a label which is
also going to have a label which is going to say new page and we're going to
going to say new page and we're going to have an icon plus Circle and plus Circle
have an icon plus Circle and plus Circle comes from Lucid react so just make sure
comes from Lucid react so just make sure that you import plus Circle from Lucid
that you import plus Circle from Lucid react so let me just collapse this props
react so let me just collapse this props so you can see how this is supposed to
so you can see how this is supposed to look like so item is a self closing tag
look like so item is a self closing tag which has the onclick label and icon
which has the onclick label and icon right here perfect so go ahead uh and
right here perfect so go ahead uh and save that and now let's go ahead and
save that and now let's go ahead and let's go inside of this underscore
let's go inside of this underscore components where we have the navigation
components where we have the navigation itself and create a new file item. DSX
itself and create a new file item. DSX and let's go ahead and let's mark this
and let's go ahead and let's mark this as use client and let's ort con item
as use client and let's ort con item like this and let's just return a div
like this and let's just return a div saying item and then we can go back
saying item and then we can go back inside of our navigation and we can
inside of our navigation and we can import that item from dot SL item so let
import that item from dot SL item so let me show you where it is there we go so
me show you where it is there we go so import item from do/ item the same way
import item from do/ item the same way we did with user item great and now we
we did with user item great and now we can go ahead and save this and let's
can go ahead and save this and let's just see all right and you should no
just see all right and you should no longer have that error in the dashboard
longer have that error in the dashboard instead you should have a little this
instead you should have a little this which now says item Right Here and Now
which now says item Right Here and Now what we have to do is we have to fix
what we have to do is we have to fix this type errors so we are sending on
this type errors so we are sending on click label and icon so let's go inside
click label and icon so let's go inside of the item and let's create an
of the item and let's create an interface item props and I'm going to go
interface item props and I'm going to go ahead and add a label U which is going
ahead and add a label U which is going to be a type of
to be a type of string I'm going to add on click which
string I'm going to add on click which is going to be a type of void and I'm
is going to be a type of void and I'm also going to add an icon and I'm going
also going to add an icon and I'm going to make it a type of lucid icon from
to make it a type of lucid icon from Lucid re yeah and now let's go ahead and
Lucid re yeah and now let's go ahead and let's extract all of those props and
let's extract all of those props and let's map them to item props so we have
let's map them to item props so we have label on click and icon great and now
label on click and icon great and now let's go ahead and let's go ahead and
let's go ahead and let's go ahead and render the label here so already in your
render the label here so already in your sidebar this should now say new page
sidebar this should now say new page because in the navigation as you can see
because in the navigation as you can see we send the label new page great let's
we send the label new page great let's go back inside of the item now and let's
go back inside of the item now and let's go ahead and give this div an onclick
go ahead and give this div an onclick option of onclick let's give it a roll
option of onclick let's give it a roll of
of button let's go ahead and let's give it
button let's go ahead and let's give it a style adding left 12 pixels and I know
a style adding left 12 pixels and I know you're wondering why am I using the
you're wondering why am I using the style prop here well that's because
style prop here well that's because we're going to reuse this item element
we're going to reuse this item element later in the future to create a list of
later in the future to create a list of documents which we have and if you
documents which we have and if you remember each document can have a child
remember each document can have a child document which means that we're going to
document which means that we're going to have to do some math to push it more to
have to do some math to push it more to the left if it's a child right so you're
the left if it's a child right so you're going to see that logic later on so I
going to see that logic later on so I just already want to prepare that inside
just already want to prepare that inside of the style prop rather than class name
of the style prop rather than class name because then we're going to have to
because then we're going to have to remove the class name and it's just
remove the class name and it's just going to be complicated so let's go
going to be complicated so let's go ahead and write an actual class name for
ahead and write an actual class name for the rest of the Styles here so we're
the rest of the Styles here so we're going to have group mean- H is going to
going to have group mean- H is going to be 27 pixels text is going to be small
be 27 pixels text is going to be small padding on top and bottom is going to be
padding on top and bottom is going to be one padding on the right is going to be
one padding on the right is going to be three width is going to be full when we
three width is going to be full when we hover on it the BG is going to be
hover on it the BG is going to be primary
primary slash5 it's going to be a flex box it's
slash5 it's going to be a flex box it's going to have its items centered and
going to have its items centered and it's going to have text muted foreground
it's going to have text muted foreground and we're also going to bold the font a
and we're also going to bold the font a bit by adding font medium great and now
bit by adding font medium great and now let's go ahead and let's render this
let's go ahead and let's render this icon in order to render this icon we
icon in order to render this icon we have to remap it to Capital icon sorry
have to remap it to Capital icon sorry icon with a capital I because now we can
icon with a capital I because now we can use it as a jsx element so make sure you
use it as a jsx element so make sure you do this inside of your props so just
do this inside of your props so just remap it to icon with a capital I and
remap it to icon with a capital I and then you can just safely render that
then you can just safely render that icon just like this and that's going to
icon just like this and that's going to render whatever you pass in so in this
render whatever you pass in so in this case we're passing in the plus Circle so
case we're passing in the plus Circle so this is going to render plus circle
this is going to render plus circle inside of here and now let's go ahead
inside of here and now let's go ahead and give this icon a class name of
and give this icon a class name of shrink -0 height of 18
shrink -0 height of 18 pixels margin right of two and text-
pixels margin right of two and text- muted D foreground excellent and last
muted D foreground excellent and last thing we have to do is wrap this uh
thing we have to do is wrap this uh label inside of a span
label inside of a span element so let's go ahead and write
element so let's go ahead and write class name truncate like this and there
class name truncate like this and there we go so let me just go back to the item
we go so let me just go back to the item uh I think that should be it for now so
uh I think that should be it for now so let me expand my screen now and there we
let me expand my screen now and there we go now we have a new a new page uh
go now we have a new a new page uh button right here you can see how when I
button right here you can see how when I hover it has a nice little effect and it
hover it has a nice little effect and it has a cursor button on it perfect so now
has a cursor button on it perfect so now what we have to do is we have to enable
what we have to do is we have to enable that when when we click on it on this
that when when we click on it on this that a new one uh is created so let's go
that a new one uh is created so let's go ahead uh and do that now so what I want
ahead uh and do that now so what I want to do is I want to go back inside of my
to do is I want to go back inside of my navigation here and let's go all the way
navigation here and let's go all the way to the top where we add the documents
to the top where we add the documents query and what I want to add is the
query and what I want to add is the create function so const create is use
create function so const create is use mutation and let's go ahead and let's
mutation and let's go ahead and let's import us mutation from convex SL react
import us mutation from convex SL react and now let's go ahead and pass in the
and now let's go ahead and pass in the API which is going to be api. documents.
API which is going to be api. documents. create great now that we have this
create great now that we have this create function let's go ahead and all
create function let's go ahead and all the way before we return something so
the way before we return something so after all of this functions for the
after all of this functions for the Navar let's go ahead and write const
Navar let's go ahead and write const handle
create and inside of here we're going to do the same thing that we did inside of
do the same thing that we did inside of this main page so we're going to create
this main page so we're going to create a promise const promise is going to be
a promise const promise is going to be create function and we're going to pass
create function and we're going to pass in the title of
in the title of Untitled and then what we can do is add
Untitled and then what we can do is add our toast from uh soner so let's go
our toast from uh soner so let's go ahead and import
ahead and import soner so import tost from
soner so import tost from soner great and now let's find that
soner great and now let's find that handle create function here then we can
handle create function here then we can do toast. promise passing. promise and
do toast. promise passing. promise and let's give it a loading state of
let's give it a loading state of creating a new note let's give it a
creating a new note let's give it a success state of New node
success state of New node created and let's give it an error state
created and let's give it an error state of failed to create a new
of failed to create a new note like this and now let's add this
note like this and now let's add this handle create in this uh item right here
handle create in this uh item right here where we currently have an empty on
where we currently have an empty on click function like this and now let's
click function like this and now let's see what happens so I'm going to refresh
see what happens so I'm going to refresh everything I have nothing inside of my
everything I have nothing inside of my documents here but when I click here
documents here but when I click here there we go a new one is a appearing
there we go a new one is a appearing here so I can do it both from here and
here so I can do it both from here and from here now and you can see I have
from here now and you can see I have four of them inside of my uh dashboard
four of them inside of my uh dashboard as well perfect so now we have our new
as well perfect so now we have our new page button working and now what I want
page button working and now what I want to create is I want to extend this item
to create is I want to extend this item component which we just created and give
component which we just created and give it a lot more functionality so it can be
it a lot more functionality so it can be reused for both this button but also for
reused for both this button but also for this rendering of individual documents
this rendering of individual documents so I want each document to have its own
so I want each document to have its own icon I want to have different levels of
icon I want to have different levels of the documents for example if this one is
the documents for example if this one is a child of this one it has to be
a child of this one it has to be indented a bit that's what we're going
indented a bit that's what we're going to use uh the where is it we're that's
to use uh the where is it we're that's what we're going to use the style
what we're going to use the style padding left for so we're going to
padding left for so we're going to double the padding if this one is a
double the padding if this one is a child of this one and stuff like
child of this one and stuff like that let's head back into the item
that let's head back into the item component right here and first I'm going
component right here and first I'm going to do is I'm going to extend the props
to do is I'm going to extend the props that you can accept so I'm going to add
that you can accept so I'm going to add the ID prop which can be optional
the ID prop which can be optional because there are some items which we're
because there are some items which we're going to use like a button for a new
going to use like a button for a new page and some items which are going to
page and some items which are going to be actual documents so they're going to
be actual documents so they're going to have to have an ID because they're going
have to have an ID because they're going to be inside of a map function so you're
to be inside of a map function so you're going to have to add their ID right so
going to have to add their ID right so we know where to redirect and stuff like
we know where to redirect and stuff like that and that ID is going to be a type
that and that ID is going to be a type of ID from convex undor generated data
of ID from convex undor generated data model like this so make sure you import
model like this so make sure you import that right here I'm just going to
that right here I'm just going to separate it all right and the way you
separate it all right and the way you write ID is open pointy brackets and
write ID is open pointy brackets and just write documents you can see how we
just write documents you can see how we have type safety here besides an
have type safety here besides an optional ID we're also going to have an
optional ID we're also going to have an optional document icon which is a type
optional document icon which is a type of string and we're also going to have
of string and we're also going to have an active uh Boolean prop we're also
an active uh Boolean prop we're also going to have
going to have expanded we're also going to have is
expanded we're also going to have is search we're also going to have a level
search we're also going to have a level which is a number and we're also going
which is a number and we're also going to have have on expand so all of these
to have have on expand so all of these are optional because as you just saw we
are optional because as you just saw we just wrote when we created the first
just wrote when we created the first item uh we just created the basics is
item uh we just created the basics is going to need but all of this else is
going to need but all of this else is optional right but we are going to use
optional right but we are going to use them uh to render the list of items uh
them uh to render the list of items uh great so now that we have that let's
great so now that we have that let's also go ahead and add all of those
also go ahead and add all of those things here so we have an ID uh we have
things here so we have an ID uh we have a label let's go ahead uh and go below
a label let's go ahead uh and go below the icon and let's add the active prop
the icon and let's add the active prop let's go ahead and add the document icon
let's go ahead and add the document icon let's add the is search let's add the
let's add the is search let's add the level and let's give it a default
level and let's give it a default property of zero like this so even if we
property of zero like this so even if we don't pass it the default level is going
don't pass it the default level is going to be zero let's give it an on expand
to be zero let's give it an on expand and expand it great so now that we have
and expand it great so now that we have uh all of those um let's go ahead now
uh all of those um let's go ahead now and first thing I want to do is add the
and first thing I want to do is add the constant for Chevron icon so const
constant for Chevron icon so const Chevron icon is going to be a expanded
Chevron icon is going to be a expanded question mark sorry
question mark sorry expanded question mark
expanded question mark Chevron down from Lucid react otherwise
Chevron down from Lucid react otherwise Chevron right from Lucid react so just
Chevron right from Lucid react so just make sure you have Chevron down Chevron
make sure you have Chevron down Chevron right and Lucid icon from Lucid uh react
right and Lucid icon from Lucid uh react package great now that we have the
package great now that we have the Chevron icon we're going to use it to
Chevron icon we're going to use it to render that next to individual item so
render that next to individual item so it indicates to the user whether they
it indicates to the user whether they have expanded this item to see its
have expanded this item to see its children or not perfect now let's go
children or not perfect now let's go back inside of this div right here and
back inside of this div right here and let's change this padding left uh to be
let's change this padding left uh to be something more Dynamic here so as I said
something more Dynamic here so as I said we're going to use the level here so if
we're going to use the level here so if we have a level in that case what we are
we have a level in that case what we are going to do so let's leave this as an
going to do so let's leave this as an else clause and go inside of here and
else clause and go inside of here and open parenthesis sorry don't open
open parenthesis sorry don't open parenthesis open vtic like this and
parenthesis open vtic like this and inside we're going to render a special
inside we're going to render a special object where we're going to do level *
object where we're going to do level * 12 like that
12 like that plus 12 pixels like this so padding left
plus 12 pixels like this so padding left is going to check if we have an level
is going to check if we have an level and in that case it's going to multiply
and in that case it's going to multiply that level by 12 and it's going to add a
that level by 12 and it's going to add a 12 additional pixels which are these
12 additional pixels which are these initial 12 which we have right here if
initial 12 which we have right here if it doesn't have a level it's simply
it doesn't have a level it's simply going to have a petting of 12 as we had
going to have a petting of 12 as we had in the beginning so depending on the
in the beginning so depending on the level that each item is rendered it
level that each item is rendered it meaning how deep
meaning how deep or how deep of a nestly child it is of a
or how deep of a nestly child it is of a specific document that's how much we're
specific document that's how much we're going to push it to the left right
going to push it to the left right perfect so now that we have that let's
perfect so now that we have that let's go ahead and let's wrap this class name
go ahead and let's wrap this class name inside of curly brackets because we're
inside of curly brackets because we're going to make this dynamic as well and
going to make this dynamic as well and to do that we're going to use the CN
to do that we're going to use the CN util so make sure you import CN like I
util so make sure you import CN like I did right here and just open parenthesis
did right here and just open parenthesis and wrap the entire string inside of it
and wrap the entire string inside of it great and then you can just press enter
great and then you can just press enter like this so it's collapsed you can
like this so it's collapsed you can clear let see okay these are my default
clear let see okay these are my default classes and now let's add conditional
classes and now let's add conditional ones which is going to be our active
ones which is going to be our active prop so if we are active we're going to
prop so if we are active we're going to do BG - primary sl5 and text- primary
do BG - primary sl5 and text- primary great and now let's go ahead inside of
great and now let's go ahead inside of here and let's check if we have the ID
here and let's check if we have the ID so if we have the ID for that I'm going
so if we have the ID for that I'm going to use this uh double exclamation points
to use this uh double exclamation points and this is going to turn this into a
and this is going to turn this into a Boolean so it's going to be true or
Boolean so it's going to be true or false you can see when I hover it says
false you can see when I hover it says that I can be either the type of ID
that I can be either the type of ID documents or undefined but since I'm
documents or undefined but since I'm going to do a Turner check with it I
going to do a Turner check with it I have to turn it inside of a Boolean so
have to turn it inside of a Boolean so let's go ahead and do it like this and
let's go ahead and do it like this and in that case we're going to render a div
in that case we're going to render a div which is simply going to render the
which is simply going to render the Chevron
Chevron icon which is this constant which we
icon which is this constant which we defined right here so Chevron icon let's
defined right here so Chevron icon let's go ahead and just not misspell it like
go ahead and just not misspell it like this so it's this conditional one which
this so it's this conditional one which is going to show whether we expect
is going to show whether we expect expanded or not on this document and
expanded or not on this document and let's go ahead and give this div uh a
let's go ahead and give this div uh a roll of button and let's give it a class
roll of button and let's give it a class name of h- full rounded D small hover
name of h- full rounded D small hover vg- neutral D300 dark vg- neutral D600
vg- neutral D300 dark vg- neutral D600 and margin right of one uh great and
and margin right of one uh great and let's give it an on click option of
let's give it an on click option of handle expand actually let's go ahead
handle expand actually let's go ahead and let's just give it an empty Arrow
and let's just give it an empty Arrow function we don't have that handle
function we don't have that handle expand yet and inside of this Chevron
expand yet and inside of this Chevron icon let's go ahead and give it a class
icon let's go ahead and give it a class name of h-4 W-4
name of h-4 W-4 shrink shrink d0 and text-- foreground
shrink shrink d0 and text-- foreground sl50 great and now that we have this
sl50 great and now that we have this let's go ahead below that and let's add
let's go ahead below that and let's add a conditional icon so right now we
a conditional icon so right now we always render the icon which we send uh
always render the icon which we send uh in the icon prop right but we're going
in the icon prop right but we're going to make this a bit different
to make this a bit different so we're going to go ahead and open if
so we're going to go ahead and open if we have a document icon in that case
we have a document icon in that case we're going to go ahead and just render
we're going to go ahead and just render a div with that document icon and if
a div with that document icon and if you're wondering why can we render the
you're wondering why can we render the document icon like this but we had to do
document icon like this but we had to do the whole um renaming of the icon right
the whole um renaming of the icon right here well that's because this icon is a
here well that's because this icon is a type of uh Lucid icon as you can see but
type of uh Lucid icon as you can see but document icon is a type of string
document icon is a type of string because it's just going to be an emoji
because it's just going to be an emoji right so that's why we can just simply
right so that's why we can just simply render the document icon like this so if
render the document icon like this so if we have the icon we're going to render
we have the icon we're going to render that emoji which the user assigned for
that emoji which the user assigned for its document otherwise we're just going
its document otherwise we're just going to render a plain old icon which we
to render a plain old icon which we initially assigned great and let's go
initially assigned great and let's go ahead and give this div a class name of
ahead and give this div a class name of shrink d0 margin right two and text of
shrink d0 margin right two and text of 18 pixels like this great and now what I
18 pixels like this great and now what I want to do is I want to go uh below this
want to do is I want to go uh below this uh span right here and I'm going to
uh span right here and I'm going to check if this type of item is used for
check if this type of item is used for searching uh items so is search like
searching uh items so is search like that and inside we're going to do a kbd
that and inside we're going to do a kbd element and we're just going to render a
element and we're just going to render a span element right here and let's go
span element right here and let's go ahead and let's just render uh span like
ahead and let's just render uh span like sorry this command item like this and K
sorry this command item like this and K unfortunately I don't know what is the
unfortunately I don't know what is the shortcut for this little uh character if
shortcut for this little uh character if you want it you can just copy it from my
you want it you can just copy it from my source code or if you want to you can
source code or if you want to you can just write control
just write control or command like this so it doesn't
or command like this so it doesn't really matter right this is just you
really matter right this is just you know how it's going to look like there
know how it's going to look like there is no functionality behind this and
is no functionality behind this and let's go ahead and let's just give this
let's go ahead and let's just give this span a class name of text- extra small
span a class name of text- extra small and let's give this kbd a class name
and let's give this kbd a class name which is going to be a bit longer so ml
which is going to be a bit longer so ml AO
AO pointer-events
pointer-events dnone inline Dash Flex height of five
dnone inline Dash Flex height of five select Das none items Das Center g-1
select Das none items Das Center g-1 rounded border BG D muted like this
rounded border BG D muted like this we're also going to have uh padding on
we're also going to have uh padding on both sides from left and right to be
both sides from left and right to be 1.5 font is going to be mono text is
1.5 font is going to be mono text is going to be 10
going to be 10 pixels font is going to be medium and
pixels font is going to be medium and text is going to be muted Das foreground
text is going to be muted Das foreground and opacity well opacity is going to be
and opacity well opacity is going to be 100% but I don't think we actually need
100% but I don't think we actually need this uh great and now that we have that
this uh great and now that we have that uh well we're going to leave it at here
uh well we're going to leave it at here for now there's one more thing that we
for now there's one more thing that we have to create here but we're going to
have to create here but we're going to come to that a bit later and now that
come to that a bit later and now that we've wrote all of that code you're
we've wrote all of that code you're probably going to notice that well our
probably going to notice that well our uh new page has not changed much right
uh new page has not changed much right but let's see what else we can do now
but let's see what else we can do now with all of these new prop which we
with all of these new prop which we created so I'm going to go ahead back
created so I'm going to go ahead back inside of my navigation right here and
inside of my navigation right here and I'm just going to expand this so I can
I'm just going to expand this so I can still see my sidebar I'm going to find
still see my sidebar I'm going to find this item where I wrote new page and I'm
this item where I wrote new page and I'm going to go ahead and write an item
going to go ahead and write an item again but this time I'm going to give it
again but this time I'm going to give it a label of search I'm going to give it
a label of search I'm going to give it an icon of search from Lucid react so
an icon of search from Lucid react so make sure you import that from Lucid
make sure you import that from Lucid react right here I'm going to give it a
react right here I'm going to give it a prop is search I'm going to give it an
prop is search I'm going to give it an on click which for now is just going to
on click which for now is just going to be an empty AR function and as you can
be an empty AR function and as you can see now let me just zoom in you can see
see now let me just zoom in you can see how because I I wrote that is search
how because I I wrote that is search thing we now have a nice little shortcut
thing we now have a nice little shortcut so the user knows in the future we don't
so the user knows in the future we don't have that yet but in the future user
have that yet but in the future user will either be able to click here to
will either be able to click here to search through all of the documents or
search through all of the documents or they'll be able to use a shortcut
they'll be able to use a shortcut command key or if you're in Windows it's
command key or if you're in Windows it's going to be control key right so let I
going to be control key right so let I just want to make this capitalized right
just want to make this capitalized right here I think it's going to look a bit
here I think it's going to look a bit better uh if I do do that so let me just
better uh if I do do that so let me just go back
go back inside my item and let me find the K
inside my item and let me find the K right here I'm just going to make it
right here I'm just going to make it capital K because I just think it looks
capital K because I just think it looks a little bit better there we go so you
a little bit better there we go so you can see how now I have this search right
can see how now I have this search right here and I have a little shortcut for it
here and I have a little shortcut for it here currently it has no functionality
here currently it has no functionality perfect so now what we're going to do is
perfect so now what we're going to do is we're going to finally uh render this
we're going to finally uh render this list of items here but before we do that
list of items here but before we do that uh one thing that I'm going to do is
uh one thing that I'm going to do is just add one more function between these
just add one more function between these actions which is still going to be a
actions which is still going to be a dummy function so go back inside the
dummy function so go back inside the navigation and go ahead and copy this
navigation and go ahead and copy this search and rename this to settings
search and rename this to settings remove the is search prop and give this
remove the is search prop and give this an icon of
an icon of settings also from Lucid react so let me
settings also from Lucid react so let me just see everything we need from Lucid
just see everything we need from Lucid react is chevron's left menu icon plus
react is chevron's left menu icon plus Circle search and
Circle search and settings great so now that we have that
settings great so now that we have that uh you should
uh you should see you should be seeing uh a new item
see you should be seeing uh a new item here so search settings a new page the
here so search settings a new page the only one that's functional is the new
only one that's functional is the new page right and now we're finally ready
page right and now we're finally ready to create our new component which is
to create our new component which is going to be called document list which
going to be called document list which is going to be a recursive component
is going to be a recursive component which is going to call itself every time
which is going to call itself every time you expand on a user so it's going to be
you expand on a user so it's going to be a very complex function and you're going
a very complex function and you're going to learn how to write recursive uh
to learn how to write recursive uh documents recursive react components in
documents recursive react components in this one and we're going to leverage uh
this one and we're going to leverage uh our schema which has the uh parent
our schema which has the uh parent document it's going to be very
document it's going to be very interesting to see how that's going to
interesting to see how that's going to work great job so
work great job so far so now let's go ahead and let's
far so now let's go ahead and let's create a new API endpoint which is
create a new API endpoint which is actually going to be used for recursive
actually going to be used for recursive calling uh for this sidebar right here
calling uh for this sidebar right here so first I have an error in navigation
so first I have an error in navigation let me just see what that is oh I have
let me just see what that is oh I have trailing white space so let me just fix
trailing white space so let me just fix all of those trunk is helping us with
all of those trunk is helping us with code quality here great and and now
code quality here great and and now let's go ahead and let's go inside of
let's go ahead and let's go inside of convex let's go inside of documents uh
convex let's go inside of documents uh right here and I'm going to go ahead and
right here and I'm going to go ahead and remove this get from here instead we're
remove this get from here instead we're going to write a new one so expert const
going to write a new one so expert const get
get sidebar is going to be a query it's
sidebar is going to be a query it's going to have arguments of parent
going to have arguments of parent document which is going to be an
document which is going to be an optional value and if it is passed it's
optional value and if it is passed it's going to have to be an ID of
going to have to be an ID of documents besides arguments we're also
documents besides arguments we're also going to have a Handler which is an
going to have a Handler which is an asynchronous function which takes in the
asynchronous function which takes in the context and the arguments which we
context and the arguments which we passed
passed above and now let's go ahead and let's
above and now let's go ahead and let's get our logged in identity so const
get our logged in identity so const identity is equal to
identity is equal to await context. out.get user identity if
await context. out.get user identity if we don't have the identity we cannot
we don't have the identity we cannot fetch this documents so let's throw new
fetch this documents so let's throw new error not authenticated and I just look
error not authenticated and I just look it shouldn't be normalized error it
it shouldn't be normalized error it should just be
should just be throw new error like this great and now
throw new error like this great and now let's extract the user ID so const user
let's extract the user ID so const user ID is
ID is identity identity.
identity identity. subject and now let's go ahead and let's
subject and now let's go ahead and let's fetch the documents but we're going to
fetch the documents but we're going to do that using this indexes we have the
do that using this indexes we have the index by user and by parent so we have
index by user and by parent so we have faster in here so let's go ahead and
faster in here so let's go ahead and write con documents to be await context.
write con documents to be await context. databasequery
documents do with index the index we're going to use is by
index the index we're going to use is by user
user parent let's go ahead and get the query
parent let's go ahead and get the query function
function here and now you can write all of this
here and now you can write all of this in one line but I just collapsed it so
in one line but I just collapsed it so you can see so I did not open anything
you can see so I did not open anything here I just added a new line here and
here I just added a new line here and let's let's write
let's let's write Q dot
Q dot equals user ID should be the currently
equals user ID should be the currently logged in user ID and it also equals the
logged in user ID and it also equals the parent
parent document to be equal arguments. parent
document to be equal arguments. parent document which if not passed it's just
document which if not passed it's just going to be undefined and now let's also
going to be undefined and now let's also add a filter here let's also get the Q
add a filter here let's also get the Q for query and again I'm just going to
for query and again I'm just going to press a space here and let's write query
press a space here and let's write query equals query do field is archived is
equals query do field is archived is going to be false so we don't want to
going to be false so we don't want to show any of the deleted documents or in
show any of the deleted documents or in our case archived and let's order all of
our case archived and let's order all of those documents by
those documents by descending and lastly let's collect them
descending and lastly let's collect them like that and now we can just return
like that and now we can just return documents there we go and I have a
documents there we go and I have a trailing wi space here so let me just
trailing wi space here so let me just remove that space and there we go
remove that space and there we go perfect we have our get sidebar function
perfect we have our get sidebar function function now and now let's go back
function now and now let's go back inside of the navigation component so
inside of the navigation component so it's located inside of the app folder
it's located inside of the app folder mainor components navigation and from
mainor components navigation and from here we can now remove the used query
here we can now remove the used query from the convex react we don't need it
from the convex react we don't need it and that means we can also remove this
and that means we can also remove this documents use Query we no longer need
documents use Query we no longer need that as well and we can also remove uh
that as well and we can also remove uh this as well we don't
this as well we don't needed so now that I removed this
needed so now that I removed this document list I just want to show you a
document list I just want to show you a little trick so if you if you're using
little trick so if you if you're using trunk right we at the beginning of the
trunk right we at the beginning of the tutorial we we installed an extension
tutorial we we installed an extension called trunk right here so as you can
called trunk right here so as you can see because of it we have this improved
see because of it we have this improved code quality where it says that I have
code quality where it says that I have trailing whites space here and usually I
trailing whites space here and usually I fix that by deleting it manually myself
fix that by deleting it manually myself but if you want to you can also go ahead
but if you want to you can also go ahead and press command shift p or control
and press command shift p or control shift p and go ahead and uh write
shift p and go ahead and uh write settings and select the UI option right
settings and select the UI option right this and you can search for format on
this and you can search for format on Save and you can enable this and then
Save and you can enable this and then when you save there we go you can see
when you save there we go you can see how the entire thing is formatted right
how the entire thing is formatted right but I'm not going to use that for the
but I'm not going to use that for the tutorial because it changes just too
tutorial because it changes just too much of the files so every time that I
much of the files so every time that I do something like this you're going to
do something like this you're going to see me uh do it manually so let me just
see me uh do it manually so let me just go ahead and find uh where I rendered
go ahead and find uh where I rendered this there we go right here so I have
this there we go right here so I have the trailing wi space I'm just going to
the trailing wi space I'm just going to remove it great all right and now inside
remove it great all right and now inside of here let's go and save this and let's
of here let's go and save this and let's go inside of the documents file sorry
go inside of the documents file sorry inside of the item file so item right
inside of the item file so item right here and go ahead all the way to the
here and go ahead all the way to the bottom and let's add a skeleton for this
bottom and let's add a skeleton for this one so item. skeleton is going to be a
one so item. skeleton is going to be a function item
function item skeleton it's going to accept a prop
skeleton it's going to accept a prop level which is going to be an optional
level which is going to be an optional number and and let's just not call this
number and and let's just not call this uh item SK on like this great and inside
uh item SK on like this great and inside just return a div like this and go ahead
just return a div like this and go ahead and give it a
and give it a style padding left if it has a level
style padding left if it has a level open back Tex and write level * 12 plus
open back Tex and write level * 12 plus 25 pixels because this is uh going to be
25 pixels because this is uh going to be a different element so uh we have to
a different element so uh we have to modify just a little bit otherwise it's
modify just a little bit otherwise it's just going to be plain old 12 pixels all
just going to be plain old 12 pixels all right and inside of it we're going to
right and inside of it we're going to render some skeletons so first let's go
render some skeletons so first let's go Ahad had inside of our terminal let me
Ahad had inside of our terminal let me open a new one and just write npx shat
open a new one and just write npx shat cn- at latest add
cn- at latest add skeleton like this just add a skeleton
skeleton like this just add a skeleton component great and now inside we can go
component great and now inside we can go ahead and render this skeleton component
ahead and render this skeleton component from at/ components UI skeleton so and
from at/ components UI skeleton so and it's going to be a self- closing tag
it's going to be a self- closing tag right so just self close it and make
right so just self close it and make sure you import skeleton from at/
sure you import skeleton from at/ components UI skeleton great and go
components UI skeleton great and go ahead and write a class name here h-4
ahead and write a class name here h-4 W-4 and go ahead and copy it and write
W-4 and go ahead and copy it and write this one to be
this one to be 30% like that and go ahead and give this
30% like that and go ahead and give this a class name of flex Gap
a class name of flex Gap dx-2 padding U bottom and top of three
dx-2 padding U bottom and top of three pixels great so now we have the skeleton
pixels great so now we have the skeleton now let's go back inside of the
now let's go back inside of the navigation right here and let's render
navigation right here and let's render the document list component which we
the document list component which we currently don't have but we're going to
currently don't have but we're going to have it in just a moment so great save
have it in just a moment so great save this file and you should get an error
this file and you should get an error now go inside of the underscore
now go inside of the underscore components and create a new file
components and create a new file document dl. DSX perfect go ahead and
document dl. DSX perfect go ahead and Mark this as use
client and now what we're going to do is we're simply going to export document
we're simply going to export document list export
list export con document
con document list return div document list like this
list return div document list like this go back inside of the navigation and you
go back inside of the navigation and you can just import the document list from
can just import the document list from uh _ document list great and now that
uh _ document list great and now that you have this let's go ahead and let's
you have this let's go ahead and let's create an
create an interface document list props parent
interface document list props parent document
document ID is going to be an optional ID from at
ID is going to be an optional ID from at ATC convex generated data model a type
ATC convex generated data model a type of documents like that besides the
of documents like that besides the parent document ID we're going to have a
parent document ID we're going to have a level because remember this is going to
level because remember this is going to be a recursive function and we're going
be a recursive function and we're going to have data which is going to be a type
to have data which is going to be a type of the document schema so for that we
of the document schema so for that we can use the doc from uh very same import
can use the doc from uh very same import right here and the doc is going to be a
right here and the doc is going to be a type of documents as well and it's going
type of documents as well and it's going to be an array of those great so let's
to be an array of those great so let's go ahead and extract this props here so
go ahead and extract this props here so parent document ID and level which by
parent document ID and level which by default is is going to be zero and we
default is is going to be zero and we don't need to render data here you're
don't need to render data here you're going to see why in a second uh all
going to see why in a second uh all right and let's just assign this props
right and let's just assign this props so document list
so document list props like that and now let's go ahead
props like that and now let's go ahead and let's get our params from use params
and let's get our params from use params from next SL navigation so just make
from next SL navigation so just make sure you add this import all right
sure you add this import all right besides the params we're also going to
besides the params we're also going to have router so use router from next SL
have router so use router from next SL navigation
navigation all right we have that now uh and now
all right we have that now uh and now let's go ahead and let's write const
let's go ahead and let's write const expanded set
expanded set expanded to be use
expanded to be use State and give it an empty fun empty
State and give it an empty fun empty object inside and let's import use state
object inside and let's import use state from react I'm just going to move that
from react I'm just going to move that to the top as well and we're going to
to the top as well and we're going to give a type of this use state to be a
give a type of this use state to be a record which takes in the string and a
record which takes in the string and a Boolean like that perfect and now let's
Boolean like that perfect and now let's write a function on expand
write a function on expand so const on expand it's going to take
so const on expand it's going to take the current document ID which we are
the current document ID which we are trying to expand and all it's going to
trying to expand and all it's going to do is set
do is set expanded prev
expanded add all the previous expanded documents and find the individual
documents and find the individual document ID which we are trying to
document ID which we are trying to expand and just toggle the function so
expand and just toggle the function so the opposite of the current state of
the opposite of the current state of document ID inside of the extended
document ID inside of the extended function
function great and now let's go ahead and let's
great and now let's go ahead and let's uh add a query for our get sidebar API
uh add a query for our get sidebar API which we just created so cons documents
which we just created so cons documents is going to be use Query let's go ahead
is going to be use Query let's go ahead and let's import use
and let's import use Query so import use Query from convex SL
Query so import use Query from convex SL react all right and inside let's render
react all right and inside let's render the API and I imported API from convex
the API and I imported API from convex generated
generated API and let's write API i. do.get
API and let's write API i. do.get sidebar like this and let's go ahead and
sidebar like this and let's go ahead and pass in some
pass in some props so we're going to passing the
props so we're going to passing the parent document to the parent document
parent document to the parent document ID from our props right here great and
ID from our props right here great and now let's go ahead and let's write the
now let's go ahead and let's write the on redirect function so const on
on redirect function so const on redirect is going to take in the
redirect is going to take in the document ID which is a type of string
document ID which is a type of string and router. push SL documents the
and router. push SL documents the individual document ID we currently
individual document ID we currently don't have this route but we're going to
don't have this route but we're going to have it in the future perfect so now
have it in the future perfect so now let's go ahead and let's render the
let's go ahead and let's render the loading function so when using convex uh
loading function so when using convex uh it will never be undefined unless it's
it will never be undefined unless it's loading so we're going to do a check for
loading so we're going to do a check for that so if documents is undefined that
that so if documents is undefined that can only mean that it's loading if it's
can only mean that it's loading if it's truly failed or wasn't able to find
truly failed or wasn't able to find anything is going to be null right but
anything is going to be null right but you can use the UN defined state to
you can use the UN defined state to activate the loading state so let's
activate the loading state so let's write
write return let's open a fragment and let's
return let's open a fragment and let's go ahead and import the item component
go ahead and import the item component from do/ item so make sure you add the
from do/ item so make sure you add the item like this and since we just added
item like this and since we just added this little skeleton to it we can now
this little skeleton to it we can now use that as our loading state so item do
use that as our loading state so item do skeleton like this and let's give it a
skeleton like this and let's give it a level of level like that and then let's
level of level like that and then let's go ahead and let's write if level is
go ahead and let's write if level is equal to
equal to zero in that that case let's go ahead
zero in that that case let's go ahead and render another fragment here with
and render another fragment here with two item skeletons so let me just close
two item skeletons so let me just close this fragment like this and you can just
this fragment like this and you can just go ahead and copy and paste
go ahead and copy and paste this two times like that perfect so now
this two times like that perfect so now we have our loading State here and now
we have our loading State here and now we're finally ready uh to render this
we're finally ready uh to render this list so change this to be a
list so change this to be a fragment and let's write the first
fragment and let's write the first paragraph here which is going to write
paragraph here which is going to write no Pages inside so this is going to be
no Pages inside so this is going to be if we click expand a document which has
if we click expand a document which has no children so go ahead and give this a
no children so go ahead and give this a style ping left if we have a level in
style ping left if we have a level in that case open back and write level *
that case open back and write level * 12+ 25 pixels or
12+ 25 pixels or undefined like that and we're also going
undefined like that and we're also going to have a class name here so class name
to have a class name here so class name is going to be CN from add/ Li utils so
is going to be CN from add/ Li utils so make sure you add that as well
make sure you add that as well so
so CN go ahead and write hidden text small
CN go ahead and write hidden text small font D medium text- muted D foreground
font D medium text- muted D foreground sl80 if it's expanded in that case go
sl80 if it's expanded in that case go ahead and give it a class of last block
ahead and give it a class of last block otherwise if level is zero go ahead and
otherwise if level is zero go ahead and render
render hidden all right so this is going to use
hidden all right so this is going to use CSS to detect if the if this is the only
CSS to detect if the if this is the only element inside of this entire fragment
element inside of this entire fragment that means that there are no other
that means that there are no other documents rendered and we can safely uh
documents rendered and we can safely uh display it right but if it's not last in
display it right but if it's not last in that case it's going to be hidden by
that case it's going to be hidden by default all right and now when we are
default all right and now when we are below that let's go ahead and render our
below that let's go ahead and render our documents so documents. map get
documents so documents. map get individual
individual document and let's go ahead uh and let's
document and let's go ahead uh and let's write a div with a key of document doore
write a div with a key of document doore whoops document _
whoops document _ ID and inside let's render the item
ID and inside let's render the item element and let's go ahead and let's
element and let's go ahead and let's give this it item and ID of document
give this it item and ID of document doore ID let's give it an on click
doore ID let's give it an on click function to Be an Arrow function which
function to Be an Arrow function which calls on redirect function and calls the
calls on redirect function and calls the document. ID inside so it knows what to
document. ID inside so it knows what to redirect to a label is going to be
redirect to a label is going to be document.title
document.title Icon by default is going to be file icon
Icon by default is going to be file icon from Lucid react so make sure you import
from Lucid react so make sure you import a file icon from Lucid
a file icon from Lucid react all right and now let's go ahead
react all right and now let's go ahead and let's edit a document icon of
and let's edit a document icon of document.
document. Icon let's give it an active prop of
Icon let's give it an active prop of pam. document ID to be identical of
pam. document ID to be identical of document doore ID level is going to be
document doore ID level is going to be level on expand is going to be an arrow
level on expand is going to be an arrow function which calls on expand
function which calls on expand documentor
documentor ID expanded is going to be expanded
ID expanded is going to be expanded documentor ID so we're going to check
documentor ID so we're going to check inside of that object and now we're
inside of that object and now we're going to do the recursive trick so in
going to do the recursive trick so in see every item can have children on its
see every item can have children on its own guess what component we're going to
own guess what component we're going to use for that well this component that we
use for that well this component that we are writing right now we're going to
are writing right now we're going to reuse the entire thing so what we can do
reuse the entire thing so what we can do is call this component document list it
is call this component document list it doesn't matter that we are writing
doesn't matter that we are writing inside of it we can call it inside but
inside of it we can call it inside but we're going to conditionally call it so
we're going to conditionally call it so we don't fall into an infinite Loop so
we don't fall into an infinite Loop so let's write if this element is expanded
let's write if this element is expanded so if expanded object which we hold in
so if expanded object which we hold in our state holds the document ID and the
our state holds the document ID and the value is true in that case we're going
value is true in that case we're going to render the entire document list which
to render the entire document list which we are just now creating and let's give
we are just now creating and let's give it a parent document of
it a parent document of document underscore ID and let's it a
document underscore ID and let's it a level of level + one like this perfect
level of level + one like this perfect so now that we have that let's go ahead
so now that we have that let's go ahead uh and let's check if that is enough for
uh and let's check if that is enough for us to actually see something and there
us to actually see something and there we go look at all of my items here
we go look at all of my items here perfect right now the expand function is
perfect right now the expand function is not working as you can clearly see and
not working as you can clearly see and when I click on any of these documents I
when I click on any of these documents I lead to a 404 because we don't because
lead to a 404 because we don't because uh we don't have that page yet but if
uh we don't have that page yet but if you look create a new note you can see
you look create a new note you can see how it's immediately
how it's immediately right here at the bottom perfect so
right here at the bottom perfect so that's exactly what we wanted what I
that's exactly what we wanted what I want to do now is an option to delete a
want to do now is an option to delete a document to create a new document and to
document to create a new document and to actually expand documents when we click
actually expand documents when we click here instead of redirect to
here instead of redirect to them so let's go ahead and quickly fix
them so let's go ahead and quickly fix this unexpanded thing so go back inside
this unexpanded thing so go back inside the item. DSX right here and let's go
the item. DSX right here and let's go ahead and write a function here so I'm
ahead and write a function here so I'm going to do it above this Chevron icon
going to do it above this Chevron icon uh const handle
uh const handle expand and it's going to take an event
expand and it's going to take an event which is a type of react. mouse event
which is a type of react. mouse event which comes from HTML div
which comes from HTML div element and has a mouse event inside
element and has a mouse event inside it's an arrow function and all it's
it's an arrow function and all it's going to do is prevent the propagation
going to do is prevent the propagation from it and then it's going to hold on
from it and then it's going to hold on expand but since it's optional we're
expand but since it's optional we're going to add a question mark Dot and
going to add a question mark Dot and then execute the function and then add
then execute the function and then add this handle EXP p uh and let's see where
this handle EXP p uh and let's see where we have to assign it uh let me just find
we have to assign it uh let me just find there we go it's right here so find this
there we go it's right here so find this uh ID tary right here and this Chevron
uh ID tary right here and this Chevron icon and we have this on click right
icon and we have this on click right here and just add it here there we go
here and just add it here there we go and let's see how that looks now so I'm
and let's see how that looks now so I'm going to refresh and now when I click
going to refresh and now when I click here you can see how it says no Pages
here you can see how it says no Pages inside isn't this really really cool
inside isn't this really really cool because none of these items have any
because none of these items have any children inside of it but now we're
children inside of it but now we're going to create a little plus icon here
going to create a little plus icon here which is going to allow us to create a
which is going to allow us to create a new document
new document inside let's head back inside of our
inside let's head back inside of our item
item component and let's go all the way to
component and let's go all the way to the bottom where we render this search
the bottom where we render this search thing and go below that and go ahead and
thing and go below that and go ahead and add another uh check if we have an ID
add another uh check if we have an ID and if we have an ID go ahead and render
and if we have an ID go ahead and render a div which is going to hold two actions
a div which is going to hold two actions one to add a child inside of of that
one to add a child inside of of that document and the other is going to be a
document and the other is going to be a drop down where we can delete the
drop down where we can delete the document so write ml- aouto Flex items D
document so write ml- aouto Flex items D Center and GAP
Center and GAP dx-2 and now inside let's go ahead and
dx-2 and now inside let's go ahead and let's create another div which is going
let's create another div which is going to render the plus icon from Lucid react
to render the plus icon from Lucid react so make sure you add this plus from
so make sure you add this plus from Lucid react here and go ahead and give
Lucid react here and go ahead and give this plus a class name of h-4 W-4 and
this plus a class name of h-4 W-4 and text- muted D4 ground and give this div
text- muted D4 ground and give this div a class name of opacity -0
a class name of opacity -0 group-
group- hover
hover opacity 100 h- full ml- AO rounded Das
opacity 100 h- full ml- AO rounded Das small on Hover BG is going to be neutral
small on Hover BG is going to be neutral D300 but on dark hover BG is going to be
D300 but on dark hover BG is going to be neutral
neutral D600 so just make sure that when we do
D600 so just make sure that when we do this group hover
this group hover we actually have a group inside of our
we actually have a group inside of our main div and we do right here so when we
main div and we do right here so when we hover on the item only then are this
hover on the item only then are this additional actions going to show so
additional actions going to show so let's see that now you can see no plus
let's see that now you can see no plus icon now but when I hover you can see I
icon now but when I hover you can see I have a little plus icon here and it's
have a little plus icon here and it's only visible on the one I'm currently
only visible on the one I'm currently looking at perfect so now let's actually
looking at perfect so now let's actually create an action that when we click on
create an action that when we click on this we don't get redirected but instead
this we don't get redirected but instead a child document is created so let's go
a child document is created so let's go ahead and let's create that function so
ahead and let's create that function so I'm going to go ahead to the top here
I'm going to go ahead to the top here just below the handle expand and let's
just below the handle expand and let's write const on create which is again
write const on create which is again going to take an event which has react.
mouseevent HTML div element and mouse
event and let's go ahead and check if we don't have an ID we can just break the
don't have an ID we can just break the function otherwise let's go ahead and
function otherwise let's go ahead and let's create a mutation so in order to
let's create a mutation so in order to create the mutation first thing we have
create the mutation first thing we have to do is add it right here to the top so
to do is add it right here to the top so let's write con create to be used
let's write con create to be used mutation and let's go ahead and import
mutation and let's go ahead and import use mutation from convex react so import
use mutation from convex react so import use mutation from convex SL react and
use mutation from convex SL react and let's go ahead and add our API from
let's go ahead and add our API from convex generated there we go so API from
convex generated there we go so API from convex generated API make sure you have
convex generated API make sure you have that and then api. documents. create
that and then api. documents. create like this perfect and now we can go
like this perfect and now we can go ahead and continue with our own create
ahead and continue with our own create function here at the bottom so let's go
function here at the bottom so let's go ahead and add a promise const
ahead and add a promise const promise is going to be the create
promise is going to be the create function the title is going to be as
function the title is going to be as always Untitled but this time we're
always Untitled but this time we're going to pass in the parent document to
going to pass in the parent document to be the ID of the current item which we
be the ID of the current item which we are doing this in so we want to create a
are doing this in so we want to create a child with the parent to be this ID
child with the parent to be this ID perfect and now that we have that let's
perfect and now that we have that let's write dot
write dot then let's get the individual document
then let's get the individual document ID if we are not expanded in that case
ID if we are not expanded in that case call the on expand optional function
call the on expand optional function like
like this and
this and router. push we don't have the router so
router. push we don't have the router so let's just quickly add the router here
let's just quickly add the router here const router
const router use
use router from next SL navigation make sure
router from next SL navigation make sure you import use router from
you import use router from here all right and now let's go ahead
here all right and now let's go ahead and just write router.
push documents document
documents document ID like that perfect and now let's go
ID like that perfect and now let's go ahead and let's add our toast from the
ahead and let's add our toast from the soner package so I'm going to go here
soner package so I'm going to go here and import toast from
and import toast from sonor and now we can do toast. promise
sonor and now we can do toast. promise passing the promise which we just
passing the promise which we just created a couple of lines above here and
created a couple of lines above here and as always let's give it some states so
as always let's give it some states so loading state is going to be creating
loading state is going to be creating creating oops creating a new
creating oops creating a new note success state is going to be new
note success state is going to be new note created and error state is going to
note created and error state is going to be fail to create a new
be fail to create a new note and now that we have this on create
note and now that we have this on create right here let's go ahead and let's
right here let's go ahead and let's assign it to this new uh div which uh
assign it to this new uh div which uh should have the roll
should have the roll button and on
button and on click to be on create like this and one
click to be on create like this and one thing that I'm just going to quickly do
thing that I'm just going to quickly do I'm going to go back to this uh on
I'm going to go back to this uh on create function uh and oh I forgot to
create function uh and oh I forgot to stop propagation here so let's just do
stop propagation here so let's just do event. stop propagation while we're here
event. stop propagation while we're here and let's also just comment out this
and let's also just comment out this router. push because all it's going to
router. push because all it's going to do right now is show a 404 page right so
do right now is show a 404 page right so let's just hide that and now let's go
let's just hide that and now let's go ahead and try this out so I'm going to
ahead and try this out so I'm going to refresh
refresh everything I'm going to go ahead and
everything I'm going to go ahead and click on plus here and look at this I
click on plus here and look at this I can do this infinitely we successfully
can do this infinitely we successfully have children and you can close them you
have children and you can close them you can open it and you can see how it
can open it and you can see how it dynamically loads them inside and you
dynamically loads them inside and you can expand the screen right here and you
can expand the screen right here and you can see how now you have more space to
can see how now you have more space to work with you can create as many of
work with you can create as many of these nested documents as you want
these nested documents as you want amazing amazing job and you can collapse
amazing amazing job and you can collapse each and every one of them you can try
each and every one of them you can try and play around just don't spam too much
and play around just don't spam too much you know these are recursive functions
you know these are recursive functions and you don't want to create too much
and you don't want to create too much band with uh on your conx account uh
band with uh on your conx account uh great amazing amazing job and now that
great amazing amazing job and now that we have this plus I icon it's time for
we have this plus I icon it's time for us to actually create additional actions
us to actually create additional actions to delete the uh entire document and
to delete the uh entire document and then we're going to create a little
then we're going to create a little Trash Can where we can restore all the
Trash Can where we can restore all the archived
archived elements so now let's go ahead and let's
elements so now let's go ahead and let's create additional actions next to this
create additional actions next to this plus icon which is going to be used for
plus icon which is going to be used for soft deleting or archiving a specific
soft deleting or archiving a specific document so the first thing I want to do
document so the first thing I want to do is I want to go back inside of our
is I want to go back inside of our convex folder inside of the documents.
convex folder inside of the documents. Cs right here and inside we're going to
Cs right here and inside we're going to go ahead and we're going to add a new
go ahead and we're going to add a new API endpoint here called archive so
API endpoint here called archive so let's go ahead and write export con
let's go ahead and write export con archive which is going to be uh not a
archive which is going to be uh not a query my apologies is going to be a
query my apologies is going to be a mutation which is going to accept
mutation which is going to accept arguments of ID which is a type of v. ID
arguments of ID which is a type of v. ID documents besides arguments is also
documents besides arguments is also going to have a Handler which has the uh
going to have a Handler which has the uh which is an asynchronous function after
which is an asynchronous function after all and it holds the context and the
all and it holds the context and the arguments which we passed above so first
arguments which we passed above so first things first let's go ahead and let's
things first let's go ahead and let's get the identity we can just copy that
get the identity we can just copy that from this right here and let's also
from this right here and let's also immediately extract the user ID so I'll
immediately extract the user ID so I'll just copy and paste that here so we save
just copy and paste that here so we save some time and now let's go ahead and
some time and now let's go ahead and let's attempt to fetch the document
let's attempt to fetch the document using this ID so let's write const
using this ID so let's write const existing document to be await context.
existing document to be await context. database. get arguments. ID and if there
database. get arguments. ID and if there is no existing document in that case we
is no existing document in that case we can just go ahead and throw new error
can just go ahead and throw new error which is going to say not
which is going to say not found and then let's go ahead and check
found and then let's go ahead and check if the user ID of the existing document
if the user ID of the existing document so this user ID which we have in our
so this user ID which we have in our schema is matching the currently logged
schema is matching the currently logged in user ID because if it's not we cannot
in user ID because if it's not we cannot modify this document right so let's go
modify this document right so let's go ahead and write if existing document.
ahead and write if existing document. user ID
user ID is not identical to the current user ID
is not identical to the current user ID which we just extracted from the
which we just extracted from the identity subject let's go ahead and
identity subject let's go ahead and throw new
throw new error unauthorized so it's not that we
error unauthorized so it's not that we are not uh not authenticated is that we
are not uh not authenticated is that we are unauthorized to modify that document
are unauthorized to modify that document and now that we have that let's go ahead
and now that we have that let's go ahead and let's change uh the document so
and let's change uh the document so const document await context. database.
const document await context. database. patch
patch ARS doid so that's the one we want to
ARS doid so that's the one we want to patch and the only thing we're going to
patch and the only thing we're going to change is is archive to be
change is is archive to be true but there is one more thing that we
true but there is one more thing that we need here so for now we can just return
need here so for now we can just return the document but what we actually need
the document but what we actually need to happen is that when we archive uh a
to happen is that when we archive uh a specific document we also want to check
specific document we also want to check for all of its children right if I
for all of its children right if I archive the parent I expect that all the
archive the parent I expect that all the children are archived as well because
children are archived as well because well you can know decide the logic for
well you can know decide the logic for yourself but this is what notion does so
yourself but this is what notion does so I'm just trying to stay true to the
I'm just trying to stay true to the original and it kind of makes sense
original and it kind of makes sense because this ones should not exist
because this ones should not exist without the parent itself and you might
without the parent itself and you might be thinking well it's unconvenient that
be thinking well it's unconvenient that my uh children get uh deleted as well
my uh children get uh deleted as well but think of it in another way what if
but think of it in another way what if you want to get rid of all these things
you want to get rid of all these things right it will be annoying that you have
right it will be annoying that you have to go individually and delete everyone
to go individually and delete everyone it will be nice that we can just delete
it will be nice that we can just delete the parent and then everyone everyone
the parent and then everyone everyone else will get deleted as well so that's
else will get deleted as well so that's what we're going to use that logic for
what we're going to use that logic for it so besides editing this document by
it so besides editing this document by ID we need to create a recursive
ID we need to create a recursive function which is going to go ahead and
function which is going to go ahead and try and fetch the parent of each
try and fetch the parent of each document and see uh and recurs delete
document and see uh and recurs delete all the children of this document so
all the children of this document so let's go ahead and let's write const
let's go ahead and let's write const recursive archive inside of this
recursive archive inside of this function just above this patch function
function just above this patch function which is going to be an asynchronous
which is going to be an asynchronous function and it's going to accept
function and it's going to accept document
document ID which is a type of ID
ID which is a type of ID documents and you can get this ID from
documents and you can get this ID from our _ generated data model right here
our _ generated data model right here perfect so now that we have that let's
perfect so now that we have that let's go ahead inside and let's go ahead and
go ahead inside and let's go ahead and fetch the children so con children is
fetch the children so con children is await context.
await context. databasequery
documents with index so we're going to use index for faster search here by user
use index for faster search here by user and by parent let's go ahead and let's
and by parent let's go ahead and let's get the
get the query and let's go ahead and write query
query and let's go ahead and write query do equals user ID to be user ID and
do equals user ID to be user ID and equals parent
equals parent document to be document ID which we pass
document to be document ID which we pass in the recursive function and lastly
in the recursive function and lastly let's just go ahead uh and let's write
let's just go ahead uh and let's write do
do collect like that perfect and now that
collect like that perfect and now that we have that we have to create a for
we have that we have to create a for Loop which is going to to iterate over
Loop which is going to to iterate over all of that children and repeat the same
all of that children and repeat the same function you might be wondering well why
function you might be wondering well why are we not not using a for each or map
are we not not using a for each or map well that's because we're going to do a
well that's because we're going to do a promise inside of that so if you if
promise inside of that so if you if you're familiar with that map and for
you're familiar with that map and for each you know that they cannot do
each you know that they cannot do promises inside of them you cannot do
promises inside of them you cannot do asyn a weight inside of a four four each
asyn a weight inside of a four four each or map for that you have to use the good
or map for that you have to use the good old for Loop so let's write it manually
old for Loop so let's write it manually for constant child of
for constant child of children we're going to do a wait
children we're going to do a wait context. database. patch Child ID is
context. database. patch Child ID is archived true like that so we're going
archived true like that so we're going to get all the children from this
to get all the children from this document and we're going to Archive them
document and we're going to Archive them as well perfect and let me just fix the
as well perfect and let me just fix the uh which errors do I have here it says
uh which errors do I have here it says trailing wi space but we're going to
trailing wi space but we're going to continue developing right now just to
continue developing right now just to see see uh if it's something else great
see see uh if it's something else great so after this we're going to go ahead
so after this we're going to go ahead and rerun the entire function gate so
and rerun the entire function gate so await recursive archive Child undor ID
await recursive archive Child undor ID so we create a loop here there we go so
so we create a loop here there we go so no more errors here so let's take a look
no more errors here so let's take a look at what we do again so in our uh archive
at what we do again so in our uh archive function what we do is we pass the
function what we do is we pass the argument ID so this is the ID of the
argument ID so this is the ID of the document we want to delete or in our
document we want to delete or in our case archive we check the identity and
case archive we check the identity and we attempt to fetch that parent document
we attempt to fetch that parent document which we trying to delete if it doesn't
which we trying to delete if it doesn't exist we throw a not found if the
exist we throw a not found if the matching user ID is not true in that
matching user ID is not true in that case we are unauthorized to modify this
case we are unauthorized to modify this now let's jump over this quickly and
now let's jump over this quickly and then what we do is we archive that
then what we do is we archive that document so we use the patch function
document so we use the patch function followed by the ID we are trying to
followed by the ID we are trying to modify and we modify its data inside of
modify and we modify its data inside of this object by setting is archived to be
this object by setting is archived to be true and now what we do well we don't do
true and now what we do well we don't do it yet but we're going to do it right
it yet but we're going to do it right now before we return the document we're
now before we return the document we're going to call recursive archive and
going to call recursive archive and we're going to pass in the ARs do ID so
we're going to pass in the ARs do ID so this very same argument that ID we
this very same argument that ID we passed so after we modify the main
passed so after we modify the main document to be deleted we pass that ID
document to be deleted we pass that ID instead of a recursive function which
instead of a recursive function which let's see what does it attempts to fetch
let's see what does it attempts to fetch all children which have that ID as their
all children which have that ID as their parent document and then we run a four
parent document and then we run a four Loop over all of those children
Loop over all of those children and we change them to be is archived to
and we change them to be is archived to true as well but we're not done here
true as well but we're not done here right because we have to check every
right because we have to check every single child one more time to confirm
single child one more time to confirm that they are uh that they don't have uh
that they are uh that they don't have uh any children as well so that's why we
any children as well so that's why we have to repeat this uh recursive archive
have to repeat this uh recursive archive inside of itself to go to the end of the
inside of itself to go to the end of the nested child and that way we know that
nested child and that way we know that when we archive this document because of
when we archive this document because of this function and everything else will
this function and everything else will be archived as well perfect so that's
be archived as well perfect so that's what we want to do with our uh archive
what we want to do with our uh archive function we can leave it like this for
function we can leave it like this for now and now we are ready to create our
now and now we are ready to create our uh UI for
uh UI for archiving for that we have to head back
archiving for that we have to head back into our item component so go inside of
into our item component so go inside of app main components item. CSX right here
app main components item. CSX right here and I'm just going to leave this un
and I'm just going to leave this un uncommented for now we we'll notice it
uncommented for now we we'll notice it later
later uh and the first thing I want to do is
uh and the first thing I want to do is go right here where we have our own
go right here where we have our own create function as you can see we
create function as you can see we created a div here which looks like it's
created a div here which looks like it's supposed to hold more elements because
supposed to hold more elements because we add a flex box and we add some item
we add a flex box and we add some item Center and a gap between elements but
Center and a gap between elements but right now we only hold one element
right now we only hold one element inside that's what because we prepared
inside that's what because we prepared to hold multiple elements inside so
to hold multiple elements inside so let's go inside of it and instead of a
let's go inside of it and instead of a div let's add a drop- down menu from
div let's add a drop- down menu from add/ components UI whoops not the
add/ components UI whoops not the separator but the drop- down menu itself
separator but the drop- down menu itself so let's import that from add/
so let's import that from add/ components UI drop down menu like this
components UI drop down menu like this and let's go ahead and let's immediately
and let's go ahead and let's immediately import everything we need from the
import everything we need from the dropdown menu so I started some imports
dropdown menu so I started some imports here just make sure you don't
here just make sure you don't accidentally import them from radex
accidentally import them from radex because you're going to think that you
because you're going to think that you did something wrong with the code when
did something wrong with the code when it's just an import so you should not
it's just an import so you should not have radics imported anywhere inside of
have radics imported anywhere inside of your code except in the UI folder but
your code except in the UI folder but you don't write those components anyway
you don't write those components anyway these are all from chatsi and UI great
these are all from chatsi and UI great so we're going to have to need drop down
so we're going to have to need drop down menu we're going to have to need uh the
menu we're going to have to need uh the trigger so let me just find uh where is
trigger so let me just find uh where is the trigger here drop down menu trigger
the trigger here drop down menu trigger we're going to need drop down menu
content so let's get that we're going to need the individual item so drop down
need the individual item so drop down menu item uh and I think that's going to
menu item uh and I think that's going to be it yes so only this are the ones we
be it yes so only this are the ones we need and now we can go back uh to that
need and now we can go back uh to that div where we started with the drop down
div where we started with the drop down menu and let's add a drop- down menu
menu and let's add a drop- down menu trigger now which we have imported and
trigger now which we have imported and let's go ahead and let's give it a prop
let's go ahead and let's give it a prop as child and let's also go ahead and
as child and let's also go ahead and give it an onclick option where I simply
give it an onclick option where I simply want to get the event and I want to say
want to get the event and I want to say event. stop prop ation so it doesn't
event. stop prop ation so it doesn't redirect us right and let's go ahead and
redirect us right and let's go ahead and let's just indent this let's fix the
let's just indent this let's fix the trailing wi space and now let's go ahead
trailing wi space and now let's go ahead and let's open a div here and let's give
and let's open a div here and let's give it a roll of
it a roll of button and let's go ahead and let's
button and let's go ahead and let's render more horizontal from Lucid react
render more horizontal from Lucid react inside of it so let me just show you
inside of it so let me just show you where I added that right here more
where I added that right here more horizontal from Lucid react perfect and
horizontal from Lucid react perfect and now let's go ahead and give this some
now let's go ahead and give this some Styles so so class name is going to be
Styles so so class name is going to be opacity -0 but when we do a group hover
opacity -0 but when we do a group hover we're going to have opacity to be 100 H
we're going to have opacity to be 100 H is going to be full ml is going to be
is going to be full ml is going to be Auto rounded small hover BG D neutral
Auto rounded small hover BG D neutral D300 on dark hover is going to be BG D
D300 on dark hover is going to be BG D neutral
neutral D600 and let's give this more horizontal
D600 and let's give this more horizontal a class name of h-4 W-4 and text- muted
a class name of h-4 W-4 and text- muted D foreground and I think that already we
D foreground and I think that already we should be start seeing something there
should be start seeing something there we go you can see how we now have this
we go you can see how we now have this little options button and when you click
little options button and when you click on it it should not redirect you to any
on it it should not redirect you to any page but if you click directly on this
page but if you click directly on this it should redirect you to 404 but
it should redirect you to 404 but because we stop propagation on the drop-
because we stop propagation on the drop- down menu trigger it doesn't do that
down menu trigger it doesn't do that right and now what we have to do is
right and now what we have to do is write the content so this actually opens
write the content so this actually opens something so let's go ahead and continue
something so let's go ahead and continue developing that so outside of the drop
developing that so outside of the drop down menu trigger let's add drop down
down menu trigger let's add drop down menu content we already have that
menu content we already have that imported and let's go ahead and give it
imported and let's go ahead and give it uh a class
uh a class name uh of
name uh of w-6 let's give it an align option of
w-6 let's give it an align option of start aside of right and force
start aside of right and force Mount now let's go ahead and let's go
Mount now let's go ahead and let's go inside and let's write drop down menu
inside and let's write drop down menu item and let's give it an on click for
item and let's give it an on click for now to just be an empty Arrow
now to just be an empty Arrow function and inside let's write a trash
function and inside let's write a trash icon from Lucid react and make sure you
icon from Lucid react and make sure you have the trash imported from Lucid react
have the trash imported from Lucid react like that give this trash icon a class
like that give this trash icon a class name of h-4 W-4 and margin right of two
name of h-4 W-4 and margin right of two and let's go ahead and write delete like
and let's go ahead and write delete like this below the drop down menu item let's
this below the drop down menu item let's go ahead and let's add drop- down menu
go ahead and let's add drop- down menu separator uh which is going to be a self
separator uh which is going to be a self closing tag like this and let's write
closing tag like this and let's write div
div oops and let's write last edited by and
oops and let's write last edited by and in here we're going to get the user
in here we're going to get the user which we don't have yet so let's go
which we don't have yet so let's go ahead and do that let's go ahead and go
ahead and do that let's go ahead and go to the top here and just add const user
to the top here and just add const user from use user and we can import use user
from use user and we can import use user from clerk so let's
import use user from at clerk clerk react now that we have our user we can
react now that we have our user we can go back inside of this drop- down uh
go back inside of this drop- down uh menu content and let's write Last ated
menu content and let's write Last ated by user full name like that great and
by user full name like that great and let's give this div a class name of
let's give this div a class name of text- extra small text- muted D
text- extra small text- muted D foreground and padding two like that and
foreground and padding two like that and let's see if we did any mistakes if this
let's see if we did any mistakes if this is going to work not so I'm going to
is going to work not so I'm going to refresh everything and I'm going to go
refresh everything and I'm going to go ahead and click here and there we go oh
ahead and click here and there we go oh I now have my little delete button here
I now have my little delete button here and it says last edited by my name right
and it says last edited by my name right here perfect so what we're going to do
here perfect so what we're going to do now is we're going to create the button
now is we're going to create the button uh here that when we click on this it
uh here that when we click on this it actually archives the entire thing and
actually archives the entire thing and since we have the API ready for it all
since we have the API ready for it all we actually have to do is just add a
we actually have to do is just add a mutation for that so let's go ahead to
mutation for that so let's go ahead to the top here we already have the create
the top here we already have the create mutation so below that add const archive
mutation so below that add const archive we use mutation api. documents. archive
we use mutation api. documents. archive and now let's go ahead and let's add
and now let's go ahead and let's add const on
archive which is going to take an event of react.
of react. mouseevent HTML
mouseevent HTML whoops HTML div element and mouse
event and inside we're going to go go ahead and write if there is no ID just
ahead and write if there is no ID just return the entire thing I mean break the
return the entire thing I mean break the function and then const promise is going
function and then const promise is going to be archive and passing the ID just
to be archive and passing the ID just like that and now let's go ahead and
like that and now let's go ahead and call our toast so toast. promise it's
call our toast so toast. promise it's going to get that promise on the loading
going to get that promise on the loading it's going to say moving to
it's going to say moving to trash success is going to say note moved
trash success is going to say note moved to trash and error is going to say
to trash and error is going to say failed to Archive
failed to Archive note great and now that we have this on
note great and now that we have this on archive well one thing I forgot to do
archive well one thing I forgot to do was stop propagation with the event so
was stop propagation with the event so let's first do that event. stop
let's first do that event. stop propagation here at the top and now
propagation here at the top and now let's copy this on archive and let's
let's copy this on archive and let's finally assign it to this empty on click
finally assign it to this empty on click with the drop- down menu icon which
with the drop- down menu icon which holds the trash icon and the delete
holds the trash icon and the delete right here on archive great and let's
right here on archive great and let's try this out so what I'm actually going
try this out so what I'm actually going to do first is I'm going to go back
to do first is I'm going to go back inside of my uh convex dashboard and I'm
inside of my uh convex dashboard and I'm just going to clear the entire table so
just going to clear the entire table so it's easier to look at what we actually
it's easier to look at what we actually have right here and it looks like we
have right here and it looks like we have this little bug here we're going to
have this little bug here we're going to revisit that uh but for now I'm not
revisit that uh but for now I'm not going to focus on that now but let's
going to focus on that now but let's create a new page here and let's go
create a new page here and let's go ahead and see here as you can see it
ahead and see here as you can see it says is archived false let's go ahead
says is archived false let's go ahead and let's try and delete it and there we
and let's try and delete it and there we go it says note move to trash and let's
go it says note move to trash and let's see right here is archived is now true
see right here is archived is now true perfect and let's see what happens if I
perfect and let's see what happens if I create a new page and inside of it I
create a new page and inside of it I create a couple of children like this as
create a couple of children like this as you can see now I have a bunch of this
you can see now I have a bunch of this new documents which are none of them are
new documents which are none of them are archived and if our recursive function
archived and if our recursive function is working correctly when I deleted the
is working correctly when I deleted the parent all of the other children should
parent all of the other children should get archived as well let's see and there
get archived as well let's see and there we go all of them are archived perfect
we go all of them are archived perfect and if you're wondering how come they
and if you're wondering how come they are not rendered just because they are
are not rendered just because they are archived well let's revisit our API
archived well let's revisit our API right here where we have the get sidebar
right here where we have the get sidebar function as you can see we have a filter
function as you can see we have a filter here which ensures that it only shows
here which ensures that it only shows those that have is archived on false
those that have is archived on false which means that all of these here which
which means that all of these here which have it on true are not going to be
have it on true are not going to be shown here so the first thing we have to
shown here so the first thing we have to do next is just fix this little issue
do next is just fix this little issue where it says no Pages inside here I
where it says no Pages inside here I don't know why that's here uh and then
don't know why that's here uh and then we're going to have to create a little
we're going to have to create a little trash box here so we can safely recover
trash box here so we can safely recover our files if needed great great
our files if needed great great job so let's go ahead and let's try and
job so let's go ahead and let's try and resolve this little issue that we have
resolve this little issue that we have here so basically when I have no
here so basically when I have no documents that should be rendered here
documents that should be rendered here this shouldn't be rendered as well so
this shouldn't be rendered as well so let's go ahead and first thing that I
let's go ahead and first thing that I want to do is revisit our navigation
want to do is revisit our navigation component so let's go inside of app main
component so let's go inside of app main components navigation right here and
components navigation right here and let's go ahead and let's find where we
let's go ahead and let's find where we render this documents list so we render
render this documents list so we render it right here let's just go below it and
it right here let's just go below it and let's add another item item here uh and
let's add another item item here uh and let's go ahead and let's give it an
let's go ahead and let's give it an onclick to be on create which we already
onclick to be on create which we already have or is it handle create do we have
have or is it handle create do we have it it's called handle create all right
it it's called handle create all right so handle
so handle create let's go ahead and let's give it
create let's go ahead and let's give it uh an icon of
uh an icon of plus from Lucid react and a label of add
plus from Lucid react and a label of add a page so we're going to have two ways
a page so we're going to have two ways to add a page here and I just added this
to add a page here and I just added this plus icon from Lucid reacts to make sure
plus icon from Lucid reacts to make sure you have that uh let's see okay it looks
you have that uh let's see okay it looks like it was that great so I just need
like it was that great so I just need another item on the bot on the bottom
another item on the bot on the bottom here perfect so yes just like in notion
here perfect so yes just like in notion we have two ways to add a page either
we have two ways to add a page either from here or from here right and let's
from here or from here right and let's see if now when I delete this and when I
see if now when I delete this and when I delete this there we go we no longer now
delete this there we go we no longer now have that no Pages inside issue because
have that no Pages inside issue because that is the last element perfect so
that is the last element perfect so looks like that's solved our issue uh
looks like that's solved our issue uh what we have to do now is a little
what we have to do now is a little element below that which is going to be
element below that which is going to be called trash so in order to do that
called trash so in order to do that first thing we have to do is go inside
first thing we have to do is go inside of uh our terminal and let's go ahead
of uh our terminal and let's go ahead and write npx sh cn- at latest at
and write npx sh cn- at latest at popover let's go ahead and wait for this
popover let's go ahead and wait for this to
to install and then let me just zoom back
install and then let me just zoom back in let's go ahead below this item right
in let's go ahead below this item right here and let's add that popover
here and let's add that popover component so before we do that first
component so before we do that first thing I want to do is add everything we
thing I want to do is add everything we need from popover so let's go ahead here
need from popover so let's go ahead here and let's import from s/ components UI
and let's import from s/ components UI popover let's import the popover itself
popover let's import the popover itself the popover trigger and the popover
the popover trigger and the popover content like that perfect and let's go
content like that perfect and let's go all the way down here
all the way down here now and let's find where we need to add
now and let's find where we need to add that or is it okay so here is I add the
that or is it okay so here is I add the page and now here we write
page and now here we write popover then we add a popover
popover then we add a popover trigger and let's give this uh a well we
trigger and let's give this uh a well we didn't actually have to uh I I thought
didn't actually have to uh I I thought we might need to add as child but I
we might need to add as child but I don't think we do let's just do a class
don't think we do let's just do a class name here with w- full and margin top of
name here with w- full and margin top of four and inside let's add an item with a
four and inside let's add an item with a label of trash like that and an icon of
label of trash like that and an icon of trash as well and let's just go ahead
trash as well and let's just go ahead and import trash from Lucid react like
and import trash from Lucid react like this and it looks like we are missing uh
this and it looks like we are missing uh on click here in the item but I'm I
on click here in the item but I'm I think that that actually doesn't have to
think that that actually doesn't have to be required so let's go ahead inside of
be required so let's go ahead inside of this item props and let's make this on
this item props and let's make this on click optional like that and seems like
click optional like that and seems like there are no errors here great okay
there are no errors here great okay there are no errors here and there are
there are no errors here and there are no errors here anymore perfect now below
no errors here anymore perfect now below that let's go ahead and let's add
that let's go ahead and let's add popover
popover content let's give it a side and let's
content let's give it a side and let's do dynamically if we are on mobile it's
do dynamically if we are on mobile it's going to be bottom otherwise it's going
going to be bottom otherwise it's going to be
to be right like
right like that and let's also go ahead and give it
that and let's also go ahead and give it a class name of padding Z and W
a class name of padding Z and W d72 and for now let's just write a
d72 and for now let's just write a paragraph which says
paragraph which says trashbox and let me just fix the
trashbox and let me just fix the trailing wies space face all right and
trailing wies space face all right and let's see if we have anything here there
let's see if we have anything here there we go looks like our trash boox uh is
we go looks like our trash boox uh is right here and just one thing that I
right here and just one thing that I want to do is I want to go inside of the
want to do is I want to go inside of the popover and I want to change its Z index
popover and I want to change its Z index so let's go ahead inside of components
so let's go ahead inside of components UI pop over right
UI pop over right here and let's find this Z index here so
here and let's find this Z index here so this is the content let's change this to
this is the content let's change this to uh
uh 99999 like that
99999 like that and I think that's all that it is to
and I think that's all that it is to change here great so we just ensure that
change here great so we just ensure that it doesn't overlap with any of the other
it doesn't overlap with any of the other elements we're going to have and
elements we're going to have and everything still looks the same perfect
everything still looks the same perfect so now what we have to do is actual
so now what we have to do is actual component for the trash
component for the trash boox so first thing that I'm going to do
boox so first thing that I'm going to do is add an API route to fetch everything
is add an API route to fetch everything that is archived that should be rendered
that is archived that should be rendered in the trash can right so let's go
in the trash can right so let's go inside of convex right here let's go
inside of convex right here let's go inside of documents uh and let's go all
inside of documents uh and let's go all the way to the bottom here and let's
the way to the bottom here and let's write export
write export const get trash that's going to be a
const get trash that's going to be a query and it's just going to have an
query and it's just going to have an asynchronous Handler which holds the
asynchronous Handler which holds the context and let's just go ahead and
context and let's just go ahead and let's copy this identity thing that we
let's copy this identity thing that we always have so just add that to Handler
always have so just add that to Handler so we get the identity from Context out
so we get the identity from Context out to get user identity we check if we have
to get user identity we check if we have it and we extract the user ID and now
it and we extract the user ID and now let's go ahead and let's write con wants
let's go ahead and let's write con wants documents to be await context.
documents to be await context. databasequery
documents wi index by
index by user query query equals user ID to be
user query query equals user ID to be user ID and let's add a filter which
user ID and let's add a filter which also has a query and let's just simply
also has a query and let's just simply write um query equals query. field is
write um query equals query. field is archived is archived uh is true like
archived is archived uh is true like this so we only fetch our uh documents
this so we only fetch our uh documents by using this index to confirm that it's
by using this index to confirm that it's made by our user ID and then we filter
made by our user ID and then we filter so that it only shows the ones that we
so that it only shows the ones that we deleted let's order by this sting and
deleted let's order by this sting and let's collect all of that information
let's collect all of that information and let's return
and let's return documents uh all right like that perfect
documents uh all right like that perfect let's let me just fix the trailing wi
let's let me just fix the trailing wi space Here and Now what I want to do is
space Here and Now what I want to do is I want to create a restore mutation
I want to create a restore mutation right so similar to what we did uh with
right so similar to what we did uh with archive now I want to create a function
archive now I want to create a function to restore them to bring them out of
to restore them to bring them out of trash so export const uh restore is
trash so export const uh restore is going to be a mutation which has
going to be a mutation which has arguments ID is a type of VI ID
arguments ID is a type of VI ID documents and Handler is an asynchronous
documents and Handler is an asynchronous function which holds the context and the
function which holds the context and the arguments let's go ahead and copy and
arguments let's go ahead and copy and paste uh this identity
paste uh this identity thing right here all right and now let's
thing right here all right and now let's attempt to fetch the document so con
attempt to fetch the document so con existing document is equal to await
existing document is equal to await context. database. getet arguments.
context. database. getet arguments. ID if we don't have the existing
ID if we don't have the existing document we can return sorry we can
document we can return sorry we can throw new error not
found and now let's check if the existing document has a matching user ID
existing document has a matching user ID so if existing document. user ID and
so if existing document. user ID and let's just not put an exclamation point
let's just not put an exclamation point here my apologies so if the existing
here my apologies so if the existing documented user ID does not match the
documented user ID does not match the current user ID that means that we are
current user ID that means that we are not authenticated to restore this so
not authenticated to restore this so throw new error
unauthorized all right and now let's go ahead and let's do a very simple uh HST
ahead and let's do a very simple uh HST document a
document a wait uh actually let me just see I think
wait uh actually let me just see I think this is not going to do well uh just a
this is not going to do well uh just a second right so what I got confused with
second right so what I got confused with is that I remember that we can
is that I remember that we can technically uh recover a document which
technically uh recover a document which has a parent right so we have to create
has a parent right so we have to create a special Logic for that so let's go
a special Logic for that so let's go ahead and let's check if our document so
ahead and let's check if our document so if our existing document has a parent
if our existing document has a parent document in that that case let's go
document in that that case let's go ahead and let's write consp parent to be
ahead and let's write consp parent to be await context. database. getet document.