First commit

This commit is contained in:
Mindiell 2023-04-29 15:57:48 +02:00
commit 7ba46a96f1
46 changed files with 1430 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
venv/
__pycache__/
output/
content/jobs/
content/news/

79
Makefile Normal file
View File

@ -0,0 +1,79 @@
PY?=
PELICAN?=pelican
PELICANOPTS=
BASEDIR=$(CURDIR)
INPUTDIR=$(BASEDIR)/content
OUTPUTDIR=$(BASEDIR)/output
CONFFILE=$(BASEDIR)/pelicanconf.py
PUBLISHCONF=$(BASEDIR)/publishconf.py
VENV = $(PWD)/venv
PIP = $(VENV)/bin/pip
PYTHON = $(VENV)/bin/python
DEBUG ?= 0
ifeq ($(DEBUG), 1)
PELICANOPTS += -D
endif
RELATIVE ?= 0
ifeq ($(RELATIVE), 1)
PELICANOPTS += --relative-urls
endif
SERVER ?= "0.0.0.0"
PORT ?= 0
ifneq ($(PORT), 0)
PELICANOPTS += -p $(PORT)
endif
help:
@echo 'Makefile for a pelican Web site '
@echo ' '
@echo 'Usage: '
@echo ' make html (re)generate the web site '
@echo ' make clean remove the generated files '
@echo ' make regenerate regenerate files upon modification '
@echo ' make publish generate using production settings '
@echo ' make serve [PORT=8000] serve site at http://localhost:8000'
@echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 '
@echo ' make devserver [PORT=8000] serve and regenerate together '
@echo ' make devserver-global regenerate and serve on 0.0.0.0 '
@echo ' make synchronize synchronize news and jobs from AFPy'
@echo ' '
@echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html '
@echo 'Set the RELATIVE variable to 1 to enable relative urls '
@echo ' '
html:
"$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
clean:
[ ! -d "$(OUTPUTDIR)" ] || rm -rf "$(OUTPUTDIR)"
regenerate:
"$(PELICAN)" -r "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
serve:
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
serve-global:
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b $(SERVER)
devserver:
"$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
devserver-global:
$(PELICAN) -lr $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -b 0.0.0.0
publish:
"$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(PUBLISHCONF)" $(PELICANOPTS)
synchronize:
"$(PYTHON)" "synchronize.py"
.PHONY: html help clean regenerate serve serve-global devserver publish synchronize

View File

@ -0,0 +1,23 @@
Title: Les inscriptions pour la PyConFr sont ouvertes !
Date: 2022-11-18 11:47:22
Category: news
Slug: inscriptions-PyConFr-2023
Author: AFPy
![Logo de la PyConFR 2023 à Bordeaux](https://www.pycon.fr/2023/static/images/banniere.png "Logo de la PyConFR 2023 à Bordeaux")
Les inscriptions sont ouvertes 🔓 !
Vous pouvez d'ores et déjà indiquer votre présence à la #PyConFR23, qui aura lieu à
Bordeaux du 16 au 19 février 2023. L'inscription est gratuite 🆓 !
[S'inscrire via helloasso](https://www.helloasso.com/associations/afpy/evenements/pyconfr-2023)
Le jeudi et vendredi, place aux Sprints Les développeurs 👨‍💻 et développeuses 👩‍💻 de
différents projets open source se rejoignent pour coder ensemble. Chaque personne est la
bienvenue pour contribuer, et nous cherchons également à accompagner les débutant·e·s 🔰.
Durant le week-end c'est conférences, vous aurez l'occasion de participer à des
présentations sur des sujets variés, autour du langage Python 🐍 , de ses usages, des
bonnes pratiques, des retours d'expériences, des partages d'idées…

View File

@ -0,0 +1,23 @@
Title: Les adhésions 2022 sont ouvertes et l'AG aura lieu le mercredi 09/02/22 (18h-20h)
Date: 2021-01-29 09:42:07
Category: news
Slug: ouverture-adhesions-2022
Author: AFPy
_Renouvelez ou adhérez à l'AFPy_
Bonjour !
Les [adhésions à l'association](https://www.helloasso.com/associations/afpy/adhesions/adhesion-2022-a-l-afpy)
pour l'année 2022 sont ouvertes !
Cette année encore les adhésions sont gérées à l'aide du site [helloasso](https://www.helloasso.com/).
L'[assemblée générale](https://discuss.afpy.org/t/adhesions-2022-et-assemblee-generale-annuelle/641/5)
aura lieu en [visioconférence](https://bbb.afpy.org/b/jul-cb2-1bd-ost) le mercredi 9 février de 18h à 20h.
Venez visiter notre [forum](https://discuss.afpy.org/) pour prendre connaissance des dernières discussions et y participer !
N'hésitez pas à également consulter les
[rapports et procès verbaux des assemblées précédentes](https://github.com/AFPy/afpy_gestion/tree/master/assemblees_generales/2020).

92
content/pages/charte.md Normal file
View File

@ -0,0 +1,92 @@
Title: Charte
Slug: charte
Authors: AFPy
Le but de l'Association Francophone Python (AFPy) est d'assurer la promotion du langage
de programmation Python auprès du plus large public possible.
Nous diffusons nos connaissances et sommes ouverts aux apports extérieurs car la
diversité, l'écoute réciproque, la solidarité et la démocratie élargissent les horizons
et accroissent le potentiel de l'AFPy et de chacun de ses membres. En conséquence, nous
encourageons donc la participation aux divers évènements que nous (co-)organisons de
toutes les personnes de la communauté Python ou souhaitant en faire partie. Dans ce
cadre, l'AFPy souhaite que toute personne intéressée soit accueillie de manière agréable
et enrichissante.
L'AFPy s'attend donc à ce que chaque membre de l'association fasse preuve de respect et
de courtoisie envers les autres membres de l'association et les personnes rencontrées
dans le cadre de tout évènement organisé (formellement ou non) par l'association.
Ce texte est notamment inspiré par le code de conduite établi par l'Ada Initiative et
par la loi française de lutte contre les discriminations.
## La version « courte »
L'AFPy souhaite éviter tout type de discrimination, que ce soit sur le sexe,
l'orientation sexuelle, le handicap, l'apparence physique, l'origine ou la religion, et
sous quelque forme que ce soit (parole, image, texte et autre). Bien évidemment, ceci
n'est pas une liste exhaustive.
L'AFPy reconnaît cependant la légitimité de minorités qui voudraient mener des actions
de soutien à destination de leurs propres membres, en vue de favoriser le rééquilibrage
de leur représentation au sein de la communauté entière.
Bien que l'AFPy ait pour but la promotion de Python dans le monde francophone,
l'association s'engage à accueillir chacun, quelle que soit son langage de programmation
ou sa langue maternelle.
L'AFPy attend de ses membres un langage et un style adaptés à une audience variée. Les
allusions sexuelles ou à caractère raciste ne sont en aucun cas tolérées, quel que soit
leur support.
Soyez poli·e. N'insultez personne. Discrimination et harcèlement sont à exclure aussi
bien dans les écrits, les visuels, les paroles et les actes, et ce quelle que soit leur
nature (sexuelle, raciste, religieuse, sociale…).
Le non respect de ces règles de bienséance pourra entraîner l'exclusion de l'évènement,
à la seule discrétion d'un ou plusieurs organisateurs, ou de l'association, après
délibération du comité directeur, ainsi que de tout service proposé par l'AFPy (planète
AFPy, blog, canaux IRC).
## La version « longue »
### Champ d'application
Ces bonnes pratiques s'appliquent dans le cadre de tout évènement (co-)organisé par
l'AFPy de manière directe ou indirecte à savoir :
* les conférences (PyconFR, évènement à la cantine et autre),
* les canaux IRC ou XMPP ou autre messagerie instantanée,
* planète Python,
* le blog,
* la liste de diffusion,
* tout évènement ou vous représentez l'AFPy, y compris les rencontres informelles (notamment AFPyros).
### Définition de la discrimination
La discrimination inclut, selon la loi française, « la situation dans laquelle, sur le fondement de son appartenance ou de sa non-appartenance, vraie ou supposée, à une ethnie ou une race, sa religion, ses convictions, son âge, son handicap, son orientation ou identité sexuelle ou son sexe, une personne est traitée de manière moins favorable qu'une autre ne l'est, ne l'a été ou ne l'aura été dans une situation comparable ».
Sont donc proscrits :
* « tout agissement à connotation sexuelle, [subi] par une personne et ayant pour objet ou pour effet de porter atteinte à sa dignité ou de créer un environnement intimidant, hostile, dégradant, humiliant ou offensant » ;
* « le fait d'enjoindre à quiconque d'adopter un [tel] comportement ».
### Comportements à éviter (proscrire ?)
En référence à la définition qui précède, nous vous invitons à vous abstenir :
* de toute expression ou attitude inappropriées,
* de présenter des images sexuelles ou choquantes (notamment violentes),
* d'intimidation délibérée, de harcèlement, des contacts physiques inconvenants et non consentis.
### Traitement des incidents
En cas de harcèlement ou de discrimination commis par un participant, les organisateurs de l'évènement ou membres du comité directeur pourront prendre immédiatement les mesures qu'ils jugent appropriées et qui peuvent aller jusqu'à l'exclusion temporaire ou définitive d'un évènement.
## Signaler
Si vous êtes harcelé(e) ou victime de discrimination, ou si vous êtes témoin de
harcèlement ou de discrimination à l'égard d'autre(s) participant(e-s), ou si vous
craignez la survenue d'un incident, contactez sans attendre un membre organisateur (dans
le cas d'un évènement) ou un membre du comité directeur de l'AFPy.
Vous pouvez également écrire à l'adresse [diversite@afpy.org](mailto:diversite@afpy.org).

View File

@ -0,0 +1,44 @@
Title: Communauté
Slug: communaute
Authors: AFPy
Summary: Communauté
## Forum de discussion
Afin d'échanger avec la communauté, un forum de discussion est disponible et traite de
tous les sujets autour de Python.
## Salons de discussion
L'AFPy est présente sur IRC et Discord.
## Rencontres
Afin de partager autour du langage Python, de ses pratiques, de sa technique et de son
écosystème, des évènements sont organisés régulièrement dans divers lieux.
* Amiens
* Bordeaux
* Bruxelles
* Grenoble
* Lille
* Lyon
* Nantes
* Montpellier
## PyConFr
La PyConFr est un évènement organisé chaque année depuis 10+ ans par l'AFPy. Cette conférence est gratuite, entièrement organisée par des bénévoles et regroupe développeu·ses·rs, chercheu·ses·rs, étudiant·e·s et amat·rices·eurs autour d'une même passion pour le langage de programmation Python.
PyConFr
## April
Pionnière du logiciel libre en France, l'April est depuis 1996 un acteur majeur de la démocratisation et de la diffusion du logiciel libre et des standards ouverts auprès du grand public, des professionnels et des institutions dans l'espace francophone.
April

21
content/pages/contact.md Normal file
View File

@ -0,0 +1,21 @@
Title: Contact
Slug: contact
Authors: AFPy
## Contactez les membres
Vous pouvez contacter les membres du bureau aux adresses :
* [presidence@afpy.org](mailto:presidence@afpy.org)
* [secretaire@afpy.org](mailto:secretaire@afpy.org)
* [tresorerie@afpy.org](mailto:tresorerie@afpy.org)
## Signalez un comportement inapproprié
Si vous êtes harcelé(e) ou victime de discrimination, ou si vous êtes témoin de
harcèlement ou de discrimination à l'égard d'autre(s) participant(e-s), ou si vous
craignez la survenue d'un incident, contactez sans attendre un membre organisateur (dans
le cas d'un évènement) ou un membre du comité directeur de l'AFPy.
Vous pouvez également écrire à l'adresse [diversite@afpy.org](mailto:diversite@afpy.org).

22
content/pages/legal.md Normal file
View File

@ -0,0 +1,22 @@
Title: Mentions légales
Slug: mentions-legales
Authors: AFPy
## Lassociation
Lassociation « A.F.P.Y. » , Association Francophone Python, fondée le 11 décembre 2004
sous le régime de la loi du 1er juillet 1901 a pour but la vulgarisation auprès dun
public francophone du langage de programmation python et de ses applications.
## Les documents administratifs
L'ensemble des documents administratifs publics sont disponibles sur
[notre dépôt GitHub](https://github.com/AFPy/afpy_gestion), en particulier :
* [les statuts](https://github.com/AFPy/afpy_gestion/blob/master/statuts/2018/statuts.rst),
* [le règlement intérieur](https://github.com/AFPy/afpy_gestion/blob/master/statuts/2018/reglement.rst),
* la comptabilité,
* la facturation,
* les comptes rendus d'assemblées générales ; et
* les comptes rendus du comité directeur.

View File

@ -0,0 +1,39 @@
Title: Adhésion
Slug: adhesions
Authors: AFPy
Summary: Adhésion
## Pourquoi Adhérer ?
### Adhérer pour soutenir les actions de l'AFPy
* Organiser les PyConFr
* Traduire la documentation
* Organiser des MeetUp
* Développer la platerforme HackInScience
* Administrer le forum
* Héberger une liste doffre emploi liés à Python
* Être membre de lApril pour soutenir le logiciel libre
### Ce que permet l'adhésion à l'AFPy
* Participer au vote à lAssemblée Générale
* Pouvoir devenir membre du Comité Directeur
* Utiliser le BigBlueButton de lassociation
* Avoir le badge Adhérent sur Discourse
### Ce qu'on aimerait faire aussi
* Des ateliers python dans les lycées
* Mettre en place une certification Python
* Être présents aux évènements
* Contribuer au Python libre
* Rémunérer des gens faisant vivre lassociation
## Adhérez à l'AFPy
<iframe id="haWidget" src="https://www.helloasso.com/associations/afpy/adhesions/adhesion-2023-a-l-afpy/widget"></iframe>
Si le widget ne fonctionne pas, essayez cette page : https://www.helloasso.com/associations/afpy/adhesions/adhesion-2023-a-l-afpy

21
content/pages/rss.md Normal file
View File

@ -0,0 +1,21 @@
Title: Flux RSS
Slug: flux-rss
Authors: AFPy
## Flux de l'AFPy
Vous pouvez suivre les informations de l'AFPy en vous abonnant aux flux de notre Discourse :
* Tout les posts : [https://discuss.afpy.org/latest.rss](https://discuss.afpy.org/latest.rss)
* [Actualités de l'asso](https://discuss.afpy.org/c/association.rss)
* [Offres d'emploi](https://discuss.afpy.org/c/emplois.rss)
Vous pouvez aussi suivre n'importe quelle autre catégorie en forgeant la bonne URL.
## Flux généralistes
Vous pouvez également vous abonner à ce flux qui agrège les informations venant de
divers sites en français sur Python. Ce flux reprend également les articles de l'AFPy :
* [Planet AFPy](https://planet.afpy.org/atom.xml)

23
content/pages/who.md Normal file
View File

@ -0,0 +1,23 @@
Title: Qui sommes-nous ?
Slug: qui-sommes-nous
Authors: AFPy
## Lassociation
Lassociation « A.F.P.Y. » , Association Francophone Python, fondée le 11 décembre 2004 sous le régime de la loi du 1er juillet 1901 a pour but la vulgarisation auprès dun public francophone du langage de programmation python et de ses applications.
## Bureau et Comité Directeur
Les membres du comité directeur 2023 sont :
* Présidente : Lucie Anglade ([presidence@afpy.org](mailto:presidence@afpy.org))
* Jean Lapostolle (Vice-président)
* Antoine Rozo ([secretaire@afpy.org](mailto:secretaire@afpy.org))
* Nicolas Ledez (Vice-secrétaire)
* Pierre Bousquié ([tresorerie@afpy.org](mailto:tresorerie@afpy.org))
* Thomas Bouchet (Vice-trésorier)
* Marc Debureaux
* Laurine Leulliette
* Bruno Bonfils

View File

@ -0,0 +1,23 @@
Title: Rapport de transparence de la PyConFr 2023
Date: 2023-04-25 21:38:00
Category: news
Slug: rapport-transparence-PyConFr-2023
Author: AFPy
![Logo de la PyConFR 2023 à Bordeaux](https://www.pycon.fr/2023/static/images/banniere.png "Logo de la PyConFR 2023 à Bordeaux")
PyCon France (PyConFR) est une conférence qui a lieu chaque année (sauf circonstances
exceptionnelles) en France. Cette année, elle a eu lieu du
[16 au 19 février à Bordeaux](https://www.pycon.fr/2023/),
rassemblant des personnes de la communauté Python. Les participantes à la conférence
sont tenues de respecter le [Code de Conduite](https://www.afpy.org/docs/charte) de
l'Association Francophone Python, l'association qui organise l'événement.
Le but de ce document est d'améliorer l'accueil et la sécurité des participantes ainsi
que de donner aux organisateurs et organisatrices des indicateurs sur le comportement de
la communauté. En effet, pour pouvoir entendre, il faut pouvoir écouter. C'est
maintenant devenu une pratique courante, pour les organisations ayant un Code de
Conduite, de publier un rapport de transparence suite à la tenue d'une conférence.
C'est le but de ce document.
[Télécharger le rapport en PDF.](https://git.afpy.org/AFPy/gestion/src/commit/67cd4d1d6df54dd3d1ac7ce5ac32df6260b885cb/compte_rendus_diversite/2023.pdf)

View File

@ -0,0 +1,33 @@
Title: Soirée traduction le 27 octobre 2021
Date: 2021-10-22 15:06:10
Category: news
Slug: soiree-traduction-le-27-octobre-2021
Author: AFPy
_TL;DR; Sur BBB le 27 octobre 19h00_
## Atelier Traduction
Qu'est-ce que c'est ?
C'est une soirée, en ligne (cause pandémie), pour s'entre-aider à traduire la documentation de Python en français :
[https://docs.python.org/fr/](https://docs.python.org/fr/)
Une bonne partie est déjà faite, mais une bonne partie reste à faire :
![graphe de la progression de la traduction](https://www.afpy.org/post_image/fr_translation_percent.png "graphe de la progression de la traduction")
### Ça se passe où et quand ?
Sur notre propre BBB :
[https://bbb.afpy.org/b/jul-fss-kpj-txw](https://bbb.afpy.org/b/jul-fss-kpj-txw)
le mercredi 27 octobre 2021 à 19h00 CEST.
### Des questions ou des suggestions
On aimerait reprendre les ateliers en présentiel, si vous voulez proposer un lieu, ou si
vous avez une question venez nous en parler sur [discuss.afpy.org](https://discuss.afpy.org/t/soiree-traduction-du-27-octobre-2021/455).

36
pelicanconf.py Normal file
View File

@ -0,0 +1,36 @@
AUTHOR = 'AFPy'
SITENAME = 'AFPy'
SITEURL = ''
PATH = 'content'
TIMEZONE = 'Europe/Paris'
LOCALE = "fr-FR"
DEFAULT_LANG = 'fr'
# Feed generation is usually not desired when developing
FEED_ALL_ATOM = None
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
# Blogroll
#LINKS = (('Pelican', 'https://getpelican.com/'),
# ('Python.org', 'https://www.python.org/'),
# ('Jinja2', 'https://palletsprojects.com/p/jinja/'),
# ('You can modify those links in your config file', '#'),)
# Social widget
#SOCIAL = (('You can add links in your config file', '#'),
# ('Another social link', '#'),)
DEFAULT_PAGINATION = 10
# Uncomment following line if you want document-relative URLs when developing
#RELATIVE_URLS = True
# Theme to use
THEME = "themes/afpy"
THEME_STATIC_DIR = "static"

21
publishconf.py Normal file
View File

@ -0,0 +1,21 @@
# This file is only used if you use `make publish` or
# explicitly specify it as your config file.
import os
import sys
sys.path.append(os.curdir)
from pelicanconf import *
# If your site is available via HTTPS, make sure SITEURL begins with https://
SITEURL = 'https://afpy.org'
RELATIVE_URLS = False
FEED_ALL_ATOM = 'feeds/all.atom.xml'
CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml'
DELETE_OUTPUT_DIRECTORY = True
# Following items are often useful when publishing
#DISQUS_SITENAME = ""
#GOOGLE_ANALYTICS = ""

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
pelican==4.8.0
feedparser==6.0.10

82
synchronize.py Normal file
View File

@ -0,0 +1,82 @@
# encoding: utf-8
from datetime import datetime
import os
from time import mktime
import feedparser
JOB_URL = "https://discuss.afpy.org/c/emplois/14.rss"
NEWS_URL = "https://discuss.afpy.org/c/association/actualites/16.rss"
def synchronize_jobs():
"""
Get jobs data from AFPy website and parse it to update jobs.
"""
os.makedirs("content/jobs", exist_ok=True)
data = feedparser.parse(JOB_URL)
for entry in data.entries:
# Retrieve informations
job_id = entry.id.split("-")[-1]
job_title = entry.title
job_author = entry.author
job_link = entry.link
job_date = datetime.fromtimestamp(mktime(entry.published_parsed))
job_body = ""
for line in entry.description.splitlines()[:-2]:
job_body += line.strip() + "\n"
job_body += "\n"
job_body += f"[Voir l'article original]({job_link})\n"
# Generating filename to save/replace job offer
filename = f"content/jobs/offre_{job_id}.md"
# Writing file
with open(filename, "w") as file_handle:
file_handle.write(f"Title: {job_title}\n")
file_handle.write(f"Date: {job_date}\n")
file_handle.write(f"Category: jobs\n")
file_handle.write(f"Slug: offre-{job_id}\n")
file_handle.write(f"Author: {job_author}\n")
file_handle.write(f"\n")
file_handle.write(f"\n")
file_handle.write(f"{job_body}")
def synchronize_news():
"""
Get news data from AFPy website and parse it to update jobs.
"""
os.makedirs("content/news", exist_ok=True)
data = feedparser.parse(NEWS_URL)
for entry in data.entries:
# Retrieve informations
news_id = entry.id.split("-")[-1]
news_title = entry.title
news_author = entry.author
news_link = entry.link
news_date = datetime.fromtimestamp(mktime(entry.published_parsed))
news_body = ""
for line in entry.description.splitlines()[:-2]:
news_body += line.strip() + "\n"
news_body += "\n"
news_body += f"[Voir l'article original]({news_link})\n"
# Generating filename to save/replace job offer
filename = f"content/news/actu_{news_id}.md"
# Writing file
with open(filename, "w") as file_handle:
file_handle.write(f"Title: {news_title}\n")
file_handle.write(f"Date: {news_date}\n")
file_handle.write(f"Category: news\n")
file_handle.write(f"Slug: actu-{news_id}\n")
file_handle.write(f"Author: {news_author}\n")
file_handle.write(f"\n")
file_handle.write(f"\n")
file_handle.write(f"{news_body}")
if __name__ == "__main__":
synchronize_jobs()
synchronize_news()

138
tasks.py Normal file
View File

@ -0,0 +1,138 @@
# -*- coding: utf-8 -*-
import os
import shlex
import shutil
import sys
import datetime
from invoke import task
from invoke.main import program
from invoke.util import cd
from pelican import main as pelican_main
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
from pelican.settings import DEFAULT_CONFIG, get_settings_from_file
OPEN_BROWSER_ON_SERVE = True
SETTINGS_FILE_BASE = 'pelicanconf.py'
SETTINGS = {}
SETTINGS.update(DEFAULT_CONFIG)
LOCAL_SETTINGS = get_settings_from_file(SETTINGS_FILE_BASE)
SETTINGS.update(LOCAL_SETTINGS)
CONFIG = {
'settings_base': SETTINGS_FILE_BASE,
'settings_publish': 'publishconf.py',
# Output path. Can be absolute or relative to tasks.py. Default: 'output'
'deploy_path': SETTINGS['OUTPUT_PATH'],
# Host and port for `serve`
'host': 'localhost',
'port': 8000,
}
@task
def clean(c):
"""Remove generated files"""
if os.path.isdir(CONFIG['deploy_path']):
shutil.rmtree(CONFIG['deploy_path'])
os.makedirs(CONFIG['deploy_path'])
@task
def build(c):
"""Build local version of site"""
pelican_run('-s {settings_base}'.format(**CONFIG))
@task
def rebuild(c):
"""`build` with the delete switch"""
pelican_run('-d -s {settings_base}'.format(**CONFIG))
@task
def regenerate(c):
"""Automatically regenerate site upon file modification"""
pelican_run('-r -s {settings_base}'.format(**CONFIG))
@task
def serve(c):
"""Serve site at http://$HOST:$PORT/ (default is localhost:8000)"""
class AddressReuseTCPServer(RootedHTTPServer):
allow_reuse_address = True
server = AddressReuseTCPServer(
CONFIG['deploy_path'],
(CONFIG['host'], CONFIG['port']),
ComplexHTTPRequestHandler)
if OPEN_BROWSER_ON_SERVE:
# Open site in default browser
import webbrowser
webbrowser.open("http://{host}:{port}".format(**CONFIG))
sys.stderr.write('Serving at {host}:{port} ...\n'.format(**CONFIG))
server.serve_forever()
@task
def reserve(c):
"""`build`, then `serve`"""
build(c)
serve(c)
@task
def preview(c):
"""Build production version of site"""
pelican_run('-s {settings_publish}'.format(**CONFIG))
@task
def livereload(c):
"""Automatically reload browser tab upon file modification."""
from livereload import Server
def cached_build():
cmd = '-s {settings_base} -e CACHE_CONTENT=true LOAD_CONTENT_CACHE=true'
pelican_run(cmd.format(**CONFIG))
cached_build()
server = Server()
theme_path = SETTINGS['THEME']
watched_globs = [
CONFIG['settings_base'],
'{}/templates/**/*.html'.format(theme_path),
]
content_file_extensions = ['.md', '.rst']
for extension in content_file_extensions:
content_glob = '{0}/**/*{1}'.format(SETTINGS['PATH'], extension)
watched_globs.append(content_glob)
static_file_extensions = ['.css', '.js']
for extension in static_file_extensions:
static_file_glob = '{0}/static/**/*{1}'.format(theme_path, extension)
watched_globs.append(static_file_glob)
for glob in watched_globs:
server.watch(glob, cached_build)
if OPEN_BROWSER_ON_SERVE:
# Open site in default browser
import webbrowser
webbrowser.open("http://{host}:{port}".format(**CONFIG))
server.serve(host=CONFIG['host'], port=CONFIG['port'], root=CONFIG['deploy_path'])
@task
def publish(c):
"""Publish to production via rsync"""
pelican_run('-s {settings_publish}'.format(**CONFIG))
c.run(
'rsync --delete --exclude ".DS_Store" -pthrvz -c '
'-e "ssh -p {ssh_port}" '
'{} {ssh_user}@{ssh_host}:{ssh_path}'.format(
CONFIG['deploy_path'].rstrip('/') + '/',
**CONFIG))
def pelican_run(cmd):
cmd += ' ' + program.core.remainder # allows to pass-through args to pelican
pelican_main(shlex.split(cmd))

6
themes/afpy/static/css/all.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,235 @@
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item}
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
a{background-color:transparent}a:active,a:hover{outline-width:0}
abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000}
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none}
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}
button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold}
button,input{overflow:visible}button,select{text-transform:none}
button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}
button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}
button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
[type=checkbox],[type=radio]{padding:0}
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
[type=search]::-webkit-search-decoration{-webkit-appearance:none}
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
/* End extract */
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}
.w3-serif{font-family:serif}.w3-sans-serif{font-family:sans-serif}.w3-cursive{font-family:cursive}.w3-monospace{font-family:monospace}
h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
hr{border:0;border-top:1px solid #eee;margin:20px 0}
.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit}
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
.w3-dropdown-hover:hover .w3-dropdown-content{display:block}
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1}
.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
.w3-main,#main{transition:margin-left .4s}
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0}
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
.w3-bar .w3-button{white-space:normal}
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0}
.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
.w3-responsive{display:block;overflow-x:auto}
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
.s1{width:8.33333%}.s2{width:16.66666%}.s3{width:24.99999%}.s4{width:33.33333%}
.s5{width:41.66666%}.s6{width:49.99999%}.s7{width:58.33333%}.s8{width:66.66666%}
.s9{width:74.99999%}.s10{width:83.33333%}.s11{width:91.66666%}.s12{width:99.99999%}
@media (min-width:601px){.m1{width:8.33333%}.m2{width:16.66666%}.m3,.w3-quarter{width:24.99999%}.m4,.w3-third{width:33.33333%}
.m5{width:41.66666%}.m6,.w3-half{width:49.99999%}.m7{width:58.33333%}.m8,.w3-twothird{width:66.66666%}
.m9,.w3-threequarter{width:74.99999%}.m10{width:83.33333%}.m11{width:91.66666%}.m12{width:99.99999%}}
@media (min-width:993px){.l1{width:8.33333%}.l2{width:16.66666%}.l3{width:24.99999%}.l4{width:33.33333%}
.l5{width:41.66666%}.l6{width:49.99999%}.l7{width:58.33333%}.l8{width:66.66666%}
.l9{width:74.99999%}.l10{width:83.33333%}.l11{width:91.66666%}.l12{width:99.99999%}}
.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px}
.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px}
.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
@media (max-width:1205px){.w3-auto{max-width:95%}}
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}}
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
.w3-display-position{position:absolute}
.w3-circle{border-radius:50%}
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
.w3-padding-top-64{padding-top:64px!important}.w3-padding-top-48{padding-top:48px!important}
.w3-padding-top-32{padding-top:32px!important}.w3-padding-top-24{padding-top:24px!important}
.w3-left{float:left!important}.w3-right{float:right!important}
.w3-button:hover{color:#000!important;background-color:#ccc!important}
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
.w3-hover-none:hover{box-shadow:none!important}
/* Colors */
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}

View File

@ -0,0 +1,10 @@
@import "w3.css";
@import "all.min.css";
@font-face{font-family:atkinson;src:url(../webfonts/Atkinson-Hyperlegible-Regular-102.ttf)}
body, h1, h2, h3, h4, h5, h6{font-family:atkinson}
img{width:100%}
.logo{width:3em}
iframe{background:#eaeaea;border:0;height:55em;width:100%}
.w3-margin-bottom-32{margin-bottom:32px!important}
.uppercase{text-transform:uppercase}

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<g id="g2894" transform="matrix(0.6745946,0,0,0.6745946,-109.00393,-38.014)">
<path id="path2896" fill="#FFFFFF" d="
M232.658,307.102c-56.779-42.106-68.673-122.269-26.566-179.048c42.109-56.777,122.27-68.671,179.049-26.564
c56.779,42.106,68.673,122.269,26.568,179.048c-42.106,56.775-122.259,68.673-179.038,26.578"/>
<path id="path2898" fill="#FF6F32" d="M309.282,203.137l-87.73,111.1
c48.834,38.695,114.96,41.116,166.467,6.057L309.282,203.137L309.282,203.137z"/>
<path id="path2900" fill="#84326B" d="M309.282,203.137
l76.913,118.409c52.698-34.653,75.588-97.834,57.316-158.199L309.282,203.137z"/>
<path id="path2902" fill="#32ADA9" d="M309.282,203.137
l134.999-37.289c-17.225-61.021-71.138-102.043-134.542-102.42L309.282,203.137L309.282,203.137z"/>
<path id="path2904" fill="#EBFF32" d="M309.282,203.137L313.2,63.523
c-63.294-1.913-118.602,36.98-138.097,97.228L309.282,203.137z"/>
<path id="path2906" fill="#327BD6" d="M309.282,203.137
l-133.506-44.214c-19.853,58.614-0.277,121.24,49.431,158.102L309.282,203.137L309.282,203.137z"/>
<path id="path2908" fill="#FFFFFF" d="M296.151,83.274c-20.598,0.107-49.162,5.941-52.404,30.453
c-1.665,8.082,0.413,18.038-1.215,25.028c-24.511-2.627-51.848,12.411-55.157,38.309c-6.81,29.067-5.168,66.718,20.653,85.775
c10.108,6.897,25.056,4.019,34.422,6.315c-2.613,20.801,6.443,44.468,28.673,49.733c31.432,11.943,72.42,10.254,96.95-14.825
c8.516-9.855,5.253-26.06,7.616-35.719c19.698,2.507,44.072-3.946,49.891-25.187c13.572-30.675,11.665-71.89-12.231-96.869
c-10.615-9.098-27.766-5.859-38.391-8.099c2.791-20.97-6.322-45.369-28.594-50.946C330.359,82.006,312.806,82.582,296.151,83.274z"
/>
<g id="g2910" transform="matrix(0.7960788,0,0,0.7636835,323.11888,330.11106)">
<linearGradient id="path2912_1_" gradientUnits="userSpaceOnUse" x1="697.1569" y1="-1591.3921" x2="979.7098" y2="-1834.491" gradientTransform="matrix(0.3021 0 0 -0.2926 -379.5969 -767.7481)">
<stop offset="0" style="stop-color:#5A9FD4"/>
<stop offset="1" style="stop-color:#306998"/>
</linearGradient>
<path id="path2912" fill="url(#path2912_1_)" d="M-19.578-310.392
c-11.879,0.057-23.223,1.069-33.206,2.835c-29.408,5.196-34.748,16.071-34.748,36.126v26.483h69.492v8.829h-69.492h-26.08
c-20.198,0-37.881,12.14-43.412,35.234c-6.382,26.469-6.665,42.987,0,70.627c4.939,20.577,16.736,35.231,36.932,35.231h23.893
v-31.747c0-22.939,19.847-43.171,43.415-43.171h69.41c19.323,0,34.749-15.911,34.749-35.315v-66.171
c0-18.835-15.888-32.981-34.749-36.126C4.692-309.544-7.693-310.446-19.578-310.392z M-57.158-289.088
c7.178,0,13.039,5.957,13.039,13.282c0,7.301-5.861,13.201-13.039,13.201c-7.204,0-13.041-5.9-13.041-13.201
C-70.199-283.132-64.362-289.088-57.158-289.088z"/>
<linearGradient id="path2914_1_" gradientUnits="userSpaceOnUse" x1="1426.6962" y1="-2348.8525" x2="1325.799" y2="-2206.1003" gradientTransform="matrix(0.3021 0 0 -0.2926 -379.5969 -767.7481)">
<stop offset="0" style="stop-color:#FFD43B"/>
<stop offset="1" style="stop-color:#FFE873"/>
</linearGradient>
<path id="path2914" fill="url(#path2914_1_)" d="M60.044-236.119v30.859
c0,23.924-20.287,44.06-43.417,44.06h-69.41c-19.013,0-34.748,16.277-34.748,35.315v66.173c0,18.833,16.376,29.91,34.748,35.311
c21.996,6.47,43.092,7.639,69.41,0c17.495-5.061,34.749-15.259,34.749-35.311v-26.485h-69.415v-8.83h69.415H86.12
c20.196,0,27.722-14.084,34.751-35.231c7.254-21.769,6.946-42.704,0-70.627c-4.997-20.106-14.526-35.234-34.751-35.234H60.044z
M21-68.54c7.206,0,13.04,5.905,13.04,13.201c0,7.326-5.834,13.28-13.04,13.28c-7.174,0-13.036-5.954-13.036-13.28
C7.963-62.635,13.826-68.54,21-68.54z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block title %}{{ SITENAME }} - Archives{% endblock %}
{% block content %}
<h1>Archives for {{ SITENAME }}</h1>
<dl>
{% for article in dates %}
<dt>{{ article.locale_date }}</dt>
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
{% endfor %}
</dl>
{% endblock %}

View File

@ -0,0 +1,65 @@
{% extends "base.html" %}
{% block html_lang %}{{ article.lang }}{% endblock %}
{% block title %}{{ SITENAME }} - {{ article.title|striptags }}{% endblock %}
{% block head %}
{{ super() }}
{% import 'translations.html' as translations with context %}
{% if translations.entry_hreflang(article) %}
{{ translations.entry_hreflang(article) }}
{% endif %}
{% if article.description %}
<meta name="description" content="{{article.description}}" />
{% endif %}
{% for tag in article.tags %}
<meta name="tags" content="{{tag}}" />
{% endfor %}
{% endblock %}
{% block content %}
<header>
<h1 class="entry-title">
<a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark"
title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h1>
{% import 'translations.html' as translations with context %}
{{ translations.translations_for(article) }}
</header>
<footer class="post-info">
<time class="published" datetime="{{ article.date.isoformat() }}">
{{ article.locale_date }}
</time>
{% if article.modified %}
<time class="modified" datetime="{{ article.modified.isoformat() }}">
{{ article.locale_modified }}
</time>
{% endif %}
{% if article.authors %}
<address class="vcard author">
Par {% for author in article.authors %}
<a class="url fn" href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a>
{% endfor %}
</address>
{% endif %}
{% if article.category %}
<div class="category">
Categorie : <a href="{{ SITEURL }}/{{ article.category.url }}">{{ article.category }}</a>
</div>
{% endif %}
{% if article.tags %}
<div class="tags">
Tags :
{% for tag in article.tags %}
<a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }}</a>
{% endfor %}
</div>
{% endif %}
</footer><!-- /.post-info -->
<article>
{{ article.content }}
</article>
{% endblock %}

View File

@ -0,0 +1,8 @@
{% extends "index.html" %}
{% block title %}{{ SITENAME }} - Articles by {{ author }}{% endblock %}
{% block content_title %}
<h1>Articles by {{ author }}</h1>
{% endblock %}

View File

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block title %}{{ SITENAME }} - Authors{% endblock %}
{% block content %}
<h1>Authors on {{ SITENAME }}</h1>
<ul>
{% for author, articles in authors|sort %}
<li><a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a> ({{ articles|count }})</li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="{% block html_lang %}{{ DEFAULT_LANG }}{% endblock html_lang %}">
<head>
{% block head %}
<title>{% block title %}{{ SITENAME }}{% endblock title %}</title>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="AFPy" />
<meta name="Description" content="" />
<meta name="Keywords" content="" />
<link rel="icon" type="image/x-icon" href="/static/img/favicon.ico">
<link rel="stylesheet" href="/static/css/website.css">
{% endblock head %}
</head>
<body>
<header>
<!-- Navigation bar -->
<div class="w3-bar w3-card w3-border-bottom w3-large">
<a href="/" class="w3-bar-item w3-button w3-hover-orange"><img src="/static/img/logo.svg" class="w3-margin-right logo" alt="Association Francophone Python" /> <span class="w3-margin-left">AFPY</span></a>
<div class="w3-hide-medium w3-hide-small">
<a href="/pages/adhesion" class="w3-bar-item w3-button w3-right w3-hover-orange w3-margin-top">Adhésion</a>
<a href="/pages/communaute" class="w3-bar-item w3-button w3-right w3-hover-orange w3-margin-top">Communauté</a>
<a href="/category/jobs" class="w3-bar-item w3-button w3-right w3-hover-orange w3-margin-top">Offres d'emploi</a>
<a href="/category/news" class="w3-bar-item w3-button w3-right w3-hover-orange w3-margin-top">Actualités</a>
<a href="/pages/qui-sommes-nous" class="w3-bar-item w3-button w3-right w3-hover-orange w3-margin-top">Qui sommes-nous ?</a>
<a href="/" class="w3-bar-item w3-button w3-right w3-hover-orange w3-margin-top">Accueil</a>
</div>
<!-- Toggle menu on small screens -->
<a class="w3-bar-item w3-button w3-right w3-hide-large w3-padding-large w3-hover-orange w3-large" href="javascript:void(0);" onclick="myFunction()" title="Toggle Navigation Menu"><i class="fa fa-bars"></i></a>
</div>
<!-- Navigation bar on small screens -->
<div id="navSmall" class="w3-bar-block w3-white w3-card w3-hide w3-large">
<a href="/" class="w3-bar-item w3-button w3-padding-large w3-hover-orange">Accueil</a>
<a href="/pages/qui-sommes-nous" class="w3-bar-item w3-button w3-padding-large w3-hover-orange">Qui sommes-nous ?</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large w3-hover-orange">Actualités</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large w3-hover-orange">Offres d'emploi</a>
<a href="/pages/communaute" class="w3-bar-item w3-button w3-padding-large w3-hover-orange">Communauté</a>
<a href="/pages/adhesion" class="w3-bar-item w3-button w3-padding-large w3-hover-orange">Adhésion</a>
</div>
</header>
<main class="w3-content w3-padding">
{% block content %}
{% endblock %}
</main>
<!-- Footer -->
<footer class="w3-container w3-orange w3-card-4 w3-center w3-padding">
<a href="/pages/contact" class="w3-button w3-hover-grey uppercase">Contact</a>
<a href="/pages/charte" class="w3-button w3-hover-grey uppercase">Charte</a>
<a href="/pages/mentions-legales" class="w3-button w3-hover-grey uppercase">Mentions légales</a>
<a href="/pages/flux-rss" class="w3-button w3-hover-grey uppercase">Flux RSS</a>
<a href="https://mamot.fr/@AFPy" class="w3-button w3-hover-grey uppercase">Mastodon</a>
<a href="https://twitter.com/asso_python_fr" class="w3-button w3-hover-grey uppercase">Twitter</a>
</footer>
<script>
// Used to toggle the menu on small screens
function myFunction() {
var x = document.getElementById("navSmall");
if (x.className.indexOf("w3-hide") == -1) {
x.className += " w3-hide";
} else {
x.className = x.className.replace(" w3-hide", "");
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block title %}{{ SITENAME }} - Categories{% endblock %}
{% block content %}
<h1>Categories on {{ SITENAME }}</h1>
<ul>
{% for category, articles in categories|sort %}
<li><a href="{{ SITEURL }}/{{ category.url }}">{{ category }}</a> ({{ articles|count }})</li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends "index.html" %}
{% block title %}{{ SITENAME }} - {{ category }}{% endblock %}
{% block content %}
<section class="w3-content w3-padding w3-center">
<h1>{{ "Actualités" if category=="news" else "Offres d'emploi" }}</h1>
<div class="w3-row-padding">
{% for article in articles_page.object_list if article.category == category %}
<article class="w3-left-align w3-card w3-margin w3-margin-bottom-32">
<header class="w3-container w3-orange">
<time class="w3-right w3-margin-top" datetime="{{ article.date.isoformat() }}"> {{ article.locale_date }} </time>
<h2 class=""><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h2>
</header>
<div class="w3-container">
<p>{{ article.summary }}</p>
</div>
<footer class="w3-container">
<div class="w3-right">
<address class="w3-margin-bottom">Par
{% for author in article.authors %}{{ author }}{% endfor %}
</address>
</div>
</footer>
</article>
{% endfor %}
{% if articles_page.has_other_pages() %}
{% include 'pagination.html' %}
{% endif %}
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% if GOSQUARED_SITENAME %}
<script type="text/javascript">
var GoSquared={};
GoSquared.acct = "{{ GOSQUARED_SITENAME }}";
(function(w){
function gs(){
w._gstc_lt=+(new Date); var d=document;
var g = d.createElement("script"); g.type = "text/javascript"; g.async = true; g.src = "https://d1l6p2sc9645hc.cloudfront.net/tracker.js";
var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(g, s);
}
w.addEventListener?w.addEventListener("load",gs,false):w.attachEvent("onload",gs);
})(window);
</script>
{% endif %}

View File

@ -0,0 +1,77 @@
{% extends "base.html" %}
{% block content %}
<section class="w3-content w3-padding w3-center w3-hide-small">
<h1>l'AFPy c'est</h1>
<div class="w3-row-padding">
<div class="w3-half">
<div class="w3-container w3-margin w3-card">
<h2>Une communauté</h2>
<div class="w3-left-align">
<p>Un forum dynamique (Discourse)</p>
<p>Des salons de discussion en temps réel (IRC & Discord)</p>
<p>&nbsp;</p>
</div>
</div>
</div>
<div class="w3-half">
<div class="w3-container w3-margin w3-card">
<h2>Des événements</h2>
<div class="w3-left-align">
<p>L'organisation annuelle de la <a href="https://pycon.fr/">PyConFr</a></p>
<p>Les <a href="https://discuss.afpy.org/c/meetups/12">Meetups</a></p>
<p>Les ateliers de traduction</p>
</div>
</div>
</div>
</div>
<div class="w3-row-padding w3-center">
<div class="w3-half">
<div class="w3-container w3-margin w3-card">
<h2>Des outils</h2>
<div class="w3-left-align">
<p>Une plateforme de Visio-conférence (Big Blue Button)</p>
<p>Un gestionnaire de dépôts (Gitea)</p>
<p>Un site d'apprentissage par exercices : <a href="https://hackinscience.org/">Hackinscience</a> (Licence CC0)</p>
</div>
</div>
</div>
<div class="w3-half">
<div class="w3-container w3-margin w3-card">
<h2>Du contenu</h2>
<div class="w3-left-align">
<p>Des offres d'emploi</p>
<p>La traduction de <a href="https://docs.python.org/fr">la documentation de Python</a> (Licence MIT)</p>
<p>&nbsp;</p>
</div>
</div>
</div>
</div>
<p>Il est possible de soutenir les projets de l'AFPy <a href="/pages/adhesions">en cotisant ou en effectuant un don.</a></p>
</section>
<section class="w3-content w3-padding w3-center">
<h1>Dernières actualités</h1>
<div class="w3-row-padding">
{% for article in articles if article.category == "news" %}
{% if loop.index < 4 %}
<article class="w3-left-align w3-card w3-margin w3-margin-bottom-32">
<header class="w3-container w3-orange">
<time class="w3-right w3-margin-top" datetime="{{ article.date.isoformat() }}"> {{ article.locale_date }} </time>
<h2 class=""><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h2>
</header>
<div class="w3-container">
<p>{{ article.summary }}</p>
</div>
<footer class="w3-container">
<div class="w3-right">
<address class="w3-margin-bottom">Par
{% for author in article.authors %}{{ author }}{% endfor %}
</address>
</div>
</footer>
</article>
{% endif %}
{% endfor %}
</div>
</section>
{% endblock content %}

View File

@ -0,0 +1,27 @@
{% extends "base.html" %}
{% block html_lang %}{{ page.lang }}{% endblock %}
{% block title %}{{ page.title|striptags }} - {{ SITENAME }}{%endblock%}
{% block head %}
{{ super() }}
{% import 'translations.html' as translations with context %}
{% if translations.entry_hreflang(page) %}
{{ translations.entry_hreflang(page) }}
{% endif %}
{% endblock %}
{% block content %}
<h1>{{ page.title }}</h1>
{% import 'translations.html' as translations with context %}
{{ translations.translations_for(page) }}
{{ page.content }}
{% if page.modified %}
<p>
Last updated: {{ page.locale_modified }}
</p>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,19 @@
{% if DEFAULT_PAGINATION %}
{% set first_page = articles_paginator.page(1) %}
{% set last_page = articles_paginator.page(articles_paginator.num_pages) %}
<p class="w3-bar">
{% if articles_page.has_previous() %}
<a href="{{ SITEURL }}/{{ articles_previous_page.url }}" class="w3-button w3-hover-orange">&laquo;</a>
{% else %}
<span class="w3-padding">&laquo;</span>
{% endif %}
{% for page in range(1, articles_paginator.num_pages + 1) %}
<a href="{{ SITEURL }}/{{ articles_paginator.page(page).url }}" class="w3-button w3-hover-orange">{{ page }}</a>
{% endfor %}
{% if articles_page.has_next() %}
<a href="{{ SITEURL }}/{{ articles_next_page.url }}" class="w3-button w3-hover-orange">&raquo;</a>
{% else %}
<span class="w3-padding">&raquo;</span>
{% endif %}
</p>
{% endif %}

View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block title %}{{ SITENAME }} - {{ period | reverse | join(' ') }} archives{% endblock %}
{% block content %}
<h1>Archives for {{ period | reverse | join(' ') }}</h1>
<dl>
{% for article in dates %}
<dt>{{ article.locale_date }}</dt>
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
{% endfor %}
</dl>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends "index.html" %}
{% block title %}{{ SITENAME }} - {{ tag }} tag{% endblock %}
{% block content_title %}
<h1>Articles tagged with {{ tag }}</h1>
{% endblock %}

View File

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block title %}{{ SITENAME }} - Tags{% endblock %}
{% block content %}
<h1>Tags for {{ SITENAME }}</h1>
<ul>
{% for tag, articles in tags|sort %}
<li><a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }}</a> ({{ articles|count }})</li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% macro translations_for(article) %}
{% if article.translations %}
Translations:
{% for translation in article.translations %}
<a href="{{ SITEURL }}/{{ translation.url }}" hreflang="{{ translation.lang }}">{{ translation.lang }}</a>
{% endfor %}
{% endif %}
{% endmacro %}
{% macro entry_hreflang(entry) %}
{% if entry.translations %}
{% for translation in entry.translations %}
<link rel="alternate" hreflang="{{ translation.lang }}" href="{{ SITEURL }}/{{ translation.url }}">
{% endfor %}
{% endif %}
{% endmacro %}