1
0
Fork 0
forked from github/pelican

Add a way to specify CSS files. Add default settings too.

--HG--
rename : samples/themes/notmyidea/archives.html => samples/themes/notmyidea/templates/archives.html
rename : samples/themes/notmyidea/article.html => samples/themes/notmyidea/templates/article.html
rename : samples/themes/notmyidea/base.html => samples/themes/notmyidea/templates/base.html
rename : samples/themes/notmyidea/categories.html => samples/themes/notmyidea/templates/categories.html
rename : samples/themes/notmyidea/category.html => samples/themes/notmyidea/templates/category.html
rename : samples/themes/notmyidea/index.html => samples/themes/notmyidea/templates/index.html
rename : samples/themes/notmyidea/tag.html => samples/themes/notmyidea/templates/tag.html
rename : samples/themes/notmyidea/tags.html => samples/themes/notmyidea/templates/tags.html
This commit is contained in:
Alexis Metaireau 2010-08-18 16:02:06 +02:00
commit a114521914
22 changed files with 631 additions and 156 deletions

1
TODO
View file

@ -1,4 +1,3 @@
* Add separated CSS files somewhere
* Fall back to settings + date of files when no metadata available * Fall back to settings + date of files when no metadata available
* Filter to generate only the files with .rst extension * Filter to generate only the files with .rst extension
* Add a licence * Add a licence

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import re import re
import shutil
from codecs import open from codecs import open
from datetime import datetime from datetime import datetime
from docutils import core from docutils import core
@ -14,29 +15,38 @@ import rstdirectives # import the directives to have pygments support
_TEMPLATES = ('index', 'tag', 'tags', 'article', 'category', 'categories', _TEMPLATES = ('index', 'tag', 'tags', 'article', 'category', 'categories',
'archives') 'archives')
_DIRECT_TEMPLATES = ('index', 'tags', 'categories', 'archives') _DIRECT_TEMPLATES = ('index', 'tags', 'categories', 'archives')
_DEFAULT_TEMPLATE_PATH =\ _DEFAULT_THEME =\
os.sep.join([os.path.dirname(os.path.abspath(__file__)), "themes"]) os.sep.join([os.path.dirname(os.path.abspath(__file__)), "themes"])
_DEFAULT_CONFIG = {'PATH': None,
'THEME': _DEFAULT_THEME,
'OUTPUT_PATH': 'output/',
'MARKUP': 'rst'}
def generate_output(path=None, theme=None, output_path=None, markup=None,
def generate_output(files, templates_path=None, output_path=None, markup=None,
settings=None): settings=None):
"""Given a list of files, a template and a destination, """Given a list of files, a template and a destination,
output the static files. output the static files.
:param files: the list of files to parse :param path: the path where to find the files to parse
:param templates_path: where to search for templates :param theme: where to search for templates
:param output_path: where to output the generated files :param output_path: where to output the generated files
:param markup: the markup language to use while parsing :param markup: the markup language to use while parsing
:param settings: the settings file to use :param settings: the settings file to use
""" """
if not templates_path: # get the settings
templates_path = _DEFAULT_TEMPLATE_PATH context = read_settings(settings)
if not output_path: path = path or context['PATH']
output_path = './output' theme = theme or context['THEME']
output_path = output_path or context['OUTPUT_PATH']
output_path = os.path.realpath(output_path) output_path = os.path.realpath(output_path)
markup = markup or context['MARKUP']
# get the list of files to parse
files = []
for root, dirs, temp_files in os.walk(path, followlinks=True):
files.extend([os.sep.join((root, f)) for f in temp_files])
articles, dates, years, tags, categories = [], {}, {}, {}, {} articles, dates, years, tags, categories = [], {}, {}, {}, {}
# for each file, get the informations. # for each file, get the informations.
for f in files: for f in files:
f = os.path.abspath(f) f = os.path.abspath(f)
@ -53,15 +63,14 @@ def generate_output(files, templates_path=None, output_path=None, markup=None,
# order the articles by date # order the articles by date
articles.sort(key=attrgetter('date'), reverse=True) articles.sort(key=attrgetter('date'), reverse=True)
templates = get_templates(templates_path) templates = get_templates(theme)
context = {}
for item in ('articles', 'dates', 'years', 'tags', 'categories'): for item in ('articles', 'dates', 'years', 'tags', 'categories'):
value = locals()[item] value = locals()[item]
if hasattr(value, 'items'): if hasattr(value, 'items'):
value = value.items() value = value.items()
context[item] = value context[item] = value
read_settings(context, settings)
# generate the output
generate = partial(generate_file, output_path) generate = partial(generate_file, output_path)
for template in _DIRECT_TEMPLATES: for template in _DIRECT_TEMPLATES:
generate('%s.html' % template, templates[template], context) generate('%s.html' % template, templates[template], context)
@ -74,6 +83,13 @@ def generate_output(files, templates_path=None, output_path=None, markup=None,
generate('%s' % article.url, generate('%s' % article.url,
templates['article'], context, article=article) templates['article'], context, article=article)
# copy css path to output/css
try:
shutil.copytree(os.path.join(theme, 'css'),
os.path.join(output_path, 'css'))
except OSError:
pass
def generate_file(path, name, template, context, **kwargs): def generate_file(path, name, template, context, **kwargs):
context.update(kwargs) context.update(kwargs)
@ -89,6 +105,7 @@ def generate_file(path, name, template, context, **kwargs):
def get_templates(path=None): def get_templates(path=None):
path = os.path.join(path, 'templates')
env = Environment(loader=FileSystemLoader(path)) env = Environment(loader=FileSystemLoader(path))
templates = {} templates = {}
for template in _TEMPLATES: for template in _TEMPLATES:
@ -102,9 +119,10 @@ def update_dict(mapping, key, value):
mapping[key].append(value) mapping[key].append(value)
def read_settings(context, filename): def read_settings(filename):
"""Load a Python file into a dictionary. """Load a Python file into a dictionary.
""" """
context = _DEFAULT_CONFIG.copy()
if filename: if filename:
tempdict = {} tempdict = {}
execfile(filename, tempdict) execfile(filename, tempdict)
@ -158,11 +176,11 @@ class Article(object):
def __init__(self, string, markup=None): def __init__(self, string, markup=None):
if markup == None: if markup == None:
markup = 'rest' markup = 'rst'
for key, value in parse_metadata(string).items(): for key, value in parse_metadata(string).items():
setattr(self, key, value) setattr(self, key, value)
if markup == 'rest': if markup == 'rst':
extra_params = {'input_encoding': 'unicode', extra_params = {'input_encoding': 'unicode',
'initial_header_level': '2'} 'initial_header_level': '2'}
rendered_content = core.publish_parts(string, writer_name='html', rendered_content = core.publish_parts(string, writer_name='html',

View file

@ -8,25 +8,24 @@ files to read and a template to use.
The main use case is to generate static-files-based blogs, to ease DVCSes as The main use case is to generate static-files-based blogs, to ease DVCSes as
storages, but it could be used with others goal in mind.""") storages, but it could be used with others goal in mind.""")
parser.add_argument('-p', '--path', default='content', dest='path',
parser.add_argument('-p', '--path', dest='path',
help='Path where to find the content files (default is "content").') help='Path where to find the content files (default is "content").')
parser.add_argument('-t', '--templates-path', default=None, dest='templates', parser.add_argument('-t', '--templates-path', dest='templates',
help='Path where to find the templates. If not specified, will uses the' help='Path where to find the templates. If not specified, will uses the'
' ones included with pelican.') ' ones included with pelican.')
parser.add_argument('-o', '--output', default=None, dest='output', parser.add_argument('-o', '--output', dest='output',
help='Where to output the generated files. If not specified, a directory' help='Where to output the generated files. If not specified, a directory'
' will be created, named "output" in the current path.') ' will be created, named "output" in the current path.')
parser.add_argument('-m', '--markup', default='rest', dest='markup', parser.add_argument('-m', '--markup', default='rst', dest='markup',
help='the markup language to use. Currently only ReSTreucturedtext is' help='the markup language to use. Currently only ReSTreucturedtext is'
' available.') ' available.')
parser.add_argument('-s', '--settings', default=None, dest='settings', parser.add_argument('-s', '--settings', dest='settings',
help='the settings of the application. Default to None.') help='the settings of the application. Default to None.')
if __name__ == '__main__': if __name__ == '__main__':
args = parser.parse_args() args = parser.parse_args()
files = [] files = []
for root, dirs, temp_files in os.walk(args.path, followlinks=True): generate_output(args.path, args.templates, args.output, args.markup,
files.extend([os.sep.join((root, f)) for f in temp_files])
generate_output(files, args.templates, args.output, args.markup,
args.settings) args.settings)
print 'Done !' print 'Done !'

View file

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
PATH = 'samples/content'
THEME = 'samples/themes/notmyidea'
BLOGNAME = 'NotMyIdea.org' BLOGNAME = 'NotMyIdea.org'
BLOGSUBTITLE = u"Alexis Métaireau's weblog" BLOGSUBTITLE = u"Alexis Métaireau's weblog"

View file

@ -0,0 +1,405 @@
/*
Name: Smashing HTML5
Date: July 2009
Description: Sample layout for HTML5 and CSS3 goodness.
Version: 1.0
Author: Enrique Ramírez
Autor URI: http://enrique-ramirez.com
*/
/* Imports */
@import url("reset.css");
/***** Global *****/
/* Body */
body {
background: #F5F4EF url('../images/bg.png');
color: #000305;
font-size: 87.5%; /* Base font size: 14px */
font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
line-height: 1.429;
margin: 0;
padding: 0;
text-align: left;
}
/* Headings */
h2 {font-size: 1.571em} /* 22px */
h3 {font-size: 1.429em} /* 20px */
h4 {font-size: 1.286em} /* 18px */
h5 {font-size: 1.143em} /* 16px */
h6 {font-size: 1em} /* 14px */
h2, h3, h4, h5, h6 {
font-weight: 400;
line-height: 1.1;
margin-bottom: .8em;
}
/* Anchors */
a {outline: 0;}
a img {border: 0px; text-decoration: none;}
a:link, a:visited {
color: #C74350;
padding: 0 1px;
text-decoration: underline;
}
a:hover, a:active {
background-color: #C74350;
color: #fff;
text-decoration: none;
text-shadow: 1px 1px 1px #333;
}
/* Paragraphs */
p {margin-bottom: 1.143em;}
* p:last-child {margin-bottom: 0;}
strong, b {font-weight: bold;}
em, i {font-style: italic;}
::-moz-selection {background: #F6CF74; color: #fff;}
::selection {background: #F6CF74; color: #fff;}
/* Lists */
ul {
list-style: outside disc;
margin: 1em 0 1.5em 1.5em;
}
ol {
list-style: outside decimal;
margin: 1em 0 1.5em 1.5em;
}
dl {margin: 0 0 1.5em 0;}
dt {font-weight: bold;}
dd {margin-left: 1.5em;}
/* Quotes */
blockquote {font-style: italic;}
cite {}
q {}
/* Tables */
table {margin: .5em auto 1.5em auto; width: 98%;}
/* Thead */
thead th {padding: .5em .4em; text-align: left;}
thead td {}
/* Tbody */
tbody td {padding: .5em .4em;}
tbody th {}
tbody .alt td {}
tbody .alt th {}
/* Tfoot */
tfoot th {}
tfoot td {}
/* HTML5 tags */
header, section, footer,
aside, nav, article, figure {
display: block;
}
/***** Layout *****/
.body {clear: both; margin: 0 auto; width: 800px;}
img.right figure.right {float: right; margin: 0 0 2em 2em;}
img.left, figure.left {float: right; margin: 0 0 2em 2em;}
/*
Header
*****************/
#banner {
margin: 0 auto;
padding: 2.5em 0 0 0;
}
/* Banner */
#banner h1 {font-size: 3.571em; line-height: .6;}
#banner h1 a:link, #banner h1 a:visited {
color: #000305;
display: block;
font-weight: bold;
margin: 0 0 .6em .2em;
text-decoration: none;
width: 427px;
}
#banner h1 a:hover, #banner h1 a:active {
background: none;
color: #C74350;
text-shadow: none;
}
#banner h1 strong {font-size: 0.36em; font-weight: normal;}
/* Main Nav */
#banner nav {
background: #000305;
font-size: 1.143em;
height: 40px;
line-height: 30px;
margin: 0 auto 2em auto;
padding: 0;
text-align: center;
width: 800px;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
#banner nav ul {list-style: none; margin: 0 auto; width: 800px;}
#banner nav li {float: left; display: inline; margin: 0;}
#banner nav a:link, #banner nav a:visited {
color: #fff;
display: inline-block;
height: 30px;
padding: 5px 1.5em;
text-decoration: none;
}
#banner nav a:hover, #banner nav a:active,
#banner nav .active a:link, #banner nav .active a:visited {
background: #C74451;
color: #fff;
text-shadow: none !important;
}
#banner nav li:first-child a {
border-top-left-radius: 5px;
-moz-border-radius-topleft: 5px;
-webkit-border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
-moz-border-radius-bottomleft: 5px;
-webkit-border-bottom-left-radius: 5px;
}
/*
Featured
*****************/
#featured {
background: #fff;
margin-bottom: 2em;
overflow: hidden;
padding: 20px;
width: 760px;
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}
#featured figure {
border: 2px solid #eee;
float: right;
margin: 0.786em 2em 0 5em;
width: 248px;
}
#featured figure img {display: block; float: right;}
#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;}
#featured h3 {font-size: 1.429em; margin-bottom: .5em;}
#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;}
#featured h3 a:hover, #featured h3 a:active {color: #fff;}
/*
Body
*****************/
#content {
background: #fff;
margin-bottom: 2em;
overflow: hidden;
padding: 20px 20px;
width: 760px;
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}
/*
Extras
*****************/
#extras {margin: 0 auto 3em auto; overflow: hidden;}
#extras ul {list-style: none; margin: 0;}
#extras li {border-bottom: 1px solid #fff;}
#extras h2 {
color: #C74350;
font-size: 1.429em;
margin-bottom: .25em;
padding: 0 3px;
}
#extras a:link, #extras a:visited {
color: #444;
display: block;
border-bottom: 1px solid #F4E3E3;
text-decoration: none;
padding: .3em .25em;
}
#extras li:last-child,
#extras li:last-child a {border: 0}
#extras .blogroll li:nth-last-child(2),
#extras .blogroll li:nth-last-child(3),
#extras .blogroll li:nth-last-child(2) a,
#extras .blogroll li:nth-last-child(3) a {border: 0;}
#extras a:hover, #extras a:active {color: #fff;}
/* Blogroll */
#extras .blogroll {
float: left;
width: 615px;
}
#extras .blogroll li {float: left; margin: 0 20px 0 0; width: 185px;}
/* Social */
#extras .social {
float: right;
width: 175px;
}
#extras div[class='social'] a {
background-repeat: no-repeat;
background-position: 3px 6px;
padding-left: 25px;
}
/* Icons */
.social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');}
.social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');}
.social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');}
.social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');}
.social a[href*='/feed/'] {background-image: url('../images/icons/rss.png');}
.social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');}
/*
About
*****************/
#about {
background: #fff;
font-style: normal;
margin-bottom: 2em;
overflow: hidden;
padding: 20px;
text-align: left;
width: 760px;
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}
#about .primary {float: left; width: 165px;}
#about .primary strong {color: #C64350; display: block; font-size: 1.286em;}
#about .photo {float: left; margin: 5px 20px;}
#about .url:link, #about .url:visited {text-decoration: none;}
#about .bio {float: right; width: 500px;}
/*
Footer
*****************/
#contentinfo {padding-bottom: 2em; text-align: right;}
/***** Sections *****/
/* Blog */
.hentry {
border-bottom: 1px solid #eee;
padding: 1.5em 0;
}
li:last-child .hentry, #content > .hentry {border: 0; margin: 0;}
#content > .hentry {padding: 1em 0;}
.entry-title {font-size: 1.429em; margin-bottom: 0;}
.entry-title a:link, .entry-title a:visited {text-decoration: none;}
.hentry .post-info * {font-style: normal;}
/* Content */
.hentry footer {margin-bottom: 2em;}
.hentry footer address {display: inline;}
#posts-list footer address {display: block;}
/* Blog Index */
#posts-list {list-style: none; margin: 0;}
#posts-list .hentry {padding-left: 200px; position: relative;}
#posts-list .hentry:hover {
background: #C64350;
color: #fff;
}
#posts-list .hentry:hover a:link, #posts-list .hentry:hover a:visited {
color: #F6CF74;
text-shadow: 1px 1px 1px #333;
}
#posts-list footer {
left: 10px;
position: absolute;
top: 1.5em;
width: 190px;
}
/* About the Author */
#about-author {
background: #f9f9f9;
clear: both;
font-style: normal;
margin: 2em 0;
padding: 10px 20px 15px 20px;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
#about-author strong {
color: #C64350;
clear: both;
display: block;
font-size: 1.429em;
}
#about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;}
/* Comments */
#comments-list {list-style: none; margin: 0 1em;}
#comments-list blockquote {
background: #f8f8f8;
clear: both;
font-style: normal;
margin: 0;
padding: 15px 20px;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
#comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;}
#comments-list li:nth-child(2n) blockquote {background: #F5f5f5;}
/* Add a Comment */
#add-comment label {clear: left; float: left; text-align: left; width: 150px;}
#add-comment input[type='text'],
#add-comment input[type='email'],
#add-comment input[type='url'] {float: left; width: 200px;}
#add-comment textarea {float: left; height: 150px; width: 495px;}
#add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;}
#add-comment input[type='submit'] {float: right; margin: 0 .5em;}
#add-comment * {margin-bottom: .5em;}

View file

@ -0,0 +1,52 @@
/*
Name: Reset Stylesheet
Description: Resets browser's default CSS
Author: Eric Meyer
Author URI: http://meyerweb.com/eric/tools/css/reset/
*/
/* v1.0 | 20080212 */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
background: transparent;
border: 0;
font-size: 100%;
margin: 0;
outline: 0;
padding: 0;
vertical-align: baseline;
}
body {line-height: 1;}
ol, ul {list-style: none;}
blockquote, q {quotes: none;}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
/* remember to define focus styles! */
:focus {
outline: 0;
}
/* remember to highlight inserts somehow! */
ins {text-decoration: none;}
del {text-decoration: line-through;}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: collapse;
border-spacing: 0;
}