Merge branch 'master' of git://github.com/ametaireau/pelican
Conflicts: docs/settings.rst pelican/generators.py pelican/settings.py
5
.gitignore
vendored
|
|
@ -2,3 +2,8 @@
|
||||||
.*.swp
|
.*.swp
|
||||||
.*.swo
|
.*.swo
|
||||||
*.pyc
|
*.pyc
|
||||||
|
docs/_build
|
||||||
|
docs/fr/_build
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
output
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ Heh, you didn't noticed? "Pelican" is an anagram for "Calepin" ;)
|
||||||
Source code
|
Source code
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
You can access the source code via mercurial at http://hg.notmyidea.org/pelican/
|
You can access the source code via git on http://github.com/ametaireau/pelican/
|
||||||
or via git on http://github.com/ametaireau/pelican/
|
|
||||||
|
|
||||||
If you feel hackish, have a look to the `pelican's internals explanations
|
If you feel hackish, have a look to the `pelican's internals explanations
|
||||||
<http://alexis.notmyidea.org/pelican/internals.html>`_.
|
<http://alexis.notmyidea.org/pelican/internals.html>`_.
|
||||||
|
|
|
||||||
4
THANKS
|
|
@ -10,3 +10,7 @@ bugs or giving ideas. Thanks to them !
|
||||||
- David Kulak
|
- David Kulak
|
||||||
- Arnaud Bos
|
- Arnaud Bos
|
||||||
- nblock (Florian)
|
- nblock (Florian)
|
||||||
|
- Bruno Bord
|
||||||
|
- Laureline Guérin
|
||||||
|
- Samuel Martin
|
||||||
|
- Marcus Fredriksson
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,15 @@ import sys, os
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
extensions = ['sphinx.ext.autodoc',]
|
||||||
source_suffix = '.rst'
|
source_suffix = '.rst'
|
||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
project = u'Pelican'
|
project = u'Pelican'
|
||||||
copyright = u'2010, Alexis Metaireau'
|
copyright = u'2010, Alexis Metaireau and contributors'
|
||||||
exclude_patterns = ['_build']
|
exclude_patterns = ['_build']
|
||||||
pygments_style = 'sphinx'
|
pygments_style = 'sphinx'
|
||||||
|
version = "2"
|
||||||
|
release = version
|
||||||
|
|
||||||
# -- Options for HTML output ---------------------------------------------------
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
38
docs/faq.rst
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
Frequently Asked Questions (FAQ)
|
||||||
|
################################
|
||||||
|
|
||||||
|
Here is a summary of the frequently asked questions for pelican.
|
||||||
|
|
||||||
|
Is it mandatory to have a configuration file ?
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
No, it's not. Configurations files are just an easy way to configure pelican.
|
||||||
|
For the basic operations, it's possible to specify options while invoking
|
||||||
|
pelican with the command line (see `pelican --help` for more informations about
|
||||||
|
that)
|
||||||
|
|
||||||
|
I'm creating my own theme, how to use pygments ?
|
||||||
|
================================================
|
||||||
|
|
||||||
|
Pygment add some classes to the generated content, so the theming of your theme
|
||||||
|
will be done thanks to a css file. You can have a look to the one proposed by
|
||||||
|
default `on the project website <http://pygments.org/demo/15101/>`_
|
||||||
|
|
||||||
|
How do I create my own theme ?
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Please refer yourself to :ref:`theming-pelican`.
|
||||||
|
|
||||||
|
How can I help ?
|
||||||
|
================
|
||||||
|
|
||||||
|
You have different options to help. First, you can use pelican, and report any
|
||||||
|
idea or problem you have on `the bugtracker
|
||||||
|
<http://github.com/ametaireau/pelican/issues>`_.
|
||||||
|
|
||||||
|
If you want to contribute, please have a look to `the git repository
|
||||||
|
<https://github.com/ametaireau/pelican/>`_, fork it, add your changes and do
|
||||||
|
a pull request, I'll review them as soon as possible.
|
||||||
|
|
||||||
|
You can also contribute by creating themes, and making the documentation
|
||||||
|
better.
|
||||||
20
docs/fr/astuces.rst
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
Trucs et astuces pour Pelican
|
||||||
|
#############################
|
||||||
|
|
||||||
|
Personnaliser l'url d'un article pour Pelican
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
Par défaut, quand vous créez un article ayant pour titre *Mon article pour Pelican*,
|
||||||
|
l'url par défaut devient *mon-article-pour-pelican.html*. Cependant, il est possible
|
||||||
|
de modifier cela en utilisant la technique utilisée pour les traductions d'article,
|
||||||
|
c'est à dire le paramètre *:slug:* ::
|
||||||
|
|
||||||
|
Mon article pour Pelican
|
||||||
|
########################
|
||||||
|
|
||||||
|
:date: 2011-01-31 11:05
|
||||||
|
:slug: super-article-pour-pelican
|
||||||
|
|
||||||
|
bla, bla, bla …
|
||||||
|
|
||||||
|
En prenant cet exemple ci dessus, votre url deviendra *super-article-pour-pelican.html*
|
||||||
58
docs/fr/bases.rst
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
Les bases de Pelican
|
||||||
|
####################
|
||||||
|
|
||||||
|
Créer son premier article
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Pour créer notre premier article, nous allons éditer un fichier, par exemple premier_article.rst ::
|
||||||
|
|
||||||
|
Premier article pour Pelican
|
||||||
|
############################
|
||||||
|
:author: Guillaume
|
||||||
|
:date: 2011-01-08 10:20
|
||||||
|
:category: GNU-Linux
|
||||||
|
:tags: tutoriel, git
|
||||||
|
Ceci est un tutoriel pour configurer git.
|
||||||
|
Bla, bla, bla ....
|
||||||
|
|
||||||
|
Maintenant que ce fichier est créé, on va lancer la création du blog ::
|
||||||
|
|
||||||
|
pelican .
|
||||||
|
|
||||||
|
Vous aller obtenir une sortie comme celle ci — $PATH représente le dossier où vous
|
||||||
|
avez créé votre article ::
|
||||||
|
|
||||||
|
[ok] writing $PATH/output/feeds/all.atom.xml
|
||||||
|
[ok] writing $PATH/output/feeds/GNU/Linux.atom.xml
|
||||||
|
[ok] writing $PATH/output/feeds/all-en.atom.xml
|
||||||
|
[ok] writing $PATH/output/premier-article-pour-pelican.html
|
||||||
|
[ok] writing $PATH/output/index.html
|
||||||
|
[ok] writing $PATH/output/tags.html
|
||||||
|
[ok] writing $PATH/output/categories.html
|
||||||
|
[ok] writing $PATH/output/archives.html
|
||||||
|
[ok] writing $PATH/output/tag/tutoriel.html
|
||||||
|
[ok] writing $PATH/output/tag/git.html
|
||||||
|
[ok] writing $PATH/output/category/GNU-Linux.html
|
||||||
|
|
||||||
|
|
||||||
|
Première analyse
|
||||||
|
================
|
||||||
|
|
||||||
|
Nous allons décortiquer un peu tout ça ensemble.
|
||||||
|
|
||||||
|
* Un dossier output/ a été créé pour y mettre le fichiers xml et html du blog.
|
||||||
|
* Dans le dossier feeds/, nous retrouvons les différents flux de syndication.
|
||||||
|
* Le fichier de l’article et la page principale du blog a été généré.
|
||||||
|
* Le répertoire tag/ propose une page par tag.
|
||||||
|
* La page correspondant à la catégorie est générée dans le répertoire category/
|
||||||
|
|
||||||
|
Si vous ouvrez le fichier index.html — ou un autre — avec votre navigateur, vous
|
||||||
|
remarquerez que :
|
||||||
|
|
||||||
|
* Le thème utilisé par défaut est notmyidea
|
||||||
|
* Le nom du blog est A Pelican Blog.
|
||||||
|
|
||||||
|
Bien évidemment, il y a des paramètres de base que l’on peut modifier pour mettre
|
||||||
|
un peu tout ça à sa sauce. C’est ce que nous allons voir au travers du fichier de configuration.
|
||||||
|
|
||||||
|
|
||||||
154
docs/fr/configuration.rst
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
Fichier de configuration
|
||||||
|
************************
|
||||||
|
|
||||||
|
On va créer un fichier de configuration que l’on va appeler **settings.py**. On peut
|
||||||
|
utiliser Pelican sans faire ce fichier, mais il faudrait à chaque fois passer les paramètres
|
||||||
|
en ligne de commande. Et comme il va nous servir à faire d’autres choses bien utile,
|
||||||
|
autant l’appréhender de suite. Cependant, nous n’allons voir que la base pour l’instant.
|
||||||
|
|
||||||
|
Paramètres de base
|
||||||
|
==================
|
||||||
|
|
||||||
|
AUTHOR :
|
||||||
|
Désigne l’auteur par défaut ;
|
||||||
|
|
||||||
|
DEFAULT_CATEGORY :
|
||||||
|
La catégorie par défaut des articles. Si ce paramètre n’est
|
||||||
|
pas documenté, il prendra la valeur misc — pour miscellaneous (divers en français) ;
|
||||||
|
|
||||||
|
SITENAME :
|
||||||
|
Le nom de votre site ;
|
||||||
|
|
||||||
|
OUTPUT_PATH :
|
||||||
|
Le répertoire de sortie du blog.
|
||||||
|
|
||||||
|
Quand je dis qu’on va faire simple, on fait simple !
|
||||||
|
Passons donc à ce quoi doit ressembler le fichier de configuration ::
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
AUTHOR = "Guillaume"
|
||||||
|
DEFAULT_CATEGORY = "GNU-Linux"
|
||||||
|
SITENAME = "Free Culture"
|
||||||
|
|
||||||
|
|
||||||
|
Si vous avez un serveur comme Apache de configuré pour votre machine, vous
|
||||||
|
pouvez paramétrer le répertoire de sortie vers **/var/www/blog** par exemple ::
|
||||||
|
|
||||||
|
OUTPUT_PATH = "/var/www/blog"
|
||||||
|
|
||||||
|
Une remarque importante. Si vous avez besoin de passer un caractère accentué, il
|
||||||
|
faut le préciser que la chaine est en unicode en faisant par exemple
|
||||||
|
*AUTHOR = u"Guillaume LAMÉ"*
|
||||||
|
|
||||||
|
Pour bien vérifier que les paramètres sont bien pris en compte, nous allons enlever les lignes *:author: Guillaume* et *:category: GNU-Linux* de notre fichier
|
||||||
|
**premier_article.rst** et regénérer le blog.
|
||||||
|
|
||||||
|
Rafraichissez votre page, ce devrait être bon.
|
||||||
|
|
||||||
|
Nous allons maintenant passer en revue les différents paramètres de Pelican. Je les
|
||||||
|
ai regroupé par thème. Cependant, c’est surtout un listing avant de rentrer dans les
|
||||||
|
détails au prochain chapitre.
|
||||||
|
|
||||||
|
Flux de syndication
|
||||||
|
===================
|
||||||
|
|
||||||
|
CATEGORY_FEED :
|
||||||
|
Chemin d’écriture des flux Atom liés aux catégories ;
|
||||||
|
|
||||||
|
CATEGORY_FEED_RSS :
|
||||||
|
Idem pour les flux rss (Optionnel);
|
||||||
|
|
||||||
|
FEED :
|
||||||
|
Chemin du flux Atom global ;
|
||||||
|
|
||||||
|
FEED_RSS :
|
||||||
|
Chemin du flux Rss global (Optionnel);
|
||||||
|
|
||||||
|
TAG_FEED :
|
||||||
|
Chemin des flux Atom pour les tags (Optionnel);
|
||||||
|
|
||||||
|
TAG_FEED_RSS :
|
||||||
|
Chemin des flux Rss pour les tags (Optionnel).
|
||||||
|
|
||||||
|
|
||||||
|
Traductions
|
||||||
|
===========
|
||||||
|
|
||||||
|
DEFAULT_LANG :
|
||||||
|
Le langage par défaut à utiliser. «*en*» par défaut ;
|
||||||
|
|
||||||
|
TRANSLATION_FEED :
|
||||||
|
Chemin du flux pour les traductions.
|
||||||
|
|
||||||
|
|
||||||
|
Thèmes
|
||||||
|
======
|
||||||
|
|
||||||
|
CSS_FILE :
|
||||||
|
Fichier css à utiliser si celui-ci est différent du fichier par défaut (*main.css*) ;
|
||||||
|
|
||||||
|
DISPLAY_PAGES_ON_MENU :
|
||||||
|
Affiche ou non les pages statiques sur le menu du thème ;
|
||||||
|
|
||||||
|
DISQUS_SITENAME :
|
||||||
|
Indiquer le nom du site spécifié sur Disqus ;
|
||||||
|
|
||||||
|
GITHUB_URL :
|
||||||
|
Indiquez votre url Github ;
|
||||||
|
|
||||||
|
GOOGLE_ANALYTICS :
|
||||||
|
'UA-XXXX-YYYY' pour activer Google analytics ;
|
||||||
|
|
||||||
|
JINJA_EXTENSIONS :
|
||||||
|
Liste d'extension Jinja2 que vous souhaitez utiliser ;
|
||||||
|
|
||||||
|
LINKS :
|
||||||
|
Une liste de tuples (Titre, url) pour afficher la liste de lien ;
|
||||||
|
|
||||||
|
PDF_PROCESSOR :
|
||||||
|
Génère ou non les articles et pages au format pdf ;
|
||||||
|
|
||||||
|
REVERSE_ARCHIVE_ORDER :
|
||||||
|
Met les articles plus récent en tête de l'archive ;
|
||||||
|
|
||||||
|
SOCIAL :
|
||||||
|
Une liste de tuples (Titre, url) pour afficher la liste de lien dans la section "Social" ;
|
||||||
|
|
||||||
|
STATIC_THEME_PATHS :
|
||||||
|
Répertoire du thème que vous souhaitez importer dans l'arborescence finale ;
|
||||||
|
|
||||||
|
THEME :
|
||||||
|
Thème à utiliser:
|
||||||
|
|
||||||
|
TWITTER_USERNAME :
|
||||||
|
Permet d'afficher un bouton permettant le tweet des articles.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Paramètres divers
|
||||||
|
=================
|
||||||
|
|
||||||
|
FALLBACK_ON_FS_DATE :
|
||||||
|
Si *True*, Pelican se basera sur le *mtime* du fichier s'il n'y a pas de date spécifiée dans le fichier de l'article ;
|
||||||
|
|
||||||
|
KEEP_OUTPUT DIRECTORY :
|
||||||
|
Ne génère que les fichiers modifiés et n'efface pas le repertoire de sortie ;
|
||||||
|
|
||||||
|
MARKUP :
|
||||||
|
Langage de balisage à utiliser ;
|
||||||
|
|
||||||
|
PATH :
|
||||||
|
Répertoire à suivre pour les fichiers inclus ;
|
||||||
|
|
||||||
|
SITEURL :
|
||||||
|
URL de base de votre site ;
|
||||||
|
|
||||||
|
STATIC_PATHS :
|
||||||
|
Les chemins statiques que vous voulez avoir accès sur le chemin de sortie "statique" ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
18
docs/fr/conventions.rst
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
Conventions
|
||||||
|
###########
|
||||||
|
|
||||||
|
Environnement de test
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Les exemples sont basées sur une distribution Debian. Pour les autres distributions,
|
||||||
|
il y aura des ajustements à faire, notamment pour l’installation de Pelican. Les
|
||||||
|
noms des paquets peuvent changer.
|
||||||
|
|
||||||
|
Conventions typographiques
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Un petit rappel concernant les codes sources.
|
||||||
|
|
||||||
|
* $ correspond à une ligne à exécuter en tant qu’utilisateur courant du systême ;
|
||||||
|
* # correspond à une ligne à exécuter en tant que root ;
|
||||||
|
* **settings.py** : Les noms des répertoires et fichiers sont en gras.
|
||||||
35
docs/fr/faq.rst
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
*Foire aux questions (FAQ)*
|
||||||
|
|
||||||
|
Voici un résumé des questions fréquemment posées pour pelican.
|
||||||
|
|
||||||
|
*Est-il obligatoire d'avoir un fichier de configuration ?*
|
||||||
|
|
||||||
|
Non. Les fichiers de configuration sont juste un moyen facile de configurer
|
||||||
|
pelican. Pour les opérations de base, il est possible de spécifier des
|
||||||
|
options
|
||||||
|
en invoquant pelican avec la ligne de commande (voir pelican --help pour
|
||||||
|
plus
|
||||||
|
d'informations à ce sujet)
|
||||||
|
|
||||||
|
*Je crée mon propre thème, comment utiliser pygments?*
|
||||||
|
|
||||||
|
Pygment ajoute quelques classes au contenu généré, de sorte qua colorisation
|
||||||
|
de votre thème se fait grâce à un fichier css. Vous pouvez jeter un oeil à
|
||||||
|
celui proposé par`sur le site du projet <http://pygments.org/demo/15101/>`_
|
||||||
|
|
||||||
|
*Comment puis-je créer mon propre thèm*
|
||||||
|
|
||||||
|
Vueillez vous référer à :ref:`theming-pelican-fr`.
|
||||||
|
|
||||||
|
*Comment puis-je aider?*
|
||||||
|
|
||||||
|
Vous avez plusieurs options pour aider. Tout d'abord, vous pouvez utiliser
|
||||||
|
le
|
||||||
|
pélican, et signaler toute idée ou problème que vous avez sur le bugtracker
|
||||||
|
.
|
||||||
|
|
||||||
|
Si vous voulez contribuer, jeter un oeil au dépôt git , ajoutez vos
|
||||||
|
modifications et faites une demande, je les regarderai dès que possible
|
||||||
|
|
||||||
|
Vous pouvez aussi contribuer en créant des thèmes, et/ou compléter la
|
||||||
|
documentation.
|
||||||
55
docs/fr/index.rst
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
Pelican
|
||||||
|
#######
|
||||||
|
|
||||||
|
Pelican est un generateur de blog simple codé en python
|
||||||
|
|
||||||
|
* Écrivez vos articles directement dans votre éditeur favori (vim !) et
|
||||||
|
directement en syntaxe reStructuredText ou Markdown ;
|
||||||
|
* Un outil simple en ligne de conmmande pour (re)générer le blog ;
|
||||||
|
* Sortie complètement statique, facile pour l'héberger n'importe où ;
|
||||||
|
|
||||||
|
Fonctionnalités
|
||||||
|
===============
|
||||||
|
|
||||||
|
Pelican supporte actuellement :
|
||||||
|
|
||||||
|
* des articles de blog ;
|
||||||
|
* des pages statiques ;
|
||||||
|
* les commentaires via un service externe (`disqus <http://disqus.com>`_)
|
||||||
|
Notez qu'étant bien un service externe assez pratique, vous ne gérez pas
|
||||||
|
vous même les commentaires. Ce qui pourrait occasionner une perte de vos données;
|
||||||
|
* support de template (les templates sont crées avec `jinja2 <http://jinjna.pocoo.org>`_) ;
|
||||||
|
* génération optionnelle de vos pages et articles en pdf.
|
||||||
|
|
||||||
|
Pourquoi le nom "Pelican" ?
|
||||||
|
============================
|
||||||
|
|
||||||
|
Vous n'avez pas remarqué ? "Pelican" est un anagramme pour "Calepin" ;)
|
||||||
|
|
||||||
|
Code source
|
||||||
|
===========
|
||||||
|
|
||||||
|
Vous pouvez accéder au code source via git à l'adresse
|
||||||
|
http://github.com/ametaireau/pelican/
|
||||||
|
|
||||||
|
Feedback !
|
||||||
|
==========
|
||||||
|
|
||||||
|
Si vous voulez de nouvelles fonctionnalitées pour Pelican, n'hésitez pas à nous le dire,
|
||||||
|
à cloner le dépôt, etc … C'est open source !!!
|
||||||
|
|
||||||
|
Contactez Alexis à "alexis at notmyidea dot org" pour quelques requêtes ou retour d'expérience que ce soi !
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
conventions
|
||||||
|
installation
|
||||||
|
bases
|
||||||
|
configuration
|
||||||
|
parametres_article
|
||||||
|
astuces
|
||||||
|
faq
|
||||||
67
docs/fr/installation.rst
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
Installation et mise à jour de Pelican
|
||||||
|
######################################
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Il y a deux façons d’installer Pelican sur son système. La première est via l’utilitaire
|
||||||
|
pip, l’autre façon est de télécharger Pelican via Github. Ici nous allons voir les deux
|
||||||
|
façons de procéder.
|
||||||
|
|
||||||
|
Via pip
|
||||||
|
-------
|
||||||
|
|
||||||
|
Pour installer Pelican via pip, vous aurez besoin du paquet python-pip. puis installez Pelican ::
|
||||||
|
|
||||||
|
# apt-get install python-pip
|
||||||
|
# pip install pelican
|
||||||
|
|
||||||
|
|
||||||
|
Via Github
|
||||||
|
----------
|
||||||
|
|
||||||
|
Pour installer Pelican en reprenant le code via Github, nous aurons besoin du paquet
|
||||||
|
git-core pour récupérez les sources de Pelican. Puis nous procédons à l’installation ::
|
||||||
|
|
||||||
|
# apt-get install git-core
|
||||||
|
$ git clone https://github.com/ametaireau/pelican.git
|
||||||
|
$ cd pelican
|
||||||
|
# python setup.py install
|
||||||
|
|
||||||
|
Mises à jour
|
||||||
|
============
|
||||||
|
|
||||||
|
Via pip
|
||||||
|
-------
|
||||||
|
|
||||||
|
Rien de bien compliqué pour mettre à jour via pip ::
|
||||||
|
|
||||||
|
$ cd votreRepertoireSource
|
||||||
|
$ pip install --upgrade pelican
|
||||||
|
|
||||||
|
|
||||||
|
Via Github
|
||||||
|
----------
|
||||||
|
|
||||||
|
C'est un peu plus long avec Github par contre ::
|
||||||
|
|
||||||
|
$ cd votreRepertoireSource
|
||||||
|
$ git pull origin master
|
||||||
|
$ cd pelican
|
||||||
|
# python setup.py install
|
||||||
|
|
||||||
|
Vous aurez un message d’erreur si le module setuptools de python n’est pas installé.
|
||||||
|
La manipulation est la suivante ::
|
||||||
|
|
||||||
|
# apt-get install python-setuptools
|
||||||
|
|
||||||
|
Alors, quelle méthode choisir ?
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Vous avez le choix entre deux méthodes, mais aussi entre deux concepts. La méthode
|
||||||
|
de Github est la version de développement, où les modifications arrivent assez
|
||||||
|
fréquemment sans être testées à fond. La version de pip est une version arrêtée avec un
|
||||||
|
numéro de version dans laquelle vous aurez moins de bug. N’oubliez cependant pas
|
||||||
|
que le projet est très jeune et manque donc de maturité. Si vous aimez avoir les toutes
|
||||||
|
dernières versions utilisez Github, sinon penchez vous sur pip.
|
||||||
|
|
||||||
106
docs/fr/parametres_article.rst
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
Les paramètres des articles dans Pelican
|
||||||
|
########################################
|
||||||
|
|
||||||
|
Les catégories
|
||||||
|
==============
|
||||||
|
|
||||||
|
Nous avons vu que pour affecter un article à une catégorie, nous avions le paramètre *:category:*.
|
||||||
|
Il y a cependant plus simple, affecter un répertoire à une catégorie.
|
||||||
|
|
||||||
|
Dans le répertoire ou vous avez vos articles, créez le repertoire **GNU-Linux** et déplacez y le fichier
|
||||||
|
**premier_article.rst**. Bien évidemment nous ne verront pas la différence, car jusqu'ici *GNU-Linux*
|
||||||
|
est notre catégorie par défaut.
|
||||||
|
|
||||||
|
Nous allons faire un autre exemple d'article avec la catégorie Pelican. Créez le répertoire **Pelican**
|
||||||
|
et collez cette exemple d'article ::
|
||||||
|
|
||||||
|
Préparation de la documentation
|
||||||
|
###############################
|
||||||
|
|
||||||
|
:date: 2011-01-27 15:28
|
||||||
|
:tags: documentation
|
||||||
|
|
||||||
|
Il y a quand même pas mal de boulot pour faire une documentation !
|
||||||
|
|
||||||
|
Et lancez la compilation du blog. Vous voyez que la catégorie est affectée automatiquement.
|
||||||
|
|
||||||
|
Les tags
|
||||||
|
========
|
||||||
|
|
||||||
|
Pour les tags, il n'y a rien de compliqué. il suffit de mettre le(s) tags séparés si besoin d'une virgule. ::
|
||||||
|
|
||||||
|
Préparation de la documentation
|
||||||
|
###############################
|
||||||
|
|
||||||
|
:date: 2011-01-27 15:28
|
||||||
|
:tags: documentation, pelican
|
||||||
|
|
||||||
|
Par contre, par soucis de clarté au niveau des url je vous conseille de mettre les expression de plusieurs
|
||||||
|
mots séparées par des tirets ::
|
||||||
|
|
||||||
|
:tags: mise-a-jour
|
||||||
|
|
||||||
|
et non ::
|
||||||
|
|
||||||
|
:tags: mise a jour
|
||||||
|
|
||||||
|
|
||||||
|
Les auteurs
|
||||||
|
===========
|
||||||
|
|
||||||
|
Par défaut, vous pouvez indiqué votre nom en tant qu'auteur dans le fichier de configuration.
|
||||||
|
S'il y a plusieurs auteurs pour le site, vous pouvez le définir manuellement dans
|
||||||
|
l'article avec la méta-donnée ::
|
||||||
|
|
||||||
|
:author: Guillaume
|
||||||
|
|
||||||
|
La date
|
||||||
|
=======
|
||||||
|
|
||||||
|
La date se met au format anglophone : **YYYY-MM-DD hh:mm** ::
|
||||||
|
|
||||||
|
:date: 2011-01-31 14:12
|
||||||
|
|
||||||
|
|
||||||
|
Les traductions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Pelican permet de générer un blog multilingue assez facilement. Pour cela nous devons :
|
||||||
|
|
||||||
|
* Définir la langue de base du blog ;
|
||||||
|
* Donner une référence à l'article initial ;
|
||||||
|
* Définir la langue du fichier traduit et y reporter la référence.
|
||||||
|
|
||||||
|
Pour définir la langue de base nous allons modifier le fichier **settings.py** et y rajouter la ligne suivante ::
|
||||||
|
|
||||||
|
DEFAULT_LANG = "fr"
|
||||||
|
|
||||||
|
Puis ajouter la référence dans notre article d'origine qui deviendra ::
|
||||||
|
|
||||||
|
Préparation de la documentation
|
||||||
|
###############################
|
||||||
|
|
||||||
|
:date: 2011-01-27 15:28
|
||||||
|
:tags: documentation
|
||||||
|
:slug: preparation-de-la-documentation
|
||||||
|
|
||||||
|
Il y a quand même pas mal de boulot pour faire une documentation !
|
||||||
|
|
||||||
|
Nous n'avons plus qu'à créer l'article en anglais ::
|
||||||
|
|
||||||
|
Start of documentation
|
||||||
|
######################
|
||||||
|
|
||||||
|
:slug: preparation-de-la-documention
|
||||||
|
:lang: en
|
||||||
|
|
||||||
|
There are still a lot of work to documentation !
|
||||||
|
|
||||||
|
**Il est important de comprendre que la valeur de :slug: deviendra votre url. Ne mettez donc pas un diminutif pour
|
||||||
|
identifier l'article**
|
||||||
|
|
||||||
|
Rien de plus à savoir pour traduire efficacement des articles.
|
||||||
|
|
||||||
|
|
||||||
|
Maintenant que vous avez toutes les clés en main pour créer un article, nous allons passer à la personnalisation
|
||||||
|
du fichier de configuration.
|
||||||
|
|
@ -17,22 +17,26 @@ install. I recommend to do so in a virtualenv::
|
||||||
$ python setup.py install
|
$ python setup.py install
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
============
|
------------
|
||||||
|
|
||||||
At this time, pelican is dependent of the following python packages:
|
At this time, pelican is dependent of the following python packages:
|
||||||
|
|
||||||
* feedgenerator, to generate the ATOM feeds.
|
* feedgenerator, to generate the ATOM feeds.
|
||||||
* jinja2, for templating support.
|
* jinja2, for templating support.
|
||||||
* pygments, to have syntactic colorization
|
|
||||||
* docutils and Markdown
|
|
||||||
|
|
||||||
If you're not using python 2.7, you will also need `argparse`.
|
If you're not using python 2.7, you will also need `argparse`.
|
||||||
|
|
||||||
All those dependencies will be processed automatically if you install pelican
|
Optionally:
|
||||||
using setuptools/distribute or pip.
|
|
||||||
|
* docutils, for reST support
|
||||||
|
* pygments, to have syntactic colorization with resT input
|
||||||
|
* Markdown, for Markdown as an input format
|
||||||
|
|
||||||
|
Writing articles using pelican
|
||||||
|
==============================
|
||||||
|
|
||||||
Files metadata
|
Files metadata
|
||||||
==============
|
--------------
|
||||||
|
|
||||||
Pelican tries to be smart enough to get the informations he needs from the
|
Pelican tries to be smart enough to get the informations he needs from the
|
||||||
file system (for instance, about the category of your articles), but you need to
|
file system (for instance, about the category of your articles), but you need to
|
||||||
|
|
@ -63,11 +67,11 @@ directory where the rst file is. For instance, the category of
|
||||||
`python/foobar/myfoobar.rst` is `foobar`.
|
`python/foobar/myfoobar.rst` is `foobar`.
|
||||||
|
|
||||||
Generate your blog
|
Generate your blog
|
||||||
==================
|
------------------
|
||||||
|
|
||||||
To launch pelican, just use the `pelican` command::
|
To launch pelican, just use the `pelican` command::
|
||||||
|
|
||||||
$ pelican /path/to/your/content/
|
$ pelican /path/to/your/content/ [-s path/to/your/settings.py]
|
||||||
|
|
||||||
And… that's all! You can see your weblog generated on the `content/` folder.
|
And… that's all! You can see your weblog generated on the `content/` folder.
|
||||||
|
|
||||||
|
|
@ -80,7 +84,7 @@ the options you can use::
|
||||||
$ pelican --help
|
$ pelican --help
|
||||||
|
|
||||||
Pages
|
Pages
|
||||||
=====
|
-----
|
||||||
|
|
||||||
If you create a folder named `pages`, all the files in it will be used to
|
If you create a folder named `pages`, all the files in it will be used to
|
||||||
generate static pages.
|
generate static pages.
|
||||||
|
|
@ -89,9 +93,60 @@ Then, use the `DISPLAY_PAGES_ON_MENU` setting, which will add all the pages to
|
||||||
the menu.
|
the menu.
|
||||||
|
|
||||||
Translations
|
Translations
|
||||||
============
|
------------
|
||||||
|
|
||||||
It is possible to translate articles. To do so, you need to add a `Lang` meta
|
It is possible to translate articles. To do so, you need to add a `lang` meta
|
||||||
in your articles/pages, and to set a `DEFAULT_LANG` setting (which is en by
|
in your articles/pages, and to set a `DEFAULT_LANG` setting (which is en by
|
||||||
default). Then, only articles with this default language will be listed, and
|
default).
|
||||||
|
Then, only articles with this default language will be listed, and
|
||||||
each article will have a translation list.
|
each article will have a translation list.
|
||||||
|
|
||||||
|
Pelican uses the "slug" of two articles to compare if they are translations of
|
||||||
|
each others. So it's possible to define (in restructured text) the slug
|
||||||
|
directly.
|
||||||
|
|
||||||
|
Here is an exemple of two articles (one in english and the other one in
|
||||||
|
french).
|
||||||
|
|
||||||
|
The english one::
|
||||||
|
|
||||||
|
Foobar is not dead
|
||||||
|
##################
|
||||||
|
|
||||||
|
:slug: foobar-is-not-dead
|
||||||
|
:lang: en
|
||||||
|
|
||||||
|
That's true, foobar is still alive !
|
||||||
|
|
||||||
|
And the french one::
|
||||||
|
|
||||||
|
Foobar n'est pas mort !
|
||||||
|
#######################
|
||||||
|
|
||||||
|
:slug: foobar-is-not-dead
|
||||||
|
:lang: fr
|
||||||
|
|
||||||
|
Oui oui, foobar est toujours vivant !
|
||||||
|
|
||||||
|
Despite the text quality, you can see that only the slug is the same here.
|
||||||
|
You're not forced to define the slug that way, and it's completely possible to
|
||||||
|
have two translations with the same title (which defines the slug)
|
||||||
|
|
||||||
|
Syntactic recognition
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Pelican is able to regognise the syntax you are using, and to colorize the
|
||||||
|
right way your block codes. To do so, you have to use the following syntax::
|
||||||
|
|
||||||
|
.. code-block:: identifier
|
||||||
|
your code goes here
|
||||||
|
|
||||||
|
The identifier is one of the lexers available `here
|
||||||
|
<http://pygments.org/docs/lexers/>`_.
|
||||||
|
|
||||||
|
Autoreload
|
||||||
|
----------
|
||||||
|
|
||||||
|
It's possible to tell pelican to watch for your modifications, instead of
|
||||||
|
manually launching it each time you need. Use the `-r` option, or
|
||||||
|
`--autoreload`.
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,7 @@ Heh, you didn't noticed? "Pelican" is an anagram for "Calepin" ;)
|
||||||
Source code
|
Source code
|
||||||
===========
|
===========
|
||||||
|
|
||||||
You can access the source code via mercurial at http://hg.notmyidea.org/pelican/
|
You can access the source code via git on http://github.com/ametaireau/pelican/
|
||||||
or via git on http://github.com/ametaireau/pelican/
|
|
||||||
|
|
||||||
Feedback !
|
Feedback !
|
||||||
==========
|
==========
|
||||||
|
|
@ -43,6 +42,8 @@ Contact me at "alexis at notmyidea dot org" for any request/feedback !
|
||||||
Documentation
|
Documentation
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
A french version of the documentation is available at :doc:`fr/index`.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|
@ -50,3 +51,4 @@ Documentation
|
||||||
settings
|
settings
|
||||||
themes
|
themes
|
||||||
internals
|
internals
|
||||||
|
faq
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ method, that is returning an HTML content and some metadata.
|
||||||
|
|
||||||
Take a look to the Markdown reader::
|
Take a look to the Markdown reader::
|
||||||
|
|
||||||
class MarkdownReader(object):
|
class MarkdownReader(Reader):
|
||||||
|
enabled = bool(Markdown)
|
||||||
|
|
||||||
def read(self, filename):
|
def read(self, filename):
|
||||||
"""Parse content and metadata of markdown files"""
|
"""Parse content and metadata of markdown files"""
|
||||||
|
|
@ -59,6 +60,12 @@ Take a look to the Markdown reader::
|
||||||
|
|
||||||
Simple isn't it ?
|
Simple isn't it ?
|
||||||
|
|
||||||
|
If your new reader requires additional Python dependencies then you should wrap
|
||||||
|
their `imports` statements in `try...except`. Then inside the reader's class
|
||||||
|
set the `enabled` class attribute to mark import success or failure. This makes
|
||||||
|
it possible for users to continue using their favourite markup method without
|
||||||
|
needing to install modules for all the additional formats they don't use.
|
||||||
|
|
||||||
How to implement a new generator ?
|
How to implement a new generator ?
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,67 +19,135 @@ processed.
|
||||||
Here are the available settings. Please note that all the settings you put in
|
Here are the available settings. Please note that all the settings you put in
|
||||||
this file will be passed to the templates as well.
|
this file will be passed to the templates as well.
|
||||||
|
|
||||||
======================= =======================================================
|
|
||||||
Setting name what it does ?
|
======================== =======================================================
|
||||||
======================= =======================================================
|
Setting name what it does ?
|
||||||
`AUTHOR` Default author (put your name)
|
======================== =======================================================
|
||||||
`CATEGORY_FEED` Where to put the atom categories feeds. default is
|
`AUTHOR` Default author (put your name)
|
||||||
`feeds/%s.atom.xml`, where %s is the name of the
|
`CATEGORY_FEED` Where to put the atom categories feeds. default is
|
||||||
category.
|
`feeds/%s.atom.xml`, where %s is the name of the
|
||||||
`CATEGORY_FEED_RSS` Where to put the categories rss feeds. default is None
|
category.
|
||||||
(no rss)
|
`CATEGORY_FEED_RSS` Where to put the categories rss feeds. default is None
|
||||||
`CSS_FILE` To specify the CSS file you want to load, if it's not
|
(no rss)
|
||||||
the default one ('main.css')
|
`CSS_FILE` To specify the CSS file you want to load, if it's not
|
||||||
`DEFAULT_CATEGORY` The default category to fallback on. `misc` by default.
|
the default one ('main.css')
|
||||||
`DEFAULT_LANG` The default language to use. Default is 'en'.
|
`DATE_FORMATS` If you do manage multiple languages, you can set
|
||||||
`DISPLAY_PAGES_ON_MENU` Display or not the pages on the menu of the template.
|
the date formatting here.
|
||||||
Templates can follow or not this settings.
|
`DEFAULT_CATEGORY` The default category to fallback on. `misc` by default.
|
||||||
`DIRECT_TEMPLATES` Tuple, containing templates to render. There should be
|
`DEFAULT_DATE_FORMAT` The default date format you want to use.
|
||||||
a html file for each of these templates in the theme.
|
`DEFAULT_LANG` The default language to use. Default is 'en'.
|
||||||
`FALLBACK_ON_FS_DATE` If True, pelican will use the file system dates infos
|
`DEFAULT_ORPHANS` The minimum number of articles allowed on the last
|
||||||
(mtime) if it can't get informations from the
|
page, defaults to zero. Use this when you don't want
|
||||||
metadata?
|
to have a last page with very few articles.
|
||||||
`FEED` relative url to output the atom feed. Default is
|
`DEFAULT_PAGINATION` The maximum number of articles to include on a page,
|
||||||
`feeds/all.atom.xml`
|
not including orphans. Default is 5.
|
||||||
`FEED_RSS` relative url to output the rss feed. Default is
|
`DISPLAY_PAGES_ON_MENU` Display or not the pages on the menu of the template.
|
||||||
None (no rss)
|
Templates can follow or not this settings.
|
||||||
`KEEP_OUTPUT_DIRECTORY` Keep the output directory and just update all the generated files.
|
`FALLBACK_ON_FS_DATE` If True, pelican will use the file system dates infos
|
||||||
Default is to delete the output directory.
|
(mtime) if it can't get informations from the
|
||||||
`MARKUP` A list of available markup languages you want to use.
|
metadata?
|
||||||
For the moment, only available values are `rst` and `md`.
|
`FEED` relative url to output the atom feed. Default is
|
||||||
`OUTPUT_PATH` Where to output the generated files. Default to
|
`feeds/all.atom.xml`
|
||||||
"output"
|
`FEED_RSS` relative url to output the rss feed. Default is
|
||||||
`PATH` path to look at for input files.
|
None (no rss)
|
||||||
`PDF_PROCESSOR` Put True if you want to have PDF versions of your
|
`JINJA_EXTENSIONS` A list of any Jinja2 extensions you want to use.
|
||||||
documents. You will need to install `rst2pdf`.
|
Default is no extensions (the empty list).
|
||||||
`REVERSE_ARCHIVE_ORDER` Reverse the archives order. (True makes it in
|
`KEEP_OUTPUT_DIRECTORY` Keep the output directory and just update all the
|
||||||
descending order: the newer first)
|
generated files.
|
||||||
`SITEURL` base URL of your website.
|
`LOCALE` Change the locale. Default is the system locale.
|
||||||
`SITENAME` Your site name,
|
Default is to delete the output directory.
|
||||||
`STATIC_PATHS` The static paths you want to have accessible on the
|
`MARKUP` A list of available markup languages you want to use.
|
||||||
output path "static". By default, pelican will copy
|
For the moment, only available values are `rst` and `md`.
|
||||||
the 'images' folder to the output folder.
|
`OUTPUT_PATH` Where to output the generated files. Default to
|
||||||
`STATIC_THEME_PATHS` Static theme paths you want to copy. Default values
|
"output"
|
||||||
is `static`, but if your theme have others static paths,
|
`PATH` path to look at for input files.
|
||||||
you can put them here.
|
`PDF_PROCESSOR` Put True if you want to have PDF versions of your
|
||||||
`TAG_CLOUD_STEPS` Count of different font sizes in the tag cloud.
|
documents. You will need to install `rst2pdf`.
|
||||||
`TAG_CLOUD_MAX_ITEMS` Maximum tags count in the cloud.
|
`REVERSE_ARCHIVE_ORDER` Reverse the archives order. (True makes it in
|
||||||
`THEME` theme to use to product the output. can be the
|
descending order: the newer first)
|
||||||
complete static path to a theme folder, or chosen
|
`REVERSE_CATEGORY_ORDER` Reverse the category order. (True makes it in
|
||||||
between the list of default themes (see below)
|
descending order, default is alphabetically)
|
||||||
`TRANSLATION_FEED` Where to put the RSS feed for translations. Default
|
`SITEURL` base URL of your website.
|
||||||
is feeds/all-%s.atom.xml where %s is the name of the
|
`SITENAME` Your site name,
|
||||||
lang.
|
`SKRIBIT_TYPE` The type of skribit widget (TAB or WIDGET).
|
||||||
======================= =======================================================
|
`SKRIBIT_TAB_COLOR` Tab color (#XXXXXX, default #333333).
|
||||||
|
`SKRIBIT_TAB_HORIZ` Tab Distance from Left (% or distance, default Null).
|
||||||
|
`SKRIBIT_TAB_VERT` Tab Distance from Top (% or distance, default 20%).
|
||||||
|
`SKRIBIT_TAB_PLACEMENT` Tab placement (Top, Bottom, Left or Right, default
|
||||||
|
LEFT).
|
||||||
|
`SKRIBIT_TAB_SITENAME` Tab identifier (See Skribit part below).
|
||||||
|
`SKRIBIT_WIDGET_ID` Widget identifier (See Skribit part below).
|
||||||
|
`STATIC_PATHS` The static paths you want to have accessible on the
|
||||||
|
output path "static". By default, pelican will copy
|
||||||
|
the 'images' folder to the output folder.
|
||||||
|
`STATIC_THEME_PATHS` Static theme paths you want to copy. Default values
|
||||||
|
is `static`, but if your theme have others static paths,
|
||||||
|
you can put them here.
|
||||||
|
`TAG_CLOUD_STEPS` Count of different font sizes in the tag cloud.
|
||||||
|
`TAG_CLOUD_MAX_ITEMS` Maximum tags count in the cloud.
|
||||||
|
`THEME` theme to use to product the output. can be the
|
||||||
|
complete static path to a theme folder, or chosen
|
||||||
|
between the list of default themes (see below)
|
||||||
|
`TRANSLATION_FEED` Where to put the RSS feed for translations. Default
|
||||||
|
is feeds/all-%s.atom.xml where %s is the name of the
|
||||||
|
lang.
|
||||||
|
`WITH_PAGINATION` Activate pagination. Default is False.
|
||||||
|
======================== =======================================================
|
||||||
|
|
||||||
|
Skribit
|
||||||
|
=======
|
||||||
|
|
||||||
|
Skribit has two ways to display suggestions : as a sidebar widget or as a
|
||||||
|
suggestions tab. You can choose one of the display by setting the SKRIBIT_TYPE
|
||||||
|
in your config.
|
||||||
|
|
||||||
|
Sidebar widget
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The settings for sidebar widget is :
|
||||||
|
|
||||||
|
* SKRIBIT_WIDGET_ID : the identifier of your blog.
|
||||||
|
|
||||||
|
All the customizations are done in the skribit web interface.
|
||||||
|
|
||||||
|
To retrieve your identifier from the code snippet, you can use this python code::
|
||||||
|
|
||||||
|
import re
|
||||||
|
regex = re.compile('.*http://assets.skribit.com/javascripts/SkribitWidget.\
|
||||||
|
js\?renderTo=writeSkribitHere&blog=(.*)&.*')
|
||||||
|
snippet = '''SNIPPET CONTENT'''
|
||||||
|
snippet = snippet.replace('\n', '')
|
||||||
|
identifier = regex.match(snippet).groups()[0]
|
||||||
|
|
||||||
|
Suggestion tab
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The setting for suggestion tab's customizations are :
|
||||||
|
|
||||||
|
* SKRIBIT_TAB_COLOR
|
||||||
|
* SKRIBIT_TAB_DISTANCE_HORIZ
|
||||||
|
* SKRIBIT_TAB_DISTANCE_VERT
|
||||||
|
* SKRIBIT_TAB_PLACEMENT
|
||||||
|
|
||||||
|
The identifier is :
|
||||||
|
|
||||||
|
* SKRIBIT_TAB_SITENAME : the identifier of your blog
|
||||||
|
|
||||||
|
To retrieve your sitename from the code snippet, you can use this python code::
|
||||||
|
|
||||||
|
import re
|
||||||
|
regex = re.compile('.*http://skribit.com/lightbox/(.*)\',.*')
|
||||||
|
snippet = '''SNIPPET CONTENT'''
|
||||||
|
snippet = snippet.replace('\n', '')
|
||||||
|
identifier = regex.match(snippet).groups()[0]
|
||||||
|
|
||||||
Themes
|
Themes
|
||||||
======
|
======
|
||||||
|
|
||||||
3 themes are available. You can specify them using the `-t` option:
|
By default, two themes are availablee. You can specify them using the `-t` option:
|
||||||
|
|
||||||
* notmyidea
|
* notmyidea
|
||||||
* simple (a synonym for "full text" :)
|
* simple (a synonym for "full text" :)
|
||||||
* martyalchin
|
|
||||||
|
|
||||||
You can define your own theme too, and specify it's emplacement in the same
|
You can define your own theme too, and specify it's emplacement in the same
|
||||||
way (be sure to specify the full absolute path to it).
|
way (be sure to specify the full absolute path to it).
|
||||||
|
|
@ -87,6 +155,8 @@ way (be sure to specify the full absolute path to it).
|
||||||
Here is `a guide on how to create your theme
|
Here is `a guide on how to create your theme
|
||||||
<http://alexis.notmyidea.org/pelican/themes.html>`_
|
<http://alexis.notmyidea.org/pelican/themes.html>`_
|
||||||
|
|
||||||
|
You can find a list of themes at http://github.com/ametaireau/pelican-themes.
|
||||||
|
|
||||||
The `notmyidea` theme can make good use of the following settings. I recommend
|
The `notmyidea` theme can make good use of the following settings. I recommend
|
||||||
to use them too in your themes.
|
to use them too in your themes.
|
||||||
|
|
||||||
|
|
@ -102,6 +172,9 @@ Setting name what it does ?
|
||||||
the header.
|
the header.
|
||||||
`SOCIAL` A list of tuples (Title, Url) to appear in the "social"
|
`SOCIAL` A list of tuples (Title, Url) to appear in the "social"
|
||||||
section.
|
section.
|
||||||
|
`TWITTER_USERNAME` Allows to add a button on the articles to tweet about
|
||||||
|
them. Add you twitter username if you want this
|
||||||
|
button to appear.
|
||||||
======================= =======================================================
|
======================= =======================================================
|
||||||
|
|
||||||
In addition, you can use the "wide" version of the `notmyidea` theme, by
|
In addition, you can use the "wide" version of the `notmyidea` theme, by
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
|
.. _theming-pelican:
|
||||||
|
|
||||||
How to create themes for pelican
|
How to create themes for pelican
|
||||||
################################
|
################################
|
||||||
|
|
||||||
Pelican uses the great `jinja2 <http://jinjna.pocoo.org>`_ templating engine to
|
Pelican uses the great `jinja2 <http://jinjna.pocoo.org>`_ templating engine to
|
||||||
generate it's HTML output.
|
generate it's HTML output. The jinja2 syntax is really simple. If you want to
|
||||||
|
create your own theme, feel free to take inspiration from the "simple" theme,
|
||||||
|
which is available `here
|
||||||
|
<https://github.com/ametaireau/pelican/tree/master/pelican/themes/simple/templates>`_
|
||||||
|
|
||||||
Structure
|
Structure
|
||||||
=========
|
=========
|
||||||
|
|
@ -61,18 +66,50 @@ categories A dict containing each category (keys), and the
|
||||||
pages The list of pages
|
pages The list of pages
|
||||||
============= ===================================================
|
============= ===================================================
|
||||||
|
|
||||||
|
index.html
|
||||||
|
----------
|
||||||
|
|
||||||
|
Home page of your blog, will finally remain at output/index.html.
|
||||||
|
|
||||||
|
If pagination is active, next pages will remain at output/index`n`.html.
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
articles_paginator A paginator object of article list
|
||||||
|
articles_page The current page of articles
|
||||||
|
dates_paginator A paginator object of article list, ordered by date,
|
||||||
|
ascending
|
||||||
|
dates_page The current page of articles, ordered by date,
|
||||||
|
ascending
|
||||||
|
page_name 'index'. Useful for pagination links.
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
category.html
|
category.html
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
This template will be processed for each of the existing categories, and will
|
This template will be processed for each of the existing categories, and will
|
||||||
finally remain at output/category/`category_name`.html.
|
finally remain at output/category/`category_name`.html.
|
||||||
|
|
||||||
============= ===================================================
|
If pagination is active, next pages will remain at
|
||||||
Variable Description
|
output/category/`category_name``n`.html.
|
||||||
============= ===================================================
|
|
||||||
articles The articles of this category
|
=================== ===================================================
|
||||||
category The name of the category being processed
|
Variable Description
|
||||||
============= ===================================================
|
=================== ===================================================
|
||||||
|
category The name of the category being processed
|
||||||
|
articles Articles of this category
|
||||||
|
dates Articles of this category, but ordered by date,
|
||||||
|
ascending
|
||||||
|
articles_paginator A paginator object of article list
|
||||||
|
articles_page The current page of articles
|
||||||
|
dates_paginator A paginator object of article list, ordered by date,
|
||||||
|
ascending
|
||||||
|
dates_page The current page of articles, ordered by date,
|
||||||
|
ascending
|
||||||
|
page_name 'category/`category_name`'. Useful for pagination
|
||||||
|
links.
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
article.html
|
article.html
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -91,11 +128,38 @@ tag.html
|
||||||
--------
|
--------
|
||||||
|
|
||||||
For each tag, this template will be processed. It will create .html files in
|
For each tag, this template will be processed. It will create .html files in
|
||||||
/output/tag/`tag_name`.html
|
/output/tag/`tag_name`.html.
|
||||||
|
|
||||||
============= ===================================================
|
If pagination is active, next pages will remain at
|
||||||
Variable Description
|
output/tag/`tag_name``n`.html.
|
||||||
============= ===================================================
|
|
||||||
tag The name of the tag being processed
|
=================== ===================================================
|
||||||
articles Articles related to this tag
|
Variable Description
|
||||||
============= ===================================================
|
=================== ===================================================
|
||||||
|
tag The name of the tag being processed
|
||||||
|
articles Articles related to this tag
|
||||||
|
dates Articles related to this tag, but ordered by date,
|
||||||
|
ascending
|
||||||
|
articles_paginator A paginator object of article list
|
||||||
|
articles_page The current page of articles
|
||||||
|
dates_paginator A paginator object of article list, ordered by date,
|
||||||
|
ascending
|
||||||
|
dates_page The current page of articles, ordered by date,
|
||||||
|
ascending
|
||||||
|
page_name 'tag/`tag_name`'. Useful for pagination links.
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
|
Include skribit script
|
||||||
|
======================
|
||||||
|
|
||||||
|
In order to support skribit scripts in your themes, you must following these
|
||||||
|
actions :
|
||||||
|
|
||||||
|
* Copy `skribit_tab_script.html` and `skribit_widget_script.html` in your
|
||||||
|
templates directory.
|
||||||
|
* Add {% include 'skribit_tab_script.html' %} in your <head> part in order to
|
||||||
|
support suggestions tab.
|
||||||
|
* Add {% include 'skribit_widget_script.html' %} where you want in order to
|
||||||
|
support sidebar widget.
|
||||||
|
|
||||||
|
You can take a look at notmyidea default theme for working example.
|
||||||
|
|
|
||||||
|
|
@ -1,87 +1,92 @@
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from pelican.settings import read_settings
|
|
||||||
from pelican.utils import clean_output_dir
|
|
||||||
from pelican.writers import Writer
|
|
||||||
from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
||||||
StaticGenerator, PdfGenerator)
|
StaticGenerator, PdfGenerator)
|
||||||
|
from pelican.settings import read_settings
|
||||||
|
from pelican.utils import clean_output_dir, files_changed
|
||||||
|
from pelican.writers import Writer
|
||||||
|
|
||||||
VERSION = "2.5.3"
|
VERSION = "2.6.0"
|
||||||
|
|
||||||
|
|
||||||
def init_params(settings=None, path=None, theme=None, output_path=None,
|
class Pelican(object):
|
||||||
markup=None, keep=False):
|
def __init__(self, settings=None, path=None, theme=None, output_path=None,
|
||||||
"""Read the settings, and performs some checks on the environment
|
markup=None, keep=False):
|
||||||
before doing anything else.
|
"""Read the settings, and performs some checks on the environment
|
||||||
"""
|
before doing anything else.
|
||||||
if settings is None:
|
"""
|
||||||
settings = {}
|
self.path = path or settings['PATH']
|
||||||
settings = read_settings(settings)
|
if not self.path:
|
||||||
path = path or settings['PATH']
|
raise Exception('you need to specify a path to search the docs on !')
|
||||||
if path.endswith('/'):
|
if self.path.endswith('/'):
|
||||||
path = path[:-1]
|
self.path = path[:-1]
|
||||||
|
|
||||||
# define the default settings
|
# define the default settings
|
||||||
theme = theme or settings['THEME']
|
self.settings = settings
|
||||||
output_path = output_path or settings['OUTPUT_PATH']
|
self.theme = theme or settings['THEME']
|
||||||
output_path = os.path.realpath(output_path)
|
output_path = output_path or settings['OUTPUT_PATH']
|
||||||
markup = markup or settings['MARKUP']
|
self.output_path = os.path.realpath(output_path)
|
||||||
keep = keep or settings['KEEP_OUTPUT_DIRECTORY']
|
self.markup = markup or settings['MARKUP']
|
||||||
|
self.keep = keep or settings['KEEP_OUTPUT_DIRECTORY']
|
||||||
|
|
||||||
# find the theme in pelican.theme if the given one does not exists
|
# find the theme in pelican.theme if the given one does not exists
|
||||||
if not os.path.exists(theme):
|
if not os.path.exists(self.theme):
|
||||||
theme_path = os.sep.join([os.path.dirname(
|
theme_path = os.sep.join([os.path.dirname(
|
||||||
os.path.abspath(__file__)), "themes/%s" % theme])
|
os.path.abspath(__file__)), "themes/%s" % self.theme])
|
||||||
if os.path.exists(theme_path):
|
if os.path.exists(theme_path):
|
||||||
theme = theme_path
|
self.theme = theme_path
|
||||||
else:
|
else:
|
||||||
raise Exception("Impossible to find the theme %s" % theme)
|
raise Exception("Impossible to find the theme %s" % theme)
|
||||||
|
|
||||||
# get the list of files to parse
|
def run(self):
|
||||||
if not path:
|
"""Run the generators and return"""
|
||||||
raise Exception('you need to specify a path to search the docs on !')
|
|
||||||
|
|
||||||
return settings, path, theme, output_path, markup, keep
|
context = self.settings.copy()
|
||||||
|
generators = [
|
||||||
|
cls(
|
||||||
|
context,
|
||||||
|
self.settings,
|
||||||
|
self.path,
|
||||||
|
self.theme,
|
||||||
|
self.output_path,
|
||||||
|
self.markup,
|
||||||
|
self.keep
|
||||||
|
) for cls in self.get_generator_classes()
|
||||||
|
]
|
||||||
|
|
||||||
|
for p in generators:
|
||||||
|
if hasattr(p, 'generate_context'):
|
||||||
|
p.generate_context()
|
||||||
|
|
||||||
|
# erase the directory if it is not the source
|
||||||
|
if os.path.realpath(self.path).startswith(self.output_path) and not self.keep:
|
||||||
|
clean_output_dir(self.output_path)
|
||||||
|
|
||||||
|
writer = self.get_writer()
|
||||||
|
|
||||||
|
for p in generators:
|
||||||
|
if hasattr(p, 'generate_output'):
|
||||||
|
p.generate_output(writer)
|
||||||
|
|
||||||
|
|
||||||
def run_generators(generators, settings, path, theme, output_path, markup, keep):
|
def get_generator_classes(self):
|
||||||
"""Run the generators and return"""
|
generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
|
||||||
|
if self.settings['PDF_GENERATOR']:
|
||||||
|
generators.append(PdfGenerator)
|
||||||
|
return generators
|
||||||
|
|
||||||
context = settings.copy()
|
def get_writer(self):
|
||||||
generators = [p(context, settings, path, theme, output_path, markup, keep)
|
return Writer(self.output_path, settings=self.settings)
|
||||||
for p in generators]
|
|
||||||
|
|
||||||
for p in generators:
|
|
||||||
if hasattr(p, 'generate_context'):
|
|
||||||
p.generate_context()
|
|
||||||
|
|
||||||
# erase the directory if it is not the source
|
|
||||||
if output_path not in os.path.realpath(path) and not keep:
|
|
||||||
clean_output_dir(output_path)
|
|
||||||
|
|
||||||
writer = Writer(output_path)
|
|
||||||
|
|
||||||
for p in generators:
|
|
||||||
if hasattr(p, 'generate_output'):
|
|
||||||
p.generate_output(writer)
|
|
||||||
|
|
||||||
|
|
||||||
def run_pelican(settings, path, theme, output_path, markup, delete):
|
|
||||||
"""Run pelican with the given parameters"""
|
|
||||||
|
|
||||||
params = init_params(settings, path, theme, output_path, markup, delete)
|
|
||||||
generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
|
|
||||||
if params[0]['PDF_GENERATOR']: # param[0] is settings
|
|
||||||
generators.append(PdfGenerator)
|
|
||||||
run_generators(generators, *params)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="""A tool to generate a
|
parser = argparse.ArgumentParser(description="""A tool to generate a
|
||||||
static blog, with restructured text input files.""")
|
static blog, with restructured text input files.""")
|
||||||
|
|
||||||
parser.add_argument(dest='path',
|
parser.add_argument(dest='path', nargs='?',
|
||||||
help='Path where to find the content files')
|
help='Path where to find the content files')
|
||||||
parser.add_argument('-t', '--theme-path', dest='theme',
|
parser.add_argument('-t', '--theme-path', dest='theme',
|
||||||
help='Path where to find the theme templates. If not specified, it will'
|
help='Path where to find the theme templates. If not specified, it will'
|
||||||
|
|
@ -99,14 +104,37 @@ def main():
|
||||||
help='Keep the output directory and just update all the generated files.'
|
help='Keep the output directory and just update all the generated files.'
|
||||||
'Default is to delete the output directory.')
|
'Default is to delete the output directory.')
|
||||||
parser.add_argument('--version', action='version', version=VERSION,
|
parser.add_argument('--version', action='version', version=VERSION,
|
||||||
help="Print the pelican version and exit")
|
help='Print the pelican version and exit')
|
||||||
|
parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true',
|
||||||
|
help="Relaunch pelican each time a modification occurs on the content"
|
||||||
|
"files")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Split the markup languages only if some have been given. Otherwise, populate
|
# Split the markup languages only if some have been given. Otherwise, populate
|
||||||
# the variable with None.
|
# the variable with None.
|
||||||
markup = [a.strip().lower() for a in args.markup.split(',')] if args.markup else None
|
markup = [a.strip().lower() for a in args.markup.split(',')] if args.markup else None
|
||||||
|
|
||||||
run_pelican(args.settings, args.path, args.theme, args.output, markup, args.keep)
|
if args.settings is None:
|
||||||
|
settings = {}
|
||||||
|
settings = read_settings(args.settings)
|
||||||
|
|
||||||
|
cls = settings.get('PELICAN_CLASS')
|
||||||
|
if isinstance(cls, basestring):
|
||||||
|
module, cls_name = cls.rsplit('.', 1)
|
||||||
|
module = __import__(module)
|
||||||
|
cls = getattr(module, cls_name)
|
||||||
|
|
||||||
|
pelican = cls(settings, args.path, args.theme, args.output, markup, args.keep)
|
||||||
|
|
||||||
|
if args.autoreload:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if files_changed(pelican.path, pelican.markup):
|
||||||
|
pelican.run()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
pelican.run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
from pelican.utils import slugify, truncate_html_words
|
from pelican.utils import slugify, truncate_html_words
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -11,12 +12,12 @@ class Page(object):
|
||||||
mandatory_properties = ('title',)
|
mandatory_properties = ('title',)
|
||||||
|
|
||||||
def __init__(self, content, metadatas={}, settings={}, filename=None):
|
def __init__(self, content, metadatas={}, settings={}, filename=None):
|
||||||
self.content = content
|
self._content = content
|
||||||
self.translations = []
|
self.translations = []
|
||||||
|
|
||||||
self.status = "published" # default value
|
self.status = "published" # default value
|
||||||
for key, value in metadatas.items():
|
for key, value in metadatas.items():
|
||||||
setattr(self, key, value)
|
setattr(self, key.lower(), value)
|
||||||
|
|
||||||
if not hasattr(self, 'author'):
|
if not hasattr(self, 'author'):
|
||||||
if 'AUTHOR' in settings:
|
if 'AUTHOR' in settings:
|
||||||
|
|
@ -47,6 +48,21 @@ class Page(object):
|
||||||
if filename:
|
if filename:
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
|
||||||
|
if not hasattr(self, 'date_format'):
|
||||||
|
if self.lang in settings['DATE_FORMATS']:
|
||||||
|
self.date_format = settings['DATE_FORMATS'][self.lang]
|
||||||
|
else:
|
||||||
|
self.date_format = settings['DEFAULT_DATE_FORMAT']
|
||||||
|
|
||||||
|
if hasattr(self, 'date'):
|
||||||
|
self.locale_date = self.date.strftime(self.date_format.encode('ascii','xmlcharrefreplace')).decode('utf')
|
||||||
|
|
||||||
|
if not hasattr(self, 'summary'):
|
||||||
|
self.summary = property(lambda self: truncate_html_words(self.content, 50)).__get__(self, Page)
|
||||||
|
|
||||||
|
# store the settings ref.
|
||||||
|
self._settings = settings
|
||||||
|
|
||||||
def check_properties(self):
|
def check_properties(self):
|
||||||
"""test that each mandatory property is set."""
|
"""test that each mandatory property is set."""
|
||||||
for prop in self.mandatory_properties:
|
for prop in self.mandatory_properties:
|
||||||
|
|
@ -54,8 +70,12 @@ class Page(object):
|
||||||
raise NameError(prop)
|
raise NameError(prop)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def summary(self):
|
def content(self):
|
||||||
return truncate_html_words(self.content, 50)
|
if hasattr(self, "_get_content"):
|
||||||
|
content = self._get_content()
|
||||||
|
else:
|
||||||
|
content = self._content
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
class Article(Page):
|
class Article(Page):
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
from operator import attrgetter, itemgetter
|
from operator import attrgetter, itemgetter
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
@ -10,13 +11,10 @@ import random
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
from jinja2.exceptions import TemplateNotFound
|
from jinja2.exceptions import TemplateNotFound
|
||||||
|
|
||||||
from pelican.utils import update_dict, copytree, process_translations, open
|
from pelican.utils import copytree, get_relative_path, process_translations, open
|
||||||
from pelican.contents import Article, Page, is_valid_content
|
from pelican.contents import Article, Page, is_valid_content
|
||||||
from pelican.readers import read_file
|
from pelican.readers import read_file
|
||||||
|
|
||||||
_TEMPLATES = ('index', 'tag', 'tags', 'article', 'category', 'categories',
|
|
||||||
'archives', 'page')
|
|
||||||
|
|
||||||
|
|
||||||
class Generator(object):
|
class Generator(object):
|
||||||
"""Baseclass generator"""
|
"""Baseclass generator"""
|
||||||
|
|
@ -32,7 +30,10 @@ class Generator(object):
|
||||||
# templates cache
|
# templates cache
|
||||||
self._templates = {}
|
self._templates = {}
|
||||||
self._templates_path = os.path.expanduser(os.path.join(self.theme, 'templates'))
|
self._templates_path = os.path.expanduser(os.path.join(self.theme, 'templates'))
|
||||||
self._env = Environment(loader = FileSystemLoader(self._templates_path))
|
self._env = Environment(
|
||||||
|
loader=FileSystemLoader(self._templates_path),
|
||||||
|
extensions=self.settings.get('JINJA_EXTENSIONS', []),
|
||||||
|
)
|
||||||
|
|
||||||
def get_template(self, name):
|
def get_template(self, name):
|
||||||
"""Return the template by name.
|
"""Return the template by name.
|
||||||
|
|
@ -84,8 +85,8 @@ class ArticlesGenerator(Generator):
|
||||||
self.articles = [] # only articles in default language
|
self.articles = [] # only articles in default language
|
||||||
self.translations = []
|
self.translations = []
|
||||||
self.dates = {}
|
self.dates = {}
|
||||||
self.tags = {}
|
self.tags = defaultdict(list)
|
||||||
self.categories = {}
|
self.categories = defaultdict(list)
|
||||||
super(ArticlesGenerator, self).__init__(*args, **kwargs)
|
super(ArticlesGenerator, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def generate_feeds(self, writer):
|
def generate_feeds(self, writer):
|
||||||
|
|
@ -97,7 +98,7 @@ class ArticlesGenerator(Generator):
|
||||||
writer.write_feed(self.articles, self.context,
|
writer.write_feed(self.articles, self.context,
|
||||||
self.settings['FEED_RSS'], feed_type='rss')
|
self.settings['FEED_RSS'], feed_type='rss')
|
||||||
|
|
||||||
for cat, arts in self.categories.items():
|
for cat, arts in self.categories:
|
||||||
arts.sort(key=attrgetter('date'), reverse=True)
|
arts.sort(key=attrgetter('date'), reverse=True)
|
||||||
writer.write_feed(arts, self.context,
|
writer.write_feed(arts, self.context,
|
||||||
self.settings['CATEGORY_FEED'] % cat)
|
self.settings['CATEGORY_FEED'] % cat)
|
||||||
|
|
@ -135,26 +136,41 @@ class ArticlesGenerator(Generator):
|
||||||
writer.write_file,
|
writer.write_file,
|
||||||
relative_urls = self.settings.get('RELATIVE_URLS')
|
relative_urls = self.settings.get('RELATIVE_URLS')
|
||||||
)
|
)
|
||||||
for template in self.settings.get('DIRECT_TEMPLATES'):
|
|
||||||
write('%s.html' % template, self.get_template(template), self.context,
|
|
||||||
blog=True)
|
|
||||||
|
|
||||||
tag_template = self.get_template('tag')
|
|
||||||
for tag, articles in self.tags.items():
|
|
||||||
write('tag/%s.html' % tag, tag_template, self.context, tag=tag,
|
|
||||||
articles=articles)
|
|
||||||
|
|
||||||
category_template = self.get_template('category')
|
|
||||||
for cat in self.categories:
|
|
||||||
write('category/%s.html' % cat, category_template, self.context,
|
|
||||||
category=cat, articles=self.categories[cat])
|
|
||||||
|
|
||||||
|
# to minimize the number of relative path stuff modification
|
||||||
|
# in writer, articles pass first
|
||||||
article_template = self.get_template('article')
|
article_template = self.get_template('article')
|
||||||
for article in chain(self.translations, self.articles):
|
for article in chain(self.translations, self.articles):
|
||||||
write(article.save_as,
|
write(article.save_as,
|
||||||
article_template, self.context, article=article,
|
article_template, self.context, article=article,
|
||||||
category=article.category)
|
category=article.category)
|
||||||
|
|
||||||
|
PAGINATED_TEMPLATES = self.settings.get('PAGINATED_DIRECT_TEMPLATES')
|
||||||
|
for template in self.settings.get('DIRECT_TEMPLATES'):
|
||||||
|
paginated = {}
|
||||||
|
if template in PAGINATED_TEMPLATES:
|
||||||
|
paginated = {'articles': self.articles, 'dates': self.dates}
|
||||||
|
write('%s.html' % template, self.get_template(template), self.context,
|
||||||
|
blog=True, paginated=paginated, page_name=template)
|
||||||
|
|
||||||
|
# and subfolders after that
|
||||||
|
tag_template = self.get_template('tag')
|
||||||
|
for tag, articles in self.tags.items():
|
||||||
|
dates = [article for article in self.dates if article in articles]
|
||||||
|
write('tag/%s.html' % tag, tag_template, self.context, tag=tag,
|
||||||
|
articles=articles, dates=dates,
|
||||||
|
paginated={'articles': articles, 'dates': dates},
|
||||||
|
page_name='tag/%s' % tag)
|
||||||
|
|
||||||
|
category_template = self.get_template('category')
|
||||||
|
for cat, articles in self.categories:
|
||||||
|
dates = [article for article in self.dates if article in articles]
|
||||||
|
write('category/%s.html' % cat, category_template, self.context,
|
||||||
|
category=cat, articles=articles, dates=dates,
|
||||||
|
paginated={'articles': articles, 'dates': dates},
|
||||||
|
page_name='category/%s' % cat)
|
||||||
|
|
||||||
|
|
||||||
def generate_context(self):
|
def generate_context(self):
|
||||||
"""change the context"""
|
"""change the context"""
|
||||||
|
|
||||||
|
|
@ -166,8 +182,7 @@ class ArticlesGenerator(Generator):
|
||||||
|
|
||||||
# if no category is set, use the name of the path as a category
|
# if no category is set, use the name of the path as a category
|
||||||
if 'category' not in metadatas.keys():
|
if 'category' not in metadatas.keys():
|
||||||
category = os.path.dirname(f).replace(
|
category = os.path.basename(os.path.dirname(f))
|
||||||
os.path.expanduser(self.path)+'/', '')
|
|
||||||
|
|
||||||
if category == self.path:
|
if category == self.path:
|
||||||
category = self.settings['DEFAULT_CATEGORY']
|
category = self.settings['DEFAULT_CATEGORY']
|
||||||
|
|
@ -186,14 +201,14 @@ class ArticlesGenerator(Generator):
|
||||||
|
|
||||||
if hasattr(article, 'tags'):
|
if hasattr(article, 'tags'):
|
||||||
for tag in article.tags:
|
for tag in article.tags:
|
||||||
update_dict(self.tags, tag, article)
|
self.tags[tag].append(article)
|
||||||
all_articles.append(article)
|
all_articles.append(article)
|
||||||
|
|
||||||
self.articles, self.translations = process_translations(all_articles)
|
self.articles, self.translations = process_translations(all_articles)
|
||||||
|
|
||||||
for article in self.articles:
|
for article in self.articles:
|
||||||
# only main articles are listed in categories, not translations
|
# only main articles are listed in categories, not translations
|
||||||
update_dict(self.categories, article.category, article)
|
self.categories[article.category].append(article)
|
||||||
|
|
||||||
|
|
||||||
# sort the articles by date
|
# sort the articles by date
|
||||||
|
|
@ -228,8 +243,13 @@ class ArticlesGenerator(Generator):
|
||||||
random.shuffle(self.tag_cloud)
|
random.shuffle(self.tag_cloud)
|
||||||
|
|
||||||
# and generate the output :)
|
# and generate the output :)
|
||||||
|
|
||||||
|
# order the categories per name
|
||||||
|
self.categories = list(self.categories.items())
|
||||||
|
self.categories.sort(reverse=self.settings.get('REVERSE_CATEGORY_ORDER'))
|
||||||
self._update_context(('articles', 'dates', 'tags', 'categories', 'tag_cloud'))
|
self._update_context(('articles', 'dates', 'tags', 'categories', 'tag_cloud'))
|
||||||
|
|
||||||
|
|
||||||
def generate_output(self, writer):
|
def generate_output(self, writer):
|
||||||
self.generate_feeds(writer)
|
self.generate_feeds(writer)
|
||||||
self.generate_pages(writer)
|
self.generate_pages(writer)
|
||||||
|
|
@ -304,7 +324,8 @@ class PdfGenerator(Generator):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def generate_output(self, writer=None):
|
def generate_output(self, writer=None):
|
||||||
# we don't use the writer passed as argument here, since we write our own files
|
# we don't use the writer passed as argument here
|
||||||
|
# since we write our own files
|
||||||
print u' Generating PDF files...'
|
print u' Generating PDF files...'
|
||||||
pdf_path = os.path.join(self.output_path, 'pdf')
|
pdf_path = os.path.join(self.output_path, 'pdf')
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
85
pelican/paginator.py
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
# From django.core.paginator
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
class Paginator(object):
|
||||||
|
def __init__(self, object_list, per_page, orphans=0):
|
||||||
|
self.object_list = object_list
|
||||||
|
self.per_page = per_page
|
||||||
|
self.orphans = orphans
|
||||||
|
self._num_pages = self._count = None
|
||||||
|
|
||||||
|
def page(self, number):
|
||||||
|
"Returns a Page object for the given 1-based page number."
|
||||||
|
bottom = (number - 1) * self.per_page
|
||||||
|
top = bottom + self.per_page
|
||||||
|
if top + self.orphans >= self.count:
|
||||||
|
top = self.count
|
||||||
|
return Page(self.object_list[bottom:top], number, self)
|
||||||
|
|
||||||
|
def _get_count(self):
|
||||||
|
"Returns the total number of objects, across all pages."
|
||||||
|
if self._count is None:
|
||||||
|
self._count = len(self.object_list)
|
||||||
|
return self._count
|
||||||
|
count = property(_get_count)
|
||||||
|
|
||||||
|
def _get_num_pages(self):
|
||||||
|
"Returns the total number of pages."
|
||||||
|
if self._num_pages is None:
|
||||||
|
hits = max(1, self.count - self.orphans)
|
||||||
|
self._num_pages = int(ceil(hits / float(self.per_page)))
|
||||||
|
return self._num_pages
|
||||||
|
num_pages = property(_get_num_pages)
|
||||||
|
|
||||||
|
def _get_page_range(self):
|
||||||
|
"""
|
||||||
|
Returns a 1-based range of pages for iterating through within
|
||||||
|
a template for loop.
|
||||||
|
"""
|
||||||
|
return range(1, self.num_pages + 1)
|
||||||
|
page_range = property(_get_page_range)
|
||||||
|
|
||||||
|
class Page(object):
|
||||||
|
def __init__(self, object_list, number, paginator):
|
||||||
|
self.object_list = object_list
|
||||||
|
self.number = number
|
||||||
|
self.paginator = paginator
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
|
||||||
|
|
||||||
|
def has_next(self):
|
||||||
|
return self.number < self.paginator.num_pages
|
||||||
|
|
||||||
|
def has_previous(self):
|
||||||
|
return self.number > 1
|
||||||
|
|
||||||
|
def has_other_pages(self):
|
||||||
|
return self.has_previous() or self.has_next()
|
||||||
|
|
||||||
|
def next_page_number(self):
|
||||||
|
return self.number + 1
|
||||||
|
|
||||||
|
def previous_page_number(self):
|
||||||
|
return self.number - 1
|
||||||
|
|
||||||
|
def start_index(self):
|
||||||
|
"""
|
||||||
|
Returns the 1-based index of the first object on this page,
|
||||||
|
relative to total objects in the paginator.
|
||||||
|
"""
|
||||||
|
# Special case, return zero if no items.
|
||||||
|
if self.paginator.count == 0:
|
||||||
|
return 0
|
||||||
|
return (self.paginator.per_page * (self.number - 1)) + 1
|
||||||
|
|
||||||
|
def end_index(self):
|
||||||
|
"""
|
||||||
|
Returns the 1-based index of the last object on this page,
|
||||||
|
relative to total objects found (hits).
|
||||||
|
"""
|
||||||
|
# Special case for the last page because there can be orphans.
|
||||||
|
if self.number == self.paginator.num_pages:
|
||||||
|
return self.paginator.count
|
||||||
|
return self.number * self.paginator.per_page
|
||||||
|
|
||||||
|
|
@ -1,11 +1,18 @@
|
||||||
from docutils import core
|
# -*- coding: utf-8 -*-
|
||||||
from markdown import Markdown
|
try:
|
||||||
|
from docutils import core
|
||||||
|
|
||||||
|
# import the directives to have pygments support
|
||||||
|
import rstdirectives
|
||||||
|
except ImportError:
|
||||||
|
core = False
|
||||||
|
try:
|
||||||
|
from markdown import Markdown
|
||||||
|
except ImportError:
|
||||||
|
Markdown = False
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
|
|
||||||
# import the directives to have pygments support
|
|
||||||
import rstdirectives
|
|
||||||
|
|
||||||
from pelican.utils import get_date, open
|
from pelican.utils import get_date, open
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -16,7 +23,12 @@ _METADATAS_PROCESSORS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RstReader(object):
|
class Reader(object):
|
||||||
|
enabled = True
|
||||||
|
|
||||||
|
class RstReader(Reader):
|
||||||
|
enabled = bool(core)
|
||||||
|
extension = "rst"
|
||||||
|
|
||||||
def _parse_metadata(self, content):
|
def _parse_metadata(self, content):
|
||||||
"""Return the dict containing metadatas"""
|
"""Return the dict containing metadatas"""
|
||||||
|
|
@ -42,7 +54,9 @@ class RstReader(object):
|
||||||
metadatas['title'] = title
|
metadatas['title'] = title
|
||||||
return content, metadatas
|
return content, metadatas
|
||||||
|
|
||||||
class MarkdownReader(object):
|
class MarkdownReader(Reader):
|
||||||
|
enabled = bool(Markdown)
|
||||||
|
extension = "md"
|
||||||
|
|
||||||
def read(self, filename):
|
def read(self, filename):
|
||||||
"""Parse content and metadata of markdown files"""
|
"""Parse content and metadata of markdown files"""
|
||||||
|
|
@ -58,8 +72,25 @@ class MarkdownReader(object):
|
||||||
)(value[0])
|
)(value[0])
|
||||||
return content, metadatas
|
return content, metadatas
|
||||||
|
|
||||||
_EXTENSIONS = {'rst': RstReader, 'md': MarkdownReader} # supported formats
|
|
||||||
|
|
||||||
|
class HtmlReader(Reader):
|
||||||
|
extension = "html"
|
||||||
|
_re = re.compile('\<\!\-\-\#\s?[A-z0-9_-]*\s?\:s?[A-z0-9\s_-]*\s?\-\-\>')
|
||||||
|
|
||||||
|
def read(self, filename):
|
||||||
|
"""Parse content and metadata of (x)HTML files"""
|
||||||
|
content = open(filename)
|
||||||
|
metadatas = {'title':'unnamed'}
|
||||||
|
for i in self._re.findall(content):
|
||||||
|
key = i.split(':')[0][5:].strip()
|
||||||
|
value = i.split(':')[-1][:-3].strip()
|
||||||
|
metadatas[key.lower()] = value
|
||||||
|
|
||||||
|
return content, metadatas
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_EXTENSIONS = dict((cls.extension, cls) for cls in Reader.__subclasses__())
|
||||||
|
|
||||||
def read_file(filename, fmt=None):
|
def read_file(filename, fmt=None):
|
||||||
"""Return a reader object using the given format."""
|
"""Return a reader object using the given format."""
|
||||||
|
|
@ -68,4 +99,6 @@ def read_file(filename, fmt=None):
|
||||||
if fmt not in _EXTENSIONS.keys():
|
if fmt not in _EXTENSIONS.keys():
|
||||||
raise TypeError('Pelican does not know how to parse %s' % filename)
|
raise TypeError('Pelican does not know how to parse %s' % filename)
|
||||||
reader = _EXTENSIONS[fmt]()
|
reader = _EXTENSIONS[fmt]()
|
||||||
|
if not reader.enabled:
|
||||||
|
raise ValueError("Missing dependencies for %s" % fmt)
|
||||||
return reader.read(filename)
|
return reader.read(filename)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
|
import locale
|
||||||
|
|
||||||
_DEFAULT_THEME = os.sep.join([os.path.dirname(os.path.abspath(__file__)),
|
_DEFAULT_THEME = os.sep.join([os.path.dirname(os.path.abspath(__file__)),
|
||||||
"themes/notmyidea"])
|
"themes/notmyidea"])
|
||||||
|
|
@ -18,6 +20,7 @@ _DEFAULT_CONFIG = {'PATH': None,
|
||||||
'FALLBACK_ON_FS_DATE': True,
|
'FALLBACK_ON_FS_DATE': True,
|
||||||
'CSS_FILE': 'main.css',
|
'CSS_FILE': 'main.css',
|
||||||
'REVERSE_ARCHIVE_ORDER': False,
|
'REVERSE_ARCHIVE_ORDER': False,
|
||||||
|
'REVERSE_CATEGORY_ORDER': False,
|
||||||
'KEEP_OUTPUT_DIRECTORY': False,
|
'KEEP_OUTPUT_DIRECTORY': False,
|
||||||
'CLEAN_URLS': False, # use /blah/ instead /blah.html in urls
|
'CLEAN_URLS': False, # use /blah/ instead /blah.html in urls
|
||||||
'RELATIVE_URLS': True,
|
'RELATIVE_URLS': True,
|
||||||
|
|
@ -25,6 +28,15 @@ _DEFAULT_CONFIG = {'PATH': None,
|
||||||
'TAG_CLOUD_STEPS': 4,
|
'TAG_CLOUD_STEPS': 4,
|
||||||
'TAG_CLOUD_MAX_ITEMS': 100,
|
'TAG_CLOUD_MAX_ITEMS': 100,
|
||||||
'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'archives'),
|
'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'archives'),
|
||||||
|
'PAGINATED_DIRECT_TEMPLATES': ('index', ),
|
||||||
|
'PELICAN_CLASS': 'pelican.Pelican',
|
||||||
|
'DEFAULT_DATE_FORMAT': '%a %d %B %Y',
|
||||||
|
'DATE_FORMATS': {},
|
||||||
|
'JINJA_EXTENSIONS': [],
|
||||||
|
'LOCALE': '', # default to user locale
|
||||||
|
'WITH_PAGINATION': False,
|
||||||
|
'DEFAULT_PAGINATION': 5,
|
||||||
|
'DEFAULT_ORPHANS': 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
def read_settings(filename):
|
def read_settings(filename):
|
||||||
|
|
@ -37,4 +49,7 @@ def read_settings(filename):
|
||||||
for key in tempdict:
|
for key in tempdict:
|
||||||
if key.isupper():
|
if key.isupper():
|
||||||
context[key] = tempdict[key]
|
context[key] = tempdict[key]
|
||||||
|
|
||||||
|
# set the locale
|
||||||
|
locale.setlocale(locale.LC_ALL, context['LOCALE'])
|
||||||
return context
|
return context
|
||||||
|
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
.hll {
|
|
||||||
background-color:#FFFFCC;
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,414 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
Design by Free CSS Templates
|
|
||||||
http://www.freecsstemplates.org
|
|
||||||
Released for free under a Creative Commons Attribution 2.5 License
|
|
||||||
*/
|
|
||||||
@import url("pygment.css");
|
|
||||||
body {
|
|
||||||
margin: 30px 0px 0px 0px;
|
|
||||||
padding: 0;
|
|
||||||
background: #7E776F url('../images/img01.jpg') repeat left top;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #3E3B36;
|
|
||||||
}
|
|
||||||
.summary h2{font-size:1.6em; color:black;}
|
|
||||||
h1, h2, h3 {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
color: #F0E9E9;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 2.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
p, ul, ol {
|
|
||||||
margin-top: 0;
|
|
||||||
line-height: 180%;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul, ol {
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #4D8D99;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrapper {
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Header */
|
|
||||||
|
|
||||||
#header-wrapper {
|
|
||||||
height: 100px;
|
|
||||||
background: #3C3230;
|
|
||||||
border-bottom: 10px solid #4F4440;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header {
|
|
||||||
width: 950px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0px 0px 0px 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Logo */
|
|
||||||
|
|
||||||
#logo {
|
|
||||||
width: 280px;
|
|
||||||
height: 140px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
background: url('../images/img07.jpg') no-repeat left top;
|
|
||||||
color: #34312C;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo h1, #logo p {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
letter-spacing: -2px;
|
|
||||||
text-align: center;
|
|
||||||
font-family: Georgia, "Times New Roman", Times, serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo h1 {
|
|
||||||
margin: 0px 0px -20px 0px;
|
|
||||||
padding: 20px 0px 0px 0px;
|
|
||||||
font-size: 50px;
|
|
||||||
color: #4D8D99;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo h1 a {
|
|
||||||
color: #F0E9E9;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo p {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
font-size: 26px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo a {
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #34312C;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search */
|
|
||||||
|
|
||||||
#search {
|
|
||||||
width: 280px;
|
|
||||||
height: 50px;
|
|
||||||
padding: 20px 0px 0px 0px;
|
|
||||||
background: url('../images/img05.jpg') no-repeat left 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search form {
|
|
||||||
margin: 0px 0px 0px 0px;
|
|
||||||
padding: 0px 0px 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search fieldset {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-text {
|
|
||||||
width: 190px;
|
|
||||||
padding: 0px 5px 2px 10px;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
text-transform: lowercase;
|
|
||||||
font: normal 11px Arial, Helvetica, sans-serif;
|
|
||||||
color: #34312C;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-submit {
|
|
||||||
width: 70px;
|
|
||||||
height: 22px;
|
|
||||||
border: none;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
text-indent: -99999px;
|
|
||||||
color: #34312C;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Menu */
|
|
||||||
|
|
||||||
#menu {
|
|
||||||
width: 280px;
|
|
||||||
margin: 20px auto 20px auto;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu ul {
|
|
||||||
margin: 0;
|
|
||||||
padding: 50px 0px 0px 0px;
|
|
||||||
list-style: none;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu li {
|
|
||||||
border-bottom: 1px dashed #191918;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu a {
|
|
||||||
display: block;
|
|
||||||
width: 260px;
|
|
||||||
height: 27px;
|
|
||||||
margin: 4px 0px;
|
|
||||||
padding: 8px 0px 0px 20px;
|
|
||||||
text-decoration: none;
|
|
||||||
text-transform: capitalize;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: normal;
|
|
||||||
color: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu a:hover, #menu .current_page_item a {
|
|
||||||
background: url('../images/img06.jpg') no-repeat left top;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu .current_page_item a {
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Page */
|
|
||||||
|
|
||||||
#page {
|
|
||||||
width: 1000px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: url('../images/img04.jpg') repeat-y left top;
|
|
||||||
}
|
|
||||||
|
|
||||||
#page-bgtop {
|
|
||||||
background: url('../images/img02.jpg') no-repeat left top;
|
|
||||||
}
|
|
||||||
|
|
||||||
#page-bgbtm {
|
|
||||||
overflow: hidden;
|
|
||||||
width: 920px;
|
|
||||||
padding: 20px 40px 20px 40px;
|
|
||||||
background: url(images/img03.jpg) no-repeat left bottom;
|
|
||||||
}
|
|
||||||
/* Content */
|
|
||||||
|
|
||||||
#content {
|
|
||||||
float: right;
|
|
||||||
width: 520px;
|
|
||||||
padding: 70px 30px 0px 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post .title {
|
|
||||||
padding: 0px 0px 0px 0px;
|
|
||||||
font-family: Georgia, "Times New Roman", Times, serif;
|
|
||||||
letter-spacing: -.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post .title a {
|
|
||||||
color: #52483E;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post .meta {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
padding: 10px 0px 0px 0px;
|
|
||||||
text-align: left;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post .meta .date {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post .meta .posted {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post .meta a {
|
|
||||||
}
|
|
||||||
|
|
||||||
.post .entry {
|
|
||||||
padding: 0px 0px 20px 0px;
|
|
||||||
border-bottom: 1px dotted #99938B;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
.post .entry dt {
|
|
||||||
font-weight:bold ;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post img {
|
|
||||||
margin:10px;
|
|
||||||
border:black;
|
|
||||||
}
|
|
||||||
.summary img{
|
|
||||||
display:none
|
|
||||||
}
|
|
||||||
|
|
||||||
.entry h2{
|
|
||||||
font-size: 1.6em;
|
|
||||||
color: #36302a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entry h3{
|
|
||||||
font-size: 1.2em;
|
|
||||||
color: #36302a;
|
|
||||||
}
|
|
||||||
h2.title {
|
|
||||||
font-size:2.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight{
|
|
||||||
background:black;
|
|
||||||
padding:2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight pre{
|
|
||||||
color:white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight{
|
|
||||||
overflow:auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.links {
|
|
||||||
padding-top: 20px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sidebar */
|
|
||||||
|
|
||||||
#sidebar {
|
|
||||||
float: left;
|
|
||||||
width: 280px;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px 0px 80px 10px;
|
|
||||||
color: #787878;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar ul {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar li {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar li ul {
|
|
||||||
margin: 0px 0px 0px 20px;
|
|
||||||
padding-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar li li {
|
|
||||||
line-height: 35px;
|
|
||||||
border-bottom: 1px dashed #191918;
|
|
||||||
border-left: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar li li span {
|
|
||||||
display: block;
|
|
||||||
margin-top: -20px;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 11px;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar li li a {
|
|
||||||
color: #787878;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar li li a:hover {
|
|
||||||
color: #F0E9E9;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar h2 {
|
|
||||||
height: 38px;
|
|
||||||
letter-spacing: -.5px;
|
|
||||||
font-size: 1.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar p {
|
|
||||||
margin: 0 0px;
|
|
||||||
padding: 0px 20px 20px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar a {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar a:hover {
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calendar */
|
|
||||||
|
|
||||||
#calendar {
|
|
||||||
}
|
|
||||||
|
|
||||||
#calendar_wrap {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#calendar table {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#calendar tbody td {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#calendar #next {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Footer */
|
|
||||||
|
|
||||||
#footer {
|
|
||||||
width: 920px;
|
|
||||||
height: 80px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0px 0 15px 310px;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer p {
|
|
||||||
margin: 0;
|
|
||||||
padding-top: 20px;
|
|
||||||
line-height: normal;
|
|
||||||
font-size: 9px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-align: center;
|
|
||||||
color: #69635E;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer a {
|
|
||||||
color: #474440;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
|
@ -1,11 +0,0 @@
|
||||||
{% if GOOGLE_ANALYTICS %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
|
||||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
try {
|
|
||||||
var pageTracker = _gat._getTracker("{{GOOGLE_ANALYTICS}}");
|
|
||||||
pageTracker._trackPageview();
|
|
||||||
} catch(err) {}</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block title %}Archives de {{ SITENAME }}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<div id="content">
|
|
||||||
<div class="post">
|
|
||||||
<dl>
|
|
||||||
<h2 class="title">Archives de {{ SITENAME }}</h2>
|
|
||||||
{% for article in dates %}
|
|
||||||
<dt>{{ article.date.strftime('%a %d %B %Y') }}</dt>
|
|
||||||
<dd><a href='{{ article.url }}'>{{ article.title }}</a></dd>
|
|
||||||
<dd>Catégorie : <a href="{{ article.category }}">{{ article.category }}</a></dd>
|
|
||||||
{% endfor %}
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
</div>
|
|
||||||
<!-- end #content -->
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block title %}{{ article.title }}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<div id="content">
|
|
||||||
<div class="post">
|
|
||||||
<h2 class="title"><a href="{{ article.url }}">{{ article.title }}</a></h2>
|
|
||||||
<p class="meta"><span class="date">Le {{ article.date.strftime('%a %d %B %Y') }} </span><span class="posted">Par <a href="#">{{ article.author }}</a></span><span> | Catégorie : <a href="{{ SITEURL }}/category/{{ article.category }}.html">{{ article.category }}</a></span></p>
|
|
||||||
<p class="meta">Tags : {% for tag in article.tags %}
|
|
||||||
<span><a href="{{ SITEURL }}/tag/{{ tag }}.html">{{ tag }}</a> / </span>
|
|
||||||
{% endfor %}</p>
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
<div class="entry">
|
|
||||||
{{ article.content }}
|
|
||||||
{% include 'twitter.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
{% if DISQUS_SITENAME %}
|
|
||||||
<div class="post">
|
|
||||||
<h2 class="title">Commentaires !</h2>
|
|
||||||
<div id="disqus_thread"></div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
var disqus_identifier = "{{ article.url }}";
|
|
||||||
(function() {
|
|
||||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
|
||||||
dsq.src = 'http://{{ DISQUS_SITENAME }}.disqus.com/embed.js';
|
|
||||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<!-- end #content -->
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<!--
|
|
||||||
Design by Free CSS Templates
|
|
||||||
http://www.freecsstemplates.org
|
|
||||||
Released for free under a Creative Commons Attribution 2.5 License
|
|
||||||
|
|
||||||
Name : Brown Stone
|
|
||||||
Description: A two-column, fixed-width design with dark color scheme.
|
|
||||||
Version : 1.0
|
|
||||||
Released : 20100928
|
|
||||||
|
|
||||||
-->
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<meta name="keywords" content="" />
|
|
||||||
<meta name="description" content="" />
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
|
||||||
<title>{% block title %}{{ SITENAME }}{%endblock%}</title>
|
|
||||||
<link href="{{ SITEURL }}/theme/css/style.css" rel="stylesheet" type="text/css" media="screen" />
|
|
||||||
<link href="{{ SITEURL }}/{{ FEED }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} ATOM Feed" />
|
|
||||||
{% if FEED_RSS %}
|
|
||||||
<link href="{{ SITEURL }}/{{ FEED_RSS }}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} RSS Feed" />
|
|
||||||
{% endif %}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="wrapper">
|
|
||||||
<div id="page">
|
|
||||||
<div id="page-bgtop">
|
|
||||||
<div id="page-bgbtm">
|
|
||||||
{% block content %}
|
|
||||||
{% endblock %}
|
|
||||||
<div id="sidebar">
|
|
||||||
<div id="logo">
|
|
||||||
<h1><a href="{{ SITEURL }}">{{ SITENAME }}</h1>
|
|
||||||
{% if SITESUBTITLE %}<p>{{ SITESUBTITLE }}</p>{% endif %}
|
|
||||||
</div>
|
|
||||||
<div id="menu">
|
|
||||||
<ul>
|
|
||||||
<li class="current_page_item"><a href="{{ SITEURL }}">Home</a></li>
|
|
||||||
<li><a href="{{ SITEURL }}/archives.html">Archives</a></li>
|
|
||||||
{% if DISPLAY_PAGES_ON_MENU %}
|
|
||||||
{% for page in PAGES %}
|
|
||||||
<li><a href="{{ SITEURL }}/pages/{{ page.url }}">{{ page.title }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<h2>Catégories</h2>
|
|
||||||
<ul>
|
|
||||||
{% for cat, null in categories %}
|
|
||||||
<li {% if cat == category %}class="active"{% endif %}><a href="{{ SITEURL }}/category/{{ cat }}.html">{{ cat }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{% if LINKS %}
|
|
||||||
<li>
|
|
||||||
<h2>Blogroll</h2>
|
|
||||||
<ul>
|
|
||||||
{% for name, link in LINKS %}
|
|
||||||
<li><a href="{{ link }}">{{ name }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% if SOCIAL %}
|
|
||||||
<li>
|
|
||||||
<h2>Social</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="{{ SITEURL }}/{{ FEED }}" rel="alternate">Flux Atom</a></li>
|
|
||||||
{% if FEED_RSS %}
|
|
||||||
<li><a href="{{ SITEURL }}/{{ FEED_RSS }}" rel="alternate">Flux Rss</a></li>
|
|
||||||
{% endif %}
|
|
||||||
{% for name, link in SOCIAL %}
|
|
||||||
<li><a href="{{ link }}">{{ name }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</li><!-- /.social -->
|
|
||||||
{% endif %}
|
|
||||||
<li>
|
|
||||||
<h2>Tags</h2>
|
|
||||||
<ul>
|
|
||||||
{% for tag, articles in tags %}
|
|
||||||
<li><a href="{{ SITEURL }}/tag/{{ tag }}.html">{{ tag }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<!-- end #sidebar -->
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- end #page -->
|
|
||||||
|
|
||||||
<div id="footer">
|
|
||||||
<p>Copyright (c) 2008 Sitename.com. All rights reserved. Design by <a href="http://www.freecsstemplates.org/">CSS Templates</a>.</p>
|
|
||||||
<p>Proudly powered by <a href="http://alexis.notmyidea.org/pelican/">pelican</a>, which takes great advantages of <a href="http://python.org">python</a>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{% include 'analytics.html' %}
|
|
||||||
<!-- end #footer -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block content %}
|
|
||||||
<div id="content">
|
|
||||||
<div class="post">
|
|
||||||
{% if articles %}
|
|
||||||
{% for article in articles %}
|
|
||||||
{% if loop.index == 1 %}
|
|
||||||
<ul>
|
|
||||||
{% for category, articles in categories %}
|
|
||||||
<li>{{ category }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
{% extends "index.html" %}
|
|
||||||
{% block title %}{{ SITENAME }} - {{ category }}{% endblock %}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block content_title %}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% if articles %}
|
|
||||||
{% for article in articles %}
|
|
||||||
{% if loop.index == 1 %}
|
|
||||||
<div id="content">
|
|
||||||
<div class="post">
|
|
||||||
<h2 class="title"><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></h2>
|
|
||||||
<p class="meta"><span class="date">Le {{ article.date.strftime('%a %d %B %Y') }} </span><span class="posted">Par <a href="#">{{ article.author }}</a></span><span> | Catégorie : <a href="{{ SITEURL }}/category/{{ article.category }}.html">{{ article.category }}</a></span></p>
|
|
||||||
<p class="meta">Tags : {% for tag in article.tags %}
|
|
||||||
<span><a href="{{ SITEURL }}/tag/{{ tag }}.html">{{ tag }}</a> / </span>
|
|
||||||
{% endfor %}</p>
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
<div class="entry">
|
|
||||||
{{ article.content }}
|
|
||||||
{% include 'twitter.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if loop.length > 1 %}
|
|
||||||
<div class="post">
|
|
||||||
<h2 class="title">Autres articles</h2>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<div class="post summary">
|
|
||||||
<h2 class="title"><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></h2>
|
|
||||||
<p class="meta"><span class="date">Le {{ article.date.strftime('%a %d %B %Y') }}</span><span class="posted">Par <a href="#">{{ article.author }}</a></span></p>
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
<div class="entry">
|
|
||||||
{{ article.summary }}
|
|
||||||
<a class="readmore" href="{{ SITEURL }}/{{ article.url }}">Lire la suite …</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<div id="content">
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block title %}{{ page.title }}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<div id="content">
|
|
||||||
<div class="post">
|
|
||||||
<h2 class="title"><a href="{{ SITEURL }}/pages/{{ page.url }}">{{ page.title }}</a></h1>
|
|
||||||
{% if PDF_PROCESSOR %}<a href="{{ SITEURL }}/pdf/{{ page.slug }}.pdf">get
|
|
||||||
the pdf</a>{% endif %}
|
|
||||||
<div style="clear: both;"> </div>
|
|
||||||
<div class="entry">
|
|
||||||
{{ page.content }}
|
|
||||||
{% include 'twitter.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
{% extends "index.html" %}
|
|
||||||
{% block title %}{{ SITENAME }} - {{ tag }}{% endblock %}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block content %}
|
|
||||||
<div id="content">
|
|
||||||
<div class="post">
|
|
||||||
<ul>
|
|
||||||
{% for tag, articles in tags %}
|
|
||||||
<li>{{ tag }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
{% if TWITTER_USERNAME %}
|
|
||||||
<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="{{TWITTER_USERNAME}}">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
@ -1,404 +0,0 @@
|
||||||
/* Resets to avoid browser differences */
|
|
||||||
|
|
||||||
body, button, div, fieldset, form, h1, h2, h3, input, label, li, p, pre, td, textarea, .typygmentdown {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-align: justify;
|
|
||||||
font-family: Georgia, serif;
|
|
||||||
font-size: 100%;
|
|
||||||
line-height: 1.25;
|
|
||||||
letter-spacing: 0;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Overall page layout */
|
|
||||||
|
|
||||||
body {
|
|
||||||
background: white;
|
|
||||||
color: black;
|
|
||||||
color: #303030;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen {
|
|
||||||
body {
|
|
||||||
width: 700px;
|
|
||||||
margin: 20px auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
body {
|
|
||||||
margin: 0 2em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Headings */
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6, .info, .info p {
|
|
||||||
font-family: Times, serif;
|
|
||||||
font-weight: normal;
|
|
||||||
page-break-inside: avoid;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 .caps, h2 .caps, h3 .caps {
|
|
||||||
letter-spacing: -.05em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-family: Times, serif;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 2.25em;
|
|
||||||
line-height: 1.111;
|
|
||||||
padding-right: 0.08em;
|
|
||||||
letter-spacing: -.07em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-top: 0.714em;
|
|
||||||
font-size: 1.75em;
|
|
||||||
line-height: 0.714;
|
|
||||||
letter-spacing: -.05em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: 0.926em;
|
|
||||||
font-size: 1.35em;
|
|
||||||
line-height: 0.926;
|
|
||||||
letter-spacing: -.03em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 .dquo, h2 .dquo, h3 .dquo, h4 .dquo, h5 .dquo, h6 .dquo {
|
|
||||||
margin-left: -.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info, .info p {
|
|
||||||
text-align: center;
|
|
||||||
letter-spacing: -.03em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info img.g {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
margin: -7px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#home h2 a[href*="http://"] {
|
|
||||||
padding-right: 28px;
|
|
||||||
background: url("/static/link.png") right center no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
#home h2 a[href*="http://"]:visited {
|
|
||||||
padding-right: 28px;
|
|
||||||
background: url("/static/visited.png") right center no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 + p.published {
|
|
||||||
float: right;
|
|
||||||
margin-top: -1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copyright {
|
|
||||||
margin: 1.25em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Page text */
|
|
||||||
|
|
||||||
p, p[class] + p {
|
|
||||||
margin-top: 1.25em;
|
|
||||||
widows: 2;
|
|
||||||
orphans: 2;
|
|
||||||
text-indent: 0;
|
|
||||||
clear: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
p + p {
|
|
||||||
text-indent: 1.5em;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p ~ img {
|
|
||||||
display: block;
|
|
||||||
margin: 1.25em auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.caps {
|
|
||||||
letter-spacing: 0.1em;
|
|
||||||
font-size: 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr {
|
|
||||||
border-bottom: 1px dotted black;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0 1em;
|
|
||||||
font-style: italic;
|
|
||||||
letter-spacing: -0.0625em;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote em {
|
|
||||||
font-style: normal;
|
|
||||||
letter-spacing: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.image {
|
|
||||||
text-align: center;
|
|
||||||
margin: 1.25em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.side {
|
|
||||||
position: absolute;
|
|
||||||
width: 150px;
|
|
||||||
height: auto;
|
|
||||||
margin-left: 710px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left.side {
|
|
||||||
margin-left: -160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right.side {
|
|
||||||
margin-left: 710px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen {
|
|
||||||
h1 a, h2 a, h3 a, .info a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:link {
|
|
||||||
color: #85ac40;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: #61883b;
|
|
||||||
}
|
|
||||||
|
|
||||||
::selection {
|
|
||||||
background: #dcff9d;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-moz-selection {
|
|
||||||
background: #e2ffaf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lists */
|
|
||||||
|
|
||||||
ul, ol {
|
|
||||||
margin: 1.25em 0 1.25em -1.5em;
|
|
||||||
padding-left: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul ul, ul ol, ol ol, ol ul {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul li {
|
|
||||||
list-style: disc;
|
|
||||||
}
|
|
||||||
|
|
||||||
li p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Code */
|
|
||||||
|
|
||||||
pre {
|
|
||||||
margin-top: 1.47em;
|
|
||||||
font-family: Courier;
|
|
||||||
font-size: .85em;
|
|
||||||
line-height: 1.47;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: Courier;
|
|
||||||
font-size: .85em;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typygmentdown .c {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typygmentdown .k, .typygmentdown .ow {
|
|
||||||
color: #404040;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typygmentdown .c, .typygmentdown .sd {
|
|
||||||
color: #808080;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Comments */
|
|
||||||
|
|
||||||
#comment-list {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-list li {
|
|
||||||
padding-bottom: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-list cite {
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-list cite + blockquote {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-list blockquote {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-list p {
|
|
||||||
margin-top: 1.25em;
|
|
||||||
text-indent: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-form th {
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-form input, #comment-form select, #comment-form textarea {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
#comment-list, #comment-form {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Friends */
|
|
||||||
|
|
||||||
#friends li {
|
|
||||||
list-style: none;
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#friends a[rel] {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#friends a[rel~="colleague"] {
|
|
||||||
background: url("/static/dj.png") left center no-repeat;
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forms */
|
|
||||||
|
|
||||||
form, form p {
|
|
||||||
text-indent: 0;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
from th, form td {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input, select, textarea {
|
|
||||||
background: white;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="submit"], button {
|
|
||||||
border: 1px outset;
|
|
||||||
text-align: center;
|
|
||||||
background: #85ac40;
|
|
||||||
padding: .2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"], textarea {
|
|
||||||
vertical-align: top;
|
|
||||||
border: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"], select {
|
|
||||||
width: 15em;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
width: 45em;
|
|
||||||
height: 7.5em;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#honeypot {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tables */
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border: none;
|
|
||||||
margin: 1.25em auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
border-bottom: 1px solid #303030;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead th {
|
|
||||||
border-bottom: 1px solid #303030;
|
|
||||||
}
|
|
||||||
|
|
||||||
tfoot th,
|
|
||||||
tfoot td {
|
|
||||||
border-top: 1px solid #303030;
|
|
||||||
}
|
|
||||||
|
|
||||||
th[scope="row"],
|
|
||||||
th[scope="col"] {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody + tbody th, tbody + tbody td {
|
|
||||||
border-top: 1px solid #d0d0d0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody + tbody tr + tr th,
|
|
||||||
tbody + tbody tr + tr td,
|
|
||||||
tfoot tr + tr th,
|
|
||||||
tfoot tr + tr td {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
th, td {
|
|
||||||
padding: 0 0.5em;
|
|
||||||
font-weight: normal;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.numeric td, table.numeric th[scope="col"] {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block title %}{{ article.title }}{%endblock%}
|
|
||||||
{% block content %}
|
|
||||||
<h1>{{ article.title }}</h1>
|
|
||||||
<div class="info">
|
|
||||||
{% if article.author %}
|
|
||||||
By <a class="url fn" href="#">{{ article.author }}</a>
|
|
||||||
{% endif %}
|
|
||||||
on <a>{{ article.date.strftime('%a %d %B %Y') }}</a>
|
|
||||||
about <a href="{{ SITEURL }}/category/{{ article.category }}.html">{{ article.category }}</a>
|
|
||||||
</div>
|
|
||||||
{{ article.content }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>{% block title %}{{ SITENAME }}{%endblock%}</title>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/style.css" type="text/css" />
|
|
||||||
<link href="{{ SITEURL }}/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} ATOM Feed" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{% block content %} {% endblock %}
|
|
||||||
|
|
||||||
<div class="copyright info vcard">Design by <a class="fn url"
|
|
||||||
href="http://martyalchin.com">Marty Alchin</a>, <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">some rights reserved</a>. Powered by <a href="http://alexis.notomyidea.org/pelican/">pelican</a></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block title %}{{ category }}{%endblock%}
|
|
||||||
<h1>{{ category }}</h1>
|
|
||||||
<div class="info"></div>
|
|
||||||
{% for article in articles %}
|
|
||||||
<h2><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></h2>
|
|
||||||
<p class="published">{{ article.date.strftime('%a %d %B %Y') }}</p>
|
|
||||||
{{ article.summary }}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block content %}
|
|
||||||
<h1><a href="{{ SITEURL }}">{{ SITENAME }}</a></h1>
|
|
||||||
{% if SITESUBTITLE %} <div class="info">{{ SITESUBTITLE }}</div> {% endif %}
|
|
||||||
{% for article in articles %}
|
|
||||||
<h2><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></h2>
|
|
||||||
<p class="published">{{ article.date.strftime('%a %d %B %Y') }}</p>
|
|
||||||
{{ article.summary }}
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block title %}{{ page.title }}{%endblock%}
|
|
||||||
{% block content %}
|
|
||||||
<h1>{{ page.title }}</h1>
|
|
||||||
{{ page.content }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
@ -276,14 +276,6 @@ img.left, figure.left {float: right; margin: 0 0 2em 2em;}
|
||||||
padding: .3em .25em;
|
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;}
|
#extras a:hover, #extras a:active {color: #fff;}
|
||||||
|
|
||||||
/* Blogroll */
|
/* Blogroll */
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
{% for article in dates %}
|
{% for article in dates %}
|
||||||
<dt>{{ article.date.strftime('%a %d %B %Y') }}</dt>
|
<dt>{{ article.locale_date }}</dt>
|
||||||
<dd><a href='{{ article.url }}'>{{ article.title }}</a></dd>
|
<dd><a href='{{ article.url }}'>{{ article.title }}</a></dd>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,7 @@
|
||||||
rel="bookmark" title="Permalink to {{ article.title }}">{{ article.title
|
rel="bookmark" title="Permalink to {{ article.title }}">{{ article.title
|
||||||
}}</a></h1> {% include 'twitter.html' %} </header>
|
}}</a></h1> {% include 'twitter.html' %} </header>
|
||||||
<div class="entry-content">
|
<div class="entry-content">
|
||||||
<footer class="post-info">
|
{% include 'article_infos.html' %}
|
||||||
<abbr class="published" title="{{ article.date.isoformat() }}">
|
|
||||||
{{ article.date.strftime('%a %d %B %Y') }}
|
|
||||||
</abbr>
|
|
||||||
{% if article.author %}
|
|
||||||
<address class="vcard author">
|
|
||||||
By <a class="url fn" href="#">{{ article.author }}</a>
|
|
||||||
</address>
|
|
||||||
{% endif %}
|
|
||||||
<p>In <a href="{{ SITEURL }}/category/{{ article.category }}.html">{{ article.category }}</a>.
|
|
||||||
{% include 'taglist.html' %}
|
|
||||||
</footer><!-- /.post-info -->
|
|
||||||
{{ article.content }}
|
{{ article.content }}
|
||||||
</div><!-- /.entry-content -->
|
</div><!-- /.entry-content -->
|
||||||
{% if DISQUS_SITENAME %}
|
{% if DISQUS_SITENAME %}
|
||||||
|
|
|
||||||
14
pelican/themes/notmyidea/templates/article_infos.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<footer class="post-info">
|
||||||
|
<abbr class="published" title="{{ article.date.isoformat() }}">
|
||||||
|
{{ article.locale_date }}
|
||||||
|
</abbr>
|
||||||
|
|
||||||
|
{% if article.author %}
|
||||||
|
<address class="vcard author">
|
||||||
|
By <a class="url fn" href="#">{{ article.author }}</a>
|
||||||
|
</address>
|
||||||
|
{% endif %}
|
||||||
|
<p>In <a href="{{ SITEURL }}/category/{{ article.category }}.html">{{ article.category }}</a>. {% if PDF_PROCESSOR %}<a href="{{ SITEURL }}/pdf/{{ article.slug }}.pdf">get the pdf</a>{% endif %}</p>
|
||||||
|
{% include 'taglist.html' %}
|
||||||
|
{% include 'translations.html' %}
|
||||||
|
</footer><!-- /.post-info -->
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<link href="{{ SITEURL }}/{{ FEED_RSS }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} RSS Feed" />
|
<link href="{{ SITEURL }}/{{ FEED_RSS }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} RSS Feed" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% include 'skribit_tab_script.html' %}
|
||||||
|
|
||||||
<!--[if IE]>
|
<!--[if IE]>
|
||||||
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
|
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
|
||||||
|
|
@ -53,6 +54,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div><!-- /.blogroll -->
|
</div><!-- /.blogroll -->
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% include 'skribit_widget_script.html' %}
|
||||||
{% if SOCIAL %}
|
{% if SOCIAL %}
|
||||||
<div class="social">
|
<div class="social">
|
||||||
<h2>social</h2>
|
<h2>social</h2>
|
||||||
|
|
|
||||||
|
|
@ -2,62 +2,53 @@
|
||||||
{% block content_title %}{% endblock %}
|
{% block content_title %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if articles %}
|
{% if articles %}
|
||||||
{% for article in articles %}
|
{% for article in articles_page.object_list %}
|
||||||
{% if loop.index == 1 %}
|
|
||||||
<aside id="featured" class="body"><article>
|
|
||||||
<h1 class="entry-title"><a href="{{ SITEURL }}/{{ article.url
|
|
||||||
}}">{{ article.title }}</a></h1>
|
|
||||||
<footer class="post-info">
|
|
||||||
<abbr class="published" title="{{ article.date.isoformat() }}">
|
|
||||||
{{ article.date.strftime('%a %d %B %Y') }}
|
|
||||||
</abbr>
|
|
||||||
|
|
||||||
{% if article.author %}
|
{# First item #}
|
||||||
<address class="vcard author">
|
{% if loop.first and not articles_page.has_previous() %}
|
||||||
By <a class="url fn" href="#">{{ article.author }}</a>
|
<aside id="featured" class="body">
|
||||||
</address>
|
<article>
|
||||||
{% endif %}
|
<h1 class="entry-title"><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></h1>
|
||||||
<p>In <a href="{{ SITEURL }}/category/{{ article.category }}.html">{{ article.category }}</a>. {% if PDF_PROCESSOR %}<a href="{{ SITEURL }}/pdf/{{ article.slug }}.pdf">get the pdf</a>{% endif %}</p>
|
{% include 'article_infos.html' %}{{ article.content }}{% include 'comments.html' %}
|
||||||
{% include 'taglist.html' %}
|
|
||||||
</footer><!-- /.post-info -->
|
|
||||||
{{ article.content }}
|
|
||||||
{% include 'comments.html' %}
|
|
||||||
</article>
|
</article>
|
||||||
</aside><!-- /#featured -->
|
{% if loop.length == 1 %}
|
||||||
{% if loop.length > 1 %}
|
{% include 'pagination.html' %}
|
||||||
<section id="content" class="body">
|
{% endif %}
|
||||||
<h1>Other articles</h1>
|
</aside><!-- /#featured -->
|
||||||
<hr />
|
{% if loop.length > 1 %}
|
||||||
<ol id="posts-list" class="hfeed">
|
<section id="content" class="body">
|
||||||
{% endif %}
|
<h1>Other articles</h1>
|
||||||
{% else %}
|
<hr />
|
||||||
<li><article class="hentry">
|
<ol id="posts-list" class="hfeed">
|
||||||
|
{% endif %}
|
||||||
|
{# other items #}
|
||||||
|
{% else %}
|
||||||
|
{% if loop.first and articles_page.has_previous %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<ol id="posts-list" class="hfeed" start="{{ articles_paginator.per_page -1 }}">
|
||||||
|
{% endif %}
|
||||||
|
<li><article class="hentry">
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h1>
|
<h1><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="entry-content">
|
<div class="entry-content">
|
||||||
<footer class="post-info">
|
{% include 'article_infos.html' %}
|
||||||
<abbr class="published" title="{{ article.date.isoformat() }}">
|
|
||||||
{{ article.date.strftime('%a %d %B %Y') }}
|
|
||||||
</abbr>
|
|
||||||
|
|
||||||
<address class="vcard author">
|
|
||||||
By <a class="url fn" href="#">{{ article.author }}</a>
|
|
||||||
</address>
|
|
||||||
<p> In <a href="{{ SITEURL }}/category/{{ article.category }}.html">{{ article.category }}</a></p>
|
|
||||||
{% include 'taglist.html' %}
|
|
||||||
<p>{% if PDF_PROCESSOR %}<a href="{{ SITEURL }}/pdf/{{ article.slug }}.pdf">pdf</a>{% endif %}</p>
|
|
||||||
</footer><!-- /.post-info -->
|
|
||||||
{{ article.summary }}
|
{{ article.summary }}
|
||||||
<a class="readmore" href="{{ SITEURL }}/{{ article.url }}">read more</a>
|
<a class="readmore" href="{{ SITEURL }}/{{ article.url }}">read more</a>
|
||||||
{% include 'comments.html' %}
|
{% include 'comments.html' %}
|
||||||
</div><!-- /.entry-content -->
|
</div><!-- /.entry-content -->
|
||||||
</article></li>
|
</article></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if loop.last and (articles_page.has_previous()
|
||||||
|
or not articles_page.has_previous() and loop.length > 1) %}
|
||||||
|
{% include 'pagination.html' %}
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol><!-- /#posts-list -->
|
{% if loop.length > 1 or articles_page.has_previous() %}
|
||||||
</section><!-- /#content -->
|
</ol><!-- /#posts-list -->
|
||||||
|
</section><!-- /#content -->
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<section id="content" class="body">
|
<section id="content" class="body">
|
||||||
<h2>Pages</h2>
|
<h2>Pages</h2>
|
||||||
|
|
|
||||||
13
pelican/themes/notmyidea/templates/pagination.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<p class="paginator">
|
||||||
|
{% if articles_page.has_previous() %}
|
||||||
|
{% if articles_page.previous_page_number() == 1 %}
|
||||||
|
<a href="{{ SITEURL }}/{{ page_name }}.html">«</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.previous_page_number() }}.html">«</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
Page {{ articles_page.number }} / {{ articles_paginator.num_pages }}
|
||||||
|
{% if articles_page.has_next() %}
|
||||||
|
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.next_page_number() }}.html">»</a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
14
pelican/themes/notmyidea/templates/skribit_tab_script.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% if SKRIBIT_TYPE and SKRIBIT_TYPE == 'TAB' and SKRIBIT_TAB_SITENAME %}
|
||||||
|
<link rel="stylesheet" type="text/css" media="screen" charset="utf-8" href="http://assets.skribit.com/stylesheets/SkribitSuggest.css"></link>
|
||||||
|
<style type="text/css" media="print" charset="utf-8">a#sk_tab{display:none !important;}</style>
|
||||||
|
<script src="http://assets.skribit.com/javascripts/SkribitSuggest.js" type="text/javascript"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
var skribit_settings = {};
|
||||||
|
skribit_settings.placement = "{{ SKRIBIT_TAB_PLACEMENT or 'right' }}";
|
||||||
|
skribit_settings.color = "{{ SKRIBIT_TAB_COLOR or '#333333' }}";
|
||||||
|
skribit_settings.text_color = "{{ SKRIBIT_TAB_TEXT_COLOR or 'white' }}";
|
||||||
|
skribit_settings.distance_vert = "{{ SKRIBIT_TAB_VERT or '20%' }}";
|
||||||
|
skribit_settings.distance_horiz = "{{ SKRIBIT_TAB_HORIZ or '' }}";
|
||||||
|
SkribitSuggest.suggest('http://skribit.com/lightbox/{{ SKRIBIT_TAB_SITENAME }}', skribit_settings);
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% if SKRIBIT_TYPE == 'WIDGET' and SKRIBIT_WIDGET_ID %}
|
||||||
|
<div id="writeSkribitHere"></div>
|
||||||
|
<script src="http://assets.skribit.com/javascripts/SkribitWidget.js?renderTo=writeSkribitHere&blog={{ SKRIBIT_WIDGET_ID }}&cnt=5"></script>
|
||||||
|
<noscript>Sorry, but the
|
||||||
|
<a href="http://skribit.com" title="Skribit - Cure Writer's Block">Skribit</a> widget only works on browsers with JavaScript support.
|
||||||
|
<a href="http://skribit.com/blogs/think-different-think-open" title="Skribit Suggestions for Think Different, Think Open">View suggestions for this blog here.</a>
|
||||||
|
</noscript>
|
||||||
|
{% endif %}
|
||||||
6
pelican/themes/notmyidea/templates/translations.html
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{% if article.translations %}
|
||||||
|
Translations:
|
||||||
|
{% for translation in article.translations %}
|
||||||
|
<a href="{{ SITEURL }}/{{ translation.url }}">{{ translation.lang }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
{% for article in dates %}
|
{% for article in dates %}
|
||||||
<dt>{{ article.date.strftime('%Y-%m-%d %H:%M') }}</dt>
|
<dt>{{ article.locale_date }}</dt>
|
||||||
<dd><a href='{{ article.url }}'>{{ article.title }}</a></dd>
|
<dd><a href='{{ article.url }}'>{{ article.title }}</a></dd>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<header> <h2 class="entry-title"><a href="{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h2> </header>
|
<header> <h2 class="entry-title"><a href="{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h2> </header>
|
||||||
<footer class="post-info">
|
<footer class="post-info">
|
||||||
<abbr class="published" title="{{ article.date.isoformat() }}">
|
<abbr class="published" title="{{ article.date.isoformat() }}">
|
||||||
{{ article.date.strftime('%Y-%m-%d %H:%M') }}
|
{{ article.locale_date }}
|
||||||
</abbr>
|
</abbr>
|
||||||
{% if article.author %}
|
{% if article.author %}
|
||||||
<address class="vcard author">
|
<address class="vcard author">
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
</header><!-- /#banner -->
|
</header><!-- /#banner -->
|
||||||
{% if categories %}<ul>
|
{% if categories %}<ul>
|
||||||
{% for category, articles in categories %}
|
{% for category, articles in categories %}
|
||||||
<li><a href="category/{{category}}.html">{{ category }}</a></li>
|
<li><a href="{{ SITEURL }}/category/{{category}}.html">{{ category }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul> {% endif %}
|
</ul> {% endif %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,29 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<ol id="post-list">
|
<ol id="post-list">
|
||||||
{% for article in articles %}
|
{% for article in articles_page.object_list %}
|
||||||
<li><article class="hentry">
|
<li><article class="hentry">
|
||||||
<header> <h2 class="entry-title"><a href="{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h2> </header>
|
<header> <h2 class="entry-title"><a href="{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h2> </header>
|
||||||
<footer class="post-info">
|
<footer class="post-info">
|
||||||
<abbr class="published" title="{{ article.date.isoformat() }}"> {{ article.date.strftime('%Y-%m-%d %H:%M') }} </abbr>
|
<abbr class="published" title="{{ article.date.isoformat() }}"> {{ article.locale_date }} </abbr>
|
||||||
{% if article.author %}<address class="vcard author">By <a class="url fn" href="#">{{ article.author }}</a></address>{% endif %}
|
{% if article.author %}<address class="vcard author">By <a class="url fn" href="#">{{ article.author }}</a></address>{% endif %}
|
||||||
</footer><!-- /.post-info -->
|
</footer><!-- /.post-info -->
|
||||||
<div class="entry-content"> {{ article.summary }} </div><!-- /.entry-content -->
|
<div class="entry-content"> {{ article.summary }} </div><!-- /.entry-content -->
|
||||||
</article></li>
|
</article></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol><!-- /#posts-list -->
|
</ol><!-- /#posts-list -->
|
||||||
|
<p class="paginator">
|
||||||
|
{% if articles_page.has_previous() %}
|
||||||
|
{% if articles_page.previous_page_number() == 1 %}
|
||||||
|
<a href="{{ SITEURL }}/{{ page_name }}.html">«</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.previous_page_number() }}.html">«</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
Page {{ articles_page.number }} / {{ articles_paginator.num_pages }}
|
||||||
|
{% if articles_page.has_next() %}
|
||||||
|
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.next_page_number() }}.html">»</a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
</section><!-- /#content -->
|
</section><!-- /#content -->
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,6 @@ from codecs import open as _open
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
def update_dict(mapping, key, value):
|
|
||||||
"""Update a dict intenal list
|
|
||||||
|
|
||||||
:param mapping: the mapping to update
|
|
||||||
:param key: the key of the mapping to update.
|
|
||||||
:param value: the value to append to the list.
|
|
||||||
"""
|
|
||||||
if key not in mapping:
|
|
||||||
mapping[key] = []
|
|
||||||
mapping[key].append(value)
|
|
||||||
|
|
||||||
|
|
||||||
def get_date(string):
|
def get_date(string):
|
||||||
"""Return a datetime object from a string.
|
"""Return a datetime object from a string.
|
||||||
|
|
@ -73,7 +62,7 @@ def clean_output_dir(path):
|
||||||
# remove all the existing content from the output folder
|
# remove all the existing content from the output folder
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -159,6 +148,7 @@ def process_translations(content_list):
|
||||||
Also, for each content_list item, it
|
Also, for each content_list item, it
|
||||||
sets attribute 'translations'
|
sets attribute 'translations'
|
||||||
"""
|
"""
|
||||||
|
content_list.sort(key=attrgetter('slug'))
|
||||||
grouped_by_slugs = groupby(content_list, attrgetter('slug'))
|
grouped_by_slugs = groupby(content_list, attrgetter('slug'))
|
||||||
index = []
|
index = []
|
||||||
translations = []
|
translations = []
|
||||||
|
|
@ -184,3 +174,27 @@ def process_translations(content_list):
|
||||||
for a in items:
|
for a in items:
|
||||||
a.translations = filter(lambda x: x != a, items)
|
a.translations = filter(lambda x: x != a, items)
|
||||||
return index, translations
|
return index, translations
|
||||||
|
|
||||||
|
|
||||||
|
LAST_MTIME = 0
|
||||||
|
|
||||||
|
|
||||||
|
def files_changed(path, extensions):
|
||||||
|
"""Return True if the files have changed since the last check"""
|
||||||
|
|
||||||
|
def with_extension(f):
|
||||||
|
return True if True in [f.endswith(ext) for ext in extensions] else False
|
||||||
|
|
||||||
|
def file_times(path):
|
||||||
|
"""Return the last time files have been modified"""
|
||||||
|
for top_level in os.listdir(path):
|
||||||
|
for root, dirs, files in os.walk(top_level):
|
||||||
|
for file in filter(with_extension, files):
|
||||||
|
yield os.stat(os.path.join(root, file)).st_mtime
|
||||||
|
|
||||||
|
global LAST_MTIME
|
||||||
|
mtime = max(file_times(path))
|
||||||
|
if mtime > LAST_MTIME:
|
||||||
|
LAST_MTIME = mtime
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,41 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from codecs import open
|
from codecs import open
|
||||||
|
from functools import partial
|
||||||
|
import locale
|
||||||
|
|
||||||
from feedgenerator import Atom1Feed, Rss201rev2Feed
|
from feedgenerator import Atom1Feed, Rss201rev2Feed
|
||||||
|
|
||||||
from pelican.utils import get_relative_path
|
from pelican.utils import get_relative_path
|
||||||
|
from pelican.paginator import Paginator
|
||||||
|
|
||||||
|
|
||||||
class Writer(object):
|
class Writer(object):
|
||||||
|
|
||||||
def __init__(self, output_path):
|
def __init__(self, output_path, settings=None):
|
||||||
self.output_path = output_path
|
self.output_path = output_path
|
||||||
|
self.reminder = dict()
|
||||||
|
self.settings = settings or {}
|
||||||
|
|
||||||
|
def _create_new_feed(self, feed_type, context):
|
||||||
|
feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed
|
||||||
|
feed = feed_class(
|
||||||
|
title=context['SITENAME'],
|
||||||
|
link=self.site_url,
|
||||||
|
feed_url=self.feed_url,
|
||||||
|
description=context.get('SITESUBTITLE', ''))
|
||||||
|
return feed
|
||||||
|
|
||||||
|
|
||||||
|
def _add_item_to_the_feed(self, feed, item):
|
||||||
|
|
||||||
|
feed.add_item(
|
||||||
|
title=item.title,
|
||||||
|
link='%s/%s' % (self.site_url, item.url),
|
||||||
|
description=item.content,
|
||||||
|
categories=item.tags if hasattr(item, 'tags') else None,
|
||||||
|
author_name=getattr(item, 'author', 'John Doe'),
|
||||||
|
pubdate=item.date)
|
||||||
|
|
||||||
def write_feed(self, elements, context, filename=None, feed_type='atom'):
|
def write_feed(self, elements, context, filename=None, feed_type='atom'):
|
||||||
"""Generate a feed with the list of articles provided
|
"""Generate a feed with the list of articles provided
|
||||||
|
|
@ -23,58 +49,171 @@ class Writer(object):
|
||||||
:param filename: the filename to output.
|
:param filename: the filename to output.
|
||||||
:param feed_type: the feed type to use (atom or rss)
|
:param feed_type: the feed type to use (atom or rss)
|
||||||
"""
|
"""
|
||||||
site_url = context.get('SITEURL', get_relative_path(filename))
|
old_locale = locale.setlocale(locale.LC_ALL)
|
||||||
|
locale.setlocale(locale.LC_ALL, 'C')
|
||||||
|
try:
|
||||||
|
self.site_url = context.get('SITEURL', get_relative_path(filename))
|
||||||
|
self.feed_url= '%s/%s' % (self.site_url, filename)
|
||||||
|
|
||||||
feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed
|
feed = self._create_new_feed(feed_type, context)
|
||||||
|
|
||||||
feed = feed_class(
|
for item in elements:
|
||||||
title=context['SITENAME'],
|
self._add_item_to_the_feed(feed, item)
|
||||||
link=site_url,
|
|
||||||
feed_url= "%s/%s" % (site_url, filename),
|
|
||||||
description=context.get('SITESUBTITLE', ''))
|
|
||||||
for element in elements:
|
|
||||||
feed.add_item(
|
|
||||||
title=element.title,
|
|
||||||
link= "%s/%s" % (site_url, element.url),
|
|
||||||
description=element.content,
|
|
||||||
categories=element.tags if hasattr(element, "tags") else None,
|
|
||||||
author_name=getattr(element, 'author', 'John Doe'),
|
|
||||||
pubdate=element.date)
|
|
||||||
|
|
||||||
if filename:
|
if filename:
|
||||||
complete_path = os.path.join(self.output_path, filename)
|
complete_path = os.path.join(self.output_path, filename)
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.dirname(complete_path))
|
os.makedirs(os.path.dirname(complete_path))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
fp = open(complete_path, 'w')
|
fp = open(complete_path, 'w')
|
||||||
feed.write(fp, 'utf-8')
|
feed.write(fp, 'utf-8')
|
||||||
print u' [ok] writing %s' % complete_path
|
print u' [ok] writing %s' % complete_path
|
||||||
|
|
||||||
fp.close()
|
fp.close()
|
||||||
return feed
|
return feed
|
||||||
|
finally:
|
||||||
|
locale.setlocale(locale.LC_ALL, old_locale)
|
||||||
|
|
||||||
def write_file(self, name, template, context, relative_urls=True,
|
def write_file(self, name, template, context, relative_urls=True,
|
||||||
**kwargs):
|
paginated=None, **kwargs):
|
||||||
"""Render the template and write the file.
|
"""Render the template and write the file.
|
||||||
|
|
||||||
:param name: name of the file to output
|
:param name: name of the file to output
|
||||||
:param template: template to use to generate the content
|
:param template: template to use to generate the content
|
||||||
:param context: dict to pass to the templates.
|
:param context: dict to pass to the templates.
|
||||||
:param relative_urls: use relative urls or absolutes ones
|
:param relative_urls: use relative urls or absolutes ones
|
||||||
|
:param paginated: dict of article list to paginate - must have the
|
||||||
|
same length (same list in different orders)
|
||||||
:param **kwargs: additional variables to pass to the templates
|
:param **kwargs: additional variables to pass to the templates
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def _write_file(template, localcontext, output_path, name):
|
||||||
|
"""Render the template write the file."""
|
||||||
|
output = template.render(localcontext)
|
||||||
|
filename = os.sep.join((output_path, name))
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.dirname(filename))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
with open(filename, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(output)
|
||||||
|
print u' [ok] writing %s' % filename
|
||||||
|
|
||||||
localcontext = context.copy()
|
localcontext = context.copy()
|
||||||
if relative_urls:
|
if relative_urls:
|
||||||
localcontext['SITEURL'] = get_relative_path(name)
|
localcontext['SITEURL'] = get_relative_path(name)
|
||||||
|
|
||||||
localcontext.update(kwargs)
|
localcontext.update(kwargs)
|
||||||
output = template.render(localcontext)
|
self.update_context_contents(name, localcontext)
|
||||||
filename = os.sep.join((self.output_path, name))
|
|
||||||
try:
|
# check paginated
|
||||||
os.makedirs(os.path.dirname(filename))
|
paginated = paginated or {}
|
||||||
except Exception:
|
if paginated:
|
||||||
pass
|
# pagination needed, init paginators
|
||||||
with open(filename, 'w', encoding='utf-8') as f:
|
paginators = {}
|
||||||
f.write(output)
|
for key in paginated.iterkeys():
|
||||||
print u' [ok] writing %s' % filename
|
object_list = paginated[key]
|
||||||
|
|
||||||
|
if self.settings.get('WITH_PAGINATION'):
|
||||||
|
paginators[key] = Paginator(object_list,
|
||||||
|
self.settings.get('DEFAULT_PAGINATION'),
|
||||||
|
self.settings.get('DEFAULT_ORPHANS'))
|
||||||
|
else:
|
||||||
|
paginators[key] = Paginator(object_list, len(object_list), 0)
|
||||||
|
|
||||||
|
# generated pages, and write
|
||||||
|
for page_num in range(paginators.values()[0].num_pages):
|
||||||
|
paginated_localcontext = localcontext.copy()
|
||||||
|
paginated_name = name
|
||||||
|
for key in paginators.iterkeys():
|
||||||
|
paginator = paginators[key]
|
||||||
|
page = paginator.page(page_num+1)
|
||||||
|
paginated_localcontext.update({'%s_paginator' % key: paginator,
|
||||||
|
'%s_page' % key: page})
|
||||||
|
if page_num > 0:
|
||||||
|
ext = '.' + paginated_name.rsplit('.')[-1]
|
||||||
|
paginated_name = paginated_name.replace(ext,
|
||||||
|
'%s%s' % (page_num + 1, ext))
|
||||||
|
|
||||||
|
_write_file(template, paginated_localcontext, self.output_path,
|
||||||
|
paginated_name)
|
||||||
|
else:
|
||||||
|
# no pagination
|
||||||
|
_write_file(template, localcontext, self.output_path, name)
|
||||||
|
|
||||||
|
def update_context_contents(self, name, context):
|
||||||
|
"""Recursively run the context to find elements (articles, pages, etc)
|
||||||
|
whose content getter needs to
|
||||||
|
be modified in order to deal with relative paths.
|
||||||
|
|
||||||
|
:param name: name of the file to output.
|
||||||
|
:param context: dict that will be passed to the templates.
|
||||||
|
"""
|
||||||
|
if context is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if type(context) == tuple:
|
||||||
|
context = list(context)
|
||||||
|
|
||||||
|
if type(context) == dict:
|
||||||
|
context = list(context.values())
|
||||||
|
|
||||||
|
for i in xrange(len(context)):
|
||||||
|
if type(context[i]) == tuple or type(context[i]) == list:
|
||||||
|
context[i] = self.update_context_contents(name, context[i])
|
||||||
|
|
||||||
|
elif type(context[i]) == dict:
|
||||||
|
context[i] = self.update_context_contents(name, context[i].values())
|
||||||
|
|
||||||
|
elif hasattr(context[i], '_content'):
|
||||||
|
relative_path = get_relative_path(name)
|
||||||
|
item = context[i]
|
||||||
|
|
||||||
|
if item in self.reminder:
|
||||||
|
if relative_path not in self.reminder[item]:
|
||||||
|
l = self.reminder[item]
|
||||||
|
l.append(relative_path)
|
||||||
|
self.inject_update_method(name, item)
|
||||||
|
else:
|
||||||
|
l = list(relative_path)
|
||||||
|
self.reminder[item] = l
|
||||||
|
self.inject_update_method(name, item)
|
||||||
|
return context
|
||||||
|
|
||||||
|
def inject_update_method(self, name, item):
|
||||||
|
"""Replace the content attribute getter of an element by a function
|
||||||
|
that will deals with its relatives paths.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _update_object_content(name, input):
|
||||||
|
"""Change all the relatives paths of the input content to relatives
|
||||||
|
paths suitable fot the ouput content
|
||||||
|
|
||||||
|
:param name: path of the output.
|
||||||
|
:param input: input resource that will be passed to the templates.
|
||||||
|
"""
|
||||||
|
content = input._content
|
||||||
|
|
||||||
|
hrefs = re.compile(r'<\s*[^\>]*href\s*=\s*(["\'])(.*?)\1')
|
||||||
|
srcs = re.compile(r'<\s*[^\>]*src\s*=\s*(["\'])(.*?)\1')
|
||||||
|
|
||||||
|
matches = hrefs.findall(content)
|
||||||
|
matches.extend(srcs.findall(content))
|
||||||
|
relative_paths = []
|
||||||
|
for found in matches:
|
||||||
|
found = found[1]
|
||||||
|
if found not in relative_paths:
|
||||||
|
relative_paths.append(found)
|
||||||
|
|
||||||
|
for relative_path in relative_paths:
|
||||||
|
if not "://" in relative_path: # we don't want to rewrite protocols
|
||||||
|
dest_path = os.sep.join((get_relative_path(name), "static",
|
||||||
|
relative_path))
|
||||||
|
content = content.replace(relative_path, dest_path)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
if item:
|
||||||
|
setattr(item, "_get_content",
|
||||||
|
partial(_update_object_content, name, item))
|
||||||
|
|
|
||||||
7
samples/content/another_super_article-fr.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
Trop bien !
|
||||||
|
###########
|
||||||
|
|
||||||
|
:lang: fr
|
||||||
|
:slug: oh-yeah
|
||||||
|
|
||||||
|
Et voila du contenu en français
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
Oh yeah !
|
Oh yeah !
|
||||||
#########################
|
#########
|
||||||
|
|
||||||
:tags: oh, bar, yeah
|
:tags: oh, bar, yeah
|
||||||
:date: 2010-10-20 10:14
|
:date: 2010-10-20 10:14
|
||||||
:category: bar
|
:category: bar
|
||||||
:author: Alexis Métaireau
|
:author: Alexis Métaireau
|
||||||
|
:slug: oh-yeah
|
||||||
|
|
||||||
Why not ?
|
Why not ?
|
||||||
=========
|
=========
|
||||||
|
|
||||||
After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
|
After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
|
||||||
YEAH !
|
YEAH !
|
||||||
|
|
||||||
|
.. image:: pictures/Sushi.jpg
|
||||||
|
:height: 450 px
|
||||||
|
:width: 600 px
|
||||||
|
:alt: alternate text
|
||||||
|
|
|
||||||
6
samples/content/cat1/article1.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
Article 1
|
||||||
|
#########
|
||||||
|
|
||||||
|
:date: 2011-02-17
|
||||||
|
|
||||||
|
Article 1
|
||||||
6
samples/content/cat1/article2.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
Article 2
|
||||||
|
#########
|
||||||
|
|
||||||
|
:date: 2011-02-17
|
||||||
|
|
||||||
|
Article 2
|
||||||
6
samples/content/cat1/article3.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
Article 3
|
||||||
|
#########
|
||||||
|
|
||||||
|
:date: 2011-02-17
|
||||||
|
|
||||||
|
Article 3
|
||||||
12
samples/content/pages/test_page.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
This is a test page
|
||||||
|
###################
|
||||||
|
|
||||||
|
:category: test
|
||||||
|
|
||||||
|
Just an image.
|
||||||
|
|
||||||
|
.. image:: pictures/Fat_Cat.jpg
|
||||||
|
:height: 450 px
|
||||||
|
:width: 600 px
|
||||||
|
:alt: alternate text
|
||||||
|
|
||||||
BIN
samples/content/pictures/Fat_Cat.jpg
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
samples/content/pictures/Sushi.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
samples/content/pictures/Sushi_Macro.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
|
@ -2,21 +2,33 @@ This is a super article !
|
||||||
#########################
|
#########################
|
||||||
|
|
||||||
:tags: foo, bar, foobar
|
:tags: foo, bar, foobar
|
||||||
:date: 2010-10-02 10:14
|
:date: 2010-12-02 10:14
|
||||||
:category: yeah
|
:category: yeah
|
||||||
:author: Alexis Métaireau
|
:author: Alexis Métaireau
|
||||||
|
:summary: This is a simple test
|
||||||
|
|
||||||
Some content here !
|
Some content here !
|
||||||
|
|
||||||
This is a simple title
|
This is a simple title
|
||||||
======================
|
======================
|
||||||
|
|
||||||
And here comes the cool stuff.
|
And here comes the cool stuff_.
|
||||||
|
|
||||||
|
.. image:: pictures/Sushi.jpg
|
||||||
|
:height: 450 px
|
||||||
|
:width: 600 px
|
||||||
|
:alt: alternate text
|
||||||
|
|
||||||
|
.. image:: pictures/Sushi_Macro.jpg
|
||||||
|
:height: 450 px
|
||||||
|
:width: 600 px
|
||||||
|
:alt: alternate text
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
>>> from ipdb import set trace
|
>>> from ipdb import set_trace
|
||||||
>>> set_trace()
|
>>> set_trace()
|
||||||
|
|
||||||
→ And now try with some utf8 hell: ééé
|
→ And now try with some utf8 hell: ééé
|
||||||
|
|
||||||
|
.. _stuff: http://books.couchdb.org/relax/design-documents/views
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ SITEURL = 'http://blog.notmyidea.org'
|
||||||
GITHUB_URL = 'http://github.com/ametaireau/'
|
GITHUB_URL = 'http://github.com/ametaireau/'
|
||||||
DISQUS_SITENAME = "blog-notmyidea"
|
DISQUS_SITENAME = "blog-notmyidea"
|
||||||
PDF_GENERATOR = False
|
PDF_GENERATOR = False
|
||||||
|
REVERSE_CATEGORY_ORDER = True
|
||||||
|
LOCALE = 'fr_FR.utf8'
|
||||||
|
DEFAULT_PAGINATION = 2
|
||||||
|
|
||||||
|
FEED_RSS = 'feeds/all.rss.xml'
|
||||||
|
CATEGORY_FEED_RSS = 'feeds/%s.rss.xml'
|
||||||
|
|
||||||
LINKS = (('Biologeek', 'http://biologeek.org'),
|
LINKS = (('Biologeek', 'http://biologeek.org'),
|
||||||
('Filyb', "http://filyb.info/"),
|
('Filyb', "http://filyb.info/"),
|
||||||
|
|
@ -17,3 +23,5 @@ LINKS = (('Biologeek', 'http://biologeek.org'),
|
||||||
SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
|
SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
|
||||||
('lastfm', 'http://lastfm.com/user/akounet'),
|
('lastfm', 'http://lastfm.com/user/akounet'),
|
||||||
('github', 'http://github.com/ametaireau'),)
|
('github', 'http://github.com/ametaireau'),)
|
||||||
|
|
||||||
|
STATIC_PATHS = ["pictures",]
|
||||||
|
|
|
||||||
2
setup.py
|
|
@ -1,7 +1,7 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
VERSION = "2.5.3" # find a better way to do so.
|
VERSION = "2.6.0" # find a better way to do so.
|
||||||
|
|
||||||
requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'Markdown']
|
requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'Markdown']
|
||||||
if sys.version_info < (2,7):
|
if sys.version_info < (2,7):
|
||||||
|
|
|
||||||
121
tools/importer.py
Executable file
|
|
@ -0,0 +1,121 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
from pelican.utils import slugify
|
||||||
|
|
||||||
|
from codecs import open
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def wp2fields(xml):
|
||||||
|
"""Opens a wordpress XML file, and yield pelican fields"""
|
||||||
|
from BeautifulSoup import BeautifulStoneSoup
|
||||||
|
|
||||||
|
xmlfile = open(xml, encoding='utf-8').read()
|
||||||
|
soup = BeautifulStoneSoup(xmlfile)
|
||||||
|
items = soup.rss.channel.findAll('item')
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
if item.fetch('wp:status')[0].contents[0] == "publish":
|
||||||
|
title = item.title.contents[0]
|
||||||
|
content = item.fetch('content:encoded')[0].contents[0]
|
||||||
|
filename = item.fetch('wp:post_name')[0].contents[0]
|
||||||
|
|
||||||
|
raw_date = item.fetch('wp:post_date')[0].contents[0]
|
||||||
|
date_object = time.strptime(raw_date, "%Y-%m-%d %H:%M:%S")
|
||||||
|
date = time.strftime("%Y-%m-%d %H:%M", date_object)
|
||||||
|
|
||||||
|
author = item.fetch('dc:creator')[0].contents[0].title()
|
||||||
|
categories = [(cat['nicename'],cat.contents[0]) for cat in item.fetch(domain='category')]
|
||||||
|
|
||||||
|
tags = [tag.contents[0].title() for tag in item.fetch(domain='tag', nicename=None)]
|
||||||
|
|
||||||
|
yield (title, content, filename, date, author, categories, tags)
|
||||||
|
|
||||||
|
def feed2fields(file):
|
||||||
|
"""Read a feed and yield pelican fields"""
|
||||||
|
import feedparser
|
||||||
|
d = feedparser.parse(file)
|
||||||
|
for entry in d.entries:
|
||||||
|
date = (time.strftime("%Y-%m-%d %H:%M", entry.updated_parsed)
|
||||||
|
if hasattr(entry, "updated_parsed") else None)
|
||||||
|
author = entry.author if hasattr(entry, "author") else None
|
||||||
|
tags = [e['term'] for e in entry.tags] if hasattr(entry, "tags") else None
|
||||||
|
|
||||||
|
slug = slugify(entry.title)
|
||||||
|
yield (entry.title, entry.description, slug, date, author, [], tags)
|
||||||
|
|
||||||
|
|
||||||
|
def build_header(title, date, author, categories, tags):
|
||||||
|
"""Build a header from a list of fields"""
|
||||||
|
header = '%s\n%s\n' % (title, '#' * len(title))
|
||||||
|
if date:
|
||||||
|
header += ':date: %s\n' % date
|
||||||
|
if categories:
|
||||||
|
header += ':category: %s\n' % ', '.join(categories)
|
||||||
|
if tags:
|
||||||
|
header += ':tags: %s\n' % ', '.join(tags)
|
||||||
|
header += '\n'
|
||||||
|
return header
|
||||||
|
|
||||||
|
|
||||||
|
def fields2pelican(fields, output_path):
|
||||||
|
for title, content, filename, date, author, categories, tags in fields:
|
||||||
|
html_filename = os.path.join(output_path, filename+'.html')
|
||||||
|
|
||||||
|
if(len(categories) == 1):
|
||||||
|
rst_filename = os.path.join(output_path, categories[0][0], filename+'.rst')
|
||||||
|
if not os.path.isdir(os.path.join(output_path, categories[0][0])):
|
||||||
|
os.mkdir(os.path.join(output_path, categories[0][0]))
|
||||||
|
else:
|
||||||
|
rst_filename = os.path.join(output_path, filename+'.rst')
|
||||||
|
|
||||||
|
with open(html_filename, 'w', encoding='utf-8') as fp:
|
||||||
|
fp.write(content)
|
||||||
|
|
||||||
|
os.system('pandoc --from=html --to=rst -o %s %s' % (rst_filename,
|
||||||
|
html_filename))
|
||||||
|
|
||||||
|
os.remove(html_filename)
|
||||||
|
|
||||||
|
with open(rst_filename, 'r', encoding='utf-8') as fs:
|
||||||
|
content = fs.read()
|
||||||
|
with open(rst_filename, 'w', encoding='utf-8') as fs:
|
||||||
|
categories = [x[1] for x in categories]
|
||||||
|
header = build_header(title, date, author, categories, tags)
|
||||||
|
fs.write(header + content)
|
||||||
|
|
||||||
|
|
||||||
|
def main(input_type, input, output_path):
|
||||||
|
if input_type == 'wordpress':
|
||||||
|
fields = wp2fields(input)
|
||||||
|
elif input_type == 'feed':
|
||||||
|
fields = feed2fields(input)
|
||||||
|
|
||||||
|
fields2pelican(fields, output_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Transform even feed or XML files to rst files."
|
||||||
|
"Be sure to have pandoc installed")
|
||||||
|
|
||||||
|
parser.add_argument(dest='input', help='The input file to read')
|
||||||
|
parser.add_argument('--wpfile', action='store_true', dest='wpfile',
|
||||||
|
help='Wordpress XML export')
|
||||||
|
parser.add_argument('--feed', action='store_true', dest='feed',
|
||||||
|
help='feed to parse')
|
||||||
|
parser.add_argument('-o', '--output', dest='output', default='output',
|
||||||
|
help='Output path')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
input_type = None
|
||||||
|
if args.wpfile:
|
||||||
|
input_type = 'wordpress'
|
||||||
|
elif args.feed:
|
||||||
|
input_type = 'feed'
|
||||||
|
else:
|
||||||
|
print "you must provide either --wpfile or --feed options"
|
||||||
|
exit()
|
||||||
|
main(input_type, args.input, args.output)
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
from BeautifulSoup import BeautifulStoneSoup
|
|
||||||
from codecs import open
|
|
||||||
import os
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
def wp2html(xml):
|
|
||||||
xmlfile = open(xml, encoding='utf-8').read()
|
|
||||||
soup = BeautifulStoneSoup(xmlfile)
|
|
||||||
items = soup.rss.channel.findAll('item')
|
|
||||||
|
|
||||||
for item in items:
|
|
||||||
if item.fetch('wp:status')[0].contents[0] == "publish":
|
|
||||||
title = item.title.contents[0]
|
|
||||||
content = item.fetch('content:encoded')[0].contents[0]
|
|
||||||
filename = item.fetch('wp:post_name')[0].contents[0]
|
|
||||||
yield (title, content, filename)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
parser = argparse.ArgumentParser(description="""Transform a wordpress xml export into rst files """)
|
|
||||||
|
|
||||||
parser.add_argument(dest='xml', help='The xml filepath')
|
|
||||||
parser.add_argument('-o', '--output', dest='output', default='output', help='Output path')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
for title, content, filename in wp2html(args.xml):
|
|
||||||
html_filename = os.path.join(args.output, filename+'.html')
|
|
||||||
rst_filename = os.path.join(args.output, filename+'.rst')
|
|
||||||
|
|
||||||
with open(html_filename, 'w', encoding='utf-8') as fp:
|
|
||||||
fp.write(content)
|
|
||||||
os.system('pandoc --from=html --to=rst -o %s %s' % (rst_filename,
|
|
||||||
html_filename))
|
|
||||||