Every thriving community needs a home. Dive right in alongside Bryant and he builds a community platform inspired by Circle. He races against the clock to build an engaging and interactive community space in just one hour.
Speaker 0: Hi guys. Welcome back to the next episode of 100 Apps, 100 Hours. I'm your host, Brian Gillespie, developer advocate at Directus. And today, we will be building a community platform. Now, this is one that is near and dear to my heart because I have built a community for sign and print shop owners myself.
We use Facebook Groups for that. Not the best community platform, but it is free and everybody already has a Facebook account. But in just a quick look at the research for this episode, There's quite a few different tools out there that I located, Circle being one of the more popular ones. It's not exactly a forum, it's not exactly a course, it's not exactly chat, it's all of those things. So the pieces that we're really going to dive into today are this concept that they have of spaces.
So each one of these items in the left navigation is a space. A space can be, either private or public. So I can see here some of the circle experts and this is their their own example community. Right? They do have courses in here.
We've already done an episode on LMS, so we won't really touch on that. But, if we get into this, we could see what's new in the product. So this is an update we're gonna post. We've got some comments down at the bottom, I'm assuming, and you had to be logged in to comment. So how do we kinda recreate some of this functionality?
It looks like they have weekly events here, but we're probably not seeing those. And maybe here's something similar. So anyway, that's what we're building. If you, have watched any of the other episodes, you probably already know the rules. We've got 60 minutes to plan and build, no more, no less.
And the second rule, which is not really a rule, is use whatever you have at your disposal. So, any of the tools that are out there, AI, Tailwind CSS is one of my favorite ones. We're going to be building this platform on Directus as well. That'll be our back end. You could probably even actually build the entire thing inside Directus, but we'll probably go for a custom UI on the front end.
Alright. So, sounds great. Let's rock and roll. So we'll start the 60 minute timer and away we go. So anytime I build an app, I always love to just kinda flesh out the functionality ahead of time.
So if we're looking at this specific app, maybe I'll just pull up a text box inside Figma here. Here's the functionality that we really want out of this app. Right? We want to create and manage different spaces. Spaces for a how do I can I constrain this?
Yeah. There we go. For a community. Maybe we have events as well that we're going to list. List and create and manage events.
Events. We need to be able to log in. Users can log in. Create posts. Right?
Is that what we're going to call that? Maybe a thread? We'll get into it. Right? We'll create some posts and add comments to those posts.
That feels like a a pretty good chunk of functionality. I don't know if we'll get to all that or not. That's, like, actually building the UI for that, could be fun. Right? Alright.
So let's just, like, flesh out our our actual data model here as well. So again, I'm not the savviest Figma user, but I try. I'm a tried. Alright. So what do we have?
We've got spaces. So those are gonna be our little homes for all this different stuff, this different type of content. Right? Then we've probably got, this is where we get into the naming. Right?
Is it a a thread? Is this a what what are these things called? Are these posts? Yeah. Let's go with that.
Right? This is a post. And a post has some comments. Probably has a probably has, like, a post type, I'm assuming. K.
Let's look at what else we've got here. Share your wins. Log in. Yeah. Okay.
So these are different posts. You can upload images to a post. You can add comments. You can like. So we probably got some likes in there.
And I don't know that we'll get to that either. But, what else do we have? We have users. That's gonna be taken care of by Directus because it gives us that out of the box, which is nice. That'll be our Directus users collection.
And what else do we need for a function community? Right. Are events gonna be a separate thing than posts? I don't know. Let's we'll try it out.
Cool. Let's just add that to the end here in case we we don't have time to get to it. Alright. So this feels pretty good. We're closing in on 4 minutes or so in the planning stage.
Alright. So what do we have set up? We have, we got Directus going here. I've got a Directus instance that is totally blank, so I just reload. You'll see there are 0 collections.
And on the front end, I've got a starter Nuxt application that just basically has the Directus module or the Directus plug in already preconfigured. We're using the SDK to communicate with the Directus instance, but I've just got Directus spun up on a local Docker instance. So, really fancy app here. We've got Tailwind. We're using Nuxt UI as well on that front end.
So got quite a few things going on there. Alright. So first and foremost, we've got spaces. Let's go ahead and create our data model. Directus makes this super easy.
We'll just go into our blank instance. We'll create our first collection. We're going to call it spaces. So those are the different spaces here. We'll generate the UID.
We'll probably have a a status for the space. What's the sort order for the spaces? Who created these? When were they created? That's all pretty standard.
Let's just take a look at the network requests on this to see if we can actually pick up some of their data model. Alright. Space groups. Alright. There's the circle community.
Allow members to spaces. What else do we have? There's a slug for the space. So that's, that's a handy piece of information to have. Spaces, discussion.
Okay. So we've got a cover image. Cover image URL. And this is via their API, so it doesn't necessarily represent the underlying database structure, but this data is coming from somewhere. So we're gonna have a name for the space.
Name for the space. That's great. Alright. Do they have a description? Space description.
Space name. We're definitely gonna have a slug, so that's great. We'll roll with that. Advanced field creation mode and, when I need something like a slug or a value that URL safe, if I go into advanced mode, I have Slugify available. So that will automatically transform the input as I type.
Lock screen heading. I don't know, man. Let's just give it a description. And let's keep that non WYSIWYG. And last but not least, for our space, spaces, Let's add a cover image.
So we've got our cover image. Right? And let's see if they had do they have a type of space? Space, slug. Visibility, post type is basic.
I I wanna say there's probably some setting in here to control what these things look like, whether this is like a discussion or this is an event or a course. As we're fetching these, okay, that's a course. Internal spaces API. Maybe a type. Is there a type?
Course type. Type is a banner. K. Those are yeah. No.
I I don't wanna waste time on it. Right? Cool. So status, we'll just leave blank for now. Is this published or is it available?
And then let's say let's add 1, like, is private. This will be a toggle. So the Boolean values Boolean value, I always used to struggle with that. That's what we'll save in the database. Is this space private or not?
And then we can do a little cleanup here on our fields. So name, slug, description, maybe we pop that right beside there. And status wise, let's just roll with it. Right? So we go in, we create our first space.
Maybe we wanna call this discussion, and that'll be at the slug for that will be discussion. Here's where we discuss stuff. Great. Is it private? Yes.
Let's make it private. And then we will let's upload a cover image. Right? Unsplash. Let's just search for discussion.
Okay. Images that are not seem to be working. Okay. Maybe some type of Internet issue. We're working here locally, anyway.
Let's just grab from Circle. Right? We're already working with this specific thing. Do they have discussion? Where's the best practices for engagement?
Yeah. Fine. Let's roll with it. Cool. Alright.
So now we've got our first space. What else do we need to add to this? Right? So we've got posts for the spaces. Then each one of those posts could have comments, potentially.
Right? So, let's just go in and create another. We'll just call it announcements as the next space. Announcements, read only channel for important announcements. Very fancy.
Important announcements. Alright. So that is not private. Let's make both of these published just to to have it. Great.
Okay, so we'll go back into our settings and let's add the next item. Let's add posts. We use the UUID. Do we have a status for the post? Yeah.
Probably. Date created, date updated, is there a sort for the post? Do we wanna control the sort order on those? Yeah. Maybe potentially you do.
Alright. So if we take a look at circle here. Let's dissect one of these posts. Right? So a post has a title, looks like.
Also has a user that created the post. So Directus has taken care of that for us out of the box. We probably got a date that this was created. We've got some rich text for the post. So that'll be the post content, maybe?
Post body? You do that. Let's just keep it as content. It seems pretty straightforward. Naming stuff is always the the hardest part about development.
What else do we have? We got that cover image for the post. Right? Cover image for our post so that, you know, if we want to upload a cover image, we can. Sweet.
Looks great. Let's go in and just create one of those posts. Right? So now we've got our post. Let's add a published post.
And, Kate, if you're watching this, I'm sorry. I'm just gonna steal this post entirely. Use it verbatim inside this platform. And I'm also gonna steal your thumbnail image. Don't sue me, please.
Alright. So we've got our post. Great. Looks savvy. Okay.
Now we need to tie these together. Right? We don't have it's just floating out in space. It's not inside a space, it's in outer space. Alright, so let's tie that together.
We're going to use the relationship indirectus for that. We'll just go to our spaces and one space could have many posts. But I think a post always belongs to a single space. We wouldn't want posts in multiple spaces. So that is a good example of our one to many relationship.
There's one space, many posts, and these are gonna be called posts. The foreign key inside our post table, we'll just call that space without the s, because it's just gonna be 1. Alright. So we'll save this. And I can go into advanced mode inside Directus just to to make sure everything that I want is getting created.
And maybe we I don't know if we actually need that sort field or not, but it's fine. Let's do a post title. I probably could have went with the post name, because we had a space name and not a title. But, again, we're splitting hairs here. There's no right or wrong when when you're naming things.
There's only shades of gray. Some things are bad, some things are not. Alright. So we've got our spaces, we've got our posts, we've got a relationship between them. Right?
So if I go into my spaces now and I click add existing, I can add that existing post to our announcements space. I could save that. And then if I were to go to our discussion, I could potentially pull that in here, but because of that relationship, it would decouple those. Alright. So next we've got, what, comments?
Posts could have multiple comments. And let's do date created. We really don't have a status on these, do we? Like, you know, if the post if the comment is edited, we'll we'll be able to tell by the user updated field or the date updated field. So there we go.
We've got the comments content, content body, comment message. Yeah. Let's roll with message. That's fine. So now we've got our comments.
Let's send that relationship to the post. So we are, again, going to do a another one to many relationship. Right? Because we have a post. One post has many con comments.
Okay. So oh, actually, we're on comments here. Right? So we need the inverse relationship of that. We've got the many to 1, because we were on the comments.
So the key here will be post. Our related collection is posts. I'm gonna open up advanced because I am going to add that corresponding field inside the posts collection. That's gonna be comments. Great.
We can add our title there. Cool. Okay. So we've got comment, we've got a post. Now if we were to go, actually, let's just hop over to our post, make sure this is showing.
Alright. Maybe we wanna show the space that this is attached to as well. Go into my post. Here's the post. There's the title.
Here's the space. I can go in and add a comment. Really simple. New comment. Bada bing bada boom.
Got a comment for that space. I can see it here, though we can't actually read it. It's just showing the UUID. So I can go back in and maybe we clean this up a little bit where we got our spaces, got our posts. And here in the display template for this, I could show the actual message.
And if I wanted to, I could even get into the the weeds a bit here and show the user avatar. Is it gonna be the avatar or maybe the actual avatar thumbnail? Yeah. There we go. Looking nice.
Cool. Let's see what that looks like. Inside our post, new comment. We don't have an avatar for for little old me, so let's solve that really quickly as well. Just do right.
Right ahead. Where are you? Me. There we go. Cool.
We'll go ahead. Alright. So I could see myself that I made a comment. We can see the space it's attached to. What what are we missing from our functionality?
Right? Comments, likes, and we could do that. Post, comments, likes. I you know, do we even really wanna do likes on this? Yeah.
I think this is fine. Right? Let's let's roll with this for now and get something happening on our front end. Let's build something cool. I'm sure I'm missing something.
But oh, what if we had, like, threaded comets? Right? I don't know if the circle support that type of maneuver. Looks like it does. Right?
So, I can also have recursive relationships. So this will be a good look at what's available inside Directus as well. So I could go in and create recursive relationships. Boom. Boom.
Boom. Boom. Boom. And, you know, we we could take care of this on the front end. Or, you know, if I wanted to show that recursion, we could do it here.
So we'll add a parent key, and then we'll just reference that same collection. And let's do, like, children. Sounds cool. Great. K.
And as far as the interface, I could also do, like, the tree view, which would show, like, nested recursive items, as it says. But, maybe we don't drill down any more than one layer here. Cool. Alright. So now I can have a comment.
I can have, a parent underneath that. Parent comment. Oh, did I get this backwards? Yeah. Maybe I goofed that up a little bit.
Name these the wrong things. So children. Yeah. I did, didn't I? Let's just sort that out.
Right? The should have been a mini to 1. Okay. So that's the parents, and that's this comments collection. And then we have our children.
Didn't necessarily have to add that one, but cool. Okay. Now now we should be looking good. Right? So I can add all the children.
This is a child comment. Cool. Alright. So we're setting up a lot of this. This is gonna look nice on the front end.
Before we get into the front end, I'm also gonna go in and add a new role to the back end here. So I'll just go in, we'll call this a user. They probably don't need app access. Right? We're going to build our own front end for this.
And then we will give them access to see all the comments, see all the posts, see all the spaces. You know, do we want them to be able to create comments? Yes. We'll let them create posts. Can they create spaces?
No. Can they edit comments? Yes. Potentially. Can they edit posts?
Yes. They could edit posts. But let's do a custom permission where user created has to equal their own ID. So user created equals current user dot ID, and I'm not sure if this is actually user created dot ID. Let's try it that way just to be sure.
Alright. So now they can only edit their own posts. We could do the same for comments. And, you know, do we want to let them delete their posts? Yeah.
Probably do. But cool. Alright. So let's check the timer. We're looking good.
And now let's start building something. Right? This is not much of an app to look at at this point, but maybe we drag this over and start building. Cool. Alright.
So on the index page, let's just take a look and and dissect what we've got here. We've got like a nav on the left, then we've got the actual space here on the right. And I think that is it's pretty static. Right? So let's use our Nuxt layouts for this.
We've got a default layout. We could see that in action here. Do we wanna use layouts, or do we wanna actually do a page for this? Let's do a page. So I could use, like, a Nuxt child route for this.
What do you call this? What do they call their URLs? Right? We load this thing up. It's just slash home.
Right? Slash c. Okay. Oh, looks like they've got slash c. Okay.
That's part of all of these. Right? So we we could do something similar where we have, pages a dot view vcomp ts. Yeah. I'll I'll usually end up doing something like app dot view.
Okay. So we're gonna have 2 sections here. We've got, like, a left sidebar, and then we have the content on the right hand side. So we can, like, flex this. And on the left sidebar, They make the is the width dynamic?
No. You can't change the width on theirs. Probably a good thing. Easier that way. So let's just say with 56, we'll do p g gray 50.
And then we have the, what, main content. Right? Sounds great. Div. And here, we're gonna put this Nuxt page component.
Right? Now let's see what we got. Right? If we go to pages slash a, What did I do? Why is this not working?
Pages slash a. Come on. Refresh. Next page. Next page.
Oh. Slasha. Okay. Slash local host/a/app. No.
Slasha. Okay. Yeah. Cool. So we got nothing here.
Right? Nothing here. There it is. There we go. Okay.
So now, let's pick up our spaces. We're gonna render these over here. If I look at the Nuxt UI library, one of the things that I like here is they have this vertical navigation component. So we're just gonna use that. Right?
Here's the structure for it. We can pull that in. Let's just drop it at the end of this. Copy these links just so we get our structure. And then we'll put vertical nav in the sidebar.
But, obviously, you gotta delete these other ones. Okay. So we now we could see something going on. Maybe this needs to be height full. What is our default look here?
High screen, maybe. Okay. Alright. So now we're getting that running the full gamut. We'll probably build in a little bit of padding here.
P y 8. K. Maybe we're gonna add a logo at the top at some point. But now how do we actually get our data from Brectus into this particular instance, into this app. Alright.
We wanna pick up these spaces dynamically. What we're gonna do in that case is call the Directus API. Alright. So we're gonna do we could use the use async data composable, especially if this is gonna be accessible on the front end, without authentication or anything. Maybe you want a server side render this if it is a space that has, you know, public data on it.
Alright. So we're gonna use async data. We give this a key. Let's just call this, root. And I think this is the syntax.
Alright. So I've got a composable setup in my Directus module. Where are you, mister Directus module? There we go. Use Directus, and here we will do this.
We're going to call use Directus, and I'm gonna use the SDK that we have here. So I'm gonna read the items from our spaces collection. And, you know, I could add in, like, a some query params here or, some parameters to filter that out, but let's just take a look at our data. So I'm already seeing in the console, we've got a server 403 fetch error forbidden. Right?
That is because we are not logged in. So how do we solve that? Right? Inside our Directus module that I've got set up, I've got a an auth composable that will log us in and fetch the user and all of that, and then store that as the user and inside use state. And I've even got in a middleware.
Right? So we could add a middleware to this page, where if we're not logged in, it is going to send us to the authentication page. So, you know, if this was actually public data. Right? Maybe we needed to adjust our permission settings.
Right? So in public, I could go in, maybe people can read all the comments. They could see the spaces. They'll probably still be able to read the see the spaces. Right?
It will probably just be like the post that you would not be able to see unless they are authenticated. Alright. So here's one way we can set that up. Right? I can go into my item permissions and go to my space.
And if this is private, if it's private, I'm going to restrict. So is private equals nothing. So if if private is null, they could see all those posts. But now if I refresh, I should remove that error. And then if I look at my app, We could drill in a couple layers here.
Where's my page? Alright. So we can see the spaces that we're getting back here. Great. Okay.
So we got our individual spaces. Now let's ditch these links. Alright. And just map these out. So our links are gonna be, let's say, the let's call these spaces.
And we'll just do something like this where nav spaces equals computed. So we'll just grab this data. And we are going to map this out. Right? So we'll do spaces dot value dot map, and we got a space.
And for each space, we are going to return what, label. So that's gonna be the space dot name. Do we have an icon for these? I we didn't have an icon, but we could potentially set one up. Or maybe we don't even have an icon.
We'll just omit that. And then we have 2. Right? So 2 is gonna be slash, and let's use a template literal here. We'll do slash dot space spaces/space.slug.
Cool. Alright. And now if I do something like this, let's just log this out to make sure we're getting that. Spaces. Nav.
Why am I not getting that? Next page. Where's our app? Slash a. Where are you, baby?
What are you doing? There it is. There's our component. Now spaces cannot read property of undefined. If spaces if no spaces maybe we do this.
Data equals unref our spaces. No. We'll just do this. If spaces, no spaces, we'll return empty array. So let's fix our issues.
What do we get here? So spaces is still undefined. What am I doing wrong? Rich, doing something wrong up here in the actual call. Let's take a look at the use async data.
Oh, duh, gosh. I need more coffee. So await async data. Why is this not still need do I need to return this? There we go.
Fingers crossed. Fingers crossed. Refresh. Okay. So we got our spaces.
We're still getting undefined on our computer here. Unrefspaces.map. Alright. Why is nav spaces undefined? Space dot name.
So if we look at our spaces here, we have a name. We have a slug for those. Spaces is an array. We can confirm that. Do we have it now?
Nope. Okay. That's always the fun of doing this. Oh, nav spaces. Undefined.
What am I doing wrong here? Good question. Let's look at the clock. 23 minutes. Alright.
So it looks like I just forgot to return this, basically. I think that solves the problem. Okay. Yeah. So now I can actually see that.
Right? Kind of a bonehead move, but there we go. Sometimes it happens. So now, we've got our spaces over here and we could even, let's have a look at this component. I don't know if it will actually return.
You can use the default slot or an avatar slot, customize the avatar, or give it an icon. Yeah. What if we just give it a, like, a circle icon? Icon is circle. Let's use the material symbols, is there material symbols here?
Maybe circle. Sorry, icon. We'll just search all these. Right? They're just like a nice circle icon we could use.
Yeah. It's fine. This is the material circle icon. Let's try that for all of these different items. Icon.
Does that work? No. We need to change the syntax with Nuxt UI. Yeah. It's not showing up.
Alright. So we'll just ditch the icon for now. Cool. Alright. Let's get on with building this thing.
Right? We've got our main page, now we've got our spaces. If I click on the space, I don't have anything showing up for the space. So we'll go in and create a new folder and then we're going to do a spaces ID dot view. Right?
The other thing that I'm going to do here is create a new folder called a and drop spaces in there as well. And then I need to go back here and adjust this to where it says a or app or whatever it is. We're just kind of following their convention here. Alright. So we've got spaces.
Id. We'll just create a View component and spaces. Alright. So we click here. Are we on the space?
Yep. And we could prove that just by doing something like this where we do cons route equals use route and route. Paramsiddiscussion. Right. And we could probably call this slug.
It might be a better way just to keep everything clean, tight. And then we refresh, we can see slug is discussion. Okay. So how do we actually use this? Again, we're just gonna go in and fetch the space and we'll use async data, and we'll do spaces.
And, actually, do we need the we're we're getting the space slug. Yeah. So we'll probably fetch that. Let's call it spaces dash. If you don't provide a, like, key for async data, it will use the the actual print.
It will use the the spot that it's at in the file, like, the the file and the line number and things like that. But we'll just give it an actual key here to use when it caches things. Alright. So as far as our data, we're gonna return, we're gonna use Directus, we're gonna read the items from spaces and we are going to filter this down. Right?
So the filter is at the slug underscore equals route dot params dot slug, you know, I could filter this out a little bit, Prayms route. I don't even know if this will work. Equal slug. Returned, use directus, slug. Unexpected keyword return.
Do I not need the return? Oh, wait. Use async data. Oh, I forgot my function there. Okay.
So we're gonna return, use directus, and, oh, I got a period on my slug. Cool. Are we actually getting data there? Let's take a look at that component. Right?
This is the slug, so we'll just use our view dev tools. Do we have our space? Yes. We do. And then inside this use async data call, let's back this out.
Right? Where are you? I can do is it transform? No. They have a a set of options.
Transform, data, data 0. Let's see what that does. Now that should grab my single space. So the spaces are space because when I read items, I'm always returning an array. But using this transform on the async data call, I can transform that data and just pick up the first item from that array.
So there's my space. I don't see any posts for discussion, but if we go to announcements alright. Do we see any posts there? Yeah. That's great.
Okay. So, let's take a look at what we've got here for circle. We've got our discussion or our spaces over here, and then we have the discussion here. Alright. Cool.
So we will add a header. It's got a cover image on it, basically. Let's try to find one where we did have some discussion. Right? Courses, engagement, Contest guidelines.
Okay. Alright. So then we click into a post, and that is the assuming that's a space. Events new. I click into that.
Events new. That's the slug for the post, I assume. Alright. So let's render out the header image for the space. Source is gonna be space dot cover underscore image.
We'll make this full width. Maybe a height of 32. Object cover. See what we've got here. Just flip back.
Input must be a string. Okay. So if we don't have the space dot cover image, space dot cover image, let's not try to render it. Is that the problem? Discussion.
Okay. So I'm trying to get the image here, but what's happening? Right? Why are we not getting the image? It is because we are getting a 403 forbidden.
We'll go into Directus here, go back to our access control. We have not allowed files to be shared. Okay? So there's our actual item. That's great.
This is gonna be flex Flex 1. With full. Yeah. Okay. Alright.
So we got our header. Let's just keep moving. Then we have our post detail. Right? I've got a v text component here that this will render, like, paragraph text.
But, if we're gonna do something like the rich text for the post, So let's look at posts. We've got, like, this post content here. So we're great for a title. Alright. So let's just do, like, a h 2 or maybe an h one for the post.
Not sure. Let's just do h two. Oh, we're not even showing the actual post. Right? Let's do an h one because we wanna show the space name.
Alright. So there's the space name. It gives us a little padding. Pxpy6. Okay.
Make this bold. Make it a little larger. 2 XL. Alright. So there we have that.
Let's dive into the actual posts. Right? So 2 ways I could go about this. I could get all of the posts in a single call with Directus, or I could fetch these separately as well. In this case, let's just render some of these posts out.
So we will go into our query here, and we'll do fields. Alright. So if I wanted to do, like, some cards so let's just back up and take a look at circle here. Right? We've got a couple of cards here that are showing up.
Let's do the ucard, which is inside that Nuxt UI library. We're gonna do a post in space dot post. And Get a key. Key is gonna be post dot ID. And And then let's just render out post dot title.
Oh, and that's not building because I did not close that off. Right. But now I'm not seeing anything. If I go to announcements, hey, I've got a card here. Nothing is rendering.
And that's because if I take a look at my data, right, where are you, data. So inside this slug, I've got the space, we've got some posts here, but it's just returning an actual ID. How do I grab the actual post for this? So I go into fields. I could grab all the root level fields like this.
And with the SDK, I can do the the TypeScript safe syntax is is actually specifying this out as an object. But for the sake of this, maybe I do, like, a double wildcard here. And now we could see, if I open this up, we can see the space, we get the post. It is fetching all of the content for that specific post. Right?
Great. Looks like we've got a card. How do these cards look? Okay. So we got a header on the card.
That's the the post image. Alright. So we got template. Be the card header. Then we just have a regular slot.
P. Oh, where are you? Mister p tag. And here, this will be the header. We've got Nuxt Image.
That'll be the v if post cover underscore image. The source would be post dot cover underscore image. Let me just close that up, see what we get. Okay. Now we're getting somewhere.
Great. This is actually gonna be a NuxLink. Right? Do we wrap the entire card? How are they doing it here?
Looks like the the entire image, and then I can click over here. Right? So we wrap the image in a Nuxt link, Nuxt link. For our spaces, we're gonna do this will be the post. We'll add, and then we'll do something like this where we have index.
I think this will give us the routing that we want. Alright. What else was I missing? The actual Nuxt link. Right?
2 a slash, we got what the space well, actually, this is gonna be the slug. Alright. Well, we've got the slug up there. And then we have post dot slug. Post dot slug.
Yeah. Cool. And there's our Nuxt link. I will just copy this here. Run that one more time.
Run it back. And does that give us where we want to go? Except it doesn't, does it? Okay. Okay.
Yeah. No. Now we're navigating where we wanna go. Why do we not have a slug? Do we not have a slug on the post?
We don't. That's why it's not showing up. Alright. So let's quickly add a slug to these posts. And, you know, we could even create a, an automation inside Directus that would do this for us.
And I'll just quickly add a test log. Okay. So we go there. Test log is not showing up. Page not found.
Why is that? Because we're not doing the actual right. So we got spaces slash spaces. K. Now we go back.
We try it again. Right? Go back. Refresh, maybe. K.
A spaces slash announcement post. Oh, the Alright. This needs to be an actual we need a folder for that. Right? What's the best way to set this up?
Okay. So spaces actually becomes this. Right? This is the space, and then this is the index route for that space. This becomes anywhere that we're referencing slug becomes the actual space.
Brand space space. Oh, let's not destructure that space. Slug. Does that work? Spaces, slug, Space.
Space. Space. Space. What are we what are we missing? What are we missing?
Let's just go back. Alright. Slug. Okay. So now I've got the space.
Right? Let's just log the params out here. Params. Why can't I like any ears? Params, slug, spaces announcements.
Oh, it has to do with the URL structure now. Right? We've changed that. So we go back to our tag here. We don't really need this.
Okay. So at least now we're getting an error. And what else do we have here? Index dot view slug space slug. Give it to me.
Input string space dot cover image. Oh. What am I doing wrong here? So there's our announcements. Okay.
It's because we don't have any. This would be v if space dot post dot length greater than 0. Solve the the issues. It doesn't like that. Vcard.
Vfpost.coverimage.source.post.coverimagespace. Why does it unlike the unlike the discussion page? No worries, though. So we change the routing there. Alright.
So now we are now we're getting somewhere. Right? We've got the routing the way that they do it. And then inside this post, we will actually fetch the individual post as well. Alright.
So we'll come here. Let's just call this post so we can render that out. The data will be post. We are going to fetch the post dot dash slug. And instead of spaces, we're gonna do post.
And in this case, this one is actually called post. Alright. What else do we need? It's gonna grab our comments as well. Alright.
Boom. Okay. So now we can see our post. Looking great. If we go back, we'll grab the header image.
K. Post dot cover image. Do we have a cover image for that post? Yes. We do.
Why are we not sorting through that post dot cover image? Input must be a string. Oh, because we're fetching all of the data. Let's just delete that. That's probably why.
Okay. So there's our cover image. Let's do a div. We're gonna do VHtml. This is gonna render out our actual content.
So post dot contents. And Telwin has some really nice typography styles already preset for you, and we are going to just use those. Right? Pros. Missing our intag.
Alright. Let's wrap this again. Div. We've got p x 4. Give us some padding.
K. There's our post. Let's get into the comments. Right? How do we get down to the comments?
We'll do just give this a little breathing room. P x a p y 8. 6 is not nearly enough padding. I definitely need to go in and, update the the actual mobile views for this as well. And then we have our comments section.
How we doing on time? 55 seconds. Man, this one has been a little bit of a struggle. A little more to it than what I thought originally. Also operating on not enough coffee.
So it's it's pretty painfully obvious at this point. Not going to get to any of the comments. So if we look at our functionality, right, we managed to get here. Users can log in. Did we even get there?
We actually did, because it was already baked in, but we didn't we didn't really mess with that. Alright? There's a auth login page where I could actually log in to this thing. Users create posts and add comments to those posts, create and manage events. Man, like, we did not do so great on this one.
So, sometimes you fail. Circle is a really cool app. You know, recreating that functionality, there's a lot baked into it. So, you know, hey. What do we give this one?
Like, Cisco and Evert would probably give this one 2 thumbs down, but that's the way it rolls. You know, we've learned a lot about the different data models and how to use the different relationships inside Directus. So let's chalk it up as a a tie, maybe. I don't know. That's it for this episode of 100 apps, 100 hours.
Thanks for joining me. We'll see you on the next one.