تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Upgrade Tailwind to JIT0:00

Okay, let's continue with the small fixes. I have them listed in my note-taking app here. So let's see if we can get through all of them. So the first one is to update Tailwind and make use of the Just-In-Time compiler. So, I started this project right before it was released. So let's go ahead and update our Tailwind version. So the latest version is 2.1.2 at the time of this recording. So let's update our package.json. Let's look for Tailwind here. And let's update Tailwind CSS to 2.1.2.

package.json. Let's look for Tailwind here. And let's update Tailwind CSS to 2.1.2. And this should have the Just-In-Time compiler within the core. So let's go ahead and npm install. And if you're not familiar with the Just-In-Time compiler, you can take a look at this link here. And in a nutshell, it generates your styles on demand, as opposed to having everything all at once. So that should be installed now. Okay, I think we only have to make one change here. So let's go to our Tailwind config.

Okay, I think we only have to make one change here. So let's go to our tailwind.config.js. Actually, before I do that, let's go ahead and npm run dev so you can see the size of the outputted CSS. Okay, as you see, we have our CSS here, and it's 2.85 megabytes. So let's go into our code and use the Just-In-Time compiler. And I think we just have to make one change here. And that is to set the mode to the jit. Okay. And make sure your purge array is

to the JIT. Okay. And make sure your purge array is set correctly, because this is where it's going to look for files to generate the CSS. So now, let's go ahead and npm run dev again and see the file size. There we go. It's 43.7 kilobytes. And just to make sure everything is still working correctly, if we refresh our app here, it still looks the same as before. But now we're using the compiler. So just note that every time you make changes to the CSS, you should run the watcher,

Use Tailwind Blend Mode2:08

But now we're using the compiler. So just note that every time you make changes to the CSS, you should run the watcher, because it needs to watch for changes and generate the CSS every time you add new classes. So the newer version of Tailwind also has support for blend modes. So let's look for that in the documentation. Let's look for blend here. And you can see the mix-blend-mode. And we are using luminosity here. So let's use this instead. So if you don't remember, we're using luminosity for this here.

So let's use this instead. So if you don't remember, we're using luminosity for this here. And I'm using an inline style for that, because this feature is new in Tailwind. So let's look for that. Ideas index, I believe. It's in a few places. And right here, we're using an inline style. But now we can make use of that new class. So let's get rid of that. And if we save that, you'll see that it's colored now. But if we add that class, it should set the blend mode correctly. Okay, cool. So we also have to do this in

Fix Firefox CSS Border3:44

rid of it. And let's add that class. Okay. Next is, we have a Firefox CSS issue. This is minor. Let's take a look. I think I have it open here. So this page, you'll see that the border here is incorrect. And since we already have our watcher running, let's go ahead and fix it. So if we go into our app.css file, so app.css, I believe we just have to get rid of, where is it? Is statusUpdate. This border image slice. To be honest, I don't even know what this does. But it does fix the background.

Show Gravatar Avatar4:48

this one next. Let's do this first. We should have the Gravatar image here when we're logged in. That should be easy enough. So back to our code. This should be in app.blade.php. I think. Look for our avatar here. Yeah. So right here. This should just be auth()->user()->getAvatar(). Okay. Does that work? It does.

Preserve New Lines5:20

Get avatar. Okay. Does that work? It does. Next. So now let's do this. So whenever we add ideas or comments, so let's add an Idea here. New Idea. And whenever we add new lines here, this is my idea. Thanks, Andre. And if I submit this. So for this page, I do want it to appear on one line. So this is fine. But on the actual Idea page,

this. So for this page, I do want it to appear on one line. So this is fine. But on the actual Idea page, I want it to preserve the new lines. So if you look in the database, the new lines actually get stored in the database. So if you go to my Client here, check out that idea, and it's sort by the last ID. Should be this one. And you can see the new lines here. However, when we do the double braces in Laravel, it strips them out. So in this case, it should be an idea show.

the double braces in Laravel, it strips them out. So in this case, it should be an Idea show. And I'm not sure what I named it. Was it description? Yeah. So whenever we do the double curlies here, it does remove the new lines. So to put that back, we can just not escape it here. Make use of php's new line to line break method. And let's also make sure to escape this. So we can use the E method within Laravel and do this.

this. So we can use the E method within Laravel and do this. And if you're not familiar with the E function, all it does is run PHP's HTML special chars function. Okay. So let's do the same thing. Actually, let's first check if that works. And now this should be, or this should preserve the new lines. And it does. Cool. So let's do the same for comments. So let's add a comment here with some new lines. Adding a comment with new lines. So let's post that. And as you see, it strips out new lines.

comment with new lines. So let's post that. And as you see, it strips out new lines here. But let's go ahead and preserve those. So we can do the same thing. Let's grab this. Should be an Idea Comment. And what did I name it? commentBody. So right here, let's just replace this. Same thing, but it's commentBody. Okay. Does that preserve the new line? It does. Cool. So the notifications are fine because I just want that to be on one line. So

Refactor Status Count Test8:32

one of the tests. So I believe it's the status test. Yeah. So for this test, can get count of each status. I'm creating one Idea for this, two for this, three, four, five for a total of 15 right here. And for some reason, I am doing it manually and not making use of the count functionality. So instead of creating two here, I mean, I am creating two, but I'm doing it manually. So not sure why I did that. We can just use a number in here, which is definitely cleaner. So

Cascade Delete Ideas9:36

we can say five or sorry, this one too. Okay. And now that's much cleaner should still pass. And it does. Cool. Next. So when we're deleting ideas, we should set the onDelete to cascade. So let's take a look at deleting ideas. So where's that delete idea? Yeah, here. So if you remember, we had to delete the votes and the comments associated with the idea manually. So right here, we're deleting the votes

So if you remember, we had to delete the votes and the comments associated with the Idea manually. So right here, we're deleting the votes here that belong to the Idea. And we're deleting the comments here that belong to the Idea. So if I were to comment this out and try deleting an Idea with votes or comments or both, then we're going to get an error. So let's try that. This one's fine. Let's refresh. Let's try deleting and we should get a database error. So like I said, it's probably a good idea to let the database handle this instead of doing it manually in our code. So if we go to our create_votes table

let the database handle this instead of doing it manually in our code. So if we go to our create_votes table for the Idea here, we can say onDelete('cascade'). So let's go ahead and do that. Let me just copy this actually. Okay. Go back here. And for the Idea, let's say onDelete('cascade'). And same for comments. So create_comments table. So for the Idea onDelete('cascade'). So now if I stop this, php artisan migrate:fresh

So for the Idea on delete cascade. So now if I stop this, migrate fresh seed, now our code should work. But the database is now responsible for deleting any votes or comments associated with the Idea. So let's take a look. Let's go back here. And let's go to the main page. And this one has votes and comments. Remember, we commented out the code that does it manually, but it should work now because the on delete cascade is set. So if we go here, we remove these,

manually, but it should work now because the onDelete cascade is set. So if we go here, we remove these, but it should work now. So let's try that out. Delete. And it does work. Cool. So let's go ahead and remove these lines of code. And I think I'm also using it in the CommentNotificationsTest. Look for that up here. So yeah, before I delete the Idea, I'm deleting the comments. So we don't need this anymore. Let's run this test. And it still passes. Cool. Next is admin

Prevent Redundant Status Changes12:16

So we don't need this anymore. Let's run this test. And it still passes. Cool. Next is adminSetStatus. Don't change status if previous status is the same. Okay. So this has to do with the setStatus functionality for the admin. So for example, if I were to go here, or anyone actually, if I set the status and the status is the same, and especially if we have this notifyAllVoters feature on, then we don't want to update the User because it's the same status. So right now this will work, even though nothing is really happening.

want to update the User because it's the same status. So right now this will work, even though nothing is really happening. Okay. So let's go ahead and fix that. So that would be in setStatus. And right here we can do a check. So let's say if this Idea status_id is equal to this status. So if it's the same status, then go ahead and do nothing. So we can just return here and we can emit the event. So it shows

then go ahead and do nothing. So we can just return here and we can emit the event. So it shows the notification. So let's just copy this. And space that in here. But we want to make it a different event because it's an error. So let's say status was updated error. And let's just say status is the same. Okay. And I'm going to cast this to an int. Or if you want, you can just use ==

Okay. And I'm going to cast this to an int. Or if you want, you can just use double equals here. So I believe we have to listen for this event. Actually, it's at a first in our what was called notificationSuccess. Okay. So we have to add that new one. So let's put it next to this one here. So status was updated and status was updated error. Okay. And I think we have to listen for that in the IdeaShow component.

Okay. And I think we have to listen for that in the IdeaShow component. So if it's here for status was updated and it is, let's also listen for that new event. Okay. Error. And let's duplicate this. Say Error. And I think in the SetStatus component, is there something here that closes it? Yeah, there is. So we have to close it. Let's use Livewire on instead. Same thing.

Yeah, there is. So we have to close it. Let's use Livewire on instead. Same thing. And let's go ahead and duplicate this and say error. Okay. If I did that correctly, this should work. So back here, if the status is the same, we should get that error. Idea status ID not found on component set status. I think I have a typo. Yes, this idea. Sorry. Try that again.

So right here, let's just duplicate this status was updated error. Okay. One more time. Refresh. Same status should be an error. And it is cool. But does it still work if it's a different status? It does. And again, to make sure it still works, let's try setting it to the same status. Okay. But I want this to be an error message instead. And I already did something similar for error messages, but it's not going to work.

this to be an error message instead. And I already did something similar for error messages, but it's not going to work in this case. So if you remember a few episodes ago, we added something here, I believe in the app.blade.php. So, yeah, we have this case where it's an error message, and I'm using flash variables here to determine if it is an error message or a success message. But this case only works for error messages after a redirect. As you see, these ones are redirected. So it has a full page refresh. So in this case, in our show.blade.php,

are redirected. So it has a full page refresh. So in this case, in our show Blade PHP, where is it here? This notification success always exists on this page. So for our notification success, we need to have a piece of state in the Alpine component instead. So let's do that. So let's say isError. Let's put it after isOpen. So this will determine if it's an error message or not. And we can keep this. So the other error message still works when it's a full page refresh.

And we can keep this. So the other error message still works when it's a full page refresh. And we can set isError based on that. So let's say if type equals success, then isError is false. And else if say type equals error, then isError should be true. And it's end if here. Now down here when we are checking which icon to show. So where is it down here? We no longer need to check it.

when we are checking which icon to show. So where is it down here? We no longer need to check it on the php variable, but on the Alpine variable. So we can get rid of this. Okay, get rid of this. But now so this is the success message icon. So let's say x-show equals !isError. Okay. And for the error case, same thing, but obviously isError. Okay.

for the error case, same thing, but obviously is error. Okay. Let's try this out. Let's re-indent this actually. Okay. Let's try this out. Hopefully I did everything correctly. So let's hard refresh. Okay. So this should be an error when I don't change the status here. And it's still green. Did I forget something? Oh yeah. So I forgot to do something here. So now whenever we receive the event here, we have to set

Add Dynamic Titles and Favicon20:52

What else here? Make title dynamic on each page. So right now the title is always laracasts voting. So let's go ahead and make that dynamic. So I want the title to show if we're on the show page. So if we're here, I want this title to show here. So let's do that. So let's go to our layout. app.blade.php. Let's go here and the title is going to be a variable. So let's say $title. But if it's null, we'll just

and the title is going to be a variable. So let's say title. But if it's no, we'll just default it to this. And let's see if this still works. But now in our show blade, we can add a name slot. So let's go to our show.blade.php and we can do x-slot equals title. And we can give it a title here. So let's close that out.

Let's replace the current one. And we can add this to our HTML. So I think we have to add it in two places because we have two layouts. So one is app.blade.php. And let's add it after here. Okay. And I think we also have to add it in guest.blade.php. Let's add it here. Okay. So now we should have a fave icon. And we do not. Oh sorry. Forgot to save it. save.

And we do not. Oh sorry. Forgot to save it. Save. Hard refresh. And there it is. Cool. So the transparency doesn't seem to be working, but I'm not too concerned about that. I'll fix it if it does go to production. So this should work in this page and also the guest page. Why does this not work? Get avatar on null. Okay. So I thought that was within in auth directive, but I guess it's not. So let's fix this. Get avatar. So let's just wrap this in auth.

it's not. So let's fix this. Get avatar. So let's just wrap this in auth. And auth. Okay. Try that again. There we go. And the fave icon does show here as well. Actually, it should be here. Yes, it does. Cool. The title is incorrect here. So let's fix that as well. Let's change this to laracasts voting. Okay. Let's go ahead and make sure everything is still working.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟