What to expect in the next generation of Laravel Forge. Read the blog post
Rewatch this lesson

Showing the feed

Getting Started with Laravel

Showing the feed
Transform your app with proper styling using Blade components. Create reusable UI components and format timestamps to build a polished social media feed.

Alright! Our application is starting to take shape, but let's be honest—it looks pretty basic right now. This is just the start of having our full Chirper application, but let's give it some TLC. We're going to add user avatars, format some timestamps, and use DaisyUI's components to make this look just a little bit nicer.

Let's transform this into something that actually looks like a social media feed!

Step 1: Create a Chirp Component

The first thing I want to tackle is this home.blade.php file. It's great, but it'd be nice if we could get every chirp as its own component. That way we only have one place where we're modifying how chirps are displayed.

Blade components aren't just for layouts—they're perfect for reusable UI pieces like this! Let's create a component for displaying individual chirps:

Create a new file at resources/views/components/chirp.blade.php:

1@props(['chirp'])
2 
3<div class="card bg-base-100 shadow">
4 <div class="card-body">
5 <div class="flex space-x-3">
6 @if($chirp->user)
7 <div class="avatar">
8 <div class="size-10 rounded-full">
9 <img src="<https://avatars.laravel.cloud/>{{ urlencode($chirp->user->email) }}"
10 alt="{{ $chirp->user->name }}'s avatar"
11 class="rounded-full" />
12 </div>
13 </div>
14 @else
15 <div class="avatar placeholder">
16 <div class="size-10 rounded-full">
17 <img src="<https://avatars.laravel.cloud/f61123d5-0b27-434c-a4ae-c653c7fc9ed6?vibe=stealth>"
18 alt="Anonymous User"
19 class="rounded-full" />
20 </div>
21 </div>
22 @endif
23 
24 <div class="min-w-0">
25 <div class="flex items-center gap-1">
26 <span class="text-sm font-semibold">{{ $chirp->user ? $chirp->user->name : 'Anonymous' }}</span>
27 <span class="text-base-content/60">·</span>
28 <span class="text-sm text-base-content/60">{{ $chirp->created_at->diffForHumans() }}</span>
29 </div>
30 
31 <p class="mt-1">
32 {{ $chirp->message }}
33 </p>
34 </div>
35 </div>
36 </div>
37</div>

Let me walk you through what we changed here. This is pretty close to what we had previously, but now we're just making it a little bit cleaner.

Notice a few key things:

  • Avatar magic: If there is a chirp user, we're using avatars.laravel.cloud, which is a free service that generates these neat little gradients for you whenever you need avatars for your application. We're just passing in the user's email to generate them specifically for that user.

  • Anonymous fallback: We have a default avatar for anonymous users too.

  • Props power: Here's the neat thing about Blade components—we can pass in a prop (in this case, a chirp model instance). This prop then allows us to access $chirp->user, $chirp->message, $chirp->created_at, and so on when we use this component in our views.

Note: We're handling both authenticated and anonymous chirps. In lesson 11, we'll add authentication so every chirp has a real user!

Step 2: Update the Feed View

Now that we have our chirp component, let's update home.blade.php to use it. We're still looping through all the chirps like we did before—we're just doing it with our new component instead.

1<x-layout>
2 <x-slot:title>
3 Home Feed
4 </x-slot:title>
5 
6 <div class="max-w-2xl mx-auto">
7 <h1 class="text-3xl font-bold mt-8">Latest Chirps</h1>
8 
9 <div class="space-y-4 mt-8">
10 @forelse ($chirps as $chirp)
11 <x-chirp :chirp="$chirp" />
12 @empty
13 <div class="hero py-12">
14 <div class="hero-content text-center">
15 <div>
16 <svg class="mx-auto h-12 w-12 opacity-30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
17 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
18 </svg>
19 <p class="mt-4 text-base-content/60">No chirps yet. Be the first to chirp!</p>
20 </div>
21 </div>
22 </div>
23 @endforelse
24 </div>
25 </div>
26</x-layout>

Notice that we're passing in the :chirp prop to our <x-chirp> component—that colon indicates it's a prop we can pass into the component. Pretty neat, right?

Step 3: Add Sample Data

Now that we're cruising along, why don't we get some more sample data without having to open php artisan tinker every time we want to create chirps? Laravel gives us an easy way to do this with something called seeders.

Let's create a seeder to generate some sample chirps. Run:

1php artisan make:seeder ChirpSeeder

Now, let's edit database/seeders/ChirpSeeder.php. Seeders are a great way to make sample data so we can make sure our application is looking and feeling and working the way we expect.

We won't get into factories in this particular course, but factories are a great way to make random data. Seeders, on the other hand, are going to be a little bit more specific—they're basically just telling our database to run particular commands. You can think of seeders as an automated way to run php artisan tinker commands, so you don't have to type it all out.

1<?php
2 
3namespace Database\Seeders;
4 
5use App\Models\User;
6use App\Models\Chirp;
7use Illuminate\Database\Seeder;
8 
9class ChirpSeeder extends Seeder
10{
11 public function run(): void
12 {
13 // Create a few sample users if they don't exist
14 $users = User::count() < 3
15 ? collect([
16 User::create([
17 'name' => 'Alice Developer',
18 'email' => '[email protected]',
19 'password' => bcrypt('password'),
20 ]),
21 User::create([
22 'name' => 'Bob Builder',
23 'email' => '[email protected]',
24 'password' => bcrypt('password'),
25 ]),
26 User::create([
27 'name' => 'Charlie Coder',
28 'email' => '[email protected]',
29 'password' => bcrypt('password'),
30 ]),
31 ])
32 : User::take(3)->get();
33 
34 // Sample chirps
35 $chirps = [
36 'Just discovered Laravel - where has this been all my life? 🚀',
37 'Building something cool with Chirper today!',
38 'Laravel\'s Eloquent ORM is pure magic ✨',
39 'Deployed my first app with Laravel Cloud. So smooth!',
40 'Who else is loving Blade components?',
41 'Friday deploys with Laravel? No problem! 😎',
42 ];
43 
44 // Create chirps for random users
45 foreach ($chirps as $message) {
46 $users->random()->chirps()->create([
47 'message' => $message,
48 'created_at' => now()->subMinutes(rand(5, 1440)),
49 ]);
50 }
51 }
52}

These are just some sample chirps in an array, and we're saying if there are fewer than three users (which there currently are in the database), let's go ahead and create some new users with this information. Again, this is exactly what we would do within tinker—this is just making it a little bit easier for us.

For each chirp message, every user is going to get a random chirp based off of this chirps array. Pretty cool, right?

Now let's run the seeder:

1php artisan db:seed --class=ChirpSeeder

Running the seeder command is as simple as that! A database was successfully seeded.

Again, a seeder is just an easier way to have all those tinker commands run for us, but within a way that Laravel expects. In this case, we're just running all that PHP code, but seeding the database with it.

Step 4: Real-time Updates (Preview)

Your feed looks great, but I want to make you aware of something we're not going to touch in this course, but something you might want to look into in the future: keeping this form up to date in real-time.

Right now, you can see that when we post a chirp, it says "0 seconds ago." But if anyone else accesses this page, they won't see new chirps until they actually refresh the page. Laravel has some great options for this, such as WebSockets with something like Laravel Reverb, which can notify all users when a new chirp comes in.

Here's what Laravel offers for real-time features:

  • Laravel Broadcasting - Push updates to browsers in real-time

  • Laravel Echo - JavaScript library for receiving broadcasts

  • Pusher or Laravel Reverb - WebSocket servers for real-time communication

Again, not something we're going to be touching on in this course, but it's helpful to know that those options are out there and might be a great way to build on top of what we're building here with Chirper!

What We've Built

Look at that! Your feed now has:

  • A reusable Blade component for chirps

  • Beautiful user avatars generated specifically for each user based on their email

  • User information and formatted timestamps

  • A polished, professional design with DaisyUI

  • Handles empty states gracefully

  • A clean way of generating sample data with seeders

So we're really moving right along! We now have a reusable Blade component for chirps, a way to generate chirps if we ever need to reset the database and start it up again, and a clean way of showing user information.

But it's still read-only. Next up: since it's still read-only, we're going to let users create their own chirps. Time to make this social network actually social!

00:00
All right.
00:00
Our application is starting to take shape, but it looks pretty basic this
00:05
is the start of having our full Chi application, but let's do a little bit
00:08
of transformation, a little bit of TLC.
00:11
We're gonna add some user avatars, format, some timestamps, and then
00:14
utilize daisy UIs uh, components to make this look just a little bit nicer.
00:20
The first thing is this home blade php is great, but it'd be
00:25
nice if we could get every chirp.
00:27
As its own components.
00:29
That way we can only have one place that we're modifying just
00:33
the chirps that are being shown.
00:35
So in this case, this whole card right here,
00:38
again, we can create components within the components directory.
00:42
I'm going to create a new file that says chirp dot blade dot php.
00:47
So let me go ahead and paste in this chirp component.
00:50
And we'll talk through some of the things that we changed.
00:52
So here's pretty close to what we had previously, but now we're just
00:56
making it a little bit cleaner.
00:58
Now if there is a chirp user, we're going to use this avatars, Laravel Cloud,
01:02
which is a free service to have these neat little gradients for you whenever
01:05
you're needing these avatars that we're having for our application.
01:08
We're just passing in the user email to generate them specifically for that user.
01:13
And then we have a default one for anonymous users.
01:16
Now, here's the neat thing.
01:16
With blade components, we can pass in a prop, in this case, an array of
01:21
chirps, or in this case a chirp model, a chirp instance of an eloquent model.
01:26
And this prop then allows us to access the chirp user or chirp user name or things
01:32
like a chirp created at or chirp message when we use this component in our view.
01:36
And that's what we're gonna do in our home view.
01:38
So in our home view, we're going to, uh, we can clear this out, but
01:42
I might just replace everything.
01:45
And lemme paste this in.
01:46
And so here we still have an empty state.
01:48
We changed that up a little bit to make the styles look a little nicer, but we
01:52
are passing in a new component that X chirp component that we just created.
01:56
We're passing in the prop, and in this case, that's what a colon indicates.
02:00
It's a prop that we can pass into the component of the chirp.
02:04
So we're still looping through all the chirps like we used to before.
02:08
We're just looping through it in the instance of a component.
02:11
Let's see what this looks like in our homepage.
02:13
Great.
02:13
I cleared out some components and so we just have anonymous
02:16
components for it right now, but this is looking pretty good.
02:19
So now that we're cruising along, why don't we get some more sample data
02:23
without having to open PHP Artisan Tinker Every time we want to do
02:27
that, Laravel gives us an easy way to do this with something called cs.
02:32
If we search for CR in our application, we have this database CER file.
02:36
And you can see here we have a user factory already created which this just
02:42
means that a new user can be created if we run a CDR within our database.
02:48
Cs are a great way to make sample data that we can then just make sure
02:52
our application is looking and feeling and working the way we would expect.
02:57
We can create a cedar, you guessed it, with the PHP artisan commands.
03:00
I'm gonna say PH.
03:01
P Artisan make cedar.
03:03
And we're gonna call this chirp cedar.
03:06
We won't get into factories in this particular course, but factories
03:09
are a great way to make random data.
03:12
Where within Cedars it's going to be a little bit more specific this is
03:16
basically just telling our database, let's run a particular command.
03:19
Let's do some things within models or eloquent as we're populating the database.
03:25
You can think of Cedars as an automated way to run PHB Artisan Tinker commands,
03:30
so you don't have to type it all out.
03:32
I am going to paste this in here.
03:34
And so these are just some sample chirps, an array of chirps, and we're
03:37
just saying if there are less than three users, which currently there are in
03:41
the database, let's go ahead and create some new users with this information.
03:45
Again, this is exactly what we would do within Tinker.
03:48
This is just making it a little bit easier for us if we wanted to, uh, ever
03:53
create multiple versions of this data.
03:56
For each chirps as message, every user is going to get a random chirps
04:01
based off of this chirps array,
04:04
And so running the Cedar Command is as simple as saying, PHP,
04:07
artisan DB, C, we're gonna pass in the class of the chirp cedar.
04:11
And a database was successfully seeded.
04:13
Again, A CDR is just an easier way to have all those tinker commands, uh, run for us,
04:20
but within, in a way that Laravel expects.
04:22
So in this case, we're just running all that PHP code, but
04:25
seeding the database with it.
04:27
Again, we're not getting into factories, which is the actual creation
04:31
of randomized data that you might have seen in that user factory file,
04:35
but that's for a different course.
04:37
So if we were to take a look.
04:38
Oops, this looks good.
04:40
But it looks like we have a CSS issue with a little bit extra spacing
04:43
now that we seated that database.
04:45
Yeah, I think it's because we have these P tags, which are adding some extra,
04:50
uh, block classing that we don't need.
04:52
I'm just going to replace them with span classes and a gap of one.
04:56
There we go.
04:57
That's what we want.
04:58
So now we have a reusable blade component for chirps.
05:00
We have a way to generate chirps if we ever needed to, uh, kill this
05:05
database and start it up again.
05:07
And then we have a clean way of showing user information as well
05:11
as generating a specific avatar for that user based on that user's email.
05:16
So we're moving right along.
05:18
Next up, since it's still read only, we're gonna let users create their own chirps.
05:21
So let's actually make this social network thing social.