import plugins from core and restructure repo

This commit is contained in:
Deniz Turgut
2013-04-10 19:12:31 -04:00
parent 66e83158ba
commit 9e70c17839
135 changed files with 2628 additions and 204 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.pyc

13
.travis.yml Normal file
View File

@@ -0,0 +1,13 @@
language: python
python:
- "2.7"
- "3.2"
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq --no-install-recommends ruby-sass
install:
- pip install nose
- pip install -e git://github.com/getpelican/pelican.git#egg=pelican
- pip install --use-mirrors Markdown
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors webassets cssmin; fi
script: nosetests tests

29
Contributing.rst Normal file
View File

@@ -0,0 +1,29 @@
Contributing a plugin
=====================
Details of how to write a plugin is explained in the official Pelican `docs`_.
If you want to contribute, please fork this repository and issue your pull
request. Make sure that your plugin follows the structure below::
my_plugin
├── __init__.py
├── my_plugin.py
└── Readme.rst / Readme.md
``my_plugin.py`` is the actual plugin implementation. Include a brief
explanation of what the plugin does as a module docstring. Leave any further
explanations and usage details to ``Readme`` file.
``__init__.py`` should contain a single line with ``from .my_plugin import *``.
If you have tests for your plugin, place them in the ``tests`` folder with name
``test_my_plugin.py``. You can use ``test_data`` folder inside, if you need content
or templates in your tests.
**Note:** Plugins in the repository are licensed with *GNU AFFERO GENERAL PUBLIC LICENSE
Version 3*. By submitting a pull request, you accept to release your
contribution under same license. Please refer to the ``LICENSE`` file for
full text of the license.
.. _docs: http://docs.getpelican.com/en/latest/plugins.html#how-to-create-plugins

View File

@@ -1,11 +0,0 @@
Pelican Plugins
###############
This repository contains plugins for Pelican. At the moment, this is only a
subset of the available plugins, with others currently residing in the primary
Pelican repository. Those latter plugins will eventually be moved here, so all
plugins will be in one place.
That being the case, if you have a plugin to contribute, please fork this
Pelican Plugins repository and issue your pull request from there (as opposed
to the primary Pelican repository).

41
Readme.rst Normal file
View File

@@ -0,0 +1,41 @@
Pelican Plugins
###############
Beginning with version 3.0, Pelican supports plugins. Plugins are a way to add
features to Pelican without having to directly modify the Pelican core. Starting
with 3.2, all plugins (including the ones previously in the core) are
moved here, so this is the central place for all plugins.
How to use plugins
==================
Easiest way to install and use these plugins is cloning this repo::
git clone https://github.com/getpelican/pelican-plugins
and activating the ones you want in your settings file::
PLUGIN_PATH = 'path/to/pelican-plugins'
PLUGINS = ['assets', 'sitemap', 'gravatar']
``PLUGIN_PATH`` can be a path relative to your settings file or an absolute path.
Alternatively, if plugins are in an importable path, you can omit ``PLUGIN_PATH``
and list them::
PLUGINS = ['assets', 'sitemap', 'gravatar']
or you can ``import`` the plugin directly and give that::
import my_plugin
PLUGINS = [my_plugin, 'assets']
Please refer to the ``Readme`` file in a plugin's folder for detailed information about
that plugin.
Contributing a plugin
=====================
Please refer to the `Contributing`_ file.
.. _Contributing: Contributing.rst

80
assets/Readme.rst Normal file
View File

@@ -0,0 +1,80 @@
Asset management
----------------
This plugin allows you to use the `Webassets`_ module to manage assets such as
CSS and JS files. The module must first be installed::
pip install webassets
The Webassets module allows you to perform a number of useful asset management
functions, including:
* CSS minifier (``cssmin``, ``yui_css``, ...)
* CSS compiler (``less``, ``sass``, ...)
* JS minifier (``uglifyjs``, ``yui_js``, ``closure``, ...)
Others filters include gzip compression, integration of images in CSS via data
URIs, and more. Webassets can also append a version identifier to your asset
URL to convince browsers to download new versions of your assets when you use
far-future expires headers. Please refer to the `Webassets documentation`_ for
more information.
When used with Pelican, Webassets is configured to process assets in the
``OUTPUT_PATH/theme`` directory. You can use Webassets in your templates by
including one or more template tags. The Jinja variable ``{{ ASSET_URL }}`` can
be used in templates and is relative to the ``theme/`` url. The
``{{ ASSET_URL }}`` variable should be used in conjunction with the
``{{ SITEURL }}`` variable in order to generate URLs properly. For example:
.. code-block:: jinja
{% assets filters="cssmin", output="css/style.min.css", "css/inuit.css", "css/pygment-monokai.css", "css/main.css" %}
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
{% endassets %}
... will produce a minified css file with a version identifier that looks like:
.. code-block:: html
<link href="http://{SITEURL}/theme/css/style.min.css?b3a7c807" rel="stylesheet">
These filters can be combined. Here is an example that uses the SASS compiler
and minifies the output:
.. code-block:: jinja
{% assets filters="sass,cssmin", output="css/style.min.css", "css/style.scss" %}
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
{% endassets %}
Another example for Javascript:
.. code-block:: jinja
{% assets filters="uglifyjs,gzip", output="js/packed.js", "js/jquery.js", "js/base.js", "js/widgets.js" %}
<script src="{{ SITEURL }}/{{ ASSET_URL }}"></script>
{% endassets %}
The above will produce a minified and gzipped JS file:
.. code-block:: html
<script src="http://{SITEURL}/theme/js/packed.js?00703b9d"></script>
Pelican's debug mode is propagated to Webassets to disable asset packaging
and instead work with the uncompressed assets.
Many of Webasset's available compilers have additional configuration options
(i.e. 'Less', 'Sass', 'Stylus', 'Closure_js'). You can pass these options to
Webassets using the ``ASSET_CONFIG`` in your settings file.
The following will handle Google Closure's compilation level and locate
LessCSS's binary:
.. code-block:: python
ASSET_CONFIG = (('closure_compressor_optimization', 'WHITESPACE_ONLY'),
('less_bin', 'lessc.cmd'), )
.. _Webassets: https://github.com/miracle2k/webassets
.. _Webassets documentation: http://webassets.readthedocs.org/en/latest/builtin_filters.html

1
assets/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .assets import *

53
assets/assets.py Normal file
View File

@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
"""
Asset management plugin for Pelican
===================================
This plugin allows you to use the `webassets`_ module to manage assets such as
CSS and JS files.
The ASSET_URL is set to a relative url to honor Pelican's RELATIVE_URLS
setting. This requires the use of SITEURL in the templates::
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
.. _webassets: https://webassets.readthedocs.org/
"""
from __future__ import unicode_literals
import os
import logging
from pelican import signals
from webassets import Environment
from webassets.ext.jinja2 import AssetsExtension
def add_jinja2_ext(pelican):
"""Add Webassets to Jinja2 extensions in Pelican settings."""
pelican.settings['JINJA_EXTENSIONS'].append(AssetsExtension)
def create_assets_env(generator):
"""Define the assets environment and pass it to the generator."""
assets_url = 'theme/'
assets_src = os.path.join(generator.output_path, 'theme')
generator.env.assets_environment = Environment(assets_src, assets_url)
if 'ASSET_CONFIG' in generator.settings:
for item in generator.settings['ASSET_CONFIG']:
generator.env.assets_environment.config[item[0]] = item[1]
logger = logging.getLogger(__name__)
if logging.getLevelName(logger.getEffectiveLevel()) == "DEBUG":
generator.env.assets_environment.debug = True
def register():
"""Plugin registration."""
signals.initialized.connect(add_jinja2_ext)
signals.generator_init.connect(create_assets_env)

View File

@@ -0,0 +1,30 @@
GitHub activity
---------------
This plugin makes use of the `feedparser`_ library that you'll need to
install.
Set the ``GITHUB_ACTIVITY_FEED`` parameter to your GitHub activity feed.
For example, to track Pelican project activity, the setting would be::
GITHUB_ACTIVITY_FEED = 'https://github.com/getpelican.atom'
On the template side, you just have to iterate over the ``github_activity``
variable, as in this example::
{% if GITHUB_ACTIVITY_FEED %}
<div class="social">
<h2>Github Activity</h2>
<ul>
{% for entry in github_activity %}
<li><b>{{ entry[0] }}</b><br /> {{ entry[1] }}</li>
{% endfor %}
</ul>
</div><!-- /.github_activity -->
{% endif %}
``github_activity`` is a list of lists. The first element is the title,
and the second element is the raw HTML from GitHub.
.. _feedparser: https://crate.io/packages/feedparser/

View File

@@ -0,0 +1 @@
from .github_activity import *

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# NEEDS WORK
"""
Copyright (c) Marco Milanesi <kpanic@gnufunk.org>
Github Activity
---------------
A plugin to list your Github Activity
"""
from __future__ import unicode_literals, print_function
from pelican import signals
class GitHubActivity():
"""
A class created to fetch github activity with feedparser
"""
def __init__(self, generator):
try:
import feedparser
self.activities = feedparser.parse(
generator.settings['GITHUB_ACTIVITY_FEED'])
except ImportError:
raise Exception("Unable to find feedparser")
def fetch(self):
"""
returns a list of html snippets fetched from github actitivy feed
"""
entries = []
for activity in self.activities['entries']:
entries.append(
[element for element in [activity['title'],
activity['content'][0]['value']]])
return entries
def fetch_github_activity(gen, metadata):
"""
registered handler for the github activity plugin
it puts in generator.context the html needed to be displayed on a
template
"""
if 'GITHUB_ACTIVITY_FEED' in gen.settings.keys():
gen.context['github_activity'] = gen.plugin_instance.fetch()
def feed_parser_initialization(generator):
"""
Initialization of feed parser
"""
generator.plugin_instance = GitHubActivity(generator)
def register():
"""
Plugin registration
"""
signals.article_generator_init.connect(feed_parser_initialization)
signals.article_generate_context.connect(fetch_github_activity)

View File

@@ -0,0 +1,6 @@
Global license
--------------
This plugin allows you to define a ``LICENSE`` setting and adds the contents of that
license variable to the article's context, making that variable available to use
from within your theme's templates.

View File

@@ -0,0 +1 @@
from .global_license import *

View File

@@ -0,0 +1,18 @@
"""
License plugin for Pelican
==========================
This plugin allows you to define a LICENSE setting and adds the contents of that
license variable to the article's context, making that variable available to use
from within your theme's templates.
"""
from pelican import signals
def add_license(generator, metadata):
if 'license' not in metadata.keys()\
and 'LICENSE' in generator.settings.keys():
metadata['license'] = generator.settings['LICENSE']
def register():
signals.article_generate_context.connect(add_license)

View File

@@ -0,0 +1 @@
from .goodreads_activity import *

View File

@@ -1,4 +1,13 @@
# -*- coding: utf-8 -*-
"""
Goodreads Activity
==================
A Pelican plugin to lists books from your Goodreads shelves.
Copyright (c) Talha Mansoor
"""
from __future__ import unicode_literals
from pelican import signals
import feedparser

15
gravatar/Readme.rst Normal file
View File

@@ -0,0 +1,15 @@
Gravatar
--------
This plugin assigns the ``author_gravatar`` variable to the Gravatar URL and
makes the variable available within the article's context. You can add
``AUTHOR_EMAIL`` to your settings file to define the default author's email
address. Obviously, that email address must be associated with a Gravatar
account.
Alternatively, you can provide an email address from within article metadata::
:email: john.doe@example.com
If the email address is defined via at least one of the two methods above,
the ``author_gravatar`` variable is added to the article's context.

1
gravatar/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .gravatar import *

31
gravatar/gravatar.py Normal file
View File

@@ -0,0 +1,31 @@
"""
Gravatar plugin for Pelican
===========================
This plugin assigns the ``author_gravatar`` variable to the Gravatar URL and
makes the variable available within the article's context.
"""
import hashlib
import six
from pelican import signals
def add_gravatar(generator, metadata):
#first check email
if 'email' not in metadata.keys()\
and 'AUTHOR_EMAIL' in generator.settings.keys():
metadata['email'] = generator.settings['AUTHOR_EMAIL']
#then add gravatar url
if 'email' in metadata.keys():
email_bytes = six.b(metadata['email']).lower()
gravatar_url = "http://www.gravatar.com/avatar/" + \
hashlib.md5(email_bytes).hexdigest()
metadata["author_gravatar"] = gravatar_url
def register():
signals.article_generate_context.connect(add_gravatar)

10
gzip_cache/Readme.rst Normal file
View File

@@ -0,0 +1,10 @@
Gzip cache
----------
Certain web servers (e.g., Nginx) can use a static cache of gzip-compressed
files to prevent the server from compressing files during an HTTP call. Since
compression occurs at another time, these compressed files can be compressed
at a higher compression level for increased optimization.
The ``gzip_cache`` plugin compresses all common text type files into a ``.gz``
file within the same directory as the original file.

1
gzip_cache/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .gzip_cache import *

84
gzip_cache/gzip_cache.py Normal file
View File

@@ -0,0 +1,84 @@
'''
Copyright (c) 2012 Matt Layman
Gzip cache
----------
A plugin to create .gz cache files for optimization.
'''
import gzip
import logging
import os
from pelican import signals
logger = logging.getLogger(__name__)
# A list of file types to exclude from possible compression
EXCLUDE_TYPES = [
# Compressed types
'.bz2',
'.gz',
# Audio types
'.aac',
'.flac',
'.mp3',
'.wma',
# Image types
'.gif',
'.jpg',
'.jpeg',
'.png',
# Video types
'.avi',
'.mov',
'.mp4',
]
def create_gzip_cache(pelican):
'''Create a gzip cache file for every file that a webserver would
reasonably want to cache (e.g., text type files).
:param pelican: The Pelican instance
'''
for dirpath, _, filenames in os.walk(pelican.settings['OUTPUT_PATH']):
for name in filenames:
if should_compress(name):
filepath = os.path.join(dirpath, name)
create_gzip_file(filepath)
def should_compress(filename):
'''Check if the filename is a type of file that should be compressed.
:param filename: A file name to check against
'''
for extension in EXCLUDE_TYPES:
if filename.endswith(extension):
return False
return True
def create_gzip_file(filepath):
'''Create a gzipped file in the same directory with a filepath.gz name.
:param filepath: A file to compress
'''
compressed_path = filepath + '.gz'
with open(filepath, 'rb') as uncompressed:
try:
logger.debug('Compressing: %s' % filepath)
compressed = gzip.open(compressed_path, 'wb')
compressed.writelines(uncompressed)
except Exception as ex:
logger.critical('Gzip compression failed: %s' % ex)
finally:
compressed.close()
def register():
signals.finalized.connect(create_gzip_cache)

View File

@@ -0,0 +1,45 @@
HTML tags for reStructuredText
------------------------------
This plugin allows you to use HTML tags from within reST documents.
Directives
----------
::
.. html::
(HTML code)
Example
-------
A search engine::
.. html::
<form action="http://seeks.fr/search" method="GET">
<input type="text" value="Pelican v2" title="Search" maxlength="2048" name="q" autocomplete="on" />
<input type="hidden" name="lang" value="en" />
<input type="submit" value="Seeks !" id="search_button" />
</form>
A contact form::
.. html::
<form method="GET" action="mailto:some email">
<p>
<input type="text" placeholder="Subject" name="subject">
<br />
<textarea name="body" placeholder="Message">
</textarea>
<br />
<input type="reset"><input type="submit">
</p>
</form>

View File

@@ -0,0 +1 @@
from .html_rst_directive import *

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
"""
HTML tags for reStructuredText
==============================
This plugin allows you to use HTML tags from within reST documents.
"""
from __future__ import unicode_literals
from docutils import nodes
from docutils.parsers.rst import directives, Directive
class RawHtml(Directive):
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = True
has_content = True
def run(self):
html = ' '.join(self.content)
node = nodes.raw('', html, format='html')
return [node]
def register():
directives.register_directive('html', RawHtml)

1
latex/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .latex import *

47
latex/latex.py Normal file
View File

@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
"""
Latex Plugin For Pelican
========================
This plugin allows you to write mathematical equations in your articles using Latex.
It uses the MathJax Latex JavaScript library to render latex that is embedded in
between `$..$` for inline math and `$$..$$` for displayed math. It also allows for
writing equations in by using `\begin{equation}`...`\end{equation}`.
"""
from pelican import signals
latexScript = """
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type= "text/javascript">
MathJax.Hub.Config({
config: ["MMLorHTML.js"],
jax: ["input/TeX","input/MathML","output/HTML-CSS","output/NativeMML"],
TeX: { extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"], equationNumbers: { autoNumber: "AMS" } },
extensions: ["tex2jax.js","mml2jax.js","MathMenu.js","MathZoom.js"],
tex2jax: {
inlineMath: [ [\'$\',\'$\'] ],
displayMath: [ [\'$$\',\'$$\'] ],
processEscapes: true },
"HTML-CSS": {
styles: { ".MathJax .mo, .MathJax .mi": {color: "black ! important"}}
}
});
</script>
"""
def addLatex(gen, metadata):
"""
The registered handler for the latex plugin. It will add
the latex script to the article metadata
"""
if 'LATEX' in gen.settings.keys() and gen.settings['LATEX'] == 'article':
if 'latex' in metadata.keys():
metadata['latex'] = latexScript
else:
metadata['latex'] = latexScript
def register():
"""
Plugin registration
"""
signals.article_generate_context.connect(addLatex)

View File

@@ -7,7 +7,9 @@ In order to mark posts as part of a multi-part post, use the `:parts:` metadata:
:parts: MY_AWESOME_MULTI_PART_POST
You can then use the `article.related_posts` variable in your templates to display other parts of current post.
You can then use the `article.metadata.parts_articles` variable in your templates
to display other parts of current post.
For example:
{% if article.metadata.parts_articles %}

1
multi_part/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .multi_part import *

View File

@@ -6,33 +6,8 @@ Multiple part support
=====================
Create a navigation menu for multi-part related_posts
Article metadata:
------------------
:parts: a unique identifier for multi-part posts, must be the same in each
post part.
Usage
-----
{% if article.metadata.parts_articles %}
<ol>
{% for part_article in article.metadata.parts_articles %}
{% if part_article == article %}
<li>
<a href='{{ SITEURL }}/{{ part_article.url }}'><b>{{ part_article.title }}</b>
</a>
</li>
{% else %}
<li>
<a href='{{ SITEURL }}/{{ part_article.url }}'>{{ part_article.title }}
</a>
</li>
{% endif %}
{% endfor %}
</ol>
{% endif %}
"""
from collections import defaultdict
from pelican import signals

View File

@@ -4,23 +4,6 @@ Neighbor Articles Plugin for Pelican
This plugin adds ``next_article`` (newer) and ``prev_article`` (older)
variables to the article's context
Installation
------------
To enable, ensure that ``neighbors.py`` is in somewhere you can ``import``.
Then use the following in your `settings`::
PLUGINS = ["neighbors"]
Or you can put the plugin in ``plugins`` folder in pelican installation. You
can find the location by typing::
python -c 'import pelican.plugins as p, os; print os.path.dirname(p.__file__)'
Once you get the folder, copy the ``neighbors.py`` there and use the following
in your settings::
PLUGINS = ["pelican.plugins.neighbors"]
Usage
-----
@@ -41,4 +24,4 @@ Usage
</a>
</li>
{% endif %}
</ul>
</ul>

1
neighbors/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .neighbors import *

View File

@@ -1,112 +0,0 @@
# -*- coding: utf-8 -*-
"""
Latex Plugin For Pelican
========================
This plugin allows you to write mathematical equations in your articles using Latex.
It uses the MathJax Latex JavaScript library to render latex that is embedded in
between `$..$` for inline math and `$$..$$` for displayed math. It also allows for
writing equations in by using `\begin{equation}`...`\end{equation}`.
Installation
------------
To enable, ensure that `latex.py` is put somewhere that is accessible.
Then use as follows by adding the following to your settings.py:
PLUGINS = ["latex"]
Be careful: Not loading the plugin is easy to do, and difficult to detect. To
make life easier, find where pelican is installed, and then copy the plugin
there. An easy way to find where pelican is installed is to verbose list the
available themes by typing `pelican-themes -l -v`.
Once the pelican folder is found, copy `latex.py` to the `plugins` folder. Then
add to settings.py like this:
PLUGINS = ["pelican.plugins.latex"]
Now all that is left to do is to embed the following to your template file
between the `<head>` parameters (for the NotMyIdea template, this file is base.html)
{% if article and article.latex %}
{{ article.latex }}
{% endif %}
Usage
-----
Latex will be embedded in every article. If however you want latex only for
selected articles, then in settings.py, add
LATEX = 'article'
And in each article, add the metadata key `latex:`. For example, with the above
settings, creating an article that I want to render latex math, I would just
include 'Latex' as part of the metadata without any value:
Date: 1 sep 2012
Status: draft
Latex:
Latex Examples
--------------
###Inline
Latex between `$`..`$`, for example, `$`x^2`$`, will be rendered inline
with respect to the current html block.
###Displayed Math
Latex between `$$`..`$$`, for example, `$$`x^2`$$`, will be rendered centered in a
new paragraph.
###Equations
Latex between `\begin` and `\end`, for example, `begin{equation}` x^2 `\end{equation}`,
will be rendered centered in a new paragraph with a right justified equation number
at the top of the paragraph. This equation number can be referenced in the document.
To do this, use a `label` inside of the equation format and then refer to that label
using `ref`. For example: `begin{equation}` `\label{eq}` X^2 `\end{equation}`. Now
refer to that equation number by `$`\ref{eq}`$`.
Template And Article Examples
-----------------------------
To see an example of this plugin in action, look at
[this article](http://doctrina.org/How-RSA-Works-With-Examples.html). To see how
this plugin works with a template, look at
[this template](https://github.com/barrysteyn/pelican_theme-personal_blog).
"""
from pelican import signals
latexScript = """
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type= "text/javascript">
MathJax.Hub.Config({
config: ["MMLorHTML.js"],
jax: ["input/TeX","input/MathML","output/HTML-CSS","output/NativeMML"],
TeX: { extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"], equationNumbers: { autoNumber: "AMS" } },
extensions: ["tex2jax.js","mml2jax.js","MathMenu.js","MathZoom.js"],
tex2jax: {
inlineMath: [ [\'$\',\'$\'] ],
displayMath: [ [\'$$\',\'$$\'] ],
processEscapes: true },
"HTML-CSS": {
styles: { ".MathJax .mo, .MathJax .mi": {color: "black ! important"}}
}
});
</script>
"""
def addLatex(gen, metadata):
"""
The registered handler for the latex plugin. It will add
the latex script to the article metadata
"""
if 'LATEX' in gen.settings.keys() and gen.settings['LATEX'] == 'article':
if 'latex' in metadata.keys():
metadata['latex'] = latexScript
else:
metadata['latex'] = latexScript
def register():
"""
Plugin registration
"""
signals.article_generate_context.connect(addLatex)

View File

@@ -1,36 +0,0 @@
Random Article Plugin For Pelican
========================
This plugin generates a html file which redirect to a random article
using javascript's window.location. The generated html file is
saved at SITEURL.
Only published articles are listed to redirect.
Installation
------------
To enable, ensure that `random_article.py` is put somewhere that is accessible.
Then use as follows by adding the following to your settings.py:
PLUGINS = ["random_article"]
An easy way to find where pelican is installed is to verbose list the
available themes by typing `pelican-themes -l -v`.
Once the pelican folder is found, copy `random_article.py` to the `plugins` folder. Then
add to settings.py like this:
PLUGINS = ["pelican.plugins.random_article"]
Usage
-----
To use it you have to add in your config file the name of the file to use:
RANDOM = 'random.html'
Then in some template you add:
<a href="{{ SITEURL }}/{{ RANDOM }}">random article</a>

19
random_article/Readme.md Normal file
View File

@@ -0,0 +1,19 @@
Random Article Plugin For Pelican
========================
This plugin generates a html file which redirect to a random article
using javascript's `window.location`. The generated html file is
saved at `SITEURL`.
Only published articles are listed to redirect.
Usage
-----
To use it you have to add in your config file the name of the file to use:
RANDOM = 'random.html'
Then in some template you add:
<a href="{{ SITEURL }}/{{ RANDOM }}">random article</a>

View File

@@ -0,0 +1 @@
from .random_article import *

View File

@@ -1,4 +1,13 @@
# -*- coding: utf-8 -*-
"""
Random Article Plugin For Pelican
========================
This plugin generates a html file which redirect to a random article
using javascript's window.location. The generated html file is
saved at SITEURL.
"""
from __future__ import unicode_literals
import os.path

19
related_posts/Readme.rst Normal file
View File

@@ -0,0 +1,19 @@
Related posts
-------------
This plugin adds the ``related_posts`` variable to the article's context.
By default, up to 5 articles are listed. You can customize this value by
defining ``RELATED_POSTS_MAX`` in your settings file::
RELATED_POSTS_MAX = 10
You can then use the ``article.related_posts`` variable in your templates.
For example::
{% if article.related_posts %}
<ul>
{% for related_post in article.related_posts %}
<li><a href="{{ SITEURL }}/{{ related_post.url }}">{{ related_post.title }}</a></li>
{% endfor %}
</ul>
{% endif %}

View File

@@ -0,0 +1 @@
from .related_posts import *

View File

@@ -0,0 +1,35 @@
"""
Related posts plugin for Pelican
================================
Adds related_posts variable to article's context
"""
from pelican import signals
from collections import Counter
def add_related_posts(generator):
# get the max number of entries from settings
# or fall back to default (5)
numentries = generator.settings.get('RELATED_POSTS_MAX', 5)
for article in generator.articles:
# no tag, no relation
if not hasattr(article, 'tags'):
continue
# score = number of common tags
scores = Counter()
for tag in article.tags:
scores += Counter(generator.tags[tag])
# remove itself
scores.pop(article)
article.related_posts = [other for other, count
in scores.most_common(numentries)]
def register():
signals.article_generator_finalized.connect(add_related_posts)

65
sitemap/Readme.rst Normal file
View File

@@ -0,0 +1,65 @@
Sitemap
-------
The sitemap plugin generates plain-text or XML sitemaps. You can use the
``SITEMAP`` variable in your settings file to configure the behavior of the
plugin.
The ``SITEMAP`` variable must be a Python dictionary and can contain three keys:
- ``format``, which sets the output format of the plugin (``xml`` or ``txt``)
- ``priorities``, which is a dictionary with three keys:
- ``articles``, the priority for the URLs of the articles and their
translations
- ``pages``, the priority for the URLs of the static pages
- ``indexes``, the priority for the URLs of the index pages, such as tags,
author pages, categories indexes, archives, etc...
All the values of this dictionary must be decimal numbers between ``0`` and ``1``.
- ``changefreqs``, which is a dictionary with three items:
- ``articles``, the update frequency of the articles
- ``pages``, the update frequency of the pages
- ``indexes``, the update frequency of the index pages
Valid frequency values are ``always``, ``hourly``, ``daily``, ``weekly``, ``monthly``,
``yearly`` and ``never``.
If a key is missing or a value is incorrect, it will be replaced with the
default value.
The sitemap is saved in ``<output_path>/sitemap.<format>``.
.. note::
``priorities`` and ``changefreqs`` are information for search engines.
They are only used in the XML sitemaps.
For more information: <http://www.sitemaps.org/protocol.html#xmlTagDefinitions>
**Example**
Here is an example configuration (it's also the default settings):
.. code-block:: python
PLUGINS=['pelican.plugins.sitemap',]
SITEMAP = {
'format': 'xml',
'priorities': {
'articles': 0.5,
'indexes': 0.5,
'pages': 0.5
},
'changefreqs': {
'articles': 'monthly',
'indexes': 'daily',
'pages': 'monthly'
}
}

1
sitemap/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .sitemap import *

View File

@@ -1,4 +1,11 @@
# -*- coding: utf-8 -*-
'''
Sitemap
-------
The sitemap plugin generates plain-text or XML sitemaps.
'''
from __future__ import unicode_literals
import collections

27
summary/Readme.rst Normal file
View File

@@ -0,0 +1,27 @@
Summary
-------
This plugin allows easy, variable length summaries directly embedded into the
body of your articles. It introduces two new settings: ``SUMMARY_BEGIN_MARKER``
and ``SUMMARY_END_MARKER``: strings which can be placed directly into an article
to mark the beginning and end of a summary. When found, the standard
``SUMMARY_MAX_LENGTH`` setting will be ignored. The markers themselves will also
be removed from your articles before they are published. The default values
are ``<!-- PELICAN_BEGIN_SUMMARY -->`` and ``<!-- PELICAN_END_SUMMARY -->``.
For example::
Title: My super title
Date: 2010-12-03 10:20
Tags: thats, awesome
Category: yeah
Slug: my-super-post
Author: Alexis Metaireau
This is the content of my super blog post.
<!-- PELICAN_END_SUMMARY -->
and this content occurs after the summary.
Here, the summary is taken to be the first line of the post. Because no
beginning marker was found, it starts at the top of the body. It is possible
to leave out the end marker instead, in which case the summary will start at the
beginning marker and continue to the end of the body.

1
summary/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .summary import *

61
summary/summary.py Normal file
View File

@@ -0,0 +1,61 @@
"""
Summary
-------
This plugin allows easy, variable length summaries directly embedded into the
body of your articles.
"""
import types
from pelican import signals
def initialized(pelican):
from pelican.settings import _DEFAULT_CONFIG
_DEFAULT_CONFIG.setdefault('SUMMARY_BEGIN_MARKER',
'<!-- PELICAN_BEGIN_SUMMARY -->')
_DEFAULT_CONFIG.setdefault('SUMMARY_END_MARKER',
'<!-- PELICAN_END_SUMMARY -->')
if pelican:
pelican.settings.setdefault('SUMMARY_BEGIN_MARKER',
'<!-- PELICAN_BEGIN_SUMMARY -->')
pelican.settings.setdefault('SUMMARY_END_MARKER',
'<!-- PELICAN_END_SUMMARY -->')
def content_object_init(instance):
# if summary is already specified, use it
if 'summary' in instance.metadata:
return
def _get_content(self):
content = self._content
if self.settings['SUMMARY_BEGIN_MARKER']:
content = content.replace(
self.settings['SUMMARY_BEGIN_MARKER'], '', 1)
if self.settings['SUMMARY_END_MARKER']:
content = content.replace(
self.settings['SUMMARY_END_MARKER'], '', 1)
return content
instance._get_content = types.MethodType(_get_content, instance)
# extract out our summary
if not hasattr(instance, '_summary') and instance._content is not None:
content = instance._content
begin_summary = -1
end_summary = -1
if instance.settings['SUMMARY_BEGIN_MARKER']:
begin_summary = content.find(instance.settings['SUMMARY_BEGIN_MARKER'])
if instance.settings['SUMMARY_END_MARKER']:
end_summary = content.find(instance.settings['SUMMARY_END_MARKER'])
if begin_summary != -1 or end_summary != -1:
# the beginning position has to take into account the length
# of the marker
begin_summary = (begin_summary +
len(instance.settings['SUMMARY_BEGIN_MARKER'])
if begin_summary != -1 else 0)
end_summary = end_summary if end_summary != -1 else None
instance._summary = content[begin_summary:end_summary]
def register():
signals.initialized.connect(initialized)
signals.content_object_init.connect(content_object_init)

13
tests/Readme.rst Normal file
View File

@@ -0,0 +1,13 @@
Test Data
---------
Place tests for your plugin here. ``test_data`` folder contains following
common data for your tests, if you need them.
=============== ===========================
File/Folder Description
=============== ===========================
content A sample content folder
themes Default themes from Pelican
pelican.conf.py A sample settings file
=============== ===========================

2
tests/__init__.py Normal file
View File

@@ -0,0 +1,2 @@
import logging
logging.getLogger().addHandler(logging.NullHandler())

142
tests/test_assets.py Normal file
View File

@@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-
# from __future__ import unicode_literals
import hashlib
import locale
import os
from codecs import open
from tempfile import mkdtemp
from shutil import rmtree
import unittest
import subprocess
from pelican import Pelican
from pelican.settings import read_settings
CUR_DIR = os.path.dirname(__file__)
THEME_DIR = os.path.join(CUR_DIR, 'test_data', 'themes', 'assets_theme')
CSS_REF = open(os.path.join(THEME_DIR, 'static', 'css',
'style.min.css')).read()
CSS_HASH = hashlib.md5(CSS_REF).hexdigest()[0:8]
def skipIfNoExecutable(executable):
"""Skip test if `executable` is not found
Tries to run `executable` with subprocess to make sure it's in the path,
and skips the tests if not found (if subprocess raises a `OSError`).
"""
with open(os.devnull, 'w') as fnull:
try:
res = subprocess.call(executable, stdout=fnull, stderr=fnull)
except OSError:
res = None
if res is None:
return unittest.skip('{0} executable not found'.format(executable))
return lambda func: func
def module_exists(module_name):
"""Test if a module is importable."""
try:
__import__(module_name)
except ImportError:
return False
else:
return True
@unittest.skipUnless(module_exists('webassets'), "webassets isn't installed")
@skipIfNoExecutable(['scss', '-v'])
@skipIfNoExecutable(['cssmin', '--version'])
class TestWebAssets(unittest.TestCase):
"""Base class for testing webassets."""
def setUp(self, override=None):
import assets
self.temp_path = mkdtemp(prefix='pelicantests.')
settings = {
'PATH': os.path.join(CUR_DIR, 'test_data', 'content'),
'OUTPUT_PATH': self.temp_path,
'PLUGINS': [assets],
'THEME': THEME_DIR,
'LOCALE': locale.normalize('en_US'),
}
if override:
settings.update(override)
self.settings = read_settings(override=settings)
pelican = Pelican(settings=self.settings)
pelican.run()
def tearDown(self):
rmtree(self.temp_path)
def check_link_tag(self, css_file, html_file):
"""Check the presence of `css_file` in `html_file`."""
link_tag = ('<link rel="stylesheet" href="{css_file}">'
.format(css_file=css_file))
html = open(html_file).read()
self.assertRegexpMatches(html, link_tag)
class TestWebAssetsRelativeURLS(TestWebAssets):
"""Test pelican with relative urls."""
def setUp(self):
TestWebAssets.setUp(self, override={'RELATIVE_URLS': True})
def test_jinja2_ext(self):
# Test that the Jinja2 extension was correctly added.
from webassets.ext.jinja2 import AssetsExtension
self.assertIn(AssetsExtension, self.settings['JINJA_EXTENSIONS'])
def test_compilation(self):
# Compare the compiled css with the reference.
gen_file = os.path.join(self.temp_path, 'theme', 'gen',
'style.{0}.min.css'.format(CSS_HASH))
self.assertTrue(os.path.isfile(gen_file))
css_new = open(gen_file).read()
self.assertEqual(css_new, CSS_REF)
def test_template(self):
# Look in the output files for the link tag.
css_file = './theme/gen/style.{0}.min.css'.format(CSS_HASH)
html_files = ['index.html', 'archives.html',
'this-is-a-super-article.html']
for f in html_files:
self.check_link_tag(css_file, os.path.join(self.temp_path, f))
self.check_link_tag(
'../theme/gen/style.{0}.min.css'.format(CSS_HASH),
os.path.join(self.temp_path, 'category/yeah.html'))
class TestWebAssetsAbsoluteURLS(TestWebAssets):
"""Test pelican with absolute urls."""
def setUp(self):
TestWebAssets.setUp(self, override={'RELATIVE_URLS': False,
'SITEURL': 'http://localhost'})
def test_absolute_url(self):
# Look in the output files for the link tag with absolute url.
css_file = ('http://localhost/theme/gen/style.{0}.min.css'
.format(CSS_HASH))
html_files = ['index.html', 'archives.html',
'this-is-a-super-article.html']
for f in html_files:
self.check_link_tag(css_file, os.path.join(self.temp_path, f))

View File

@@ -0,0 +1,4 @@
FILENAME_METADATA example
#########################
Some cool stuff!

View File

@@ -0,0 +1,7 @@
Trop bien !
###########
:lang: fr
:slug: oh-yeah
Et voila du contenu en français

View File

@@ -0,0 +1,20 @@
Oh yeah !
#########
:tags: oh, bar, yeah
:date: 2010-10-20 10:14
:category: bar
:author: Alexis Métaireau
:slug: oh-yeah
:license: WTFPL
Why not ?
=========
After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !
.. image:: |filename|/pictures/Sushi.jpg
:height: 450 px
:width: 600 px
:alt: alternate text

View File

@@ -0,0 +1,9 @@
Deuxième article
################
:tags: foo, bar, baz
:date: 2012-02-29
:lang: fr
:slug: second-article
Ceci est un article, en français.

View File

@@ -0,0 +1,9 @@
Second article
##############
:tags: foo, bar, baz
:date: 2012-02-29
:lang: en
:slug: second-article
This is some article, in english

View File

@@ -0,0 +1,7 @@
Article 1
#########
:date: 2011-02-17
:yeah: oh yeah !
Article 1

View File

@@ -0,0 +1,6 @@
Article 2
#########
:date: 2011-02-17
Article 2

View File

@@ -0,0 +1,6 @@
Article 3
#########
:date: 2011-02-17
Article 3

View File

@@ -0,0 +1,7 @@
Title: A markdown powered article
Date: 2011-04-20
You're mutually oblivious.
[a root-relative link to unbelievable](|filename|/unbelievable.rst)
[a file-relative link to unbelievable](|filename|../unbelievable.rst)

View File

@@ -0,0 +1,7 @@
A draft article
###############
:status: draft
This is a draft article, it should live under the /drafts/ folder and not be
listed anywhere else.

View File

@@ -0,0 +1,2 @@
User-agent: *
Disallow: /static/pictures

View File

@@ -0,0 +1,9 @@
This is a test hidden page
##########################
:category: test
:status: hidden
This is great for things like error(404) pages
Anyone can see this page but it's not linked to anywhere!

View File

@@ -0,0 +1,6 @@
{% extends "base.html" %}
{% block content %}
Some text
{% endblock %}

View File

@@ -0,0 +1,9 @@
Override url/save_as
####################
:date: 2012-12-07
:url: override/
:save_as: override/index.html
Test page which overrides save_as and url so that this page will be generated
at a custom location.

View File

@@ -0,0 +1,12 @@
This is a test page
###################
:category: test
Just an image.
.. image:: |filename|/pictures/Fat_Cat.jpg
:height: 450 px
:width: 600 px
:alt: alternate text

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,36 @@
This is a super article !
#########################
:tags: foo, bar, foobar
:date: 2010-12-02 10:14
:category: yeah
:author: Alexis Métaireau
:summary:
Multi-line metadata should be supported
as well as **inline markup**.
Some content here !
This is a simple title
======================
And here comes the cool stuff_.
.. image:: |filename|/pictures/Sushi.jpg
:height: 450 px
:width: 600 px
:alt: alternate text
.. image:: |filename|/pictures/Sushi_Macro.jpg
:height: 450 px
:width: 600 px
:alt: alternate text
::
>>> from ipdb import set_trace
>>> set_trace()
→ And now try with some utf8 hell: ééé
.. _stuff: http://books.couchdb.org/relax/design-documents/views

View File

@@ -0,0 +1,9 @@
Unbelievable !
##############
:date: 2010-10-15 20:30
Or completely awesome. Depends the needs.
`a root-relative link to markdown-article <|filename|/cat1/markdown-article.md>`_
`a file-relative link to markdown-article <|filename|cat1/markdown-article.md>`_

View File

@@ -0,0 +1 @@
not to be parsed

45
tests/test_data/pelican.conf.py Executable file
View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
AUTHOR = 'Alexis Métaireau'
SITENAME = "Alexis' log"
SITEURL = 'http://blog.notmyidea.org'
TIMEZONE = "Europe/Paris"
GITHUB_URL = 'http://github.com/ametaireau/'
DISQUS_SITENAME = "blog-notmyidea"
PDF_GENERATOR = False
REVERSE_CATEGORY_ORDER = True
LOCALE = "C"
DEFAULT_PAGINATION = 4
DEFAULT_DATE = (2012, 3, 2, 14, 1, 1)
FEED_ALL_RSS = 'feeds/all.rss.xml'
CATEGORY_FEED_RSS = 'feeds/%s.rss.xml'
LINKS = (('Biologeek', 'http://biologeek.org'),
('Filyb', "http://filyb.info/"),
('Libert-fr', "http://www.libert-fr.com"),
('N1k0', "http://prendreuncafe.com/blog/"),
('Tarek Ziadé', "http://ziade.org/blog"),
('Zubin Mithra', "http://zubin71.wordpress.com/"),)
SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
('lastfm', 'http://lastfm.com/user/akounet'),
('github', 'http://github.com/ametaireau'),)
# global metadata to all the contents
DEFAULT_METADATA = (('yeah', 'it is'),)
# static paths will be copied under the same name
STATIC_PATHS = ["pictures", ]
# A list of files to copy from the source to the destination
FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),)
# custom page generated with a jinja2 template
TEMPLATE_PAGES = {'pages/jinja2_template.html': 'jinja2_template.html'}
# foobar will not be used, because it's not in caps. All configuration keys
# have to be in caps
foobar = "barbaz"

View File

@@ -0,0 +1 @@
body{font:14px/1.5 "Droid Sans",sans-serif;background-color:#e4e4e4;color:#242424}a{color:red}a:hover{color:orange}

View File

@@ -0,0 +1,19 @@
/* -*- scss-compile-at-save: nil -*- */
$baseFontFamily : "Droid Sans", sans-serif;
$textColor : #242424;
$bodyBackground : #e4e4e4;
body {
font: 14px/1.5 $baseFontFamily;
background-color: $bodyBackground;
color: $textColor;
}
a {
color: red;
&:hover {
color: orange;
}
}

View File

@@ -0,0 +1,7 @@
{% extends "!simple/base.html" %}
{% block head %}
{% assets filters="scss,cssmin", output="gen/style.%(version)s.min.css", "css/style.scss" %}
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
{% endassets %}
{% endblock %}

View File

@@ -0,0 +1,446 @@
/*
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");
@import url("pygment.css");
@import url("typogrify.css");
@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin);
/***** Global *****/
/* Body */
body {
background: #F5F4EF;
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 */
h1 {font-size: 2em }
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 */
h1, h2, h3, h4, h5, h6 {
font-weight: 400;
line-height: 1.1;
margin-bottom: .8em;
font-family: 'Yanone Kaffeesatz', arial, serif;
}
h3, h4, h5, h6 { margin-top: .8em; }
hr { border: 2px solid #EEEEEE; }
/* 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;
}
h1 a:hover {
background-color: inherit
}
/* Paragraphs */
div.line-block,
p { margin-top: 1em;
margin-bottom: 1em;}
strong, b {font-weight: bold;}
em, i {font-style: italic;}
/* Lists */
ul {
list-style: outside disc;
margin: 0em 0 0 1.5em;
}
ol {
list-style: outside decimal;
margin: 0em 0 0 1.5em;
}
li { margin-top: 0.5em;}
.post-info {
float:right;
margin:10px;
padding:5px;
}
.post-info p{
margin-top: 1px;
margin-bottom: 1px;
}
.readmore { float: right }
dl {margin: 0 0 1.5em 0;}
dt {font-weight: bold;}
dd {margin-left: 1.5em;}
pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;}
/* Quotes */
blockquote {
margin: 20px;
font-style: italic;
}
cite {}
q {}
div.note {
float: right;
margin: 5px;
font-size: 85%;
max-width: 300px;
}
/* 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: left; margin: 0 2em 2em 0;}
/*
Header
*****************/
#banner {
margin: 0 auto;
padding: 2.5em 0 0 0;
}
/* Banner */
#banner h1 {font-size: 3.571em; line-height: 0;}
#banner h1 a:link, #banner h1 a:visited {
color: #000305;
display: block;
font-weight: bold;
margin: 0 0 .6em .2em;
text-decoration: none;
}
#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 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*='about.me'] {background-image: url('../images/icons/aboutme.png');}
.social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');}
.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*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');}
.social a[href*='github.com'],
.social a[href*='git.io'] {background-image: url('../images/icons/github.png');}
.social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');}
.social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');}
.social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');}
.social a[href*='news.ycombinator.com'],
.social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');}
.social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');}
.social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');}
.social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');}
.social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');}
.social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');}
.social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');}
.social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');}
.social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');}
.social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.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 {
display: block;
clear: both;
border-bottom: 1px solid #eee;
padding: 1.5em 0;
}
li:last-child .hentry, #content > .hentry {border: 0; margin: 0;}
#content > .hentry {padding: 1em 0;}
.hentry img{display : none ;}
.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;}
.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;}
.entry-title a:visited {background-color: #fff;}
.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: 10px; position: relative;}
#posts-list footer {
left: 10px;
position: relative;
float: left;
top: 0.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,205 @@
.hll {
background-color:#eee;
}
.c {
color:#408090;
font-style:italic;
}
.err {
border:1px solid #FF0000;
}
.k {
color:#007020;
font-weight:bold;
}
.o {
color:#666666;
}
.cm {
color:#408090;
font-style:italic;
}
.cp {
color:#007020;
}
.c1 {
color:#408090;
font-style:italic;
}
.cs {
background-color:#FFF0F0;
color:#408090;
}
.gd {
color:#A00000;
}
.ge {
font-style:italic;
}
.gr {
color:#FF0000;
}
.gh {
color:#000080;
font-weight:bold;
}
.gi {
color:#00A000;
}
.go {
color:#303030;
}
.gp {
color:#C65D09;
font-weight:bold;
}
.gs {
font-weight:bold;
}
.gu {
color:#800080;
font-weight:bold;
}
.gt {
color:#0040D0;
}
.kc {
color:#007020;
font-weight:bold;
}
.kd {
color:#007020;
font-weight:bold;
}
.kn {
color:#007020;
font-weight:bold;
}
.kp {
color:#007020;
}
.kr {
color:#007020;
font-weight:bold;
}
.kt {
color:#902000;
}
.m {
color:#208050;
}
.s {
color:#4070A0;
}
.na {
color:#4070A0;
}
.nb {
color:#007020;
}
.nc {
color:#0E84B5;
font-weight:bold;
}
.no {
color:#60ADD5;
}
.nd {
color:#555555;
font-weight:bold;
}
.ni {
color:#D55537;
font-weight:bold;
}
.ne {
color:#007020;
}
.nf {
color:#06287E;
}
.nl {
color:#002070;
font-weight:bold;
}
.nn {
color:#0E84B5;
font-weight:bold;
}
.nt {
color:#062873;
font-weight:bold;
}
.nv {
color:#BB60D5;
}
.ow {
color:#007020;
font-weight:bold;
}
.w {
color:#BBBBBB;
}
.mf {
color:#208050;
}
.mh {
color:#208050;
}
.mi {
color:#208050;
}
.mo {
color:#208050;
}
.sb {
color:#4070A0;
}
.sc {
color:#4070A0;
}
.sd {
color:#4070A0;
font-style:italic;
}
.s2 {
color:#4070A0;
}
.se {
color:#4070A0;
font-weight:bold;
}
.sh {
color:#4070A0;
}
.si {
color:#70A0D0;
font-style:italic;
}
.sx {
color:#C65D09;
}
.sr {
color:#235388;
}
.s1 {
color:#4070A0;
}
.ss {
color:#517918;
}
.bp {
color:#007020;
}
.vc {
color:#BB60D5;
}
.vg {
color:#BB60D5;
}
.vi {
color:#BB60D5;
}
.il {
color:#208050;
}

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;
}

View File

@@ -0,0 +1,3 @@
.caps {font-size:.92em;}
.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;}
.dquo {margin-left:-.38em;}

View File

@@ -0,0 +1,48 @@
@import url("main.css");
body {
font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif;
}
.post-info{
display: none;
}
#banner nav {
display: none;
-moz-border-radius: 0px;
margin-bottom: 20px;
overflow: hidden;
font-size: 1em;
background: #F5F4EF;
}
#banner nav ul{
padding-right: 50px;
}
#banner nav li{
float: right;
color: #000;
}
#banner nav li a {
color: #000;
}
#banner h1 {
margin-bottom: -18px;
}
#featured, #extras {
padding: 50px;
}
#featured {
padding-top: 20px;
}
#extras {
padding-top: 0px;
padding-bottom: 0px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Some files were not shown because too many files have changed in this diff Show More