Series: Building a Social Network with Flask & Stream – Part 10

This segment is the tenth installment of a tutorial series focused on how to create a full-stack application using Flask and Stream. In this article, we are going to start styling our app and adding cool new features like notification counts and link previews. Be sure to check out the Github repo to follow along!

Getting Started

As of our previous tutorial, we have built all of the basic functionality of our site. Our last issue to resolve is that the app lacks any kind of aesthetic appeal. Currently, any links that a user might add do not have any visual flare- the feeds definitely won't be winning any UI design awards. One thing that would drastically improve the look of our site would be to add link previews, similar to Facebook, Twitter, or Pinterest. Also, being able to auto-populate the title and description fields for the user after they enter a link would make for a much better user experience.

Pre-Previews

Luckily, Stream provides a very convenient, asynchronous JavaScript function that takes a URL and returns all of the information that we need using Open Graph. Open Graph protocol returns titles, descriptions, images, and videos from a link. We already have the description and title, so the only thing left to add is images. Feel free (even encouraged!) to add a conditional into your app to allow videos to display instead of images if they are available.

However, before we can start integrating this functionality, we need to make space for it in our web app. The first step is adding images to our database model, as well as providing a way to update our Stream Feeds for new fields (in app/models.py).

https://gist.github.com/Porter97/39801fd94955ba0508edbf2f5c6ee8b4

Hindsight Is 20/20

Before we can start adding new content, any links to existing content do not have images associated with them yet. When we start using images in our feeds, some of them will display with images, and others will have a large, ugly “None” text showing instead. Therefore, we need a solution that allows us to update each image in the database as well as our Stream feeds. Since we are using Open Graph on the front end, the backend script should use the same thing. To do so, we will use the Python-OpenGraph library. To install it, run pip install python-opengraph. Then (in application.py) we will create a CLI script that returns all content entries in the database, queries their Open Graph values, returning and updating their image values for the table and Stream.

https://gist.github.com/Porter97/60ec782a1967183f73eb8fc1b7e5dd92

Again, we have altered our database model, so be sure to run flask db migrate, flask db upgrade, as well as the newly created flask update-images. The command line does not recognize underscores, so replace the underscore(_) with a dash(-) when running the command.

Picture Perfect

Now that everything is up to date, we can start to change our forms, views, and templates for the new field. We begin with the templates (in app/templates/_content.html).

https://gist.github.com/Porter97/a87c4b58cc377ed026296fff6b9ca0f2

Next, we need to adjust our index page for the home timeline to retrieve and render the content through the Stream request (in app/templates/index.html).

https://gist.github.com/Porter97/a16bcf7449853ffedf22031154daac8f

Finally, we do the same for the collection page (in app/templates/collection.html).

https://gist.github.com/Porter97/59fe63f2e1e437538c8a1c829d69667c

See It To Believe It

We want to give users the chance to see their content before they post it to a collection by creating a link preview in the new content screen. The preview needs to have a few bits of functionality. First, we want it to show and return the image, but we don’t want the image field itself to show. Second, we want the preview to reflect the on-screen input fields for title and description. We start this process off with our forms (in app/main/forms.py`)

https://gist.github.com/Porter97/da3a635b8309d4d2f82b0a74f7571b41

I added ID parameters to each of the fields in the form, which help us select them using jQuery in the template. I also created the image field as a hidden field so that it won’t show to the user.

We also need to update our new content view to return a token for the user (for the Stream function) as well as to provide the ability to use the new image field in creating a record from the form (in app/main/views.py).

https://gist.github.com/Porter97/7ad68ef939ff20d3a2b03868ceb60eb6

Since the preview does not need nor have some of the information provided by the full content template, we need to create a new one (in app/templates/_content_preview.html).

https://gist.github.com/Porter97/4cae49002995588d4a757de51128a20a

The Stream Open Graph scraper works in a very similar way to the requests we have been doing for a while, so it is a straightforward crossover for our existing JavaScript code (in app/templates/new_content.html).

https://gist.github.com/Porter97/35d65404069a2d6b910a42716dfded82

The input string variables at the top provide regex for two things. The first is for ‘dirty’ URLs, or when a link is surrounded by unrelated text, and the second identifies a ‘clean’ URL, one that does not have any surrounding text.

This page includes the addition of the onkeyup and onkeypress methods at the bottom which trigger an update to the preview at the top when the input fields are changed. Also, we use jQuery to set values for the form when the preview function is run, so import it in app\templates\base.html.

https://gist.github.com/Porter97/97f67cb8f5f57f65761781b41e05589d

The last thing we have to do is update the content page itself to include the image (in app/templates/content.html).

https://gist.github.com/Porter97/49b05d0d495b17d4ae7821e8c12cfef4

Notify Me

Even though we have a notifications feed running, it does not provide the notification-count that you would expect to see from a modern social media platform. Luckily, we can put this together in a snap. Since the notification-count displays in the navbar, we need to create a badge (like our follower-count) that visibly shows the count of unseen notifications (in app/templates/base.html).

https://gist.github.com/Porter97/f6ffcb9f49479f65b333acbff5e09450

Since the navbar returns on every page, we need to provide a current user ID # to the Stream request to get the count. While I am going to pass through the current user token on every rendered template, you could just as easily modify the code to use cookies instead.

https://gist.github.com/Porter97/347c00c30755da25e9395b34dc223e00

Finally, we want the count to return to zero once a user opens the notification page, as that would indicate they have, in fact, seen the notifications. This step requires a very simple tweak to accomplish (in app/templates/notifications.html).

https://gist.github.com/Porter97/f8e6104f9d93834a54b96adbbf426139

Gotta Have Style

We are getting close to the end now! The last thing that we need to tackle is some simple CSS changes to polish the look of the site. First, let's take a look at changing the font. I personally prefer to stick to one or two fonts at an absolute maximum, as font-weight, style, and decoration can provide all of the variation you actually need. In the case of this demo, I chose Montserrat from Google Fonts, but feel free to play around and find what works best for you. We can import the font in app/templates/base.html.

https://gist.github.com/Porter97/9642bc3efe4777ba3215647816d27856

Additionally, we have text notifying a user that they have reached the end of a feed. It would look cleaner and clearer if we replaced the text to use an image instead. We will have to update this in all of the templates that use feeds, starting with the home page (in app/templates/index.html).

https://gist.github.com/Porter97/8fc227530c88ef2f56c7667897895253

Then notifications (in `app/templates/notifications.html)

https://gist.github.com/Porter97/aff7d1cde1e443aaf00fd34757f85305

Next, the user page (in app/templates/user.html)

https://gist.github.com/Porter97/839dbb5fb1672c75fef7b8059754a374

And finally, the collection page (in app/templates/collection.html)

https://gist.github.com/Porter97/fb6e6229e0592e11d9372b743ffb1e4a

Profiling

As you can see, our user page has some slight stylistic issues, particularly with the username and user’s name being displayed right beside each other. This appears redundant, so it would help if only one of these elements were displayed, preferably their actual name. Additionally, we need to add some tags to the page to add styles (in app/templates/user.html).

https://gist.github.com/Porter97/d5579de6184bae95db576f7506dc3f99

Final Touches

Now, all we have to do is put together our CSS for the page, and we are done!

We’start off by creating the CSS document and defining our element level references (in app/static/styles.css).

https://gist.github.com/Porter97/ad8f7509031f1d9ee5e620af69877507

Next, we set a maximum width on our content container to limit the size of the pictures and nicely center the content (in app/static/styles.css).

https://gist.github.com/Porter97/18e3a058ceee09ecedd94bc8f449d39d

After that step, we give some visual flair to the content elements, specifically the image. Creating an animated shadow for the image will add a nice-looking effect. Varying the font sizes and weights (but don’t go too crazy!) also helps to break up the text and allows the user to focus on different sections independently (in app/static/styles.css).

https://gist.github.com/Porter97/fc8261a9f030db4bd1a935f791b13bcc

In continuation, we focus on the page headers, our profile, and content pages, centering the text and putting emphasis on the user’s name (in app/static/styles.css).

https://gist.github.com/Porter97/c44ca55705edbdb9bd142d2425de1a9d

The notifications-count has a rather bland gray background, which undercuts its importance. A sleek-looking gradient effect can make it appear a lot more interesting (in app/static/styles.css).

https://gist.github.com/Porter97/7d3a70acec714d74d2f961156150a5c8

Last but not least, we need to center and size the “finished” image we integrated this week (in app/static/styles.css).

https://gist.github.com/Porter97/5aa6d7b96b8104a7e181e1261499f5b6

Final Thoughts

Congratulations!

You have officially created an entire web application with Flask and Stream, complete with styling and some rather slick functionality. The response times for our content is seamless thanks to lightning-quick data retrieval from Stream, with a modern, feed-based view to check out all the latest and greatest activities from your friends. We are getting very close to the end of this section of the tutorial, with our last step being deployment and configuration. In the next article, I am going to take you through deploying the entire app as a serverless function using AWS Lambda, RDS, and Amazon Mail!

As always, thanks for reading and happy coding!

Note: The next post in this series can be found here

Tutorials

Feeds