.            ★.        . blessfrey.me ..          ☆        .

The Making of Blessfrey.me in BottlePy

Welcome to Blessfrey.me, my webdev playground written in BottlePy! Twice a month, God willing, I post my projects and personal reflections. Originally in PHP, Blessfrey.me now thrives on Bottle Python web framework. To celebrate my website, I'll share some of my front end and back end code, as well as the evolution of my design philosophy.

Why not use a premade blogging platform like WordPress?

Generalized blogging platforms are overkill, as Blessfrey.me is mostly a few static pages and a blog. Unused features bog down the website and pose potential security vulnerabilities. And prominent blogging platforms like WordPress are flooded with features.

There's also blogging platforms like Medium or Wattpad, which throw you into giant established communities and probably give you better chances of ending up on the front page of Google. There's something dreamy about having your own corner of the internet that is unabashedly you, though. No risk of losing everything due to some policy change or business restructuring. I'm not lost in the droves of social media nor pressured to follow their trends and positioning tactics.

I just do what my friends and I think is cool, and maybe some people will stumble in through an old profile link or obscure keywords on a search engine and find this odd stash of personal projects and diaries. That's how the internet was in the 90s and into the 00s, and I'm really nostalgic for that mode of life. Even if it never amounted to fame or fortune, it was full of personality and discovery. I always daydreamed about having my own corner of the internet and what I could share on there.

But anyway, Blessfrey.me is a programming portfolio, so it just seems obvious to write my own frontend and backend. Taking my website from initial sketches, to Hello World, to various prototypes, to something polished enough to show my friends has been a valuable chance to learn. It's probably just as valuable if not more to demonstrate working knowledge of WordPress, Bootstrap, or other popular webdev utilities since that's what clients crave, so obviously figure out what best suits you!

Why Bottle?

Blessfrey.me was originally written in PHP. Designing the diary underscored how prohibitively repetitive raw HTML code is. It is not merely annoying; it's completely not scalable when managing years' worth of diary entries. HTML templates are a must for decoupling diary entries from the codebase and allowing for graphical redesigns.

While searching for a templating engine, I stumbled upon Bottle's SimpleTemple. Bottle not only comes with SimpleTemplate out of the box, but it also provides a lightweight and less verbose alternative to PHP. PHP may hold a place in my heart as the lingua franca of old petsites, but frankly, Python is more enjoyable to use.

How does Blessfrey.me work behind the scenes?

The strength of SimpleTemplate in building a dynamic page without all that repetitive HTML

Blessfrey.me's pages aren't a static collection of HTML pages hosted on my server but are dynamically constructed by a Bottle script upon request.

Bottle's templating engine receives content from Bottle in the form of a dictionary and populates the given template. SimpleTemplate also allows Python code to be written directly onto the template, which is how Blessfrey.me displays random styles of bullets with each refresh, populates galleries and diary snippets, and calculates the required number of pages needed for the diary's navigation links.

To stay consistent without copy-pasted code, every page is based upon the frame template below. Nested templates can be inserted into other templates through {{!base}} to create increasingly specific templates. (By the way, double curly brackets denote variables, and exclamation marks disable escaping.)


<!DOCTYPE html> 
<html lang="en"> 
 
<head> 
% include('header.tpl')https://wiki.blessfrey.me/view/Blessfrey
</head> 
 
<body> 
 
<div class="grid"> 
 
% include('logo-bar.tpl')
 
% include('nav.tpl')
 
    <div class="body-row"> </div> 
 
{{!base}}
 
</div>
 
% include('footer.tpl')
 
</body>
 
</html>

There are a few variables in the header template below (incorporated into the main template at % include('header.tpl')). If Bottle doesn't provide a title, it defaults to 'blessfrey.me.' SimpleTemplate also allows for seamless integration of variables into paths and URLs, such as for Blessfrey.me's stylesheet links.


<title>{{title or 'blessfrey.me'}}</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="/static/css/{{css}}.css"/>

Maybe I could feasibly copy-and-paste the header onto a couple of static pages, but the diary has an ever-expanding backlog of entries and demands a more scalable solution. SimpleTemplate allows Python code to mingle with HTML on the same template and programmatically adjust to an variable amount of content. Below is an excerpt of the diary's template that shows how Blessfrey.me builds its previews using a for loop.

Not shown is the template's first line % rebase('frame.tpl'), which tells the templating engine to insert this block of content at the {{!base}} variable in the main template.

The limit (max number of snippets per page) is provided by Bottle script. The snippetsvariable is a list of lists. It contains all diary snippets, which are themselves packaged as a list containing the title, content, timestamp, and so on. By iterating over snippets, any information about the article can be pulled out as needed for the HTML.


    <div class="diary-pages">
        % for s in snippets[page * limit:page * limit + limit]:
            <div class="snippet">
                <div class="snippet-title">
                    <a href={{s[3]}} rel="nofollow"><h1>{{!s[0]}}</h1></a>
                </div>
                <div class="snippet-content">
                    {{!s[1]}}
                </div>
                <div class="snippet-info">
                    <b>{{!s[2]}} 
                    • <a class="social-link social-twitter" 
                        href='http://twitter.com/share?text={{s[4]}}
                        &url=https://blessfrey.me{{s[3]}}&via=lilchimchooree' 
                        target="_blank">tweet</a> 
                    • <a class="social-link social-fb" 
                        href='http://www.facebook.com/share.php?u={{s[3]}}'>
                            facebook</a> 
                    % message = "Hey,+check+out+this+post:+" + s[1] + ".,+" + s[3]
                    % message = message.replace('+','\+')
                    % message = re.sub('\s+?','+', message)
                    % message = message.replace('\\','')
                    % message = re.sub('<.*?>','', message)
                    • <a class="social-link social-email" 
                        href='mailto:?body={{message}}'>email</a></b>
                </div>
                <div class="snippet-link">
                    <a href={{s[3]}} rel="nofollow"><b>read more</b></a>
                </div>
            </div>
        % end
    </div>
The page number comes from the Bottle script shown in the next section and is derived from the URL.

What does Bottle look like on the backend?

Bottle takes URLs and generates the corresponding web page upon request. Each URL is coupled with a method, which returns a template and a dictionary of data to be used by SimpleTemplate. Since Bottle is a Python framework, it provides access to all the Python libraries out there.

By the way, the page is ensured to be an int by a line of assert isinstance(variable, datatyle).


# Start on first Diary page if no page given
@route('/diary')
def diary():
    return diary(0)
 
# Diary Page - Diary Template - list all articles
@route('/diary/<page:int>')
def diary(page):
    """diary"""
    loc = 'diary/entries/'
    assert isinstance(page, int)
    info = {'css': 'diary', 'title': 'chimchooree\'s diary', 'year': find_year(), 
        'snippets': list_snippets(gather_and_sort(loc), loc), 
        'latest': list_headlines(gather_and_sort(loc)[0:5], loc), 
        'tags': fill_word_cloud(curate_files(gather_files(loc)), loc), 
        'total': len(curate_files(gather_files(loc))), 'limit': 8, 'cluster': 3, 
        'page': page, 'category': "diary"
    }
    return template('diary.tpl', info)

This is how the methods for specific routes are structured. Every time you visit Blessfrey.me/diary, one of the above methods is called, depending on whether any query parameters follow the URL. To collect all the data the template will need, it calls a medley of Python functions to access my folder of diary entries, convert them into previews for the snippets section and headlines for the sidebar, and count the total number of entries.

The styling is nothing fancy, just CSS

The website is styled using CSS, heavily relying on the CSS Grid and a bit of Flexbox. CSS Grids can be used inside CSS Grids, so my pages are generally blocked out, with smaller internal grids managing specific content.

(image: CSS Grid traced over screenshot of projects page.)

My 2021 design with the RPG skillbar nav pane...cute.

The projects page (predates the current games page) is an example of nested grids. Almost every page uses the yellow general layout. The content unique to the projects page is mapped out in green, with a section for the header, featured projects, and other projects. The other projects use a 2-column grid in blue to evenly space out all the little thumbnails.

Some CSS code for project's general grid and the nested 'more' grid are shown below. This code is very outdated, but you can always find my current stylesheets by right-clicking and choosing your browser's equivalent of "View Page Source" and examine the structure of my grids with the Inspector.


.grid {
    display: grid;
    grid-template-columns: auto 800px auto;
    grid-template-rows: 25px 90px repeat(2, auto);
    grid-column-gap: 0px;
    grid-row-gap: 0px;
}
 
.featured {
    grid-area: 2 / 1 / 3 / 3;
}

.featured-desc {
    color: #F9B3D7;
    font-size: 25px;
    text-align: right;
    margin-right: 10px;
}

.more {
    grid-area: 3 / 1 / 4 / 3;
    width: 800px;
    display: grid;
    grid-template-columns: auto auto;
}

.more-desc {
    color: #F9B3D7;
    font-size: 18px;
    text-align: center;
    margin-right: 10px;
}

Of course, design is its own beast you'll have to figure out on your own.

As I've attempted to emulate my favorite odd blogs and coding experiments from the 90s and 00s, Blessfrey.me has used HTML, CSS, PHP, BottlePy, SimpleTemplate, Apache, NGINX, Jenkins, Ansible, my husband's LazyWiki, and maybe other stuff, who knows? I think following a dream like that is a fun way to learn more than following a stuffy textbook or sticking to rigid website makers. After all, the more personal your requirements, the more likely you'll have to figure it out on your own.

I think a dream also leads you to explore all those existential questions like "What is even the point of having a website?" The evolution of the overall design and content mix reflects that journey. I began by taking heavy inspiration from iconic promotional Japanese websites for Playstation and PSP otome games. (All are now broken with the loss of Adobe Flash Player.) It looked cool, but what's the point when I had no playable game for Blessfrey? Over time, I slowly adjusted to what actually suited my Godot RPG dream project, Blessfrey.

As I actually used my website, I yearned to include a broader range of content. It took years to shake out all my preconceived notions of what makes a cool website and all the boring, samey advice shared by online husslers. A laser-tight focus might work for businesses, but it's lame to narrow your personal showcase into a niche. I much prefer having a cute, comfy little site that accomodates anything I might make.

For example, the most random thing I've integrated is my Bible study notes wiki. Someone at church was unable to take a class that I had attended and wished to see my notes. My notes are comprehensive but unfortunately were completely inaccessible without setting up my family's private wiki software on a Linux computer and controlling it with the terminal. With a few changes, though, everyone can see my notes at Blessfrey.me's wiki! It's convenient to be able to access it on my phone and adds some value for other people, so why omit it?

It's pivots like that that let me get all the mileage out of my server rent and really fall in love with webdev. It took about 4 years of janky CSS and meandering purpose, but Blessfrey.me is finally something I proudly show to other people. :)

Now you know how to make your own website!

Or you can keep using blogging platforms or social media or whatever works for you. But at least admit it's cute to build your own playground! If you really decide to, be easy on yourself and open-minded while exploring webdev. Your site won't be perfect at first, but be honest about your needs and dreams, and you'll get there! See ya.

Last updated March 1, 2024