init
3
.gitignore
vendored
@ -4,6 +4,9 @@ __pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
output/
|
||||
Output/
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
|
19
content/firstbatch.md
Normal file
@ -0,0 +1,19 @@
|
||||
Title: First batch
|
||||
Date: 2019-05-14
|
||||
Category: News
|
||||
Summary: On the 5th of April 2019 we brewed the first Multilaterale [brew]({filename}redale.md) at the [Noord-Hollandse Bierbrouwerij](http://www.dnhbb.nl/dnhbb/).
|
||||
|
||||
On the 5th of April 2019 we brewed the first Multilaterale [brew]({filename}redale.md) at the [Noord-Hollandse Bierbrouwerij](http://www.dnhbb.nl/dnhbb/).
|
||||
|
||||
![]({attach}images/bottling.jpeg)
|
||||
|
||||
We bottled 3528 bottles on the 14th of May.
|
||||
|
||||
![]({attach}images/delivery.jpeg)
|
||||
|
||||
We received this on the 29th of May.
|
||||
|
||||
The first batch also featured a special design for Goethe Institut Niederlande.
|
||||
|
||||
![]({attach}images/redale.jpg)
|
||||
![]({attach}images/goethe.jpeg)
|
16
content/goethecollab.md
Normal file
@ -0,0 +1,16 @@
|
||||
Title: Ongoing specials for Goethe-Institut NL
|
||||
Date: 2020-02-11
|
||||
Category: News
|
||||
Summary: This is already our second special edition made for the Goethe-Institut Netherlands.
|
||||
|
||||
For every batch that we brew we ask our stakeholders if they are interested to have their own label for the upcoming batch. This is already the second time we worked together with Goethe-Institut Netherlands to design and produce their own label!.
|
||||
|
||||
## GI Pale Ale
|
||||
![]({attach}/images/goethe_paleale.jpeg)
|
||||
|
||||
## GI Red Ale
|
||||
![]({attach}/images/goethe.jpeg)
|
||||
|
||||
## Interested?
|
||||
|
||||
If you are intersted in doing the same, get in touch!
|
17
content/goldendawn.md
Normal file
@ -0,0 +1,17 @@
|
||||
Title: Golden Dawn
|
||||
Date: 2020-11-03
|
||||
Category: Brews
|
||||
Image: images/web96_igfm_1.jpg
|
||||
Summary: Golden Dawn for Murder Capital
|
||||
|
||||
A Golden Ale made for [Intergalactic.fm](https://intergalactic.fm). Fresh with a moderate bitterness. Hopped with Magnum and Ariana.
|
||||
|
||||
![]({static}images/web96_igfm_1.jpg)
|
||||
|
||||
###Data
|
||||
|
||||
* IBU: 21
|
||||
* EBC: 9
|
||||
* ABV: 4.1%
|
||||
* TOP fermentation
|
||||
|
18
content/grooscollab.md
Normal file
@ -0,0 +1,18 @@
|
||||
Title: Irish Stout
|
||||
Date: 2020-07-29
|
||||
Category: Brews
|
||||
Summary: Irish Stout in collaboration with Brouwerij Groos
|
||||
Image: images/Stout.jpg
|
||||
|
||||
This Irish Stout came to be in collaboration with [Brouwerij Groos](https://untappd.com/BrouwerijGroos). It has a souple body, roasty notes of coffee and chocolate. Already sold out and here mostly for archival purposes.
|
||||
|
||||
![]({static}images/Stout.jpg)
|
||||
|
||||
|
||||
###Data
|
||||
|
||||
* IBU: 24
|
||||
* EBC: 75
|
||||
* ABV: 4.5%
|
||||
* TOP fermentation
|
||||
|
BIN
content/images/MC.Beer.jpg
Normal file
After Width: | Height: | Size: 479 KiB |
BIN
content/images/MC.kit.jpg
Normal file
After Width: | Height: | Size: 492 KiB |
BIN
content/images/Multilaterale_Pale_3.jpg
Normal file
After Width: | Height: | Size: 146 KiB |
BIN
content/images/Stout.jpg
Normal file
After Width: | Height: | Size: 133 KiB |
BIN
content/images/bottling.jpeg
Normal file
After Width: | Height: | Size: 130 KiB |
BIN
content/images/cheerswference.jpg
Normal file
After Width: | Height: | Size: 302 KiB |
BIN
content/images/delivery.jpeg
Normal file
After Width: | Height: | Size: 144 KiB |
BIN
content/images/goethe.jpeg
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
content/images/goethe_paleale.jpeg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
content/images/paleale.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
content/images/redale.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
content/images/skiddaw.jpg
Normal file
After Width: | Height: | Size: 164 KiB |
BIN
content/images/web96_igfm_1.jpg
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
content/images/web96_session_pale.jpg
Normal file
After Width: | Height: | Size: 80 KiB |
19
content/pages/about.md
Normal file
@ -0,0 +1,19 @@
|
||||
Title: About
|
||||
Date: 2019-01-01
|
||||
|
||||
### About
|
||||
|
||||
Multilaterale is a brewing initiative by and for the independent art spaces in Rotterdam.The idea is that the Multilaterale Group can brew high quality beers of styles otherwise not commonly found, while the spaces in the Multilaterale network can use the sales to finance their activities. With this model we hope to sustain both independent spaces and community brewing initiatives.
|
||||
|
||||
### Support
|
||||
|
||||
Rather than purchasing the brews after production, the spaces in the network order in advance. This minimizes financial risks for the brewers, which allows for more creativity on the one hand and guarantees good wholesale prices for the network on the other hand. This way Multilaterale is also an invitation to the network to participate in and think about the brewing processes, logistics, design and mutual support.
|
||||
|
||||
### Who?
|
||||
|
||||
Multilaterale is an initiative by Henning Rosenbrock and Roel Roscam Abbing who are also founding members of the [Brouwvereniging Rotterdam](https://brouwvereniging.nl), the home brewing association of Rotterdam.
|
||||
|
||||
|
||||
### Contact
|
||||
|
||||
You can reach us via cheers[at]multilaterale.group!
|
62
content/pages/network.md
Normal file
@ -0,0 +1,62 @@
|
||||
Title: Network
|
||||
Date: 2019-01-01
|
||||
|
||||
Currently the Multilaterale network is composed of the following spaces. These are also the locations where you can purchase Multilaterale. You can also contact us to purchase directly.
|
||||
|
||||
###Multilaterale Group
|
||||
https://multilaterale.group
|
||||
|
||||
Get in touch if you have a party, an opening, a presentation or in need of a gift. Drop us a mail at cheers[at]multilaterale.group
|
||||
|
||||
### varia
|
||||
Gouwstraat 3 Rotterdam | <https://varia.zone>
|
||||
|
||||
varia is a space for developing collective approaches to everyday technology.
|
||||
|
||||
Multilaterale beers are available during the events.
|
||||
|
||||
### DE PLAYER
|
||||
Hillelaan 49d Rotterdam | <https://www.deplayer.nl/>
|
||||
|
||||
|
||||
DE PLAYER is a polymorhpic production platform in Rotterdam (nl), which has been putting together programs on the cutting edge of performance art, experimental music and the visual arts.
|
||||
|
||||
Multilaterale was available during Gardena, we don't know wheter they still have stock.
|
||||
|
||||
### Stichting AppendiX Grafiek
|
||||
<http://www.appendix-grafiek.nl>
|
||||
|
||||
AppendiX is a Rotterdam based platform for contemporary print, graphics and fine arts.
|
||||
|
||||
Multilaterale beers are available during the events.
|
||||
|
||||
|
||||
|
||||
### Goethe Institut Niederlande
|
||||
Westersingel 9 Rotterdam en Herengracht 470 Amsterdam | <https://www.goethe.de/nederland>
|
||||
|
||||
Multilaterale beers were available during the events, but we don't know whether they still have stock.
|
||||
|
||||
### ook_huis
|
||||
Brielselaan 198 Rotterdam | <http://ook.website/>
|
||||
|
||||
ook_huis can also be used freely by neighbors and acquaintances.
|
||||
By programming various activities, ook_ wants to show a communal presence: just meeting eachother.
|
||||
It is a home for also_artistic activity, in whatever way.
|
||||
|
||||
Sometimes there is also Multilaterale.
|
||||
|
||||
###Shimmer
|
||||
Waalhaven Oostzijde 1 Rotterdam | <http://shimmershimmer.org>
|
||||
|
||||
Shimmer is a Rotterdam based exhibition space that operates with an ever-changing studio-like mentality where knowledge arises through participation and experimentation.
|
||||
|
||||
Multilaterale beers are available during openings.
|
||||
|
||||
### LAG
|
||||
1e Schinkelstraat 14-16 Amsterdam | <https://laglab.org/>
|
||||
|
||||
LAG is:
|
||||
onsidering hacking a political practice. We give workshops and learn how to have difficulties finding where people to challenging environment where people to challenging environment away from one is free to create and we want to be more their technology an
|
||||
|
||||
They drank all the Multilaterale and we are currently waiting to hear if they want more!
|
39
content/paleale.md
Normal file
@ -0,0 +1,39 @@
|
||||
Title: Pale Ale
|
||||
Date: 2020-02-11
|
||||
Category: Brews
|
||||
Image: images/paleale.jpg
|
||||
|
||||
A new brew has arrived! A hoppy, fruity Pale Ale this time!
|
||||
|
||||
Brewed with Cascade, Hersbrucker and Aurora hops this refreshing light-colored beer will leave you wanting for more! Since this is a smaller batch, make sure to get it while it lasts!
|
||||
|
||||
The perfect beer for all those who ask you 'Do you also have something special?'.
|
||||
|
||||
This ale was brewed in collaboration with our friends at Groos brewery.
|
||||
|
||||
![]({static}images/paleale.jpg)
|
||||
|
||||
###Data
|
||||
|
||||
* IBU: 23
|
||||
* EBC: 12
|
||||
* ABV: 5.3%
|
||||
* TOP fermentation
|
||||
|
||||
### Malts
|
||||
|
||||
* Barley
|
||||
* Oats
|
||||
|
||||
### Hops
|
||||
|
||||
* Cascade
|
||||
* Hersbrucker
|
||||
* Aurora
|
||||
|
||||
<br>
|
||||
|
||||
![]({attach}images/Multilaterale_Pale_3.jpg)
|
||||
|
||||
Right off the bottling line!
|
||||
|
19
content/panamaracingclub.md
Normal file
@ -0,0 +1,19 @@
|
||||
Title: Special Editions for Murder Capital
|
||||
Date: 2020-07-29
|
||||
Category: News
|
||||
Summary: Panama Racing Club special editions.
|
||||
|
||||
Our Red Ale and Irish Stout have been labelled in a Panama Racing Club theme for Murder Capital label. The Panama Red and Night Rider. Check them out in the IFM webshop: https://www.intergalactic.fm/shop/main/murdercapital-beer/?v=7516fd43adaa
|
||||
|
||||
## Here they are
|
||||
![]({attach}/images/MC.Beer.jpg)
|
||||
|
||||
![]({attach}/images/MC.kit.jpg)
|
||||
|
||||
## Cheers
|
||||
|
||||
![]({attach}/images/cheerswference.jpg)
|
||||
|
||||
## Interested?
|
||||
|
||||
If you are intersted in doing the same, get in touch!
|
37
content/redale.md
Normal file
@ -0,0 +1,37 @@
|
||||
Title: Red Ale
|
||||
Date: 2019-05-14
|
||||
Category: Brews
|
||||
Image: images/redale.jpg
|
||||
|
||||
Our first Multilaterale Group beer is a Red Ale. Inspired by Irish Red Ales.
|
||||
|
||||
It has a vibrant copper red colour. Smooth and malty flavour with tender hoppiness and a slight hint of sour in the after taste.
|
||||
|
||||
The perfect beer for all those who ask you 'Do you also have normal beer?'.
|
||||
|
||||
![]({static}images/redale.jpg)
|
||||
|
||||
###Data
|
||||
|
||||
* IBU: 18
|
||||
* EBC: 22
|
||||
* ABV: 4.7%
|
||||
* TOP fermentation
|
||||
|
||||
### Malts
|
||||
|
||||
* 65% Pale Ale
|
||||
* 24% Cara Red
|
||||
* 12% Cara 120
|
||||
|
||||
### Hops
|
||||
|
||||
* Magnum
|
||||
* Fuggle
|
||||
* Bramling Cross
|
||||
|
||||
<br>
|
||||
|
||||
![]({attach}images/skiddaw.jpg)
|
||||
|
||||
We have evidence of an Irishman approving of our Red Ale. This obviously bespeaks of the quality of this beer.
|
17
content/sessionpale.md
Normal file
@ -0,0 +1,17 @@
|
||||
Title: Session Pale
|
||||
Date: 2020-11-03
|
||||
Category: Brews
|
||||
Image: images/web96_session_pale.jpg
|
||||
Summary: Session Pale Ale
|
||||
|
||||
New Session Pale Ale from yours truly. Fruity, hoppy with a grapefruit-like bitterness. Hopped with Magnum and Cascade.
|
||||
|
||||
![]({static}images/web96_session_pale.jpg)
|
||||
|
||||
###Data
|
||||
|
||||
* IBU: 30
|
||||
* EBC: 10
|
||||
* ABV: 4.1%
|
||||
* TOP fermentation
|
||||
|
41
pelicanconf.py
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*- #
|
||||
from __future__ import unicode_literals
|
||||
|
||||
AUTHOR = 'the group'
|
||||
SITENAME = 'MULTILATERALE'
|
||||
SITEURL = 'https://multilaterale.group'
|
||||
|
||||
PATH = 'content'
|
||||
|
||||
TIMEZONE = 'Europe/Paris'
|
||||
|
||||
DEFAULT_LANG = 'en'
|
||||
DEFAULT_DATE = 'fs'
|
||||
|
||||
THEME = "themes/multilaterale/"
|
||||
|
||||
PLUGIN_PATHS = ['plugins']
|
||||
PLUGINS = ["representative_image"]
|
||||
|
||||
# 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', 'http://getpelican.com/'),
|
||||
('Python.org', 'http://python.org/'),
|
||||
('Jinja2', 'http://jinja.pocoo.org/'),
|
||||
('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 = False
|
||||
|
||||
# Uncomment following line if you want document-relative URLs when developing
|
||||
#RELATIVE_URLS = True
|
1
plugins/representative_image/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .representative_image import *
|
50
plugins/representative_image/representative_image.py
Normal file
@ -0,0 +1,50 @@
|
||||
import six
|
||||
from pelican import signals
|
||||
from pelican.contents import Article, Page
|
||||
from pelican.generators import ArticlesGenerator
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
|
||||
def images_extraction(instance):
|
||||
representativeImage = None
|
||||
if type(instance) in (Article, Page):
|
||||
if 'image' in instance.metadata:
|
||||
representativeImage = instance.metadata['image']
|
||||
|
||||
# Process Summary:
|
||||
# If summary contains images, extract one to be the representativeImage and remove images from summary
|
||||
soup = BeautifulSoup(instance.summary, 'html.parser')
|
||||
images = soup.find_all('img')
|
||||
for i in images:
|
||||
if not representativeImage:
|
||||
representativeImage = i['src']
|
||||
i.extract()
|
||||
if len(images) > 0:
|
||||
# set _summary field which is based on metadata. summary field is only based on article's content and not settable
|
||||
instance._summary = six.text_type(soup)
|
||||
|
||||
# If there are no image in summary, look for it in the content body
|
||||
if not representativeImage:
|
||||
soup = BeautifulSoup(instance._content, 'html.parser')
|
||||
imageTag = soup.find('img')
|
||||
if imageTag:
|
||||
representativeImage = imageTag['src']
|
||||
|
||||
# Set the attribute to content instance
|
||||
instance.featured_image = representativeImage
|
||||
|
||||
|
||||
def run_plugin(generators):
|
||||
for generator in generators:
|
||||
if isinstance(generator, ArticlesGenerator):
|
||||
for article in generator.articles:
|
||||
images_extraction(article)
|
||||
|
||||
|
||||
def register():
|
||||
try:
|
||||
signals.all_generators_finalized.connect(run_plugin)
|
||||
except AttributeError:
|
||||
# NOTE: This results in #314 so shouldn't really be relied on
|
||||
# https://github.com/getpelican/pelican-plugins/issues/314
|
||||
signals.content_object_init.connect(images_extraction)
|
33
plugins/thumbnailer/Readme.md
Normal file
@ -0,0 +1,33 @@
|
||||
Thumbnail Creation of images
|
||||
============================
|
||||
|
||||
This plugin creates thumbnails for all of the images found under a specific directory, in various thumbnail sizes.
|
||||
It requires `PIL` to function properly since `PIL` is used to resize the images, and the thumbnail will only be re-built
|
||||
if it doesn't already exist (to save processing time).
|
||||
|
||||
Installation
|
||||
-------------
|
||||
|
||||
Set up like any other plugin, making sure to set `PLUGIN_PATH` and add `thumbnailer` to the `PLUGINS` list.
|
||||
|
||||
[PIL](http://www.pythonware.com/products/pil/) or [Pillow](http://pillow.readthedocs.org/en/latest/installation.html#)
|
||||
is required. If you choose Pillow, you need to install some additional
|
||||
[external libraries](http://www.pythonware.com/products/pil/) to add support for image types like `jpg`.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
* `IMAGE_PATH` is the path to the image directory. It should reside inside your content directory, and defaults to "pictures".
|
||||
* `THUMBNAIL_DIR` is the path to the output sub-directory where the thumbnails are generated.
|
||||
* `THUMBNAIL_SIZES` is a dictionary mapping size name to size specifications.
|
||||
The generated filename will be `originalname_thumbnailname.ext` unless `THUMBNAIL_KEEP_NAME` is set.
|
||||
* `THUMBNAIL_KEEP_NAME` is a Boolean that, if set, puts the file with the original name in a thumbnailname folder, named like the key in `THUMBNAIL_SIZES`.
|
||||
* `THUMBNAIL_KEEP_TREE` is a Boolean that, if set, saves the image directory tree.
|
||||
* `THUMBNAIL_INCLUDE_REGEX` is an optional string that is used as regular expression to restrict thumbnailing to matching files. By default all files not starting with a dot are respected.
|
||||
|
||||
Sizes can be specified using any of the following formats:
|
||||
|
||||
* wxh will resize to exactly wxh cropping as necessary to get that size
|
||||
* wx? will resize so that the width is the specified size, and the height will scale to retain aspect ratio
|
||||
* ?xh same as wx? but will height being a set size
|
||||
* s is a shorthand for wxh where w=h
|
1
plugins/thumbnailer/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .thumbnailer import *
|
BIN
plugins/thumbnailer/test_data/expected_exact.jpg
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
plugins/thumbnailer/test_data/expected_height.jpg
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
plugins/thumbnailer/test_data/expected_square.jpg
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
plugins/thumbnailer/test_data/expected_width.jpg
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
plugins/thumbnailer/test_data/sample_image.jpg
Normal file
After Width: | Height: | Size: 330 KiB |
BIN
plugins/thumbnailer/test_data/subdir/sample_image.jpg
Normal file
After Width: | Height: | Size: 330 KiB |
63
plugins/thumbnailer/test_thumbnails.py
Normal file
@ -0,0 +1,63 @@
|
||||
from thumbnailer import _resizer
|
||||
from unittest import TestCase, main
|
||||
import os
|
||||
from PIL import Image
|
||||
|
||||
class ThumbnailerTests(TestCase):
|
||||
|
||||
def path(self, filename):
|
||||
return os.path.join(self.img_path, filename)
|
||||
|
||||
def setUp(self):
|
||||
self.img_path = os.path.join(os.path.dirname(__file__), "test_data")
|
||||
self.img = Image.open(self.path("sample_image.jpg"))
|
||||
|
||||
def testSquare(self):
|
||||
r = _resizer('square', '100', self.img_path)
|
||||
output = r.resize(self.img)
|
||||
self.assertEqual((100, 100), output.size)
|
||||
|
||||
def testExact(self):
|
||||
r = _resizer('exact', '250x100', self.img_path)
|
||||
output = r.resize(self.img)
|
||||
self.assertEqual((250, 100), output.size)
|
||||
|
||||
def testWidth(self):
|
||||
r = _resizer('aspect', '250x?', self.img_path)
|
||||
output = r.resize(self.img)
|
||||
self.assertEqual((250, 166), output.size)
|
||||
|
||||
def testHeight(self):
|
||||
r = _resizer('aspect', '?x250', self.img_path)
|
||||
output = r.resize(self.img)
|
||||
self.assertEqual((375, 250), output.size)
|
||||
|
||||
class ThumbnailerFilenameTest(TestCase):
|
||||
|
||||
def path(self, *parts):
|
||||
return os.path.join(self.img_path, *parts)
|
||||
|
||||
def setUp(self):
|
||||
self.img_path = os.path.join(os.path.dirname(__file__), "test_data")
|
||||
|
||||
def testRoot(self):
|
||||
"""Test a file that is in the root of img_path."""
|
||||
|
||||
r = _resizer('square', '100', self.img_path)
|
||||
new_name = r.get_thumbnail_name(self.path('sample_image.jpg'))
|
||||
self.assertEqual('sample_image_square.jpg', new_name)
|
||||
|
||||
def testRootWithSlash(self):
|
||||
r = _resizer('square', '100', self.img_path + '/')
|
||||
new_name = r.get_thumbnail_name(self.path('sample_image.jpg'))
|
||||
self.assertEqual('sample_image_square.jpg', new_name)
|
||||
|
||||
def testSubdir(self):
|
||||
"""Test a file that is in a sub-directory of img_path."""
|
||||
|
||||
r = _resizer('square', '100', self.img_path)
|
||||
new_name = r.get_thumbnail_name(self.path('subdir', 'sample_image.jpg'))
|
||||
self.assertEqual('subdir/sample_image_square.jpg', new_name)
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
210
plugins/thumbnailer/thumbnailer.py
Normal file
@ -0,0 +1,210 @@
|
||||
import os
|
||||
import os.path as path
|
||||
import re
|
||||
from pelican import signals
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
from PIL import Image, ImageOps
|
||||
enabled = True
|
||||
except ImportError:
|
||||
logging.warning("Unable to load PIL, disabling thumbnailer")
|
||||
enabled = False
|
||||
|
||||
DEFAULT_IMAGE_DIR = "pictures"
|
||||
DEFAULT_THUMBNAIL_DIR = "thumbnails"
|
||||
DEFAULT_THUMBNAIL_SIZES = {
|
||||
'thumbnail_square': '150',
|
||||
'thumbnail_wide': '150x?',
|
||||
'thumbnail_tall': '?x150',
|
||||
}
|
||||
DEFAULT_TEMPLATE = """<a href="{url}" rel="shadowbox" title="{filename}"><img src="{thumbnail}" alt="{filename}"></a>"""
|
||||
DEFAULT_GALLERY_THUMB = "thumbnail_square"
|
||||
|
||||
class _resizer(object):
|
||||
""" Resizes based on a text specification, see readme """
|
||||
|
||||
REGEX = re.compile(r'(\d+|\?)x(\d+|\?)')
|
||||
|
||||
def __init__(self, name, spec, root):
|
||||
self._name = name
|
||||
self._spec = spec
|
||||
# The location of input images from _image_path.
|
||||
self._root = root
|
||||
|
||||
def _null_resize(self, w, h, image):
|
||||
return image
|
||||
|
||||
def _exact_resize(self, w, h, image):
|
||||
retval = ImageOps.fit(image, (w,h), Image.BICUBIC)
|
||||
return retval
|
||||
|
||||
def _aspect_resize(self, w, h, image):
|
||||
retval = image.copy()
|
||||
retval.thumbnail((w, h), Image.ANTIALIAS)
|
||||
|
||||
return retval
|
||||
|
||||
def resize(self, image):
|
||||
resizer = self._null_resize
|
||||
|
||||
# Square resize and crop
|
||||
if 'x' not in self._spec:
|
||||
resizer = self._exact_resize
|
||||
targetw = int(self._spec)
|
||||
targeth = targetw
|
||||
else:
|
||||
matches = self.REGEX.search(self._spec)
|
||||
tmpw = matches.group(1)
|
||||
tmph = matches.group(2)
|
||||
|
||||
# Full Size
|
||||
if tmpw == '?' and tmph == '?':
|
||||
targetw = image.size[0]
|
||||
targeth = image.size[1]
|
||||
resizer = self._null_resize
|
||||
|
||||
# Set Height Size
|
||||
if tmpw == '?':
|
||||
targetw = image.size[0]
|
||||
targeth = int(tmph)
|
||||
resizer = self._aspect_resize
|
||||
|
||||
# Set Width Size
|
||||
elif tmph == '?':
|
||||
targetw = int(tmpw)
|
||||
targeth = image.size[1]
|
||||
resizer = self._aspect_resize
|
||||
|
||||
# Scale and Crop
|
||||
else:
|
||||
targetw = int(tmpw)
|
||||
targeth = int(tmph)
|
||||
resizer = self._exact_resize
|
||||
|
||||
logging.debug("Using resizer {0}".format(resizer.__name__))
|
||||
return resizer(targetw, targeth, image)
|
||||
|
||||
def get_thumbnail_name(self, in_path):
|
||||
# Find the partial path + filename beyond the input image directory.
|
||||
prefix = path.commonprefix([in_path, self._root])
|
||||
new_filename = in_path[len(prefix) + 1:]
|
||||
|
||||
# Generate the new filename.
|
||||
(basename, ext) = path.splitext(new_filename)
|
||||
return "{0}_{1}{2}".format(basename, self._name, ext)
|
||||
|
||||
def resize_file_to(self, in_path, out_path, keep_filename=False):
|
||||
""" Given a filename, resize and save the image per the specification into out_path
|
||||
|
||||
:param in_path: path to image file to save. Must be supported by PIL
|
||||
:param out_path: path to the directory root for the outputted thumbnails to be stored
|
||||
:return: None
|
||||
"""
|
||||
|
||||
if keep_filename:
|
||||
filename = path.join(out_path, path.basename(in_path))
|
||||
else:
|
||||
filename = path.join(out_path, self.get_thumbnail_name(in_path))
|
||||
out_path = path.dirname(filename)
|
||||
if not path.exists(out_path):
|
||||
os.makedirs(out_path)
|
||||
if not path.exists(filename):
|
||||
try:
|
||||
image = Image.open(in_path)
|
||||
thumbnail = self.resize(image)
|
||||
logger.debug('test')
|
||||
thumbnail.save(filename)
|
||||
logger.info("Generated Thumbnail {0}".format(path.basename(filename)))
|
||||
except IOError:
|
||||
logger.info("Generating Thumbnail for {0} skipped".format(path.basename(filename)))
|
||||
|
||||
|
||||
def resize_thumbnails(pelican):
|
||||
""" Resize a directory tree full of images into thumbnails
|
||||
|
||||
:param pelican: The pelican instance
|
||||
:return: None
|
||||
"""
|
||||
global enabled
|
||||
if not enabled:
|
||||
return
|
||||
|
||||
in_path = _image_path(pelican)
|
||||
|
||||
include_regex = pelican.settings.get('THUMBNAIL_INCLUDE_REGEX')
|
||||
if include_regex:
|
||||
pattern = re.compile(include_regex)
|
||||
is_included = lambda name: pattern.match(name)
|
||||
else:
|
||||
is_included = lambda name: not name.startswith('.')
|
||||
|
||||
sizes = pelican.settings.get('THUMBNAIL_SIZES', DEFAULT_THUMBNAIL_SIZES)
|
||||
resizers = dict((k, _resizer(k, v, in_path)) for k,v in sizes.items())
|
||||
logger.debug("Thumbnailer Started")
|
||||
for dirpath, _, filenames in os.walk(in_path):
|
||||
for filename in filenames:
|
||||
if is_included(filename):
|
||||
for name, resizer in resizers.items():
|
||||
in_filename = path.join(dirpath, filename)
|
||||
out_path = get_out_path(pelican, in_path, in_filename, name)
|
||||
resizer.resize_file_to(
|
||||
in_filename,
|
||||
out_path, pelican.settings.get('THUMBNAIL_KEEP_NAME'))
|
||||
|
||||
|
||||
def get_out_path(pelican, in_path, in_filename, name):
|
||||
base_out_path = path.join(pelican.settings['OUTPUT_PATH'],
|
||||
pelican.settings.get('THUMBNAIL_DIR', DEFAULT_THUMBNAIL_DIR))
|
||||
logger.debug("Processing thumbnail {0}=>{1}".format(in_filename, name))
|
||||
if pelican.settings.get('THUMBNAIL_KEEP_NAME', False):
|
||||
if pelican.settings.get('THUMBNAIL_KEEP_TREE', False):
|
||||
return path.join(base_out_path, name, path.dirname(path.relpath(in_filename, in_path)))
|
||||
else:
|
||||
return path.join(base_out_path, name)
|
||||
else:
|
||||
return base_out_path
|
||||
|
||||
|
||||
def _image_path(pelican):
|
||||
return path.join(pelican.settings['PATH'],
|
||||
pelican.settings.get("IMAGE_PATH", DEFAULT_IMAGE_DIR)).rstrip('/')
|
||||
|
||||
|
||||
def expand_gallery(generator, metadata):
|
||||
""" Expand a gallery tag to include all of the files in a specific directory under IMAGE_PATH
|
||||
|
||||
:param pelican: The pelican instance
|
||||
:return: None
|
||||
"""
|
||||
if "gallery" not in metadata or metadata['gallery'] is None:
|
||||
return # If no gallery specified, we do nothing
|
||||
|
||||
lines = [ ]
|
||||
base_path = _image_path(generator)
|
||||
in_path = path.join(base_path, metadata['gallery'])
|
||||
template = generator.settings.get('GALLERY_TEMPLATE', DEFAULT_TEMPLATE)
|
||||
thumbnail_name = generator.settings.get("GALLERY_THUMBNAIL", DEFAULT_GALLERY_THUMB)
|
||||
thumbnail_prefix = generator.settings.get("")
|
||||
resizer = _resizer(thumbnail_name, '?x?', base_path)
|
||||
for dirpath, _, filenames in os.walk(in_path):
|
||||
for filename in filenames:
|
||||
if not filename.startswith('.'):
|
||||
url = path.join(dirpath, filename).replace(base_path, "")[1:]
|
||||
url = path.join('/static', generator.settings.get('IMAGE_PATH', DEFAULT_IMAGE_DIR), url).replace('\\', '/')
|
||||
logger.debug("GALLERY: {0}".format(url))
|
||||
thumbnail = resizer.get_thumbnail_name(filename)
|
||||
thumbnail = path.join('/', generator.settings.get('THUMBNAIL_DIR', DEFAULT_THUMBNAIL_DIR), thumbnail).replace('\\', '/')
|
||||
lines.append(template.format(
|
||||
filename=filename,
|
||||
url=url,
|
||||
thumbnail=thumbnail,
|
||||
))
|
||||
metadata['gallery_content'] = "\n".join(lines)
|
||||
|
||||
|
||||
def register():
|
||||
signals.finalized.connect(resize_thumbnails)
|
||||
signals.article_generator_context.connect(expand_gallery)
|
25
publishconf.py
Normal file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*- #
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# 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://multilaterale.group'
|
||||
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 = ""
|
63
themes/multilaterale/static/multilaterale_logo.svg
Normal file
After Width: | Height: | Size: 70 KiB |
64
themes/multilaterale/static/multilaterale_logo_opacity.svg
Normal file
After Width: | Height: | Size: 70 KiB |
64
themes/multilaterale/static/multilaterale_logo_pink.svg
Normal file
After Width: | Height: | Size: 70 KiB |
64
themes/multilaterale/static/multilaterale_logo_watermerk.svg
Normal file
After Width: | Height: | Size: 70 KiB |
134
themes/multilaterale/static/multilaterale_text.svg
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg56"
|
||||
version="1.1"
|
||||
viewBox="0 0 98.008278 15.28714"
|
||||
height="15.28714mm"
|
||||
width="98.008278mm"
|
||||
sodipodi:docname="multilaterale_text.svg"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="835"
|
||||
id="namedview22"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="0.2102413"
|
||||
inkscape:cx="133.49146"
|
||||
inkscape:cy="-235.56536"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg56" />
|
||||
<defs
|
||||
id="defs50" />
|
||||
<metadata
|
||||
id="metadata53">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
transform="translate(-69.680384,-70.886192)">
|
||||
<g
|
||||
id="g38"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,55.458765,58.740274)">
|
||||
<g
|
||||
id="g36">
|
||||
<g
|
||||
id="g34">
|
||||
<path
|
||||
d="m 74.435,90.483 c 2.182,-15.25 5.161,-29.756 9.365,-43.115 2.994,-0.485 5.997,-0.963 9.758,-0.729 2.877,16.991 0.961,37.921 2.341,54.074 -2.186,0.607 -5.174,0.374 -7.416,0 -0.062,-13.412 -0.62,-27.838 -0.391,-43.115 -3.815,13.724 -7.469,27.594 -9.363,43.115 -1.709,1.325 -4.424,1.705 -7.029,2.191 -4.294,-14 -6.646,-29.829 -9.755,-44.939 -1.862,12.464 0.728,32.056 -0.781,44.259 -1.868,0.928 -4.654,1.002 -7.023,1.46 0.521,-15.714 2.023,-40.129 -0.39,-56.315 2.089,-1.697 7.095,-0.663 10.145,-1.462 5.57,12.931 7.697,29.086 10.539,44.576 z"
|
||||
id="path8"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 193.85,46.639 c 0,18.879 -1.204,35.87 -0.39,53.71 -1.387,0.858 -5.205,1.087 -7.023,0.364 -0.435,-10.956 1.148,-25.8 0,-39.095 -0.436,-5.047 -0.344,-12.585 0.39,-15.711 2.62,-0.018 4.712,0.459 7.023,0.732 z"
|
||||
id="path10"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 241.463,46.272 c 6.176,16.259 7.063,37.473 12.875,54.076 -0.688,1.434 -3.978,2.349 -5.851,1.459 -2.881,-1.812 -2.148,-7.001 -3.904,-9.865 -4.649,0.335 -7.923,-0.618 -11.706,-1.097 -1.288,3.044 -1.792,7.131 -1.955,10.233 -2.054,1.055 -4.386,-0.422 -7.024,0 3.066,-17.474 7.365,-36.951 11.709,-54.44 2.375,0.505 4.127,-1.477 5.856,-0.366 z m -7.419,38.362 c 3.609,-0.086 5.368,1.553 9.366,1.097 -1.052,-9.607 -2.98,-18.398 -4.292,-27.767 -2.541,8.093 -3.996,17.206 -5.074,26.67 z"
|
||||
id="path12"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 328.488,77.694 c 5.016,5.777 6.66,14.709 7.805,24.114 -2.193,0.383 -4.279,0.865 -6.636,1.096 -0.948,-5.265 -1.318,-14.801 -4.294,-19.363 -1.234,-1.895 -3.202,-3.151 -6.239,-2.558 -0.499,6.205 0.324,14.295 0.387,21.191 -2.472,0 -4.941,0 -7.414,0 0.037,-18.249 0.239,-36.76 1.17,-55.535 0.286,-0.344 0.71,-0.557 1.174,-0.732 6.042,0.962 11.736,0.11 16.389,3.291 7.925,5.409 7.099,26.598 -2.342,28.496 z m -9.364,-2.924 c 13.823,2.469 14.092,-24.284 0.78,-22.653 -0.201,7.491 -2.055,14.956 -0.78,22.653 z"
|
||||
id="path14"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 358.146,45.906 c 5.461,17.175 7.442,37.607 12.488,55.173 -1.634,0.668 -4.115,1.636 -6.244,0.729 -1.693,-2.677 -2.075,-6.583 -3.122,-9.865 -4.553,0.242 -8.098,-0.457 -11.707,-1.097 -1.752,2.624 -1.626,7.003 -2.342,10.597 -2.673,0.187 -4.251,-0.646 -7.026,-0.364 3.611,-18.301 7.408,-36.422 11.709,-54.076 1.858,-0.575 3.758,-1.108 6.244,-1.097 z m -7.804,38.364 c 2.983,0.618 5.458,1.712 9.366,1.461 -0.923,-9.612 -2.607,-18.508 -4.294,-27.402 -2.464,7.921 -3.621,17.068 -5.072,25.941 z"
|
||||
id="path16"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 109.948,46.639 c 2.832,14.273 -0.078,33.927 3.122,47.861 2.345,0.685 2.957,0.203 7.413,-0.366 1.112,-15.023 0.02,-30.647 0.78,-47.496 2.115,-0.035 4.9,-0.699 7.023,0 -0.201,11.018 1.38,25.194 0,36.171 -0.524,4.187 0.516,10.155 -0.779,13.153 -2.578,5.962 -18.239,6.605 -20.469,3.324 -1.707,-2.521 -2.747,-11.867 -2.946,-16.113 -0.202,-4.341 -0.202,-9.822 -0.388,-15.344 -0.245,-7.173 -0.322,-17.879 0.779,-21.191 1.384,-0.53 4.08,-0.53 5.465,0.001 z"
|
||||
id="path18"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 304.487,46.272 c 0.243,1.602 1.014,2.704 1.173,4.385 -2.989,1.244 -10.263,1.436 -14.437,1.458 -1.089,4.674 0.04,10.435 0,15.348 3.961,1.574 8.12,-0.465 12.875,0.366 0.723,1.374 1.258,4.529 0.389,6.21 -4.032,0 -8.061,0 -12.096,0 -1.256,6.528 -1.729,14.799 -1.562,21.557 5.031,-0.642 9.317,0.674 14.438,-0.365 -0.118,1.544 0.686,3.988 0,5.848 -9.191,-1.399 -15.91,2.705 -21.849,-1.097 0.705,-10.108 2.208,-21.826 1.561,-33.981 -0.356,-6.654 -2.488,-12.875 -0.782,-18.633 5.311,-1.981 13.507,0.005 20.29,-1.096 z"
|
||||
id="path20"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 383.903,46.272 c 1.311,1.716 -0.448,3.328 -0.78,5.113 -0.88,4.736 0.141,10.375 0,16.444 -0.205,8.887 -1.712,17.018 -0.78,26.305 3.283,0.274 8.814,-0.182 13.267,0 0.449,2.244 1.144,3.203 0.78,5.483 -5.261,1.891 -13.173,1.307 -20.291,1.462 -2.033,-17.257 0.512,-36.942 -0.78,-53.711 2.517,-0.684 5.985,-0.483 8.584,-1.096 z"
|
||||
id="path22"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 422.929,46.272 c 0.575,1.41 1.215,2.76 1.17,4.749 -3.521,0.604 -10.199,1.208 -14.438,1.095 -1.101,4.929 0.546,10.449 0.39,15.713 4.508,0.75 8.018,-0.701 12.879,0 0.392,1.827 0.919,3.523 0.779,5.846 -3.584,0.784 -8.661,0.172 -12.878,0.364 -1.109,6.514 -1.405,13.79 -1.561,21.191 3.659,0.125 9.785,0.676 14.438,0 0.624,1.242 0.624,4.604 0,5.849 -9.153,-1.225 -15.046,2.282 -21.464,-0.731 1.943,-18.594 0.919,-35.21 0.39,-52.98 5.405,-1.89 13.449,-0.052 20.295,-1.096 z"
|
||||
id="path24"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 179.413,46.639 c 0.52,1.581 0.655,3.522 0.78,5.478 -3.375,-0.112 -6.106,0.375 -8.977,0.731 1.484,13.166 -1.045,32.147 0.779,46.718 -2.729,0 -4.8,0.622 -7.805,0.365 -1.914,-14.928 2.24,-32.977 0,-47.083 -2.777,-0.811 -7.303,0.022 -10.145,-0.731 0,-1.458 0,-2.919 0,-4.382 7.609,-1.132 16.543,-0.436 25.368,-1.096 z"
|
||||
id="path26"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 278.535,46.639 c 0.799,1.199 0.211,3.698 0.39,5.478 -3.043,-0.046 -5.787,0.187 -8.194,0.731 0.054,15.79 -1.346,32.466 0,48.595 -2.734,0 -4.802,0.62 -7.808,0.365 -1.845,-16.432 2.39,-33.22 0,-48.96 -2.714,-0.867 -7.351,0.065 -10.148,-0.731 0,-1.458 0,-2.919 0,-4.382 7.82,-1.19 16.737,-0.442 25.76,-1.096 z"
|
||||
id="path28"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 143.508,47.734 c 2.706,14.84 -0.671,30.869 0,47.132 5.866,0.729 7.947,0.339 12.9,-0.342 0.216,2.639 -0.285,4.835 -1.089,6.521 -5.749,-0.682 -8.819,0.099 -18.056,0.035 -2.396,-16.072 1.661,-35.996 0,-52.979 2.404,0.176 3.731,-0.651 6.245,-0.367 z"
|
||||
id="path30"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 209.459,47.734 c 1.919,16.194 -0.557,28.907 -0.388,45.298 4.199,0.819 10.039,0.364 13.737,-0.08 -0.197,2.244 -0.96,5.805 -1.949,7.316 -4.947,-1.312 -17.046,-0.454 -19.53,-0.837 2.104,-13.509 3.419,-33.511 1.496,-51.331 2.487,0.131 3.99,-0.648 6.634,-0.366 z"
|
||||
id="path32"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.9 KiB |
176
themes/multilaterale/static/style.css
Normal file
@ -0,0 +1,176 @@
|
||||
html {
|
||||
background-color: rgb(240,240,240);
|
||||
background-image:url('/theme/multilaterale_logo_opacity.svg');
|
||||
background-size:200vw;
|
||||
background-position: center top;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size:22px;
|
||||
font-family: 'Kotta One', serif;
|
||||
max-width:50%;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color:deeppink;
|
||||
text-decoration-style: wavy;
|
||||
}
|
||||
|
||||
h1,h2,h3{
|
||||
text-transform: uppercase;
|
||||
/*font-family: 'Amatic SC', cursive;*/
|
||||
}
|
||||
h3{
|
||||
margin:0;
|
||||
margin-top:2em;
|
||||
}
|
||||
|
||||
h3 + p {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom:0.2em;
|
||||
}
|
||||
|
||||
#banner{
|
||||
margin-top:2em;
|
||||
margin-bottom:0em;
|
||||
}
|
||||
|
||||
#banner_img{
|
||||
width:100%;
|
||||
}
|
||||
|
||||
#menu ul li{
|
||||
display:inline;
|
||||
}
|
||||
|
||||
#menu ul {
|
||||
padding-left:0px;
|
||||
font-size: 2em;
|
||||
text-align: center;
|
||||
margin-top:0px;
|
||||
margin-bottom:1.5em;
|
||||
}
|
||||
|
||||
#menu a {
|
||||
color:black;
|
||||
text-decoration-style: none;
|
||||
}
|
||||
|
||||
#menu a:hover {
|
||||
color:black;
|
||||
text-decoration-style: wavy;
|
||||
text-decoration-color: deeppink;
|
||||
}
|
||||
|
||||
#menu .active a{
|
||||
|
||||
text-decoration-style: wavy;
|
||||
text-decoration-color: deeppink;
|
||||
}
|
||||
|
||||
.featured_image{
|
||||
display:inline-block;
|
||||
max-width: 40%;
|
||||
}
|
||||
|
||||
.featured_image img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.summary{
|
||||
display:inline-block;
|
||||
max-width: 50%;
|
||||
vertical-align: top;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.summary h2 {
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0;
|
||||
/*border-bottom: 6px solid black;*/
|
||||
}
|
||||
|
||||
.entry-content p img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#data-left, #data-right{
|
||||
max-width: 49%;
|
||||
display:inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#data-left img{
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#data h3 {
|
||||
margin:0.3em;
|
||||
}
|
||||
|
||||
#data ul {
|
||||
margin:0.5em;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
body {
|
||||
font-size:24px;
|
||||
max-width: 92%
|
||||
}
|
||||
#menu ul {
|
||||
font-size:1.5em;
|
||||
}
|
||||
#banner{
|
||||
margin-top:1em;
|
||||
}
|
||||
|
||||
#data-left, #data-right{
|
||||
max-width: 100%;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 300px) {
|
||||
body {
|
||||
font-size:18px;
|
||||
max-width: 92%
|
||||
}
|
||||
#menu ul {
|
||||
font-size:1.2em;
|
||||
}
|
||||
#banner{
|
||||
margin-top:1em;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (orientation: portrait) {
|
||||
body {
|
||||
font-size:48px;
|
||||
max-width: 92%
|
||||
}
|
||||
|
||||
#menu ul {
|
||||
font-size:1.5em;
|
||||
}
|
||||
#banner{
|
||||
margin-top:1em;
|
||||
}
|
||||
.featured_image{
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.featured_image img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.summary{
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
}
|
14
themes/multilaterale/templates/archives.html
Normal 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 %}
|
30
themes/multilaterale/templates/article.html
Normal file
@ -0,0 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
{% block html_lang %}{{ article.lang }}{% endblock %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - {{ article.title }}{% 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 %}
|
||||
<section id="content" class="body">
|
||||
<div class="entry-content">
|
||||
<h3>{{article.title}}</h3>
|
||||
{{ article.content }}
|
||||
</div><!-- /.entry-content -->
|
||||
</section>
|
||||
{% endblock %}
|
8
themes/multilaterale/templates/author.html
Normal file
@ -0,0 +1,8 @@
|
||||
{% extends "index.html" %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - Articles by {{ author }}{% endblock %}
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Articles by {{ author }}</h2>
|
||||
{% endblock %}
|
||||
|
12
themes/multilaterale/templates/authors.html
Normal 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 %}
|
48
themes/multilaterale/templates/base.html
Normal file
@ -0,0 +1,48 @@
|
||||
<!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" />
|
||||
<link rel="stylesheet" type="text/css" href="{{SITEURL}}/theme/style.css">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Kotta+One&display=swap" rel="stylesheet">
|
||||
|
||||
{% block rss %}
|
||||
{% endblock rss %}
|
||||
{% endblock head %}
|
||||
</head>
|
||||
|
||||
<body id="index" class="home">
|
||||
{% block menu %}
|
||||
<header id="banner" class="body">
|
||||
<a href="{{ SITEURL }}/"><img id="banner_img"src="/theme/multilaterale_text.svg"></a>
|
||||
</header><!-- /#banner -->
|
||||
<nav id="menu"><ul>
|
||||
{% for title, link in MENUITEMS %}
|
||||
<li><a href="{{ link }}">{{ title }}</a></li>
|
||||
{% endfor %}
|
||||
{% if DISPLAY_PAGES_ON_MENU %}
|
||||
{% for p in pages %}
|
||||
<li{% if p == page %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ p.url }}">{{ p.title }}</a> - </li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if DISPLAY_CATEGORIES_ON_MENU %}
|
||||
{% for cat, null in categories %}
|
||||
{% if loop.last %}
|
||||
<li{% if cat == category %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ cat.url }}">{{ cat }}</a> </li>
|
||||
{% else %}
|
||||
<li{% if cat == category %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ cat.url }}">{{ cat }}</a> - </li>
|
||||
{%endif%}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</ul></nav><!-- /#menu -->
|
||||
{% endblock menu %}
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
<footer id="contentinfo" class="body">
|
||||
<address id="about" class="vcard body">
|
||||
</address><!-- /#about -->
|
||||
</footer><!-- /#contentinfo -->
|
||||
</body>
|
||||
</html>
|
12
themes/multilaterale/templates/categories.html
Normal 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 %}
|
35
themes/multilaterale/templates/category.html
Normal file
@ -0,0 +1,35 @@
|
||||
{% extends "index.html" %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - {{ category }} category{% endblock %}
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Articles in the {{ category }} category</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section id="content">
|
||||
|
||||
<div id="post-list">
|
||||
{% for article in articles_page.object_list %}
|
||||
|
||||
<article class="hentry">
|
||||
<div class="entry-content">
|
||||
{% if article.category != 'Brews' %}
|
||||
<header> <h2 class="entry-title log"><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title|striptags }}">{{ article.title }} | {{ article.date | strftime('%d %B %Y')}}</a></h2> </header>
|
||||
{{article.summary}}
|
||||
{% else %}
|
||||
<header> <h2 class="entry-title log"><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h2> </header>
|
||||
<a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title|striptags }}"><img src="{{SITURL}}/{{article.featured_image}}"></a>
|
||||
{{article.summary}}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- /#posts-list -->
|
||||
{% if articles_page.has_other_pages() %}
|
||||
{% include 'pagination.html' %}
|
||||
{% endif %}
|
||||
</section><!-- /#content -->
|
||||
{% endblock content %}
|
14
themes/multilaterale/templates/gosquared.html
Normal 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 %}
|
45
themes/multilaterale/templates/index.html
Normal file
@ -0,0 +1,45 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<section id="content">
|
||||
{% block content_title %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
<div id="post-list">
|
||||
{% for article in articles_page.object_list %}
|
||||
{% if article.category != 'News' %}
|
||||
<article class="hentry">
|
||||
<div class="entry-content">
|
||||
<div class="featured_image">
|
||||
{% if article.featured_image %}
|
||||
<img src="{{SITEURL}}/{{ article.featured_image }}">
|
||||
{% endif %}</div>
|
||||
<div class="summary">
|
||||
<header> <h2 class="entry-title"><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h2> </header>
|
||||
{{article.summary}}<a href="{{ SITEURL }}/{{ article.url }}">[continued]</a>
|
||||
</div>
|
||||
</div><!-- /.entry-content -->
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<h2>UPDATES</h2>
|
||||
{% for article in articles_page.object_list %}
|
||||
{% if article.category != 'Brews' %}
|
||||
<article class="hentry">
|
||||
<div class="entry-content">
|
||||
<div class="summary">
|
||||
<header> <h2 class="entry-title"><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h2> </header>
|
||||
{{article.date | strftime('%d %B %Y')}}
|
||||
{{article.summary}}
|
||||
</div>
|
||||
</div><!-- /.entry-content -->
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- /#posts-list -->
|
||||
{% if articles_page.has_other_pages() %}
|
||||
{% include 'pagination.html' %}
|
||||
{% endif %}
|
||||
</section><!-- /#content -->
|
||||
{% endblock content %}
|
26
themes/multilaterale/templates/page.html
Normal file
@ -0,0 +1,26 @@
|
||||
{% extends "base.html" %}
|
||||
{% block html_lang %}{{ page.lang }}{% endblock %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - {{ page.title }}{%endblock%}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
|
||||
{% import 'translations.html' as translations with context %}
|
||||
{% if translations.entry_hreflang(page) %}
|
||||
{{ translations.entry_hreflang(page) }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% 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 %}
|
11
themes/multilaterale/templates/pagination.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% if DEFAULT_PAGINATION %}
|
||||
<p class="paginator">
|
||||
{% if articles_page.has_previous() %}
|
||||
<a href="{{ SITEURL }}/{{ articles_previous_page.url }}">«</a>
|
||||
{% endif %}
|
||||
Page {{ articles_page.number }} / {{ articles_paginator.num_pages }}
|
||||
{% if articles_page.has_next() %}
|
||||
<a href="{{ SITEURL }}/{{ articles_next_page.url }}">»</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
14
themes/multilaterale/templates/period_archives.html
Normal 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 %}
|
27
themes/multilaterale/templates/rss.html
Normal file
@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
{%block rss%}
|
||||
{% if FEED_ALL_ATOM %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if FEED_ALL_ATOM_URL %}{{ FEED_ALL_ATOM_URL }}{% else %}{{ FEED_ALL_ATOM }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} Full Atom Feed" />
|
||||
{% endif %}
|
||||
{% if FEED_ALL_RSS %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if FEED_ALL_RSS_URL %}{{ FEED_ALL_RSS_URL }}{% else %}{{ FEED_ALL_RSS }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} Full RSS Feed" />
|
||||
{% endif %}
|
||||
{% if FEED_ATOM %}
|
||||
<link href="{{ FEED_DOMAIN }}/{%if FEED_ATOM_URL %}{{ FEED_ATOM_URL }}{% else %}{{ FEED_ATOM }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} Atom Feed" />
|
||||
{% endif %}
|
||||
{% if FEED_RSS %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if FEED_RSS_URL %}{{ FEED_RSS_URL }}{% else %}{{ FEED_RSS }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} RSS Feed" />
|
||||
{% endif %}
|
||||
{% if CATEGORY_FEED_ATOM and category %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if CATEGORY_FEED_ATOM_URL %}{{ CATEGORY_FEED_ATOM_URL|format(category.slug) }}{% else %}{{ CATEGORY_FEED_ATOM|format(category.slug) }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} Categories Atom Feed" />
|
||||
{% endif %}
|
||||
{% if CATEGORY_FEED_RSS and category %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if CATEGORY_FEED_RSS_URL %}{{ CATEGORY_FEED_RSS_URL|format(category.slug) }}{% else %}{{ CATEGORY_FEED_RSS|format(category.slug) }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} Categories RSS Feed" />
|
||||
{% endif %}
|
||||
{% if TAG_FEED_ATOM and tag %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if TAG_FEED_ATOM_URL %}{{ TAG_FEED_ATOM_URL|format(tag.slug) }}{% else %}{{ TAG_FEED_ATOM|format(tag.slug) }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} Tags Atom Feed" />
|
||||
{% endif %}
|
||||
{% if TAG_FEED_RSS and tag %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if TAG_FEED_RSS_URL %}{{ TAG_FEED_RSS_URL|format(tag.slug) }}{% else %}{{ TAG_FEED_RSS|format(tag.slug) }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} Tags RSS Feed" />
|
||||
{% endif %}
|
||||
{%endblock rss%}
|
7
themes/multilaterale/templates/tag.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% extends "index.html" %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - {{ tag }} tag{% endblock %}
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Articles tagged with {{ tag }}</h2>
|
||||
{% endblock %}
|
12
themes/multilaterale/templates/tags.html
Normal 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 %}
|
16
themes/multilaterale/templates/translations.html
Normal 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 %}
|