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
Click to expand
Click to explore the full interactive mind map • Zoom, pan, and navigate
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.
parent document sorry existing document. parent document like that let me try and
parent document like that let me try and expand this even more all right so if we
expand this even more all right so if we have a parent let's check it if parent
have a parent let's check it if parent is archived so even if the parent is
is archived so even if the parent is archived let's go ahead uh and let's
archived let's go ahead uh and let's change some things so in order to do
change some things so in order to do this we first have to Define some
this we first have to Define some options here so const options are going
options here so const options are going to be
to be partial
partial document documents like that and that's
document documents like that and that's going to be an object and this is not
going to be an object and this is not partal it's partial like that and let's
partal it's partial like that and let's give it is archived to be
give it is archived to be false and so if is parent is archived in
false and so if is parent is archived in that case options. parent document is
that case options. parent document is going to be
going to be undefined like that all right and now
undefined like that all right and now let's go ahead ahead and let's just do
let's go ahead ahead and let's just do await context. database. patch
await context. database. patch arguments. ID and
arguments. ID and options like that and let's return uh
options like that and let's return uh the existing
the existing document like that great uh and now we
document like that great uh and now we have to do a recursive restore the same
have to do a recursive restore the same way we did with recursive delete right
way we did with recursive delete right so let's go ahead Above This options
so let's go ahead Above This options here and let's write const
here and let's write const recursive
restore is going to be an asynchronous function which takes in the document ID
function which takes in the document ID which is a type of ID of
documents and let's go ahead and get all the children so con children are await
the children so con children are await context.
databasequery documents with
documents with index uh we're going to use by user
index uh we're going to use by user parent let's get a a query query equals
parent let's get a a query query equals user ID to be user ID and it equals
user ID to be user ID and it equals parent document to be parent
document uh let's see if we uh no not parent document it's document ID my
parent document it's document ID my apologies all right and let's just
apologies all right and let's just collect that and now let's do a four uh
collect that and now let's do a four uh loop here so
loop here so four
four child of
child of children await context. database. patch
children await context. database. patch Child ID and let's give it his archive
Child ID and let's give it his archive to be false so we unarchive it and now
to be false so we unarchive it and now let's do await recursive restore to be
let's do await recursive restore to be Child
Child ID great and now that we have that uh
ID great and now that we have that uh let's go
let's go ahead below this and let's write
ahead below this and let's write recursive restore to be arguments. ID
recursive restore to be arguments. ID perfect one more mutation that we have
perfect one more mutation that we have to write is the actual remove forever
to write is the actual remove forever mutation and that's going to be a bit
mutation and that's going to be a bit simpler so let's just write export const
simpler so let's just write export const remove to be a mutation which takes the
remove to be a mutation which takes the arguments and an ID of wi. ID
arguments and an ID of wi. ID documents Handler is an asynchronous
documents Handler is an asynchronous function which has the context and the
function which has the context and the arguments and let's just copy and paste
arguments and let's just copy and paste the identity thing with the user ID from
the identity thing with the user ID from our previous function like this so
our previous function like this so identity check for the identity and
identity check for the identity and extraction of user ID and let's go ahead
extraction of user ID and let's go ahead and let's fetch the document we trying
and let's fetch the document we trying to remove const existing document
to remove const existing document await context. database. getet
await context. database. getet arguments.
arguments. ID if there is no existing document
ID if there is no existing document throw new error not
throw new error not found and
found and if existing document men. user ID is not
if existing document men. user ID is not identical to currently logged in user ID
identical to currently logged in user ID in that case we can throw
unauthorized like this great and now that we solved that
this great and now that we solved that we can just simply go ahead and do const
we can just simply go ahead and do const document to be await context. database.
document to be await context. database. delete arguments. ID like this and
delete arguments. ID like this and return the
return the document
perfect uh and I think that uh should be it and let's just change this one so go
it and let's just change this one so go back inside of this um inside of this
back inside of this um inside of this restore function here and I just want to
restore function here and I just want to do this one simple thing I don't think
do this one simple thing I don't think it really matters but we returning this
it really matters but we returning this existing document which we fetch all the
existing document which we fetch all the way here right so we don't actually
way here right so we don't actually modify that element even though I think
modify that element even though I think this should work what I want to do is
this should work what I want to do is just just cons document here and then
just just cons document here and then just return that document instead like
just return that document instead like this very simple uh great so now that we
this very simple uh great so now that we have that we are finally ready to create
have that we are finally ready to create our trashbox
our trashbox component let's go back inside of the
component let's go back inside of the navigation so app folder main components
navigation so app folder main components navigation right here and inside we have
navigation right here and inside we have a paragraph inside of this popover and
a paragraph inside of this popover and the popover content we wrote a paragraph
the popover content we wrote a paragraph for trashbox let's change it to be an
for trashbox let's change it to be an actual trash box like this if we save of
actual trash box like this if we save of course we're going to get some errors so
course we're going to get some errors so let's go inside of this underscore
let's go inside of this underscore components and create a new file trash
components and create a new file trash uh dashbox DSX let's mark this as use
uh dashbox DSX let's mark this as use client and let's export con
client and let's export con trashbox to very simply return a div
trashbox to very simply return a div saying trashbox like that go back inside
saying trashbox like that go back inside of navigation and import the trash box
of navigation and import the trash box from slash trash dashbox and there we go
from slash trash dashbox and there we go we no longer have an error and now we
we no longer have an error and now we can fully Focus uh on this right here so
can fully Focus uh on this right here so let's go ahead and let's add some hooks
let's go ahead and let's add some hooks first so const uh router whoops const
first so const uh router whoops const router from use router from next SL
router from use router from next SL navigation con forams use perams from
navigation con forams use perams from next SL navigation con
next SL navigation con documents is going to be use
documents is going to be use Query which we have to import from
Query which we have to import from convex react so use Query and let's add
convex react so use Query and let's add use mutation while we are here from
use mutation while we are here from convex SL react and let's add the API
convex SL react and let's add the API from at/ convex generated API so for the
from at/ convex generated API so for the documents we're going to use api.
documents we're going to use api. documents. getet TR that's the function
documents. getet TR that's the function we're going to use now let's add the
we're going to use now let's add the restore mutation so con restore is use
restore mutation so con restore is use mutation api. documents. restore the
mutation api. documents. restore the function we just wrote and and let's
function we just wrote and and let's also do remove con remove use mutation
also do remove con remove use mutation api. documents.
api. documents. remove great now let's go ahead and
remove great now let's go ahead and let's add a search State because we want
let's add a search State because we want to be able to search through the entire
to be able to search through the entire trash box so con search set
search whoops set search from use State and let's give it the default
State and let's give it the default value of an empty string and make sure
value of an empty string and make sure you import US state from react
you import US state from react and now let's go ahead and let's write
and now let's go ahead and let's write const filtered documents to be documents
const filtered documents to be documents question mark. filter let's get the
question mark. filter let's get the individual document and let's return
individual document and let's return document. title. two lower
document. title. two lower case do includes search. to lowercase as
case do includes search. to lowercase as well so a quick little function to
well so a quick little function to filter out documents using this search
filter out documents using this search state right here and now let's just add
state right here and now let's just add a const on click function to get the
a const on click function to get the individual document ID which is a type
individual document ID which is a type of string and let's just do router.
of string and let's just do router. push back tis
push back tis documents document ID so that page that
documents document ID so that page that we don't yet have uh all right and now
we don't yet have uh all right and now let's go ahead uh and let's add two more
let's go ahead uh and let's add two more functions uh so functions for ReStore
functions uh so functions for ReStore and for delete so const on restore is
and for delete so const on restore is going to have an
going to have an event which is a type of react.
mouseevent HTML div element mouse event as
well and it's O mouse event and it's also going to have the document ID which
also going to have the document ID which we are trying to restore which is a type
we are trying to restore which is a type of ID and you can get that from convex
of ID and you can get that from convex generated data
generated data model and it's going to be an ID of
model and it's going to be an ID of documents like that uh great and now
documents like that uh great and now let's open this Arrow function here and
let's open this Arrow function here and let's stop the propagation from the
let's stop the propagation from the event and let's write const promise to
event and let's write const promise to be restore and let's pass in the ID to
be restore and let's pass in the ID to be document ID and now let's get our
be document ID and now let's get our toast from soner so import toast from
toast from soner so import toast from soner and let's go ahead now and let's
soner and let's go ahead now and let's write post. promise let's pass in this
write post. promise let's pass in this promise let's give it a loading state of
promise let's give it a loading state of restoring
restoring note uh let's go ahead and give it a
note uh let's go ahead and give it a success state of note restored and let's
success state of note restored and let's give it an error of failed to restore
give it an error of failed to restore note there we
note there we go and now let's go ahead uh and let's
go and now let's go ahead uh and let's copy and paste this entire
copy and paste this entire thing and let's rename it to on remove
thing and let's rename it to on remove and this one is not going to take the
and this one is not going to take the event so it's just going to take a
event so it's just going to take a document ID so no need to stop
document ID so no need to stop propagation here and let's just change
propagation here and let's just change this promise to not use restore but
this promise to not use restore but instead to use remove by document ID and
instead to use remove by document ID and this is not going to be restoring note
this is not going to be restoring note it's going to be deleting
it's going to be deleting note and this is going to be note
note and this is going to be note deleted and this is going to be failed
deleted and this is going to be failed to delete note uh great and now let's
to delete note uh great and now let's just do if perm. document ID is equal to
just do if perm. document ID is equal to document ID so if we are looking at the
document ID so if we are looking at the document which we just deleted forever
document which we just deleted forever uh we want to redirect back away from
uh we want to redirect back away from that document otherwise we're going to
that document otherwise we're going to get an error because we can no longer
get an error because we can no longer load that page so we're going to do
load that page so we're going to do router. push SL documents just like
router. push SL documents just like that uh great now that we have that
that uh great now that we have that let's go ahead and let's add our loading
let's go ahead and let's add our loading State here so if documents is
State here so if documents is undefined that means it's still loading
undefined that means it's still loading so we can go ahead and return a did with
so we can go ahead and return a did with a spinner component so import this
a spinner component so import this spinner from add/ components spinner
spinner from add/ components spinner give it a size of large and give it a
give it a size of large and give it a class name of h- full Flex items D
class name of h- full Flex items D Center justify Dash Center and padding
Center justify Dash Center and padding off four uh great uh so now what I want
off four uh great uh so now what I want to do is uh actually show the list of
to do is uh actually show the list of our items in trash here before we do
our items in trash here before we do that let's go quickly inside of our
that let's go quickly inside of our terminal here and let's go ahead and
terminal here and let's go ahead and write npx chat CN UI at latest add input
write npx chat CN UI at latest add input so we're going to need the input
so we're going to need the input component for this one great make sure
component for this one great make sure you have that let's Zoom back in and
you have that let's Zoom back in and let's give this div a class name of text
let's give this div a class name of text small let's open a new div with a class
small let's open a new div with a class name of flex items D Center Gap dx-1 and
name of flex items D Center Gap dx-1 and padding of two let's render these search
padding of two let's render these search icon
icon inside we can get the search icon from
inside we can get the search icon from Lucid react so make sure you import
Lucid react so make sure you import search from Lucid react let me just move
search from Lucid react let me just move it
it here uh where are we uh okay right here
here uh where are we uh okay right here and let's give this search icon a class
and let's give this search icon a class name of h-4 and
name of h-4 and W-4 and below that let's add our new
W-4 and below that let's add our new input component which we just added and
input component which we just added and that's located at s/ components uiinput
that's located at s/ components uiinput and let me just show you that right here
and let me just show you that right here there we go make sure you add that
there we go make sure you add that perfect and let's go ahead and give this
perfect and let's go ahead and give this a value of our search State let's give
a value of our search State let's give it an unchange to take the event and
it an unchange to take the event and let's just do set search to be event.
let's just do set search to be event. target. value and let's give it a class
target. value and let's give it a class name of
name of h-7 padding X of two Focus D
h-7 padding X of two Focus D visible ring- transparent and v-
visible ring- transparent and v- secondary
secondary and let's give it the placeholder of
and let's give it the placeholder of filter by Page
filter by Page title all right and now let's go outside
title all right and now let's go outside of this div and let's open a new
of this div and let's open a new one and let's give this one a class name
one and let's give this one a class name of margin top 2 px1 and
of margin top 2 px1 and pb1 and let's add a paragraph here no
pb1 and let's add a paragraph here no documents found and let's only show that
documents found and let's only show that paragraph if there is nothing else
paragraph if there is nothing else rendered inside and we can do that using
rendered inside and we can do that using C CSS so let's add a class name hidden
C CSS so let's add a class name hidden by default and it's only visible if it's
by default and it's only visible if it's the last element inside of this list
the last element inside of this list like that and it's going to have a extra
like that and it's going to have a extra small text it's going to be centered
small text it's going to be centered text as well and it's going to be muted
text as well and it's going to be muted for ground color and padding bottom off
for ground color and padding bottom off to let's see if we can already see any
to let's see if we can already see any of those let me just refresh this let's
of those let me just refresh this let's click on this trash icon and there we go
click on this trash icon and there we go you can see how it loads for a second we
you can see how it loads for a second we have a little search here and it says no
have a little search here and it says no doc docents found here perfect and now
doc docents found here perfect and now we have to render the documents inside
we have to render the documents inside so let's go ahead and do that so just
so let's go ahead and do that so just below this paragraph right here go ahead
below this paragraph right here go ahead and open filtered documents question
and open filtered documents question mark. map get the individual document
mark. map get the individual document and render a div and let's give this div
and render a div and let's give this div a key of document doore ID all right
a key of document doore ID all right let's give it a roll off button let's
let's give it a roll off button let's give it an onclick
give it an onclick to be uh an nrow function which calls on
to be uh an nrow function which calls on click and documentor
click and documentor ID and we have this on click defined
ID and we have this on click defined right here so when we click on it we're
right here so when we click on it we're going to redirect to it all right and
going to redirect to it all right and then let's go ahead and give it a class
then let's go ahead and give it a class name of text
name of text small rounded small W po power BG
small rounded small W po power BG primary sl5 Flex items D Center text
primary sl5 Flex items D Center text primary and justify
primary and justify between and inside let's go ahead and
between and inside let's go ahead and let's render our span element which is
let's render our span element which is going to render the document title all
going to render the document title all right and let's see if we are already
right and let's see if we are already seeing that here there we go look at all
seeing that here there we go look at all of our deleted items right here and if
of our deleted items right here and if you click it should lead you to a 404
you click it should lead you to a 404 page because we don't have it yet
page because we don't have it yet perfect so now we're going to style this
perfect so now we're going to style this a bit and we're going to add some
a bit and we're going to add some actions beside it to restore it back or
actions beside it to restore it back or to delete it forever great so go uh
to delete it forever great so go uh below this span right here and create a
below this span right here and create a div here with a class name of
div here with a class name of truncate in case the title is too long
truncate in case the title is too long p-2 oh my apologies this is actually a
p-2 oh my apologies this is actually a class name that I wanted to give to this
class name that I wanted to give to this span like that and for this they just a
span like that and for this they just a class name of a simple Flex item
class name of a simple Flex item Center and inside open a div which is
Center and inside open a div which is going to have an onclick function get
going to have an onclick function get the event and call on
the event and call on restore pass in the event but also pass
restore pass in the event but also pass in the documentor ID and give this a
in the documentor ID and give this a roll of button and a class name of uh
roll of button and a class name of uh rounded small padding to and hover BG
rounded small padding to and hover BG neutral
neutral 200 great and inside we're going to
200 great and inside we're going to render the undo icon from Lucid react so
render the undo icon from Lucid react so make sure you import undo from Lucid
make sure you import undo from Lucid react let's see how that looks now when
react let's see how that looks now when I click on trash okay we have a big undo
I click on trash okay we have a big undo button on the side here so now let's
button on the side here so now let's just style that button a bit so let's go
just style that button a bit so let's go ahead and give it a class name height
ahead and give it a class name height four with four and text muted foreground
four with four and text muted foreground like that
like that perfect and now go below that and add a
perfect and now go below that and add a new div uh which is going to render the
new div uh which is going to render the trash can from Lucid react so let's go
trash can from Lucid react so let's go ahead and import trash from Lucid react
ahead and import trash from Lucid react all right let's give it a class name of
all right let's give it a class name of height
height four with four and text muted
four with four and text muted foreground and let's go ahead and give
foreground and let's go ahead and give this Dave a roll of button and the class
this Dave a roll of button and the class name of rounded small padding to and
name of rounded small padding to and hover BG neutral 200 like that and now
hover BG neutral 200 like that and now we should have two little icons here
we should have two little icons here there we go the trash icon and the
there we go the trash icon and the restore button and I think our restore
restore button and I think our restore uh should already be working there we go
uh should already be working there we go you can see how when I restore they all
you can see how when I restore they all become individual items because they
become individual items because they don't have a parent right and let's go
don't have a parent right and let's go ahead and delete them individually and
ahead and delete them individually and we can do that as well perfect and let
we can do that as well perfect and let me just delete absolutely everything
me just delete absolutely everything from my table so I can try this out even
from my table so I can try this out even more so I'm going to try this I'm going
more so I'm going to try this I'm going to add a new parent inside there we go
to add a new parent inside there we go so I have three elements I have nothing
so I have three elements I have nothing in trash I'm going to delete the parent
in trash I'm going to delete the parent like this and I think that this is the
like this and I think that this is the parent the first one that was deleted
parent the first one that was deleted and I'm just going to attempt to restore
and I'm just going to attempt to restore that one and everything else should be
that one and everything else should be restored as well let's see there we go
restored as well let's see there we go everything else is restored inside
everything else is restored inside perfect so what's left to do now let me
perfect so what's left to do now let me have something deleted is the actual
have something deleted is the actual delete function right now it doesn't do
delete function right now it doesn't do anything beside actually redirect me to
anything beside actually redirect me to that page um so that's what I have to do
that page um so that's what I have to do uh
uh next so to wrap it up we have to add the
next so to wrap it up we have to add the complete remove function and in order to
complete remove function and in order to do that I don't want to assign it to
do that I don't want to assign it to just be on click I want to have a nice
just be on click I want to have a nice little model so the user can confirm
little model so the user can confirm that they want to do this because this
that they want to do this because this is not a reversible action for just
is not a reversible action for just archiving we don't need a confirmation
archiving we don't need a confirmation model because they can always go to the
model because they can always go to the trash boox and bring it back but for the
trash boox and bring it back but for the absolute complete removal from the
absolute complete removal from the database I think it's nice that we
database I think it's nice that we create a little confirmation model for
create a little confirmation model for that so let's go inside of our terminal
that so let's go inside of our terminal and let's install a package
and let's install a package MPX Shad cn- at latest ADD alert D
MPX Shad cn- at latest ADD alert D dialogue go ahead and install this
dialogue go ahead and install this package and after that is done we're
package and after that is done we're going to create a reusable component
going to create a reusable component called confirm model so let's go inside
called confirm model so let's go inside uh of our components folder and create a
uh of our components folder and create a new folder called models and inside
new folder called models and inside create a new file uh confirm dasm model.
create a new file uh confirm dasm model. DSX like this let's let's go ahead and
DSX like this let's let's go ahead and Mark this as use client and let's go
Mark this as use client and let's go ahead and let's import everything we
ahead and let's import everything we need from s/ components UI alert
need from s/ components UI alert dialogue which we just installed so we
dialogue which we just installed so we need the dialogue uh
need the dialogue uh itself we need the dialogue action we
itself we need the dialogue action we need the cancel action as well we need
need the cancel action as well we need the content we need the
the content we need the description
description putter Adder
putter Adder whoops so I alert dialogue header and
whoops so I alert dialogue header and title and last one
title and last one trigger so all of this inside perfect
trigger so all of this inside perfect and let's go ahead and write an
and let's go ahead and write an interface for this so interface confirm
interface for this so interface confirm model props is going to accept children
model props is going to accept children which are react do react
which are react do react node and we're going to have the on
node and we're going to have the on confirm option which is going to be well
confirm option which is going to be well whatever we want depending on the use
whatever we want depending on the use case and now let's export
case and now let's export const uh confirm a model
and let's go ahead and assign this props here so confirm model props and let's
here so confirm model props and let's extract the children and the on confirm
extract the children and the on confirm great and now let's go ahead and let's
great and now let's go ahead and let's just do a return of the alert dialogue
just do a return of the alert dialogue let's add the alert dialogue
let's add the alert dialogue trigger and let's render the children
trigger and let's render the children inside so the trigger is going to be
inside so the trigger is going to be whatever we want it to whatever we wrap
whatever we want it to whatever we wrap the confirm model around around that's
the confirm model around around that's going to be the trigger button and let's
going to be the trigger button and let's add the on click which just simply is
add the on click which just simply is going to call event. stop propagation
going to call event. stop propagation and let's give the as child option
and let's give the as child option perfect now inside let's add the alert
perfect now inside let's add the alert dialog uh
content great alert dialogue header and let's go ahead and write the alert
let's go ahead and write the alert dialogue title which is going to have
dialogue title which is going to have the title of R you app absolutely
the title of R you app absolutely sure and below the title we're going to
sure and below the title we're going to add the alert dialogue
add the alert dialogue description which is just going to
description which is just going to confirm to the user that this is uh an
confirm to the user that this is uh an irreversible action so this action
irreversible action so this action cannot be
cannot be undone and now let's go uh outside of
undone and now let's go uh outside of the header and let's add the alert
the header and let's add the alert dialogue
dialogue footer and uh let's just go ahead and
footer and uh let's just go ahead and write the alert dialogue cancel button
write the alert dialogue cancel button here
here whoops it's not going to be a self
whoops it's not going to be a self closing
closing tag like this and let's go
tag like this and let's go inside and let's just write cancel and
inside and let's just write cancel and let's give it an on click event event.
let's give it an on click event event. stop
stop propagation like that and now let's add
propagation like that and now let's add the alert dialogue action and this one
the alert dialogue action and this one uh let's also give it an ending tag and
uh let's also give it an ending tag and this one is going to say
this one is going to say confirm like this and now let's just go
confirm like this and now let's just go ahead and write a function handle
ahead and write a function handle confirm so const
confirm so const handle confirm is going to be an event
handle confirm is going to be an event of react.
of react. mouseevent HTML button element and mouse
mouseevent HTML button element and mouse event like this let me just put this in
event like this let me just put this in a separate line so that's going to be
a separate line so that's going to be our event and let's do event stop
our event and let's do event stop propagation and let's do on confirm
propagation and let's do on confirm right here and then we can use this
right here and then we can use this handle confirm to be an onclick for this
handle confirm to be an onclick for this action and now we can go back inside of
action and now we can go back inside of our trash box here and we can wrap this
our trash box here and we can wrap this entire thing inside a confirm model like
this so make sure you import confirm model from add/ components models
model from add/ components models confirm model wrap the entire div around
confirm model wrap the entire div around it and just give this one on confirm uh
it and just give this one on confirm uh to be a
to be a function which is going to uh remove the
function which is going to uh remove the document so it's going to be an arrow
document so it's going to be an arrow function function which calls on remove
function function which calls on remove document ID like that and we have on
document ID like that and we have on removed right here perfect now let's go
removed right here perfect now let's go ahead and try that out so I have three
ahead and try that out so I have three items in the database uh let's see two
items in the database uh let's see two of them are active one is in the trash
of them are active one is in the trash if I click here oh it looks like I have
if I click here oh it looks like I have a model but as you can see it's not the
a model but as you can see it's not the Z index is not correct so before we try
Z index is not correct so before we try this out let's actually fix the Z index
this out let's actually fix the Z index first so we have to go inside of uh
first so we have to go inside of uh components UI alert
components UI alert dialogue and let's find the Z index for
dialogue and let's find the Z index for the overlay and change the 50 to 5 9 so
the overlay and change the 50 to 5 9 so 1 2 3 one two like that and let's copy
1 2 3 one two like that and let's copy and paste this so we did it for the
and paste this so we did it for the overlay and now let's also just do it
overlay and now let's also just do it for uh the content so let's just find Z
for uh the content so let's just find Z Index right here there we go let's add
Index right here there we go let's add it here let's see if we have the index
it here let's see if we have the index anywhere else I think that's it yeah
anywhere else I think that's it yeah great so just those two places and let's
great so just those two places and let's try this again when I click here there
try this again when I click here there we go you can see how now it's at top uh
we go you can see how now it's at top uh and let's just not click at anything
and let's just not click at anything else while we're doing this and let's
else while we're doing this and let's click confirm and there we go note is
click confirm and there we go note is deleted and it's no longer in trash and
deleted and it's no longer in trash and if I look at my database I only have two
if I look at my database I only have two items perfect and let's go ahead and try
items perfect and let's go ahead and try this one more time there we go I can now
this one more time there we go I can now completely remove my entire database
completely remove my entire database just by using UI amazing amazing amazing
just by using UI amazing amazing amazing job so now let's go ahead and let's wrap
job so now let's go ahead and let's wrap up our sidebar items right here so we
up our sidebar items right here so we have our working uh Pages here we have
have our working uh Pages here we have the working trash but we don't have the
the working trash but we don't have the working settings and the search bar so
working settings and the search bar so before I get onto that I just want to
before I get onto that I just want to bring to your attention that currently
bring to your attention that currently when I expand here you can see how for a
when I expand here you can see how for a second it's like I have a blank space
second it's like I have a blank space and then I have something rendered
and then I have something rendered instead of that I was hoping that the
instead of that I was hoping that the skeleton would show because we did
skeleton would show because we did create an item skeleton right here in
create an item skeleton right here in our app folder main components item you
our app folder main components item you can see that right here we have a
can see that right here we have a skeleton right here but looks like
skeleton right here but looks like something's not working so what I want
something's not working so what I want to do is go inside of components UI and
to do is go inside of components UI and find the skeleton right here and it says
find the skeleton right here and it says that this background is muted so let's
that this background is muted so let's go ahead and let's change that to be BG
go ahead and let's change that to be BG primary sl5 like this let's change that
primary sl5 like this let's change that to this and let's see if that improves
to this and let's see if that improves anything there we go you can see how now
anything there we go you can see how now for a second it's very subtle but if you
for a second it's very subtle but if you look at it I have like a like a small
look at it I have like a like a small little skeleton inside instead of just a
little skeleton inside instead of just a blank space and in my opinion that looks
blank space and in my opinion that looks better perfect so now let's go ahead and
better perfect so now let's go ahead and let's create the search functionality
let's create the search functionality for that uh let's go ahead and let's
for that uh let's go ahead and let's close everything and first things first
close everything and first things first let's go ahead and let's install two
let's go ahead and let's install two stand so npm install two we're going to
stand so npm install two we're going to use that as our Global State Management
use that as our Global State Management uh to open uh the actual search command
uh to open uh the actual search command so now let's go ahead and let's create a
so now let's go ahead and let's create a hook for that so go inside of your hooks
hook for that so go inside of your hooks folder and create a new file use-
folder and create a new file use- search. TSX like that and go ahead and
search. TSX like that and go ahead and import create from
import create from tan and go ahead and write type search
tan and go ahead and write type search store to have is open which is aoan is
store to have is open which is aoan is going to have on open which is going to
going to have on open which is going to be a void it's going to have on close
be a void it's going to have on close which is also going to be a void and
which is also going to be a void and we're also going to have a toggle which
we're also going to have a toggle which is going to be a void as well and then
is going to be a void as well and then let's export con use search to be create
let's export con use search to be create with a type of search
with a type of search store and go ahead and open parenthesis
store and go ahead and open parenthesis open parenthesis again and extract the
open parenthesis again and extract the set and get options and go ahead and
set and get options and go ahead and return an immediate object like this and
return an immediate object like this and press enter and let's give it a default
press enter and let's give it a default Val of is open to false on open to be a
Val of is open to false on open to be a function an arrow function which calls
function an arrow function which calls the set and just uses the is open to be
the set and just uses the is open to be true on close is also an arrow function
true on close is also an arrow function which uses set to reset is open back to
which uses set to reset is open back to false and last one is going to be toggle
false and last one is going to be toggle which is an arrow function which uses
which is an arrow function which uses set again and it's going to take the
set again and it's going to take the current value of this open and do the
current value of this open and do the reverse of it so is open is going to be
reverse of it so is open is going to be question mark get is open like
question mark get is open like this there we go uh perfect so now that
this there we go uh perfect so now that we have this
we have this uh let's go ahead and let's uh install
uh let's go ahead and let's uh install the command from shat CN UI so go back
the command from shat CN UI so go back inside of your terminal here and go
inside of your terminal here and go ahead and write mpm whoops MPX
ahead and write mpm whoops MPX sheni at latest at command like this
sheni at latest at command like this let's wait a second for this to
let's wait a second for this to install and just a couple of seconds
install and just a couple of seconds more and and install the dialogue as
more and and install the dialogue as well
well great and now let's go ahead and zoom
great and now let's go ahead and zoom back in and let's go inside of our
back in and let's go inside of our Global uh components folder and create a
Global uh components folder and create a new file called search- command. DSX and
new file called search- command. DSX and let me expand my sbar so you can see
let me expand my sbar so you can see this so search- command. DSX perfect
this so search- command. DSX perfect let's go ahead and Mark this as use
let's go ahead and Mark this as use client and let's import use effect and
client and let's import use effect and use state from react let's go ahead and
use state from react let's go ahead and import file from Lucid react let's go
import file from Lucid react let's go ahead and import use
ahead and import use Query from convex SL
Query from convex SL react let's go ahead and import use
react let's go ahead and import use router from next SL navigation and let's
router from next SL navigation and let's go ahead and let's import use user from
go ahead and let's import use user from uh add clerk cl-
react great and now let's go ahead and import everything we need from our new
import everything we need from our new component
component command we're going to have the command
command we're going to have the command dialogue we're going to have the command
dialogue we're going to have the command empty the command
empty the command group
group input command input we're going to get
input command input we're going to get the command item and the command list uh
the command item and the command list uh great besides that we're also going to
great besides that we're also going to import that hook which we just created
import that hook which we just created called use search from at/ hooks use-
called use search from at/ hooks use- search and we're also going to import
search and we're also going to import our API from convex generated API great
our API from convex generated API great and now let's export con search
and now let's export con search command to Be an Arrow
command to Be an Arrow function and let's go ahead and let's
function and let's go ahead and let's write a constant user be use user let's
write a constant user be use user let's go ahead and let's get the router from
go ahead and let's get the router from use router let's go ahead and fetch the
use router let's go ahead and fetch the documents and let's write use Query and
documents and let's write use Query and I just remembered that we actually did
I just remembered that we actually did not write uh the function the API
not write uh the function the API endpoint to load all the documents
endpoint to load all the documents needed for search we have uh the thing
needed for search we have uh the thing to load for sidebar but for search is
to load for sidebar but for search is going to be a bit different so let's
going to be a bit different so let's head back inside of convex inside of
head back inside of convex inside of documents. DS right here and let's go
documents. DS right here and let's go all the way to the bottom here and let's
all the way to the bottom here and let's add a new endpoint export con get search
add a new endpoint export con get search which is going to be a query it's going
which is going to be a query it's going to take a Handler which is an
to take a Handler which is an asynchronous function which has the
asynchronous function which has the context and let's just copy and paste
context and let's just copy and paste the identity thing as we always do and
the identity thing as we always do and copy the user ID as well just like that
copy the user ID as well just like that and let's write constant documents to be
and let's write constant documents to be await context.
await context. databasequery
databasequery documents dowi
documents dowi index by user and passing the query
index by user and passing the query which is just going to search for query
which is just going to search for query that equals user ID to be user
that equals user ID to be user ID and let's filter let's get the query
ID and let's filter let's get the query again and the only thing we're going to
again and the only thing we're going to to filter is query equals query. field
to filter is query equals query. field is archived to be false so we are not
is archived to be false so we are not going to be able to search through our
going to be able to search through our files for that we have the trash box let
files for that we have the trash box let me just fix the trailing whitespace here
me just fix the trailing whitespace here uh and let's add order to be descending
uh and let's add order to be descending and let's just collect
everything like that perfect and then we can just return
can just return documents that's it that's all we need
documents that's it that's all we need for our get uh search uh endpoint now
for our get uh search uh endpoint now let's go back inside of the Search
let's go back inside of the Search Command and let's use that in this query
Command and let's use that in this query so api. documents. getet search there
so api. documents. getet search there there we go and now let's get our toggle
there we go and now let's get our toggle so cons toggle is equal use search get
so cons toggle is equal use search get the store and write store.
the store and write store. toggle let's copy and paste this two
toggle let's copy and paste this two times let's change this one to be is
times let's change this one to be is open from the store and let's change
open from the store and let's change this one to be on close from the store
this one to be on close from the store great and now let's go ahead uh above uh
great and now let's go ahead uh above uh below these documents and let's add a
below these documents and let's add a state is mounted and set is mounted to
state is mounted and set is mounted to be use State false
be use State false and now let's write a use
and now let's write a use effect to change this mounted to true
effect to change this mounted to true and go ahead and give it an empty
and go ahead and give it an empty dependency array so the reason we are
dependency array so the reason we are doing this is to prevent hydration
doing this is to prevent hydration errors with stuff like dialogs and
errors with stuff like dialogs and command uses dialogue in the background
command uses dialogue in the background so the reason we are doing this is
so the reason we are doing this is because uh even though this is marked as
because uh even though this is marked as use client uh nextjs is still going to
use client uh nextjs is still going to do some server side rendering on it
do some server side rendering on it first and with dialogues which can
first and with dialogues which can appear dynamically for example our
appear dynamically for example our Search Command can appear on a shortcut
Search Command can appear on a shortcut right that can cause hydration errors
right that can cause hydration errors because in server side it's not going to
because in server side it's not going to exist and then it reaches uh client side
exist and then it reaches uh client side and all of a sudden it exists here and
and all of a sudden it exists here and that's called a hydration error so we're
that's called a hydration error so we're going to prevent that by not even
going to prevent that by not even allowing it to be rendered on the server
allowing it to be rendered on the server side even though it already has used
side even though it already has used client that's not enough so use client
client that's not enough so use client still does some server side rendering
still does some server side rendering right so that's why we have to use this
right so that's why we have to use this trick that only when it's mounted we're
trick that only when it's mounted we're actually going to render anything
actually going to render anything because we're going to add if uh is not
because we're going to add if uh is not mounted just return null and this way we
mounted just return null and this way we prevent that hydration error um perfect
prevent that hydration error um perfect so now let's go ahead and let's go and
so now let's go ahead and let's go and return our actual command here so
return our actual command here so command
command dialogue uh it's going to have open of
dialogue uh it's going to have open of is open and on open change is going to
is open and on open change is going to be on
be on close go inside side and add the command
close go inside side and add the command input component and go ahead and give it
input component and go ahead and give it placeholder to be open btic like this
placeholder to be open btic like this and we're going to write search open
and we're going to write search open special object user question mark full
special object user question mark full name apostrophe s Jan so search
name apostrophe s Jan so search Antonio's Jan in my case right uh and
Antonio's Jan in my case right uh and then go ahead and end the command list
then go ahead and end the command list and add the command empty which is just
and add the command empty which is just going to render no
going to render no results results
results results found like that and then add a command
found like that and then add a command group and give the command group a
group and give the command group a heading of
heading of documents and let's go ahead and let's
documents and let's go ahead and let's write
write documents map question mark. map let's
documents map question mark. map let's get the individual
get the individual document like
document like that or I can just immediately return
that or I can just immediately return like this uh and let's return a command
like this uh and let's return a command item and first things first let's go
item and first things first let's go ahead and give the command item some
ahead and give the command item some props so we're going to have a key which
props so we're going to have a key which is going to be documentor ID let's go
is going to be documentor ID let's go ahead and give it a value of open btic a
ahead and give it a value of open btic a combination of document ID Dash
combination of document ID Dash document.title because what we searched
document.title because what we searched through is the value so we have to
through is the value so we have to combine both of those uh and then let's
combine both of those uh and then let's go ahead and give it a title of
go ahead and give it a title of document.title
document.title let's write on select for now to just be
let's write on select for now to just be an empty Arrow
an empty Arrow function and uh we'll already added the
function and uh we'll already added the key that's it and inside let's
key that's it and inside let's dynamically check for the document icon
dynamically check for the document icon so if document has an icon in that case
so if document has an icon in that case we're going to render a paragraph with
we're going to render a paragraph with document.
document. icon and let's just go ahead uh and
icon and let's just go ahead uh and let's give this a class
let's give this a class name of margin right 2 and text 18
name of margin right 2 and text 18 pixels
pixels otherwise we're going to go ahead and
otherwise we're going to go ahead and render the file icon from Lucid react
render the file icon from Lucid react which we just imported and add a class
which we just imported and add a class name of margin right two height four and
name of margin right two height four and W4 great and Below all of that add a
W4 great and Below all of that add a span which is just going to render
span which is just going to render document. title perfect and now let's go
document. title perfect and now let's go ahead and let's create this uh on select
ahead and let's create this uh on select function right here so go above this if
function right here so go above this if clause and write Con on select to have
clause and write Con on select to have an ID of string and router. push to/
an ID of string and router. push to/ documents slid individual document and
documents slid individual document and on close after that happens perfect and
on close after that happens perfect and now let's go ahead and let's create a
now let's go ahead and let's create a use effect so we have a shortcut so we
use effect so we have a shortcut so we can open this search dialogue whenever
can open this search dialogue whenever we want so let's do that close to this
we want so let's do that close to this use effect that we already have
use effect that we already have here let's just prepare an empty use
here let's just prepare an empty use effect for now and let's write
effect for now and let's write const down which is going to have an
const down which is going to have an event of keyboard
event of keyboard event and let's check if event. key is
event and let's check if event. key is equal to K and if e is a meta key or r e
equal to K and if e is a meta key or r e is control key so we handle both windows
is control key so we handle both windows and MacBooks here in that case let's
and MacBooks here in that case let's prevent default and let's just toggle
prevent default and let's just toggle whether it's opened or not and lastly
whether it's opened or not and lastly let's do document. add event
let's do document. add event listener D down and let's do the down
listener D down and let's do the down function here and now let's do a return
function here and now let's do a return so on unmount we have to remove the
so on unmount we have to remove the event listener to prevent any overflow
event listener to prevent any overflow so document. remove event listener key
so document. remove event listener key down and down function and we have to
down and down function and we have to add toggle inside of the dependency
add toggle inside of the dependency array and now let's copy this use on
array and now let's copy this use on select here and let's replace it right
select here and let's replace it right here there we go perfect and now we have
here there we go perfect and now we have to go and add this Search Command inside
to go and add this Search Command inside of our layout but not just any layout we
of our layout but not just any layout we have to add it inside of app main
have to add it inside of app main layout. DSX right
layout. DSX right here and let's go ahead Above This
here and let's go ahead Above This children but still inside of Main and
children but still inside of Main and render the search
render the search command so we imported search command
command so we imported search command from as/ components Search Command and I
from as/ components Search Command and I think that already if you try and let me
think that already if you try and let me refresh if I press command key there we
refresh if I press command key there we go you can see that I have my dialogue
go you can see that I have my dialogue opened so if you don't uh make sure that
opened so if you don't uh make sure that you try control key and just confirm
you try control key and just confirm with my code that your use effect is
with my code that your use effect is working and as you can see it's working
working and as you can see it's working but you can see that the sidebar is not
but you can see that the sidebar is not blurred so that's because of the zindex
blurred so that's because of the zindex thing so let's go
thing so let's go ahead and let's revisit our components
ahead and let's revisit our components UI and let's see what we have to change
UI and let's see what we have to change here so I think we actually don't have
here so I think we actually don't have to change anything inside of the command
to change anything inside of the command let's see uh I think we don't yeah I
let's see uh I think we don't yeah I think what we have to do is change it
think what we have to do is change it inside of dialogue . DSX so let's go
inside of dialogue . DSX so let's go ahead inside of the dialogue here and
ahead inside of the dialogue here and find the index 50 and change it to 59s
find the index 50 and change it to 59s like this go ahead and copy this and do
like this go ahead and copy this and do the same thing for the content right
the same thing for the content right here so we did it for the overlay and we
here so we did it for the overlay and we did it for the content and I think
did it for the content and I think that's it I don't think anything else
that's it I don't think anything else needs it and if I try now there we go
needs it and if I try now there we go you can see how now even the sidebar is
you can see how now even the sidebar is blurred and I can search for well
blurred and I can search for well everything is named the same but you can
everything is named the same but you can try and search something complet
try and search something complet different to get a wrong thing and if
different to get a wrong thing and if you click on one of them you're going to
you click on one of them you're going to get a 404 because we don't have that yet
get a 404 because we don't have that yet perfect so now what we have to do is
perfect so now what we have to do is enable that when we click on this that
enable that when we click on this that happens as well and thankfully we can do
happens as well and thankfully we can do that very very easily we can just go
that very very easily we can just go inside of the app folder main components
inside of the app folder main components navigation right here and while we're
navigation right here and while we're here let's import use search from hooks
here let's import use search from hooks use search like that and let's add that
use search like that and let's add that inside of here so const uh search search
inside of here so const uh search search is equal use
is equal use search like that and then let's go ahead
search like that and then let's go ahead and find our search item there we go
and find our search item there we go it's right here and on click change this
it's right here and on click change this to just be search do unopen just like
to just be search do unopen just like this and let's try that out now when I
this and let's try that out now when I click here there we go it opens so I can
click here there we go it opens so I can use the shortcut or I can click on it
use the shortcut or I can click on it right here great so we're going to do a
right here great so we're going to do a very similar thing to enable the
very similar thing to enable the settings
settings and now let's create the last item in
and now let's create the last item in the sidebar which is this settings right
the sidebar which is this settings right here so we're going to use a very
here so we're going to use a very similar method through what we did with
similar method through what we did with the search right here we're going to
the search right here we're going to create a hook called use settings which
create a hook called use settings which is going to use two to create a global
is going to use two to create a global store to track whether we have clicked
store to track whether we have clicked on this or not and that's going to
on this or not and that's going to toggle the is open Boolean to true or
toggle the is open Boolean to true or false and depending on that we're going
false and depending on that we're going to keep that component opened or not so
to keep that component opened or not so let's start by creating our
let's start by creating our um uh hook so let's go inside of hooks
um uh hook so let's go inside of hooks and let's go ahead and create -
and let's go ahead and create - settings. DSX let's go ahead and let's
settings. DSX let's go ahead and let's import create from
import create from toand and let's write type settings
toand and let's write type settings store and very similar to search store
store and very similar to search store it's going to have is open which is a
it's going to have is open which is a Boolean is going to have onopen which is
Boolean is going to have onopen which is just a void and on close which is also
just a void and on close which is also just a void but it's not going to have a
just a void but it's not going to have a toggle and let export cons use settings
toggle and let export cons use settings here to be create pass in the settings
here to be create pass in the settings store and go ahead and extract the Set
store and go ahead and extract the Set uh well just the set function and go
uh well just the set function and go ahead and return an immediate object set
ahead and return an immediate object set is open to have a default value or false
is open to have a default value or false on open to be a function sorry not void
on open to be a function sorry not void but call a set function which is going
but call a set function which is going to set the is open to true and copy and
to set the is open to true and copy and paste this and change this one to be on
paste this and change this one to be on close and that one is going to set is
close and that one is going to set is open to
open to false great and now let's go ahead and
false great and now let's go ahead and let's create our settings model so save
let's create our settings model so save this file close everything go inside of
this file close everything go inside of components models and create a new file
components models and create a new file settings- model. DSX and let's go ahead
settings- model. DSX and let's go ahead and let's mark everything as use client
and let's mark everything as use client inside and let's go ahead and let's
inside and let's go ahead and let's import everything we need from at/
import everything we need from at/ components UI dialogue so we never
components UI dialogue so we never actually installed the dialogue
actually installed the dialogue explicitly right but we did get it
explicitly right but we did get it installed when we installed the command
installed when we installed the command component for the Search Command right
component for the Search Command right here when we install these things you
here when we install these things you can see that the command uses the
can see that the command uses the dialogue right but just in case if you
dialogue right but just in case if you don't have the dialogue so if you can't
don't have the dialogue so if you can't find that inside of your UI folder this
find that inside of your UI folder this dialogue right here even though you
dialogue right here even though you should have it because I think in the
should have it because I think in the previous part we changed the Z index
previous part we changed the Z index here right but just in case you don't
here right but just in case you don't have it it um you can always just go
have it it um you can always just go into your terminal and do npx shat CNU
into your terminal and do npx shat CNU at latest add dialogue like this I'm not
at latest add dialogue like this I'm not going to do it because we already have
going to do it because we already have it all right let me Zoom back in and
it all right let me Zoom back in and let's import the dialogue the dialogue
let's import the dialogue the dialogue content and the dialogue
content and the dialogue header and let's go ahead and let's
header and let's go ahead and let's import use settings from hooks use
import use settings from hooks use settings and uh well we need a label so
settings and uh well we need a label so let's go ahead and let's do that by
let's go ahead and let's do that by going inside of our terminal I I shut it
going inside of our terminal I I shut it down too soon and let's write npx shat
down too soon and let's write npx shat cn- at latest AD Label like this wait a
cn- at latest AD Label like this wait a second for this to install and once it's
second for this to install and once it's done we can go back into the code here
done we can go back into the code here and let's import the
and let's import the label from at/ components slui
label from at/ components slui label and lastly I want to import the
label and lastly I want to import the mode toggle component from well it autoc
mode toggle component from well it autoc completed for this but I'm going to
completed for this but I'm going to change to S SL
change to S SL components so we already have mode
components so we already have mode toggle if you remember we have that
toggle if you remember we have that inside of our uh navigation bar when we
inside of our uh navigation bar when we log out so let me just log out from here
log out so let me just log out from here and there we go this is the mode total
and there we go this is the mode total component which can switch to light and
component which can switch to light and dark mode so let me just head back
dark mode so let me just head back inside of my component
inside of my component here let me uh let me go back okay and
here let me uh let me go back okay and now that we confirm that we have that
now that we confirm that we have that mode toggle so you can also just contr
mode toggle so you can also just contr controll click and go here to confirm
controll click and go here to confirm that you have it and now let's go ahead
that you have it and now let's go ahead and let's uh write export const settings
and let's uh write export const settings model like that let's write con settings
model like that let's write con settings to be used
to be used settings and let's return a dialogue
settings and let's return a dialogue component let's go ahead and let's give
component let's go ahead and let's give this dialogue an open prop of settings
this dialogue an open prop of settings is open and onop change to be
is open and onop change to be settings.on
settings.on close let's go ahead and render the
close let's go ahead and render the dialogue content and let's render the
dialogue content and let's render the dialogue
dialogue header let's give it a class name of
header let's give it a class name of Border bottom and padding bottom of
Border bottom and padding bottom of three let's add an H2 element which is
three let's add an H2 element which is just going to say my settings like that
just going to say my settings like that and let me just collapse that so we can
and let me just collapse that so we can safely add a class name here without
safely add a class name here without taking much of my space here so the
taking much of my space here so the class name is going to have a large text
class name is going to have a large text and a semibold font uh actually let's do
and a semibold font uh actually let's do medium semi bold might be a bit too much
medium semi bold might be a bit too much uh great and now uh below this dialog
uh great and now uh below this dialog header open up a div and let's give this
header open up a div and let's give this a flex so Flex items Das Center and
a flex so Flex items Das Center and justify Das
justify Das between and on this side uh we're going
between and on this side uh we're going to have another div which is going to be
to have another div which is going to be a flex column so flex
a flex column so flex flex-all and GAP
flex-all and GAP y1 and let's give it a label here which
y1 and let's give it a label here which we imported above with
we imported above with appearance and a span which is just
appearance and a span which is just going to say customize how
going to say customize how Jan looks on your device and let's give
Jan looks on your device and let's give this a class name of
this a class name of text uh
text uh 0.8 REM and text- muted D forground
0.8 REM and text- muted D forground all right and now let's go outside of
all right and now let's go outside of this div right here and let's render a
this div right here and let's render a mode
mode toggle just like this perfect and now if
toggle just like this perfect and now if you remember in the settings uh in the
you remember in the settings uh in the so not in the settings in the Search
so not in the settings in the Search Command where is it let me close this in
Command where is it let me close this in the Search Command we do this trick with
the Search Command we do this trick with mounting right but it looks like I
mounting right but it looks like I didn't do it here in the settings model
didn't do it here in the settings model why is that it's the very same logic it
why is that it's the very same logic it uses the model right and it use it to
uses the model right and it use it to stand for the state well you're correct
stand for the state well you're correct but we're not going to do it here
but we're not going to do it here because we're going to have uh another
because we're going to have uh another model in this application and we can do
model in this application and we can do a little trick with a common component
a little trick with a common component to do that for us so we can just leave
to do that for us so we can just leave the settings model as it is and instead
the settings model as it is and instead let's go ahead inside of our providers
let's go ahead inside of our providers so I'm going to close everything go
so I'm going to close everything go inside of components providers here and
inside of components providers here and create a new file model- provider. TSX
create a new file model- provider. TSX mark this as use client go ahead and
mark this as use client go ahead and import use effect from react and use
import use effect from react and use state from
state from react and now let's go ahead and let's
react and now let's go ahead and let's import the settings
import the settings model and I'm just going to change this
model and I'm just going to change this to be add components it doesn't really
to be add components it doesn't really matter but I like to be consistent and
matter but I like to be consistent and now let's do expert const model
provider and let's go ahead and let's return a frag whoops what did they do
return a frag whoops what did they do let's return a fragment which is going
let's return a fragment which is going to render a list of our models the only
to render a list of our models the only one we have right now is the settings
one we have right now is the settings model so we can just do this and now
model so we can just do this and now here we're going to write the is mounted
here we're going to write the is mounted set is mounted we use State false by
set is mounted we use State false by default and the use effect here let's
default and the use effect here let's start with an empty one and let's just
start with an empty one and let's just write set is mounted to
write set is mounted to true so now none of the models are going
true so now none of the models are going to be rendered unless we are fully on
to be rendered unless we are fully on the client side so on server side we're
the client side so on server side we're just not going to render any models
just not going to render any models that's completely fine we don't need
that's completely fine we don't need them to be optimized or anything and
them to be optimized or anything and that's not going to cause any hydration
that's not going to cause any hydration errors and let's just do if is not
errors and let's just do if is not mounted return now great and now that we
mounted return now great and now that we have the model provider we also have to
have the model provider we also have to add that uh model provider to our layout
add that uh model provider to our layout so let me just save this and let's go
so let me just save this and let's go inside of our app layout.
inside of our app layout. vsx and let's go ahead and add it below
vsx and let's go ahead and add it below the toaster here so model
the toaster here so model provider and make sure you import a
provider and make sure you import a model Provider from here so I'm just
model Provider from here so I'm just going to keep my providers together like
going to keep my providers together like that so I have these three providers let
that so I have these three providers let me move this to the top and let me have
me move this to the top and let me have this all the way here there we go so let
this all the way here there we go so let me just show you you should have these
me just show you you should have these three providers model providers is the
three providers model providers is the one we just added here and we rendered
one we just added here and we rendered it right here model provider perfect and
it right here model provider perfect and now well nothing is still shown here
now well nothing is still shown here right so if I click nothing happens so
right so if I click nothing happens so let's go back inside of our app folder
let's go back inside of our app folder main components navigation and just the
main components navigation and just the same way with the add the use search go
same way with the add the use search go ahead and copy and paste this and rename
ahead and copy and paste this and rename this to use settings and change this to
this to use settings and change this to use
use settings and then you can use that here
settings and then you can use that here in the same way con
in the same way con settings use settings and go ahead and
settings use settings and go ahead and find the settings item the same way we
find the settings item the same way we did with the search item uh it's right
did with the search item uh it's right here there we go so just below the
here there we go so just below the search and change this to be settings.
search and change this to be settings. unopen on open whoops like this there we
unopen on open whoops like this there we go and let's try it out
go and let's try it out now if I go into settings there we go
now if I go into settings there we go let me see if I can click on dark mode
let me see if I can click on dark mode and there we go now everything here is
and there we go now everything here is on dark mode and it looks like we have
on dark mode and it looks like we have uh a bit of issues here so let's see
uh a bit of issues here so let's see first thing I'm noticing is that on dark
first thing I'm noticing is that on dark mode this seems to have its own little
mode this seems to have its own little border here which is just weird so we're
border here which is just weird so we're going to have to way find a way to fix
going to have to way find a way to fix that let's see how the search looks
that let's see how the search looks search looks fine uh let's see how this
search looks fine uh let's see how this looks this looks fine as well uh the
looks this looks fine as well uh the trash looks fine but let's see if that's
trash looks fine but let's see if that's true when I delete something so let's go
true when I delete something so let's go ahead oh look at this as you can see
ahead oh look at this as you can see this ones look uh too white for the dark
this ones look uh too white for the dark mode so let's go ahead and quickly
mode so let's go ahead and quickly resolve that first so have something in
resolve that first so have something in your trash and let's go ahead and let's
your trash and let's go ahead and let's revisit our trash component so in inside
revisit our trash component so in inside of app main components trash box right
of app main components trash box right here
here let's find where that is so it's those
let's find where that is so it's those two items right here so find the confirm
two items right here so find the confirm model and find this div with the roll
model and find this div with the roll button so these two ones are our
button so these two ones are our suspects and looks like we put this
suspects and looks like we put this hover color on uh uh light mode but
hover color on uh uh light mode but let's add uh dark hover in that case BG
let's add uh dark hover in that case BG is neutral 600 like that and let's copy
is neutral 600 like that and let's copy and paste this and add it for this div
and paste this and add it for this div as well which has the roll button which
as well which has the roll button which has the trash icon so let me just add a
has the trash icon so let me just add a space here and paste that let's see if
space here and paste that let's see if that improved anything so I'm going to
that improved anything so I'm going to go back here there we go that that looks
go back here there we go that that looks a bit better now it's not as as shiny as
a bit better now it's not as as shiny as it was before let's just confirm yeah I
it was before let's just confirm yeah I think I think that looks okay it kind of
think I think that looks okay it kind of looks the same when I hover here that's
looks the same when I hover here that's fine uh and let me just see what's going
fine uh and let me just see what's going on uh with this right
on uh with this right here so we have to go back inside of our
here so we have to go back inside of our item component for this let me close
item component for this let me close this let's find the app main components
this let's find the app main components item and let's find the Chevron icon
item and let's find the Chevron icon because that's the one uh that we need
because that's the one uh that we need here where is this is the Chevron icon
here where is this is the Chevron icon and we render it right here let's see
and we render it right here let's see the class names so H full rounded small
the class names so H full rounded small hover BG neutral and then on dark oh
hover BG neutral and then on dark oh looks like we added the BG neutral like
looks like we added the BG neutral like this it's missing a dark hover like this
this it's missing a dark hover like this dark colon hover colon
dark colon hover colon let's try it out now and there we go now
let's try it out now and there we go now it looks a bit better perfect so this is
it looks a bit better perfect so this is how I wanted it to look like perfect and
how I wanted it to look like perfect and as you can see everything looks great
as you can see everything looks great here great great job so now we are ready
here great great job so now we are ready to continue uh working here and now
to continue uh working here and now we're going to go ahead and work on this
we're going to go ahead and work on this nov bar so when we click on this first
nov bar so when we click on this first we're going to get rid of this 404 error
we're going to get rid of this 404 error and we're not going to display anything
and we're not going to display anything yet but we're just going to be working
yet but we're just going to be working on the kn bar so we can finally rename
on the kn bar so we can finally rename our documents and you're going to see
our documents and you're going to see how cool it is when it happens in real
how cool it is when it happens in real time using the convex
time using the convex database so now that we have our sidebar
database so now that we have our sidebar finished we have the working search we
finished we have the working search we have the working settings let's go ahead
have the working settings let's go ahead and let's fix this 404 page which
and let's fix this 404 page which happens when we click on a specific
happens when we click on a specific document from our sidebar here so in
document from our sidebar here so in order to fix that let's go ahead inside
order to fix that let's go ahead inside of our app folder main routes documents
of our app folder main routes documents and in inside create another folder in
and in inside create another folder in uh square brackets document ID like this
uh square brackets document ID like this and inside create a new file page. DSX
and inside create a new file page. DSX and let's go ahead and name this
and let's go ahead and name this document ID
document ID page and for now let's just return
page and for now let's just return document ID inside and already if you
document ID inside and already if you save this it should be enough to prevent
save this it should be enough to prevent any errors when I click here there we go
any errors when I click here there we go now it says document ID so if you're
now it says document ID so if you're wondering how this works well look at
wondering how this works well look at the look at the URL that I have it's
the look at the URL that I have it's Local Host 3000 documents SL the ID of
Local Host 3000 documents SL the ID of my document right and let's take a look
my document right and let's take a look at the structure we created so we have a
at the structure we created so we have a folder documents and then we have
folder documents and then we have document ID so by using square brackets
document ID so by using square brackets we've made this a route which can be
we've made this a route which can be dynamic so it can be any ID that we want
dynamic so it can be any ID that we want it to be and that's why we can that's
it to be and that's why we can that's way this works if we remove the brackets
way this works if we remove the brackets then it would expect it to literally be
then it would expect it to literally be document ID and it's not what we want so
document ID and it's not what we want so that's why these square brackets are
that's why these square brackets are important uh great so we're going to
important uh great so we're going to leave it like that for now and instead
leave it like that for now and instead we're going to go ahead and focus on
we're going to go ahead and focus on creating uh the navigation bar which is
creating uh the navigation bar which is going to be right here and it's going to
going to be right here and it's going to be only visible when we click on a
be only visible when we click on a specific um item so let's go ahead back
specific um item so let's go ahead back inside of our main folder here inside of
inside of our main folder here inside of components and inside of navigation. DSX
components and inside of navigation. DSX and let's go ahead here and find we
and let's go ahead here and find we already have one navigation here but
already have one navigation here but this is only a placeholder while nothing
this is only a placeholder while nothing is active right it's only used to
is active right it's only used to collapse a specific menu item so let's
collapse a specific menu item so let's go ahead now and let's add the params in
go ahead now and let's add the params in here perhaps we already have them we
here perhaps we already have them we don't so let's go ahead and write con
don't so let's go ahead and write con params to be use perams and you can
params to be use perams and you can import use perams from next SL
import use perams from next SL navigation so just make sure you add use
navigation so just make sure you add use perams from next SL navigation and now
perams from next SL navigation and now that we have prams we can go all the way
that we have prams we can go all the way down here and turn this into a Dynamic
down here and turn this into a Dynamic view so let's go ahead and uh make sure
view so let's go ahead and uh make sure you're inside of this div which holds
you're inside of this div which holds the Navar ref and then we're dynamically
the Navar ref and then we're dynamically going to render the content so if we
going to render the content so if we have rams. document ID so we're using
have rams. document ID so we're using this double exclamation points to turn
this double exclamation points to turn this uh string into a Boolean so if we
this uh string into a Boolean so if we have that in that case we're going to go
have that in that case we're going to go ahead and render a Navar component which
ahead and render a Navar component which we don't yet have which is going to have
we don't yet have which is going to have a prop is collapsed to be is collapsed
a prop is collapsed to be is collapsed which we hold in a state and on reset
which we hold in a state and on reset width it's going to be reset width like
width it's going to be reset width like that otherwise if we don't have it we're
that otherwise if we don't have it we're just going to render this current nov
just going to render this current nov bar which we have right here which just
bar which we have right here which just simply holds the menu icon to expand the
simply holds the menu icon to expand the menu on mobile mode and if you save of
menu on mobile mode and if you save of course you're going to get an error so
course you're going to get an error so now let's go ahead inside of this
now let's go ahead inside of this underscore components and let's create a
underscore components and let's create a new file navb bar. TSX and let's export
new file navb bar. TSX and let's export const
const navbar and let's just return a div say
navbar and let's just return a div say navbar now we can go back inside of our
navbar now we can go back inside of our navigation. TSX and we can import that
navigation. TSX and we can import that from slore navbar make sure you don't
from slore navbar make sure you don't accidentally import this one from the
accidentally import this one from the marketing page so this new one which we
marketing page so this new one which we created which is in the same folder and
created which is in the same folder and let me show you uh how that looks
let me show you uh how that looks so/ navbar make sure you have that and
so/ navbar make sure you have that and as you can see now I have some uh
as you can see now I have some uh overlapping text right here because it's
overlapping text right here because it's both the Novar and the document ID which
both the Novar and the document ID which I've written in the document ID page but
I've written in the document ID page but let's not worry about that now and
let's not worry about that now and instead let's go back inside of navbar
instead let's go back inside of navbar here and let's go ahead and Mark it as
here and let's go ahead and Mark it as use
use client and then let's write interface
client and then let's write interface navbar props to be is collapsed Boolean
navbar props to be is collapsed Boolean and on reset width to be a
and on reset width to be a void and let's go ahead and just assign
void and let's go ahead and just assign those props here so I'm going to extract
those props here so I'm going to extract is collaps and on reset withd
is collaps and on reset withd and I'm going to map them to navbar
and I'm going to map them to navbar props and now if you go back into
props and now if you go back into navigation you should no longer have any
navigation you should no longer have any errors regarding of the rendering of
errors regarding of the rendering of this Novar
this Novar component now let's go back inside of
component now let's go back inside of our convex API because we need to add a
our convex API because we need to add a specific API which we're going to use
specific API which we're going to use inside of this navbar function here so
inside of this navbar function here so let's go inside of the convex folder
let's go inside of the convex folder inside of the documents. DS and let's go
inside of the documents. DS and let's go all the way to the bottom here and let's
all the way to the bottom here and let's go ahead and write export const get by
go ahead and write export const get by ID that's going to be a query which has
ID that's going to be a query which has the arguments of document ID which is a
the arguments of document ID which is a type of v. ID documents besides the
type of v. ID documents besides the arguments we're also going to have a
arguments we're also going to have a Handler which is an asynchronous
Handler which is an asynchronous function which has the context and the
function which has the context and the arguments we pass in Above So as always
arguments we pass in Above So as always first let's go ahead and let's get our
first let's go ahead and let's get our identity so const identity is equal to
identity so const identity is equal to weight context. out user identity and
weight context. out user identity and now we don't have to check for uh
now we don't have to check for uh whether we have the Identity or not
whether we have the Identity or not because we're going to reuse this API
because we're going to reuse this API route for guests to view your published
route for guests to view your published notes right if you remember from the
notes right if you remember from the demo we're going to have a functionality
demo we're going to have a functionality where you will be able to publish your
where you will be able to publish your notes to the web and then everyone who
notes to the web and then everyone who has a link will be able to see them even
has a link will be able to see them even in incognito mode without them being
in incognito mode without them being logged in so we're not just going to
logged in so we're not just going to check for the identity here we're just
check for the identity here we're just going to extract it and instead we're
going to extract it and instead we're immediately going to fetch the document
immediately going to fetch the document so con document is equal to await
so con document is equal to await context. database. getet arguments.
context. database. getet arguments. doent
doent ID and first things first let's check if
ID and first things first let's check if this even exists so if we don't have the
this even exists so if we don't have the document we can go ahead and throw new
document we can go ahead and throw new error not
error not found and now let's check if we can
found and now let's check if we can already show this document to the user
already show this document to the user and the way we know that we can show
and the way we know that we can show this document even without checking
this document even without checking whether we are logged or not is if the
whether we are logged or not is if the document is published so if we publish
document is published so if we publish the documents that means we can already
the documents that means we can already return it but I just want to do one
return it but I just want to do one quick thing I want to confirm that by
quick thing I want to confirm that by any chance it's not archived so let's
any chance it's not archived so let's also confirm the document is not deleted
also confirm the document is not deleted from the side of the Creator and then we
from the side of the Creator and then we can safely return the document and if
can safely return the document and if this is not the case in that case we
this is not the case in that case we continue with our checks and the first
continue with our checks and the first check we have to do if is if we have the
check we have to do if is if we have the identity after all if we don't have it
identity after all if we don't have it throw new error not
authenticated and now let's go ahead and let's extract the user ID const user ID
let's extract the user ID const user ID to be uh identity.
subject and let's go ahead and write if document. user ID is not equal it's not
document. user ID is not equal it's not identical to the user ID which just
identical to the user ID which just extracted in that case it means we are
extracted in that case it means we are not author ized so unauthorized to view
not author ized so unauthorized to view this and otherwise return the
this and otherwise return the document great so now that we have this
document great so now that we have this API endpoint we can head back inside of
API endpoint we can head back inside of our navbar here and let's go ahead and
our navbar here and let's go ahead and let's
let's import uh use Query from convex
import uh use Query from convex react like that and we also have to add
react like that and we also have to add our params so use pams from next SL
our params so use pams from next SL navigation
navigation and now let's go ahead and let's extract
and now let's go ahead and let's extract the
prams and now we can do the query so cons document is equal use Query api.
cons document is equal use Query api. document oops let me show you what I'm
document oops let me show you what I'm writing uh I didn't import API so let's
writing uh I didn't import API so let's import API from
import API from atcore generated API right here so just
atcore generated API right here so just as I did it here I'm just going to
as I did it here I'm just going to separate this Imports and then we can
separate this Imports and then we can just autocomplete API documents get by
just autocomplete API documents get by ID and we have to passing the argument
ID and we have to passing the argument which is the document ID and that's
which is the document ID and that's going to be pam. doent ID but now we're
going to be pam. doent ID but now we're going to have a type error here because
going to have a type error here because pam. doent ID is a string but what we
pam. doent ID is a string but what we expect is a type of ID documents so we
expect is a type of ID documents so we can just simply fix this by writing as
can just simply fix this by writing as ID and we have to import that from ATC
ID and we have to import that from ATC convex _ generated data model so make
convex _ generated data model so make sure you add this import as well and
sure you add this import as well and extract the ID and then we can just
extract the ID and then we can just write ID documents and there we go no
write ID documents and there we go no errors here perfect now let's go ahead
errors here perfect now let's go ahead and let's write if document is undefined
and let's write if document is undefined for now we're just going to return a
for now we're just going to return a paragraph saying loading later we're
paragraph saying loading later we're going to change that to be a proper
going to change that to be a proper skeleton uh perfect and now let's go
skeleton uh perfect and now let's go ahead and let's just write if by chance
ahead and let's just write if by chance the document is null we're going to
the document is null we're going to return null as well otherwise let's go
return null as well otherwise let's go ahead and let's change this to be a
ahead and let's change this to be a fragment like that let's add the
fragment like that let's add the navigation element and let's give it a
navigation element and let's give it a class name of BG Das background let's
class name of BG Das background let's give it a dark of BG Das hex code 1 F1
give it a dark of BG Das hex code 1 F1 f1f PX3 py 2 w- full Flex items D Center
f1f PX3 py 2 w- full Flex items D Center and GAP
and GAP dx-4 great so now that we have that
dx-4 great so now that we have that let's go inside of here and let's
let's go inside of here and let's dynamically render our is collapsed
dynamically render our is collapsed in that case go ahead and render the
in that case go ahead and render the menu icon from Lucid react so make sure
menu icon from Lucid react so make sure you add the menu icon from Lucid react
you add the menu icon from Lucid react I'm going to move it with this Global
I'm going to move it with this Global Imports at the top and let's go ahead
Imports at the top and let's go ahead and let's give this one uh a roll of
and let's give this one uh a roll of button let's give it an on click on on
button let's give it an on click on on reset width and let's give it a class
reset width and let's give it a class name of h-6 w-6 and text- muted D
name of h-6 w-6 and text- muted D foreground uh great and now out inside
foreground uh great and now out inside this uh Dynamic uh conditional rendering
this uh Dynamic uh conditional rendering open up a
open up a div with a class
div with a class name uh which is going to be Flex items
name uh which is going to be Flex items D Center justify Das between n w- full
D Center justify Das between n w- full like that and let's just write Novar
like that and let's just write Novar here and there we go let's take a look
here and there we go let's take a look at how this looks now as you can see on
at how this looks now as you can see on desktop it just says Novar and as you
desktop it just says Novar and as you can see right now uh it looks like our
can see right now uh it looks like our document ID text has disappeared but
document ID text has disappeared but it's still here is just that we've given
it's still here is just that we've given this a white background so it's no
this a white background so it's no longer visible but don't worry when we
longer visible but don't worry when we come back to the document we're going to
come back to the document we're going to properly align all that and as you can
properly align all that and as you can see when I completely collapse this I
see when I completely collapse this I have a nice little menu here and if I go
have a nice little menu here and if I go ahead and delete this you can see how it
ahead and delete this you can see how it still says navbar here so let's see if
still says navbar here so let's see if that's oh okay because the URL is still
that's oh okay because the URL is still here so let's manually just change to SL
here so let's manually just change to SL documents like this there we go and if I
documents like this there we go and if I Collapse now you can see how we still
Collapse now you can see how we still have all of that and if we go here then
have all of that and if we go here then you can see how it's next to the nov bar
you can see how it's next to the nov bar here because it's going to load the that
here because it's going to load the that specific document here perfect uh so
specific document here perfect uh so make sure you click on a specific
make sure you click on a specific document make sure you have the N bar
document make sure you have the N bar here and what we're going to do now is
here and what we're going to do now is we're going to create a little component
we're going to create a little component called title so the user can actually
called title so the user can actually change the title from
change the title from here so inside of this nav element right
here so inside of this nav element right here let's go ahead and replace this
here let's go ahead and replace this text which says navbar with a title
text which says navbar with a title component which is going to have initial
component which is going to have initial data to be document which we fetch from
data to be document which we fetch from this query right here and if you save of
this query right here and if you save of course you're going to get an error
course you're going to get an error because title does not exist as a
because title does not exist as a component yet so let's go ahead and
component yet so let's go ahead and quickly create that right here in the
quickly create that right here in the underscore components where our Navar
underscore components where our Navar and navigation is create a title. vsx
and navigation is create a title. vsx let's go ahead and Mark this as use
let's go ahead and Mark this as use client as well and let's export cons
client as well and let's export cons title and return a div saying title now
title and return a div saying title now we can go back to the nov bar and we can
we can go back to the nov bar and we can import that uh make sure you don't
import that uh make sure you don't import from any of this so just do
import from any of this so just do /title it's in the same folder so just
/title it's in the same folder so just like that no need to complicate it
like that no need to complicate it further now let's go back inside of the
further now let's go back inside of the title component and let's give it some
title component and let's give it some props so interface title props initial
props so interface title props initial data is a type of document which we get
data is a type of document which we get from at/
from at/ convex uh generated data model and let's
convex uh generated data model and let's go ahead and extract documents like that
go ahead and extract documents like that and let's go ahead and extract that here
and let's go ahead and extract that here so title props and initial data uh great
so title props and initial data uh great so now what we have to do is create
so now what we have to do is create another API endpoint which is going to
another API endpoint which is going to be used uh for updating a document since
be used uh for updating a document since we're going to change the title here we
we're going to change the title here we have to prepare that endpoint so let's
have to prepare that endpoint so let's go back inside of our documents in the
go back inside of our documents in the convex folder right here let's go all
convex folder right here let's go all the way down and let's go ahead and
the way down and let's go ahead and write export const update to the am
write export const update to the am mutation
mutation which has uh the following arguments it
which has uh the following arguments it will have an ID which is a type of ID
will have an ID which is a type of ID documents it's going to have the title
documents it's going to have the title which is an optional value so not always
which is an optional value so not always are we going to have to pass that and
are we going to have to pass that and it's a type of v. string we're also
it's a type of v. string we're also going to have the content which is also
going to have the content which is also optional and also a type of string we're
optional and also a type of string we're going to have a cover image which is
going to have a cover image which is also going to be optional and the type
also going to be optional and the type of
of string besides the the cover image we're
string besides the the cover image we're also going to have an icon which is also
also going to have an icon which is also an optional
an optional string and last one is going to be is
string and last one is going to be is published which is an optional
published which is an optional Boolean great and now let's get our
Boolean great and now let's get our Handler which is an asynchronous
Handler which is an asynchronous function which has the context and the
function which has the context and the arguments and let's go ahead and let's
arguments and let's go ahead and let's start by checking if we have the
start by checking if we have the identity so const identity is equal to
identity so const identity is equal to await context. r arguments sorry
await context. r arguments sorry context. out.get user identity if there
context. out.get user identity if there is no
is no identity in that case throw new error un
unauthenticated okay and now let's extract the user ID to be identity.
extract the user ID to be identity. subject and now let's prepare our data
subject and now let's prepare our data from these arguments right here so I'm
from these arguments right here so I'm going to go ahead and write const
going to go ahead and write const from the arguments and I'm going to
from the arguments and I'm going to extract the ID and then I'm just going
extract the ID and then I'm just going to keep everything as rest so I'm D
to keep everything as rest so I'm D structuring everything inside of these
structuring everything inside of these arguments and that's all of this stuff
arguments and that's all of this stuff and I'm purposely extracting the ID
and I'm purposely extracting the ID because we're never going to send the ID
because we're never going to send the ID to be updated we're just going to use it
to be updated we're just going to use it um to find what we have to update but
um to find what we have to update but with this one we can just pass in the
with this one we can just pass in the rest in the patch function and that's
rest in the patch function and that's going to update whatever we send it so
going to update whatever we send it so if we sent a title title is going to get
if we sent a title title is going to get updated if we sent a content content and
updated if we sent a content content and same for all the other things so we kind
same for all the other things so we kind of eliminated or omited the ID from the
of eliminated or omited the ID from the arguments object by creating a
arguments object by creating a destructuring method here where we just
destructuring method here where we just kept everything else inside of a
kept everything else inside of a constant name rest and extracted ID
constant name rest and extracted ID separately all right and now let's fetch
separately all right and now let's fetch the documents so con existing document
the documents so con existing document is going to be await context. database.
is going to be await context. database. getet arguments
getet arguments ID and now let's go if there is no
ID and now let's go if there is no existing
existing document throw new
document throw new error
error not
not found and let's check if we have the
found and let's check if we have the authorization to do this so if the
authorization to do this so if the existing document. user ID is not
existing document. user ID is not identical to the user ID we extracted
identical to the user ID we extracted using the identity subject in that case
using the identity subject in that case throw new
throw new error unauthorized
and now we can just do cons document to be await context. database. patch
be await context. database. patch arguments. ID and just spread rest and
arguments. ID and just spread rest and return the document just like that we
return the document just like that we have our uh Pat function here perfect so
have our uh Pat function here perfect so we're going to use this uh function
we're going to use this uh function update every time we need to update
update every time we need to update something and the first place we're
something and the first place we're going to use it is inside of the title
going to use it is inside of the title component so let's go ahead and let's
component so let's go ahead and let's import use mutation from convex
import use mutation from convex react and let's also import our API from
react and let's also import our API from convex generated
convex generated API and let's go ahead and let's write
API and let's go ahead and let's write const update to be use mutation api.
const update to be use mutation api. documents Dot and it's right here
documents Dot and it's right here update great so now that we have that
update great so now that we have that let's go ahead and let's actually render
let's go ahead and let's actually render something here so in this div we're
something here so in this div we're going to go ahead and give it a class
going to go ahead and give it a class name of flex items D Center and GAP
name of flex items D Center and GAP X1 we're going to go ahead and render
X1 we're going to go ahead and render the icon if we have it so if inside of
the icon if we have it so if inside of the initial data we have the icon in
the initial data we have the icon in that case go ahead and render a
that case go ahead and render a paragraph oops my apologies and inside
paragraph oops my apologies and inside we're just going to render the initial
we're just going to render the initial data do icon that simple and now let's
data do icon that simple and now let's go ahead and write uh well first we have
go ahead and write uh well first we have to add a state called is editing so
to add a state called is editing so let's go ahead and do that const is
let's go ahead and do that const is editing and set is editing it's going to
editing and set is editing it's going to be used state from react with a default
be used state from react with a default value of false so let me just move this
value of false so let me just move this to the top right here uh great and now
to the top right here uh great and now let's go ahead and let's dynamically
let's go ahead and let's dynamically render using this is editing Boolean
render using this is editing Boolean right here so if we are
right here so if we are editing then we're going to render the
editing then we're going to render the input component from add/ components UI
input component from add/ components UI input make sure you have this imported
input make sure you have this imported from chaten like this and let's go ahead
from chaten like this and let's go ahead and let's give it uh well for now we can
and let's give it uh well for now we can just give it a class name of h-7 px-2
just give it a class name of h-7 px-2 and focus D visible to be ring-
and focus D visible to be ring- transparent like that uh and we don't
transparent like that uh and we don't have to give it anything else for now
have to give it anything else for now and let's go ahead and write the else
and let's go ahead and write the else function here instead we're going to
function here instead we're going to render a button like that so make sure
render a button like that so make sure you import button from at/ components UI
you import button from at/ components UI button and what we're going to do is
button and what we're going to do is going to render the initial
going to render the initial data do title like this inside and let's
data do title like this inside and let's go ahead and give this button and on
go ahead and give this button and on click which is just going to be an empty
click which is just going to be an empty Arrow function for now a variant of
Arrow function for now a variant of ghost a size of small and the class name
ghost a size of small and the class name of font
of font dormal h- aouto and padding of one and
dormal h- aouto and padding of one and let's wrap this inside of a
let's wrap this inside of a span
span and let's write a class name
and let's write a class name truncate great so now if you take a look
truncate great so now if you take a look here this becomes a little button and
here this becomes a little button and when we click on it we're going to
when we click on it we're going to change this is editing state to true and
change this is editing state to true and then that's going to turn into an input
then that's going to turn into an input so let's go ahead and play around with
so let's go ahead and play around with that so let's add some refs that we need
that so let's add some refs that we need here and some functions so I'm going to
here and some functions so I'm going to write const input ref here to be use ref
write const input ref here to be use ref from uh react make sure you import user
from uh react make sure you import user ref right here and let's give it a type
ref right here and let's give it a type of HTML input element with a default
of HTML input element with a default value of
value of null great now let's go ahead uh and
null great now let's go ahead uh and let's create uh the title uh uh state so
let's create uh the title uh uh state so cons title set title is use State and
cons title set title is use State and the default value is initial data. tile
the default value is initial data. tile or
or Untitled just in case we are not able to
Untitled just in case we are not able to load it and let's write Con in enable
load it and let's write Con in enable input to be set title to initial data.
input to be set title to initial data. title in case it has changed in that
title in case it has changed in that time and then set is editing to be
time and then set is editing to be true and set
timeout with a timeout of zero so we're just using a little hack here because I
just using a little hack here because I want to focus on the input and to do
want to focus on the input and to do that we're going to use the input ref.
that we're going to use the input ref. current question mark focus and we're
current question mark focus and we're going to input ref. current question
going to input ref. current question mark set selection range to start from
mark set selection range to start from zero and end by the
zero and end by the entire length of the value great and now
entire length of the value great and now that we have that uh let's go ahead uh
that we have that uh let's go ahead uh and let's add a couple of more functions
and let's add a couple of more functions which we need here so we're going to
which we need here so we're going to need the disable input con disable input
need the disable input con disable input is going to be a function which just
is going to be a function which just calls Set uh is
calls Set uh is editing back to false so very simple but
editing back to false so very simple but we're going to use it in a function so
we're going to use it in a function so it's easier to call and now let's do
it's easier to call and now let's do const on change to be a type of event
const on change to be a type of event which has the react. change
which has the react. change event HTML input element like
event HTML input element like that and let's set title locally to be
that and let's set title locally to be event. target. value and then let's go
event. target. value and then let's go ahead and let's call our update function
ahead and let's call our update function our update mutation to have the ID of
our update mutation to have the ID of initial
initial data doore ID and let's pass in the
data doore ID and let's pass in the title to be event. target. value or
title to be event. target. value or Untitled so if we try to delete
Untitled so if we try to delete everything it's automatically going to
everything it's automatically going to go back to Untitled we're never going to
go back to Untitled we're never going to allow uh the user to delete the entire
allow uh the user to delete the entire title if they remove everything it's
title if they remove everything it's going to be Untitled all right and now
going to be Untitled all right and now that we have this let's just create a uh
that we have this let's just create a uh Onkey down function so Con on key down
Onkey down function so Con on key down and in here we're going to check if the
and in here we're going to check if the user presses enter we're going to
user presses enter we're going to consider that they want to save that so
consider that they want to save that so go ahead and get the event again which
go ahead and get the event again which is react. keyboard event with a type of
is react. keyboard event with a type of HTML input
HTML input element and we're going to check if
element and we're going to check if event. key is
event. key is enter in that case disable the
enter in that case disable the input great so now that we have all of
input great so now that we have all of that let's go ahead and let's go revisit
that let's go ahead and let's go revisit our input here let's give it a ref of
our input here let's give it a ref of input ref let's give it an on click to
input ref let's give it an on click to be enable
be enable input let's give it an on
input let's give it an on blur to be disable
blur to be disable input let's give it an on change to be
input let's give it an on change to be on change on key down to be on key down
on change on key down to be on key down and the value is going to be our State
and the value is going to be our State title great and now let's go ahead and
title great and now let's go ahead and give this button and on click to be
give this button and on click to be enable
enable input like that and that should be it
input like that and that should be it let's go ahead and let's see if this is
let's go ahead and let's see if this is working so right now this file is called
working so right now this file is called entitled let's confirm that in the
entitled let's confirm that in the dashboard
dashboard here uh okay let's see it's the this one
here uh okay let's see it's the this one I think let me actually just clear
I think let me actually just clear everything so it's easier clear the
everything so it's easier clear the entire table from convex here great now
entire table from convex here great now we have an error don't worry we're going
we have an error don't worry we're going to solve that so for now just go ahead
to solve that so for now just go ahead to slash documents so remove the ID from
to slash documents so remove the ID from your URL and let let's create a new page
your URL and let let's create a new page here let's go inside of it and let's go
here let's go inside of it and let's go ahead and let's rename and there we go
ahead and let's rename and there we go it's renamed in real time because we're
it's renamed in real time because we're using a realtime database so our use
using a realtime database so our use Query which uses the get sidebar
Query which uses the get sidebar endpoint is also watching for the
endpoint is also watching for the changes in real time and we can do that
changes in real time and we can do that for the children as well so we can
for the children as well so we can change this and you can see how it
change this and you can see how it reflects even though it's a children so
reflects even though it's a children so it's a very very cool database perfect
it's a very very cool database perfect you can see how this is changed in the
you can see how this is changed in the database as well if you have any doubts
database as well if you have any doubts perfect so now what I want to do is I
perfect so now what I want to do is I want to add a skeleton for this title so
want to add a skeleton for this title so we can actually use some proper loading
we can actually use some proper loading state in the nav bar so let's write
state in the nav bar so let's write title do
skeleton uh skeleton to be function title
title skeleton and go ahead and return the
skeleton and go ahead and return the actual skeleton which we have from at/
actual skeleton which we have from at/ components skeleton so just make sure
components skeleton so just make sure you import that and let's go ahead and
you import that and let's go ahead and give this one a class name of h-9
give this one a class name of h-9 w-16 and rounded medium
w-16 and rounded medium perfect now let's head back uh inside of
perfect now let's head back uh inside of our navbar
our navbar component find where we have this if
component find where we have this if document is undefined we just return a
document is undefined we just return a paragraph and go ahead and change that
paragraph and go ahead and change that instead we're going to render a NV bar
instead we're going to render a NV bar which is going to have uh the very same
which is going to have uh the very same uh class name here except for the flex
uh class name here except for the flex so we don't need Flex you can just copy
so we don't need Flex you can just copy BG background dark PX3 py and you can
BG background dark PX3 py and you can just copy this actually we do need Flex
just copy this actually we do need Flex as well uh so let's go ahead and copy
as well uh so let's go ahead and copy the flex as well my apologies so just
the flex as well my apologies so just like this BG background or dark
like this BG background or dark background padding uh on siid three
background padding uh on siid three padding on top and bottom two uh W full
padding on top and bottom two uh W full like this and the flex and items Center
like this and the flex and items Center great and inside what we're going to do
great and inside what we're going to do is render title do
is render title do skeleton like this and
skeleton like this and now if you try and play around with this
now if you try and play around with this you can see how for a second we have a
you can see how for a second we have a nice skeleton instead of just a blank
nice skeleton instead of just a blank page here you can see how it's a
page here you can see how it's a skeleton here perfect and you can play
skeleton here perfect and you can play around you can reduce the size of the
around you can reduce the size of the skeleton if you think it's too much so
skeleton if you think it's too much so let's see let's use height six for
let's see let's use height six for example maybe that's going to look a
example maybe that's going to look a tiny bit better let's
tiny bit better let's yeah maybe maybe not but you know you
yeah maybe maybe not but you know you can play around and find the one you
can play around and find the one you need so let's see if I can reduce it to
need so let's see if I can reduce it to maybe three and maybe increase
maybe three and maybe increase this will that do any better let's see
this will that do any better let's see uh maybe I go back to four so I'm just
uh maybe I go back to four so I'm just trying it out now uh let's see if that
trying it out now uh let's see if that looks
looks better yeah looks like that one uh looks
better yeah looks like that one uh looks the closest maybe uh five would that be
the closest maybe uh five would that be better let let me just bring it back to
better let let me just bring it back to six yeah okay I'm I'm going to bring it
six yeah okay I'm I'm going to bring it back to what was it before was it
back to what was it before was it nine it doesn't really matter you can
nine it doesn't really matter you can play around but I just want it to look
play around but I just want it to look as good as possible okay let's leave it
as good as possible okay let's leave it like this uh great great job so you
like this uh great great job so you started with the navbar and we do have a
started with the navbar and we do have a couple of more things to add to the
couple of more things to add to the Navar we're going to do that later um
Navar we're going to do that later um but what I want to do next is a little
but what I want to do next is a little Banner which is going to show if you
Banner which is going to show if you deleted a specific uh document so if you
deleted a specific uh document so if you go ahead and click it from here you can
go ahead and click it from here you can still work with it right but I want to
still work with it right but I want to show a little Banner here which is
show a little Banner here which is saying that this is archived and give
saying that this is archived and give you the actions to unarchive
you the actions to unarchive it so now let's go ahead and create that
it so now let's go ahead and create that little Banner here so let's go back
little Banner here so let's go back inside of the let me just check the
inside of the let me just check the navigation a bit I think I've noticed
navigation a bit I think I've noticed while I was watching the video back I
while I was watching the video back I think I've noticed I made a a mistake in
think I've noticed I made a a mistake in in one of the V uh this W full classes
in one of the V uh this W full classes perhaps it's here in the knv bar let's
perhaps it's here in the knv bar let's see W full here looks good W full here
see W full here looks good W full here looks good oh there we go I have a
looks good oh there we go I have a little bug here so this should be W full
little bug here so this should be W full all right uh great so now let's go ahead
all right uh great so now let's go ahead and let's create that Banner component
and let's create that Banner component so that's why we added a little fragment
so that's why we added a little fragment here so we're going to go below this
here so we're going to go below this right here and we're going to write if
right here and we're going to write if the document is archived in that case
the document is archived in that case we're going to go ahead and render uh
we're going to go ahead and render uh well let's not use the question mark
well let's not use the question mark let's use the end end
let's use the end end option in that case we're going to
option in that case we're going to render a banner component and you can go
render a banner component and you can go ahead and save this and don't worry
ahead and save this and don't worry about the error for now and let's go
about the error for now and let's go ahead and give it a prop of document ID
ahead and give it a prop of document ID to be document uncore ID because that's
to be document uncore ID because that's the only thing uh that we need from it
the only thing uh that we need from it and now let's go ahead inside of the
and now let's go ahead inside of the components and create a new file banner.
components and create a new file banner. DSX like that let's mark this as use
DSX like that let's mark this as use client and let's go ahead and Export con
client and let's go ahead and Export con banner and return a div saying banner
banner and return a div saying banner and go back to navbar right here and
and go back to navbar right here and import the banner from slash uh Banner
import the banner from slash uh Banner like that and now let's go ahead and
like that and now let's go ahead and give it an interface so I can already
give it an interface so I can already see the banner here if you can see it
see the banner here if you can see it it's probably because you're looking in
it's probably because you're looking in one of these so make sure you're in the
one of these so make sure you're in the trash or just add something to the trash
trash or just add something to the trash and then click on it here and then you
and then click on it here and then you should see this Banner because we are
should see this Banner because we are only rendering the banner if the
only rendering the banner if the document is archived great so now let's
document is archived great so now let's go inside of the banner and let's go
go inside of the banner and let's go ahead and create an interface so
ahead and create an interface so interface Banner props it's going to
interface Banner props it's going to accept a document ID which is going to
accept a document ID which is going to be a type of string like that uh you can
be a type of string like that uh you can just leave it uh actually you can let's
just leave it uh actually you can let's give it the proper type this is the
give it the proper type this is the proper type yeah like that and now let's
proper type yeah like that and now let's go ahead and extract the document
go ahead and extract the document ID and let's assign that to Banner props
ID and let's assign that to Banner props and I just have a typo here so ID like
and I just have a typo here so ID like that and there we go looks like this is
that and there we go looks like this is okay because underscore ID is this type
okay because underscore ID is this type right here ID documents perfect so we
right here ID documents perfect so we can uh give it that type in the props
can uh give it that type in the props great so now let's add our router so con
great so now let's add our router so con rout is equal to use router from next SL
rout is equal to use router from next SL navigation so make sure you add that I'm
navigation so make sure you add that I'm just going to keep this import separated
just going to keep this import separated besides the router we're also going to
besides the router we're also going to have our mutations for removing and
have our mutations for removing and restoring so const remove is going to be
restoring so const remove is going to be use mutation from convex react make sure
use mutation from convex react make sure you add this so we're going to have two
you add this so we're going to have two mutations this one is going to be API so
mutations this one is going to be API so make sure you add API from convex
make sure you add API from convex generated API api. documents. remove and
generated API api. documents. remove and copy and paste this and this one is
copy and paste this and this one is going to be Resto store and the API
going to be Resto store and the API route is going to be restore like that
route is going to be restore like that uh great so now let's go ahead and let's
uh great so now let's go ahead and let's import toast from the soner package and
import toast from the soner package and let's go ahead and create some uh
let's go ahead and create some uh functions here so const on remove it's
functions here so const on remove it's very simply going to be a function which
very simply going to be a function which gets the
gets the promise and calls the remove mutation
promise and calls the remove mutation and passes in the ID to be document ID
and passes in the ID to be document ID which we have in the props and then we
which we have in the props and then we can do toast. promise passing the
can do toast. promise passing the promise and do the loading state which
promise and do the loading state which says deleting
says deleting note we're going to have the success
note we're going to have the success state which says note
state which says note deleted and we're going to have the
deleted and we're going to have the error state which says failed to delete
error state which says failed to delete note perfect and now we can copy and
note perfect and now we can copy and paste this and it's going to be very
paste this and it's going to be very similar for the restore option so this
similar for the restore option so this one is going to be called on restore and
one is going to be called on restore and instead of uh prom is being removed it's
instead of uh prom is being removed it's going to be restore and instead of
going to be restore and instead of deleting it's going to be restoring
deleting it's going to be restoring instead of note deleted it's going to be
instead of note deleted it's going to be note restored and this is going to be
note restored and this is going to be failed to restore note great so now we
failed to restore note great so now we have these two actions on remove and on
have these two actions on remove and on restore which call these two mutations
restore which call these two mutations here and now let's go
here and now let's go ahead uh and yeah once let's also go
ahead uh and yeah once let's also go back to this on remove here and once we
back to this on remove here and once we remove it uh let's also add a redirect
remove it uh let's also add a redirect so do then here let's just go ahead and
so do then here let's just go ahead and write router. push to/
write router. push to/ documents like that great uh and now
documents like that great uh and now let's go and finally style this Banner
let's go and finally style this Banner here so go ahead and give this div a
here so go ahead and give this div a class name of
class name of w-o background of
w-o background of r-500 great text is going to be
r-500 great text is going to be centered text is also going to be small
centered text is also going to be small padding is going to be two text is going
padding is going to be two text is going to be white
to be white Flex items Cent
Flex items Cent Center Gap X2 and justify Center great
Center Gap X2 and justify Center great and now let's go ahead and give this a
and now let's go ahead and give this a paragraph which is going to say this
paragraph which is going to say this page is in the
page is in the trash like that and now go ahead and add
trash like that and now go ahead and add a button here and let's import the
a button here and let's import the button from add/ components UI button so
button from add/ components UI button so make sure you have this import here
make sure you have this import here great and inside let's just say restore
great and inside let's just say restore page and now let's go ahead and give it
page and now let's go ahead and give it a size of small let's give it an onclick
a size of small let's give it an onclick to be on
to be on restore which is the function we created
restore which is the function we created a variant is going to be outline and
a variant is going to be outline and let's go ahead and give it a class name
let's go ahead and give it a class name of Border D white BG
of Border D white BG transparent cover dg- primary
transparent cover dg- primary sl5 text is going to be white let me
sl5 text is going to be white let me just scroll down so this is Centered for
just scroll down so this is Centered for you on Hover text is also going to be
you on Hover text is also going to be white padding one px2 height is going to
white padding one px2 height is going to be Auto and font is going to be normal
be Auto and font is going to be normal there we go and then you can copy and
there we go and then you can copy and paste this button like this and make
paste this button like this and make this one to be delete
this one to be delete forever forever like this and use the
forever forever like this and use the function on remove like that but we're
function on remove like that but we're not going to do uh just that I also want
not going to do uh just that I also want to import the confirm model so let's go
to import the confirm model so let's go ahead and
import confirm model and remember this one doesn't use the two stand instead it
one doesn't use the two stand instead it has a trigger and Trigger is whatever we
has a trigger and Trigger is whatever we wrap it around so in this case it's
wrap it around so in this case it's going to be this button so confirm
going to be this button so confirm model like this and just wrap the entire
model like this and just wrap the entire delete forever button because this is an
delete forever button because this is an irreversible action so we want to make
irreversible action so we want to make sure that user has the confirmation for
sure that user has the confirmation for it if they accidentally click on it and
it if they accidentally click on it and then you can remove this on click from
then you can remove this on click from here from the button and instead you can
here from the button and instead you can add it here and write on confirm to be
add it here and write on confirm to be on remove great and let's go ahead and
on remove great and let's go ahead and try this out so now it says this page is
try this out so now it says this page is in trash if I click restore it says note
in trash if I click restore it says note restored perfect and if I go ahead and
restored perfect and if I go ahead and delete it again now it says this page is
delete it again now it says this page is in trash and if I go ahead and check
in trash and if I go ahead and check it's right here if I click delete
it's right here if I click delete forever I have a model and confirm and
forever I have a model and confirm and uh okay looks like it did not redirect
uh okay looks like it did not redirect us back let's confirm why that is
us back let's confirm why that is happening that we do something wrong
happening that we do something wrong here all right it we do remove then we
here all right it we do remove then we do a then
do a then H let me just see what's going on
H let me just see what's going on here so let's try not by wrapping it in
here so let's try not by wrapping it in a DOT then let's just do it at the end
a DOT then let's just do it at the end of the function and remove this chain to
of the function and remove this chain to then
then here uh now we're still going to get an
here uh now we're still going to get an error because we are here so just go
error because we are here so just go back to SL documents like we did
back to SL documents like we did previously and let's go ahead and
previously and let's go ahead and attempt this again so let me delete this
attempt this again so let me delete this and let's go ahead and delete this
and let's go ahead and delete this forever and there we go now we don't
forever and there we go now we don't have the error great so just go ahead
have the error great so just go ahead and add that uh to the end of the
and add that uh to the end of the function no need to wait for this
function no need to wait for this promise so we actually want to be faster
promise so we actually want to be faster than the promise uh great so now you
than the promise uh great so now you have a fully working Banner which shows
have a fully working Banner which shows Once you delete a specific um a
Once you delete a specific um a page and just one thing that I want to
page and just one thing that I want to do before we go on to some other things
do before we go on to some other things that we're going to have in the nav bar
that we're going to have in the nav bar uh is I want to visit our uh components
uh is I want to visit our uh components UI button. DSX and as you can see it
UI button. DSX and as you can see it says that rounded is medium I want to
says that rounded is medium I want to change it to rounded small like that so
change it to rounded small like that so I want every single button in in our
I want every single button in in our page to have a smaller roundness and I
page to have a smaller roundness and I just think it looks closer to original
just think it looks closer to original notion uh great so we did that and and
notion uh great so we did that and and let me just go ahead and reset
let me just go ahead and reset everything so the next thing we're going
everything so the next thing we're going to do is we're going to add a little uh
to do is we're going to add a little uh menu here to also be able to delete the
menu here to also be able to delete the entire page from here so currently we
entire page from here so currently we can only do it from this three buttons
can only do it from this three buttons it would be nice to also have those
it would be nice to also have those three buttons here at the top so let's
three buttons here at the top so let's do
do that let's go back inside of our Navar
that let's go back inside of our Navar component so inside the app folder main
component so inside the app folder main components
components Novar and besides the title right here
Novar and besides the title right here go ahead and add a div right here and
go ahead and add a div right here and give it a class name of
give it a class name of flex items Das Center and GAP X2 and go
flex items Das Center and GAP X2 and go ahead and render the menu component
ahead and render the menu component which we don't yet have and give it a
which we don't yet have and give it a document ID to be
document ID to be documentor ID and save the file and of
documentor ID and save the file and of course we get a little error here so
course we get a little error here so let's go ahead and create that comp
let's go ahead and create that comp component menu. CSX mark it as use
component menu. CSX mark it as use client and let's export const
client and let's export const menu and return a div saying menu and
menu and return a div saying menu and now we can go back inside of the enough
now we can go back inside of the enough bar and fix this error so make sure it's
bar and fix this error so make sure it's not the Lucid react import but the do/
not the Lucid react import but the do/ menu so from this very same folder the
menu so from this very same folder the same thing we did with the title and the
same thing we did with the title and the banner and now obviously we have some
banner and now obviously we have some typescript errors here so let's go ahead
typescript errors here so let's go ahead uh and uh let's give it an interface
uh and uh let's give it an interface menu
menu props and I'm just going to write the
props and I'm just going to write the document ID to be a type of ID
document ID to be a type of ID documents great and let's go ahead and
documents great and let's go ahead and assign those props here so menu props
assign those props here so menu props and let's extract the document
and let's extract the document whoa ID great so I just want to bring
whoa ID great so I just want to bring your attention this is called menu and
your attention this is called menu and this from Lucid react I named menu icon
this from Lucid react I named menu icon so if you didn't do that if you have any
so if you didn't do that if you have any errors with conflicting menu That's
errors with conflicting menu That's because menu icon from Lucid react can
because menu icon from Lucid react can also be imported as menu but as you can
also be imported as menu but as you can see then we have duplicate identifier
see then we have duplicate identifier here so make sure that the one from
here so make sure that the one from Lucid react is menu icon or you can do
Lucid react is menu icon or you can do menu as menu icon for
menu as menu icon for example just want to bring your
example just want to bring your attention if you're wondering if you for
attention if you're wondering if you for example didn't do the icon thing and
example didn't do the icon thing and instead just named the menu uh great so
instead just named the menu uh great so we have that now and now we can head
we have that now and now we can head back inside of the menu here and let's
back inside of the menu here and let's import everything we need from the
import everything we need from the drop-down uh menu so go ahead and import
drop-down uh menu so go ahead and import from s/ components UI uh and drop- down
from s/ components UI uh and drop- down menu right here we're going to need the
menu right here we're going to need the drop down menu itself like we always do
drop down menu itself like we always do and we're also going to need a trigger
and we're also going to need a trigger we're also going to need the
we're also going to need the content we're going to need the
content we're going to need the individual item and a
individual item and a separator uh great and now let's go
separator uh great and now let's go ahead and let's add some Hooks and some
ahead and let's add some Hooks and some functions here so const router whoops
functions here so const router whoops const router is use router from next SL
const router is use router from next SL navigation make sure you have that UT
navigation make sure you have that UT I'm just going to move it all the way to
I'm just going to move it all the way to the top because I like to separate my
the top because I like to separate my Global inputs from the ones starting
Global inputs from the ones starting with uh my
with uh my alas besides the router we're also going
alas besides the router we're also going to extract the user from us user which
to extract the user from us user which we GL from clerk as I did right here and
we GL from clerk as I did right here and you already know that I'm going to move
you already know that I'm going to move it here to the top all right
it here to the top all right and now let's go ahead and let's also
and now let's go ahead and let's also get the archive mutation so use mutation
get the archive mutation so use mutation from convex react it's right here let's
from convex react it's right here let's get it out to the top and we also need
get it out to the top and we also need our API so make sure you import API from
our API so make sure you import API from at convex generated API and you already
at convex generated API and you already know API documents. archive like that
know API documents. archive like that and let's write const on
and let's write const on archive to Be an Arrow function where we
archive to Be an Arrow function where we we are simply going to get the
we are simply going to get the promise to be archive with an ID of
promise to be archive with an ID of document
document idid and let's write toast from soner so
idid and let's write toast from soner so just make sure you add this soner
just make sure you add this soner import so toast from sunar is going to
import so toast from sunar is going to be a promise passing that promise and
be a promise passing that promise and let's give it a state of loading to be
let's give it a state of loading to be moving to
trash let's give it a success state of uh note moved to
uh note moved to trash and an error State uh to be piled
trash and an error State uh to be piled to Archive
to Archive note great and let's also do router.
note great and let's also do router. push to/ documents here once we archive
push to/ documents here once we archive it uh great and now instead of this div
it uh great and now instead of this div let's render the drop- down menu which
let's render the drop- down menu which we imported let's add a drop- down menu
we imported let's add a drop- down menu trigger let's give it a prop as child
trigger let's give it a prop as child and inside let's add a button component
and inside let's add a button component so make sure you import the button from
so make sure you import the button from shaten UI I mean from components
shaten UI I mean from components UI all right and let's give it a closing
UI all right and let's give it a closing tag and let's just simply write more
tag and let's just simply write more horizontal from Lucid react so we're
horizontal from Lucid react so we're going to render an icon uh from Lucid
going to render an icon uh from Lucid react and now let's style this a little
react and now let's style this a little bit so give this button a size of small
bit so give this button a size of small and a
and a variant of uh ghost and give this one a
variant of uh ghost and give this one a class name of H4 n W-4 so we uh make
class name of H4 n W-4 so we uh make this a bit smaller now add the dropdown
this a bit smaller now add the dropdown menu
menu content and inside of here let's go
content and inside of here let's go ahead and give it a class
ahead and give it a class name of w- 60 let's give it an Aline on
name of w- 60 let's give it an Aline on end a line offset of eight and force
end a line offset of eight and force amount so let me just collapse all of
amount so let me just collapse all of this like this so it's easier for you to
this like this so it's easier for you to see
great and now inside of here we're going to go ahead and render the drop- down
to go ahead and render the drop- down menu item and we're going to render the
menu item and we're going to render the trash icon from Lucid react so make sure
trash icon from Lucid react so make sure you import uh
you import uh trash okay we're going to give this
trash okay we're going to give this trash a class name of h-4 W-4 and margin
trash a class name of h-4 W-4 and margin right of two and below that we're going
right of two and below that we're going to add a delete text and give this drop
to add a delete text and give this drop down menu item on click to be on
down menu item on click to be on archive uh great and now below this drop
archive uh great and now below this drop down menu item add a drop- down menu
down menu item add a drop- down menu separator which is going to have a div
separator which is going to have a div which is going to say last edited
which is going to say last edited by user question mark full name like
by user question mark full name like this and give this D A Class name of
this and give this D A Class name of text extra small text muted foreground
text extra small text muted foreground and padding off to perfect and now let's
and padding off to perfect and now let's go ahead and see how that looks here so
go ahead and see how that looks here so now I have these three buttons here and
now I have these three buttons here and there we go it says delete I can press
there we go it says delete I can press on it and as you can see it's moved to
on it and as you can see it's moved to trash and I can visit it back from here
trash and I can visit it back from here perfect so now let's go ahead and let's
perfect so now let's go ahead and let's turn this into a skeleton as well so
turn this into a skeleton as well so when this is loading the same way we
when this is loading the same way we have a skeleton here I want to have a
have a skeleton here I want to have a skeleton on this side as well so in
skeleton on this side as well so in order to do that we're going to go
order to do that we're going to go inside of this menu component and add
inside of this menu component and add menu. skeleton to be a function menu
menu. skeleton to be a function menu skeleton
skeleton and go ahead and return a skeleton
and go ahead and return a skeleton component which I imported right here
component which I imported right here from components UI skeleton and go ahead
from components UI skeleton and go ahead and give it a class name of height 10
and give it a class name of height 10 and
and W10 let's go ahead back inside of our
W10 let's go ahead back inside of our Navar now and we have to find uh this
Navar now and we have to find uh this loading state which we have and create a
loading state which we have and create a div below it with a class name of flex
div below it with a class name of flex items D Center and GAP X2 and add the
items D Center and GAP X2 and add the menu do skeleton inside like that we are
menu do skeleton inside like that we are also going to have another element
also going to have another element inside of here so that's why we have
inside of here so that's why we have this Gap X2 the same reason why we have
this Gap X2 the same reason why we have it here because we're going to have two
it here because we're going to have two elements here but we're going to skip
elements here but we're going to skip that one uh for later and now if you
that one uh for later and now if you refresh everything you should see for a
refresh everything you should see for a second a little skeleton there as well
second a little skeleton there as well so let's just try it
so let's just try it out oh oh no we are not seeing it it
out oh oh no we are not seeing it it seems to be right here so let me see uh
seems to be right here so let me see uh what we did
what we did wrong I think I know what we did wrong
wrong I think I know what we did wrong so let's just quickly uh see our loading
so let's just quickly uh see our loading State here oh all right so I think it's
State here oh all right so I think it's because in this Novar when we give it a
because in this Novar when we give it a flex we don't give it a justify between
flex we don't give it a justify between option so let's give it justify Dash
option so let's give it justify Dash between so this title skeleton and this
between so this title skeleton and this div is going to be far away from each
div is going to be far away from each other so let's try that now I'm going to
other so let's try that now I'm going to refresh everything again and there we go
refresh everything again and there we go now for a second there I saw a nice
now for a second there I saw a nice little skeleton perfect so I have the
little skeleton perfect so I have the skeleton here I have it here exactly
skeleton here I have it here exactly what we wanted great so now we're
what we wanted great so now we're finally ready uh and it seems like I
finally ready uh and it seems like I have some weird error here let me just
have some weird error here let me just reload my window uh okay and now we're
reload my window uh okay and now we're finally ready to start developing uh the
finally ready to start developing uh the well the view for this document ID page
well the view for this document ID page we're going to start by adding uh some
we're going to start by adding uh some title here and then a cover image and
title here and then a cover image and then the editor itself and then what's
then the editor itself and then what's left is to add a publish button great
left is to add a publish button great great job so
great job so far so now that we have our knv bar
far so now that we have our knv bar semifinished here let's go ahead and
semifinished here let's go ahead and let's head back inside of the document
let's head back inside of the document ID page so we can start rendering some
ID page so we can start rendering some content here so find the document ID
content here so find the document ID page it's located inside the app fold
page it's located inside the app fold main routes documents document ID page.
main routes documents document ID page. TSX right here and first thing I want to
TSX right here and first thing I want to do is I want to mark this page as use
do is I want to mark this page as use client so use client and let's go ahead
client so use client and let's go ahead and let's import the API and the use
and let's import the API and the use Query so use Query from convex react and
Query so use Query from convex react and let's import the API from convex
let's import the API from convex generated API and then let's go ahead
generated API and then let's go ahead and let's write an interface
and let's write an interface document ID page props which is going to
document ID page props which is going to have prams which have the document ID
have prams which have the document ID inside of it which is a type of string
inside of it which is a type of string but for ease of use we're going to write
but for ease of use we're going to write ID which we can import from convex
ID which we can import from convex generated data model and we're going to
generated data model and we're going to write documents so we don't have to
write documents so we don't have to change that every time we use it here
change that every time we use it here and how do we know that we have this
and how do we know that we have this params and document ID where does the
params and document ID where does the this come from well it comes from this
this come from well it comes from this this folder name since this is a dynamic
this folder name since this is a dynamic folder and because you can think of this
folder and because you can think of this as a variable so we created this folder
as a variable so we created this folder which becames a part of the URL and the
which becames a part of the URL and the route and whatever is written inside of
route and whatever is written inside of parentheses becames a variable which we
parentheses becames a variable which we can access through params props so every
can access through params props so every route has this page has this params if
route has this page has this params if it's visible and there are different
it's visible and there are different ways you can access perams so you can do
ways you can access perams so you can do it directly in the page like this if
it directly in the page like this if it's that specific page or you can use
it's that specific page or you can use the use params which we do in document
the use params which we do in document list for example you can see that we use
list for example you can see that we use do params here and you can see that I
do params here and you can see that I have pam. doent ID right here so it's
have pam. doent ID right here so it's the same thing but this way we don't
the same thing but this way we don't have to use that hook it would work if
have to use that hook it would work if we use the hook as well but I just want
we use the hook as well but I just want to show you different ways of doing that
to show you different ways of doing that great so let's go ahead and extract that
great so let's go ahead and extract that uh params here and let's go ahead and
uh params here and let's go ahead and give it the type of document ID page
give it the type of document ID page props um great and now let's go ahead
props um great and now let's go ahead and let's fetch the document using the
and let's fetch the document using the query so con document is equal to use
query so con document is equal to use Query API the documents. getet by ID and
Query API the documents. getet by ID and let's go ahead
let's go ahead oops comma and let's go ahead and give
oops comma and let's go ahead and give you the argument of ID oh sorry document
you the argument of ID oh sorry document ID to be pam. document
ID to be pam. document ID great and now let's go ahead and
ID great and now let's go ahead and let's just write if the document is
let's just write if the document is undefined in that case let's just go
undefined in that case let's just go ahead and write a div loading later
ahead and write a div loading later we're going to change it to a proper
we're going to change it to a proper skeleton and let's go ahead and let's
skeleton and let's go ahead and let's write if document is
write if document is null let's go ahead and let's return a
null let's go ahead and let's return a div saying not found and I forgot uh the
div saying not found and I forgot uh the return here my apologies so wrap this in
return here my apologies so wrap this in a
a return
return great and now let's go ahead and write
great and now let's go ahead and write the main function here so let's go ahead
the main function here so let's go ahead and give this div a class name of
and give this div a class name of padding bottom 40 like that and let's go
padding bottom 40 like that and let's go ahead and create a div here with a class
ahead and create a div here with a class name of MD Max 3 EXL so we are limiting
name of MD Max 3 EXL so we are limiting how wide this document can go and on
how wide this document can go and on large devices let's do MD uh Max W4
large devices let's do MD uh Max W4 Excel and let's write MX outo actually
Excel and let's write MX outo actually this is a mistake sorry so LG is Max W4
this is a mistake sorry so LG is Max W4 Exel great great and now inside of here
Exel great great and now inside of here let's go ahead and write
let's go ahead and write document document ID like that and it
document document ID like that and it seems like we're still not seeing it
seems like we're still not seeing it because it's behind the sidebar but
because it's behind the sidebar but that's okay for now uh we can ignore
that's okay for now uh we can ignore that uh instead let's go ahead and let's
that uh instead let's go ahead and let's replace this document ID with a toolbar
replace this document ID with a toolbar like this a toolbar doesn't exist yet
like this a toolbar doesn't exist yet and all it's going to have is initial
and all it's going to have is initial data to be our document which we load so
data to be our document which we load so now let's go ahead and let let's create
now let's go ahead and let let's create this toolbar
this toolbar component so we're going to reuse this
component so we're going to reuse this toolbar component so we're going to
toolbar component so we're going to create it inside of the components
create it inside of the components folder so create a new file toolbar. TSX
folder so create a new file toolbar. TSX let's go ahead and Mark it as use
let's go ahead and Mark it as use client and let's export cons
client and let's export cons toolbar and return a div saying toolbar
toolbar and return a div saying toolbar and go back to page. CSX and then you
and go back to page. CSX and then you can import toolbar from s/ components
can import toolbar from s/ components toolbar like I did right here
toolbar like I did right here great now let's go ahead uh and let's
great now let's go ahead uh and let's give it some
give it some props so go ahead and write interface
props so go ahead and write interface toolbar props and we're going to have
toolbar props and we're going to have the initial data which is a type of doc
the initial data which is a type of doc from convex generated model specifically
from convex generated model specifically the documents and we're also going to
the documents and we're also going to have another prop which is going to be
have another prop which is going to be optional and used later called preview
optional and used later called preview so it's going to be an optional Boolean
so it's going to be an optional Boolean and let's go ahead now and let's just
and let's go ahead now and let's just assign those so toolbar
props and let's extract the initial data and the preview great and now what I
and the preview great and now what I want to do is I want to go back inside
want to do is I want to go back inside of our page uh.
of our page uh. DSX right here and let's go ahead and
DSX right here and let's go ahead and let's just add a div here it doesn't
let's just add a div here it doesn't really matter let's just give it a
really matter let's just give it a self-closing tag and give it a class
self-closing tag and give it a class name of
name of h35
h35 VH like this so it gives a lot of space
VH like this so it gives a lot of space right here
right here perfect and now let's go ahead inside of
perfect and now let's go ahead inside of this toolbar and let's go ahead and
this toolbar and let's go ahead and style it a bit so I'm going to give this
style it a bit so I'm going to give this toolbar a class name of padding left 54
toolbar a class name of padding left 54 pixels group and relative like that and
pixels group and relative like that and now let's go ahead uh and let's check if
now let's go ahead uh and let's check if we have the icon so if we have the icon
we have the icon so if we have the icon initial data icon and if this is not a
initial data icon and if this is not a preview meaning that we are looking to
preview meaning that we are looking to edit this right we are looking uh at
edit this right we are looking uh at this as an owner not as a guest who is
this as an owner not as a guest who is looking at our published document if
looking at our published document if that is the case let's go ahead and
that is the case let's go ahead and render a div like this with a class name
render a div like this with a class name of flex items D Center Gap X2 like that
of flex items D Center Gap X2 like that group
group slash icon and padding top of six like
slash icon and padding top of six like that
that perfect now let's go ahead and let's
perfect now let's go ahead and let's install a
install a package uh called let me just expand my
package uh called let me just expand my screen so let's install a package called
screen so let's install a package called Emoji picker react go ahead and install
Emoji picker react go ahead and install that so let's wait a second for this to
that so let's wait a second for this to finish great and let's go ahead and
finish great and let's go ahead and let's create a new component called icon
let's create a new component called icon picker so let's go inside of our
picker so let's go inside of our components folder and create a new file
components folder and create a new file icon dasp
icon dasp pier. DSX and let's just save our work
pier. DSX and let's just save our work in the toolbar here and let's go ahead
in the toolbar here and let's go ahead and Mark this as use client let's go
and Mark this as use client let's go ahead and import Emoji picker and let's
ahead and import Emoji picker and let's go ahead and import theme from emoji
go ahead and import theme from emoji picker
picker react let's go ahead and import used
react let's go ahead and import used theme from next themes which we already
theme from next themes which we already have installed and let's import
have installed and let's import everything we need from components UI
everything we need from components UI popover and that's going to be the
popover and that's going to be the popover itself the popover content and
popover itself the popover content and the popover
the popover trigger great let's create an interface
trigger great let's create an interface icon picker props which is going to have
icon picker props which is going to have an onchange which takes in the icon
an onchange which takes in the icon which is a type of string because it's
which is a type of string because it's just going to be an emoji children are
just going to be an emoji children are going to be react. react node and as
going to be react. react node and as child is going to be an optional
child is going to be an optional Boolean great now let's go ahead and
Boolean great now let's go ahead and assign that so expert con icon
assign that so expert con icon picker and let's assign the icon picker
picker and let's assign the icon picker props let's extract all of those props
props let's extract all of those props so onchange children and as
so onchange children and as child and for what I want to do now is
child and for what I want to do now is get the resolve
theme from used theme and let's go ahead and write const
theme and let's go ahead and write const current
theme the check for the resolved theme or give it default value of light as key
or give it default value of light as key off type off and what we have to do now
off type off and what we have to do now is write theme map and let's go ahead
is write theme map and let's go ahead and create theme map so cons theme map
and create theme map so cons theme map is an object which has an option for
is an object which has an option for dark which is going to use theme. dark
dark which is going to use theme. dark and it has an option for light which is
and it has an option for light which is them. light so I'm doing this because
them. light so I'm doing this because this Emoji picker from emoji picker
this Emoji picker from emoji picker react has its own theme prop so we have
react has its own theme prop so we have to use the theme that we are using using
to use the theme that we are using using next themes and then map it correctly to
next themes and then map it correctly to what is compatible with their theme and
what is compatible with their theme and then let's just write cons theme to be
then let's just write cons theme to be theme map current
theme all right and now we can finally do return get the
do return get the popover write the popover
popover write the popover trigger give it an option as child to be
trigger give it an option as child to be as child
as child and inside render the children so that's
and inside render the children so that's going to be our trigger and then write
going to be our trigger and then write popover
content let's go ahead and end this like that let's give this popover content a
that let's give this popover content a class name of padding zero W full border
class name of padding zero W full border none and Shadow
none and Shadow none and inside we're going to render
none and inside we're going to render the Emoji picker which is a self closing
the Emoji picker which is a self closing tag let's go ahead and give it a height
tag let's go ahead and give it a height of
of 350 let's give it a theme of theme and
350 let's give it a theme of theme and let's give it an on emoji click to get
let's give it an on emoji click to get the data and use the on change to send
the data and use the on change to send data. emoji which is a string like that
data. emoji which is a string like that perfect so now we can head back inside
perfect so now we can head back inside of the toolbar right here and now we can
of the toolbar right here and now we can add that icon picker
add that icon picker here so import the icon picker from do/
here so import the icon picker from do/ Pier because both of those are in the
Pier because both of those are in the global components folder so we working
global components folder so we working in toolbar and we just created the icon
in toolbar and we just created the icon picker here and go ahead and pass inside
picker here and go ahead and pass inside of the icon picker uh a paragraph which
of the icon picker uh a paragraph which is going to be the initial data.
is going to be the initial data. icon great and now let's go ahead and
icon great and now let's go ahead and give this a class name of text
give this a class name of text 6xl cover opacity -75 and
6xl cover opacity -75 and transition and give this icon picker an
transition and give this icon picker an unchange to just be an empty Arrow
unchange to just be an empty Arrow function for now like that and right now
function for now like that and right now you should not be able to see anything
you should not be able to see anything here but let me show you a little trick
here but let me show you a little trick to how you can uh preview something here
to how you can uh preview something here so not big deal if you don't do this you
so not big deal if you don't do this you can just continue coding as normal but I
can just continue coding as normal but I want to demonstrate that code picker to
want to demonstrate that code picker to you so right now that emoji picker is
you so right now that emoji picker is only going to be shown if we already
only going to be shown if we already have an icon so let's go ahead and see
have an icon so let's go ahead and see that we can very easily do that by going
that we can very easily do that by going inside of our database
inside of our database here go ahead let me just clear
here go ahead let me just clear everything so I'm going to go uh and
everything so I'm going to go uh and delete
delete this uh and let me just delete this one
this uh and let me just delete this one as well like that so let me go to this
as well like that so let me go to this page and let me clear everything I have
page and let me clear everything I have inside let's create a new one and now
inside let's create a new one and now all I have to do is give this document
all I have to do is give this document uh if I can do that from here I'm
uh if I can do that from here I'm actually not uh sure you know what
actually not uh sure you know what ignore that let's just continue
ignore that let's just continue developing I think I just confused you
developing I think I just confused you even more okay I wanted to show you
even more okay I wanted to show you already but we're just going to have to
already but we're just going to have to be patient I'm sorry for that uh all
be patient I'm sorry for that uh all right so now let's go ahead outside of
right so now let's go ahead outside of this uh conditional right here actually
this uh conditional right here actually uh go outside of this icon picker here
uh go outside of this icon picker here and add a button
and add a button component so import uh this from UI
component so import uh this from UI button but I'm going to change it to
button but I'm going to change it to components and go ahead and add a button
components and go ahead and add a button and render the X icon from Lucid react
and render the X icon from Lucid react so make sure you add this import here so
so make sure you add this import here so this is going to be our button to remove
this is going to be our button to remove the icon if we have it and add a class
the icon if we have it and add a class name of H4 n
name of H4 n W-4 and let's go ahead and give this an
W-4 and let's go ahead and give this an on click for now to be an empty Arrow
on click for now to be an empty Arrow function and let's give it a class name
function and let's give it a class name of rounded Das full
of rounded Das full opacity -0
opacity -0 group whoops group- hover SL icon
group whoops group- hover SL icon opacity 100 transition and text- needed
opacity 100 transition and text- needed uh Das foreground and we also need to
uh Das foreground and we also need to give it a text of extra small besides
give it a text of extra small besides class name give it a variant of outline
class name give it a variant of outline and a size of Icon great so I'm sorry
and a size of Icon great so I'm sorry you can't already see this perhaps I
you can't already see this perhaps I should have approached this in a
should have approached this in a different way but it's quite hard to do
different way but it's quite hard to do it already so let's just continue the
it already so let's just continue the way we are I know you can't see this but
way we are I know you can't see this but when we add an icon you're going to be
when we add an icon you're going to be able to see this so this is going to
able to see this so this is going to control uh the icon we can change or we
control uh the icon we can change or we can remove it Al together uh great so
can remove it Al together uh great so now let's go ahead uh below that and
now let's go ahead uh below that and let's write otherwise if we have the
let's write otherwise if we have the initial data that icon but if this is a
initial data that icon but if this is a preview meaning that a guest is looking
preview meaning that a guest is looking at this in that case it's going to be
at this in that case it's going to be much simpler we're just going to render
much simpler we're just going to render that icon so add a paragraph and render
that icon so add a paragraph and render the initial data do icon inside and
the initial data do icon inside and let's give this paragraph a class
let's give this paragraph a class name of text- 6 Excel hover well it
name of text- 6 Excel hover well it doesn't need any hover it just needs a
doesn't need any hover it just needs a padding top of six so this is going to
padding top of six so this is going to be if a guest is looking at it so this
be if a guest is looking at it so this is if we are looking at it that means
is if we are looking at it that means that we can change the icon and we can
that we can change the icon and we can remove it right but a guest can just
remove it right but a guest can just look at it uh great so now let's go
look at it uh great so now let's go outside of this and let's create a div
outside of this and let's create a div here with a class name of opacity d0
here with a class name of opacity d0 group
group - hover opacity
- hover opacity D100 Flex items D Center Gap dx-1 and
D100 Flex items D Center Gap dx-1 and padding y off four and inside if we
padding y off four and inside if we don't have the
don't have the icon and if this is not a
icon and if this is not a preview in that case go ahead and render
preview in that case go ahead and render the icon picker again and this time
the icon picker again and this time we're going to add a button component
we're going to add a button component with a smile icon inside so import smile
with a smile icon inside so import smile from Lucid react the same way we did
from Lucid react the same way we did with the X icon let's go back down here
with the X icon let's go back down here all right and let's go ahead and write
all right and let's go ahead and write add
add icon and give this smile a class name of
icon and give this smile a class name of uh it's going to be H4 W-4 and margin
uh it's going to be H4 W-4 and margin right to give this button a class name
right to give this button a class name of text- muted D
of text- muted D foreground and text extra small
foreground and text extra small give it a variant of outline and a size
give it a variant of outline and a size of small and give this icon picker as
of small and give this icon picker as child option and on change it's just
child option and on change it's just going to be an empty Arrow function
going to be an empty Arrow function perfect so now if you find it so just go
perfect so now if you find it so just go ahead and hover over your screen or you
ahead and hover over your screen or you can remove the opacity like this so just
can remove the opacity like this so just change the opacity to 100 there we go
change the opacity to 100 there we go and now you can click on this and there
and now you can click on this and there we go we have our emojis here so it's
we go we have our emojis here so it's going to be right here the reason
going to be right here the reason there's so much space here is because I
there's so much space here is because I just wanted to move it away from the knv
just wanted to move it away from the knv bar later on this is going to have a
bar later on this is going to have a cover image so that's why we're not
cover image so that's why we're not going to need all that space But for now
going to need all that space But for now you can look at this uh icon how it
you can look at this uh icon how it looks here and if you change the
looks here and if you change the appearance to
appearance to dark this is going to be dark as well so
dark this is going to be dark as well so that's what I wanted to do great so now
that's what I wanted to do great so now we have this add icon element here so
we have this add icon element here so let's quickly change this default
let's quickly change this default opacity if you change it back to zero
opacity if you change it back to zero perfect so now that we have that uh
perfect so now that we have that uh let's go ahead uh outside of this so
let's go ahead uh outside of this so still inside of this div but outside of
still inside of this div but outside of this conditional render here and go
this conditional render here and go ahead and write if we don't have initial
ahead and write if we don't have initial data cover image and if this is not a
data cover image and if this is not a preview then go ahead and render a
preview then go ahead and render a button again which is just going to
button again which is just going to render the image icon from Lucid react
render the image icon from Lucid react so make sure you import the image icon
so make sure you import the image icon give this a class name of h-4 W-4 and
give this a class name of h-4 W-4 and margin right of two and give this button
margin right of two and give this button a class name of text- muted D foreground
a class name of text- muted D foreground text- extra small give it a variant of
text- extra small give it a variant of outline and size of small and for now
outline and size of small and for now give it an on click just an empty Arrow
give it an on click just an empty Arrow function like that and if you try again
function like that and if you try again and hover again uh we now have two
and hover again uh we now have two buttons here but we forgot to add a
buttons here but we forgot to add a little text here
little text here below this image icon to be add
below this image icon to be add hover perfect so now you can see when
hover perfect so now you can see when you just try and hover somewhere and
you just try and hover somewhere and there we go you going to have add an
there we go you going to have add an icon and add a cover and if you're
icon and add a cover and if you're wondering why are they only showing when
wondering why are they only showing when I hover in something well that's because
I hover in something well that's because we don't have the title rendered here
we don't have the title rendered here but we're going to have that soon and
but we're going to have that soon and it's going to make a bit more sense all
it's going to make a bit more sense all right so now that we have that let's go
right so now that we have that let's go ahead and let's add some states here
ahead and let's add some states here let's go ahead and add some functions
let's go ahead and add some functions here so first thing I'm going to add is
here so first thing I'm going to add is const input ref to be use ref from react
const input ref to be use ref from react and give it a type of element
and give it a type of element ref which has a type of text area with a
ref which has a type of text area with a default value of null then let's go
default value of null then let's go ahead and let's add uh the state is
ahead and let's add uh the state is editing and set is
editing and set is editing to be use State and false and
editing to be use State and false and make sure you import use State from
make sure you import use State from react so I have uh element ref use ref
react so I have uh element ref use ref and use state from react and let me just
and use state from react and let me just move that to the
move that to the top all right besides that we're also
top all right besides that we're also going to have the value and not import
going to have the value and not import sorry constant value and set value from
sorry constant value and set value from use State and default is going to be
use State and default is going to be initial data.
initial data. title then let's go ahead and let's
title then let's go ahead and let's write const update to be use mutation
write const update to be use mutation from convex react so make sure you add
from convex react so make sure you add use mutation from convex
use mutation from convex react and and we're going to call the
react and and we're going to call the API so we have to import that as well
API so we have to import that as well which I just did right here so import
which I just did right here so import API from convex generated API I'll just
API from convex generated API I'll just move it with the other stuff here and
move it with the other stuff here and we're going to use api. documents.
we're going to use api. documents. update so we already created that
update so we already created that function uh great and now let's go ahead
function uh great and now let's go ahead and let's write const enable input to be
and let's write const enable input to be an M function if it's preview just break
an M function if it's preview just break the function right because a guest is
the function right because a guest is looking at this so a guest should not be
looking at this so a guest should not be able to even click on this but just in
able to even click on this but just in case they do uh we're just going to
case they do uh we're just going to break the function let's do set is
break the function let's do set is editing to be true and let's do set
editing to be true and let's do set timeout to set the value of initial
timeout to set the value of initial data. title and to do input ref. current
data. title and to do input ref. current Focus like that and zero as the timeout
Focus like that and zero as the timeout value uh great now let's go ahead and
value uh great now let's go ahead and let's add add con disable
let's add add con disable input to just very simply be set is
input to just very simply be set is editing to
editing to false now let's go ahead and let's add
false now let's go ahead and let's add const on input to take the value which
const on input to take the value which is a string and do set value value and
is a string and do set value value and update ID initial dataor
update ID initial dataor ID and let's give it a title of value or
ID and let's give it a title of value or un titled if we try and delete the
un titled if we try and delete the entire title so very similar to what we
entire title so very similar to what we did in with our uh navbar uh great and
did in with our uh navbar uh great and let's add one more thing const on key
let's add one more thing const on key down to take the event which is a type
down to take the event which is a type of react. keyboard event and it's going
of react. keyboard event and it's going to come from html text area
to come from html text area element all right and inside of it what
element all right and inside of it what we're going to do is check if event. key
is enter and if that's the case we're going to prevent
default and we're going to disable the input um great so now we can go back uh
input um great so now we can go back uh inside of our code here go all the way
inside of our code here go all the way down where this ends and go outside of
down where this ends and go outside of this div so right here we should only
this div so right here we should only have one closing div at the bottom and
have one closing div at the bottom and show if is editing and if it is not
show if is editing and if it is not preview in that case go ahead and render
preview in that case go ahead and render uh a component which we actually have to
uh a component which we actually have to install which is called uh text area
install which is called uh text area Auto size so let's go inside of our
Auto size so let's go inside of our terminal and let's install mpm install
terminal and let's install mpm install react text area Auto size like that so
react text area Auto size like that so that's going to help us because uh well
that's going to help us because uh well we could code our own but this is just a
we could code our own but this is just a faster way of doing it so let's go ahead
faster way of doing it so let's go ahead and import that here so import text area
and import that here so import text area Auto uh size from react text area Auto
Auto uh size from react text area Auto size perfect and let's go ahead and use
size perfect and let's go ahead and use it
it here so if we are editing and if it's
here so if we are editing and if it's not a preview we're going to render that
not a preview we're going to render that text area out to size and give it a ref
text area out to size and give it a ref of input ref go ahead and give it an on
of input ref go ahead and give it an on blur to be disabled
blur to be disabled input go ahead and use the on key down
input go ahead and use the on key down to be on key down go ahead and give it a
to be on key down go ahead and give it a value of value on change is going to
value of value on change is going to take the event and call the on input
take the event and call the on input with event. target. value and let's give
with event. target. value and let's give it a class name of text- 5 Excel BG -
it a class name of text- 5 Excel BG - transparent font uh trans arent font Das
transparent font uh trans arent font Das bold
bold break
break dwords outline Das non text Dash open
dwords outline Das non text Dash open pointy square brackets 3 f3f
pointy square brackets 3 f3f 3F and on dark
3F and on dark mode text is going to be
mode text is going to be cfcfcf and let's add resize Das none so
cfcfcf and let's add resize Das none so we don't have that icon uh and now let's
we don't have that icon uh and now let's go ahead and write the else here this is
go ahead and write the else here this is going to be the last element here uh and
going to be the last element here uh and let's go ahead and write a
let's go ahead and write a div which is going to render the initial
div which is going to render the initial data. title and let's go ahead and give
data. title and let's go ahead and give this an onclick of enable input and
this an onclick of enable input and let's give it a class
let's give it a class name of padding
name of padding bottom padding
bottom padding bottom to be 11.5 pixels text five
bottom to be 11.5 pixels text five pixels five Excel sorry font dbol break
pixels five Excel sorry font dbol break words outline dnone and we can copy this
words outline dnone and we can copy this text and dark text from the text area
text and dark text from the text area out of size and just whoa I copied too
out of size and just whoa I copied too much so just this and paste it here like
much so just this and paste it here like that and that should be it let's go
that and that should be it let's go ahead and take a look now so there we go
ahead and take a look now so there we go we now you can see now it makes sense
we now you can see now it makes sense when we hover on our title that's when
when we hover on our title that's when we have the options to add an icon or to
we have the options to add an icon or to add a cover and let's try and click on
add a cover and let's try and click on this and then you should be able to
this and then you should be able to modify this end because we use the
modify this end because we use the update function is here in real time so
update function is here in real time so now if you change it from the nav bar
now if you change it from the nav bar it's right here or from here it's
it's right here or from here it's visible in all three places amazing
visible in all three places amazing amazing job uh so now I want to go ahead
amazing job uh so now I want to go ahead and enable us to add an icon because
and enable us to add an icon because currently when we do that nothing
currently when we do that nothing happens in order to do that we have to
happens in order to do that we have to create an AP a function for
create an AP a function for it so we don't actually need an API
it so we don't actually need an API route to add an icon but we do need it
route to add an icon but we do need it to delete an icon so let's go inside of
to delete an icon so let's go inside of convex inside of documents right here
convex inside of documents right here let's go all the way to the bottom and
let's go all the way to the bottom and let's add export cons remove icon to be
let's add export cons remove icon to be a type of
imitation let's get the arguments to be an ID of we. ID
an ID of we. ID documents let's get the Handler to be an
documents let's get the Handler to be an asynchronous function which has the
asynchronous function which has the context and the
arguments and let's do the thing that we always do which is get the identity and
always do which is get the identity and the user ID so I just copyed that from
the user ID so I just copyed that from the function Above So const identity we
the function Above So const identity we check if we don't have the identity and
check if we don't have the identity and extract the user ID now let's get the
extract the user ID now let's get the existing document using await context.
existing document using await context. database. getet
database. getet uh sorry context. datab database
uh sorry context. datab database .g rs.
.g rs. ID like that if there is no existing
ID like that if there is no existing document in that case you can just throw
document in that case you can just throw new
new error not
error not found and let's also do if existing
found and let's also do if existing document. user ID is not identical to
document. user ID is not identical to the user ID which we just extracted in
the user ID which we just extracted in that case throw new error
that case throw new error unauthorized
unauthorized uh and now let's go ahead and write cons
uh and now let's go ahead and write cons document to be await context. database.
document to be await context. database. patch arguments. ID and let's write icon
patch arguments. ID and let's write icon undefined so we remove that row and
undefined so we remove that row and write
write return document
here perfect so now we can go back inside of the toolbar right here and
inside of the toolbar right here and let's write two functions here so we're
let's write two functions here so we're going to write const on icon select to
going to write const on icon select to get the icon which is a string and call
get the icon which is a string and call the update function using ID to be
the update function using ID to be initial
initial dataor ID and an icon like this so very
dataor ID and an icon like this so very simple and now let's go ahead and do
simple and now let's go ahead and do const on remove icon to be remove
const on remove icon to be remove icon
icon oops remove icon and we don't have it so
oops remove icon and we don't have it so let's go ahead and create it here so
let's go ahead and create it here so const remove icon is use mutation api.
const remove icon is use mutation api. documents. remove
documents. remove icon all right so we called the remove
icon all right so we called the remove icon and we're just going to go ahead
icon and we're just going to go ahead and pass in the ID to be initial data ID
and pass in the ID to be initial data ID as simple as that and now we can assign
as simple as that and now we can assign those two so find the icon picker here
those two so find the icon picker here and go ahead and give it an option of on
and go ahead and give it an option of on icon
icon select for this button which holds the X
select for this button which holds the X class the X icon sorry uh give it an on
class the X icon sorry uh give it an on icon remove or on remove icon sorry and
icon remove or on remove icon sorry and we need the on icon select inside of
we need the on icon select inside of this icon picker below as
this icon picker below as well like this and let's try it out now
well like this and let's try it out now so if I click add an icon and select an
so if I click add an icon and select an icon there we go it's in all three
icon there we go it's in all three places it's right here it's in the
places it's right here it's in the sidebar and it's right here and I can
sidebar and it's right here and I can just as easily remove it or bring it
just as easily remove it or bring it back and it's also in my database
back and it's also in my database perfect so we finished uh this heading
perfect so we finished uh this heading here and now we're going to go ahead and
here and now we're going to go ahead and create our cover and upload our image
create our cover and upload our image great great
great great job all right so now that we have this
job all right so now that we have this toolbar and the icon working let's go
toolbar and the icon working let's go ahead and let's enable this add cover
ahead and let's enable this add cover button right here so before we go on to
button right here so before we go on to implementing the actual Edge store which
implementing the actual Edge store which we're going to use the upload the files
we're going to use the upload the files first let's go ahead and create a model
first let's go ahead and create a model which is going to open when we click on
which is going to open when we click on ADD cover for that let's revisit our
ADD cover for that let's revisit our Hooks and let's create a new file use-
Hooks and let's create a new file use- cover- image. DSX and let's go ahead and
cover- image. DSX and let's go ahead and let's import create from tand let's
let's import create from tand let's write the type cover Image store let's
write the type cover Image store let's give it is open to be a Boolean onop to
give it is open to be a Boolean onop to be a void function on close to be the
be a void function on close to be the very same void function and then let's
very same void function and then let's do export con use cover image to be
do export con use cover image to be create and let's give this create a type
create and let's give this create a type of cover Image store and let's extract
of cover Image store and let's extract set so just do double parenthesis inside
set so just do double parenthesis inside set and open an immediate object like
set and open an immediate object like this wrapped in parenthesis and now
this wrapped in parenthesis and now let's assign is open to be false by
let's assign is open to be false by default on open to call a set function
default on open to call a set function which sets the is open to true and on
close we'll call the set as well and set is open to be
is open to be false great and now let's go ahead and
false great and now let's go ahead and let's create our cover image model so go
let's create our cover image model so go inside of components models and create
inside of components models and create cover image model. TSX let's mark it as
cover image model. TSX let's mark it as use client and let's import everything
use client and let's import everything we need from s/ components UI dialogue
we need from s/ components UI dialogue here so we're going to need the dialogue
here so we're going to need the dialogue itself
itself whoops dialogue we're going to need the
whoops dialogue we're going to need the dialogue content and the dialogue
dialogue content and the dialogue header let's also import the use cover
header let's also import the use cover image from the hook we just created and
image from the hook we just created and now let's write export con cover image
now let's write export con cover image model to very simply use the cover image
model to very simply use the cover image from use cover
from use cover image and let's go ahead and let's
image and let's go ahead and let's return our dialogue so
return our dialogue so dialogue and let's give it a prop open
dialogue and let's give it a prop open to be cover image on open sorry is open
to be cover image on open sorry is open and let's give it an onop change to be
and let's give it an onop change to be cover image on
cover image on close inside of the dialogue add the
close inside of the dialogue add the dialogue
dialogue content add the dialog header
content add the dialog header uh let's see did I import the dialog
uh let's see did I import the dialog header I did okay add the dialog header
header I did okay add the dialog header and add an H2 class sorry H2 element
and add an H2 class sorry H2 element which is going to say cover image and
which is going to say cover image and give this H2 a class name of text-
give this H2 a class name of text- Center text- large and font semi bolt
Center text- large and font semi bolt and outside of the dialog header let's
and outside of the dialog header let's just do a div which says to do upload
just do a div which says to do upload image great and now let's go ahead and
image great and now let's go ahead and let's add the this entire dialogue
let's add the this entire dialogue inside of our models provider so let's
inside of our models provider so let's go inside of providers model provider
go inside of providers model provider here and let's go ahead and import cover
here and let's go ahead and import cover image model and I'm just going to
image model and I'm just going to replace this to add/ components cover
replace this to add/ components cover image model so models cover image model
image model so models cover image model which we just created and let's add it
which we just created and let's add it below right
below right here like that and then we can go back
here like that and then we can go back inside of our toolbar component so
inside of our toolbar component so that's inside of components if I'm not
that's inside of components if I'm not mistaken yes it's right here and let's
mistaken yes it's right here and let's go ahead and let's import it here so I'm
go ahead and let's import it here so I'm just going to do it here const cover
just going to do it here const cover image to be use cover image from hooks
image to be use cover image from hooks use cover image so that hook we just
use cover image so that hook we just created I imported it right here all
created I imported it right here all right and now that we have the cover
right and now that we have the cover image let's go ahead and find the button
image let's go ahead and find the button which adds our cover image so I believe
which adds our cover image so I believe it should be right here this button
it should be right here this button which currently has an empty on click
which currently has an empty on click which says add cover and has the image
which says add cover and has the image icon so let's go ahead and give it a on
icon so let's go ahead and give it a on click cover image on open and now if you
click cover image on open and now if you go ahead and click on ADD cover there we
go ahead and click on ADD cover there we go you can see how we have a model and
go you can see how we have a model and we have a to-do upload image great so
we have a to-do upload image great so this is a great start now we have our
this is a great start now we have our model which is going to open to upload a
model which is going to open to upload a new image uh what we have to do now is
new image uh what we have to do now is set up Edge
set up Edge store so in order to set up Edge store
store so in order to set up Edge store we have to visit EDG
we have to visit EDG st.dev or you can use my link in the
st.dev or you can use my link in the description so let's go ahead and click
description so let's go ahead and click Start for free right here and you can
Start for free right here and you can create an account using GitHub so let's
create an account using GitHub so let's go ahead and just sign
go ahead and just sign in and as you can see right here I
in and as you can see right here I already have a project which I used for
already have a project which I used for the initial development of the notion
the initial development of the notion tutorial but for you go ahead and find
tutorial but for you go ahead and find the button which says new project and
the button which says new project and let's go ahead and name this notion Das
let's go ahead and name this notion Das tututorial and let's click create let's
tututorial and let's click create let's wait a second for this to install and
wait a second for this to install and there we go now you should be seeing
there we go now you should be seeing these two keys right here uh if this
these two keys right here uh if this changes in the future don't worry I'm
changes in the future don't worry I'm going to also show you some alternative
going to also show you some alternative ways where you can find your keys uh
ways where you can find your keys uh inside of your project but if you are
inside of your project but if you are seeing this screen you can just go ahead
seeing this screen you can just go ahead and copy this keys and go inside of the
and copy this keys and go inside of the environment file which we have so let me
environment file which we have so let me just close everything here find your
just close everything here find your environment. local right here and just
environment. local right here and just go ahead and paste the Keys here so you
go ahead and paste the Keys here so you need to have Edge store access key and
need to have Edge store access key and Edge store secret key um great let me
Edge store secret key um great let me just quickly show you that you can
just quickly show you that you can always go inside of your projects you
always go inside of your projects you can select a specific project and from
can select a specific project and from here you can always click on this little
here you can always click on this little info icon and then click on Project keys
info icon and then click on Project keys and you can visit them here as well so
and you can visit them here as well so later when we actually have some files
later when we actually have some files inside this screen is going to disappear
inside this screen is going to disappear but you can always see it by clicking on
but you can always see it by clicking on this little info here and then clicking
this little info here and then clicking on Pro project Keys um great so now
on Pro project Keys um great so now let's once we've added this inside of
let's once we've added this inside of our app let's click continue Indo right
our app let's click continue Indo right here and let's install everything we
here and let's install everything we need so we need to install edge store
need so we need to install edge store server Edge store react and Zod and
server Edge store react and Zod and let's go ahead and click copy here and
let's go ahead and click copy here and let's go inside of our terminal and I'm
let's go inside of our terminal and I'm going to go ahead and install all of
going to go ahead and install all of that so I'm installing Edge store server
that so I'm installing Edge store server EDG store react and Zod and let me just
EDG store react and Zod and let me just zoom out one more time just so you can
zoom out one more time just so you can see all this in one line so EDG store
see all this in one line so EDG store SLS server Edge store SL react and Zod
SLS server Edge store SL react and Zod and just go ahead and press
and just go ahead and press enter great uh once this is installed
enter great uh once this is installed let's go ahead and see what the next
let's go ahead and see what the next steps are so we need to add the
steps are so we need to add the environment variables but we already did
environment variables but we already did that and now let's set up our back end
that and now let's set up our back end as you can see it has both the
as you can see it has both the instructions for the app folder and for
instructions for the app folder and for the pages folder we are working with the
the pages folder we are working with the app folder so this pre-selected option
app folder so this pre-selected option works for us and you can just go ahead
works for us and you can just go ahead and click copy from here if for any
and click copy from here if for any reason you cannot find this you can
reason you cannot find this you can always visit my source code and go ahead
always visit my source code and go ahead and find the file that I'm about to
and find the file that I'm about to create now and we can take a look at
create now and we can take a look at where we need to create it so we need to
where we need to create it so we need to create it inside the app folder API Edge
create it inside the app folder API Edge store create the dynamic Edge store
store create the dynamic Edge store Route and then route. DS inside so let's
Route and then route. DS inside so let's go inside of the app folder create a new
go inside of the app folder create a new folder called API and inside create
folder called API and inside create another folder called Edge store like
another folder called Edge store like this and then inside create another
this and then inside create another folder in square brackets and spread
folder in square brackets and spread Edge store inside like this and create
Edge store inside like this and create route. DS and just again copy everything
route. DS and just again copy everything from this file or copy it from my GitHub
from this file or copy it from my GitHub and you can just go ahead and save this
and you can just go ahead and save this file um great now that we have
file um great now that we have this let's go ahead and let's see what
this let's go ahead and let's see what the next step is so the next step is to
the next step is so the next step is to create a lib for the edge store which is
create a lib for the edge store which is going to be our hook which we are going
going to be our hook which we are going to use in all our client components to
to use in all our client components to easily upload files from the front end
easily upload files from the front end so copy this file make sure you're
so copy this file make sure you're selecting the app folder make sure and
selecting the app folder make sure and this is the front end section right and
this is the front end section right and we need to create a lib called EDG
we need to create a lib called EDG store. TS so let's go ahead inside of
store. TS so let's go ahead inside of our lib folder we already have utils
our lib folder we already have utils inside and now we're going to create a
inside and now we're going to create a new file EDG store. DX
new file EDG store. DX and paste everything inside great and
and paste everything inside great and now that we have that we have to wrap
now that we have that we have to wrap our entire app inside of the edge store
our entire app inside of the edge store provider so let's go ahead inside of our
provider so let's go ahead inside of our app folder so our root layout app folder
app folder so our root layout app folder layout right here and let's go ahead and
layout right here and let's go ahead and let's import The Edge uh store Provider
let's import The Edge uh store Provider from atli Edge store so that file we
from atli Edge store so that file we just created and I'm going to go ahead
just created and I'm going to go ahead and wrap it inside of the convex client
and wrap it inside of the convex client provider like this and just here where
provider like this and just here where it ends just like that let's look at the
it ends just like that let's look at the documentation if that's it and looks
documentation if that's it and looks like that is it we are now ready to
like that is it we are now ready to actually upload a file as you can see we
actually upload a file as you can see we can do it very easily we just need to
can do it very easily we just need to upload Edge store from use Edge store
upload Edge store from use Edge store and we need an input which is actually
and we need an input which is actually going to allow the user to select the
going to allow the user to select the file and then all we do is await Edge
file and then all we do is await Edge store public files upload and we pass in
store public files upload and we pass in the file if we want to do some UI with
the file if we want to do some UI with the percentage of the progress that's
the percentage of the progress that's been uploaded we can use this hook for
been uploaded we can use this hook for it right here and if you look at the
it right here and if you look at the documentation even further you can see
documentation even further you can see that this Edge store has a a
that this Edge store has a a functionality to replace a URL this is
functionality to replace a URL this is going to come useful with our cover
going to come useful with our cover image because we're going to have an
image because we're going to have an option to replace an image so it's very
option to replace an image so it's very cool that we have this we can just send
cool that we have this we can just send the old URL that's going to be deleted
the old URL that's going to be deleted and then we have the new one in that
and then we have the new one in that place and you can also delete delete
place and you can also delete delete files very easily but make sure that you
files very easily but make sure that you also add the before delete life cycle
also add the before delete life cycle hook on the bucket we're going to do all
hook on the bucket we're going to do all that let me just show you a bit more
that let me just show you a bit more what you can do so you can also do
what you can do so you can also do temporary files if for any reason your
temporary files if for any reason your UI is needed for a temporary file as you
UI is needed for a temporary file as you can see they will be automatically
can see they will be automatically deleted after 24 hours if they are not
deleted after 24 hours if they are not confirmed and you have a nice little uh
confirmed and you have a nice little uh URL to confirm right here which you get
URL to confirm right here which you get and then you can use that to confirm an
and then you can use that to confirm an upload so just something if you're
upload so just something if you're playing and using this in your uh own
playing and using this in your uh own application great so now that we have
application great so now that we have that if you want to you can already try
that if you want to you can already try with this very simple example with an
with this very simple example with an input with a set file here and then an
input with a set file here and then an upload or you can go ahead and set up
upload or you can go ahead and set up this uh image component right here as
this uh image component right here as you can see this is a drag and drop uh
you can see this is a drag and drop uh drops down here so I'm going to be using
drops down here so I'm going to be using this single image component so let's go
this single image component so let's go ahead and skip the usage for now of
ahead and skip the usage for now of course you can take a look at it if
course you can take a look at it if you're wondering how this is going to
you're wondering how this is going to look in the end but what I want to go is
look in the end but what I want to go is I want to go to the installation part
I want to go to the installation part right here and as you can see we have to
right here and as you can see we have to install Tailwind merge react drop zone
install Tailwind merge react drop zone and Lucid react if I believe we already
and Lucid react if I believe we already have lucid react installed as well as
have lucid react installed as well as Tailwind merge but it doesn't matter if
Tailwind merge but it doesn't matter if you want you can just do npm install
you want you can just do npm install react drop zone or you can just copy
react drop zone or you can just copy this entire line but you will get some
this entire line but you will get some new versions with this if any new
new versions with this if any new versions came out by the time you
versions came out by the time you started this tutorial but I think it's
started this tutorial but I think it's safe enough to do that so let's go ahead
safe enough to do that so let's go ahead and let's do this so mpm install
and let's do this so mpm install Tailwind Das merge react d drop zone and
Tailwind Das merge react d drop zone and Lucid react go ahead and install all of
Lucid react go ahead and install all of these dependencies great let me just
these dependencies great let me just zoom back in and now let's go ahead and
zoom back in and now let's go ahead and copy uh the following component inside
copy uh the following component inside of our components folder so it's right
of our components folder so it's right here this very big uh component here if
here this very big uh component here if for any reason uh you cannot find this
for any reason uh you cannot find this or maybe the documentation changed in
or maybe the documentation changed in the future you can always just visit my
the future you can always just visit my GitHub and find this component which I
GitHub and find this component which I copied from here you didn't have to
copied from here you didn't have to worry about it and there are also much
worry about it and there are also much simpler ways of doing this if you don't
simpler ways of doing this if you don't want the drops Zone you don't have to
want the drops Zone you don't have to use one but let's go ahead and click
use one but let's go ahead and click copy right here and let's go inside of
copy right here and let's go inside of our components folder and create a new
our components folder and create a new file single- image- drop zone. DSX let
file single- image- drop zone. DSX let me try and expand my sidebar so single-
me try and expand my sidebar so single- image- drop zone. DSX and I'm going to
image- drop zone. DSX and I'm going to paste all of this inside great as you
paste all of this inside great as you can see we have no errors meaning that
can see we have no errors meaning that we have all of the packages installed
we have all of the packages installed perfect so first thing that I want to do
perfect so first thing that I want to do is I want to go inside of this input
is I want to go inside of this input props and I want to make the height and
props and I want to make the height and width optional like this so you can just
width optional like this so you can just put a little question mark here because
put a little question mark here because we're not going to have them have fixed
we're not going to have them have fixed height and width because ours is in a
height and width because ours is in a model and then what I'm going to do is
model and then what I'm going to do is I'm going to go ahead and import
spinner from do/ spinner like this because they are in the same component
because they are in the same component sorry in the same folder the global
sorry in the same folder the global components folder we have the spinner
components folder we have the spinner right here and the single image right
right here and the single image right here so we can just do dot SL spinner
here so we can just do dot SL spinner perfect uh and now what I want to do uh
perfect uh and now what I want to do uh is I want to go ahead uh and change the
is I want to go ahead uh and change the way uh it shows the loading state so
way uh it shows the loading state so let's go ahead all the way down to where
let's go ahead all the way down to where it actually returns something so right
it actually returns something so right here
here and let's go ahead and give this main
and let's go ahead and give this main div right here a class name of
div right here a class name of relative and let's go ahead and create
relative and let's go ahead and create an optional
an optional disabled so if this uh entire single
disabled so if this uh entire single image drop zone is disabled let's go
image drop zone is disabled let's go ahead and give it a div which is going
ahead and give it a div which is going to render our spinner component with the
to render our spinner component with the size of large and go ahead and give it a
size of large and go ahead and give it a class name of flex items D Center
class name of flex items D Center justify Das Center like this absolute
justify Das Center like this absolute D absolute like that and we're also
D absolute like that and we're also going to have inset dy- Z height full
going to have inset dy- Z height full width full and BG Das background sl80
width full and BG Das background sl80 and Z index of 50 like that perfect and
and Z index of 50 like that perfect and now let's go ahead even uh lower here
now let's go ahead even uh lower here and find this upload icon comment or
and find this upload icon comment or this upload icon upload Cloud icon if
this upload icon upload Cloud icon if it's easier like that and let's go ahead
it's easier like that and let's go ahead uh and modify this a little bit so I'm
uh and modify this a little bit so I'm going to go ahead and remove this div
going to go ahead and remove this div which has this button here we're not
which has this button here we're not going to need that and instead I'm just
going to need that and instead I'm just going to focus on this div right here
going to focus on this div right here and I'm going to change this text to be
and I'm going to change this text to be click or drag file to this area to
click or drag file to this area to upload like that uh if you want of
upload like that uh if you want of course you didn't have to change
course you didn't have to change anything inside of this file right but
anything inside of this file right but I'm just doing exactly what I want so it
I'm just doing exactly what I want so it looks better in our notion clone perfect
looks better in our notion clone perfect so again you can just visit my source
so again you can just visit my source code and copy the single image drop zone
code and copy the single image drop zone if you find this hard to follow uh it's
if you find this hard to follow uh it's always a bit more complicated with
always a bit more complicated with working with code we have to copy but
working with code we have to copy but that's completely fine uh let's go ahead
that's completely fine uh let's go ahead now back inside of our models uh cover
now back inside of our models uh cover image model right here and let's go
image model right here and let's go ahead and import that component right so
ahead and import that component right so I'm going to go ahead and import single
I'm going to go ahead and import single image drop zone and I'm going to rename
image drop zone and I'm going to rename this to use at SL
this to use at SL components like that and let's go ahead
components like that and let's go ahead and let's create our state for the
and let's create our state for the uploaded file so const file set file is
uploaded file so const file set file is going to be use state from react so make
going to be use state from react so make sure you add this this
sure you add this this import and I'm going to go ahead and
import and I'm going to go ahead and give this uh use State a file sorry a
give this uh use State a file sorry a type of
type of file like this and let's go ahead and
file like this and let's go ahead and write
write const is
const is submitting set is submitting to be used
submitting set is submitting to be used state fulse in the beginning like this
state fulse in the beginning like this and now let's go ahead and let's import
and now let's go ahead and let's import whoops let's add the edge store from use
whoops let's add the edge store from use Edge store and we can get that from s/
Edge store and we can get that from s/ lib Edge store like right here as I did
lib Edge store like right here as I did it perfect and it's going to be that
it perfect and it's going to be that easy to add our upload now now that we
easy to add our upload now now that we have our uh Edge store sorry it's not
have our uh Edge store sorry it's not Edge store with a capital S it's Edge
Edge store with a capital S it's Edge store like this you can let type safety
store like this you can let type safety completed for you so I wrote it with a
completed for you so I wrote it with a capital S so that's why I had a little
capital S so that's why I had a little error make sure you just change it to
error make sure you just change it to lowercase s great and now let's go ahead
lowercase s great and now let's go ahead and let's create our own change function
and let's create our own change function so
so const on change is going to be an
const on change is going to be an asynchronous function which accepts a
asynchronous function which accepts a file which is an optional prop if it has
file which is an optional prop if it has a file it's going to go ahead and set is
a file it's going to go ahead and set is submitting to be true it's it's going to
submitting to be true it's it's going to set file to be file and it's write const
set file to be file and it's write const to be await EDG store dopu files.
to be await EDG store dopu files. upload that specific file as easy as
upload that specific file as easy as that and then let's go ahead and let's
that and then let's go ahead and let's add our update mutation here so I will
add our update mutation here so I will just separate uh let me just do it like
just separate uh let me just do it like this I'm just playing around so it look
this I'm just playing around so it look so it makes more sense okay so states
so it makes more sense okay so states are here and these other hooks are here
are here and these other hooks are here and now let's go ahead and let's add
and now let's go ahead and let's add const update to be use mutation from
const update to be use mutation from convex react so make sure you add use
convex react so make sure you add use mutation from convex react and let me
mutation from convex react and let me move it to the top here and separate
move it to the top here and separate those Imports and let's add our API from
those Imports and let's add our API from convex generated API api. documents.
convex generated API api. documents. update great and now inside when we have
update great and now inside when we have this response here we can go ahead and
this response here we can go ahead and write a wait update ID to be pams which
write a wait update ID to be pams which we don't yet have so let's do con perams
we don't yet have so let's do con perams to be use perms
to be use perms from next SL navigation so make sure you
from next SL navigation so make sure you add this input right here and I'm just
add this input right here and I'm just going to move it
going to move it here and we're going to use pam.
here and we're going to use pam. document ID as ID which you can get from
document ID as ID which you can get from convex generated data model so make sure
convex generated data model so make sure you import this as well and that's going
you import this as well and that's going to be a type of ID documents and the
to be a type of ID documents and the thing we're going to update is the cover
thing we're going to update is the cover image and that's going to be response.
image and that's going to be response. URL like that perfect and now let's go
URL like that perfect and now let's go ahead and let's add our on close
ahead and let's add our on close function so
function so const on
close is going to be an arrow function which set file to
which set file to undefined set is submitting to false and
undefined set is submitting to false and call the cover image on
call the cover image on close like that and then we're going to
close like that and then we're going to go ahead uh to the end of this await and
go ahead uh to the end of this await and then we're going to call the enclos like
then we're going to call the enclos like this perfect and now we're ready to
this perfect and now we're ready to replace this to-do and this div with our
replace this to-do and this div with our single image drop zone like this and
single image drop zone like this and let's go ahead and give it a class name
let's go ahead and give it a class name of w- full outline
of w- full outline dnone let's give it a disabled prop of
dnone let's give it a disabled prop of is
is submitting and let's give it a value of
submitting and let's give it a value of file if we selected it and onchange to
file if we selected it and onchange to be
be onchange great so if we set up
onchange great so if we set up everything correctly this should be
everything correctly this should be working so let's go ahead and prepare a
working so let's go ahead and prepare a couple of stuff I want you to go inside
couple of stuff I want you to go inside of your dashboard in the edge store and
of your dashboard in the edge store and go ahead and select your project as you
go ahead and select your project as you can see currently I have no files inside
can see currently I have no files inside no buckin nothing and now let's go ahead
no buckin nothing and now let's go ahead and refresh my project here which I
and refresh my project here which I think I forgot to run or maybe because
think I forgot to run or maybe because of too much changes it shut down so let
of too much changes it shut down so let me just find there we go looks like my
me just find there we go looks like my project shut down so if that happened to
project shut down so if that happened to you don't worry it happens in
you don't worry it happens in development especially when we do a lot
development especially when we do a lot lot of changes at once so just go ahead
lot of changes at once so just go ahead and mpm run Dev uh make sure you have
and mpm run Dev uh make sure you have your uh MPX convex running as
your uh MPX convex running as well and let's go ahead and refresh this
well and let's go ahead and refresh this now let's wait a second and there we go
now let's wait a second and there we go it seems that the app is working let's
it seems that the app is working let's click add a cover image and let's go
click add a cover image and let's go ahead and select
ahead and select something so I just change the folder
something so I just change the folder for my images and let's go ahead and I
for my images and let's go ahead and I don't know select this image from
don't know select this image from unsplash
unsplash let's wait and let's see if we have this
let's wait and let's see if we have this Let me refresh this right here and there
Let me refresh this right here and there we go it says one file and we have the
we go it says one file and we have the file uploaded right here we currently
file uploaded right here we currently cannot see it so let's visit our
cannot see it so let's visit our dashboard our convex dashboard to see if
dashboard our convex dashboard to see if it's stored in the database correctly so
it's stored in the database correctly so go to convex dodev go ahead and click on
go to convex dodev go ahead and click on login and go ahead and select your
login and go ahead and select your project here and there we go cover image
project here and there we go cover image as you can see has has its own uh URL
as you can see has has its own uh URL here meaning that it's successfully
here meaning that it's successfully uploaded perfect and now what we have to
uploaded perfect and now what we have to do is as you can see we no longer have a
do is as you can see we no longer have a button to upload a cover image because
button to upload a cover image because instead we should already be showing our
instead we should already be showing our cover image so that's our next step
cover image so that's our next step we're going to go ahead and render that
we're going to go ahead and render that cover image and add the buttons to
cover image and add the buttons to replace it and to delete it so let's go
replace it and to delete it so let's go ahead and visit our uh document ID page
ahead and visit our uh document ID page so I'm going to close everything here go
so I'm going to close everything here go inside of the app folder main routes
inside of the app folder main routes documents document ID page. TSX and
documents document ID page. TSX and let's go ahead and remove this div which
let's go ahead and remove this div which currently holds all this space and
currently holds all this space and instead we're going to render our cover
instead we're going to render our cover component which currently doesn't exist
component which currently doesn't exist so when you save you're going to get an
so when you save you're going to get an error so let's go ahead and add the
error so let's go ahead and add the cover not inside of here but inside of
cover not inside of here but inside of our main components because that's going
our main components because that's going to be reusable as well so add cover. DSX
to be reusable as well so add cover. DSX mark it as use client and let's let's
mark it as use client and let's let's export const
export const cover and return a div sying cover image
cover and return a div sying cover image go back inside of the page. vsx where
go back inside of the page. vsx where you added the cover and you can now
you added the cover and you can now import it from s/ components cover like
import it from s/ components cover like this and if you save your errors should
this and if you save your errors should go away now let's go ahead and give this
go away now let's go ahead and give this cover a URL prop to be document. cover
cover a URL prop to be document. cover image and let's go inside of cover right
image and let's go inside of cover right now and we have to create an interface
now and we have to create an interface for that so inter face power image props
for that so inter face power image props it's going to have a URL which is an
it's going to have a URL which is an optional string and it's also going to
optional string and it's also going to have a preview optional Boolean let's go
have a preview optional Boolean let's go ahead and extract those props so cover
ahead and extract those props so cover image props and extract the URL and the
image props and extract the URL and the preview just like that now you should no
preview just like that now you should no longer have any errors inside of this uh
longer have any errors inside of this uh page. DSX and instead we can focus on
page. DSX and instead we can focus on what's written here so let's give this
what's written here so let's give this div a class name which is going to be
div a class name which is going to be Dynamics so go ahead and import CN from
Dynamics so go ahead and import CN from lib utils and let's go ahead and let's
lib utils and let's go ahead and let's first give it some default classes so
first give it some default classes so that's going to be a relative it's going
that's going to be a relative it's going to be W full height of fixed 35 VH and
to be W full height of fixed 35 VH and group and now let's give it if we don't
group and now let's give it if we don't have the URL we can lower that space so
have the URL we can lower that space so let's give it a height of 12 VH and if
let's give it a height of 12 VH and if we have an URL we're going to go ahead
we have an URL we're going to go ahead and write BG to be muted as well so for
and write BG to be muted as well so for a second it takes to load it's going to
a second it takes to load it's going to take uh it's going to look like a little
take uh it's going to look like a little skeleton there perfect now let's go
skeleton there perfect now let's go inside and let's check if we have the
inside and let's check if we have the URL in that case so this is double
URL in that case so this is double exclamation point don't mistake it with
exclamation point don't mistake it with a single exclamation point it's a
a single exclamation point it's a different thing this will turn this into
different thing this will turn this into a Boolean which is right now a string or
a Boolean which is right now a string or undefined so we're working with booleans
undefined so we're working with booleans here so if this is true meaning if we
here so if this is true meaning if we have the URL in that case render an
have the URL in that case render an image component from next SL image so
image component from next SL image so just make make sure you import this I'm
just make make sure you import this I'm just going to separate those two Imports
just going to separate those two Imports and let's go ahead and let's give it a
and let's go ahead and let's give it a source of URL itself let's give it a
source of URL itself let's give it a fill property an ALT of cover and a
fill property an ALT of cover and a class name of object Das cover like this
class name of object Das cover like this uh and let's see if we can already see
uh and let's see if we can already see something and we can see an error but
something and we can see an error but this is a step in the good direction as
this is a step in the good direction as you can see we have if you watch my
you can see we have if you watch my tutorials a familiar error so it says
tutorials a familiar error so it says that the next image host name files EDG
that the next image host name files EDG st.dev is not configured in our next
st.dev is not configured in our next config JS so when working with images in
config JS so when working with images in nextjs specifically when using the image
nextjs specifically when using the image component from next SL image right and
component from next SL image right and if you just use the regular IMG element
if you just use the regular IMG element this would not happen that's me you're
this would not happen that's me you're using the optimized images from next SL
using the optimized images from next SL image we have to add the host name where
image we have to add the host name where our file is inside of next. config.js so
our file is inside of next. config.js so let's go ahead and look at this eror go
let's go ahead and look at this eror go ahead and find find where res sets the
ahead and find find where res sets the host name and find the host name right
host name and find the host name right here for me it's files. edore dodev and
here for me it's files. edore dodev and we have to add that to next. config.js
we have to add that to next. config.js so let's go ahead and do that I'm going
so let's go ahead and do that I'm going to go inside uh of my next. config.js
to go inside uh of my next. config.js inside of this object add images domains
inside of this object add images domains and go ahead and just paste that
and go ahead and just paste that specific uh URL host name inside and my
specific uh URL host name inside and my recommendation is that you also reset
recommendation is that you also reset your server so go ahead and find your
your server so go ahead and find your Local Host here looks like it's working
Local Host here looks like it's working you can see it found a change in next
you can see it found a change in next config but let me shut it down just in
config but let me shut it down just in case and rerun it because I found some
case and rerun it because I found some kind some weird errors are happening
kind some weird errors are happening there perfect and as always uh let's go
there perfect and as always uh let's go ahead and also do npx convex Dev again
ahead and also do npx convex Dev again just in case you know uh well I I'm
just in case you know uh well I I'm pretty sure this lives outside separate
pretty sure this lives outside separate of the nextjs environment but I just
of the nextjs environment but I just want to bring your attention that we
want to bring your attention that we need to have this running as well in
need to have this running as well in case you forgot about this terminal so
case you forgot about this terminal so go ahead and rerun it just to refresh
go ahead and rerun it just to refresh your memory of it great and let's try
your memory of it great and let's try and refresh now and if I'm not mistaken
and refresh now and if I'm not mistaken we should already be seeing our uploaded
we should already be seeing our uploaded cover image for this document there we
cover image for this document there we go our beautiful image is right here
go our beautiful image is right here perfect and now we have to find a way to
perfect and now we have to find a way to remove it and to replace it so let's go
remove it and to replace it so let's go ahead back inside uh of our components
ahead back inside uh of our components cover right here and now let's go
cover right here and now let's go ahead uh and let's write if we have the
ahead uh and let's write if we have the URL and if this is not a preview in that
URL and if this is not a preview in that case we're going to add some actions
case we're going to add some actions here so this is going to be a div with a
here so this is going to be a div with a class name of opacity -0 but when we
class name of opacity -0 but when we hover on the uh this image we're going
hover on the uh this image we're going to have the opacity to 100 it's going to
to have the opacity to 100 it's going to be an absolute class with a bottom of
be an absolute class with a bottom of five right of five a flex box with items
five right of five a flex box with items centered and a gap between them of two
centered and a gap between them of two and let's go ahead and add a button so
and let's go ahead and add a button so make sure you import button like this
make sure you import button like this I'm going to change it to
I'm going to change it to components great and let's go ahead and
components great and let's go ahead and write change cover and let's give this
write change cover and let's give this an image icon from Lucid react so make
an image icon from Lucid react so make sure you import
sure you import that it's a self closing tag and give it
that it's a self closing tag and give it a class name of h-4 W-4 and margin right
a class name of h-4 W-4 and margin right off two and let's give this
off two and let's give this button an on click for now to just be an
button an on click for now to just be an empty Arrow function and let's go ahead
empty Arrow function and let's go ahead and write class name text- muted Das
and write class name text- muted Das foreground text whoops foreground text-
foreground text whoops foreground text- extra
extra small let's give it a
small let's give it a variant of outline and let's just just
variant of outline and let's just just not misspell
not misspell variant and give it a size of small and
variant and give it a size of small and then you can copy and paste this
then you can copy and paste this button like that and go ahead and change
button like that and go ahead and change this to be X from Lucid react so make
this to be X from Lucid react so make sure you import
sure you import X and let's go ahead and let's write
X and let's go ahead and let's write remove like this uh and I think that
remove like this uh and I think that should be it let's take a look now when
should be it let's take a look now when I hover here there we go I have the
I hover here there we go I have the option to change the cover or to remove
option to change the cover or to remove it so let's go ahead and create this
it so let's go ahead and create this functions now so to change a cover we
functions now so to change a cover we can just very simply add our cover image
can just very simply add our cover image hook right so const cover
hook right so const cover image is use cover image and we can do
image is use cover image and we can do that from s/ hooks use cover image and
that from s/ hooks use cover image and then I can just do find this first
then I can just do find this first button and give it an on click to be
button and give it an on click to be cover image do on open like this and
cover image do on open like this and let's go ahead and try that so when I
let's go ahead and try that so when I click cover image
click cover image let's go ahead and select another image
let's go ahead and select another image here let's wait for it to upload and
here let's wait for it to upload and there we go I successfully changed my
there we go I successfully changed my image here and now let's go ahead and
image here and now let's go ahead and let's add the remove image from
let's add the remove image from here uh so we're going to have to create
here uh so we're going to have to create a function for that and we're also going
a function for that and we're also going to have to create another API endpoint
to have to create another API endpoint inside of our uh documents file so let's
inside of our uh documents file so let's go inside of
go inside of convex documents right here so very
convex documents right here so very similarly to the way we created this
similarly to the way we created this remove icon we're going to go ahead and
remove icon we're going to go ahead and create our remove uh cover image so
create our remove uh cover image so let's go ahead and write that export con
let's go ahead and write that export con remove cover image is going to be a
remove cover image is going to be a mutation which accept the arguments to
mutation which accept the arguments to be ID of uh v. ID
be ID of uh v. ID documents a Handler it's going to be a
documents a Handler it's going to be a synchronous function which takes the
synchronous function which takes the context and the arguments we pass from
context and the arguments we pass from above let's go ahead and let's do uh
above let's go ahead and let's do uh exactly what we did above so we get the
exactly what we did above so we get the identity user ID and let's also uh copy
identity user ID and let's also uh copy the existing
the existing document so the identity check for the
document so the identity check for the identity user ID and existing
identity user ID and existing document if we don't have the existing
document if we don't have the existing document in that case throw new
error not bound if existing document user ID is
bound if existing document user ID is not identical
not identical to user ID throw new error
to user ID throw new error unauthorized and now let's go ahead and
unauthorized and now let's go ahead and let's actually update the document so
let's actually update the document so cons document await context. database.
cons document await context. database. patch arguments. ID hover image is
patch arguments. ID hover image is undefined
document great uh and now that we have that we can go back inside of our cover
that we can go back inside of our cover and let's go ahead and import the
and let's go ahead and import the mutation so
mutation so import use mutation from convex react
import use mutation from convex react and let's import our API from convex
and let's import our API from convex generated API and now let's go ahead and
generated API and now let's go ahead and add the remove cover image from use
add the remove cover image from use mutation api. documents remove cover
mutation api. documents remove cover image great and now let's go ahead and
image great and now let's go ahead and let's create const on remove to Be an
let's create const on remove to Be an Arrow function which calls the remove
Arrow function which calls the remove cover
cover image and just passes in the ID as pam.
image and just passes in the ID as pam. document we don't have the params so
document we don't have the params so let's add cons pams to be used params
let's add cons pams to be used params from next SL navigation make sure you
from next SL navigation make sure you add this import I'm going to move it
add this import I'm going to move it here and let's use pam. document ID as
here and let's use pam. document ID as ID from convex generated data model
ID from convex generated data model because we need to use the proper type
because we need to use the proper type here which is documents ID perfect and
here which is documents ID perfect and now we can assign this on remove inside
now we can assign this on remove inside of this onclick right here for the
of this onclick right here for the remove button and let's see if that is
remove button and let's see if that is working as well so when I click remove
working as well so when I click remove right here there we go I now can do uh
right here there we go I now can do uh add a cover again so let me just add a
add a cover again so let me just add a new cover here again from unsplash and
new cover here again from unsplash and let's see if it's still working there we
let's see if it's still working there we go it's working and I can even expand my
go it's working and I can even expand my screen and you can see how it works as
screen and you can see how it works as well it scales and everything I can
well it scales and everything I can collapse the entire screen and then it
collapse the entire screen and then it takes more space amazing amazing
takes more space amazing amazing job now let's go ahead and let's improve
job now let's go ahead and let's improve our change cover and remove
our change cover and remove functionality so it works perfectly on
functionality so it works perfectly on the UI side but if we take a look at our
the UI side but if we take a look at our Edge store you can see that inside I
Edge store you can see that inside I have three documents uploaded but only
have three documents uploaded but only one actual file that I'm using so it
one actual file that I'm using so it will be nice if we had a cleanup
will be nice if we had a cleanup function when we click remove and change
function when we click remove and change cover replaces the old URL instead so
cover replaces the old URL instead so what I want to do now is I want to go
what I want to do now is I want to go ahead and clear my entire schema sorry
ahead and clear my entire schema sorry my entire table from convex uh database
my entire table from convex uh database and I'm going to select all of the files
and I'm going to select all of the files here and I'm going to go ahead and empty
here and I'm going to go ahead and empty the bucket like this and let me just
the bucket like this and let me just confirm this so notion D tututorial
confirm this so notion D tututorial SLU files and let's go ahead and empty
SLU files and let's go ahead and empty these three files great so now we have
these three files great so now we have no files inside and let's go ahead and
no files inside and let's go ahead and go back to slash documents don't worry
go back to slash documents don't worry about this error we're going to handle
about this error we're going to handle errors later for now just go back to
errors later for now just go back to slash documents inside of your URL and
slash documents inside of your URL and let's go ahead and create a new page
let's go ahead and create a new page here and let's add a cover image here so
here and let's add a cover image here so I'm just going to use a random one let's
I'm just going to use a random one let's wait for this to
wait for this to upload great so now we have a file here
upload great so now we have a file here and if I refresh in the edge store I
and if I refresh in the edge store I have one file here let's head inside of
have one file here let's head inside of the documentation and let's see how
the documentation and let's see how exactly we can remove files so we're
exactly we can remove files so we're going to follow the documentation here
going to follow the documentation here we're also going to do the replace file
we're also going to do the replace file but first let's do the delete file so we
but first let's do the delete file so we can delete a file by passing the URL of
can delete a file by passing the URL of the file inside the delete method but in
the file inside the delete method but in in order to allow that we need to set
in order to allow that we need to set the before delete life cycle hook on the
the before delete life cycle hook on the bucket so let's go ahead and click here
bucket so let's go ahead and click here and see what that's about all right so
and see what that's about all right so we have to find our Edge store router
we have to find our Edge store router let's do that first I'm fairly certain
let's do that first I'm fairly certain that our Edge store router is located
that our Edge store router is located inside of API EDG stor route. DS right
inside of API EDG stor route. DS right here so there we go it's EDG store
here so there we go it's EDG store router right here and let's see what
router right here and let's see what life cycle hook we actually have to give
life cycle hook we actually have to give it so here we have the before upload
it so here we have the before upload hook and we have the before uh before
hook and we have the before uh before delete hook it says that by default
delete hook it says that by default every upload from our app is allowed so
every upload from our app is allowed so we don't need to add this hook I mean we
we don't need to add this hook I mean we already confirmed that uploading Works
already confirmed that uploading Works instead we need to add this before
instead we need to add this before delete hook right here so let's go ahead
delete hook right here so let's go ahead and copy this let's remove this comma
and copy this let's remove this comma from here and let's paste it here so we
from here and let's paste it here so we have this before delete and in my case
have this before delete and in my case we can just return true right we don't
we can just return true right we don't have to even extract any params from
have to even extract any params from here we can just simply return true so
here we can just simply return true so make sure you add this inside of your Ed
make sure you add this inside of your Ed Edge store router and then let's go back
Edge store router and then let's go back and see what we have to do for the
and see what we have to do for the deletion of the file so we have to use
deletion of the file so we have to use AWA EDG store. public files. delete and
AWA EDG store. public files. delete and passing the URL to delete and we do that
passing the URL to delete and we do that inside of our uh cover right here we
inside of our uh cover right here we have the on remove button so go inside
have the on remove button so go inside of your cover component which is inside
of your cover component which is inside of component cover. DSX and let's go
of component cover. DSX and let's go ahead and let's import Edge store from
ahead and let's import Edge store from oops uh use Edge store from at/ Li Edge
oops uh use Edge store from at/ Li Edge store let me show you that so at/ Li EDG
store let me show you that so at/ Li EDG store and I imported use Edge store by
store and I imported use Edge store by destructuring it and let's go ahead and
destructuring it and let's go ahead and inside of this on remove first thing
inside of this on remove first thing that I'm going to do is I'm going to
that I'm going to do is I'm going to write Edge store do public files. delete
write Edge store do public files. delete like that and I'm going to pass in the
like that and I'm going to pass in the URL to be let's see if we have the URL
URL to be let's see if we have the URL we have it inside of the cover so
we have it inside of the cover so passing the URL like this and let's go
passing the URL like this and let's go ahead and let's wrap this inside of if
ahead and let's wrap this inside of if we have the URL like
this like this and let's go ahead and Mark this on remove to be an
Mark this on remove to be an asynchronous function and put this
asynchronous function and put this inside of an await so this only runs
inside of an await so this only runs after this has been finished let's see
after this has been finished let's see if that's going to improve our code and
if that's going to improve our code and whether we did everything correctly so
whether we did everything correctly so inside of our Edge store right now I
inside of our Edge store right now I only have this one file and if I go
only have this one file and if I go ahead and remove the file I should
ahead and remove the file I should remove it from the database that
remove it from the database that obviously happened but let's refresh
obviously happened but let's refresh here to see if it removed from here and
here to see if it removed from here and it is as you can see the file is
it is as you can see the file is successfully removed from here here as
successfully removed from here here as well perfect and now what we have to do
well perfect and now what we have to do is we have to improve this functionality
is we have to improve this functionality that when we change cover it doesn't add
that when we change cover it doesn't add a new image instead it uses this replace
a new image instead it uses this replace file method right
file method right here in order to do that first thing I'm
here in order to do that first thing I'm going to do is go back inside of my uh
going to do is go back inside of my uh hooks use cover image right here and I'm
hooks use cover image right here and I'm going to add a new method in the type to
going to add a new method in the type to be on replaced
be on replaced and that's going to accept the URL which
and that's going to accept the URL which is a string and give it a void and then
is a string and give it a void and then we're going to go ahead and add a we
we're going to go ahead and add a we actually have to add another one which
actually have to add another one which is URL to be a type of string and let's
is URL to be a type of string and let's make it optional like this and let's now
make it optional like this and let's now write on replace here to get that URL
write on replace here to get that URL which is a type of string and let's go
which is a type of string and let's go ahead and call set is open to be true
ahead and call set is open to be true and URL to be the URL which we pass from
and URL to be the URL which we pass from here here and on close let's add the URL
here here and on close let's add the URL to be undefined like that perfect and
to be undefined like that perfect and you can also if you want to add the URL
you can also if you want to add the URL undefined explicitly here even though
undefined explicitly here even though you saw that we got no errors so you
you saw that we got no errors so you don't have to but if you want to
don't have to but if you want to explicitly write it you can do it here
explicitly write it you can do it here perfect and now let's go ahead inside of
perfect and now let's go ahead inside of our components cover right here and when
our components cover right here and when we call the uh this cover image we call
we call the uh this cover image we call the uh cover image on open instead let's
the uh cover image on open instead let's do this let's change this to be an arrow
do this let's change this to be an arrow function which calls cover image on
function which calls cover image on replace and passes in the URL prop
replace and passes in the URL prop perfect so now when we open this we're
perfect so now when we open this we're going to open our model cover image
going to open our model cover image model right here and in this cover image
model right here and in this cover image we now going to have that URL so let's
we now going to have that URL so let's go ahead and see how we have to do that
go ahead and see how we have to do that so I'm going to check if cover image has
so I'm going to check if cover image has the URL in that case I'm going to run
the URL in that case I'm going to run something else and I'm going to mark
something else and I'm going to mark this in an else function like this so
this in an else function like this so let's go ahead and wrap this and instead
let's go ahead and wrap this and instead let's go ahead and do it like this let's
let's go ahead and do it like this let's do rest and change this to not be a
do rest and change this to not be a constant but to assign to that response
constant but to assign to that response and then do a rest here and let's go
and then do a rest here and let's go ahead and follow the replace file method
ahead and follow the replace file method so we have to write await Edge store
so we have to write await Edge store dopu
dopu files.
files. upload right here let's go ahead and
upload right here let's go ahead and pass in the file we want to upload and
pass in the file we want to upload and let's pass in the options to be replace
let's pass in the options to be replace Target URL to be cover
Target URL to be cover image image. URL like this and it may be
image image. URL like this and it may be that we don't even need this if else
that we don't even need this if else perhaps we can just go ahead and add the
perhaps we can just go ahead and add the options here but first let's try it this
options here but first let's try it this way so I'm going to go ahead and try
way so I'm going to go ahead and try that now let's go inside of here let's
that now let's go inside of here let's confirm that we only have one image here
confirm that we only have one image here and now let's attempt to change the
and now let's attempt to change the cover here I'm going to go ahead and
cover here I'm going to go ahead and change it to another picture and if our
change it to another picture and if our code is correct now there should still
code is correct now there should still be only one but with a different URL
be only one but with a different URL let's refresh and there we go look at
let's refresh and there we go look at this the URL has changed and we have a
this the URL has changed and we have a working image here so our code is
working image here so our code is working and now let's try to improve it
working and now let's try to improve it even further as I said perhaps we don't
even further as I said perhaps we don't even need this if else so let's go ahead
even need this if else so let's go ahead and do this instead I'm going to remove
and do this instead I'm going to remove this I'm going to bring this back to be
this I'm going to bring this back to be a constant and then I'm going to add
options and what was the code I forgot the code was replace Target URL so let's
the code was replace Target URL so let's pass in the replace Target URL and go
pass in the replace Target URL and go ahead and pass in cover image. URL and
ahead and pass in cover image. URL and looks like it's working because the
looks like it's working because the replace Target URL can be undefined so
replace Target URL can be undefined so even if this is our first time adding an
even if this is our first time adding an image this code should work let's try
image this code should work let's try out all of the cases now so again
out all of the cases now so again confirming your Edge store we only have
confirming your Edge store we only have one file let's go ahead and call the
one file let's go ahead and call the change cover and let's replace it with
change cover and let's replace it with another file here so I'm changing a
another file here so I'm changing a completely different image it's working
completely different image it's working let's refresh our Edge store there we go
let's refresh our Edge store there we go the URL changed and we only have one
the URL changed and we only have one file now let's try and removing the file
file now let's try and removing the file there we go we no longer have this let's
there we go we no longer have this let's refresh Edge store no fil is here and
refresh Edge store no fil is here and let's try now adding a cover image to
let's try now adding a cover image to confirm that is working as well so
confirm that is working as well so something we haven't pasted let's see if
something we haven't pasted let's see if that's going to work and it looks like
that's going to work and it looks like it's working when I refresh we have it
it's working when I refresh we have it right here perfect so we did not even
right here perfect so we did not even need that if else Clause we can just
need that if else Clause we can just pass in the cover image. URL beautiful
pass in the cover image. URL beautiful amazing job and now let's try and create
amazing job and now let's try and create a new title just to confirm that we did
a new title just to confirm that we did not mess up anything so I'm going to go
not mess up anything so I'm going to go ahead and add another image from
ahead and add another image from unsplash here just to confirm that none
unsplash here just to confirm that none of this are replacing the other image so
of this are replacing the other image so let me try and replace this child cover
let me try and replace this child cover right here uh with some other image
right here uh with some other image let's see this other image from unsplash
let's see this other image from unsplash looks like it's working this one did not
looks like it's working this one did not change and I should only have two images
change and I should only have two images inside and I do have two images let's
inside and I do have two images let's try and remove this one from the child
try and remove this one from the child there we go this one is still intact and
there we go this one is still intact and now I should only have one image perfect
now I should only have one image perfect looks like it's working as intended and
looks like it's working as intended and we successfully have the deletion of our
we successfully have the deletion of our files we have the replacement of our
files we have the replacement of our files and we confirm that individually
files and we confirm that individually they do not remove each other so our
they do not remove each other so our code is working perfectly fine great
code is working perfectly fine great great
great job so now that we have our fully
job so now that we have our fully working cover image here um let's go
working cover image here um let's go ahead and I just want to add one extra
ahead and I just want to add one extra layer of security um inside of this hook
layer of security um inside of this hook right here use cover image so I don't
right here use cover image so I don't ever want us to accidentally replace an
ever want us to accidentally replace an image so whenever we use onopen I'm just
image so whenever we use onopen I'm just going to go ahead and set the URL to
going to go ahead and set the URL to undefined explicitly like this so just
undefined explicitly like this so just in case we called the on replace
in case we called the on replace somewhere and somehow we forget to reset
somewhere and somehow we forget to reset that even though the onay enclose resets
that even though the onay enclose resets it to the URL to undefined it would be
it to the URL to undefined it would be weird that it's it's left in the state
weird that it's it's left in the state and causes some unexpected events so I
and causes some unexpected events so I just changed on open to have URL
just changed on open to have URL undefined as well here and now that
undefined as well here and now that shouldn't change absolutely anything so
shouldn't change absolutely anything so I should be able to modify my screen
I should be able to modify my screen right here let's see I have one file
right here let's see I have one file here and when I refresh I have another
here and when I refresh I have another file instead and it's all still working
file instead and it's all still working it seems perfect let's go ahead and
it seems perfect let's go ahead and let's confirm inside of another file
let's confirm inside of another file here when I add the initial image I
here when I add the initial image I should now have two images in my Edge
should now have two images in my Edge store so let's refresh that that is
store so let's refresh that that is working as well that seems to be working
working as well that seems to be working the last image was not uh misplaced
the last image was not uh misplaced let's try and replace an image from the
let's try and replace an image from the other child here just confirm that that
other child here just confirm that that function is still working so I always
function is still working so I always like to be thorough when making these
like to be thorough when making these changes there we go still two images and
changes there we go still two images and let's try and remove an image and now it
let's try and remove an image and now it should be only one image great
should be only one image great everything seems to be working fine
everything seems to be working fine perfect now let's go ahead and let's go
perfect now let's go ahead and let's go in back inside of our cover. DSX so
in back inside of our cover. DSX so inside of the components
inside of the components folder and let's go ahead all the way to
folder and let's go ahead all the way to the bottom and let's write cover.
the bottom and let's write cover. skeleton to be a function cover
skeleton which is going to return the skeleton from /ui skeleton and let's
skeleton from /ui skeleton and let's just go ahead and find where we import
just go ahead and find where we import that and I'm just going to change it to
that and I'm just going to change it to add/ components UI skeleton and move it
add/ components UI skeleton and move it here to the top and let's go ahead and
here to the top and let's go ahead and give this skeleton a class name of w-
give this skeleton a class name of w- full andh of 12 VH like that and now
full andh of 12 VH like that and now let's go back inside of app main routes
let's go back inside of app main routes document ID page. DSX right here and
document ID page. DSX right here and let's focus on this document undefined
let's focus on this document undefined where we did the loading and let's now
where we did the loading and let's now import the cover. skeleton here and
import the cover. skeleton here and let's add a div here with a class name
let's add a div here with a class name of MD
of MD maxw 3XL LG Max W4 Excel mx- aouto and
maxw 3XL LG Max W4 Excel mx- aouto and margin top of 10 and inside let's add a
margin top of 10 and inside let's add a div which is going to have a class name
div which is going to have a class name of space- y-4 padding left of eight and
of space- y-4 padding left of eight and padding top of four and let's add the
padding top of four and let's add the skeleton component again from at/
skeleton component again from at/ components UI skeletons let me show you
components UI skeletons let me show you I just imported that right here and
I just imported that right here and let's go ahead and give this skeleton a
let's go ahead and give this skeleton a class name of height 14 and W
class name of height 14 and W 50% and you can copy this a couple of
50% and you can copy this a couple of times and let's give this one these
times and let's give this one these others a height of four like that and
others a height of four like that and let's give this one 80% let's give this
let's give this one 80% let's give this one 40 and this one uh 60% perfect so
one 40 and this one uh 60% perfect so now we have a nicer loading skeleton
now we have a nicer loading skeleton here and let's try that out so I'm going
here and let's try that out so I'm going to make sure you refresh everything and
to make sure you refresh everything and as you can see when I go ahead and
as you can see when I go ahead and switch my pages you can see how for a
switch my pages you can see how for a second I have a nice little loading
second I have a nice little loading skeleton which looks just a bit better
skeleton which looks just a bit better perfect and now we're finally ready to
perfect and now we're finally ready to create our editor so let's go ahead and
create our editor so let's go ahead and do
do that so we have to head inside of our
that so we have to head inside of our terminal here and let's go ahead and
terminal here and let's go ahead and let's do npm install at block note SL
let's do npm install at block note SL react and block note SL core like this
react and block note SL core like this so these two items let me try and expand
so these two items let me try and expand this there we go so block not/ react and
this there we go so block not/ react and at blote SL core like this and let's
at blote SL core like this and let's wait wait a second for all of this um to
wait wait a second for all of this um to install and then we're going to go back
install and then we're going to go back inside of this page. CSX and we're going
inside of this page. CSX and we're going to add our editor finally so let's just
to add our editor finally so let's just wait a second for this to
wait a second for this to finish great and now let's go back
finish great and now let's go back inside of page. DSX where we just
inside of page. DSX where we just rendered this skeleton right here and
rendered this skeleton right here and let's go below the toolbar and let's
let's go below the toolbar and let's render the editor component we currently
render the editor component we currently don't have it so if you save you're to
don't have it so if you save you're to get an error let's write onchange for
get an error let's write onchange for now to just be an empty Arrow function
now to just be an empty Arrow function and let's write initial content to be
and let's write initial content to be document.
content like that and now let's go inside of the components folder where we
inside of the components folder where we have the cover the toolbar the single
have the cover the toolbar the single image drop zone right here and create a
image drop zone right here and create a new file editor. DSX let's go ahead and
new file editor. DSX let's go ahead and let's mark the entire editor as used
let's mark the entire editor as used client
client and let's go ahead and let's import
and let's go ahead and let's import block node editor partial block from at
block node editor partial block from at block
block nodecore let's go ahead and let's import
nodecore let's go ahead and let's import from at blocknote
from at blocknote react block note View and use block note
react block note View and use block note like that and let's go ahead and let's
like that and let's go ahead and let's import the Styles so import at blocknote
import the Styles so import at blocknote SL 4/
SL 4/ style.css like this perfect and now
style.css like this perfect and now let's go ahead and let's write the
let's go ahead and let's write the interface editor props to have the
interface editor props to have the onchange which accepts the value which
onchange which accepts the value which is a string and a void we're going to
is a string and a void we're going to have the optional initial content which
have the optional initial content which is a string and editable to be an
is a string and editable to be an optional
optional Boolean and now let's go ahead and
Boolean and now let's go ahead and Export const editor and let's assign
Export const editor and let's assign this props here here so we're going to
this props here here so we're going to have the editor
have the editor props and let's extract them so onchange
props and let's extract them so onchange initial content and editable and for now
initial content and editable and for now let's just go ahead and return a div
let's just go ahead and return a div saying editor now we can go back inside
saying editor now we can go back inside of page. DSX and we can import editor
of page. DSX and we can import editor from at/ components editor so make sure
from at/ components editor so make sure you add this import and save the file
you add this import and save the file and you should no longer have any errors
and you should no longer have any errors and now you should just see a text which
and now you should just see a text which says editor right here let's go inside
says editor right here let's go inside of the editor here uh and let's start uh
of the editor here uh and let's start uh developing this so I'm going to go ahead
developing this so I'm going to go ahead inside of the editor props here and I'm
inside of the editor props here and I'm going to write const Editor to be a type
going to write const Editor to be a type of block note editor which we imported
of block note editor which we imported and that's going to use block
and that's going to use block note let's go ahead and write editable
note let's go ahead and write editable here let's give it an initial content to
here let's give it an initial content to be initial content question mark
be initial content question mark json.parse initial content and we're
json.parse initial content and we're going to give it a type as
partial block and an array of it or undefined like this so make sure this is
undefined like this so make sure this is written uh in one line like this but let
written uh in one line like this but let me just simplify it just so you can see
me just simplify it just so you can see it uh like
it uh like this all
right or you can just write it in one line as I did I just don't want to keep
line as I did I just don't want to keep this zoomed out so you can see better
this zoomed out so you can see better and let's write on editor content
and let's write on editor content change like this and you can write it
change like this and you can write it like that you can make it as an object
like that you can make it as an object and then just give it an arrow function
and then just give it an arrow function and don't forget to add a comma here at
and don't forget to add a comma here at the end and let's do on change to use
the end and let's do on change to use json. stringify like this editor. toop
json. stringify like this editor. toop level blocks null and two just like this
level blocks null and two just like this perfect and now let's go
perfect and now let's go ahead and let's go ahead and render the
ahead and let's go ahead and render the block note view which is a self- closing
block note view which is a self- closing tag let's give it an editor of editor
tag let's give it an editor of editor let's give it a
let's give it a theme uh well we have to uh carefully
theme uh well we have to uh carefully assign the theme because it's not the
assign the theme because it's not the same as we want the one we use inside of
same as we want the one we use inside of our code so let's write const uh resolve
our code so let's write const uh resolve the
the theme to be use theme from next themes
theme to be use theme from next themes so make sure you imported use theme I'm
so make sure you imported use theme I'm just going to move it to the top all
just going to move it to the top all right and now let's go ahead and let's
right and now let's go ahead and let's write if resolve theme is dark then we
write if resolve theme is dark then we use dark otherwise use light like this
use dark otherwise use light like this and let's go ahead and see if we can
and let's go ahead and see if we can already see this right here as you can
already see this right here as you can see we have an editor now I can do a
see we have an editor now I can do a slash I can add a heading component I
slash I can add a heading component I can go ahead and add a subheading I can
can go ahead and add a subheading I can go ahead and make a bullet list you can
go ahead and make a bullet list you can go ahead and select this and bold it
go ahead and select this and bold it italic underlying strike through it you
italic underlying strike through it you can add colors to it you can make it
can add colors to it you can make it nested you can unest it you can create a
nested you can unest it you can create a link if you want to you can also go
link if you want to you can also go ahead and move these blocks above
ahead and move these blocks above another like this so everything you can
another like this so everything you can almost everything you can do in the
almost everything you can do in the original notion and we are using this uh
original notion and we are using this uh thanks to block note so you can always
thanks to block note so you can always visit block note.
visit block note. JS like like this and you can see
JS like like this and you can see everything it has uh in its in its
everything it has uh in its in its documentation you can also try it right
documentation you can also try it right here uh inside of this uh editor here or
here uh inside of this uh editor here or you can visit the documentation and you
you can visit the documentation and you can customize it you can uh create
can customize it you can uh create different themes and styling you can
different themes and styling you can format the toolbar if you don't like it
format the toolbar if you don't like it you can modify the slash menu uh you can
you can modify the slash menu uh you can even add additional blocks on your own
even add additional blocks on your own so a bunch of stuff you can do and this
so a bunch of stuff you can do and this entire block note Ed editor is buil on
entire block note Ed editor is buil on top of Pros mirror and tip tab which are
top of Pros mirror and tip tab which are uh undoubtedly the best what you see is
uh undoubtedly the best what you see is what you get editors in
what you get editors in 2023 perfect so now that we have that
2023 perfect so now that we have that there's one thing that we have to do
there's one thing that we have to do here currently if we refresh right here
here currently if we refresh right here nothing that we've written is saved and
nothing that we've written is saved and that's because we don't have the on
that's because we don't have the on change function so let's go ahead and
change function so let's go ahead and let's create that uh on change function
let's create that uh on change function by going inside of page where we rendom
by going inside of page where we rendom the editor and let's go ahead and add
the editor and let's go ahead and add const update to be use mutation from
const update to be use mutation from convex react so just make sure you add
convex react so just make sure you add use
use mutation all right and we're going to
mutation all right and we're going to import API documents. update like this
import API documents. update like this and let's add Con on change to accept
and let's add Con on change to accept the content which is a type of string
the content which is a type of string and go ahead and update the ID using
and go ahead and update the ID using pam. document ID and the content just
pam. document ID and the content just like that and and copy this on change
like that and and copy this on change and now we can go ahead and just simply
and now we can go ahead and just simply assign it to here on change let's go
assign it to here on change let's go ahead and see how that looks now so now
ahead and see how that looks now so now if I try hello world if I add a heading
if I try hello world if I add a heading hello big world and if I refresh the
hello big world and if I refresh the entire thing as you can see it's still
entire thing as you can see it's still here perfect so you have a fully
here perfect so you have a fully functioning editor here but one thing
functioning editor here but one thing that we are missing is when we select an
that we are missing is when we select an image here we can only embed by URL but
image here we can only embed by URL but how do we add an upload file well thanks
how do we add an upload file well thanks to the combination of block editor and
to the combination of block editor and Edge store very very simply let's go
Edge store very very simply let's go inside of editor right here and let's go
inside of editor right here and let's go ahead and let's import use Edge store so
ahead and let's import use Edge store so I'm going to go here and I'm going to
I'm going to go here and I'm going to import use Edge store from /li use Edge
import use Edge store from /li use Edge store like this let's go ahead and let's
store like this let's go ahead and let's extract The Edge store from use Edge
extract The Edge store from use Edge store and now what we have to do is add
store and now what we have to do is add a function con handle upload which is a
a function con handle upload which is a synchronous function which takes in the
synchronous function which takes in the file which is the type of file and all
file which is the type of file and all it's going to do is const response to be
it's going to do is const response to be await EDG store dopu files. upload and
await EDG store dopu files. upload and pass in that file like that and return
pass in that file like that and return response. URL great and now all we have
response. URL great and now all we have to do is add that inside of the used
to do is add that inside of the used block number
block number so we're going to do upload file to just
so we're going to do upload file to just be handle upload perfect let's go ahead
be handle upload perfect let's go ahead and try it out now so I'm going to go
and try it out now so I'm going to go ahead and refresh
ahead and refresh this all right uh and let me delete this
this all right uh and let me delete this block and try again so you can either
block and try again so you can either write image like this and there we go we
write image like this and there we go we can now click upload and let's go ahead
can now click upload and let's go ahead uh and do that so let me just find my
uh and do that so let me just find my assets and let's try and import
assets and let's try and import something from here as you can see it's
something from here as you can see it's loading and there we go go look at our
loading and there we go go look at our beautiful image from here and if you
beautiful image from here and if you take a look at the convex dashboard you
take a look at the convex dashboard you can see that we have content now and
can see that we have content now and this content is just a very big uh
this content is just a very big uh string of uh stringified object right
string of uh stringified object right because it's too big to be defined as an
because it's too big to be defined as an object and this is how it's officially
object and this is how it's officially recommended from the documentation of
recommended from the documentation of block node to save it in the database
block node to save it in the database perfect amazing job you just added the
perfect amazing job you just added the editor here uh great so what I want to
editor here uh great so what I want to do next is I want to go ahead and enable
do next is I want to go ahead and enable you to publish this note so everyone
you to publish this note so everyone else can see it and also I think that if
else can see it and also I think that if I currently go onto mobile mode right
I currently go onto mobile mode right now H it seems like I can change this
now H it seems like I can change this cover and remove it but the problem is
cover and remove it but the problem is this is all on Hover right so perhaps it
this is all on Hover right so perhaps it would be a good idea to change it on
would be a good idea to change it on mobile but maybe it even looks okay I
mobile but maybe it even looks okay I don't know you can play around it with
don't know you can play around it with yourself but what I'm going to focus on
yourself but what I'm going to focus on now uh is go ahead and Publishing this
now uh is go ahead and Publishing this but before we do that let's take a look
but before we do that let's take a look at everything we left commented out so
at everything we left commented out so currently when I create a new page I'm
currently when I create a new page I'm not redirected to that page let's change
not redirected to that page let's change that so I'm going to go back inside of
that so I'm going to go back inside of my uh components
my uh components folder navigation where is it uh it's
folder navigation where is it uh it's app main components
app main components navigation right here and I think I
navigation right here and I think I commented out this
commented out this function let's try and find it is it
function let's try and find it is it even here maybe it's not here let's try
even here maybe it's not here let's try and find this so I need to find this new
and find this so I need to find this new page which ises handle create where is
page which ises handle create where is it oh it's right here handle create uh
it oh it's right here handle create uh okay and what I want to do is write do
okay and what I want to do is write do then and what we need to do is redirect
then and what we need to do is redirect to that page so we can just simply get
to that page so we can just simply get the document ID from this callback and
the document ID from this callback and then do router. push and we don't have
then do router. push and we don't have the router so let's go ahead and add the
the router so let's go ahead and add the router
router here so cons router use router from next
here so cons router use router from next SL navigation so let's see where I
SL navigation so let's see where I imported that there we go use router
imported that there we go use router from next SL navigation and then let's
from next SL navigation and then let's go ahead and find the handle create
go ahead and find the handle create again and let's use the lowercase
again and let's use the lowercase router. push let's use the back Tex SL
router. push let's use the back Tex SL documents SL individual document ID
documents SL individual document ID great and now if I go ahead and click
great and now if I go ahead and click new page here there we go I'm redirected
new page here there we go I'm redirected to it and if I click here I'm redirected
to it and if I click here I'm redirected to it as well so let's just confirm
to it as well so let's just confirm there we go uh one place where I think
there we go uh one place where I think this is not happening right now uh is if
this is not happening right now uh is if I go ahead and let's delete this forever
I go ahead and let's delete this forever if I click from here I'm not redirected
if I click from here I'm not redirected into it so let's go ahead and resolve
into it so let's go ahead and resolve that so I'm going to close everything
that so I'm going to close everything I'm going to go inside of the app folder
I'm going to go inside of the app folder main routes uh I'm going to go inside of
main routes uh I'm going to go inside of documents page. DSX and in here the very
documents page. DSX and in here the very simp thing we have the oncreate so let's
simp thing we have the oncreate so let's go ahead and add then let's get the
go ahead and add then let's get the document ID and let's go ahead and add
document ID and let's go ahead and add our router use router from next SL
our router use router from next SL navigation let me just move it to the
navigation let me just move it to the top with the others and let's do router.
top with the others and let's do router. push backck SL documents and individual
push backck SL documents and individual document ID great so now if I click from
document ID great so now if I click from here it should be the same thing perfect
here it should be the same thing perfect uh and and let's see some
uh and and let's see some inconsistencies here so when I delete
inconsistencies here so when I delete from here I'm redirected to this screen
from here I'm redirected to this screen but if I read but if I delete it from
but if I read but if I delete it from here I'm not redirected so you can
here I'm not redirected so you can choose the functionality you want right
choose the functionality you want right it doesn't matter but what I want to do
it doesn't matter but what I want to do is I want to make it equal I want to
is I want to make it equal I want to make it if I delete it from here I also
make it if I delete it from here I also want to get redirected away from it so
want to get redirected away from it so let's find that I think that's located
let's find that I think that's located inside of the app main components item
inside of the app main components item right here I think we have a function oh
right here I think we have a function oh great so we have Theon create here as
great so we have Theon create here as well so we have to fix that but let's
well so we have to fix that but let's first find the own archive like this so
first find the own archive like this so once we finish this let's go ahead and
once we finish this let's go ahead and let's do router. push to/ documents like
let's do router. push to/ documents like this so when I delete it from here I
this so when I delete it from here I also want to get redirected so pick a
also want to get redirected so pick a random document make sure you selected
random document make sure you selected and delete it from here and there we go
and delete it from here and there we go we are redirected to here okay uh and
we are redirected to here okay uh and now what I want to do is that when we
now what I want to do is that when we click create on here I'm redirected to
click create on here I'm redirected to the child document that makes sense
the child document that makes sense right so let's go ahead and find the
right so let's go ahead and find the oncreate inside of item component and I
oncreate inside of item component and I commented out this router. push because
commented out this router. push because at the time we didn't have it so let's
at the time we didn't have it so let's go ahead and see how that works now when
go ahead and see how that works now when I click plus here as you can see the
I click plus here as you can see the child is immediately the new selected uh
child is immediately the new selected uh component perfect great job so what I
component perfect great job so what I want to do now is just go ahead and
want to do now is just go ahead and quickly fix how we are supposed to
quickly fix how we are supposed to import uh the editor component so let's
import uh the editor component so let's go
go ahead inside of editor
ahead inside of editor component so components editor right
component so components editor right here and I actually don't want to do
here and I actually don't want to do export const editor instead what I want
export const editor instead what I want to do is just const editor and then at
to do is just const editor and then at the bottom I'm going to do export
the bottom I'm going to do export default
default editor so now what I can do is go back
editor so now what I can do is go back inside of my app folder main routes
inside of my app folder main routes document ID page. DSX where I use the
document ID page. DSX where I use the editor
editor and I'm not going to use this import
and I'm not going to use this import right here uh instead what I'm going to
right here uh instead what I'm going to do is I'm going to import Dynamic from
do is I'm going to import Dynamic from next SL Dynamic and I'm also going to
next SL Dynamic and I'm also going to import use Memo from react so let's go
import use Memo from react so let's go ahead inside of our document ID page
ahead inside of our document ID page right here and let's write const Editor
right here and let's write const Editor to be use memo open an arrow function
to be use memo open an arrow function and just add inde dependency array at
and just add inde dependency array at the end in this Arrow function function
the end in this Arrow function function called
called Dynamic and that Arrow function inside
Dynamic and that Arrow function inside is going to have an import which is
is going to have an import which is going to call the s/ components slash
going to call the s/ components slash the editor like that but we're not done
the editor like that but we're not done here we also have to pass in this option
here we also have to pass in this option SSR PSE to it so let me try and zoom out
SSR PSE to it so let me try and zoom out so you can see this in one line here so
so you can see this in one line here so we use use memo we call an arrow
we use use memo we call an arrow function which calls Dynamic which opens
function which calls Dynamic which opens parentheses and calls its own import
parentheses and calls its own import and then inside of the dynamic
and then inside of the dynamic parenthesis we set the configuration to
parenthesis we set the configuration to not use server s side rendering on it so
not use server s side rendering on it so this is the recommended way from the
this is the recommended way from the Block note
Block note documentation great so now that we uh
documentation great so now that we uh have that uh I think we are finally uh
have that uh I think we are finally uh ready well to handle our error state
ready well to handle our error state right that's one thing that you probably
right that's one thing that you probably noticed we have not handled yet so I'm
noticed we have not handled yet so I'm talking about this let's go ahead inside
talking about this let's go ahead inside of a trash and let's copy the URL for
of a trash and let's copy the URL for this one and let's click delete forever
this one and let's click delete forever and remove it and if I go back to it
and remove it and if I go back to it what happens is that we get an error
what happens is that we get an error well that's expected but I think we
well that's expected but I think we should handle it in a more graceful
should handle it in a more graceful way so I want you to go inside of my
way so I want you to go inside of my GitHub and go ahead and find the public
GitHub and go ahead and find the public folder and you're going to need to
folder and you're going to need to download the error dark and the
download the error dark and the error.png files so let's go ahead and
error.png files so let's go ahead and prepare our public folder so here on the
prepare our public folder so here on the side I'm just going to close everything
side I'm just going to close everything and I'm to open my public folder and
and I'm to open my public folder and let's just expand this a bit so find the
let's just expand this a bit so find the error.png and go ahead and download that
error.png and go ahead and download that file so I will drag and drop it inside
file so I will drag and drop it inside of my public folder and now go ahead and
of my public folder and now go ahead and download error dark so go ahead and
download error dark so go ahead and download that file as well and drag and
download that file as well and drag and drop it inside of your public folder now
drop it inside of your public folder now just go ahead and confirm that both of
just go ahead and confirm that both of these files are named correctly so it
these files are named correctly so it should be error.png and error -
should be error.png and error - dark.png and now let's go ahead and
dark.png and now let's go ahead and close everything and let's go inside of
close everything and let's go inside of our app folder and here in the root
our app folder and here in the root create error. vsx let's go ahead and
create error. vsx let's go ahead and Mark it as use client because every
Mark it as use client because every error component needs to be a use client
error component needs to be a use client component let's import image from next
component let's import image from next image and let's import link from next
image and let's import link from next link and let's import the button from s/
link and let's import the button from s/ components UI button and then we can
components UI button and then we can write uh sfc error like this and let's
write uh sfc error like this and let's go ahead and do a div
go ahead and do a div here with a class name h- full Flex
here with a class name h- full Flex flex-all items D Center justify - Center
flex-all items D Center justify - Center and space-
and space- y-4 and inside go ahead and render the
y-4 and inside go ahead and render the image so we're going to go ahead and
image so we're going to go ahead and render source error.png
render source error.png we're going to give it a height of 300 a
we're going to give it a height of 300 a width of 300 an Al of error like this
width of 300 an Al of error like this and let's also give it a class name of
and let's also give it a class name of dark
dark hidden and then we can go ahead and copy
hidden and then we can go ahead and copy and paste this image component and you
and paste this image component and you can give this one an error SL dark and
can give this one an error SL dark and give this an error block but hidden on
give this an error block but hidden on default great and now let's go below
default great and now let's go below those these two images and add an H2
those these two images and add an H2 element which will say something went
element which will say something went wrong and let's write class name text-
wrong and let's write class name text- extra large and font D medium and let's
extra large and font D medium and let's add the button component let's give it
add the button component let's give it an as child prop and inside of it let's
an as child prop and inside of it let's render a link component which says go
render a link component which says go back and give it an hre of Slash
back and give it an hre of Slash documents like this and make sure you do
documents like this and make sure you do expert default error and there we go now
expert default error and there we go now our error screen is looking much better
our error screen is looking much better better so in development we can still
better so in development we can still see the errors which are happening but
see the errors which are happening but in production users will not be able to
in production users will not be able to see this but they will be able to see
see this but they will be able to see this screen right here which when we go
this screen right here which when we go back leads to the working SL documents
back leads to the working SL documents page great amazing job you're so close
page great amazing job you're so close to being done here uh one more thing
to being done here uh one more thing that I want to do now is just enable you
that I want to do now is just enable you to publish a specific page and then uh
to publish a specific page and then uh allow guests to view that page perfect
allow guests to view that page perfect uh amazing job and there's and after
uh amazing job and there's and after that we also going to do the deployment
that we also going to do the deployment of
of course so now let's go ahead and let's
course so now let's go ahead and let's create the publish functionality but
create the publish functionality but before we do that I just want to quickly
before we do that I just want to quickly bring your attention that my icons in
bring your attention that my icons in the nav bar are not exactly aligned as
the nav bar are not exactly aligned as they should be you can see that this
they should be you can see that this little button here doesn't exactly match
little button here doesn't exactly match up to this button here same with this
up to this button here same with this icon it just seems a bit off uh and I
icon it just seems a bit off uh and I just caught that so let's go ahead
just caught that so let's go ahead inside of the app folder inside of main
inside of the app folder inside of main components and pick the item. TSX right
components and pick the item. TSX right here and go ahead and find where we have
here and go ahead and find where we have this document icon if else clause and
this document icon if else clause and you can leave this one as it is but
you can leave this one as it is but inside of this icon besides the height
inside of this icon besides the height 18 pixels also give it a width of 18
18 pixels also give it a width of 18 pixels like this and save the file and
pixels like this and save the file and now as you can see it's much more
now as you can see it's much more aligned uh one below another and it
aligned uh one below another and it looks a bit better it was bugging me I
looks a bit better it was bugging me I know it's a very small detail but you
know it's a very small detail but you know that's what we do uh in this
know that's what we do uh in this channel we focus in the details great so
channel we focus in the details great so let's go ahead now and let's create the
let's go ahead now and let's create the publish button which is going to be
publish button which is going to be right here next to my drop down for the
right here next to my drop down for the uh uh deleting a specific document so
uh uh deleting a specific document so I'm going to go ahead uh inside of the
I'm going to go ahead uh inside of the nav bar so you can find that in app main
nav bar so you can find that in app main components nov bar bar. vsx uh right
components nov bar bar. vsx uh right here and go ahead and find where you
here and go ahead and find where you render uh the menu right here and above
render uh the menu right here and above it go ahead and render the publish
it go ahead and render the publish component which we don't yet have so you
component which we don't yet have so you can save and you're going to get an
can save and you're going to get an error and let's go ahead and write
error and let's go ahead and write initial data to be the document which we
initial data to be the document which we have inside now let's go and create that
have inside now let's go and create that component so go ahead and create
component so go ahead and create publish. DSX inside of underscore
publish. DSX inside of underscore components in the main folder here let's
components in the main folder here let's go ahead and Mark this as use client
go ahead and Mark this as use client export con publish to Be an Arrow
export con publish to Be an Arrow function which just returns a div saying
function which just returns a div saying publish great and now we can go back to
publish great and now we can go back to the nov bar and you can import that
the nov bar and you can import that component from
ublishing this to confirm nothing is going wrong anymore there we go we have
going wrong anymore there we go we have a big publish text right here and and
a big publish text right here and and now let's go ahead inside of the publish
now let's go ahead inside of the publish and let's fix this typescript error
and let's fix this typescript error which is telling us that we have the
which is telling us that we have the invalid props for it so I'm going to go
invalid props for it so I'm going to go ahead and create an interface publish
ahead and create an interface publish props to have the initial data which is
props to have the initial data which is a type of document from convex generated
a type of document from convex generated module specifically documents schema and
module specifically documents schema and now let's go ahead and assign that so
now let's go ahead and assign that so publish
publish props and let's go inside of here and
props and let's go inside of here and write the initial
write the initial data great and now I want to create a
data great and now I want to create a hook called use origin because we're
hook called use origin because we're going to need it for this part so let's
going to need it for this part so let's go inside of our Hooks and create a new
go inside of our Hooks and create a new one called use origin. DSX let's go
one called use origin. DSX let's go ahead and import use effect and let's
ahead and import use effect and let's import use state from react and let's
import use state from react and let's write export con use
write export con use origin let's do mounted set mounted use
origin let's do mounted set mounted use state
state pulse because we're going to use the
pulse because we're going to use the window object inside of here and that
window object inside of here and that can cause hydration errors when it comes
can cause hydration errors when it comes to serice side rendering and now let's
to serice side rendering and now let's write const origin is type of
write const origin is type of window not
window not undefined inside of uh apostrophes like
undefined inside of uh apostrophes like this so we're checking if type of window
this so we're checking if type of window is not undefined in that case we're
is not undefined in that case we're going to do window. location. orig
going to do window. location. orig question mark window.location do origin
question mark window.location do origin otherwise we're going to use an empty
otherwise we're going to use an empty string and now let me just zoom out so
string and now let me just zoom out so you can see how this looks in one line
you can see how this looks in one line so origin type of window is undefined is
so origin type of window is undefined is not undefined in that case we're going
not undefined in that case we're going checking if we have the window location
checking if we have the window location origin if we do we are using the origin
origin if we do we are using the origin otherwise we are adding the empty string
otherwise we are adding the empty string great and now let's do use effect
great and now let's do use effect here set mounted to be true and give it
here set mounted to be true and give it an empty dependency array if we are not
an empty dependency array if we are not mounted just return an empty string
mounted just return an empty string otherwise you can return
otherwise you can return origin great and now let's go back
origin great and now let's go back inside of publish. DSX and let's import
inside of publish. DSX and let's import everything we need from our popover so
everything we need from our popover so import from popover uh add add/
import from popover uh add add/ components UI popover let's import the
components UI popover let's import the popover trigger let's import the popover
popover trigger let's import the popover and the popover
and the popover content great and now let's go ahead and
content great and now let's go ahead and let's write some functions and some
let's write some functions and some states which we're going to need for
states which we're going to need for this so first let's get the origin from
this so first let's get the origin from use origin which we just created which
use origin which we just created which is at/ hooks use origin so make sure you
is at/ hooks use origin so make sure you add this import here now let's go ahead
add this import here now let's go ahead and let's add our update mutation so
and let's add our update mutation so const update is use mutation from convex
const update is use mutation from convex react I'm just going to move it to the
react I'm just going to move it to the top here and we are also going to need
top here and we are also going to need the API so import the API from convex
the API so import the API from convex generated API and it's going to be api.
generated API and it's going to be api. documents.
documents. update and now let's add some states so
update and now let's add some states so we're going to write const copied set
we're going to write const copied set copied use state from react false so
copied use state from react false so just make sure you import use state from
just make sure you import use state from react and I'm going to move it to the
react and I'm going to move it to the top here besides the uh this one we're
top here besides the uh this one we're also going to have is submitting and set
also going to have is submitting and set is submitting to be used State
is submitting to be used State false let's get the URL to be origin
false let's get the URL to be origin slash preview and initial
slash preview and initial dataor ID so using this constant we are
dataor ID so using this constant we are generating what is the URL that the user
generating what is the URL that the user can share with guests to look at the
can share with guests to look at the published uh note we have so that's why
published uh note we have so that's why we needed the origin hook so we can get
we needed the origin hook so we can get whatever this website is being hosted on
whatever this website is being hosted on so if it's Local Host it's going to say
so if it's Local Host it's going to say Local Host if it's uh whatever HTTP
Local Host if it's uh whatever HTTP something.com it's going to be HTTP
something.com it's going to be HTTP something.com preview SL this great and
something.com preview SL this great and now let's add the function to actually
now let's add the function to actually publish this so const on publish is an
publish this so const on publish is an arrow function which does set is
arrow function which does set is submitting to be
submitting to be true and then const promise is an update
true and then const promise is an update function which has the ID of initial
function which has the ID of initial dataor ID and is published is set to
dataor ID and is published is set to true and now let's go ahead and do the
true and now let's go ahead and do the finally on this function and let's just
finally on this function and let's just do set is submitting to be false and now
do set is submitting to be false and now let's give it a toast here from sunar so
let's give it a toast here from sunar so make sure you import toast from Sunner
make sure you import toast from Sunner I'm just going to move it here and
I'm just going to move it here and inside of it here we're going to do
inside of it here we're going to do toast. promise we're going to pass in
toast. promise we're going to pass in the promise and we're going to write the
the promise and we're going to write the loading
loading state to be
state to be publishing we're GNA get the success
publishing we're GNA get the success state to be note
state to be note published and we're going to write the
published and we're going to write the error state to be failed to
error state to be failed to publish
publish note great and now we can copy and paste
note great and now we can copy and paste this entire onp publish
this entire onp publish function and we can rename it to on
function and we can rename it to on unpublish and we're going to do the is
unpublish and we're going to do the is published here to be false like this and
published here to be false like this and we're going to change the toast to be
unpublishing and this is going to say note unpublished and this will be failed
note unpublished and this will be failed to uh unpublish note great and one more
to uh unpublish note great and one more thing that we have is Con on copy so we
thing that we have is Con on copy so we can copy the published URL that's going
can copy the published URL that's going to be Navigator do
to be Navigator do clipboard. write text URL which we
clipboard. write text URL which we generated in this constant right
generated in this constant right here and then we're just going to say
here and then we're just going to say set copied to be true so we're going to
set copied to be true so we're going to show a little icon uh with a check mark
show a little icon uh with a check mark if we successfully copied it and then
if we successfully copied it and then we're going to wait out 1 second before
we're going to wait out 1 second before we change the icon back to uh what it
we change the icon back to uh what it was originally so 1,000 millisecs is 1
was originally so 1,000 millisecs is 1 second and we're just going to do set
second and we're just going to do set copy to be false here great and now
copy to be false here great and now let's go ahead and let's render our
let's go ahead and let's render our popover
popover component and inside of here add a
component and inside of here add a popover trigger which has and as child
popover trigger which has and as child prop and inside of it we're going to
prop and inside of it we're going to render a button component so make sure
render a button component so make sure you import
you import button from add/ components UI
button from add/ components UI button let's go ahead and write an end
button let's go ahead and write an end tag here and inside we're going to
tag here and inside we're going to render publish like this and we're going
render publish like this and we're going to check if by chance we already
to check if by chance we already published this so if it's published
published this so if it's published initial data that is published in that
initial data that is published in that case we're going to go ahead and render
case we're going to go ahead and render the glob Globe icon from Lucid react so
the glob Globe icon from Lucid react so make sure you import Globe from Lucid
make sure you import Globe from Lucid react I'm going to move it here to the
react I'm going to move it here to the top so globe and it's a self closing tag
top so globe and it's a self closing tag like this let me just wrap this in
like this let me just wrap this in parenthesis so I can uh do it in
parenthesis so I can uh do it in multiple lines and we're going to go
multiple lines and we're going to go ahead and give this globe uh a class
name of text Sky 500 W of four and height of four and ml2
500 W of four and height of four and ml2 like this and let's go ahead back to
like this and let's go ahead back to this button now give it a size of small
this button now give it a size of small and a variant of
and a variant of ghost great and now let's go ahead
ghost great and now let's go ahead outside of the trigger here and let's
outside of the trigger here and let's add the popover
add the popover content let's give this popover content
content let's give this popover content a class name of width of 72 let's give
a class name of width of 72 let's give it an align of
it an align of end let me just collapse this items here
end let me just collapse this items here so align of
so align of end and and let's also do uh a line
end and and let's also do uh a line offset to
offset to be8 and force Mount now inside of here
be8 and force Mount now inside of here check if we already published this so if
check if we already published this so if initial data is published in that case
initial data is published in that case let's go ahead and create a div here for
let's go ahead and create a div here for now which is just going to say
now which is just going to say published otherwise let's go ahead and
published otherwise let's go ahead and create the uh screen which we're going
create the uh screen which we're going to see first which is going to be a div
to see first which is going to be a div with a class name
with a class name of flex flex-all items D Center and
of flex flex-all items D Center and justify Das
justify Das Center and inside of this div uh let's
Center and inside of this div uh let's go ahead and render the globe which we
go ahead and render the globe which we have imported and let's go ahead and
have imported and let's go ahead and give it a class name of h-8 w-8 text
give it a class name of h-8 w-8 text muted
muted foreground and the margin bottom of
foreground and the margin bottom of two let's write a paragraph here which
two let's write a paragraph here which says publish this note and and let's
says publish this note and and let's write a class name of text small font
write a class name of text small font medium and margin bottom of two and
medium and margin bottom of two and below the paragraph let's add a span
below the paragraph let's add a span element which is saying share your work
element which is saying share your work with others and let's give this a class
with others and let's give this a class name of text extra small text muted
name of text extra small text muted foreground and also margin bottom of
foreground and also margin bottom of four and below that add a button which
four and below that add a button which will say publish
will say publish and this button will be disabled if we
and this button will be disabled if we are
are submitting like that it's going to have
submitting like that it's going to have an on click to be on
an on click to be on publish and the class
publish and the class name is going to be full withth with a
name is going to be full withth with a extra small text and size is going to be
extra small text and size is going to be small and I think we can already see
small and I think we can already see this now so let's go ahead and click on
this now so let's go ahead and click on this publish here and there we go we
this publish here and there we go we have a popup which says publish this
have a popup which says publish this note and and share your work with others
note and and share your work with others and if you click publish there we go now
and if you click publish there we go now it should just say published and if you
it should just say published and if you check your convex database so let me go
check your convex database so let me go ahead and log in
ahead and log in here and let's go ahead and find the is
here and let's go ahead and find the is published you can see that one of my uh
published you can see that one of my uh documents right here is published so
documents right here is published so this is true for it perfect so it's
this is true for it perfect so it's working and now let's go ahead and you
working and now let's go ahead and you can see how I have a little icon here
can see how I have a little icon here because it's published and now let's
because it's published and now let's modify how this looks uh when it's
modify how this looks uh when it's actually uh published so we need to have
actually uh published so we need to have the button to unpublish it and we also
the button to unpublish it and we also need to have an input where the URL is
need to have an input where the URL is going to be written so give this div a
going to be written so give this div a class name of space
class name of space y4 create another div inside with a
y4 create another div inside with a class name of flex items Center and GAP
class name of flex items Center and GAP X2 add a globe uh icon in here with a
X2 add a globe uh icon in here with a class name of text Sky 500 animated Das
class name of text Sky 500 animated Das pulls and height of four sorry pulse
pulls and height of four sorry pulse height of four and width of four go
height of four and width of four go ahead and add a paragraph This note is
ahead and add a paragraph This note is live on web give this a class name of
live on web give this a class name of text extra small font D medium and text
text extra small font D medium and text Sky
Sky 500 and outside of this div create a new
500 and outside of this div create a new div with a class name Flex items D
Center all right and inside of here open a native HT ml
a native HT ml input like this is going to be a self
input like this is going to be a self closing tag give it a value uh of the
closing tag give it a value uh of the URL which we have as a constant and give
URL which we have as a constant and give it a class name of flex -1 px-2 text
it a class name of flex -1 px-2 text extra small border rounded D l- MD so
extra small border rounded D l- MD so only on the left side is going to be
only on the left side is going to be rounded height of
rounded height of eight and BG muted and
eight and BG muted and truncate and important it's also going
truncate and important it's also going to be the disabled and now right beside
to be the disabled and now right beside it we're going to add a button which is
it we're going to add a button which is going to check if we have copied it in
going to check if we have copied it in that case it's going to render the check
that case it's going to render the check icon from Lucid react so just make sure
icon from Lucid react so just make sure you import the check icon from Lucid
you import the check icon from Lucid react and this is going to have a class
react and this is going to have a class name of height four and width
name of height four and width four like that and otherwise we're going
four like that and otherwise we're going to render the uh copy icon from Lucid
to render the uh copy icon from Lucid react so make sure you add the copy icon
react so make sure you add the copy icon as well and give this a class name of
as well and give this a class name of height
height four and width of four like that and
four and width of four like that and give this button uh an on click to be on
give this button uh an on click to be on copy give it a disabled prop uh to be
copy give it a disabled prop uh to be copied and give it a class name of
copied and give it a class name of height 8 BG sorry and rounded Das l-9
height 8 BG sorry and rounded Das l-9 none like that perfect so let's take a
none like that perfect so let's take a look at how this looks let me just
look at how this looks let me just refresh
this and there we go you can see how now I have an input and I can copy this now
I have an input and I can copy this now and if I try and paste this you can see
and if I try and paste this you can see that I have that copied preview URL you
that I have that copied preview URL you if you try and go there you're going to
if you try and go there you're going to get a 404 we're going to do that in a
get a 404 we're going to do that in a moment and now we need to add a button
moment and now we need to add a button here to unpublished note if we want to
here to unpublished note if we want to do that so let's go
do that so let's go ahead and let's go outside of this div
ahead and let's go outside of this div and let's just add a button here which
and let's just add a button here which is going to say
is going to say unpublish and let's go ahead and give it
unpublish and let's go ahead and give it a size of small let's go ahead and give
a size of small let's go ahead and give it a class
it a class name of w full and text extra small
name of w full and text extra small let's give it a disabled prop of is
let's give it a disabled prop of is submitting and let's give it an on click
submitting and let's give it an on click to be on
to be on unpublish great and now I think that
unpublish great and now I think that should be it so let's go ahead and click
should be it so let's go ahead and click publish here if we unpublish you can see
publish here if we unpublish you can see that note is unpublish and it's no
that note is unpublish and it's no longer available but when I click on
longer available but when I click on publish you can see that the note is
publish you can see that the note is live on web and we can copy that URL
live on web and we can copy that URL link perfect so now we actually have to
link perfect so now we actually have to create this route because if I go there
create this route because if I go there now we're getting a 404 because the
now we're getting a 404 because the preview page doesn't exist so let's go
preview page doesn't exist so let's go ahead and do
ahead and do that so we can actually do that quite
that so we can actually do that quite easily because we have all the
easily because we have all the components we already need there so
components we already need there so let's go ahead and create a new app
let's go ahead and create a new app organizational router s organizational
organizational router s organizational folder which is going to be called
folder which is going to be called public so this is not going to have any
public so this is not going to have any of the layouts that we usually have like
of the layouts that we usually have like a sidebar or a off bar right so this is
a sidebar or a off bar right so this is why organizational routes are so cool
why organizational routes are so cool and now go ahead inside of here and
and now go ahead inside of here and create another folder routes and inside
create another folder routes and inside of it create a new folder preview and
of it create a new folder preview and then the final folder which is going to
then the final folder which is going to be the IND individual document ID inside
be the IND individual document ID inside and then create a page. DSX and what you
and then create a page. DSX and what you can do is just go inside of main routes
can do is just go inside of main routes document ID page. DSX and literally copy
document ID page. DSX and literally copy everything inside so this page which
everything inside so this page which renders the editor using use memo and
renders the editor using use memo and dynamic and has the prams you can copy
dynamic and has the prams you can copy that entire page go inside of public and
that entire page go inside of public and paste it inside of this page right here
paste it inside of this page right here and as you can see we have no errors
and as you can see we have no errors with the Imports because this ones are
with the Imports because this ones are reusable right so we have no problems
reusable right so we have no problems with that but we do have to change a
with that but we do have to change a couple of stuff so first thing that I
couple of stuff so first thing that I want to do is I want to give this cover
want to do is I want to give this cover a preview prop so it's not going to be
a preview prop so it's not going to be editable same thing for the toolbar a
editable same thing for the toolbar a preview prop and same thing for the
preview prop and same thing for the editor here a preview prop sorry not
editor here a preview prop sorry not preview but editable is going to be
preview but editable is going to be false like that perfect and now let's go
false like that perfect and now let's go ahead and try if this is already working
ahead and try if this is already working so I'm going to click publish I'm going
so I'm going to click publish I'm going to copy this I'm going to paste it
to copy this I'm going to paste it inside and what I should see is this
inside and what I should see is this very same document but without the
very same document but without the sidebar I cannot edit I cannot add
sidebar I cannot edit I cannot add anything I cannot remove the image
anything I cannot remove the image nothing perfect so this is exactly what
nothing perfect so this is exactly what we want and now let's just try it out if
we want and now let's just try it out if this works when we are logged
this works when we are logged out so I'm going to go ahead uh and copy
out so I'm going to go ahead uh and copy this here and paste it in incognito mode
this here and paste it in incognito mode where I'm logged out and there we go
where I'm logged out and there we go look at it it's work working right
look at it it's work working right perfect and now let's go ahead and go
perfect and now let's go ahead and go back here and let's unpublish it from
back here and let's unpublish it from here so I'm going to click unpublish and
here so I'm going to click unpublish and look at this now we have an error
look at this now we have an error because it's no longer working and well
because it's no longer working and well I just want to bring your attention the
I just want to bring your attention the technically you can still go here where
technically you can still go here where you're logged in and here I think you
you're logged in and here I think you should oh maybe not no okay no worries I
should oh maybe not no okay no worries I thought that maybe you can still see it
thought that maybe you can still see it from here but not uh great so now you
from here but not uh great so now you can publish the route you can refresh
can publish the route you can refresh from here and everything seems to be
from here and everything seems to be working but it looks like we have a
working but it looks like we have a little mismatch of colors in our dark
little mismatch of colors in our dark mode uh so we're going to fix that of
mode uh so we're going to fix that of course but that is it we've finished all
course but that is it we've finished all the functionalities we need for this
the functionalities we need for this project amazing amazing job all that
project amazing amazing job all that it's left is to actually um deploy this
it's left is to actually um deploy this entire application but before we do that
entire application but before we do that let's just go ahead and go inside of our
let's just go ahead and go inside of our dark mode and see if anything needs
dark mode and see if anything needs fixing so it looks like here everything
fixing so it looks like here everything is okay but it looks like on preview
is okay but it looks like on preview this background is too dark let's take a
this background is too dark let's take a look at this publish button uh this
look at this publish button uh this looks fine this looks okay this looks
looks fine this looks okay this looks fine as well the trash we already fixed
fine as well the trash we already fixed some stuff that looks all good let's go
some stuff that looks all good let's go ahead and uh well everything actually
ahead and uh well everything actually seems fine it looks like great so let's
seems fine it looks like great so let's go ahead in the preview and make sure
go ahead in the preview and make sure this is published so let's just refresh
this is published so let's just refresh this and let's go ahead and and fix the
this and let's go ahead and and fix the color and we can do that easily uh by
color and we can do that easily uh by going
going inside of the preview right here sorry
inside of the preview right here sorry inside of the public folder and just
inside of the public folder and just create a file layout. DSX like this so
create a file layout. DSX like this so we reflect everything that's inside and
we reflect everything that's inside and let's go ahead and let's write sfc
let's go ahead and let's write sfc public layout let's go ahead and let's
public layout let's go ahead and let's extract the
extract the children from it like
children from it like this children rea
this children rea react
react node and now let's go ahead and let's
node and now let's go ahead and let's render a div with those children and
render a div with those children and let's give this div a class name of H
let's give this div a class name of H full and dark background to be a hex
full and dark background to be a hex code one F1
code one F1 f1f like this perfect let's try it out
f1f like this perfect let's try it out now so I'm going to go back here and
now so I'm going to go back here and there we go looks beautiful exactly as
there we go looks beautiful exactly as we expect it to look like in light and
we expect it to look like in light and dark mode
dark mode amazing amazing job this was a very hard
amazing amazing job this was a very hard project we learned a bunch of different
project we learned a bunch of different Technologies in this project uh and you
Technologies in this project uh and you completed uh the entire thing and all
completed uh the entire thing and all that's left to do is to deploy
that's left to do is to deploy it let's go ahead and do the last step
it let's go ahead and do the last step of this tutorial which is deploying the
of this tutorial which is deploying the application so if you haven't already go
application so if you haven't already go ahead and create a repository for this
ahead and create a repository for this application I did this in the beginning
application I did this in the beginning of the tutorial when I explained you how
of the tutorial when I explained you how to use trunk but just in case you
to use trunk but just in case you haven't done this let's go ahead and see
haven't done this let's go ahead and see how we do this so go ahead and open a
how we do this so go ahead and open a new repository on GitHub and go ahead
new repository on GitHub and go ahead and give your repository name like next3
and give your repository name like next3 notion
notion tutorial or actually I'm going to use
tutorial or actually I'm going to use Jan
Jan tutorial like this and I'm going to set
tutorial like this and I'm going to set it to private and I'm going to click
it to private and I'm going to click create a repository and after this is
create a repository and after this is done since this is not a new uh new
done since this is not a new uh new repository right we have a lot of files
repository right we have a lot of files here if you're going to select this
here if you're going to select this second option push an existing
second option push an existing repository from the command line and let
repository from the command line and let me see if I can do that because I
me see if I can do that because I already have a repository uh inside of
already have a repository uh inside of this so let's see if I can do this I'm
this so let's see if I can do this I'm going to go ahead and what you can
going to go ahead and what you can actually do is shut down everything so
actually do is shut down everything so you're no longer going to need the
you're no longer going to need the convex Dev or the mpm runev and just
convex Dev or the mpm runev and just paste this commands from here and there
paste this commands from here and there we go I have an error because remote
we go I have an error because remote origin already exists but let's see if
origin already exists but let's see if this command still worked or not let me
this command still worked or not let me refresh looks like it's not working but
refresh looks like it's not working but for you it's going to work if you
for you it's going to work if you haven't set up your repository
haven't set up your repository beforehand on the other side if you
beforehand on the other side if you already have the GitHub repository uh so
already have the GitHub repository uh so just refresh this page and then you're
just refresh this page and then you're going to see your GitHub repository so I
going to see your GitHub repository so I already have it let me just show you uh
already have it let me just show you uh where it
where it is so let's go inside of my repositories
is so let's go inside of my repositories and I have it right here notion dclone
and I have it right here notion dclone tutorial so this is my repository and
tutorial so this is my repository and now let's take a look at everything we
now let's take a look at everything we need to do uh to prepare convex for
need to do uh to prepare convex for production so click on Docs right here
production so click on Docs right here and find the production tab inside and
and find the production tab inside and you have the option hosting and
you have the option hosting and deployment and select verell and let's
deployment and select verell and let's go ahead and see what we need to do here
go ahead and see what we need to do here so we need to create a versal account so
so we need to create a versal account so do that if you haven't and try and sign
do that if you haven't and try and sign up with your GitHub since it's going to
up with your GitHub since it's going to be easier now we have to link our
be easier now we have to link our project on versel so click add new here
project on versel so click add new here and select a project and go ahead and
and select a project and go ahead and select that uh repository so for my case
select that uh repository so for my case it's notion dclone Das tututorial go
it's notion dclone Das tututorial go ahead and click import here and I'm just
ahead and click import here and I'm just going to change this to uh something
going to change this to uh something else because I recommend you don't use
else because I recommend you don't use the original application name inside of
the original application name inside of your url because it can be labeled as a
your url because it can be labeled as a fishing site so I'm going to change this
fishing site so I'm going to change this to note taking app like this you can
to note taking app like this you can leave the framework pres it as it is and
leave the framework pres it as it is and let's take a look at what we need to do
let's take a look at what we need to do next so it says we need to overwrite the
next so it says we need to overwrite the build command so let's go ahead and do
build command so let's go ahead and do that click on build and output seconds
that click on build and output seconds and click on the overr right tab right
and click on the overr right tab right here and change the Run command to be
here and change the Run command to be npm run build and convex deploy like
npm run build and convex deploy like this so npm run build and convex deploy
this so npm run build and convex deploy and let's see what was previously it was
and let's see what was previously it was next build so now it's mpm run build and
next build so now it's mpm run build and convex deploy and now we need to set up
convex deploy and now we need to set up our environment variables so first let's
our environment variables so first let's do it the easy way go inside of your
do it the easy way go inside of your environment. loal go ahead and copy
environment. loal go ahead and copy everything from here and paste it in
everything from here and paste it in this one and there we go I have all of
this one and there we go I have all of my uh variables right here but we're not
my uh variables right here but we're not done here because we have to change our
done here because we have to change our convex project to production so let's go
convex project to production so let's go inside of our convex dashboard select
inside of our convex dashboard select the application you're working with and
the application you're working with and let's go ahead and choose production
let's go ahead and choose production like this and there we go now it's
like this and there we go now it's creating our production and as you can
creating our production and as you can see this is completely empty so let's
see this is completely empty so let's try and find our uh URLs here so I
try and find our uh URLs here so I clicked on uh settings right here and
clicked on uh settings right here and let's see what we need to do so what we
let's see what we need to do so what we need is the deployment URL right here so
need is the deployment URL right here so let's go ahead and copy this deployment
let's go ahead and copy this deployment URL let's go here and let's find that
URL let's go here and let's find that next Publix convex URL I think that is
next Publix convex URL I think that is this one so let's paste it here so
this one so let's paste it here so replace it like that now we have the
replace it like that now we have the convex deployment here uh and let's see
convex deployment here uh and let's see if there's anything else we have to
if there's anything else we have to change uh let's try and generating a new
change uh let's try and generating a new deployment key like this there we go so
deployment key like this there we go so deploy key right here go ahead and copy
deploy key right here go ahead and copy that and change the convex deployment to
that and change the convex deployment to be the production instance of it like
be the production instance of it like this and I think uh that should be it so
this and I think uh that should be it so in this case it's convex deploy key key
in this case it's convex deploy key key but since we're working with nextjs I
but since we're working with nextjs I think ours is correct if it's not no
think ours is correct if it's not no worries and if we have any errors we're
worries and if we have any errors we're going to fix them so let's click deploy
going to fix them so let's click deploy make sure you did this changes for
make sure you did this changes for production and I'm going to pause the
production and I'm going to pause the video and I'm going to show you the
video and I'm going to show you the results I have from the
results I have from the deployment so it looks like I have an
deployment so it looks like I have an error here and I'm pretty sure you're
error here and I'm pretty sure you're going to have it as well the deployment
going to have it as well the deployment failed and it says that convex deploy
failed and it says that convex deploy key is not set so it looks like we made
key is not set so it looks like we made a mistake following this uh after all so
a mistake following this uh after all so let's go ahead and leave this as it is
let's go ahead and leave this as it is and I'm just going to zoom out and I'm
and I'm just going to zoom out and I'm going to click back here and let me just
going to click back here and let me just go ahead back inside of my projects here
go ahead back inside of my projects here let me refresh this so I have this not
let me refresh this so I have this not taking app which I tried to deploy but
taking app which I tried to deploy but it failed I'm going to click on settings
it failed I'm going to click on settings here and I'm going to go on the
here and I'm going to go on the environment variables here on the side
environment variables here on the side right and let's go ahead and see so we
right and let's go ahead and see so we have the convex deployment but we don't
have the convex deployment but we don't have the convex deployment key so let's
have the convex deployment key so let's go ahead and create that so copy this
go ahead and create that so copy this deploy key from here and we have to name
deploy key from here and we have to name it convex unor deploy unor key so let's
it convex unor deploy unor key so let's add that so convex _ deploy undor key
add that so convex _ deploy undor key and paste it like this and click save
and paste it like this and click save there we go so now we have the convex
there we go so now we have the convex deployment key like this and I'm just
deployment key like this and I'm just going to leave this as it is I'm not
going to leave this as it is I'm not even sure if if we need convex
even sure if if we need convex deployment after all and now that you
deployment after all and now that you added the new environment variables go
added the new environment variables go back inside of uh deployments here find
back inside of uh deployments here find the one that failed click on these three
the one that failed click on these three dots here and click redeploy and click
dots here and click redeploy and click redeploy one more time and I'm going to
redeploy one more time and I'm going to go ahead and pause the video again and
go ahead and pause the video again and we're going to see if there are any more
we're going to see if there are any more errors we need to
errors we need to fix and there we go looks like it's
fix and there we go looks like it's working so now let's go ahead and click
working so now let's go ahead and click on no taking app here click on Project
on no taking app here click on Project so you can get the URL which is no
so you can get the URL which is no taking app- r.v. apppp in my case in
taking app- r.v. apppp in my case in your case it's going to be something
your case it's going to be something different and look at this oh seems like
different and look at this oh seems like we have a little bug here oh well we're
we have a little bug here oh well we're going to fix that right away so I'm
going to fix that right away so I'm going to show you how to fix it but
going to show you how to fix it but let's go ahead and check if everything
let's go ahead and check if everything is working so I'm going to log in with
is working so I'm going to log in with my GitHub from here I'm going to
my GitHub from here I'm going to authorize clerk let's go ahead and there
authorize clerk let's go ahead and there we go I can enter Jan and since we are
we go I can enter Jan and since we are in production we have no no Pages
in production we have no no Pages created here and there we go so I can
created here and there we go so I can start from the beginning here perfect
start from the beginning here perfect real time is working let's test our
real time is working let's test our upload if that is working as well so let
upload if that is working as well so let me just find my
me just find my folder all right let's select a random
folder all right let's select a random image from here let's see if that is
image from here let's see if that is going to work there we go that is
going to work there we go that is working as well let's try it from here
working as well let's try it from here so I'm going to upload an image from
so I'm going to upload an image from here as well let's go ahead and add that
here as well let's go ahead and add that there we go let's try and remove an
there we go let's try and remove an image that seems to be working let's try
image that seems to be working let's try and deleting this it's in the trash we
and deleting this it's in the trash we can recover it everything is working as
can recover it everything is working as we expected let's add a little icon here
we expected let's add a little icon here there we go everything in our project is
there we go everything in our project is working the only problem we seem to have
working the only problem we seem to have is in our landing page so let's try and
is in our landing page so let's try and resolve that so I'm going to go ahead
resolve that so I'm going to go ahead and log out just make sure you have your
and log out just make sure you have your app running again so let me just go
app running again so let me just go ahead and
ahead and do terminal here
do terminal here mpm
mpm runev inside of my project and let me
runev inside of my project and let me just refresh this so I should be uh back
just refresh this so I should be uh back on my landing page and there we go this
on my landing page and there we go this is an error we have well not an error
is an error we have well not an error but it looks like our background is not
but it looks like our background is not fully uh dark here so let's see how we
fully uh dark here so let's see how we can resolve that first thing I'm going
can resolve that first thing I'm going to check is the layout page of the
to check is the layout page of the marketing folder so I'm going to go
marketing folder so I'm going to go inside of my app folder marketing here
inside of my app folder marketing here and I see I have a layout page
and I see I have a layout page and it looks like in here we do give it
and it looks like in here we do give it a specific dark color so let's see uh
a specific dark color so let's see uh what else could we change here let's go
what else could we change here let's go inside of page. DSX to see that hm maybe
inside of page. DSX to see that hm maybe here something is missing and yes let's
here something is missing and yes let's try and give that dark background inside
try and give that dark background inside of the page. DSX as well like this let's
of the page. DSX as well like this let's see if that fixes it and that seems to
see if that fixes it and that seems to have fixed it so how do you redeploy
have fixed it so how do you redeploy well very easily with versel all you
well very easily with versel all you have have to do is add this change
have have to do is add this change commit this change so
commit this change so fix and get push like this go ahead and
fix and get push like this go ahead and push that and now you can go back inside
push that and now you can go back inside of your versel you can click on
of your versel you can click on deployments and as you can see I have a
deployments and as you can see I have a new deployment building right now so I'm
new deployment building right now so I'm just going to go ahead uh and uh pause
just going to go ahead uh and uh pause my screen and then we're going to visit
my screen and then we're going to visit the landing page
the landing page again all right it's successfully
again all right it's successfully deployed and let's go ahead and check
deployed and let's go ahead and check check it out now so I'm going to go
check it out now so I'm going to go ahead and log
ahead and log out and let's take a look and there we
out and let's take a look and there we go we no longer have that black bar here
go we no longer have that black bar here which we had everything is in the color
which we had everything is in the color it's supposed to be perfect amazing
it's supposed to be perfect amazing amazing job thank you so much for
amazing job thank you so much for watching this entire tutorial and
watching this entire tutorial and remember to leave a like share comment
remember to leave a like share comment and subscribe and see you in the next
and subscribe and see you in the next one
Click on any text or timestamp to jump to that moment in the video
Share:
Most transcripts ready in under 5 seconds
One-Click Copy125+ LanguagesSearch ContentJump to Timestamps
Paste YouTube URL
Enter any YouTube video link to get the full transcript
Transcript Extraction Form
Most transcripts ready in under 5 seconds
Get Our Chrome Extension
Get transcripts instantly without leaving YouTube. Install our Chrome extension for one-click access to any video's transcript directly on the watch page.