Merge pull request #4 from RealOrangeOne/pelican-refresh
Pelican refresh
This commit is contained in:
commit
b4c50c26e7
48 changed files with 506 additions and 407 deletions
2
.buildpacks
Normal file
2
.buildpacks
Normal file
|
@ -0,0 +1,2 @@
|
|||
https://github.com/heroku/heroku-buildpack-nodejs
|
||||
https://github.com/heroku/heroku-buildpack-python
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"extends": "./node_modules/eslint-config/.eslintrc",
|
||||
"extends": "eslint-config-dabapps/base/.eslintrc",
|
||||
"globals": {
|
||||
$: true
|
||||
"$": true
|
||||
}
|
||||
}
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -60,7 +60,5 @@ target/
|
|||
# Pelican stuff
|
||||
output/
|
||||
theme/static/build/
|
||||
pelican_plugins/
|
||||
|
||||
theme/static/src/scss/pygment.css
|
||||
deploy/
|
||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "pelican_plugins"]
|
||||
path = pelican_plugins
|
||||
url = https://github.com/getpelican/pelican-plugins
|
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
|||
5.10.1
|
||||
6.9.4
|
||||
|
|
|
@ -56,6 +56,7 @@ rules:
|
|||
force-pseudo-nesting: 0
|
||||
force-element-nesting: 0
|
||||
placeholder-in-extend: 0
|
||||
no-url-domains: 0
|
||||
nesting-depth:
|
||||
- 2
|
||||
-
|
||||
|
|
80
Makefile
80
Makefile
|
@ -1,80 +0,0 @@
|
|||
BASEDIR=$(PWD)
|
||||
ENV=$(BASEDIR)/env/bin
|
||||
NODE_BIN=node_modules/.bin
|
||||
PELICAN=$(ENV)/pelican
|
||||
|
||||
OUTPUTDIR=$(BASEDIR)/output
|
||||
PLUGINS_DIR=$(BASEDIR)/pelican_plugins
|
||||
DEPLOY_DIR=$(BASEDIR)/deploy
|
||||
CONFIG_FILE=$(BASEDIR)/config/pelicanconf.py
|
||||
|
||||
FLAKE8_IGNORE=--ignore=E128,E501,E401,E402
|
||||
|
||||
build: install
|
||||
rm -rf $(OUTPUTDIR)/*
|
||||
@echo ">> Building static data..."
|
||||
mkdir -p theme/static/build/js/lib theme/static/build/fonts theme/static/build/css theme/static/build/img
|
||||
cp -R node_modules/font-awesome/fonts theme/static/build/
|
||||
npm run build-js
|
||||
npm run build-scss
|
||||
@echo ">> Building pelican..."
|
||||
$(PELICAN) -o $(OUTPUTDIR) -vs $(CONFIG_FILE)
|
||||
mv $(OUTPUTDIR)/assets/robots.txt $(OUTPUTDIR)
|
||||
cp -R $(OUTPUTDIR)/assets/* $(OUTPUTDIR)/static
|
||||
rm -rf $(OUTPUTDIR)/assets
|
||||
|
||||
clean:
|
||||
rm -rf $(OUTPUTDIR)/*
|
||||
rm -rf $(BASEDIR)/env/
|
||||
rm -rf $(BASEDIR)/node_modules/
|
||||
rm -rf $(PLUGINS_DIR)/*
|
||||
|
||||
|
||||
install: env node_modules pelican_plugins
|
||||
|
||||
pelican_plugins: env
|
||||
rm -rf $(PLUGINS_DIR) || "No existing extensions"
|
||||
git clone --recursive https://github.com/getpelican/pelican-plugins $(PLUGINS_DIR) || "Git Fail"
|
||||
@echo ">> Hotfixing..."
|
||||
rm -rf $(PLUGINS_DIR)/pelican-jinja2content
|
||||
git clone https://github.com/RealOrangeOne/pelican-jinja2content -b patch-1 --depth=1 $(PLUGINS_DIR)/pelican-jinja2content
|
||||
|
||||
env:
|
||||
pyvenv env
|
||||
$(ENV)/pip install -r requirements.txt --upgrade
|
||||
|
||||
node_modules:
|
||||
npm install
|
||||
|
||||
|
||||
test: unittest lint spellcheck securitycheck
|
||||
|
||||
unittest:
|
||||
$(ENV)/nose2 --verbose
|
||||
|
||||
lint:
|
||||
$(NODE_BIN)/eslint 'theme/static/src/js/'
|
||||
$(NODE_BIN)/sass-lint -vqc .sass-lint.yml
|
||||
$(ENV)/flake8 $(BASEDIR)/plugins/ $(FLAKE8_IGNORE)
|
||||
$(ENV)/flake8 $(BASEDIR)/scripts/ $(FLAKE8_IGNORE)
|
||||
$(ENV)/flake8 $(BASEDIR)/config/ $(FLAKE8_IGNORE)
|
||||
$(ENV)/flake8 $(BASEDIR)/tests/ $(FLAKE8_IGNORE)
|
||||
$(ENV)/yamllint config/config.yml
|
||||
|
||||
spellcheck:
|
||||
$(NODE_BIN)/mdspell --en-gb -ranx theme/templates/**/*.* theme/templates/*.*
|
||||
$(NODE_BIN)/mdspell --en-gb -ranx content/**/*.md content/*.md content/**/*.html content/*.html
|
||||
|
||||
securitycheck:
|
||||
$(NODE_BIN)/nsp check
|
||||
$(ENV)/bandit -r plugins/ config/ tests/
|
||||
|
||||
|
||||
upload:
|
||||
git clone https://github.com/RealOrangeOne/host-container.git $(DEPLOY_DIR)
|
||||
cp -rf $(OUTPUTDIR)/. $(DEPLOY_DIR)/site/
|
||||
@cd $(DEPLOY_DIR) && git remote add dokku $(DEPLOY_URL) && git add . && git commit -m "add files" && git push -f dokku master --quiet
|
||||
rm -rf $(DEPLOY_DIR)
|
||||
|
||||
|
||||
.PHONY: build clean test lint install upload
|
1
Procfile
Normal file
1
Procfile
Normal file
|
@ -0,0 +1 @@
|
|||
web: bash scripts/run-build-server.sh
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
[![Circle CI](https://circleci.com/gh/RealOrangeOne/theorangeone.net.svg?style=svg)](https://circleci.com/gh/RealOrangeOne/theorangeone.net)
|
||||
|
||||
Find it here: [https://theorangeone.net](http://theorangeone.net)
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
make
|
||||
./scripts/build
|
||||
```
|
||||
|
||||
## Run Tests
|
||||
```bash
|
||||
make test
|
||||
./scripts/test
|
||||
```
|
||||
|
|
22
circle.yml
22
circle.yml
|
@ -2,24 +2,22 @@ machine:
|
|||
python:
|
||||
version: 3.5.1
|
||||
node:
|
||||
version: 5.11.1
|
||||
version: 6.9.4
|
||||
environment:
|
||||
BUILD_PRODUCTION: true
|
||||
NODE_ENV: production
|
||||
NPM_CONFIG_PRODUCTION: false
|
||||
|
||||
checkout:
|
||||
post:
|
||||
- git submodule sync
|
||||
- git submodule update --init --recursive
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- make -B
|
||||
override:
|
||||
- scripts/build
|
||||
- pelican -v
|
||||
|
||||
test:
|
||||
override:
|
||||
- make test
|
||||
|
||||
deployment:
|
||||
production:
|
||||
branch: master
|
||||
commands:
|
||||
- git config --global user.email "git@theorangeone.net"
|
||||
- git config --global user.name "TheOrangeOne"
|
||||
- make upload
|
||||
- scripts/test
|
||||
|
|
|
@ -2,29 +2,12 @@ import yaml
|
|||
import os.path
|
||||
|
||||
|
||||
class DotDictionary(dict):
|
||||
def __getattr__(self, attr):
|
||||
value = self[attr]
|
||||
if type(value) == dict:
|
||||
value = DotDictionary(value)
|
||||
return value
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__
|
||||
settings_dir = os.path.dirname(__file__)
|
||||
|
||||
|
||||
class WrappedSettings:
|
||||
def __init__(self):
|
||||
self.settings_dir = os.path.join(os.path.dirname(__file__), 'config.yml')
|
||||
settings = open(self.settings_dir)
|
||||
self.settings = yaml.safe_load(settings)
|
||||
def get_config(filename):
|
||||
with open(os.path.join(settings_dir, '{}.yml'.format(filename))) as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def __getattr__(self, name):
|
||||
value = self.settings[name]
|
||||
if type(value) == dict:
|
||||
value = DotDictionary(value)
|
||||
return value
|
||||
|
||||
def __str__(self):
|
||||
return str(self.settings)
|
||||
|
||||
settings = WrappedSettings()
|
||||
social = get_config('social')
|
||||
|
|
|
@ -1,22 +1,4 @@
|
|||
---
|
||||
|
||||
author: Jake Howard
|
||||
site_name: TheOrangeOne
|
||||
url: https://theorangeone.net
|
||||
timezone: Europe/London
|
||||
language: en
|
||||
|
||||
pelican_plugins:
|
||||
- sitemap
|
||||
- filetime_from_git
|
||||
- pelican-jinja2content
|
||||
- metatags
|
||||
- autopages
|
||||
- screenfetch
|
||||
|
||||
sitemap_format: xml
|
||||
|
||||
|
||||
accounts:
|
||||
github:
|
||||
- GitHub
|
||||
|
@ -103,7 +85,3 @@ footer_accounts:
|
|||
- instagram
|
||||
- youtube
|
||||
- flickr
|
||||
|
||||
piwik:
|
||||
url: piwik.theorangeone.net
|
||||
site_id: 1
|
|
@ -1 +0,0 @@
|
|||
web: bash scripts/server.sh
|
35
package.json
35
package.json
|
@ -3,8 +3,9 @@
|
|||
"version": "4.0.0",
|
||||
"description": " Source code for TheOrangeOne.net",
|
||||
"scripts": {
|
||||
"build-js": "./scripts/build-js.sh",
|
||||
"build-scss": "./scripts/build-scss.sh"
|
||||
"postinstall": "npm run create-build-dirs",
|
||||
"create-build-dirs": "mkdir -p theme/static/build/js theme/static/build/fonts theme/static/build/css theme/static/build/img",
|
||||
"start": "tstatic output/"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -14,27 +15,23 @@
|
|||
"animate.css": "=3.5.2",
|
||||
"ansi_up": "=1.3.0",
|
||||
"bootstrap-sass": "=3.3.7",
|
||||
"font-awesome": "=4.6.3",
|
||||
"jquery": "=2.2.3",
|
||||
"jquery.easing": "=1.3.2",
|
||||
"font-awesome": "=4.7.0",
|
||||
"jquery": "=3.1.1",
|
||||
"pygments-css": "=1.0.0",
|
||||
"tstatic": "RealOrangeOne/tstatic",
|
||||
"underscore": "=1.8.3",
|
||||
"wow.js": "=1.2.0"
|
||||
"wow.js": "=1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "=6.5.0",
|
||||
"babel-preset-es2015": "=6.13.2",
|
||||
"babel-preset-react": "=6.11.1",
|
||||
"babelify": "=7.3.0",
|
||||
"browserify": "=13.1.0",
|
||||
"clean-css": "=3.4.20",
|
||||
"eslint": "=1.5.0",
|
||||
"eslint-config": "git://github.com/dabapps/eslint-config.git",
|
||||
"eslint-plugin-react": "=3.4.2",
|
||||
"autoprefixer": "=6.6.1",
|
||||
"browserify": "=13.3.0",
|
||||
"clean-css": "=3.4.23",
|
||||
"eslint-config": "dabapps/eslint-config.git#2.0.4",
|
||||
"markdown-spellcheck": "=0.11.0",
|
||||
"node-sass": "=3.8.0",
|
||||
"nsp": "=2.6.1",
|
||||
"node-sass": "=4.3.0",
|
||||
"nsp": "=2.6.2",
|
||||
"postcss-cli": "=2.6.0",
|
||||
"sass-lint": "=1.9.1",
|
||||
"uglify-js": "=2.7.3"
|
||||
"sass-lint": "=1.10.2",
|
||||
"uglify-js": "=2.7.5"
|
||||
}
|
||||
}
|
||||
|
|
1
pelican_plugins
Submodule
1
pelican_plugins
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 6cd5a608b45fdc21bb11ed1f72a151cdb71c1169
|
|
@ -1,23 +1,25 @@
|
|||
# -*- coding: utf-8 -*- #
|
||||
from __future__ import unicode_literals
|
||||
from git import Repo
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.realpath('./'))
|
||||
|
||||
from config import settings
|
||||
|
||||
# Global core settings
|
||||
AUTHOR = settings.author
|
||||
SITENAME = settings.site_name
|
||||
SITEURL = settings.url
|
||||
PATH = '../content'
|
||||
TIMEZONE = settings.timezone
|
||||
DEFAULT_LANG = settings.language
|
||||
AUTHOR = "Jake Howard"
|
||||
SITENAME = "TheOrangeOne"
|
||||
SITEURL = "https://theorangeone.net"
|
||||
PATH = 'content'
|
||||
TIMEZONE = "Europe/London"
|
||||
DEFAULT_LANG = "en"
|
||||
PAGE_PATHS = ["pages"]
|
||||
THEME = "../theme"
|
||||
THEME = "theme"
|
||||
THEME_STATIC_DIR = "static"
|
||||
THEME_STATIC_PATHS = ["static/build"]
|
||||
STATIC_PATHS = ["assets"]
|
||||
DEFAULT_DATE = 'fs'
|
||||
WITH_FUTURE_DATES = True
|
||||
LOAD_CONTENT_CACHE = False
|
||||
CACHE_CONTENT = False
|
||||
DELETE_OUTPUT_DIRECTORY = True
|
||||
|
||||
USE_FOLDER_AS_CATEGORY = True
|
||||
DEFAULT_PAGINATION = False
|
||||
|
@ -30,11 +32,13 @@ FOOTER_LINKS = links.footer()
|
|||
INDEX_PROJECTS = links.index_projects()
|
||||
|
||||
# Extra config
|
||||
REPO = Repo(search_parent_directories=True)
|
||||
BUILD_PRODUCTION = 'BUILD_PRODUCTION' in os.environ
|
||||
from plugins import image_resizer
|
||||
META_IMAGES = image_resizer.generate()
|
||||
PIWIK = settings.piwik
|
||||
PIWIK = {
|
||||
'url': 'piwik.theorangeone.net',
|
||||
'site_id': 1
|
||||
}
|
||||
|
||||
# Disable some pages
|
||||
TAG_URL = False
|
||||
|
@ -61,14 +65,22 @@ FEED_ATOM = 'feed.atom'
|
|||
FEED_DOMAIN = SITEURL
|
||||
|
||||
# Setup plugins
|
||||
PLUGIN_PATHS = ["../pelican_plugins", "../plugins"]
|
||||
PLUGINS = settings.pelican_plugins
|
||||
PLUGIN_PATHS = ["plugins", "pelican_plugins"]
|
||||
PLUGINS = [
|
||||
'sitemap',
|
||||
'pelican-jinja2content',
|
||||
'metatags',
|
||||
'autopages',
|
||||
'screenfetch',
|
||||
'post_build',
|
||||
'static_build'
|
||||
]
|
||||
|
||||
if BUILD_PRODUCTION:
|
||||
PLUGINS.append("minify") # only minify on production build
|
||||
|
||||
SITEMAP = {
|
||||
"format": settings.sitemap_format
|
||||
"format": 'xml'
|
||||
}
|
||||
CATEGORY_PAGE_PATH = "theme/templates/categories"
|
||||
MINIFY = {
|
||||
|
@ -81,14 +93,16 @@ MINIFY = {
|
|||
from fontawesome_markdown import FontAwesomeExtension
|
||||
from pyembed.markdown import PyEmbedMarkdown
|
||||
from mkdcomments import CommentsExtension
|
||||
MD_EXTENSIONS = [
|
||||
MARKDOWN = {
|
||||
'extensions': [
|
||||
FontAwesomeExtension(),
|
||||
PyEmbedMarkdown(),
|
||||
CommentsExtension(),
|
||||
'codehilite(css_class=highlight)',
|
||||
'extra'
|
||||
]
|
||||
|
||||
],
|
||||
"output_format": "html5"
|
||||
}
|
||||
# Setup jinja2 filters
|
||||
from plugins import filters
|
||||
JINJA_FILTERS = {
|
||||
|
@ -96,3 +110,12 @@ JINJA_FILTERS = {
|
|||
"category_find": filters.category_find,
|
||||
"limit": filters.limit
|
||||
}
|
||||
|
||||
JINJA_ENVIRONMENT = {
|
||||
'trim_blocks': True,
|
||||
'lstrip_blocks': True,
|
||||
'extensions': [
|
||||
'jinja2.ext.with_',
|
||||
'plugins.include_with.IncludeWith'
|
||||
]
|
||||
}
|
53
plugins/include_with.py
Normal file
53
plugins/include_with.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
# Jinja-IncludeWith
|
||||
|
||||
A Jinja2 preprocessor extension that let you update the `include`
|
||||
context like this:
|
||||
|
||||
{% include "something.html" with foo=bar %}
|
||||
{% include "something.html" with a=3, b=2+2, c='yes' %}
|
||||
|
||||
You **must** also include 'jinja2.ext.with_' in the extensions list.
|
||||
|
||||
:copyright: [Juan-Pablo Scaletti] (http://jpscaletti.com).
|
||||
:license: [MIT] (http://www.opensource.org/licenses/mit-license.php).
|
||||
|
||||
Copied from https://github.com/jpscaletti/jinja-includewith due to not pip-installable
|
||||
|
||||
"""
|
||||
import re
|
||||
|
||||
from jinja2.ext import Extension
|
||||
|
||||
|
||||
__version__ = '0.1'
|
||||
|
||||
rx = re.compile(r'\{\%\s*include\s+(?P<tmpl>[^\s]+)\s+with\s+(?P<context>.*?)\s*\%\}',
|
||||
re.IGNORECASE)
|
||||
|
||||
|
||||
class IncludeWith(Extension):
|
||||
|
||||
def preprocess(self, source, name, filename=None):
|
||||
lastpos = 0
|
||||
while 1:
|
||||
m = rx.search(source, lastpos)
|
||||
if not m:
|
||||
break
|
||||
|
||||
lastpos = m.end()
|
||||
d = m.groupdict()
|
||||
context = d['context'].strip()
|
||||
if context == 'context':
|
||||
continue
|
||||
|
||||
source = ''.join([
|
||||
source[:m.start()],
|
||||
'{% with ', context, ' %}',
|
||||
'{% include ', d['tmpl'].strip(), ' %}',
|
||||
'{% endwith %}',
|
||||
source[m.end():]
|
||||
])
|
||||
|
||||
return source
|
|
@ -1,6 +1,6 @@
|
|||
from collections import namedtuple
|
||||
from random import shuffle
|
||||
from config import settings, DotDictionary
|
||||
from config import social
|
||||
|
||||
|
||||
ProjectLink = namedtuple("ProjectLink", ["name", "url", "image"])
|
||||
|
@ -8,20 +8,20 @@ ProjectLink = namedtuple("ProjectLink", ["name", "url", "image"])
|
|||
|
||||
def accounts():
|
||||
links = {}
|
||||
for key, (site, user, url, icon) in settings.accounts.items():
|
||||
links[key] = DotDictionary({
|
||||
for key, (site, user, url, icon) in social['accounts'].items():
|
||||
links[key] = {
|
||||
'key': key,
|
||||
'site': site,
|
||||
'username': user,
|
||||
'url': url.format(user),
|
||||
'icon': icon
|
||||
})
|
||||
}
|
||||
return links
|
||||
|
||||
|
||||
def footer():
|
||||
all_accounts = accounts()
|
||||
return [all_accounts[account] for account in settings.footer_accounts]
|
||||
return [all_accounts[account] for account in social['footer_accounts']]
|
||||
|
||||
|
||||
def index_projects():
|
||||
|
|
|
@ -17,10 +17,10 @@ def html_to_raw(html):
|
|||
def get_twiter_tags(instance):
|
||||
return {
|
||||
"twitter:card": "summary_large_image",
|
||||
"twitter:site": instance.settings.get("ACCOUNTS")["twitter"].username,
|
||||
"twitter:site": instance.settings.get("ACCOUNTS")["twitter"]['username'],
|
||||
"twitter:title": instance.metadata.get("title", ""),
|
||||
"twitter:description": html_to_raw(instance.metadata.get("summary", "")),
|
||||
"twitter:creator": instance.settings.get("ACCOUNTS")["twitter"].username,
|
||||
"twitter:creator": instance.settings.get("ACCOUNTS")["twitter"]['username'],
|
||||
"twitter:image": instance.metadata.get("image", ""),
|
||||
"twitter:image:alt": html_to_raw(instance.metadata.get("summary", "")),
|
||||
"twitter:url": os.path.join(instance.settings.get("SITEURL", ""), instance.url)
|
||||
|
|
39
plugins/pelican-jinja2content.py
Normal file
39
plugins/pelican-jinja2content.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import os
|
||||
from pelican import signals, contents
|
||||
from jinja2 import Environment, ChoiceLoader, FileSystemLoader
|
||||
from config import social
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def execjinja2(instance):
|
||||
if type(instance) in (contents.Article, contents.Page):
|
||||
jinja2_env = Environment( # nosec
|
||||
loader=ChoiceLoader([
|
||||
FileSystemLoader(
|
||||
os.path.join(BASE_DIR, instance.settings['THEME'], 'templates')
|
||||
),
|
||||
FileSystemLoader(
|
||||
os.path.join(BASE_DIR, instance.settings['PATH'])
|
||||
)
|
||||
]),
|
||||
**instance.settings['JINJA_ENVIRONMENT'],
|
||||
)
|
||||
|
||||
jinja2_env.filters.update(instance.settings['JINJA_FILTERS'])
|
||||
|
||||
jinja2_template = jinja2_env.from_string(instance._content)
|
||||
|
||||
kwargs = instance._context
|
||||
if type(instance) is contents.Article:
|
||||
kwargs['article'] = instance
|
||||
elif type(instance) is contents.Page:
|
||||
kwargs['page'] = instance
|
||||
|
||||
kwargs['social'] = social
|
||||
|
||||
instance._content = jinja2_template.render(**kwargs)
|
||||
|
||||
|
||||
def register():
|
||||
signals.content_object_init.connect(execjinja2)
|
25
plugins/post_build.py
Normal file
25
plugins/post_build.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from pelican import signals
|
||||
import os
|
||||
from plugins.utils import run_command
|
||||
|
||||
|
||||
OUTPUT_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'output')
|
||||
|
||||
|
||||
def post_build(*args, **kwargs):
|
||||
run_command('Copying Robots.txt', [
|
||||
'mv', os.path.join(OUTPUT_PATH, 'assets', 'robots.txt'), OUTPUT_PATH
|
||||
])
|
||||
run_command('Copying Assets', [
|
||||
'cp', '-R', os.path.join(OUTPUT_PATH, 'assets', '*'), os.path.join(OUTPUT_PATH, 'static')
|
||||
], True)
|
||||
run_command('Remove Old Assets', [
|
||||
'rm', '-rf', os.path.join(OUTPUT_PATH, 'assets')
|
||||
])
|
||||
run_command('Remove Drafts', [
|
||||
'rm', '-rf', os.path.join(OUTPUT_PATH, 'drafts')
|
||||
])
|
||||
|
||||
|
||||
def register():
|
||||
signals.finalized.connect(post_build)
|
36
plugins/static_build.py
Normal file
36
plugins/static_build.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
from pelican import signals
|
||||
from plugins.utils import node_bin, run_command, NODE_PRODUCTION
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
|
||||
|
||||
def static_build(*args, **kwargs):
|
||||
if NODE_PRODUCTION:
|
||||
logger.info('Building Production...')
|
||||
UGLIFY_ARGS = ['--compress', '--screw-ie8', '--define', '--stats', '--keep-fnames']
|
||||
else:
|
||||
UGLIFY_ARGS = []
|
||||
run_command('Copying Fonts', ['cp', '-r', 'node_modules/font-awesome/fonts', 'theme/static/build/'])
|
||||
run_command('Building Bootstrap', [node_bin('uglifyjs'), 'node_modules/bootstrap-sass/assets/javascripts/bootstrap.js', UGLIFY_ARGS, '-o', 'theme/static/build/js/bootstrap.js'])
|
||||
run_command('Building jQuery', [node_bin('uglifyjs'), 'node_modules/jquery/dist/jquery.js', UGLIFY_ARGS, '-o', 'theme/static/build/js/jquery.js'])
|
||||
run_command('Building Application', [
|
||||
node_bin('browserify'),
|
||||
'theme/static/src/js/app.js',
|
||||
'-o', 'theme/static/build/js/app.js'
|
||||
])
|
||||
|
||||
logger.info('JS built!')
|
||||
|
||||
run_command('Building Styles', [node_bin('node-sass'), 'theme/static/src/scss/index.scss', 'theme/static/build/css/index.css', '--source-map-embed'])
|
||||
|
||||
logger.info('SCSS Built!')
|
||||
|
||||
if NODE_PRODUCTION:
|
||||
run_command('Compressing Application', [node_bin('uglifyjs'), 'theme/static/build/js/app.js', UGLIFY_ARGS, '-o', 'theme/static/build/js/app.js'])
|
||||
run_command('Prefixing Styles', [node_bin('postcss'), '-u', 'autoprefixer', '-o', 'theme/static/build/css/index.css', 'theme/static/build/css/index.css'])
|
||||
run_command('Compressing Styles', [node_bin('cleancss'), '-d', '--s0', '-o', 'theme/static/build/css/index.css', 'theme/static/build/css/index.css'])
|
||||
|
||||
|
||||
def register():
|
||||
signals.static_generator_init.connect(static_build)
|
31
plugins/utils.py
Normal file
31
plugins/utils.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
import subprocess # nosec
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
|
||||
|
||||
NODE_PRODUCTION = os.environ.get('NODE_ENV') == 'production'
|
||||
|
||||
|
||||
def flatten_list(array):
|
||||
res = []
|
||||
for el in array:
|
||||
if isinstance(el, (list, tuple)):
|
||||
res.extend(flatten_list(el))
|
||||
continue
|
||||
res.append(el)
|
||||
return res
|
||||
|
||||
|
||||
def run_command(detail, args, wrap=False):
|
||||
if wrap:
|
||||
run_command(detail, ['bash', '-c', ' '.join(flatten_list(args))])
|
||||
else:
|
||||
logger.info(detail + '...')
|
||||
subprocess.run(flatten_list(args), check=True)
|
||||
|
||||
|
||||
def node_bin(exec):
|
||||
return os.path.join('node_modules', '.bin', exec)
|
|
@ -1,16 +1,16 @@
|
|||
bandit==1.1.0
|
||||
flake8==3.0.4
|
||||
fontawesome_markdown==0.2.5
|
||||
bandit==1.4.0
|
||||
flake8==3.2.1
|
||||
fontawesome_markdown==0.2.6
|
||||
git+https://github.com/ryneeverett/python-markdown-comments.git
|
||||
gitpython==2.0.8
|
||||
gitpython==2.1.1
|
||||
iso8601==0.1.11
|
||||
markdown==2.6.7
|
||||
nose2==0.6.5
|
||||
pelican-minify==0.9
|
||||
pelican==3.6.3
|
||||
pelican==3.7.1
|
||||
pyembed-markdown==1.1.0
|
||||
pygments-style-github==0.4
|
||||
python-resize-image==1.1.3
|
||||
pyyaml==3.12
|
||||
sh==1.11
|
||||
yamllint==1.4.1
|
||||
safety==0.5.1
|
||||
sh==1.12.9
|
||||
yamllint==1.6.0
|
||||
|
|
1
runtime.txt
Normal file
1
runtime.txt
Normal file
|
@ -0,0 +1 @@
|
|||
python-3.5.1
|
18
scripts/build
Executable file
18
scripts/build
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$NVM_DIR" ]
|
||||
then
|
||||
NVM_DIR="$HOME/.nvm"
|
||||
fi
|
||||
|
||||
. $NVM_DIR/nvm.sh
|
||||
nvm install
|
||||
nvm use
|
||||
|
||||
set -e
|
||||
|
||||
pyvenv env
|
||||
|
||||
env/bin/pip install -r requirements.txt
|
||||
|
||||
npm install
|
|
@ -1,44 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$NODE_ENV" = "production" ]
|
||||
then
|
||||
echo ">>> WARNING: Building in Production Mode!"
|
||||
fi
|
||||
|
||||
mkdir -p theme/static/build/js/lib
|
||||
|
||||
if [ "$NODE_ENV" = "production" ]
|
||||
then
|
||||
echo ">> Compressing Libraries..."
|
||||
uglifyjs node_modules/bootstrap-sass/assets/javascripts/bootstrap.js --compress --screw-ie8 --define --stats --keep-fnames -o theme/static/build/js/lib/bootstrap.js
|
||||
uglifyjs theme/static/build/js/lib/* --compress --screw-ie8 --define --stats --keep-fnames -o theme/static/build/js/libs.js
|
||||
else
|
||||
echo ">> Building Libraries..."
|
||||
cp node_modules/bootstrap-sass/assets/javascripts/bootstrap.js theme/static/build/js/lib/bootstrap.js
|
||||
uglifyjs theme/static/build/js/lib/* --screw-ie8 --stats --keep-fnames -o theme/static/build/js/libs.js
|
||||
fi
|
||||
|
||||
rm -rf theme/static/build/js/lib
|
||||
|
||||
if [ "$NODE_ENV" = "production" ]
|
||||
then
|
||||
echo ">> Compressing jQuery..."
|
||||
uglifyjs node_modules/jquery/dist/jquery.js --compress --screw-ie8 --define --stats --keep-fnames -o theme/static/build/js/jquery.js
|
||||
else
|
||||
echo ">> Building jQuery..."
|
||||
cp node_modules/jquery/dist/jquery.js theme/static/build/js/jquery.js
|
||||
fi
|
||||
|
||||
|
||||
echo ">> Building Application JS..."
|
||||
browserify -t [ babelify --presets [ es2015 react ] ] theme/static/src/js/app.js -o theme/static/build/js/app.js
|
||||
|
||||
if [ "$NODE_ENV" = "production" ]
|
||||
then
|
||||
echo ">> Compressing Application..."
|
||||
uglifyjs theme/static/build/js/app.js --compress --screw-ie8 --define --stats --keep-fnames -o theme/static/build/js/app.js
|
||||
fi
|
||||
|
||||
echo "> JS Built!"
|
|
@ -1,23 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$NODE_ENV" = "production" ]
|
||||
then
|
||||
echo ">>> WARNING: Building in Production Mode!"
|
||||
fi
|
||||
|
||||
echo ">> Generating Pygments styles..."
|
||||
env/bin/pygmentize -S github -f html -a .highlight > theme/static/src/scss/pygment.css
|
||||
|
||||
echo ">> Building SCSS..."
|
||||
node-sass theme/static/src/scss/index.scss theme/static/build/css/index.css --source-map-embed
|
||||
|
||||
echo ">> Post-Processing..."
|
||||
postcss -u autoprefixer -o theme/static/build/css/index.css theme/static/build/css/index.css
|
||||
|
||||
if [ "$NODE_ENV" = "production" ]
|
||||
then
|
||||
echo ">> Compressing CSS..."
|
||||
cleancss -d --s0 -o theme/static/build/css/index.css theme/static/build/css/index.css
|
||||
fi
|
10
scripts/run-build-server.sh
Executable file
10
scripts/run-build-server.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#/usr/bin/env bash
|
||||
|
||||
# Make pelican build on startup
|
||||
|
||||
|
||||
echo "> Building Site"
|
||||
pelican -v
|
||||
|
||||
echo "Starting Server"
|
||||
npm start
|
|
@ -1,4 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
cd output/
|
||||
python3 -m pelican.server $PORT
|
36
scripts/test
Executable file
36
scripts/test
Executable file
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
export PATH=env/bin:${PATH}
|
||||
export PATH=node_modules/.bin:${PATH}
|
||||
|
||||
FLAKE8_IGNORE=--ignore=E128,E501,E401,E402
|
||||
|
||||
set -e
|
||||
|
||||
echo "> Running tests"
|
||||
|
||||
nose2
|
||||
|
||||
echo ">> Testing client-side"
|
||||
eslint 'theme/static/src/js/'
|
||||
sass-lint -vqc .sass-lint.yml
|
||||
|
||||
echo ">> Running flake8"
|
||||
flake8 plugins/ $FLAKE8_IGNORE
|
||||
flake8 config/ $FLAKE8_IGNORE
|
||||
flake8 tests/ $FLAKE8_IGNORE
|
||||
flake8 pelicanconf.py $FLAKE8_IGNORE
|
||||
|
||||
echo ">> Checking config"
|
||||
yamllint config/social.yml
|
||||
|
||||
echo ">> Running spellcheck"
|
||||
mdspell --en-gb -ranx theme/templates/**/*.* theme/templates/*.*
|
||||
mdspell --en-gb -ranx content/**/*.md content/*.md content/**/*.html content/*.html
|
||||
|
||||
echo ">> Running security check"
|
||||
nsp check
|
||||
safety check
|
||||
bandit -r plugins/ config/ tests/
|
||||
|
||||
echo "> Tests complete!"
|
|
@ -29,7 +29,7 @@ class TestCase(unittest.TestCase):
|
|||
client = TestClient()
|
||||
|
||||
def get_children(self, content):
|
||||
return str(list(content.children)[0])
|
||||
return str(list(content.children)[0]).strip()
|
||||
|
||||
def assertTitle(self, content, title):
|
||||
self.assertIn(title, content.title.string)
|
||||
|
@ -37,3 +37,6 @@ class TestCase(unittest.TestCase):
|
|||
def assertHeaderTitle(self, content, title):
|
||||
header_title = content.find('h1', class_="section-heading")
|
||||
self.assertIn(title, self.get_children(header_title))
|
||||
|
||||
def assertSamePath(self, p1, p2):
|
||||
self.assertEqual(self.client.build_path(p1), self.client.build_path(p2))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from tests import TestCase
|
||||
from config import settings, DotDictionary
|
||||
from bs4 import BeautifulSoup
|
||||
import pelicanconf as settings
|
||||
from config import social as social_settings
|
||||
from unittest import skipIf
|
||||
from os import environ
|
||||
|
||||
|
@ -16,22 +17,24 @@ class CorePagesTestCase(TestCase):
|
|||
|
||||
def test_has_sitemap(self):
|
||||
content = self.client.get('sitemap.xml')
|
||||
self.assertIn(settings.url, content)
|
||||
self.assertIn(settings.SITEURL, content)
|
||||
|
||||
def test_has_atom_feed(self):
|
||||
content = self.client.get('feed.atom')
|
||||
self.assertIn(settings.url, content)
|
||||
self.assertIn(settings.SITEURL, content)
|
||||
|
||||
def test_has_404_page(self):
|
||||
content = self.client.get('.404.html')
|
||||
self.assertTitle(content, '404')
|
||||
|
||||
|
||||
class CommonPagesTestCase(TestCase):
|
||||
def test_has_scripts(self):
|
||||
content = self.client.get('index.html')
|
||||
for script in content.find_all('script'):
|
||||
if script.attrs.get('id') == 'piwik':
|
||||
continue
|
||||
self.client.exists(script.attrs['src'])
|
||||
self.assertTrue(self.client.exists(script.attrs['src']))
|
||||
|
||||
def test_has_stylesheet(self):
|
||||
content = self.client.get('index.html')
|
||||
|
@ -49,9 +52,25 @@ class CorePagesTestCase(TestCase):
|
|||
content = self.client.get('index.html')
|
||||
footer = content.footer
|
||||
for link in footer.find('p', class_="social").find_all('a'):
|
||||
self.assertIn(link.attrs['alt'], settings.footer_accounts)
|
||||
self.assertIn(link.attrs['alt'], social_settings['footer_accounts'])
|
||||
self.assertIn("fa fa-", str(list(link.children)[0]))
|
||||
|
||||
def test_navbar_links(self):
|
||||
content = self.client.get('.404.html') # a page that isnt home
|
||||
links = content.find('ul', class_='navbar-nav').find_all('a')
|
||||
self.assertEqual(len(links), 5)
|
||||
for link in links:
|
||||
element = self.get_children(link)
|
||||
self.assertEqual(link.attrs['href'], '/{}/'.format(element.lower()))
|
||||
self.assertTrue(self.client.exists(link.attrs['href']))
|
||||
|
||||
def test_navbar_index_link(self):
|
||||
content = self.client.get('.404.html') # a page that isnt home
|
||||
link = content.find('a', class_='navbar-brand')
|
||||
self.assertTrue(self.client.exists(link.attrs['href']))
|
||||
self.assertSamePath(link.attrs['href'], '/')
|
||||
self.assertEqual(self.get_children(link), settings.SITENAME)
|
||||
|
||||
@skipIf(not environ.get('BUILD_PRODUCTION', False), 'Not building production')
|
||||
def test_has_analytics(self):
|
||||
content = self.client.get('index.html', False)
|
||||
|
@ -59,60 +78,10 @@ class CorePagesTestCase(TestCase):
|
|||
self.assertNotEqual(piwik_script_tag, None)
|
||||
piwik_script = self.get_children(piwik_script_tag)
|
||||
self.assertIn('piwik.js', piwik_script)
|
||||
self.assertIn(str(settings.piwik.site_id), piwik_script)
|
||||
self.assertIn(str(settings.PIWIK['site_id']), piwik_script)
|
||||
piwik_img = content.find('noscript', id='piwik').find('img')
|
||||
self.assertIn(settings.piwik.url, piwik_img.attrs['src'])
|
||||
self.assertIn(str(settings.piwik.site_id), piwik_img.attrs['src'])
|
||||
|
||||
|
||||
class DotDictionaryTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.test_dict = DotDictionary({
|
||||
'foo': 'bar',
|
||||
'bar': {
|
||||
'foo': 'bar'
|
||||
}
|
||||
})
|
||||
|
||||
def test_returns_value(self):
|
||||
self.assertEqual(self.test_dict.foo, 'bar')
|
||||
|
||||
def test_returns_self_on_dict(self):
|
||||
self.assertEqual(self.test_dict.bar, {
|
||||
'foo': 'bar'
|
||||
})
|
||||
self.assertIsInstance(self.test_dict.bar, DotDictionary)
|
||||
|
||||
def test_set(self):
|
||||
self.test_dict.baz = 'foo'
|
||||
self.assertEqual(self.test_dict, {
|
||||
'foo': 'bar',
|
||||
'baz': 'foo',
|
||||
'bar': {
|
||||
'foo': 'bar'
|
||||
}
|
||||
})
|
||||
|
||||
def test_delete(self):
|
||||
del self.test_dict.bar
|
||||
with self.assertRaises(KeyError):
|
||||
print(self.test_dict.bar)
|
||||
self.assertEqual(self.test_dict, {
|
||||
'foo': 'bar'
|
||||
})
|
||||
|
||||
|
||||
class WrappedSettingTestCase(TestCase):
|
||||
def test_has_data(self):
|
||||
self.assertIsInstance(settings.settings, dict)
|
||||
self.assertTrue(len(settings.settings))
|
||||
|
||||
def test_returns_values(self):
|
||||
self.assertEqual(settings.language, 'en')
|
||||
self.assertEqual(settings.timezone, 'Europe/London')
|
||||
|
||||
def test_returns_dict(self):
|
||||
self.assertIsInstance(settings.accounts, DotDictionary)
|
||||
self.assertIn(settings.PIWIK['url'], piwik_img.attrs['src'])
|
||||
self.assertIn(str(settings.PIWIK['site_id']), piwik_img.attrs['src'])
|
||||
|
||||
|
||||
class TestClientTestCase(TestCase):
|
||||
|
|
|
@ -1,12 +1,24 @@
|
|||
from tests import TestCase
|
||||
from config import settings
|
||||
from config import social as social_settings
|
||||
import os.path
|
||||
|
||||
|
||||
class HomepageTestCase(TestCase):
|
||||
def test_about_section(self):
|
||||
content = self.client.get('index.html')
|
||||
about = content.find('section', id='about')
|
||||
self.assertIsNotNone(about)
|
||||
about_content = about.find('p')
|
||||
self.assertNotEqual(self.get_children(about_content), '')
|
||||
about_link = about.find('a')
|
||||
self.assertTrue(self.client.exists(about_link.attrs['href']))
|
||||
|
||||
def test_blog_links(self):
|
||||
content = self.client.get('index.html')
|
||||
blogs = content.find('section', id='blog').find_all('div', class_="col-xs-12")
|
||||
blog = content.find('section', id='blog')
|
||||
blog_link = blog.find('a', class_='btn')
|
||||
self.assertTrue(self.client.exists(blog_link.attrs['href']))
|
||||
blogs = blog.find_all('div', class_="col-xs-12")
|
||||
self.assertTrue(len(blogs) <= 4)
|
||||
for post in blogs:
|
||||
url = os.path.join(post.find('a').attrs['href'], 'index.html')
|
||||
|
@ -19,6 +31,15 @@ class HomepageTestCase(TestCase):
|
|||
url = os.path.join(project.attrs['href'], 'index.html')
|
||||
self.assertTrue(self.client.exists(url))
|
||||
|
||||
def test_navbar(self):
|
||||
content = self.client.get('index.html')
|
||||
links = content.find('ul', class_='navbar-nav').find_all('a')
|
||||
self.assertEqual(len(links), 5)
|
||||
for link in links:
|
||||
self.assertIn('page-scroll', link.attrs['class'])
|
||||
element = self.get_children(link)
|
||||
self.assertEqual(link.attrs['href'], '#' + element.lower())
|
||||
|
||||
|
||||
class AboutPageTestCase(TestCase):
|
||||
def test_title(self):
|
||||
|
@ -44,7 +65,7 @@ class AboutPageTestCase(TestCase):
|
|||
self.assertEqual(len(tags), 1)
|
||||
tag = tags[0]
|
||||
self.assertEqual('medium', tag.attrs['data-theme'])
|
||||
self.assertEqual(settings.accounts.github[1], tag.attrs['data-github'])
|
||||
self.assertEqual(social_settings['accounts']['github'][1], tag.attrs['data-github'])
|
||||
|
||||
|
||||
class Page404TestCase(TestCase):
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import './creative';
|
||||
import ansi_up from 'ansi_up';
|
||||
'use strict';
|
||||
|
||||
require('./creative');
|
||||
var ansi_up = require('ansi_up');
|
||||
var consts = require('./consts');
|
||||
|
||||
|
||||
$('.image').each(function () { // setup div-image hybrids
|
||||
const ele = $(this);
|
||||
var ele = $(this);
|
||||
if (ele.data('image')) {
|
||||
ele.css('background-image', 'url(' + ele.data('image') + ')');
|
||||
} else {
|
||||
|
@ -12,6 +15,18 @@ $('.image').each(function () { // setup div-image hybrids
|
|||
});
|
||||
|
||||
$('.ansi-up').each(function () {
|
||||
const ele = $(this);
|
||||
var ele = $(this);
|
||||
ele.html(ansi_up.ansi_to_html(ele.html()));
|
||||
});
|
||||
|
||||
|
||||
$('.navbar-brand').bind('click', function (event) {
|
||||
if ($('html').scrollTop() > consts.NAVBAR_HEIGHT) {
|
||||
$('html, body').stop().animate({
|
||||
scrollTop: 0
|
||||
}, consts.SCROLL_SPEED);
|
||||
} else {
|
||||
window.location = '/';
|
||||
}
|
||||
event.preventDefault();
|
||||
});
|
||||
|
|
6
theme/static/src/js/consts.js
Normal file
6
theme/static/src/js/consts.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
NAVBAR_HEIGHT: $('#main-nav').height(),
|
||||
SCROLL_SPEED: 750
|
||||
};
|
|
@ -1,37 +0,0 @@
|
|||
/*!
|
||||
* Start Bootstrap - Creative Bootstrap Theme (http://startbootstrap.com)
|
||||
* Code licensed under the Apache License v2.0.
|
||||
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*/
|
||||
|
||||
// jQuery for page scrolling feature - requires jQuery Easing plugin
|
||||
$('a.page-scroll').bind('click', function(event) {
|
||||
const anchor = $(this);
|
||||
$('html, body').stop().animate(
|
||||
{
|
||||
scrollTop: ($(anchor.attr('href')).offset().top - 50)
|
||||
},
|
||||
1250,
|
||||
'easeInOutExpo'
|
||||
);
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Highlight the top nav as scrolling occurs
|
||||
$('body').scrollspy({
|
||||
target: '.navbar-fixed-top',
|
||||
offset: 51
|
||||
});
|
||||
|
||||
// Closes the Responsive Menu on Menu Item Click
|
||||
$('.navbar-collapse ul li a').click(function() {
|
||||
$('.navbar-toggle:visible').click();
|
||||
});
|
||||
|
||||
|
||||
// Offset for Main Navigation
|
||||
$('#main-nav').affix({
|
||||
offset: {
|
||||
top: 50
|
||||
}
|
||||
});
|
|
@ -1,6 +1,41 @@
|
|||
import 'jquery.easing';
|
||||
import './creative';
|
||||
'use strict';
|
||||
|
||||
import WOW from 'wow.js';
|
||||
var WOW = require('wow.js');
|
||||
var consts = require('../consts');
|
||||
|
||||
new WOW().init();
|
||||
|
||||
/*!
|
||||
* Start Bootstrap - Creative Bootstrap Theme (http://startbootstrap.com)
|
||||
* Code licensed under the Apache License v2.0.
|
||||
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
|
||||
* (Edited for theorangeone.net)
|
||||
*/
|
||||
|
||||
// jQuery for page scrolling feature
|
||||
$('a.page-scroll').bind('click', function(event) {
|
||||
$('html, body').stop().animate(
|
||||
{ scrollTop: $($(this).attr('href')).offset().top - consts.NAVBAR_HEIGHT },
|
||||
consts.SCROLL_SPEED
|
||||
);
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Highlight the top nav as scrolling occurs
|
||||
$('body').scrollspy({
|
||||
target: '.navbar-fixed-top',
|
||||
offset: consts.NAVBAR_HEIGHT + 1
|
||||
});
|
||||
|
||||
// Closes the Responsive Menu on Menu Item Click
|
||||
$('.navbar-collapse ul li a').click(function() {
|
||||
$('.navbar-toggle:visible').click();
|
||||
});
|
||||
|
||||
|
||||
// Offset for Main Navigation
|
||||
$('#main-nav').affix({
|
||||
offset: {
|
||||
top: consts.NAVBAR_HEIGHT * 1.5
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
/* @group Libraries */
|
||||
@import "node_modules/bootstrap-sass/assets/stylesheets/_bootstrap";
|
||||
@import "node_modules/animate.css/animate";
|
||||
@import "node_modules/pygments-css/github";
|
||||
|
||||
$fa-font-path: "../fonts";
|
||||
@import "node_modules/font-awesome/scss/font-awesome";
|
||||
|
@ -18,7 +19,6 @@ $fa-font-path: "../fonts";
|
|||
|
||||
/* @group Other Imports */
|
||||
@import "creative/creative";
|
||||
@import "pygment";
|
||||
@import "homepage";
|
||||
@import "footer";
|
||||
@import "library-overrides";
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'extras/header.html' with context %}
|
||||
{% include 'extras/header.html' with instance=article %}
|
||||
<section>
|
||||
<div class="container">
|
||||
{{ article.content }}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
{% include "extras/footer.html" %}
|
||||
|
||||
<script src="/static/js/jquery.js" type="text/javascript"></script>
|
||||
<script src="/static/js/libs.js" type="text/javascript"></script>
|
||||
<script src="/static/js/bootstrap.js" type="text/javascript"></script>
|
||||
<script src="/static/js/app.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'extras/header.html' with context %}
|
||||
{% include 'extras/header.html' with instance=article %}
|
||||
<section>
|
||||
<div class="container">
|
||||
<p class="text-right small">
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
---
|
||||
hide_from_nav: true
|
||||
---
|
||||
|
||||
|
||||
I've always had a keen interest with security and privacy. Whether it's protecting my personal information, or needlessly encrypting things, security is very important to me. With an interest in keeping things secure, comes an interest in breaking through others security.
|
||||
|
||||
Whenever I start using a new tool, or piece of software, I almost instantly go to the security settings and check out what it supports. The same goes for making the software, I've been known to spend a lot of extra time working on the security aspect more than actual features.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<section id="header" class="bg-primary image" data-image="{{ article.image }}">
|
||||
<section id="header" class="bg-primary image" data-image="{{ instance.image }}">
|
||||
<div class="container text-center text-uppercase">
|
||||
<h1 class="section-heading">{{ article.title }}</h1>
|
||||
<h1 class="section-heading">{{ instance.title }}</h1>
|
||||
<hr class="light">
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -8,15 +8,16 @@
|
|||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand page-scroll" href="/">
|
||||
TheOrangeOne
|
||||
{{ SITENAME }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="main-navbar">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/about/">About</a></li>
|
||||
<li><a href="/blog/">Blog</a></li>
|
||||
<li><a href="/projects/">Projects</a></li>
|
||||
<li><a href="/setup/">Setup</a></li>
|
||||
{% for category, articles in categories %}
|
||||
{% if not category.page.hide_from_nav %}
|
||||
<li><a href="/{{ category.url }}">{{ category.name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<section id="header" class="bg-primary image" data-image="{{ page.image }}">
|
||||
<div class="container text-center text-uppercase">
|
||||
<h1 class="section-heading">{{ page.title }}</h1>
|
||||
<hr class="light">
|
||||
</div>
|
||||
</section>
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
{% block content %}
|
||||
{% if not page.no_container %}
|
||||
{% include 'extras/page-header.html' with context %}
|
||||
{% include 'extras/header.html' with instance=page %}
|
||||
<section>
|
||||
<div class="container">
|
||||
{{ page.content }}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'extras/header.html' with context %}
|
||||
{% include 'extras/header.html' with instance=article %}
|
||||
<section>
|
||||
<div class="container">
|
||||
<p class="text-right small">
|
||||
|
@ -18,7 +18,9 @@
|
|||
{{ article.content }}
|
||||
</div>
|
||||
</section>
|
||||
<div class="container text-center">
|
||||
{% if article.download_link or article.repo %}
|
||||
<section class="text-center">
|
||||
<div class="container">
|
||||
<div class="btn-group">
|
||||
{% if article.download_link %}
|
||||
<a class="btn btn-primary btn-xl" href="{{ article.download_link }}">Download {{ article.title }}</a>
|
||||
|
@ -29,4 +31,6 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
Reference in a new issue