Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
projectpages: bootstrap4 compatibility (for v8)
Signed-off-by: Chris Warrick <kwpolska@gmail.com>
  • Loading branch information
Kwpolska committed Apr 22, 2018
1 parent dec75f6 commit d38c08a
Show file tree
Hide file tree
Showing 14 changed files with 625 additions and 4 deletions.
2 changes: 1 addition & 1 deletion v7/projectpages/projectpages.plugin
Expand Up @@ -8,6 +8,6 @@ MinVersion = 7.1.0+

[Documentation]
Author = Chris Warrick
Version = 0.1.11
Version = 0.1.12
Website = https://chriswarrick.com/projects/
Description = Generate project pages
2 changes: 1 addition & 1 deletion v7/projectpages/projectpages.py
Expand Up @@ -90,7 +90,7 @@ def generate_json(self, jdst, lang):
data[p.meta[lang]['slug']]['permalink'] = p.permalink(lang)
data[p.meta[lang]['slug']]['text'] = p.text(lang)
with open(jdst, 'w') as fh:
json.dump(data, fh, sort_keys=True)
json.dump(data, fh, sort_keys=True, indent=4, separators=(',', ': '))

def gen_tasks(self):
"""Render project list."""
Expand Down
1 change: 0 additions & 1 deletion v7/projectpages/templates/jinja/project.tmpl
@@ -1,7 +1,6 @@
{# -*- coding: utf-8 -*- #}
{% extends 'story.tmpl' %}
{% import 'project_helper.tmpl' as project with context %}
{% import 'crumbs.tmpl' as crumbs with context %}
{% block content %}
<header class="page-header">
<h1>{{ title }}</h1>
Expand Down
1 change: 0 additions & 1 deletion v7/projectpages/templates/mako/project.tmpl
@@ -1,7 +1,6 @@
## -*- coding: utf-8 -*-
<%inherit file="story.tmpl"/>
<%namespace name="project" file="project_helper.tmpl"/>
<%namespace name="crumbs" file="crumbs.tmpl"/>
<%block name="content">
<header class="page-header">
<h1>${title}</h1>
Expand Down
92 changes: 92 additions & 0 deletions v8/projectpages/README.md
@@ -0,0 +1,92 @@
Project Pages plugin for Nikola
===============================

This is a generator of project pages. It is based on meta fields in story
files.

**LIVE DEMO:** <https://chriswarrick.com/projects/>

**SOURCE FILES FOR THE ABOVE:** <https://github.com/Kwpolska/chriswarrick.com/tree/master/projects>

Why use a plugin?
-----------------

1. So someone can do the thinking for you.
2. So you can just create standardized files and have pretty subpages and
indexes generated for you.
3. So many things are automated for you.

Usage
-----

1. `projects` directory is the default directory for projects. You can change
this by setting `PROJECT_PATH` to a different value:

PROJECT_PATH = 'projects'

2. Create an entry in `PAGES` for your project directory, eg.

("projects/*.rst", "projects", "project.tmpl")

3. Create project pages in reStructuredText (or any other supported markup language).
4. Optionally create your own templates (some are provided with the plugin).
The default templates include `project.tmpl`, `project_helper.tmpl` and
`projects.tmpl`.

The default templates assume you use Bootstrap 3 and [**Font
Awesome**](http://fortawesome.github.io/Font-Awesome) (which is **not**
included in the default Nikola themes). You can alter the templates to use
glyphicons if you want.

The plugin generates two files in each language:

* projects/index.html (or whatever `PROJECT_PATH` and `INDEX_FILE` are) — a HTML
page with a slider and list of projects, from template `projects.tmpl`
* projects/projects.json — a JSON file, dict of `{slug: all meta data}`

Project subpage generation is handled by Nikola’s built-in stories framework.

Meta fields
-----------

* **title** — the project name in a human friendly form
* **description** — tagline or short project description
* **previewimage** — promotional graphics (used in slider and social networks)
* **logo** — project logo (used on the right side of the project page)
* **status** (str/int) — Development Status. Use your own phrasing, or the
following numbers to get nice formatting:

1. Planning
2. Pre-Alpha
3. Alpha
4. Beta
5. Production/Stable
6. Mature
7. Inactive
* **sort** — sorting key, used for determining order. Defaults to 1, larger numbers
first. Falls back to alphabetical sorting by title descending. *Negative
numbers not allowed.*
* **link** — link to the project website
* **download** — main download link (eg. PyPI page)
* **github** — GitHub link
* **bitbucket** — BitBucket link
* **bugtracker** — bug tracker link
* **gallery** — screenshot gallery link
* **language** — programming language
* **license** — name of the license under which the project
* **role** — your role in the project. Free-form, sample values include
*Contributor* and *Maintainer*
* **featured** (bool) — show in the slider
* **hidden** (bool) — don’t show under “all projects” (can still be in slider though)
* Also: the **post text** is a full description of the project. You can put a
README here. (Bonus points for using a .meta file for the metadata and a
symlink to the actual README as the post, assuming you have good READMEs)

**title**, **description**, **status** are required. **previewimage** is needed if
**featured** is set. **date** and **tags** are ignored and not included in the
JSON file.

Any other fields are not used by default — however, you can modify templates
and include them. (Or, if you believe they will really useful to the general
public, request addition in the plugins repo. The author of this plugin wasn’t
very creative when coming up with the list.)
4 changes: 4 additions & 0 deletions v8/projectpages/conf.py.sample
@@ -0,0 +1,4 @@
PAGES = (
("projects/*.rst", "projects", "project.tmpl"),
)
PROJECT_PATH = 'projects'
13 changes: 13 additions & 0 deletions v8/projectpages/projectpages.plugin
@@ -0,0 +1,13 @@
[Core]
Name = projectpages
Module = projectpages

[Nikola]
PluginCategory = Task
MinVersion = 8.0.0

[Documentation]
Author = Chris Warrick
Version = 0.1.12
Website = https://chriswarrick.com/projects/
Description = Generate project pages
190 changes: 190 additions & 0 deletions v8/projectpages/projectpages.py
@@ -0,0 +1,190 @@
# -*- coding: utf-8 -*-

# Copyright © 2014–2016, Chris Warrick.

# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import unicode_literals
import os
import json

from nikola.plugin_categories import Task
from nikola import utils


class ProjectPages(Task):
"""Render project indexes."""

name = 'projectpages'
dates = {}
conf_project_path = 'projects'

def set_site(self, site):
"""Set Nikola site."""
site.register_path_handler('project', self.project_path)
self.conf_project_path = site.config.get('PROJECT_PATH', 'projects')
site._GLOBAL_CONTEXT['project_path'] = self.conf_project_path
site._GLOBAL_CONTEXT['project_index'] = {}
for lang, tpath in site.config['TRANSLATIONS'].items():
site._GLOBAL_CONTEXT['project_index'][lang] = '/' + os.path.join(tpath, self.conf_project_path, site.config['INDEX_FILE']).replace('\\', '/')

# If you want to use breadcrumbs as provided by the crumbs template:

# def project_breadcrumbs(p, lang, translations, project_path):
# return (('/' + os.path.join(translations[lang], project_path, 'index.html').replace('\\', '/'), "Projects"), (p.permalink(), p.title()))
# site._GLOBAL_CONTEXT['project_breadcrumbs'] = project_breadcrumbs

return super(ProjectPages, self).set_site(site)

def project_path(self, name, lang):
"""Generate links to project pages."""
return [_f for _f in self.projects[name].permalink(lang).split('/') if _f]

def is_project(self, p):
"""Test projecthood of a page."""
return p.destination_path(lang=self.kw['default_lang']).startswith(self.conf_project_path)

def find_projects(self):
"""Find all projects."""
self._projects = [p for p in self.site.timeline if self.is_project(p)]

@property
def projects(self):
"""Look for projects if we haven’t already."""
try:
return self._projects
except AttributeError:
self.find_projects()
return self._projects

def generate_json(self, jdst, lang):
"""Generate a JSON file with all project data."""
data = {}
for p in self.projects:
data[p.meta[lang]['slug']] = p.meta[lang]
del data[p.meta[lang]['slug']]['date']
if 'tags' in data[p.meta[lang]['slug']]:
del data[p.meta[lang]['slug']]['tags']
if 'hyphenate' in data[p.meta[lang]['slug']]:
del data[p.meta[lang]['slug']]['hyphenate']
data[p.meta[lang]['slug']]['permalink'] = p.permalink(lang)
data[p.meta[lang]['slug']]['text'] = p.text(lang)
with open(jdst, 'w') as fh:
json.dump(data, fh, sort_keys=True, indent=4, separators=(',', ': '))

def gen_tasks(self):
"""Render project list."""

self.image_ext_list = ['.jpg', '.png', '.jpeg', '.gif', '.svg', '.bmp', '.tiff']
self.image_ext_list.extend(self.site.config.get('EXTRA_IMAGE_EXTENSIONS', []))

self.kw = {
'project_path': self.conf_project_path,
'index_file': self.site.config['INDEX_FILE'],
'strip_indexes': self.site.config['STRIP_INDEXES'],
'output_folder': self.site.config['OUTPUT_FOLDER'],
'cache_folder': self.site.config['CACHE_FOLDER'],
'default_lang': self.site.config['DEFAULT_LANG'],
'filters': self.site.config['FILTERS'],
'translations': self.site.config['TRANSLATIONS'],
'global_context': self.site.GLOBAL_CONTEXT,
'tzinfo': self.site.tzinfo,
}

for k, v in self.site.GLOBAL_CONTEXT['template_hooks'].items():
self.kw['||template_hooks|{0}||'.format(k)] = v._items

yield self.group_task()

template_name = "projects.tmpl"

self.site.scan_posts()
self.find_projects()

# Create index.html for each language
for lang in self.kw['translations']:
# save navigation links as dependencies
self.kw['navigation_links|{0}'.format(lang)] = self.kw['global_context']['navigation_links'](lang)

short_tdst = os.path.join(self.kw['translations'][lang], self.kw['project_path'], self.kw['index_file'])
short_jdst = os.path.join(self.kw['translations'][lang], self.kw['project_path'], 'projects.json')
tdst = os.path.normpath(os.path.join(self.kw['output_folder'], short_tdst))
jdst = os.path.normpath(os.path.join(self.kw['output_folder'], short_jdst))

context = {}
context["lang"] = lang

# TODO: tranlsations?
context["title"] = "Projects"
context["description"] = None

def sortf(p):
return ((-int(p.meta('sort')) if p.meta('sort') != '' else -1), p.title())

context["featured"] = sorted((p for p in self.projects if p.meta('featured') not in ('False', '0', 'false', 'no', '')), key=sortf)
context["projects"] = sorted((p for p in self.projects if p.meta('hidden') not in ('False', '0', 'false', 'no')), key=sortf)

link = short_tdst.replace('\\', '/')
index_len = len(self.kw['index_file'])
if self.kw['strip_indexes'] and link[-(1 + index_len):] == '/' + self.kw['index_file']:
link = link[:-index_len]
context["permalink"] = '/' + link

context["pagekind"] = ['projectpages']

all_meta = [(p.title(), p.meta('status')) for p in self.projects]
all_meta += [p.meta('previewimage') for p in context["featured"]]
all_meta += [p.source_path for p in context["featured"]]

template_dep = self.site.template_system.template_deps(template_name)
file_dep = []

for p in self.projects:
file_dep += [p.translated_base_path(l) for l in self.kw['translations'] if l in p.translated_to]

yield utils.apply_filters({
'basename': self.name,
'name': tdst,
'file_dep': file_dep + template_dep,
'targets': [tdst],
'actions': [
(self.site.render_template, (template_name, tdst, context))],
'clean': True,
'uptodate': [utils.config_changed({
1: self.kw,
2: all_meta,
}, 'projectpages:html:' + tdst)],
}, self.kw['filters'])

yield utils.apply_filters({
'basename': self.name,
'name': jdst,
'file_dep': file_dep,
'targets': [jdst],
'actions': [(self.generate_json, (jdst, lang))],
'clean': True,
'uptodate': [utils.config_changed({
1: self.kw,
2: all_meta,
}, 'projectpages:json:' + jdst)],
}, self.kw['filters'])

0 comments on commit d38c08a

Please sign in to comment.