How I built my new blog
Today, I ’d like to write about building this blog. I could use a Haxo or Hugo, or any other platform that exists, however I ended up writing my own static site generator in golang.
For my blog generator I used the core ideas of Mario Zupan’s blog generator and altered it to fit my needs.
Zupzup explains clearly the concepts of a static blog generator, so go here and read his blog post and I’ll continue from where he stopped.
1. Use a configuration file.
Even though his implementation is solid, changing variables in the code in order to produce a different blog and then compiling the project again wasn’t efficient for me.
Additionaly, because I change blog posts on my computer and then push them to git I’ve implemented a local variation of datasource so I can use that local folder instead of a git repository.
switch config.SiteInfo.DataSource.Type {
case "git":
ds := datasource.NewGitDataSource()
_, err = ds.Fetch(config.SiteInfo.DataSource.Repository,
config.SiteInfo.TempFolder)
case "local":
ds := datasource.NewLocalDataSource()
_, err = ds.Fetch(config.SiteInfo.DataSource.Repository,
config.SiteInfo.TempFolder)
case "":
log.Fatal("please provide a datasource in the configuration file")
}
The configuration file looks like this:
{
"Author": "Romanos Trechlis",
"BlogURL": "romanostrechlis.github.io",
"BlogLanguage": "en-us",
"BlogDescription": "Desc",
"DateFormat": "2006-01-02 15:04:05",
"ThemePath": "./static/",
"BlogTitle": "RTB",
"NumPostsFrontPage": 10,
"DataSource": {
"Type": "git",
"Repository": "https://github.com/RomanosTrechlis/blog.git"
},
"TempFolder": "./tmp",
"DestFolder": "./public"
}
The DataSource Type can also be local and the Repository can be a folder
{
"Type": "local",
"Repository": "C:/Users/Romanos/Desktop/testLocal/blog/"
}
2. Use of cli to break functionality
Another issue I had was that I wish to download the blog content once and then generate the site multiple times with different templates.
I also wish to see what my blog would look like before I push it.
In order to achieve that I used flags to broke the functionality to distinct steps. So, if I want to generate, download and see the results I will run the command:
site-generator -fetch -generate -run
This will download my content, generate the site and run a local server.
3. Paging
Zupzup shows a fixed number of blog posts on the frontpage and uses archive to show all his blog posts.
For my blog I wished to show a fixed number of posts and give the visitor the ability to navigate to the next page with the next fixed number of blog posts.
I did that using the following code:
// frontpage
paging := config.SiteInfo.NumPostsFrontPage
numOfPages := getNumberOfPages(posts)
for i := 0; i < numOfPages; i++ {
to := destination
if i != 0 {
to = fmt.Sprintf("%s/%d", destination, i+1)
}
toP := (i + 1) * paging
if (i + 1) == numOfPages {
toP = len(posts)
}
generators = append(generators, &ListingGenerator{&ListingConfig{
Posts: posts[i*paging : toP],
Template: t,
Destination: to,
PageTitle: "",
PageNum: i + 1,
MaxPageNum: numOfPages,
}})
}
That loop appends a new generator for every 10 post (the number of posts per page is given in the configuration file).
Additionally, in the html template:
<div id="paging">
{{if ne .PageNum 0}}
{{ if ne .PrevPageNum 0}}
<a href="/{{if ne .PrevPageNum 1}}{{.PrevPageNum}}/{{end}}">
<!-- Less Than icon by Icons8 -->
<img style="vertical-align:middle"
class="icon icons8-Less-Than"
width="30" height="30">
</a>
{{end}}
<span><strong>{{.PageNum}}</strong></span>
{{ if ne .NextPageNum 0 }}
<a href="/{{.NextPageNum}}/">
<!-- More Than icon by Icons8 -->
<img style="vertical-align:middle"
class="icon icons8-More-Than"
width="30" height="30">
</a>
{{end}}
{{end}}
</div>
This code creates numbered folders that contain a new page with the next fixed amount of blog posts.
4. Share buttons
I also like share buttons to my blog posts. So, here is the template code:
{{if .IsPost}}
<div id="share-buttons">
<div class="share-button share-text">
<span>Share</span>
</div>
<div class="share-button share-button-facebook"
data-share-url="{{.URL}}">
<div class="box">
<a href="https://www.facebook.com/sharer/sharer.php
?u={{.URL}}">
<!-- Facebook icon by Icons8 -->
<img class="icon icons8-Facebook"
width="48" height="48" >
</a>
</div>
</div>
<div class="share-button share-button-twitter"
data-share-url="{{.URL}}">
<div class="box">
<a href="http://twitter.com/intent/tweet
?source=sharethiscom
&text={{.PageTitle}}
&url={{.URL}}&via=r_trechlis">
<!-- Twitter icon by Icons8 -->
<img class="icon icons8-Twitter"
width="48" height="48" >
</a>
</div>
</div>
<div class="share-button share-button-gplus"
data-share-url="{{.URL}}">
<div class="box">
<a href="https://plus.google.com/share?url={{.URL}}">
<!-- Google Plus icon by Icons8 -->
<img class="icon icons8-Google-Plus"
width="48" height="48" >
</a>
</div>
</div>
</div>
{{end}}
IsPost is a boolean and URL the blog’s url.
5. Future functionality: Upload
I also would like to automatically upload the generated blog to github.
For that end I defined the Endpoint interface:
type Endpoint interface {
Upload(to string) error
}
Get the full code here