Skip to content

greghendershott/frog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Frog

Happy Green frog

+ -> +

Frog image by @Goug8888, used under Creative Commons license Attribution-NonCommercial-ShareAlike 2.0 Generic

Overview

Frog is a static web site generator written in Racket.

You write content in Markdown. You generate files. To deploy, you push them to a GitHub Pages repo (or copy them to Amazon S3, or whatever).

Posts get a variety of automatic blog features.

You can also create non-post pages.

The generated site uses Bootstrap, which is responsive, automatically adapting to various screen sizes.

Yes, it's very much like Octopress and others. But Frog doesn't require installing Ruby. Installing Racket is typically waaaay simpler and faster.

The only non-Racket part is optionally using Pygments to do syntax highlighting.

Q: "Frog"? A: Frozen blog.

Note: This has been tested on Mac OS/X and Ubuntu; I'm using it for my blog. CAVEAT: It has not yet been tested on Windows--it's likely that the path handling isn't exactly right.

Quick Start

Installing Frog

Install Racket 5.3.4 or newer.

Install Frog:

$ raco pkg install frog

Frog depends on two other Racket projects:

  1. #lang rackjure

  2. Racket Markdown parser

The raco pkg install frog should have asked to install them. If you need to install them individually, use raco pkg install rackjure and raco pkg install markdown.

Install Pygments (optional, if you want syntax highlighting for fenced code blocks). On OS X and Linux:

$ sudo easy_install Pygments

On Linux you might first need to install easy_install:

$ sudo apt-get install python-setuptools

Starting a new blog project

Creating a new blog project is 3 easy steps:

# 1. Create a subdir
$ mkdir frog-project

# 2. Go there
$ cd frog-project

# 3. Tell Frog to create default files and dirs
$ raco frog --init
Configuration /tmp/frog-project/.frogrc not found; using defaults.
Creating files in /tmp/frog-project/:
/tmp/frog-project/.frogrc
/tmp/frog-project/_src/About.md
/tmp/frog-project/_src/page-template.html
/tmp/frog-project/_src/post-template.html
/tmp/frog-project/_src/posts/2012-01-01-a-2012-blog-post.md
/tmp/frog-project/css/
/tmp/frog-project/js/
/tmp/frog-project/img/
Project ready. Try `raco frog -bp` to build and preview.

You can go ahead and build/preview this to get a feel for the default starting point:

# Build and preview it
$ raco frog -bp
Using configuration /tmp/frog-project/.frogrc
13:28 Done generating files
Your Web application is running at http://localhost:3000/.
Stop this program at any time to terminate the Web Server.
# The home page should launch in your web browser.
# Switch back to the command prompt and type C-c to quit:
^C
Web Server stopped.

Project file tree

Here is the file tree that raco frog --init creates for you and Frog expects:

project/
  # Files provided by you:
  .frogrc       # see next section of README for details
  _src/
    page-template.html  # lets you define the page layout
    post-template.html  # lets you define the <article> layout
    posts/
      # You'll create these using `raco frog -n <post-title>`
      2013-01-01-a-blog-post.md
      2013-02-15-another-blog-post.md
      ...
    # Zero or more other .md files for non-post pages.
    # May be in subdirs.
  css/
    bootstrap.css                #\
    bootstrap.min.css            # get these files
    bootstrap-responsive.css     # from Bootstrap
    bootstrap-responsive.min.css #/
    pygments.css                 # used to style code elements from Pygments
    custom.css                   # other styles you provide; may be empty
  js/
    bootstrap.js                 # get these files
    bootstrap.min.js             # from Bootstrap
  img/
    feed.png
  favicon.ico

  # Files generated by Frog.
  # (Just shown FYI, you don't create these manually)
  index.html
  sitemap.txt
  tags/
  feeds/
  # Post pages in subdirs.
  # Exact layout depends on `permalink` in `.frogrc`.
  blog/
    2013/
      01/
        a-blog-post-title/
          index.html
        ...
    2013/
      02/
        another-blog-post-title/
          index.html
        ...
  ...

TIP: The official Bootstrap files are at http://twitter.github.io/bootstrap/. For alternative "themes", see http://http://bootswatch.com/.

TIP: For examples of files you can use and rename to pygments.css, see https://github.com/richleland/pygments-css.

Per-project configuration: .frogrc

raco frog --init creates a .frogrc file in your project directory:

# Required: Should NOT end in trailing slash.
scheme/host = http://www.example.com

title = My Awesome Blog
author = The Unknown Author

# Whether to show the count of posts next to each tag in sidebar
show-tag-counts? = false

# Pattern for blog post permalinks
# Optional: Default is "/{year}/{month}/{title}.html".
# Here's an example of the Jekyll "pretty" style:
permalink = /blog/{year}/{month}/{day}/{title}/index.html
# There is also {filename}, which is the `this-part` portion of
# your post's YYYY-MM-DD-this-part.md file name. This is in case
# you don't like Frog's encoding of your post title and want to
# specify it exactly yourself, e.g. to match a previous blog URI.

# Should index page items contain full posts -- more than just the
# portion above "the jump" <!-- more --> marker (if any)?
index-full? = true

# Should feed items contain full posts -- more than just the portion
# above "the jump" <!-- more --> marker (if any)?
feed-full? = true

# How many items to include on index pages?
max-index-items = 20

# How many items to include in feeds?
max-feed-items = 20

# Decorate feed URIs with Google Analytics query parameters like
# utm_source ?
decorate-feed-uris? = true

# Insert in each feed item an image bug whose URI is decorated with
# Google Analytics query parameters like utm_source ?
feed-image-bugs? = true

Creating blog posts

A typical workflow:

  1. Create a new post with raco frog -n "My Post Title". The name of the new .md file is displayed to stdout.

  2. Edit the .md file in your preferred plain text editor.

  3. Regenerate your site and preview it with raco frog -bp. (You might repeat steps 2 and 3 a few times until you're satisfied.)

  4. Deploy. If you're using GitHub Pages, you can commit and push to deploy to your real site. If you're using some other method, you can copy or rsync the files to your static file server.

TIP: If you use Emacs, try markdown-mode. Although Markdown is really simple, markdown-mode makes it even more enjoyable.

More details

Posts

You create new posts in _src/posts. They should be named YYYY-MM-DD-TITLE.md and need to have some meta-data in the first few lines.

You can do raco frog -n "My Title" to create such a file easily. This will also fill in the required meta-data section. The markdown file starts with a code block (indented 4 spaces) that must contain these three lines:

    Title: A blog post
    Date: 2012-01-01T00:00:00
    Tags: foo, bar, tag with spaces, baz

Everything from here to the end is your post's contents.

If you put `<--! more -->` on a line, that is the "above-the-fold"
marker. Contents above the line are the "summary" for index pages and
Atom feeds.

<!-- more -->

Contents below `<!-- more -->` are omitted from index pages and Atom
feeds. A "Continue reading..." link is provided instead.

Title can be anything.

Date must be an ISO-8601 datetime string: yyyy-mm-ddThr:mn:sc.

Tags are optional (although you have to include the Tags: part).

The tag DRAFT (all uppercase) causes the post .html file not to be generated.

Automatic post features

Posts are automatically included in various index pages and feeds.

Posts with any tag go on the home page /index.html, in an Atom feed /feeds/all.atom.xml, and in an RSS feed /feeds/all.rss.xml.

Posts for each tag go on an index page /tags/<tag>.html, in an Atom feed /feeds/<tag>.atom.xml, and in an RSS feed /feeds/<tag>.rss.xml.

The default template post-template.html provides:

  • Twitter and Google+ sharing buttons.
  • Disqus comments.

The default template page-template.html (used for all pages, not just post pages) also provides:

  • Twitter follow button.
  • Google Analytics tracking.

Non-post pages

You can put other .md files in _src, and in subdirs of it (other than _src/posts). They will be converted to HTML pages. For example, _src/About.md will be /About.html in the site.

NOTE: Non-post pages are not included in any automatically generated index pages or feeds. You can manually add them to the nav bar by editing that porition of page-template.html.

sitemap.txt

A /sitemap.txt file (for web crawlers) is automatically generated and includes all post and non-post pages. (It does not include index pages for tags.)

Templates

Frog uses the Racket web-server/templates system based on scribble/text @-expressions. This means that the files are basically normal HTML format, with the ability to use @ to reference a template variable --- or indeed to "escape" to arbitrary Racket code.

In contrast to most templating systems, you have a full programming language available -- Racket -- should you need it. However most of what you need to do will probably very simple, such as the occasional if or when test, or perhaps defining a helper function to minimize repetition.

Page template: _src/page-template.html

The _src/page-template.html template specifies an <html> element used by Frog to generate every page on your site.

Anything in the file that looks like @variable or @|variable| is a template variable supplied by Frog. Most of these should be self-explanatory from their name and from seeing how they are used in the default template. Specifically:

  • contents: The contents of the page.
  • title: The title of the page (for <title>)
  • description: The description of the page (for <meta> content element)
  • keywords: The keywords for the page (for <meta> keywords element)
  • uri-path: The path portion of the URI, e.g. /path/to/file.html
  • full-uri: The full URI, e.g. http://example.com/path/to/file.html
  • atom-feed-uri: The full URI to the Atom feed
  • rss-feed-uri: The full URI to the RSS feed
  • tag: If this an index page, tag is the name of the index (such as "All Posts") or ("Posts tagged foo"), else tag is #f.
  • tags/feeds: HTML that has, for each tag, a link to its index page and a link to its Atom feed.

Post template: _src/post-template.html

The _src/post-template.html template determines how blog posts are laid out, on page that are dedicated to one post. The default template defines an <article> element.

For pages that are blog posts, the result of post-template.html becomes most of the @|contents| variable in page-template.html. In other words, the post template is effectively nested in the page template. (They are two separate templates so that the page template can also be used for pages that are not blog post pages.)

+---------------------------+
| page-template             |
|                           |
|       +---------------+   |
|       | post-template |   |
|       +---------------+   |
|                           |
+---------------------------+

NOTE: This template does not control how a blog post is laid out on an index page like /index.html or /tags/<some-tag>.html. Why? The main purpose of this template is to specify things like Disqus comments, Tweet and +1 sharing buttons, and older/newer links --- things that only make sense in the context of pages dedicated to one blog post.

Anything in the file that looks like @variable or @|variable| is a template variable supplied by Frog. Most of these should be self-explanatory from their name and from seeing how they are used in the default template. Specifically:

  • title: The title of the post
  • uri-path: The path portion of the URI, e.g. /path/to/file.html
  • full-uri: The full URI, e.g. http://example.com/path/to/file.html
  • date+tags: The date and tags of the post
  • content: The content of the post
  • older-uri: The URI of the next older post, if any, or #f
  • older-title: The title of the next older post, if any, or #f
  • newer-uri: The URI of the next newer post, if any, or #f
  • newer-title: The title of the next newer post, if any, or #f

Widgets

In addition to the variables described above for each template, some predefined functions are available for templates to use: "widgets".

Anything a widget can do, you could code directly in the template. There's no magic. But widgets minimize clutter in the templates. Plus they make clearer what are the user-specific parameters (as opposed to putting stuff like <!-- CHANGE THIS! --> in the template).

For example, @google-analytics["UA-xxxxx" "example.com"] returns text for a <script> element to insert Google Analytics tracking code. You supply it the two user-specific pieces of information, which it plugs into the boilerplate and returns.

Likewise there are widgets for things like Twitter and Google+ share buttons, Twitter follow button, Disqus comments, older/newer post links.

See widgets.rkt for the complete list. See the example page and post templates for usage examples.

NOTE: If you'd like to add a widget, pull requests are welcome!

Code blocks

Frog optionally uses Pygments to do syntax highlighting. When using fenced code blocks, you can specify a language (as on GitHub):

```language
some lines
of code
```

That language is given to Pygments as the lexer to use.

For example this:

```js
/**
 * Some JavaScript
 */
function foo()
{
    if (counter <= 10)
        return;
    // it works!
```

Yields this using the js lexer:

/**
 * Some JavaScript
 */
function foo()
{
    if (counter <= 10)
        return;
    // it works!

And this:

```racket
#lang racket
;; Finds Racket sources in all subdirs
(for ([path (in-directory)])
  (when (regexp-match? #rx"[.]rkt$" path)
    (printf "source file: ~a\n" path)))
```

Yields this using the racket lexer:

#lang racket
;; Finds Racket sources in all subdirs
(for ([path (in-directory)])
  (when (regexp-match? #rx"[.]rkt$" path)
    (printf "source file: ~a\n" path)))

The colors are controlled by your css/pygments.css file. There are examples of many styles.

If you use larger font sizes, code may wrap and get out of alignment with the line numbers. To avoid the wrapping, add the following to your css/custom.css:

/* When highlighted code blocks are too wide, they wrap. Resulting in the */
/* line numbers column's rows not lining up with the code rows. Prevent */
/* wrapping. */
pre {
    white-space: pre;
    width: inherit;
}

NOTE: I have a soft spot for Pygments because it's actually the first existing open source project to which I contributed. I added a lexer for the Racket language. More importantly it has lexers for tons of languages and is used by things like GitHub (via pygments.rb), BitBucket, and so on. Plus, it fits the spirit of static web site generation better than JavaScript options like SyntaxHighlighter.

Bug reports? Feature requests?

Please use GitHub Issues.

About

Frog is a static blog generator implemented in Racket, targeting Bootstrap and able to use Pygments.

Topics

Resources

Stars

Watchers

Forks