Skip to content

Commit

Permalink
added "Theme Sandbox" example app
Browse files Browse the repository at this point in the history
  • Loading branch information
leafstorm committed Jul 15, 2010
1 parent c731151 commit 94f30e1
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 0 deletions.
95 changes: 95 additions & 0 deletions example/posts.yaml
@@ -0,0 +1,95 @@
# example posts for Theme Sandbox
# part of Flask-Themes
# copyright 2010 Matthew "LeafStorm" Frazier
# licensed under the MIT/X11 license (see LICENSE for details)

slug: introduction
created: 2010-07-01 16:00:00
title: Introduction
body: >
Welcome to the Theme Sandbox. This is a simple Web application intended
to emulate a weblog. Of course, to save on time and effort, all the posts
are pregenerated, and the application is just displaying them. But still,
it gives people a chance to see how themes are implemented.
There are some templates by default, but they aren't particularly shiny.
You will want to set a theme if you want the blog to look good.
---

slug: creating-themes
created: 2010-07-01 14:00:00
title: Creating Themes
body: >
With the Theme Sandbox, probably the easiest way to create a theme is just
to drop it in the "themes/" folder. You can set THEME_PATHS in the
configuration, but that is still the easiest.
To actually create a theme, you will need to check the manual for details.
But it essentially boils down to:
An info.json file that contains metadata about the theme,
A templates/ folder that contains the theme's Jinja2 templates.
A static/ folder containing static files to be served.
A license.txt file (optional) containing the theme's complete license.
---

slug: inspirations
created: 2010-07-01 13:00:00
title: Theme System Inspirations
body: >
My primary inspiration for the theme system was the blogging system Zine.
I didn't implement all its features, like options for themes, simply
because those are tied in to Zine's particular mode of configuration, and
applications will probably have their own.
One person asked if it was inspired by Deliverance. I looked it up, and
thought that it looked confusing. But basically, the differences are that
Flask-Themes is for single applications, Deliverance is for multiple
applications. Flask-Themes works at the template level, Deliverance works
at the HTML level. Flask-Themes doesn't deal with HTML/XML, while
Deliverance does.
---

slug: templates
created: 2010-07-01 11:00:00
title: Templates
body: >
The templates used by this site are:
layout.html, which should have a "body" block and a "head" block (where
"head" is in the HTML head element), and should expect an exported
variable named "title" that is the page's title.
index.html, which accepts a "posts" variable that contains three posts.
_helpers.html, which exports a "link_to" macro that takes a caption, an
endpoint, and keyword arguments.
archive.html, which accepts a "posts" variable that contains *all* of the
posts.
post.html, which accepts a single "post".
about.html, which accepts "text", the about text as Markup.
themes.html, which accepts a list of themes and should create links to
"settheme" for each of them.
---

slug: adding-posts
created: 2010-07-01 9:00:00
title: Adding Posts
body: >
The blog probably seems pretty small to you. And that's the idea - have a
dataset just big enough to simulate real-world usage. But if you want, you
can add more posts.
All the posts are stored in the posts.yaml file. You can add them there.
Slugs must be unique, but that's about the only restriction.
3 changes: 3 additions & 0 deletions example/templates/_helpers.html
@@ -0,0 +1,3 @@
{% macro link_to(text, endpoint) -%}
<a href="{{ url_for(endpoint, **kwargs) }}">{{ text }}</a>
{%- endmacro %}
9 changes: 9 additions & 0 deletions example/templates/_post.html
@@ -0,0 +1,9 @@
{% macro show_post(post) %}

<h2>{{ post.title }}</h2>

<p class=meta>Created on {{ post.created.strftime('%x at %X') }}</p>

{{ post.content }}

{% endmacro %}
11 changes: 11 additions & 0 deletions example/templates/about.html
@@ -0,0 +1,11 @@
{% extends theme('layout.html') %}

{% set title = 'About' %}

{% block body %}

<h2>About</h2>

{{ text }}

{% endblock body %}
14 changes: 14 additions & 0 deletions example/templates/archive.html
@@ -0,0 +1,14 @@
{% extends theme('layout.html') %}

{% set title = 'Archive' %}

{% block body %}
<h2>Archive</h2>

<ul>
{%- for post in posts %}
<li>{{ link_to(post.title, 'post', slug=post.slug) }}
&mdash; created on {{ post.created.strftime('%x at %X') }}</li>
{%- endfor %}
</ul>
{% endblock body %}
16 changes: 16 additions & 0 deletions example/templates/index.html
@@ -0,0 +1,16 @@
{% extends theme('layout.html') %}
{% from theme('_post.html') import show_post %}

{% set title = 'Index' %}

{% block body %}

{% for post in posts %}

{{ show_post(post) }}

<p class=permalink>{{ link_to('Permalink', 'post', slug=post.slug) }}</p>

{% endfor %}

{% endblock body %}
20 changes: 20 additions & 0 deletions example/templates/layout.html
@@ -0,0 +1,20 @@
<!doctype html>
{% from "_helpers.html" import link_to %}
<head>
<title>Theme Sandbox: {{ title }}</title>
{% block head %}{% endblock head %}
</head>

<body>
<h1>Theme Sandbox</h1>

<p>
{{ link_to('Index', 'index') }} |
{{ link_to('Archive', 'archive') }} |
{{ link_to('About', 'about') }} |
{{ link_to('Themes', 'themes') }}
</p>

{% block body %}
{% endblock body %}
</body>
10 changes: 10 additions & 0 deletions example/templates/post.html
@@ -0,0 +1,10 @@
{% extends theme('layout.html') %}
{% from theme('_post.html') import show_post %}

{% set title = post.title %}

{% block body %}

{{ show_post(post) }}

{% endblock body %}
20 changes: 20 additions & 0 deletions example/templates/themes.html
@@ -0,0 +1,20 @@
{% extends theme('layout.html') %}
{% from "_helpers.html" import link_to %}

{% set title = 'Themes' %}

{% block body %}

<h2>Theme Selection</h2>

{% for theme in themes %}

<h3>{{ theme.title }}</h3>

<p>{{ theme.description }}</p>

<p class=select>{{ link_to('Select this theme', 'settheme', ident=theme.identifier) }}</p>

{% endfor %}

{% endblock body %}
120 changes: 120 additions & 0 deletions example/themesandbox.py
@@ -0,0 +1,120 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
themesandbox.py
===============
A sandbox to play around with themes in.
:copyright: 2010 Matthew "LeafStorm" Frazier
:license: MIT/X11, see LICENSE for details
"""
import yaml
from flask import (Flask, url_for, redirect, session, Markup, abort)
from flaskext.themes import (setup_themes, render_theme_template,
get_themes_list)
from operator import attrgetter

# default settings

DEFAULT_THEME = 'calmblue'
SECRET_KEY = 'not really secret'


# application

app = Flask(__name__)
app.config.from_object(__name__)
setup_themes(app, app_identifier='themesandbox')


# data

class Post(object):
def __init__(self, data):
self.slug = data['slug']
self.body = data['body']
self.title = data['title']
self.created = data['created']

@property
def content(self):
return Markup('\n\n'.join(
'<p>%s</p>' % line for line in self.body.splitlines()
))


class PostStore(object):
def __init__(self):
self.by_date = []
self.by_slug = {}

def add_posts(self, post_data):
posts = [Post(post) for post in post_data]
for post in posts:
if post.slug in self.by_slug:
raise RuntimeError("slugs must be unique")
self.by_slug[post.slug] = post
self.by_date.extend(posts)
self.by_date.sort(key=attrgetter('created'), reverse=True)


store = PostStore()

with app.open_resource('posts.yaml') as fd:
post_data = yaml.load_all(fd)
store.add_posts(post_data)


ABOUT_TEXT = Markup('<p>This is a demonstration of Flask-Themes.</p>')


# themes

def render(template, **context):
theme = session.get('theme', app.config['DEFAULT_THEME'])
return render_theme_template(theme, template, **context)


# views

@app.route('/')
def index():
posts = store.by_date[:3]
return render('index.html', posts=posts)


@app.route('/archive')
def archive():
posts = store.by_date[:]
return render('archive.html', posts=posts)


@app.route('/post/<slug>')
def post(slug):
post = store.by_slug.get(slug)
if post is None:
abort(404)
return render('post.html', post=post)


@app.route('/about')
def about():
return render('about.html', text=ABOUT_TEXT)


@app.route('/themes/')
def themes():
themes = get_themes_list()
return render('themes.html', themes=themes)


@app.route('/themes/<ident>')
def settheme(ident):
if ident not in app.theme_manager.themes:
abort(404)
session['theme'] = ident
return redirect(url_for('themes'))


if __name__ == '__main__':
app.run(debug=True)

0 comments on commit 94f30e1

Please sign in to comment.