
Join the Conversation!
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
"Please login to view comments"
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
How did you manage to remove the blur property and reach here?
Upgrading gives you access to quizzes so you can test your knowledge, track progress, and improve your skills.
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
##Looks like we found a thief monkey By the way, I liked the trick how you reached till here. You have a good sense of humor. You will improve a lot if you join our course with this passion.
var
(function-scoped, outdated)let
(block-scoped, modern and recommended)const
(block-scoped, cannot be reassigned)_
, or $
let let = 5;
is invalid)myVar
and myvar
are different)string
, number
, boolean
, null
, undefined
, bigint
, symbol
Objects
, Arrays
, Functions
Subscribing gives you access to a brief, insightful summary of each lecture to stay on track.
00:00:02 Now that we've implemented those three cards right at the top of our homepage, we can start focusing on the bottom two.
00:00:08 The companions list and the call to action.
00:00:11 The recently completed section will look something like this.
00:00:15 So it'll have to be a table.
00:00:17 of sorts.
00:00:18 Not a full-on table with lines in between the items creating an Excel sheet design, but it still has some columns and rows.
00:00:27 So, to achieve this design, we'll use a Schatzian table, a responsive table component that by default looks like this, but I'll show you how we can style
00:00:36 it further.
00:00:37 So let's install it by running this mpx-shad-cn-add-latest-add-table command, which we can run right here within our second terminal.
00:00:47 There we go.
00:00:49 And then head over into the Companions list.
00:00:52 Within it, we can start by copying the usage part of a Schatzian table component and paste it right at the top.
00:00:59 Then I'll wrap the entire Companions list in an article instead of a div so we can encapsulate it.
00:01:05 And within it, let's just render an H2 that will say something like recent sessions.
00:01:12 And then below that H2, I will then copy the second part of the usage of the table, which is the table itself, and then just paste it over here.
00:01:22 If I do this and head back over to our deployed application, you'll notice that now at the bottom, we have what seems to be a very simple straightforward table.
00:01:33 But of course, we want to make it look like the one that I showed you in the design.
00:01:37 So to achieve that, Let's actually head back over into our homepage and let's first pass the necessary props, one of which will contain the data for the table.
00:01:48 But we can start with a simple title.
00:01:51 So title will be equal to recently completed sessions.
00:01:57 Next, we'll have companions, and here is where we actually have to pass the data, so we'll make it equal to recentSessions.
00:02:06 And this is coming directly from constants, index.ts.
00:02:10 Here, you can see that I created an array of a couple of different objects that have the IDs, and then subjects, names, topics,
00:02:19 durations, and colors, so we can nicely display some dummy data within that table, at least for now.
00:02:26 Later on, all of this data will be coming for real from our database.
00:02:31 So alongside the companions, we can also pass some additional class names that will alter how the companions list will be rendered.
00:02:39 So I'll give it a class names equal to W of 2 over 3. So this is the width because one third will be kept for the call to action button.
00:02:49 And then on maxLargeDevices, we'll actually make it take the full width.
00:02:55 So I'll do a WFool.
00:02:57 Now we can head over into the companions list and accept these props.
00:03:02 So let's accept the title, the companions, as well as class names.
00:03:10 And all of these will be of a type companions.
00:03:14 list props, and we can declare that as an interface right above companions list props, where it'll have a title of a type string.
00:03:25 It'll have companions, which will be optional of a type companion coming from index DTS array.
00:03:34 And finally, a class names optional of a type string.
00:03:39 So what is this companion array?
00:03:42 Well, this companion is a type that I already created within our index.d.ts, which is where we have most of our Tabscript interfaces.
00:03:52 And here we say just that each companion will have a name, subject, topic, duration, and whether it had been bookmarked or not.
00:04:00 So now that we're accepting those props, let's actually pass the class names into this article by saying class name.
00:04:08 is equal to, I'll make it dynamic by rendering CN class names and we'll always render the companion list.
00:04:18 But then on top of it, we'll also pass the additional class names.
00:04:23 This will turn that ugly boring table into a bit more interesting table.
00:04:28 Still not good enough.
00:04:30 So I'll style this H2 by giving it a class name of font-bold text-3xl.
00:04:39 There we go.
00:04:40 That's making it stand out a bit more.
00:04:42 And now we can focus on the table.
00:04:45 We first have the table, no need for a table caption.
00:04:50 The table header will contain a table row and table row will contain the table head.
00:04:57 In this case, the first one will have a class name equal to text-lg and then width 2 over 3. And it'll simply say lessons.
00:05:09 The next one will have a class name equal to text-lg And this one will render a heading of subject.
00:05:19 And then another one will have a class name equal to text-lg, text-write.
00:05:27 And this one will render the text that'll say duration.
00:05:32 That's it.
00:05:33 We only need three.
00:05:34 And then below it, within the table body, we can map over the data that we're passing into this table as a prop.
00:05:42 So, I will simply map over companions question mark dot map where we get each individual companion and for each companion,
00:05:53 we can automatically return a table row and within each table row, we'll return a table cell.
00:06:02 And within a table cell, we'll render a link component with an href pointing to forward slash companions, forward slash companion,
00:06:13 And within it, for now, I'll just render a companion.subject, just so we can visualize it.
00:06:21 So now, if you take a look, we have split the table into three different columns, Lessons, Subject, and Duration.
00:06:30 We can remove the second table row, that was from the default Schatzian component usage, but now we have something that looks a bit closer to what we have
00:06:38 on the design, still not quite there yet.
00:06:42 So first, to get rid of this error, each table row will have to have a key equal to companion.id.
00:06:50 And I'm noticing that we started repeating ourselves just a tiny bit.
00:06:53 So we can automatically destructure the prompts from a companion, such as an ID, a subject, maybe also a name, and a topic.
00:07:05 Is there something else?
00:07:06 Well, I think there is a duration.
00:07:09 but that should be more or less it.
00:07:11 So now we don't have to repeat ourselves, and we can just say id, subject, and so on.
00:07:17 We're good.
00:07:17 And within this link, we'll actually create a div.
00:07:21 This div will have a class name equal to flex-items-center and a gap of two in between the elements.
00:07:31 And then within it, I'll render another div that will then render an image right within it.
00:07:37 Image with a source of forward slash icons, forward slash dynamic code of subject.svg.
00:07:46 So I prepared a couple of images or icons for each one of the subjects.
00:07:50 We can also give it an alt tag of subject and a width of about 35 and a height of 35 as well.
00:08:00 And we can close it there.
00:08:02 And maybe just so it makes a bit more sense, I'll split it into multiple lines.
00:08:07 There we go.
00:08:08 So now we can see different icons for each one of these subjects.
00:08:12 We can give this div a class name, equal to, size of 72 pixels, flex, items-center, justify-center, rounded-lg, on max medium devices,
00:08:31 hidden, because we don't have any space to show it on this type of view.
00:08:35 We can also apply a style.
00:08:38 because it allows us to be a bit more dynamic where we can set the background color to be equal to getSubjectColor.
00:08:47 to which we can pass the subject.
00:08:50 And this getSubjectColor is coming from utils, which we imported before.
00:08:55 It is possible that the utils got overridden when we installed ShadCN.
00:09:00 So if that happened, you'll just have to bring back the utils that we got from the assets file within the video kit.
00:09:07 Once you do that, now we are assigning a new color to each one of these divs, although they are hidden on mobile devices because there's not a lot of space
00:09:16 to show them.
00:09:17 but we will show it later on on desktop devices.
00:09:20 For now, let's head below this div, and let's create another div with a class name equal to flex, flex-call, a gap of two,
00:09:33 and then within it, we can display a p tag that'll have a class name equal to font-bold, and text-2xl, that will render a companion name,
00:09:48 or in this case, just the name.
00:09:51 So if we do this, you should be able to see different companion names.
00:09:55 And if you click on one of these, it'll actually point us to the companion session, which is the details page for that specific companion.
00:10:03 Below it, I'll also render another p tag with a class name equal to text-lg, so a bit smaller than 2xl, And here we'll render the topic.
00:10:15 Perfect.
00:10:15 So now we can see all the different lessons.
00:10:18 That's it that we want to show in the lessons table, but now we want to head over to the subject table.
00:10:24 So I'll go a bit below and we will exit the first table cell, but we'll start a new one right here.
00:10:33 This second table cell will have a div that will render the subject of a specific session.
00:10:39 Science, maths, language, coding, and so on.
00:10:43 And we can give this div a class name equal to subject-badge.
00:10:51 w-fit maxmd hidden because we don't have any space for it.
00:10:57 Then I'll create another one that we will have the space for on mobile.
00:11:01 So I'll create a div with a class name equal to flex items-center justify-center rounded-lg w-fit padding of two and on medium devices it'll be hidden
00:11:21 and we'll also give it a style equal to background color will be set to get subject color to which we can pass the subject within that div we can render
00:11:32 an image And this image will run through a source of forward slash icons, forward slash subject dot SVG with an alt tag equal to subject,
00:11:47 a width of 18, and a height of 18 as well.
00:11:52 And we can close that image right here.
00:11:55 That should look something like this once we indent it properly.
00:11:59 And now you can see that in mobile devices, we see something that looks like this, but this .svg was supposed to be outside of the subject.
00:12:07 And now we can see those small icons.
00:12:10 Now we can head into the last table cell.
00:12:13 So I'll create it right here.
00:12:15 This one will be for the duration.
00:12:17 So I will create a new div right within it with a class name equal to flex items-center.
00:12:26 gap of two w full and justify end and within it we can render a p tag that will render the duration there we go now you can see the number of minutes but
00:12:38 let's style it a bit by giving it a class name equal to text-2xl then after duration we can give it a bit of spacing and then display a span that will
00:12:51 be hidden on maxMD devices, and it'll simply say mince.
00:12:56 So on mobile, we don't have the space to say mince, but on larger devices, we will have the space.
00:13:02 We can also render an image right below this p tag.
00:13:08 that'll have a source of icons, clock.svg, with an alt tag of minutes, a width of 14, a height of 14, and a class of medium devices hidden.
00:13:23 Once again, to save some time on mobile, because on mobile we'll show the clock, usually we'll say mince.
00:13:29 So, with that in mind, now we have created this table, which looks something like this.
00:13:34 Looks great on mobile, and you can see that it even functions well on mobile, because we can still see all of the contents.
00:13:40 But where this table really shines is, of course, the desktop view, where we can see these more detailed icons.
00:13:47 Then, since we're showing the icons here in a bit of a larger format, here we show just the regular text, and then we specify the duration.
00:13:56 Pretty cool, right?
00:13:57 And finally, we have to render this call to action part.
00:14:00 That will look something like this.
00:14:02 We have to create a card within it, a little banner, a heading, a subheading, and then an image showing all the different subjects,
00:14:11 and then a button that allows us to build a new companion.
00:14:14 So to implement it, we can close what we have right now.
00:14:19 and just head over into this call to action component.
00:14:22 To start implementing it, I will turn it into a section with a class name of CTA section, which will give it this nice looking background.
00:14:33 Then I'll create a div right within it with a class name equal to CTA badge And I'll make it say, start learning your way.
00:14:45 There we go.
00:14:46 Already much better.
00:14:48 Next, an H2 right within it with a class name of text-3xl to make it stand out and font-gold.
00:14:57 And we can make it say, build and personalize.
00:15:01 your learning companion.
00:15:04 If you save it, that really sticks out.
00:15:07 I think if we remove your, it'll fit even more nicely.
00:15:10 And then below that h2, we can render a paragraph for which the text we can copy from the design.
00:15:17 something like pick a name, subject, voice, and personality and start recording through voice conversations that feel natural and fun.
00:15:26 There we go.
00:15:27 That's looking great.
00:15:28 But of course, we need the actual image and a button.
00:15:32 So let's render an image.
00:15:34 with a source of images cta.svg, an alt tag of cta, a width of about 362, and a height of about 232. I found those values to work the best.
00:15:51 There we go.
00:15:52 And below it, a new button.
00:15:55 with a class name equal to btnPrimary that'll then render a new image with a source of icons plus an alt tag of plus a width of only 12 and a height of 12
00:16:15 as well.
00:16:15 And below it, we can render a link component with an href pointing to companions new.
00:16:22 This will lead us to a form that allow us to create a new companion.
00:16:27 So the text within it can simply say, build a new companion.
00:16:34 And we can save it.
00:16:36 There we go.
00:16:37 This is actually looking amazing.
00:16:39 It looks great on mobile, but I think you can imagine it, it looks even better on desktop.
00:16:46 And everything is already technically functional.
00:16:49 I mean, you can click on each one of these lines and it'll lead you to the companion details.
00:16:54 You can click on launch lesson, which also leads to the companion details.
00:16:58 Or you can click on build a new companion, which leads you to the new companion form.
00:17:03 Pretty cool.
00:17:04 It almost feels like we have already developed our app, as everything looks almost exactly like it does on the design.
00:17:12 But we still have a long way to go.
00:17:15 For now, we have developed the UI of the homepage.
00:17:18 But now, let's develop the UI of the create a companion form, or in other words, a companion builder.