[WIP] A rusty makeover.

Design inspired and stolen from blog.rust-lang.org and rust-lang.org.
WIP. Few issues still need to resolved like handheld device compatibility, subscription form submission etc.
This commit is contained in:
Vikrant Chaudhary 2015-06-17 01:19:13 +05:30
parent 7d59a894c6
commit d22f445ac1
16 changed files with 759 additions and 2 deletions

3
.gitignore vendored
View File

@ -4,4 +4,5 @@ lib
include
output
*~
cache
cache
.sass-cache

View File

@ -8,7 +8,10 @@ SITEURL = 'http://this-week-in-rust.org'
SOURCE_URL = 'https://github.com/cmr/this-week-in-rust'
THEME = 'pelican-elegant-1.3'
THEME = 'themes/rusted'
PLUGIN_PATHS = ["plugins"]
PLUGINS = ['assets']
TIMEZONE = 'America/New_York'

106
plugins/assets/Readme.rst Normal file
View File

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

View File

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

72
plugins/assets/assets.py Normal file
View File

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

View File

@ -0,0 +1,192 @@
/**
* Reset some basic elements
*/
body, h1, h2, h3, h4, h5, h6,
p, blockquote, pre, hr,
dl, dd, ol, ul, figure {
margin: 0;
padding: 0;
}
/**
* Basic styling
*/
body {
font-family: $base-font-family;
font-size: $base-font-size;
line-height: $base-line-height;
font-weight: 300;
color: $text-color;
background-color: $background-color;
}
/**
* Set `margin-bottom` to maintain vertycal rhythm
*/
h1, h2, h3, h4, h5, h6,
p, blockquote, pre,
ul, ol, dl, figure,
%vertical-rhythm {
margin-bottom: $spacing-unit / 2;
}
/**
* Images
*/
img {
max-width: 100%;
vertical-align: middle;
}
/**
* Figures
*/
figure > img {
display: block;
}
figcaption {
font-size: $small-font-size;
}
/**
* Lists
*/
ul, ol {
margin-left: $spacing-unit;
}
li {
> ul,
> ol {
margin-bottom: 0;
}
}
/**
* Headings
*/
h1, h2, h3, h4, h5, h6 {
font-weight: 300;
}
/**
* Links
*/
a {
color: $brand-color;
text-decoration: none;
&:visited {
color: darken($brand-color, 15%);
}
&:hover {
color: $text-color;
text-decoration: underline;
}
}
/**
* Blockquotes
*/
blockquote {
color: $grey-colour;
border-left: 4px solid $grey-colour-light;
padding-left: $spacing-unit / 2;
font-size: 18px;
letter-spacing: -1px;
font-style: italic;
> :last-child {
margin-bottom: 0;
}
}
/**
* Code formatting
*/
pre,
code {
font-size: 15px;
border: 1px solid $grey-colour-light;
border-radius: 3px;
background-color: #eef;
}
code {
padding: 1px 5px;
}
pre {
padding: 8px 12px;
overflow-x: scroll;
> code {
border: 0;
padding-right: 0;
padding-left: 0;
}
}
/**
* Wrapper
*/
.wrapper {
// don't use calc(), doesn't seem to work in minified CSS.
max-width: 800px - ($spacing-unit * 2);
margin-right: auto;
margin-left: auto;
padding-right: $spacing-unit;
padding-left: $spacing-unit;
@extend %clearfix;
@include media-query($on-laptop) {
max-width: 800px - $spacing-unit;
padding-right: $spacing-unit / 2;
padding-left: $spacing-unit / 2;
}
}
/**
* Clearfix
*/
%clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
/**
* Text styling
*/
strong, b {
font-weight: bold;
}

View File

@ -0,0 +1,6 @@
.btn-primary {
background-color: rgb(66, 139, 202);
border-color: rgb(53, 126, 189);
color: rgb(255, 255, 255);
}

View File

@ -0,0 +1,12 @@
.pitch {
font-size: 46px;
font-style: italic;
line-height: 1.25;
margin-bottom: 40px;
margin-top: 36px;
}
.subtext {
}

View File

@ -0,0 +1,135 @@
/**
* Site header
*/
.site-header {
border-top: 5px solid $grey-colour-dark;
border-bottom: 1px solid $grey-colour-light;
min-height: 56px;
// Positioning context for the mobile navigation icon
position: relative;
}
.site-title {
font-size: 36px;
font-weight: bold;
line-height: 64px;
letter-spacing: -1px;
margin-bottom: 0;
&,
&:visited {
color: $grey-colour-dark;
}
}
/**
* Site footer
*/
body > footer {
border-top: 1px solid $grey-colour-light;
padding: $spacing-unit 0;
margin-top: $spacing-unit;
}
/**
* Post list
*/
.past-issues {
margin-top: 20px;
li.nav-header h2 {
border-bottom: 1px solid $grey-colour-light;
}
li {
line-height: 1.8;
}
}
.time-prefix {
font-family: "Fira Mono", monospace;
}
.post-title {
font-size: 20px;
}
/**
* Page content
*/
.page-content {
padding-top: $spacing-unit;
}
.page-heading {
font-size: 20px;
}
.post-list {
margin-left: 0;
list-style: none;
> li {
margin-bottom: $spacing-unit;
}
}
.post-meta {
font-size: $small-font-size;
color: $grey-colour;
}
.post-link {
display: block;
font-size: 24px;
}
/**
* Posts
*/
.post {
margin-top: 32px;
border: 1px solid $grey-colour-light;
padding: 24px;
border-radius: 8px;
}
.post-header {
margin-bottom: $spacing-unit;
}
.post-content {
margin-bottom: $spacing-unit;
h2 {
font-size: 32px;
@include media-query($on-laptop) {
font-size: 28px;
}
}
h3 {
font-size: 26px;
@include media-query($on-laptop) {
font-size: 22px;
}
}
h4 {
font-size: 20px;
@include media-query($on-laptop) {
font-size: 18px;
}
}
}

View File

@ -0,0 +1,46 @@
@charset "utf-8";
// Our variables
$base-font-family: 'Fira Sans', "Helvetica Neue", Helvetica, Arial, sans-serif;
$base-font-size: 16px;
$small-font-size: $base-font-size * 0.875;
$base-line-height: 1.5;
$spacing-unit: 30px;
$text-color: #444;
$background-color: #fdfdfd;
$brand-color: #2a7ae2;
$grey-colour: #828282;
$grey-colour-light: lighten($grey-colour, 40%);
$grey-colour-dark: darken($grey-colour, 25%);
$on-palm: 600px;
$on-laptop: 800px;
// Using media queries with like this:
// @include media-query($palm) {
// .wrapper {
// padding-right: $spacing-unit / 2;
// padding-left: $spacing-unit / 2;
// }
// }
@mixin media-query($device) {
@media screen and (max-width: $device) {
@content;
}
}
// Import partials
@import
"bootstrap-overrides",
"base",
"layout",
"homepage"
;

View File

@ -0,0 +1,10 @@
<div class="row post-title">
<div class="col-xs-4 col-md-4">
<span class="small text-muted time-prefix">
<time pubdate="pubdate" datetime="{{ article.date.isoformat() }}">{{ article.date.strftime("%d %b %Y").upper() }}</time>
</span>
</div>
<div class="col-xs-8 col-md-8 text-right">
<a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a>
</div>
</div>

View File

@ -0,0 +1,13 @@
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<div class="input-group input-group-lg">
<input type="email" class="form-control" placeholder="Enter your email" />
<span class="input-group-btn">
<input type="commit" class="btn btn-default btn-primary" value="Subscribe!" />
</span>
</div>
<span class="help-block small text-muted">Receive a weekly newsletter, every Monday. Easy to unsubscribe and no spam, promise.</span>
</div>
<div class="col-md-1"></div>
</div>

View File

@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="col-md-12">
<ul class="list-unstyled past-issues">
<li class="nav-header disabled"><h2>Past issues</h2></li>
{% for article in articles %}
<li>
{% include "_post-title.html" %}
</li>
{% endfor %}
</ul>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,37 @@
{% extends "base.html" %}
{% block title %}
{{ article.title }} {%if article.subtitle %} - {{ article.subtitle }} {% endif %} · {{ super() }}
{% endblock title %}
{% block head_description %}
{% if article.summary %}
{{ article.summary|striptags }}
{% endif %}
{% endblock head_description %}
{% block meta_tags_in_head %}
{% if article.tags or article.category or article.keywords %}
<meta name="keywords" content="{{ [article.tags|join(', '), article.category, article.keywords]|join(', ') }}" />
{% endif %}
{% endblock meta_tags_in_head %}
{% block content %}
<div class="row text-center">
<h3> Like what you see? Subscribe! </h3>
</div>
{% include "_subscribe-form.html" %}
<div class="post">
<header class="post-header">
{% include "_post-title.html" %}
</header>
<article class="post-content">
{{ article.content }}
</article>
</div>
{% endblock content %}

View File

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
{% if article and article.author %}
<meta name="author" content="{{ article.author }}" />
<meta name="copyright" content="{{ article.author }}" />
{% elif page and page.author %}
<meta name="author" content="{{ page.author }}" />
<meta name="copyright" content="{{ page.author }}" />
{% else %}
<meta name="author" content="{{ AUTHOR }}" />
<meta name="copyright" content="{{ AUTHOR }}" />
{% endif %}
{% if SITE_DESCRIPTION %}
<meta name="description" content="{% block head_description %}{{ SITE_DESCRIPTION }}{% endblock head_description %}" />
{% endif %}
{% block meta_tags_in_head %}
{% endblock meta_tags_in_head %}
<title>{% block title %}{{ SITENAME|striptags }}{% endblock title %}</title>
{% block head_links %}
{% endblock head_links %}
<link href="{{ FEED_DOMAIN }}/{{ FEED_ALL_ATOM }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME|striptags }} - Full Atom Feed" />
<link href='https://fonts.googleapis.com/css?family=Fira+Sans:400,400italic,500,500italic|Fira+Mono:400' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
{% assets filters="scss,cssmin", output="css/web-min.css", "css/main.scss" %}
<link rel="stylesheet" href="/{{ ASSET_URL }}">
{% endassets %}
</head>
<body>
<header class="site-header">
<div class="container wrapper">
<a class="site-title" href="{{ SITEURL }}/">{{ SITENAME }}</a>
</div>
</header>
<div class="page-content">
<div class="container wrapper">
{% block content %}
{% endblock content %}
</div>
</div>
<footer>
<div class="container wrapper">
<div class="row">
<div class="col-md-6">
<ul class="list-unstyled">
<li><a href="{{ SITEURL }}/blog/archives/index.html">past issues</a></li>
<li><a href="{{ SITEURL }}/{{ FEED_ALL_ATOM }}">atom feed</a></li>
<li><a href="{{ SOURCE_URL }}">source code</a></li>
</ul>
</div>
<div class="col-md-6 text-right">
<ul class="list-unstyled">
<li>
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
<img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" />
</a>
</li>
</ul>
</div>
</div>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,31 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="col-md-12 text-center">
<h1 class="pitch">Handpicked Rust updates, <br /> delivered to your inbox.</h1>
<p class="subtext">Stay up to date with events, learning resources, and recent developments in Rust community.</p>
</div>
</div>
{% include "_subscribe-form.html" %}
<div class="row">
<div class="col-md-12">
<ul class="list-unstyled past-issues">
<li class="nav-header disabled"><h2>Past issues</h2></li>
{% for article in articles %}
{% if not RECENT_ARTICLES_COUNT %}
{% set RECENT_ARTICLES_COUNT = 5 %}
{% endif %}
{% if loop.index0 < RECENT_ARTICLES_COUNT %}
<li>
{% include "_post-title.html" %}
</li>
{% endif %}
{% endfor %}
<li class="text-right">
<a href="{{ SITEURL }}/blog/archives/index.html">View more &rarr;</a>
</li>
</ul>
</div>
</div>
{% endblock content %}