1
Fork 0

Merge pull request #1 from RealOrangeOne/v3

V3
This commit is contained in:
Jake Howard 2016-05-13 19:40:43 +01:00
commit f02ced64ff
133 changed files with 2043 additions and 6358 deletions

6
.eslintrc Normal file
View file

@ -0,0 +1,6 @@
{
"extends": "./node_modules/eslint-config/.eslintrc",
"globals": {
$: true
}
}

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
5.10.1

38
.spelling Normal file
View file

@ -0,0 +1,38 @@
# markdown-spellcheck spelling configuration file
# Format - lines beginning # are comments
# global dictionary is at the start, file overrides afterwards
# one word per line, to define a file override use ' - filename'
# where filename is relative to this configuration file
Django
SQLite
eg
MyWindowsHosting
nginx
backends
PyGame
easter
_Enabler
Hipchat
DabApps
JakeSidSmith
facepalm
notsureif
wat
premis
hipchat
plugin
firefox
Jetpack
Javascript
facebook
github
morse
wikipedia
iframe
querystring
javascript
jQuery
gists
Lenovo
Collyer's
til

22
LICENSE
View file

@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Jake Howard
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.

View file

@ -1 +1,3 @@
# My Website
[![Circle CI](https://circleci.com/gh/RealOrangeOne/theorangeone.net.svg?style=svg)](https://circleci.com/gh/RealOrangeOne/theorangeone.net)

21
build
View file

@ -1,11 +1,28 @@
#!/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-3.4 env
pyvenv env
env/bin/pip install -r requirements.txt --upgrade
scripts/get-private-data.sh
npm install
npm run build
npm run build $@
env/bin/python manage.py collectstatic --noinput
if [[ $BUILD_PRODUCTION ]]
then
echo ">> Running Migrations..."
env/bin/python manage.py migrate
fi

20
circle.yml Normal file
View file

@ -0,0 +1,20 @@
machine:
python:
version: 3.4.2
node:
version: 5.10.1
environment:
DEBUG: true
DATABASE_URL: sqlite://~/database.db
EMAIL_BACKEND: django.core.mail.backends.console.EmailBackend
BUILD_PRODUCTION: true
dependencies:
pre:
- ./build
cache_directories:
- env
test:
override:
- ./runtests

6
data/context.yml Normal file
View file

@ -0,0 +1,6 @@
links:
github: https://github.com/RealOrangeOne
twitter: https://twitter.com/RealOrangeOne
instagram: https://instagram.com/RealOrangeOne
youtube: https://www.youtube.com/user/TheOrangeOneOfficial
reddit: https://www.reddit.com/user/realorangeone

9
data/page_context.yml Normal file
View file

@ -0,0 +1,9 @@
index:
body_class: index
html_title: Homepage
projects/hipchat-emoticons-for-all:
header_image: https://hipchat-magnolia-cdn.atlassian.com/assets/img/hipchat/hipchat_og_image.jpg
projects/yoga-pal:
header_image: http://www.lenovo.com/images/OneWebImages/SubSeries/gallery/laptops/IdeaPad-Yoga-13-Convertible-Laptop-PC-Clementine-Orange-Closed-Cover-View-gallery-940x529.jpg

1
data/path_switch.yml Normal file
View file

@ -0,0 +1 @@
college/attack-on-blocks: projects/attack-on-blocks

View file

@ -1,3 +1,3 @@
DEBUG=false
DATABASE_URL=sqlite:///database.db
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
BUILD_PRODUCTION=true

View file

@ -1,3 +1,2 @@
DEBUG=true
DATABASE_URL=sqlite:///database.db
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend

View file

@ -1,43 +1,50 @@
{
"name": "TheOrangeOne-Site",
"version": "0.0.1",
"description": "TheOrangeOne.net site",
"main": "app.js",
"version": "3.0.0",
"description": " Source code for TheOrangeOne.net",
"scripts": {
"lint": "echo 'Nothing yet.';",
"build-js": "bash scripts/build-js.sh",
"create-build-dirs": "mkdir -p static/build/js static/build/fonts static/build/css static/build/img private",
"lint": "eslint 'static/src/js/'",
"build-js": "./scripts/build-js.sh",
"create-build-dirs": "mkdir -p static/build/js/lib static/build/fonts static/build/css static/build/img",
"build": "npm run create-build-dirs && npm run build-fonts && npm run build-images && npm run build-js && npm run build-less",
"build-less": "lessc --silent static/src/less/style.less static/build/css/style.css && cleancss -d --s0 -o static/build/css/style.css static/build/css/style.css",
"build-fonts": "cp -R node_modules/bootstrap/dist/fonts static/build/ && cp -R node_modules/ionicons-pre/fonts static/build/ ",
"build-less": "./scripts/build-less.sh",
"build-fonts": "cp -R node_modules/bootstrap/dist/fonts static/build/ && cp -R node_modules/ionicons/fonts static/build/ ",
"build-images": "cp -r static/src/img/* static/build/img/",
"watch-images": "watch 'npm run build-images' static/src/img/",
"watch-less": "watch 'npm run build-less' static/src/less/",
"watch": "npm run watch-less & npm run watch-images",
"clean": "rm -rf static/build collected-static/ node_modules/ env/ private"
"watch": "npm run watch-less",
"clean": "./scripts/clean.js",
"test": "npm run lint",
"spellcheck": "mdspell --en-gb -ranx \"templates/**/*.*\""
},
"repository": {
"type": "git",
"url": "https://github.com/RealOrangeOne/theorangeone.net"
},
"dependencies": {
"bootstrap": "^3.3.5",
"jquery": "^2.1.4",
"less": "^2.5.1",
"markdown": "^0.5.0",
"react": "^0.13.3",
"react-bootstrap": "^0.25.1",
"skrollr": "^0.6.26"
"animate.css": "=3.4.0",
"bootstrap": "=3.3.5",
"ionicons": "=2.0.1",
"jquery": "=2.1.4",
"react": "=0.13.3",
"react-bootstrap": "=0.25.1",
"whatwg-fetch": "=0.10.1"
},
"devDependencies": {
"browserify": "^11.0.1",
"clean-css": "^3.4.1",
"eslint": "^1.5.0",
"eslint-plugin-react": "^3.4.2",
"ionicons-pre": "^1.0.0-pre",
"react-tools": "^0.13.2",
"reactify": "^1.1.1",
"uglify-js": "^2.4.24",
"watch": "^0.16.0"
"autoprefixer": "=6.3.3",
"babel-preset-es2015": "=6.1.18",
"babel-preset-react": "=6.1.18",
"babelify": "=7.2.0",
"browserify": "=11.0.1",
"clean-css": "=3.4.1",
"eslint": "=1.5.0",
"eslint-config": "git://github.com/dabapps/eslint-config.git",
"eslint-plugin-react": "=3.4.2",
"less": "=2.5.1",
"less-mixins": "git://github.com/RealOrangeOne/less-mixins.git",
"markdown-spellcheck": "=0.10.0",
"postcss-cli": "=2.5.1",
"react-tools": "=0.13.2",
"uglify-js": "=2.4.24",
"watch": "=0.16.0"
}
}

67
project/blog/tests.py Normal file
View file

@ -0,0 +1,67 @@
from django.test import TestCase
import requests_mock, json
from . import utils
from django.core.urlresolvers import reverse
@requests_mock.mock()
class WordPressAPITestCase(TestCase):
def setUp(self):
self.test_blog_data = {
"title": "Test Blog Post",
"ID": 1,
"content": "<p>Test blog post content</p>",
"slug": "test-post"
}
self.invalid_blog_data = {
"title": "Invalid blog post",
"content": "<p></p>",
"slug": "invalid"
}
def test_gets_correct_data(self, m):
payload = json.dumps(self.test_blog_data)
m.get(utils.build_url(self.test_blog_data['slug']), text=payload)
blog_data = utils.get_post(self.test_blog_data['slug'])
self.assertEqual(blog_data, self.test_blog_data)
def test_invalid_response(self, m):
payload = json.dumps(self.invalid_blog_data)
m.get(utils.build_url(self.invalid_blog_data['slug']), text=payload)
blog_data = utils.get_post(self.invalid_blog_data['slug'])
self.assertFalse(blog_data)
def test_invalid_status(self, m):
payload = json.dumps(self.test_blog_data)
m.get(utils.build_url(self.test_blog_data['slug']), text=payload, status_code=500)
blog_data = utils.get_post(self.test_blog_data['slug'])
self.assertFalse(blog_data)
def test_no_slug(self, m):
blog_data = utils.get_post('')
self.assertFalse(blog_data)
@requests_mock.mock()
class BlogViewTestCase(TestCase):
def setUp(self):
self.test_blog_data = {
"title": "Test Blog Post",
"ID": 1,
"content": "<p>Test blog post content</p>",
"slug": "test-post",
"date": "2000-01-01T18:05:00+00:00"
}
def test_accessable(self, m):
payload = json.dumps(self.test_blog_data)
m.get(utils.build_url(self.test_blog_data['slug']), text=payload)
response = self.client.get(reverse('blog:blog-post', args=[self.test_blog_data['slug']]))
self.assertEqual(response.status_code, 200)
def test_correct_content(self, m):
payload = json.dumps(self.test_blog_data)
m.get(utils.build_url(self.test_blog_data['slug']), text=payload)
response = self.client.get(reverse('blog:blog-post', args=[self.test_blog_data['slug']]))
self.assertContains(response, self.test_blog_data['content'])
self.assertEqual(response.context['html_title'], self.test_blog_data['title'])

6
project/blog/urls.py Normal file
View file

@ -0,0 +1,6 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<slug>.+)/?$', views.BlogView.as_view(), name='blog-post'),
]

25
project/blog/utils.py Normal file
View file

@ -0,0 +1,25 @@
import requests, iso8601
from django.conf import settings
API_PATH = "https://public-api.wordpress.com/rest/v1.1/sites/{0}/posts/slug:{1}"
def build_url(slug):
if not slug:
return
return API_PATH.format(settings.WORDPRESS_URL, slug)
def get_post(slug):
if not slug:
return
response = requests.get(build_url(slug))
if response.status_code != 200:
return
data = response.json()
return data if "ID" in data else False
def reformat_date(iso_date):
return iso8601.parse_date(iso_date).strftime("%x %I:%M")

22
project/blog/views.py Normal file
View file

@ -0,0 +1,22 @@
from django.views.generic import TemplateView
from .utils import get_post, reformat_date
from django.http import Http404
class BlogView(TemplateView):
template_name = "blog/post.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['blog'] = self.blog_data
context['blog']['date'] = reformat_date(self.blog_data['date'])
context['html_title'] = self.blog_data['title']
if 'featured_image' in self.blog_data:
context['header_image'] = self.blog_data['featured_image']
return context
def dispatch(self, request, *args, **kwargs):
self.blog_data = get_post(kwargs['slug'])
if not self.blog_data:
raise Http404
return super().dispatch(request, *args, **kwargs)

View file

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View file

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,7 +0,0 @@
from django.conf.urls import url
from .views import StudentServerView
urlpatterns = [
url(r'^student-server', StudentServerView.as_view(), name='student-server')
]

View file

@ -1,5 +0,0 @@
from django.views.generic import TemplateView
from project.common.views import CustomHeaderBG
class StudentServerView(CustomHeaderBG.Template):
template_name = 'college/student-server.html'

46
project/common/data.py Normal file
View file

@ -0,0 +1,46 @@
import os.path
import yaml
from glob import glob
from project.pages.utils import get_title_from_markdown, parse_content
def get_data_from_file(base_dir, filename):
with open(os.path.join(base_dir, 'data', filename)) as data_file:
return yaml.load(data_file) or {}
def generate_config(base_dir):
default = get_data_from_file(base_dir, 'context.yml')
page = get_data_from_file(base_dir, 'page_context.yml')
switcher = get_data_from_file(base_dir, 'path_switch.yml')
# Add projects config
default['projects'] = generate_projects(base_dir)
# Join projects config with it's page context
for i in range(len(default['projects'])):
project = default['projects'][i]
if project['path'] in page: # If there's a custom config
default['projects'][i] = dict(project, **page[project['path']])
return default, page, switcher
def generate_projects(base_dir):
projects_path = os.path.join(base_dir, 'templates/projects')
files = []
for path in glob(projects_path + '/*.*'):
filename = path.replace(projects_path, '')
if filename == '/index.html':
continue
with open(path) as f:
if filename.split('.')[1] == 'md':
parsed_content = parse_content(f.read(), filename.split('.')[1])
filename = get_title_from_markdown(parsed_content)
else:
filename = filename.split('.')[0]
files.append({
"name": filename,
"path": 'projects' + path.replace(projects_path, '').split('.')[0],
"url": '/projects' + path.replace(projects_path, '').split('.')[0],
})
return files

View file

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,13 +0,0 @@
from django.views.generic import TemplateView
class CustomHeaderBG():
"""Allow custom header background"""
class Template(TemplateView):
header_BG = ""
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['header_BG'] = self.header_BG
return context

View file

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,8 +0,0 @@
from django.conf.urls import url
from .views import GalleryView, YoutubeView
urlpatterns = [
url(r'^gallery', GalleryView.as_view(), name='gallery'),
url(r'^youtube', YoutubeView.as_view(), name='youtube')
]

View file

@ -1,10 +0,0 @@
from django.views.generic import TemplateView
from project.common.views import CustomHeaderBG
class YoutubeView(CustomHeaderBG.Template):
template_name = "media/youtube.html"
class GalleryView(TemplateView):
template_name = "media/gallery.html"

View file

@ -1,3 +1,19 @@
# from django.test import TestCase
from django.test import TestCase
from django.conf import settings
import os.path
from glob import glob
# Create your tests here.
class PagesTestCase(TestCase):
def setUp(self):
directories = glob(os.path.join(settings.BASE_DIR, 'templates') + '/**/*.*')
self.urls = []
for directory in directories:
if 'email' in directory or 'blog' in directory:
continue
self.urls.append(directory.replace(os.path.join(settings.BASE_DIR, 'templates'), '').split('.')[0].replace('index', ''))
def test_pages_accessable(self):
for path in self.urls:
response = self.client.get(path)
self.assertEqual(response.status_code, 200)

View file

@ -1,11 +1,7 @@
from django.conf.urls import url
from . import views
from .views import page_view
urlpatterns = [
url(r'^about/website/$', views.AboutWebsiteView.as_view(), name='about-website'),
url(r'^about/$', views.AboutIndexView.as_view(), name='about'),
url(r'^no-js/$', views.NoJavascriptView.as_view(), name='no-js'),
url(r'^404/$', views.Custom404View.as_view(), name='404'),
url(r'^$', views.IndexView.as_view(), name='index')
url(r'^(?P<path>.*)', page_view, name='page'),
]

29
project/pages/utils.py Normal file
View file

@ -0,0 +1,29 @@
from django.conf import settings
from bs4 import BeautifulSoup
import markdown2
def get_context(path):
if path in settings.PAGE_CONTEXT:
context = dict(settings.DEFAULT_CONTEXT, **settings.PAGE_CONTEXT[path])
else:
context = dict(settings.DEFAULT_CONTEXT)
return context
def get_title_from_markdown(md):
html_tree = BeautifulSoup(md, "html.parser")
tag = html_tree.find('h1')
return tag.contents[0]
def parse_content(content, extension):
if extension == 'md':
return markdown2.markdown(content)
return content
def swap_page(path):
if path in settings.PAGE_SWITCH:
return settings.PAGE_SWITCH[path]
return path

View file

@ -1,34 +1,33 @@
from django.views.generic import TemplateView
from project.common.views import CustomHeaderBG
from django.contrib.staticfiles.templatetags.staticfiles import static
import os.path
from django.conf import settings
from django.http import HttpResponse, Http404
from django.template.loader import get_template
from .utils import get_context, parse_content, get_title_from_markdown, swap_page
class IndexView(TemplateView):
template_name = 'index.html'
def page_view(request, path):
template = None
if path.endswith('/'): # Strip trailing slash
path = path[:-1]
path = swap_page(path)
class NoJavascriptView(TemplateView):
template_name = 'core/no-js.html'
class Custom404View(CustomHeaderBG.Template):
template_name = 'core/404.html'
header_BG = static('img/ninjas.png')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['no_footer'] = True
return context
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context, status=404)
class AboutWebsiteView(CustomHeaderBG.Template):
template_name = 'about/website.html'
header_BG = ''
class AboutIndexView(TemplateView):
template_name = 'about/index.html'
if os.path.isdir(os.path.join(settings.BASE_DIR, 'templates', path)):
path = os.path.join(path, 'index')
for extension in ['md', 'html']:
try:
template = get_template("{}.{}".format(path, extension))
break
except:
pass
if not template:
raise Http404
context = get_context(path)
parsed_content = parse_content(template.render(context, request), extension)
if extension == 'md':
template = get_template('markdown_content.html')
context['markdown_content'] = parsed_content
context['page_title'] = get_title_from_markdown(parsed_content)
context['html_title'] = context['page_title']
parsed_content = template.render(context, request)
return HttpResponse(parsed_content)

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,16 +0,0 @@
from django.conf.urls import url
from . import views
urlpatterns = [
# Project URLs
url(r'^attack-on-blocks', views.AttackOnBlocksView.as_view(), name="attack-on-blocks"),
url(r'^bsod-enabler', views.BSODEnablerView.as_view(), name='bsod-enabler'),
url(r'^hipchat-emoticons-for-all', views.HipChatEmoticonsForAllView.as_view(), name='hipchat-emoticons'),
url(r'^pithos', views.PithosView.as_view(), name='pithos'),
# Code URLs
url(r'^morse-code-decoder', views.MorseCodeDecoderView.as_view(), name='morse-code-decoder'),
url(r'^wiki-game-solver', views.WikiGameSolverView.as_view(), name='wiki-game-solver'),
url(r'^', views.AllProjectsView.as_view(), name="index")
]

View file

@ -1,35 +0,0 @@
from django.views.generic import TemplateView
from project.common.views import CustomHeaderBG
# Project Views
class AllProjectsView(TemplateView):
template_name = "projects/all_projects.html"
class AttackOnBlocksView(CustomHeaderBG.Template):
template_name = "college/attack-on-blocks.html"
class BSODEnablerView(CustomHeaderBG.Template):
template_name = 'projects/BSOD-Enabler.html'
header_BG = 'http://cdn9.howtogeek.com/wp-content/uploads/2013/05/xwindows-8-blue-screen-error.png.pagespeed.ic.yOWUS_rYGn.png'
class HipChatEmoticonsForAllView(CustomHeaderBG.Template):
template_name = 'projects/hipchat-emoticons-for-all.html'
header_BG = "https://info.seibert-media.net/plugins/servlet/pptslide?attachment=HipChat+Server+Sales+Pitch+Final+PPT.pptx&attachmentId=7536966&attachmentVer=1&pageId=3179011&slide=0"
class PithosView(CustomHeaderBG.Template):
template_name = 'projects/pithos.html'
# Code Views
class MorseCodeDecoderView(CustomHeaderBG.Template):
template_name = 'projects/morse-code-decoder.html'
class WikiGameSolverView(CustomHeaderBG.Template):
template_name = 'projects/wiki-game-solver.html'
header_BG = "http://is1.mzstatic.com/image/pf/us/r30/Purple/v4/a3/3f/31/a33f31dd-3ace-ffe4-5531-89d3f3a1106f/mzl.ihqwkbih.png"

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,10 +0,0 @@
from django.conf.urls import url
from .views import Index2015View, Index2014View, RoboticsIndexView, Robot2015View
urlpatterns = [
url(r'^$', RoboticsIndexView.as_view(), name='index' ),
url(r'^2015', Index2015View.as_view(), name='2015-index'),
url(r'^2015/robot', Robot2015View.as_view(), name='2015-robot'),
url(r'^2014', Index2014View.as_view(), name='2014-index')
]

View file

@ -1,22 +0,0 @@
from django.views.generic import TemplateView
from project.common.views import CustomHeaderBG
class RoboticsIndexView(TemplateView):
template_name = 'robotics/index.html'
# 2015
class Index2015View(CustomHeaderBG.Template):
template_name = 'robotics/2015-index.html'
header_BG = "https://farm8.staticflickr.com/7711/17122633430_7d1bde923a_k.jpg"
class Robot2015View(CustomHeaderBG.Template):
template_name = 'robotics/2015-robot.html'
header_BG = ""
# 2014
class Index2014View(CustomHeaderBG.Template):
template_name = 'robotics/2014-index.html'
header_BG = "nothing"

View file

@ -1,19 +1,6 @@
"""
Django settings for project.
Generated by 'django-admin startproject' using Django 1.8.3.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import dj_database_url
# import logging
import os
import sys
import dj_database_url, os
from private import export
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -22,7 +9,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'q&^k#n_lkd5l9&g^k7$q1rhj_=%9yqy-)ln78ik414-bcowedy'
SECRET_KEY = export('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
@ -31,23 +18,13 @@ ALLOWED_HOSTS = ['too.ctf.sh', 'theorangeone.net']
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'bootstrapform',
'project.pages',
'project.common',
'project.projects',
'project.robotics',
'project.setup',
'project.media',
'project.college'
'project.blog'
)
MIDDLEWARE_CLASSES = (
@ -85,7 +62,7 @@ WSGI_APPLICATION = 'project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
'default': dj_database_url.config(default=os.environ['DATABASE_URL'])
'default': dj_database_url.config(default='sqlite://memory')
}
EMAIL_BACKEND = os.environ['EMAIL_BACKEND']
@ -105,4 +82,9 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'collected-static')
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static', 'build'),
)
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
WORDPRESS_URL = "realorangeone.wordpress.com"
# Generate config data
from project.common.data import generate_config
DEFAULT_CONTEXT, PAGE_CONTEXT, PAGE_SWITCH = generate_config(BASE_DIR)

View file

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View file

@ -1,27 +0,0 @@
from django.db import models
import uuid
class Device(models.Model):
device_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
device_name = models.CharField(max_length=50, blank=False, null=True)
friendly_name = models.CharField(max_length=50, blank=False, null=True, unique=True)
model_name = models.CharField(max_length=50, blank=False, null=True, unique=True)
description = models.TextField(blank=True, null=True)
computer = models.ForeignKey('setup.Computer')
class Computer(models.Model):
computer_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
CPU = models.TextField(max_length=30, blank=False, null=True, verbose_name="Processor")
GPU = models.TextField(max_length=40, blank=True, null=True, verbose_name="Graphics Card")
RAM = models.IntegerField(blank=False, null=True)
class Peripheral(models.Model):
peripheral_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=40, blank=False, null=True)
model_name = models.CharField(max_length=100, blank=False, null=True)
device = models.ForeignKey('setup.Device')

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,7 +0,0 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^desk', views.DeskView.as_view(), name="desk"),
url(r'^', views.SetupIndexView.as_view(), name="index")
]

View file

@ -1,11 +0,0 @@
from django.views.generic import TemplateView
from project.common.views import CustomHeaderBG
class SetupIndexView(TemplateView):
template_name = "setup/index.html"
class DeskView(CustomHeaderBG.Template):
template_name = "setup/my-rig.html"
header_BG = "https://c1.staticflickr.com/1/557/18312934624_b51a541594_h.jpg"

View file

@ -1,15 +1,7 @@
from django.conf.urls import include, url
from django.contrib import admin
from project.pages.views import Custom404View
urlpatterns = [
url(r'^site-admin/', include(admin.site.urls)),
url(r'^student-robotics/', include('project.robotics.urls', namespace='robotics')),
url(r'^projects/', include('project.projects.urls', namespace='projects')),
url(r'^media/', include('project.media.urls', namespace='media')),
url(r'^setup/', include('project.setup.urls', namespace='setup')),
url(r'^college/', include('project.college.urls', namespace='college')),
url(r'^blog/', include('project.blog.urls', namespace='blog')),
url(r'', include('project.pages.urls', namespace='pages'))
]
handler404 = Custom404View

View file

@ -1,11 +1,3 @@
"""
WSGI config for twm project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")

View file

@ -1,12 +1,13 @@
Django==1.8.3
beautifulsoup4==4.4.1
coverage==4.0.3
colorama==0.3.6
Django==1.8.11
dj-database-url==0.3.0
django-bootstrap-form==3.2
djangorestframework==3.2.0
djorm-ext-pgfulltext==0.10
flake8==2.4.1
pep8==1.5.7
pycrypto==2.6.1
pyflakes==0.8.1
six==1.9.0
waitress==0.8.9
whitenoise==2.0.2
flake8==2.5.0
iso8601==0.1.11
markdown2==2.3.0
PyYAML==3.11
requests==2.9.1
requests-mock==0.7.0
whitenoise==2.0.6
waitress==0.8.10

View file

@ -1,7 +1,67 @@
#!/usr/bin/env bash
#!/usr/bin/env python3
import coverage
import os, sys
import subprocess
from colorama import Fore, init
set -e
export PATH=env/bin:${PATH}
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
from django.core.management import execute_from_command_line
init(autoreset=True)
flake8 project --ignore=E128,E501 --exclude="migrations,settings,*/wsgi.py"
bin_dir = os.path.abspath(os.path.join(sys.executable, os.path.pardir))
PERCENTAGE = 95
EXIT_CODE = 0
def check_if_exit_code():
if EXIT_CODE != 0:
print("\n{}Tests Failed. {}Please check messages above and then re-run the command.".format(Fore.RED, Fore.YELLOW))
exit(EXIT_CODE)
cov = coverage.Coverage(
source=["project"],
omit=["*/wsgi.py", "*/settings.py", "*/migrations/*.py", "*/__init__*", "*/tests.py"]
)
cov.start()
print(Fore.YELLOW + "Running Tests...")
execute_from_command_line([sys.argv[0], 'test'])
cov.stop()
print("{}Tests Complete. {}Collecting Coverage...".format(Fore.GREEN, Fore.YELLOW))
cov.save()
cov.html_report()
covered = cov.report()
if covered < PERCENTAGE:
print("{}ERROR: Your coverage needs to be higher. Current coverage: {}%. Required: {}%.".format(Fore.RED, covered, PERCENTAGE))
EXIT_CODE = 1
check_if_exit_code()
print("{}Coverage Complete. {}Linting...".format(Fore.GREEN, Fore.YELLOW))
FLAKE8_IGNORE = '--ignore=E128,E501,E401,E402'
try:
subprocess.check_output([os.path.join(bin_dir, 'flake8'), 'project', FLAKE8_IGNORE, '--exclude=migrations,settings,wsgi.py,__init__.py'])
subprocess.check_output([os.path.join(bin_dir, 'flake8'), 'scripts', FLAKE8_IGNORE])
subprocess.check_output([os.path.join(bin_dir, 'flake8'), sys.argv[0], FLAKE8_IGNORE])
except subprocess.CalledProcessError as e:
print(Fore.RED, e.output.decode())
EXIT_CODE = 1
check_if_exit_code()
print("{}All Python tests passed! {}Testing Static Files...".format(Fore.GREEN, Fore.YELLOW))
EXIT_CODE = os.system('npm test')
check_if_exit_code()
print("{}All static tests passed! {}Running spell check...".format(Fore.GREEN, Fore.YELLOW))
EXIT_CODE = os.system('')
check_if_exit_code()
print("{}All Tests Passed!".format(Fore.GREEN))

48
scripts/build-js.sh Normal file → Executable file
View file

@ -1,18 +1,44 @@
#!/usr/bin/bash
#!/usr/bin/env bash
set -e
cp node_modules/bootstrap/dist/js/bootstrap.js static/src/js/lib/
cp node_modules/skrollr/src/skrollr.js static/src/js/lib/
if [[ $BUILD_PRODUCTION ]]
then
echo ">>> WARNING: Building in Production Mode!"
fi
mkdir -p static/build/js/lib
if [[ $BUILD_PRODUCTION ]]
then
echo ">> Compressing Libraries..."
uglifyjs node_modules/bootstrap/dist/js/bootstrap.js --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/lib/bootstrap.js
uglifyjs static/build/js/lib/* --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/libs.js
else
echo ">> Building Libraries..."
cp node_modules/bootstrap/dist/js/bootstrap.js static/build/js/lib/bootstrap.js
uglifyjs static/build/js/lib/* --screw-ie8 --stats --keep-fnames -o static/build/js/libs.js
fi
rm -rf static/build/js/lib
if [[ $BUILD_PRODUCTION ]]
then
echo ">> Compressing jQuery..."
uglifyjs node_modules/jquery/dist/jquery.js --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/jquery.js
else
echo ">> Building jQuery..."
uglifyjs node_modules/jquery/dist/jquery.js --screw-ie8 --stats --keep-fnames -o static/build/js/jquery.js
fi
echo ">> Building Libraries..."
uglifyjs node_modules/jquery/dist/jquery.js --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/jquery.js
uglifyjs node_modules/markdown/lib/markdown.js --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/markdown.js
uglifyjs static/src/js/lib/* --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/libs.js
echo ">> Building Application JS..."
browserify -t reactify static/src/js/app.js -o static/build/js/app.js
# uglifyjs static/build/js/app.js --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/app.js
browserify -t [ babelify --presets [ es2015 react ] ] static/src/js/app.js -o static/build/js/app.js
echo ">> Building Global Utilities..."
uglifyjs static/src/js/utils.js --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/utils.js
if [[ $BUILD_PRODUCTION ]]
then
echo ">> Compressing Application..."
uglifyjs static/build/js/app.js --compress --screw-ie8 --define --stats --keep-fnames -o static/build/js/app.js
fi
echo "> JS Built!"

22
scripts/build-less.sh Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
if [[ $BUILD_PRODUCTION ]]
then
echo ">>> WARNING: Building in Production Mode!"
fi
echo ">> Building LESS..."
lessc --silent static/src/less/style.less static/build/css/style.css
echo ">> Post-Processing..."
postcss -u autoprefixer -o static/build/css/style.css static/build/css/style.css
if [[ $BUILD_PRODUCTION ]]
then
echo ">> Compressing LESS..."
cleancss -d --s0 -o static/build/css/style.css static/build/css/style.css
fi
echo "> LESS Built!"

15
scripts/clean.sh Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -e
echo ">> Removing VirtualEnv..."
rm -rf env/
echo ">> Removing Node Modules..."
rm -rf node_modules/
echo ">> Removing Static Build Directory..."
rm -rf static/build/
echo "> Cleaning Complete."

24
scripts/fresh.sh Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
echo ">> Removing VirtualEnv..."
rm -rf env/
echo ">> Removing Collected Static Files..."
rm -rf collected-static/
echo ">> Removing Private Data..."
rm -rf private/
echo ">> Removing Node Modules..."
rm -rf node_modules/
echo ">> Removing Static Build Directory..."
rm -rf static/build/
echo ">> Removing Stray Files and Folders..."
rm -rf htmlcov/ .coverage
echo "> Much Fresher!"

9
scripts/get-private-data.sh Executable file
View file

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
echo ">> Removing old Private Data..."
rm -rf private/
echo ">> Getting Private Data..."
git clone git@bitbucket.org:TheOrangeOne/theorangeone.net-site-private-data.git --branch master --single-branch private/

View file

@ -1,14 +0,0 @@
#!/usr/bin/bash
set -e
echo ">> Removing old Private data..."
rm -rf private/*
mkdir private/
cd private/
echo ">> Cloning Private Repo..."
git clone git@bitbucket.org:TheOrangeOne/theorangeone.net-site-private-data.git
echo ">> That's it for now..."

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

View file

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -1,14 +1,24 @@
var React = require('react');
var indexCarousel = require('./components/indexCarousel.js');
import './events.js';
import './globals.js';
require('./events.js');
import 'whatwg-fetch';
import React from 'react';
if ($('#index-carousel-container').length == 1) {
React.render(indexCarousel, $("#index-carousel-container")[0]);
import NavBar from './components/navbar/navbar';
import Breadcrumbs from './components/breadcrumbs';
import renderImagePanels from './components/image-panel';
renderImagePanels();
if ($('navbar').length > 0) {
React.render(<NavBar />, $('navbar')[0]);
}
$(window).load(function(){
$(window).trigger('scroll').trigger('resize');
var s = skrollr.init();
});
if ($('#breadcrumbs').length > 0) {
React.render(<Breadcrumbs />, $('#breadcrumbs')[0]);
}
if ($('.header h1').text()) {
$('.markdown-content h1').eq(0).hide();
}

View file

@ -0,0 +1,33 @@
import React from 'react';
export default class Breadcrumbs extends React.Component {
render() {
const loc = location.pathname.endsWith('/') ? location.pathname.slice(0, -1) : location.pathname;
const urlParts = Object.freeze(loc.split('/').slice(1));
if (urlParts.length < 2) {
return null;
}
var elements = [];
for (var i = 0; i < urlParts.length; i++) {
var dirs = [];
for (var j = 0; j <= i; j++) {
dirs.push(urlParts[j]);
}
if (i === (urlParts.length - 1)) {
elements.push(
<li className="active">{urlParts[i]}</li>
);
} else {
var url = '/' + dirs.join('/') + '/';
elements.push(
<li><a href={url}>{urlParts[i]}</a></li>
);
}
}
return (
<ol className="breadcrumb">
{ elements }
</ol>
);
}
}

View file

@ -0,0 +1,24 @@
export default function renderImagePanels() {
$('.image-panel').each(function () {
const element = $(this);
if (!element.data('image')) { // if it doesnt have an image, ignore it.
return;
}
element.css('background-image', 'url("' + element.data('image') + '")');
let height;
switch (element.data('size')) {
case 'small':
height = '30';
break;
default:
case 'medium':
height = '60';
break;
case 'large':
height = '100';
}
element.css('height', `${height}vh`);
});
}

View file

@ -1,27 +0,0 @@
var React = require('react');
var Bootstrap = require('react-bootstrap');
var Carousel = Bootstrap.Carousel;
var CarouselItem = Bootstrap.CarouselItem;
const indexCarousel = (
<Carousel>
<CarouselItem>
<div className='carousel-image'></div>
<div className='carousel-caption'>
<h3>Setup</h3>
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
</div>
</CarouselItem>
<CarouselItem>
<div className='carousel-image'></div>
<div className='carousel-caption'>
<h3>Student Robotics</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</CarouselItem>
</Carousel>
);
module.exports = indexCarousel;

View file

@ -0,0 +1,20 @@
import React from 'react';
export default class Dropdown extends React.Component {
render() {
return (
<li className="dropdown">
<a className="dropdown-toggle"
data-toggle="dropdown"
role="button"
aria-haspopup="true"
aria-expanded="false">
{ this.props.title } <i className="icon ion-ios-arrow-up navbar-icon h4 hidden-sm"></i>
</a>
<ul className="dropdown-menu dropup">
{ this.props.children }
</ul>
</li>
);
}
}

View file

@ -0,0 +1,28 @@
import React from 'react';
export default class Header extends React.Component {
render() {
const items = [0, 1, 2];
var iconBars = items.map(function (item) {
return (
<span className="icon-bar" key={item} />
);
});
return (
<div className="navbar-header">
<button type="button"
className="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar"
aria-expanded="false" >
<span className="sr-only">Toggle navigation</span>
{{ iconBars }}
</button>
<a className="navbar-brand visible-xs">
<i className="icon ion-compass" />
Navigation
</a>
</div>
);
}
}

View file

@ -0,0 +1,23 @@
import React from 'react';
export default class Item extends React.Component {
render() {
const href = this.props.href.endsWith('/') ? this.props.href : this.props.href + '/';
let icon;
if (this.props.icon) {
if (this.props.icon.startsWith('ion')) {
icon = (
<i className={'icon ' + this.props.icon} />
);
} else if (this.props.icon.startsWith('glyphicon')) {
icon = (
<span className={'glyphicon ' + this.props.icon} aria-hidden="true" />
);
}
}
return (
<li><a href={href}>{icon}{this.props.children}</a></li>
);
}
}

View file

@ -0,0 +1,74 @@
import React from 'react';
import Header from './header';
import Dropdown from './dropdown';
import Item from './item';
export default class NavBar extends React.Component {
render() {
return (
<span>
<div id="navbar-anchor" />
<div id="navbar-container" className="align">
<nav className="navbar navbar-inverse">
<div className="container-fluid">
<Header />
<div className="collapse navbar-collapse" id="navbar">
<ul className="nav navbar-nav home-button hidden-sm hidden-md">
<Item href="/" icon="ion-home" />
</ul>
<ul className="nav navbar-nav" id="navigation">
<Dropdown title="Projects">
<Item href="/projects/yoga-pal/" icon="ion-laptop">Yoga Pal</Item>
<Item href="/projects/bsod-enabler/" icon="ion-ios-monitor">BSOD Enabler</Item>
<Item href="/projects/hipchat-emoticons-for-all/" icon="ion-chatbox-working">
Hipchat Emoticons for All
</Item>
<Item href="#" icon="ion-social-windows">Custom PC</Item>
<Item href="/projects/" icon="ion-android-more-vertical">All Projects...</Item>
</Dropdown>
<Dropdown title="Code">
<Item href="#" icon="ion-code-working">Code Challenges</Item>
<Item href="#" icon="ion-ios-circle-filled">Pi Time Lapse</Item>
<Item href="/projects/wiki-game-solver/" icon="ion-ios-game-controller-a">The Wiki Game Solver</Item>
</Dropdown>
<Dropdown title="College">
<Item href="/robotics/">Student Robotics</Item>
<Item href="/college/attack-on-blocks/" icon="ion-cube">Attack on Blocks Game</Item>
<Item href="/college/student-server/" icon="glyphicon-hdd">Student Server</Item>
<Item href="#" icon="ion-ios-paper">EPQ</Item>
<Item href="#">Wall of Sheep</Item>
</Dropdown>
<Dropdown title="Setup">
<Item href="#">&#128129; Desk</Item>
<Item href="#" icon="ion-briefcase">Work</Item>
<Item href="#" icon="ion-model-s">On The Go</Item>
<Item href="#" icon="ion-android-phone-portrait">Devices</Item>
<Item href="#">Servers</Item>
</Dropdown>
<Dropdown title="Work">
<Item href="#" icon="ion-form-repo">Projects</Item>
<Item href="#" icon="ion-android-desktop">Setup</Item>
</Dropdown>
<Dropdown title="Media">
<Item
href="https://www.youtube.com/user/TheOrangeOneOfficial"
icon="ion-social-youtube">
YouTube Channel
</Item>
<Item href="/blog/" icon="ion-social-rss">Blog</Item>
<Item href="https://www.flickr.com/photos/theorangeone/" icon="ion-social-camera">Gallery</Item>
</Dropdown>
<Item href="#">Links</Item>
<Dropdown title="About">
<Item href="/about/me/" icon="ion-android-person">Me</Item>
<Item href="/about/website/" icon="ion-cloud">Website</Item>
</Dropdown>
</ul>
</div>
</div>
</nav>
</div>
</span>
);
}
}

View file

@ -1,16 +1,69 @@
$(window).scroll(function() {
position_navbar();
/* global $ */
var is_navbar_attached = false;
$(window).load(function() {
$(window).trigger('scroll');
});
function detach_navbar() {
$('#navbar-container').removeClass('stick-top').addClass('align');
$('.dropdown-menu').removeClass('dropdown').addClass('dropup');
}
$(window).resize(function() {
set_page_sizes();
space_navbar();
function attach_navbar() {
$('#navbar-container').removeClass('align').addClass('stick-top');
$('.dropdown-menu').removeClass('dropup').addClass('dropdown');
}
function flip_dropdowns(obj, direction) {
if (obj.hasClass('drop' + direction)) { return; }
var reverse = ((direction === 'up') ? 'down' : 'up');
obj.removeClass('drop' + reverse).addClass('drop' + direction);
obj.prev().find('i').removeClass('ion-ios-arrow-' + reverse).addClass('ion-ios-arrow-' + direction);
}
function position_navbar() {
if ($(window).width() < 862) { // @screen-sm
$('.navbar-icon').removeClass('ion-ios-arrow-up').addClass('ion-ios-arrow-down');
return;
}
if ($(window).scrollTop() > $('#navbar-anchor').offset().top) {
if (!is_navbar_attached) {
attach_navbar();
is_navbar_attached = true;
}
} else if (is_navbar_attached) {
detach_navbar();
is_navbar_attached = false;
}
$('.dropdown-menu').each(function() {
var direction = ($(this).height() + 10 < $('nav').offset().top - $(window).scrollTop()) ? 'up' : 'down';
flip_dropdowns($(this), direction);
});
}
$(function() { // https://css-tricks.com/snippets/jquery/smooth-scrolling/
$('a[href*=#]:not([href=#])').click(function() {
if ($(this).data('toggle') === 'collapse') {
return true;
}
if (location.pathname.replace(/^\//, '') === this.pathname.replace(/^\//, '')
&& location.hostname === this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
});
$("#page-down").click(function() {
$('html, body').animate({
scrollTop: $("#navbar-anchor").offset().top
}, 750);
$('a[href="soon"]').click(function (e) {
e.preventDefault();
alert('Content coming soon, stand by!');
});
$(window).scroll(position_navbar);

7
static/src/js/globals.js Normal file
View file

@ -0,0 +1,7 @@
window.updateTitle = function (value) {
document.title = value + ' | TheOrangeOne';
};
if ($('.header h1').length) {
window.updateTitle($('.header h1').text());
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,83 +0,0 @@
var is_navbar_attached = false;
function position_navbar() {
if ($(window).width() < 862) { // @screen-sm
$('.navbar-icon').removeClass('ion-ios-arrow-up').addClass('ion-ios-arrow-down');
return;
}
if ($(window).scrollTop() > $('#navbar-anchor').offset().top) {
if(!is_navbar_attached) {attach_navbar(); is_navbar_attached = true;}
} else if (is_navbar_attached) {
detach_navbar();
is_navbar_attached = false;
}
$('.dropdown-menu').each(function(){
direction = ($(this).height() + 10 < $('nav').offset().top - $(window).scrollTop()) ? 'up' : 'down';
flip_dropdowns($(this), direction);
});
}
function detach_navbar() {
$('#navbar-container').removeClass('stick-top').addClass('align');
$('.dropdown-menu').removeClass('dropdown').addClass('dropup');
}
function set_page_sizes() {
win_height = $(window).height();
win_width = $(window).width();
$('.page-height').each(function() {
$(this).height(win_height);
});
$('.page-width').each(function() {
$(this).width(win_width);
});
}
function attach_navbar() {
$('#navbar-container').removeClass('align').addClass('stick-top');
$('.dropdown-menu').removeClass('dropup').addClass('dropdown');
}
function flip_dropdowns(obj, direction) {
if (obj.hasClass('drop'+direction)){ return; }
reverse = direction == 'up' ? 'down' : 'up';
obj.removeClass('drop' + reverse).addClass('drop' + direction);
obj.prev().children().removeClass('ion-ios-arrow-' + reverse).addClass('ion-ios-arrow-' + direction);
}
function space_navbar() { //This really should be CSS!
if ($(window).width() < 862) {return;} // @screen-sm
nav_width = $('#navigation').outerWidth(true);
full_width = $('nav > .container-fluid').outerWidth(true) - $('.home-button').outerWidth(true);
margin = (full_width - nav_width) / 2;
$('#navigation').css('margin-left', margin);
}
function checkDomain(url) {
if ( url.indexOf('//') === 0 ) { url = location.protocol + url; }
return url.toLowerCase().replace(/([a-z])?:\/\//,'$1').split('/')[0];
}
function isExternal(url) {
return ( ( url.indexOf(':') > -1 || url.indexOf('//') > -1 ) && checkDomain(location.href) !== checkDomain(url) );
}
function is_on_screen(elm) {
var vpH = $(window).height(), // Viewport Height
st = $(window).scrollTop(), // Scroll Top
y = $(elm).offset().top,
elementHeight = $(elm).height();
return ((y < (vpH + st)) && (y > (st - elementHeight)));
}
function navTo(url){
location.href=url;
}

View file

@ -0,0 +1,6 @@
@btn-srobo-color: @gray-lighter;
@btn-srobo-bg: #253571;
@btn-srobo-border: darken(@btn-srobo-bg, 5%);
.btn-srobo {
.button-variant(@btn-srobo-color; @btn-srobo-bg; @btn-srobo-border);
}

View file

@ -0,0 +1,8 @@
.image-panel {
background-attachment: fixed;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
width: 100%;
margin-top: 20px;
}

View file

@ -0,0 +1,197 @@
@blueprint-logo: url(http://ultimatestorytellingblueprint.com/wp-content/uploads/2014/07/Blueprint-Background1.jpg);
@container-inset: 35px;
body.index {
#header {
height: 100vh;
background: #232323;
background-size: cover;
background-position: fixed;
.jumbotron {
margin-top: 19vh;
text-align: center;
background-color: transparent;
color: white;
padding-bottom: 0;
margin-bottom: 0;
.box-shadow(initial);
h1 {
margin-bottom: 15px;
margin-top: 10px;
}
p.scroll-icon {
margin-top: 45px;
}
i.icon {
cursor: pointer;
font-size: 30px;
.transition(color 0.4s);
&:hover {
color: #ff7f00;
}
}
img {
height: 275px;
}
}
}
#intro-text {
background-color: #333;
.container {
text-align: center;
margin-top: @container-inset;
margin-bottom: @container-inset;
color: white;
}
}
#twitter-feed {
text-align: center;
.container {
margin-top: @container-inset;
margin-bottom: @container-inset;
}
.twitter-timeline {
height: 65vh !important; // Because twitter uses inline styles.
.box-shadow(4px 5px 2px 0 rgba(0,0,0,0.4));
}
.twitter-icon {
text-align: center;
font-size: 175px;
height: 65vh;
position: relative;
.icon {
position: absolute;
text-shadow: 4px 5px 2px rgba(0,0,0,0.4);
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.transition(color 0.6s);
&:hover {
color: #55ACEE;
}
}
}
}
#project-thumbnails {
background-image: @blueprint-logo;
background-size: cover;
background-attachment: fixed;
& > div > .row {
margin-top: @container-inset;
margin-bottom: @container-inset;
& > h1 {
color: white;
text-align: center;
}
}
.thumbnail {
padding: 15px;
height: 275px;
text-align: center;
&.larger {
.inner {
position: relative;
top: 50%;
transform: translateY(-50%);
h1, h2 {
margin: 0;
}
}
&.project h2 {
@media (min-width: @screen-sm-min) {
font-size: 30px;
}
}
}
img {
max-width: 100%;
max-height: 45%;
}
h3 {
margin: 10px 0;
}
.caption {
padding: 0;
}
}
}
}
/* @group project-images */
.project-image {
.wrapper {
color: white;
margin: 0 auto;
cursor: pointer;
background-size: cover;
background-position: center;
.box-shadow(0px 4px 5px 2px rgba(0,0,0,0.7));
&:hover .project {
opacity: 1;
}
@media screen and (max-width: @screen-xs-max) {
&, & .project {
height: 240px;
width: 240px;
margin-bottom: 15px;
}
}
@media screen and (min-width: @screen-sm-min) {
&, & .project {
height: 210px;
width: 210px;
}
}
@media screen and (min-width: @screen-md-min) {
&, & .project {
height: 280px;
width: 280px;
}
}
& .project {
padding: 8%;
.flexbox();
align-items: center;
justify-content: center;
.transition(~"opacity 0.5s ease-in");
opacity: 0;
background-color: rgba(0,0,0,0.7);
text-align: center;
@media screen and (max-width: @screen-xs-max) {
p, a.btn {
font-size: 14px;
margin-bottom: 13px;
}
h4 {
font-size: 25px;
}
}
@media screen and (min-width: @screen-sm-min) {
p, a.btn {
font-size: 13px;
}
h4 {
font-size: 21px;
}
}
@media screen and (min-width: @screen-md-min) {
p, a.btn {
font-size: 17px;
margin-bottom: 15px;
}
h4 {
font-size: 25px;
margin-bottom: 15px;
}
}
}
}
}
/* @end project-images */

136
static/src/less/navbar.less Normal file
View file

@ -0,0 +1,136 @@
#navigation {
@media (min-width: @screen-xs-max) {
.flexbox();
justify-content: center;
float: none;
}
& a {
.transition(~"ease-in-out .3s color");
}
& > li {
max-height: @navbar-height;
@media (min-width: @screen-md-min) {
margin-right: 15px;
}
}
.dropdown-toggle, & > li > a {
font-size: 19px;
max-height: @navbar-height;
}
.dropdown-menu {
.transition(~"ease-in-out .2s all");
@media (min-width: @screen-sm) {
right: auto;
left: 50%;
transform: translate(-50%, 0);
}
& > li > a {
font-size: 15px;
}
&.dropup {
bottom: 100%;
top: initial;
}
&.dropdown {
top: 100%;
bottom: initial;
}
.open & {
opacity: 1;
}
}
}
.navbar {
border-radius: 0;
border: none;
.home-button a {
.transition(~"ease-in-out .3 all");
}
@media (min-height: @screen-sm-min) {
max-height: @navbar-height;
}
}
.navbar-nav.nav {
margin: 0;
}
.navbar-toggle {
right: 10px;
}
#navbar-container {
margin: 0;
z-index: 10000;
@media (max-width: @screen-xs-max) {
width: 96%;
left: 2%;
}
@media (min-width: @screen-sm-min) {
width: 100%;
}
i + *, .glyphicon + * {
margin-left: 5px;
}
& .container-fluid{
padding-right: 0;
padding-left: 0;
}
&.align {
@media (min-width: @screen-sm) {
position: initial;
height: @navbar-height;
margin-top: -50px;
}
@media (max-width: @screen-sm) {
position: fixed;
top: 0;
width: 95%;
}
}
}
#navbar-anchor {
width: 100%;
height: 50px;
}
@media (min-width: @screen-xs-max) {
.home-button {
margin-right: 15px !important;
}
}
#navbar {
margin: 0;
padding: 0;
}
.navbar-brand {
margin-left: 15px;
}
.stick-top {
position: fixed;
top: 0;
z-index: 10000;
}
// /* @group Header Navbar*/
// @media (min-width: @screen-sm-min) {
// .header {
// #navbar-container {
// margin: 0 auto;
// &:not(.stick-top) {
// position: initial;
// }
// &.stick-top {
// width: 100%;
// }
// }
// }
// }
// /* @end Header Navbar*/

View file

@ -1,99 +1,31 @@
@import "node_modules/less-mixins/index.less";
@import "node_modules/bootstrap/less/bootstrap";
@import "node_modules/ionicons/less/ionicons";
@import "node_modules/bootstrap/less/theme";
@import "node_modules/ionicons-pre/less/ionicons";
@import url(https://fonts.googleapis.com/css?family=Roboto:400,300,400italic,700);
@import "variables";
/* @group mixins */
.transition(@value) {
-webkit-transition: @value;
-moz-transition: @value;
-o-transition: @value;
-ms-transition: @value;
transition: @value;
}
.box-shadow(@value) {
-webkit-box-shadow: @value;
-moz-box-shadow: @value;
box-shadow: @value;
}
/* @end mixins */
/* @group Global Transitions */
@import (inline) "node_modules/animate.css/animate.css";
@import 'homepage';
@import 'variables';
@import 'navbar';
@import 'assets';
@import 'components';
/* @group Global */
.btn {
.transition(~"ease-in-out .2s background-color");
.transition(~"ease-in-out .4s background-color");
}
p > a {
.transition(~"ease-in-out .20s ease");
&:not(.no-line):not(.btn) {
text-decoration: none;
position:relative;
&::before {
content: ' ';
display: block;
position: absolute;
opacity: 0;
width: 100%;
height: 1px;
left: 0;
right: 0;
bottom: 0;
background-color: @link-color;
.transition(~"ease-in-out .2s opacity, ease-in-out .2s background-color");
}
&:hover,
&:focus {
text-decoration: none;
&::before {
opacity: 1;
background-color: @link-hover-color;
}
}
}
}
/* @end Global Transitions */
/* @group Global Styles */
html, body{
margin: 0;
padding: 0;
width: 100% !important;
height: 100% !important;
font-family: 'Roboto', sans-serif;
height: 100%;
width: 100%;
font-weight: 300;
}
p {
font-size: 16px;
line-height: 1.4;
}
.row {
margin-left: 0;
margin-right: 0;
& > div {
// margin-left: 0;
padding-left: 0;
a {
.transition(color 0.4s);
}
}
.panel {
margin-bottom: 0;
& h3 {
margin-top: 10px;
}
}
.container {
margin-top: 10px;
margin-bottom: 20px;
}
ol , ul{
@ -103,61 +35,38 @@ ol , ul{
}
}
/* @end Global Styles */
/* @group Functional Clases */
.stick-top {
position: fixed;
top: 0;
z-index: 10000;
blockquote {
font-size: @font-size-base + 1px;
}
.full-width {
width: 100%;
a.no-color-change {
color: inherit;
&:hover {
color: inherit;
}
}
img {
max-width: 100%;
}
.clickable {
cursor: pointer;
}
/* @end Global */
.no-font {
font-size: 0px;
}
/* @group Functional */
.full-height {
height: 100%;
.center-align {
margin-left: auto;
margin-right: auto;
}
.center-text {
text-align: center;
}
div.fix-image {
background-attachment: fixed;
background-size: cover;
}
.margin-bottom {
margin-bottom: 10px;
}
.black-text {
color: black !important;
}
.white-text {
color: white !important;
}
.drop-shadow {
.box-shadow(0 0.4px 6px 0 rgba(0, 0, 0, 0.9));
}
.mega-icon {
font-size: 110px;
text-align: center;
margin-bottom: 0;
cursor: default;
& ~ div.caption {
padding-top: 0;
@ -167,213 +76,158 @@ div.fix-image {
}
}
/* @end Functional Classes */
/* @end Functional */
/* @group Header */
#header {
margin: 0;
background: url(../img/header-bg.png);
background-attachment: fixed;
background-size: cover;
backgorund-position: center center;
margin-bottom: 15px;
color: @gray-lighter;
& div.jumbotron.container {
color: @gray-lighter;
text-align: center;
position: absolute;
top: 25%;
background-color: transparent;
& div.row {
text-shadow: 0px 3px 3px rgba(0, 0, 0, 1);
}
}
.content-wrapper {
min-height: %(~"calc(100% - %d)", @footer-height);
}
#page-down {
position: absolute;
bottom: 20%;
text-align: center !important;
& i {
.transition(~"ease-in-out .30s color");
&:hover {
color: black;
}
}
}
/* @end Header */
/* @group Navigation Bar */
.dropdown-menu {
@media (min-width: @screen-sm) {
right: auto;
left: 50%;
transform: translate(-50%, 0);
opacity: 0;
.transition(~"ease-in-out .2s all");
}
&.dropup {
bottom: 100%;
top: initial;
}
&.dropdown {
top: 100%;
bottom: initial;
}
.open & {
opacity: 1;
}
}
#navigation {
& a {
.transition(~"ease-in-out .3s color");
}
& > li {
@media (min-width: @screen-md-min) {
margin-right: 23px;
}
@media (max-width: @screen-sm-max) {
margin-right: 10px;
margin-left: 11px;
}
& > a {
@media (min-width: @screen-md-min) {
padding: 15px 10px;
}
@media (max-width: @screen-sm-max) {
padding: 15px 3px;
}
}
}
}
.navbar-nav.nav {
margin: 0;
}
#navbar-container {
z-index: 0;
& .container-fluid{
padding-right: 0;
padding-left: 0;
}
&.align {
@media (min-width: @screen-sm) {
position: absolute;
bottom: 0;
height: 52px;
}
@media (max-width: @screen-sm) {
position: fixed;
top: 0;
width: 100%;
}
}
}
#navbar-anchor {
position: absolute;
bottom: 0;
height: 52px;
}
.home-button {
margin-right: 15px !important;
}
#navbar {
margin: 0;
padding: 0;
}
.navbar-brand {
margin-left: 15px;
}
/* @end Navigation Bar */
/* @group Footer */
@footer-link-margin: 7px;
@footer-height: 250px;
footer {
height: 100px;
height: @footer-height;
width: 100%;
margin-top: 15px;
background-color: black;
color: @text-color;
p:first-child {
text-align: center;
padding-top: 30px;
margin-bottom: 0px;
color: white;
background-color: #232323;
a {
color: #ff7f00;
&:hover {
text-decoration: none;
color: inherit;
}
p.footer-links > a {
font-size: 12px;
margin-top: -4px;
margin-left: @footer-link-margin;
margin-right: @footer-link-margin;
}
.bar-links {
margin: 0 7px;
}
.powered-by {
font-size: @font-size-h6;
}
.social {
font-size: 23px;
margin: 0;
padding: 7px;
a {
margin: 0 4px;
color: white;
&:hover {
color: #ff7f00;
}
}
}
.ci-badge {
height: @font-size-h4;
margin-top: 10px;
}
}
/* @end Footer */
/* @group Index */
@index-carousel-height: 525px;
@index-carousel-width: 100%;
#index-carousel-container {
height: @index-carousel-height;
width: @index-carousel-width;
& div.carousel-item {
height: @index-carousel-height;
overflow: hidden;
/* @group 404 */
.four-o-four {
.header {
height: 15vh;
font-size: 35px;
text-align: center;
}
& div.carousel-image {
width: @index-carousel-width;
height: @index-carousel-height;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
background-attachment: fixed;
}
& div.item:nth-child(1) div.carousel-image {
background-image: url(https://farm1.staticflickr.com/557/18747807580_d01e8e877a_c.jpg);
}
& div.item:nth-child(2) div.carousel-image {
background-image: url(https://farm9.staticflickr.com/8815/17122387228_8b59d46392_b.jpg);
}
}
/* @end Index */
/* @group Student Robotics */
@btn-srobo-color: @gray-lighter;
@btn-srobo-bg: #253571;
@btn-srobo-border: darken(@btn-srobo-bg, 5%);
.btn-srobo {
.button-variant(@btn-srobo-color; @btn-srobo-bg; @btn-srobo-border);
}
.thumbnail.sr-option {
padding: 5px;
& div.image {
.image {
background: url(../img/ninjas.png);
background-size: cover;
background-position: center;
height: 70vh;
}
.message {
height: 15vh;
color: white;
background-color: #232323;
text-align: center;
}
.move-on {
text-align: center;
background-color: #333;
color: white;
height: 5vh;
}
}
/* @end 404 */
/* @group no-js */
.no-js {
.header {
background-color: #232323;
color: white;
}
#ie-scare {
height: 150px;
float: right;
}
}
/* @end no-js*/
/* @group content base */
.jumbotron.header {
padding-top: 10px;
padding-bottom: 0;
margin-bottom: 15px;
background-color: @body-bg;
@media (max-width: @screen-xs-max) {
padding-top: 50px;
}
h1 {
margin: 10px 0;
display: inline-block;
font-size: 60px;
}
.image {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
width: 100%;
height: 250px;
margin: 0;
height: 225px;
margin: 10px 0;
}
}
/* @end Student Robotics */
/* @group external */
.gist {
width: 100%
#breadcrumbs {
text-align: right;
.breadcrumb {
background: transparent;
font-size: @font-size-h4;
margin: 10px 0;
padding: 0;
li::before {
content: "/";
padding: 0 3px;
}
a {
.transition(color 0.4s);
color: #333;
&:hover {
color: #ff7f00;
}
}
}
}
/* @end external*/
/* @end content base */
.panel {
margin-bottom: 40px;
}
.row {
width: initial;
}
.gh-card iframe {
.box-shadow(0px 4px 4px 3px rgba(0,0,0,0.6));
}
/* @group X-Large */
@media (min-width: 1500px) {
.container {
width: 1400px + @grid-gutter-width;
}
}
/* @end X-Large */

View file

@ -1,11 +1,3 @@
//
// Variables
// --------------------------------------------------
//== Colors
//
//## Gray and brand colors for use across Bootstrap.
@gray-base: #000;
@gray-darker: lighten(@gray-base, 13.5%);
@gray-dark: lighten(@gray-base, 20%);
@ -15,34 +7,18 @@
@brand-primary: #ff7f00;
@brand-success: #5cb85c;
@brand-info: #5bc0de;
@brand-warning: #ebd300;
@brand-warning: #f0ad4e;
@brand-danger: #d9534f;
//== Scaffolding
//
//## Settings for some of the most global styles.
//** Background color for `<body>`.
@body-bg: #232323;
//** Global text color on `<body>`.
@text-color: @gray-lighter;
//** Global textual link color.
@body-bg: #fff;
@text-color: @gray-dark;
@link-color: @brand-primary;
//** Link hover color set via `darken()` function.
@link-hover-color: darken(@link-color, 15%);
//** Link hover decoration.
@link-hover-decoration: underline;
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-serif: Georgia, "Times New Roman", Times, serif;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
@font-family-sans-serif: 'Roboto', sans-serif;
@font-family-serif: 'Roboto';
@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
@font-family-base: @font-family-sans-serif;
@font-size-base: 14px;
@font-size-base: 18px;
@font-size-large: ceil((@font-size-base * 1.25));
@font-size-small: ceil((@font-size-base * 0.85));
@font-size-h1: floor((@font-size-base * 2.6));
@ -51,31 +27,15 @@
@font-size-h4: ceil((@font-size-base * 1.25));
@font-size-h5: @font-size-base;
@font-size-h6: ceil((@font-size-base * 0.85));
//** Unit-less `line-height` for use in components like buttons.
@line-height-base: 1.428571429;
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
@line-height-computed: floor((@font-size-base * @line-height-base));
//** By default, this inherits from the `<body>`.
@headings-font-family: inherit;
@headings-font-weight: 500;
@headings-font-weight: 300;
@headings-line-height: 1.1;
@headings-color: inherit;
//== Iconography
//
//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
//** Load fonts from this directory.
@icon-font-path: "../fonts/";
//** File name for all font files.
@icon-font-name: "glyphicons-halflings-regular";
//** Element ID within SVG icon file.
@icon-font-svg-id: "glyphicons_halflingsregular";
//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
@padding-base-vertical: 6px;
@padding-base-horizontal: 12px;
@padding-large-vertical: 10px;
@ -89,42 +49,22 @@
@border-radius-base: 4px;
@border-radius-large: 6px;
@border-radius-small: 3px;
//** Global color for active items (e.g., navs or dropdowns).
@component-active-color: #fff;
//** Global background color for active items (e.g., navs or dropdowns).
@component-active-bg: @brand-primary;
//** Width of the `border` for generating carets that indicator dropdowns.
@caret-width-base: 4px;
//** Carets increase slightly in size for larger components.
@caret-width-large: 5px;
//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.
//** Padding for `<th>`s and `<td>`s.
@table-cell-padding: 8px;
//** Padding for cells in `.table-condensed`.
@table-condensed-cell-padding: 5px;
//** Default background color used for all tables.
@table-bg: transparent;
//** Background color used for `.table-striped`.
@table-bg-accent: @gray-light;
//** Background color used for `.table-hover`.
@table-bg-accent: #f9f9f9;
@table-bg-hover: #f5f5f5;
@table-bg-active: @table-bg-hover;
//** Border color for table and cell borders.
@table-border-color: #ddd;
//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.
@btn-font-weight: normal;
@btn-default-color: #333;
@btn-default-bg: #fff;
@btn-default-border: #ccc;
@btn-primary-color: @gray-darker;
@btn-primary-color: #fff;
@btn-primary-bg: @brand-primary;
@btn-primary-border: darken(@btn-primary-bg, 5%);
@btn-success-color: #fff;
@ -133,80 +73,42 @@
@btn-info-color: #fff;
@btn-info-bg: @brand-info;
@btn-info-border: darken(@btn-info-bg, 5%);
@btn-warning-color: @gray-base;
@btn-warning-color: #fff;
@btn-warning-bg: @brand-warning;
@btn-warning-border: darken(@btn-warning-bg, 5%);
@btn-danger-color: #fff;
@btn-danger-bg: @brand-danger;
@btn-danger-border: darken(@btn-danger-bg, 5%);
@btn-link-disabled-color: @gray-light;
//== Forms
//
//##
//** `<input>` background color
@input-bg: #fff;
//** `<input disabled>` background color
@input-bg-disabled: @gray-lighter;
//** Text color for `<input>`s
@input-color: @gray;
//** `<input>` border color
@input-border: #ccc;
//** Default `.form-control` border radius
@input-border-radius: @border-radius-base;
//** Large `.form-control` border radius
@input-border-radius-large: @border-radius-large;
//** Small `.form-control` border radius
@input-border-radius-small: @border-radius-small;
//** Border color for inputs on focus
@input-border-focus: @brand-primary;
//** Placeholder text color
@input-border-focus: #66afe9;
@input-color-placeholder: #999;
//** Default `.form-control` height
@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
//** Large `.form-control` height
@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
//** Small `.form-control` height
@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
//** `.form-group` margin
@form-group-margin-bottom: 15px;
@legend-color: @gray-dark;
@legend-border-color: #e5e5e5;
//** Background color for textual input addons
@input-group-addon-bg: @gray-lighter;
//** Border color for textual input addons
@input-group-addon-border-color: @input-border;
//** Disabled cursor for form controls and buttons.
@cursor-disabled: not-allowed;
//== Dropdowns
//
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
@dropdown-bg: #fff;
//** Dropdown menu `border-color`.
@dropdown-border: rgba(0,0,0,.15);
//** Dropdown menu `border-color` **for IE8**.
@dropdown-fallback-border: #ccc;
//** Divider color for between dropdown items.
@dropdown-divider-bg: #e5e5e5;
//** Dropdown link text color.
@dropdown-link-color: @gray-dark;
//** Hover color for dropdown links.
@dropdown-link-hover-color: @dropdown-bg;
//** Hover background for dropdown links.
@dropdown-link-hover-bg: @dropdown-link-color;
//** Active dropdown menu item text color.
@dropdown-link-hover-color: #fff;
@dropdown-link-hover-bg: darken(@gray-dark, 30%);
@dropdown-link-active-color: @component-active-color;
//** Active dropdown menu item background color.
@dropdown-link-active-bg: @component-active-bg;
//** Disabled dropdown menu item background color.
@dropdown-link-disabled-color: @gray-light;
//** Text color for headers within dropdown menus.
@dropdown-header-color: @gray-light;
//** Deprecated `@dropdown-caret-color` as of v3.1.0
@dropdown-caret-color: #000;
@zindex-navbar: 1000;
@zindex-dropdown: 1000;
@ -215,67 +117,31 @@
@zindex-navbar-fixed: 1030;
@zindex-modal-background: 1040;
@zindex-modal: 1050;
//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
//** Deprecated `@screen-xs` as of v3.0.1
@screen-xs: 480px;
//** Deprecated `@screen-xs-min` as of v3.2.0
@screen-xs-min: @screen-xs;
//** Deprecated `@screen-phone` as of v3.0.1
@screen-phone: @screen-xs-min;
//** Deprecated `@screen-sm` as of v3.0.1
@screen-sm: 862px;
@screen-sm: 768px;
@screen-sm-min: @screen-sm;
//** Deprecated `@screen-tablet` as of v3.0.1
@screen-tablet: @screen-sm-min;
//** Deprecated `@screen-md` as of v3.0.1
@screen-md: 1080px;
@screen-md: 992px;
@screen-md-min: @screen-md;
//** Deprecated `@screen-desktop` as of v3.0.1
@screen-desktop: @screen-md-min;
//** Deprecated `@screen-lg` as of v3.0.1
@screen-lg: 1200px;
@screen-lg-min: @screen-lg;
//** Deprecated `@screen-lg-desktop` as of v3.0.1
@screen-lg-desktop: @screen-lg-min;
@screen-xs-max: (@screen-sm-min - 1);
@screen-sm-max: (@screen-md-min - 1);
@screen-md-max: (@screen-lg-min - 1);
//== Grid system
//
//## Define your custom responsive grid.
//** Number of columns in the grid.
@grid-columns: 12;
//** Padding between columns. Gets divided in half for the left and right.
@grid-gutter-width: 30px;
//** Point at which the navbar becomes uncollapsed.
@grid-float-breakpoint: @screen-sm-min;
//** Point at which the navbar begins collapsing.
@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.
@container-tablet: (660px + @grid-gutter-width);
//** For `@screen-sm-min` and up.
@container-tablet: (720px + @grid-gutter-width);
@container-sm: @container-tablet;
@container-desktop: (880px + @grid-gutter-width);
//** For `@screen-md-min` and up.
@container-desktop: (940px + @grid-gutter-width);
@container-md: @container-desktop;
@container-large-desktop: (1080px + @grid-gutter-width);
//** For `@screen-lg-min` and up.
@container-large-desktop: (1140px + @grid-gutter-width);
@container-lg: @container-large-desktop;
//== Navbar
//
//##
@navbar-height: 50px;
@navbar-margin-bottom: @line-height-computed;
@navbar-border-radius: @border-radius-base;
@ -314,21 +180,11 @@
@navbar-inverse-toggle-hover-bg: #333;
@navbar-inverse-toggle-icon-bar-bg: #fff;
@navbar-inverse-toggle-border-color: #333;
//== Navs
//
//##
//=== Shared nav styles
@nav-link-padding: 10px 15px;
@nav-link-hover-bg: @gray-lighter;
@nav-disabled-link-color: @gray-light;
@nav-disabled-link-hover-color: @gray-light;
//== Tabs
//
//##
@nav-tabs-border-color: #ddd;
@nav-tabs-link-hover-border-color: @gray-lighter;
@nav-tabs-active-link-hover-bg: @body-bg;
@ -336,19 +192,9 @@
@nav-tabs-active-link-hover-border-color: #ddd;
@nav-tabs-justified-link-border-color: #ddd;
@nav-tabs-justified-active-link-border-color: @body-bg;
//== Pills
//
//##
@nav-pills-border-radius: @border-radius-base;
@nav-pills-active-link-hover-bg: @component-active-bg;
@nav-pills-active-link-hover-color: @component-active-color;
//== Pagination
//
//##
@pagination-color: @link-color;
@pagination-bg: #fff;
@pagination-border: #ddd;
@ -361,11 +207,6 @@
@pagination-disabled-color: @gray-light;
@pagination-disabled-bg: #fff;
@pagination-disabled-border: #ddd;
//== Pager
//
//##
@pager-bg: @pagination-bg;
@pager-border: @pagination-border;
@pager-border-radius: 15px;
@ -373,21 +214,11 @@
@pager-active-bg: @pagination-active-bg;
@pager-active-color: @pagination-active-color;
@pager-disabled-color: @pagination-disabled-color;
//== Jumbotron
//
//##
@jumbotron-padding: 30px;
@jumbotron-color: @gray-dark;
@jumbotron-bg: #fff;
@jumbotron-color: inherit;
@jumbotron-bg: @gray-lighter;
@jumbotron-heading-color: inherit;
@jumbotron-font-size: ceil((@font-size-base * 1.5));
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.
@state-success-text: #3c763d;
@state-success-bg: #dff0d8;
@state-success-border: darken(spin(@state-success-bg, -10), 5%);
@ -400,101 +231,43 @@
@state-danger-text: #a94442;
@state-danger-bg: #f2dede;
@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
//== Tooltips
//
//##
//** Tooltip max width
@tooltip-max-width: 200px;
//** Tooltip text color
@tooltip-color: #fff;
//** Tooltip background color
@tooltip-bg: #000;
@tooltip-opacity: .9;
//** Tooltip arrow width
@tooltip-arrow-width: 5px;
//** Tooltip arrow color
@tooltip-arrow-color: @tooltip-bg;
//== Popovers
//
//##
//** Popover body background color
@popover-bg: #fff;
//** Popover maximum width
@popover-max-width: 276px;
//** Popover border color
@popover-border-color: rgba(0,0,0,.2);
//** Popover fallback border color
@popover-fallback-border-color: #ccc;
//** Popover title background color
@popover-title-bg: darken(@popover-bg, 3%);
//** Popover arrow width
@popover-arrow-width: 10px;
//** Popover arrow color
@popover-arrow-color: @popover-bg;
//** Popover outer arrow width
@popover-arrow-outer-width: (@popover-arrow-width + 1);
//** Popover outer arrow color
@popover-arrow-outer-color: fadein(@popover-border-color, 5%);
//** Popover outer arrow fallback color
@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);
//== Labels
//
//##
//** Default label background color
@label-default-bg: @gray-light;
//** Primary label background color
@label-primary-bg: @brand-primary;
//** Success label background color
@label-success-bg: @brand-success;
//** Info label background color
@label-info-bg: @brand-info;
//** Warning label background color
@label-warning-bg: @brand-warning;
//** Danger label background color
@label-danger-bg: @brand-danger;
//** Default label text color
@label-color: #fff;
//** Default text color of a linked label
@label-link-hover-color: #fff;
//== Modals
//
//##
//** Padding applied to the modal body
@modal-inner-padding: 15px;
//** Padding applied to the modal title
@modal-title-padding: 15px;
//** Modal title line-height
@modal-title-line-height: @line-height-base;
//** Background color of modal content area
@modal-content-bg: #fff;
//** Modal content border color
@modal-content-border-color: rgba(0,0,0,.2);
//** Modal content border color **for IE8**
@modal-content-fallback-border-color: #999;
//** Modal backdrop background color
@modal-backdrop-bg: #000;
//** Modal backdrop opacity
@modal-backdrop-opacity: .5;
//** Modal header border color
@modal-header-border-color: #e5e5e5;
//** Modal footer border color
@modal-footer-border-color: @modal-header-border-color;
@modal-lg: 900px;
@modal-md: 600px;
@modal-sm: 300px;
//== Alerts
//
//## Define alert colors, border radius, and padding.
@alert-padding: 15px;
@alert-border-radius: @border-radius-base;
@alert-link-font-weight: bold;
@ -510,68 +283,33 @@
@alert-danger-bg: @state-danger-bg;
@alert-danger-text: @state-danger-text;
@alert-danger-border: @state-danger-border;
//== Progress bars
//
//##
//** Background color of the whole progress component
@progress-bg: #f5f5f5;
//** Progress bar text color
@progress-bar-color: #fff;
//** Variable for setting rounded corners on progress bar.
@progress-border-radius: @border-radius-base;
//** Default progress bar color
@progress-bar-bg: @brand-primary;
//** Success progress bar color
@progress-bar-success-bg: @brand-success;
//** Warning progress bar color
@progress-bar-warning-bg: @brand-warning;
//** Danger progress bar color
@progress-bar-danger-bg: @brand-danger;
//** Info progress bar color
@progress-bar-info-bg: @brand-info;
//== List group
//
//##
//** Background color on `.list-group-item`
@list-group-bg: #fff;
//** `.list-group-item` border color
@list-group-border: #ddd;
//** List group border radius
@list-group-border-radius: @border-radius-base;
//** Background color of single list items on hover
@list-group-hover-bg: #f5f5f5;
//** Text color of active list items
@list-group-active-color: @component-active-color;
//** Background color of active list items
@list-group-active-bg: @component-active-bg;
//** Border color of active list elements
@list-group-active-border: @list-group-active-bg;
//** Text color for content within active list items
@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
//** Text color of disabled list items
@list-group-disabled-color: @gray-light;
//** Background color of disabled list items
@list-group-disabled-bg: @gray-lighter;
//** Text color for content within disabled list items
@list-group-disabled-text-color: @list-group-disabled-color;
@list-group-link-color: #555;
@list-group-link-hover-color: @list-group-link-color;
@list-group-link-heading-color: #333;
//== Panels
//
//##
@panel-bg: #fff;
@panel-body-padding: 15px;
@panel-heading-padding: 10px 15px;
@panel-footer-padding: @panel-heading-padding;
@panel-border-radius: @border-radius-base;
//** Border color for elements within panels
@panel-inner-border: #ddd;
@panel-footer-bg: #f5f5f5;
@panel-default-text: @gray-dark;
@ -592,66 +330,28 @@
@panel-danger-text: @state-danger-text;
@panel-danger-border: @state-danger-border;
@panel-danger-heading-bg: @state-danger-bg;
//== Thumbnails
//
//##
//** Padding around the thumbnail image
@thumbnail-padding: 5px;
//** Thumbnail background color
@thumbnail-bg: @gray-darker;
//** Thumbnail border color
@thumbnail-border: #999;
//** Thumbnail border radius
@thumbnail-padding: 4px;
@thumbnail-bg: @body-bg;
@thumbnail-border: #ddd;
@thumbnail-border-radius: @border-radius-base;
//** Custom text color for thumbnail captions
@thumbnail-caption-color: #fff;
//** Padding around the thumbnail caption
@thumbnail-caption-padding: 7px;
//== Wells
//
//##
@well-bg: @jumbotron-bg;
@thumbnail-caption-color: @text-color;
@thumbnail-caption-padding: 9px;
@well-bg: #f5f5f5;
@well-border: darken(@well-bg, 7%);
//== Badges
//
//##
@badge-color: #fff;
//** Linked badge text color on hover
@badge-link-hover-color: #fff;
@badge-bg: @gray-light;
//** Badge text color in active nav link
@badge-active-color: @link-color;
//** Badge background color in active nav link
@badge-active-bg: #fff;
@badge-font-weight: bold;
@badge-line-height: 1;
@badge-border-radius: 10px;
//== Breadcrumbs
//
//##
@breadcrumb-padding-vertical: 8px;
@breadcrumb-padding-horizontal: 15px;
//** Breadcrumb background color
@breadcrumb-bg: #f5f5f5;
//** Breadcrumb text color
@breadcrumb-color: #ccc;
//** Text color of current page in the breadcrumb
@breadcrumb-active-color: @gray-light;
//** Textual separator for between breadcrumb elements
@breadcrumb-separator: "/";
//== Carousel
//
//##
@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
@carousel-control-color: #fff;
@carousel-control-width: 15%;
@ -660,19 +360,9 @@
@carousel-indicator-active-bg: #fff;
@carousel-indicator-border-color: #fff;
@carousel-caption-color: #fff;
//== Close
//
//##
@close-font-weight: bold;
@close-color: #000;
@close-text-shadow: 0 1px 0 #fff;
//== Code
//
//##
@code-color: #c7254e;
@code-bg: #f9f2f4;
@kbd-color: #fff;
@ -681,28 +371,13 @@
@pre-color: @gray-dark;
@pre-border-color: #ccc;
@pre-scrollable-max-height: 340px;
//== Type
//
//##
//** Horizontal offset for forms and lists.
@component-offset-horizontal: 180px;
//** Text muted color
@text-muted: @gray-light;
//** Abbreviations and acronyms border color
@abbr-border-color: @gray-light;
//** Headings small color
@headings-small-color: @gray-light;
//** Blockquote small color
@blockquote-small-color: @gray-light;
//** Blockquote font size
@blockquote-font-size: (@font-size-base * 1.25);
//** Blockquote border color
@blockquote-border-color: @gray-lighter;
//** Page header border color
@page-header-border-color: @gray-lighter;
//** Width of horizontal description list titles
@dl-horizontal-offset: @component-offset-horizontal;
//** Horizontal line color.
@hr-border: @gray-lighter;

View file

@ -1,49 +1,41 @@
{% extends 'base.html' %}
{% extends 'content_base.html' %}
{% block pageTitle %}About all the things{% endblock %}
{% block htmltitle %}About{% endblock %}
{% block headercontent %}
{% block content %}
<div class="container">
<div class="row">
<h1>About all the things</h1>
</div>
<div class="row">
<h4>So, who and/or what am I exactly? Let's find out...</h4>
</div>
{% endblock %}
{% block content%}
<div class="container">
<div class="col-sm-6">
<div class="thumbnail">
<p class="center-text mega-icon">
<span class="glyphicon glyphicon-hdd" aria-hidden="true"></span>
</p>
<div class="caption">
<h3>About Website</h3>
<p>
There are 2 parts to this, me and my website. Information for both of which is below.
Some info about my website, which clearly works well as you're using it right now!
</p>
<p>
<a href="/about/website/" class="btn btn-primary btn-block">More Info</a>
</p>
</div>
<div class="container">
<div class="row center-text">
</div>
</div>
<div class="col-sm-6">
<div class="thumbnail panel-primary">
<div class="thumbnail">
<p class="center-text mega-icon">
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
</p>
<div class="caption">
<h3>About Me</h3>
<p></p>
<p><a href="#" class="btn btn-primary btn-block btn-lg" role="button">Find out more</a></p>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="thumbnail panel-primary">
<p class="center-text mega-icon">
<span class="glyphicon glyphicon-hdd" aria-hidden="true"></span>
<p>
Some info about me. Although not very much. Because Privacy!
</p>
<p>
<a href="/about/me/" class="btn btn-primary btn-block">More Info</a>
</p>
<div class="caption">
<h3>About the website</h3>
<p></p>
<p><a href="#" class="btn btn-primary btn-block btn-lg" role="button">Find out more</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

19
templates/about/me.html Normal file
View file

@ -0,0 +1,19 @@
{% extends 'content_base.html' %}
{% block pageTitle %}About Me{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-8">
<p>Stuff</p>
</div>
<div class="col-sm-4 gh-card">
<div data-theme="medium" data-github="RealOrangeOne" class="github-card"></div>
</div>
</div>
</div>
<script async defer src="//cdn.jsdelivr.net/github-cards/latest/widget.js"></script>
{% endblock %}

View file

@ -1,54 +0,0 @@
{% extends 'base.html' %}
{% block htmltitle %}About the website{% endblock %}
{% block headercontent %}
<div class="row">
<h1>The Website</h1>
</div>
<div class="row">
<h4>Well it's obvious it works pretty damn well, you're looking at it right now!</h4>
</div>
{% endblock %}
{% block content%}
<div class="container">
<p>
My website is the culmination of all my knowledge, compiled into 1 place. It not only contains all my projects, but it in itself is a project. Making sure this website works properly is a tall order, especially considering it's self hosted. And making sure that it stays secure is also important, as it contains a large amount of personal information.
</p>
</div>
<div class="container">
<div class="row">
<div class="col-sm-4">
<img style="border-radius: 12px;" class="full-width" src="" />
</div>
<div class="col-sm-8">
<h3>The server</h3>
<p>
The server itself is a VPS hosted by Inception hosting. Obviously if I did more looking around I could probably find a slightly better deal, but these people have brilliant customer support, fast and customizable servers, that are also hosted in a data center in the UK (a major bonus)!
</p>
<p>
The spec on this server are nothing special, but considering it wouldn't be running much, other than a web server, and a couple of other applications, it's pleanty. The most important thing is that it is hosted in the UK, for connection speed, and for other applications like a VPN.
</p>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-sm-4">
<img style="border-radius: 12px;" class="full-width" src="" />
</div>
<div class="col-sm-8">
<h3>The website</h3>
<p>
The website itself is written in python, using Django, and a PostgreSQL database. Now obviously for what I need this is massivly overkill, but it means I can use the skills and shortcuts I learn at work to make a very fast and good looking website. It also means that if I ever want to expand and add new features, then with python running the back end, it's going to be very easy!
</p>
<p>
I went with the Django framework because it's what I work with at work, so I have a lot of contact with it, so exposure to bugs or clean ways to write things happen on a daily basis. I also chose it because it's written in python, one of my favourite languages, and one i'm highly fluent in. I chose PostgreSQL as a database engine because it's again what we use at work, and I already had some files preconfigured with the required config.
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,14 @@
# About my website
My website is the culmination of all my knowledge, compiled into 1 place. It not only contains all my projects, but it in itself is a project. Making sure this website works properly is a tall order, especially considering it's self hosted.
## The Website
The website itself is written in python, using the Django framework, and a SQLite database. For what I need it's more than overkill, but hey, why not!
I went with the Django framework because it's what I use with at work, as well as the fact it's simple, clean and easy. It also allows for some server side assets, eg blogging.
The only reason I have a database is because certain sections require it. For this reason I went with SQLite, because it's really lightweight and simple.
## The server
The website is hosted on my UK VPS. Previous versions have been hosted on 1&1 and MyWindowsHosting.
The Django application itself is served using waitress. This get's it's port from a custom reverse proxy allowing me to host multiple sites on a single server easily. This is the same one I use for local development. The main web-facing server is nginx, because it's simple to setup, and damn fast!

View file

@ -2,151 +2,62 @@
<!DOCTYPE html>
<html>
<head>
<title>{% block htmltitle %}{% endblock %} | TheOrangeOne</title>
<title>{{ html_title }} | TheOrangeOne</title>
<meta chatset='utf-8' />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<script type="text/javascript" src="{% static 'js/jquery.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}"/>
<link rel="shortcut icon" href=""/>
</head>
<body>
<div class="row page-width page-height" id="header" {% if header_BG %}style="background-image: url('{{ header_BG }}');" {% endif %}>
<div class="col-sm-10 col-sm-offset-1 jumbotron container">
{% block headercontent %}{% endblock %}
<body class="{{ body_class }}">
<div class="content-wrapper">
{% block baseContent%}{% endblock %}
</div>
<div class="row page-width" id="page-down">
<div class="col-md-2 col-md-offset-5">
<i class="icon ion-chevron-down h2 clickable" id="page-down-button"></i>
</div>
</div>
</div>
<div id='navbar-anchor'></div>
<div id="navbar-container" class="align h4" style="width: 96%; left: 2%; margin: 0; z-index: 10000;">
<nav class="navbar navbar-inverse" style="border-radius: 0;">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand visible-xs"><i class="icon ion-compass"></i> Navigation</a>
</div>
<div class="collapse navbar-collapse" id="navbar" style=" padding-left: 0px;">
<ul class="nav navbar-nav home-button hidden-sm">
<li class="active home"><a href="{% url 'pages:index' %}"><i class="icon ion-home"></i></a></li>
</ul>
<ul class="nav navbar-nav" id="navigation">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Projects <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li><a href="#"><i class="icon ion-social-freebsd-devil"></i> Pithos</a></li>
<li><a href="{% url 'projects:bsod-enabler'%}"><i class="icon ion-ios-monitor"></i> BSOD Enabler</a></li>
<li><a href="{% url 'projects:hipchat-emoticons' %}"><i class="icon ion-chatbox-working"></i> Hipchat Emoticons for All</a></li>
<li><a href="{% url 'setup:desk' %}"><i class="icon ion-social-windows"></i> Custom PC</a></li>
<li><a href="{% url 'projects:index' %}"><i class="icon ion-android-more-vertical"></i> All Projects...</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Code <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li><a href="#"><i class="icon ion-code-working"></i> Code Challenges</a></li>
<li><a href="{% url 'projects:morse-code-decoder' %}"><i class="icon ion-ios-circle-filled"></i> Morse Code Decoder</a></li>
<li><a href="{% url 'projects:wiki-game-solver' %}"><i class="icon ion-ios-game-controller-a"></i> The Wiki Game Solver</a></li>
<li><a href=""><span class="glyphicon glyphicon-print" aria-hidden="true"></span> Printr</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
College <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li><a href="{% url 'robotics:index' %}">Student Robotics</a></li>
<li><a href="{% url 'projects:attack-on-blocks' %}"><i class="icon ion-cube"></i> Attack on Blocks Game</a></li>
<li><a href="{% url 'college:student-server' %}"><span class="glyphicon glyphicon-console" aria-hidden="true"></span> Student Server</a></li>
<li><a href="#"><i class="icon ion-ios-paper"></i> EPQ</a></li>
<li><a href="#">Wall of Sheep</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Setup <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li><a href="{% url 'setup:desk' %}">&#128129; Desk</a></li>
<li><a href="#"><i class="icon ion-briefcase"></i> Work</a></li>
<li><a href="#"><i class="icon ion-model-s"></i> On the Go</a></li>
<li><a href="#"><i class="icon ion-android-phone-portrait"></i> Devices</a></li>
<li><a href="#"><span class="glyphicon glyphicon-console" aria-hidden="true"></span> Servers</a></li>
<li><a href="{% url 'setup:index' %}"><i class="icon ion-android-more-vertical"></i> All</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Work <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li><a href="#"><i class="icon ion-fork-repo"></i> Projects</a></li>
<li><a href="#"><i class="icon ion-android-desktop"></i> Setup</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Media <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li><a href="{% url 'media:youtube' %}"><i class="icon ion-social-youtube"></i> Youtube Channel</a></li>
<li><a href="#"><i class="icon ion-social-rss"></i> Feed</a></li>
<li><a href="{% url 'media:gallery' %}"><i class="icon ion-ios-camera"></i> Gallery</a></li>
</ul>
</li>
<li><a href="#">Links</a></li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
About <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li><a href="#"><i class="icon ion-android-person"></i> Me</a></li>
<li><a href="{% url 'pages:about-website' %}"><span class="glyphicon glyphicon-tasks" aria-hidden="true"></span> Website</a></li>
<li><a href="#"><i class="icon ion-android-contacts"></i> Contact Me</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Account <i class="icon ion-ios-arrow-up navbar-icon h4"></i>
</a>
<ul class="dropdown-menu dropup">
<li class="active hidden-xs"><a><i class="icon ion-ios-body-outline"></i> *username*</a></li>
<li><a href="#"><i class="icon ion-ios-cog-outline"></i> Preferences</a></li>
<li><a href="#"><i class="icon ion-log-in"></i> Login / Logout</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
{% block content %}{% endblock %}
{% if not no_footer %}
<footer>
<p class="center-text">Copyright &copy; Jake Howard 2015</p>
<p class="center-text footer-links">
<a href="{%url 'pages:about' %}">About</a> - <a href="">Contact</a> - <a href="">Things</a>
<div class="container">
<div class="row">
<div class="col-xs-12">
<p class="social">
<a href="{{ links.twitter }}"><i class="icon ion-social-twitter"></i></a>
<a href="{{ links.instagram }}"><i class="icon ion-social-instagram-outline"></i></a>
<a href="{{ links.reddit }}"><i class="icon ion-social-reddit"></i></a>
<a href="{{ links.youtube }}"><i class="icon ion-social-youtube"></i></a>
<a href="soon"><i class="icon ion-social-codepen"></i></a>
<a href="soon"><i class="icon ion-social-twitch-outline"></i></a>
<a href="{{ links.github }}"><i class="icon ion-social-octocat"></i></a>
</p>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<p class="bar-links">
<a href="/about/">About</a> |
<a href="{{ links.github }}/theorangeone.net" target="_blank">View Source</a>
<p>
</div>
</div>
<div class="row">
<div class="col-xs-12 powered-by">
<p>Powered by <a href="https://www.djangoproject.com/">Django</a>, <a href="https://clients.inceptionhosting.com/aff.php?aff=256">Inception Hosting</a>, and a whole heap of <a href="https://github.com/RealOrangeOne/theorangeone.net">Magic</a>!</p>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<a href="https://circleci.com/gh/RealOrangeOne/theorangeone.net" target="_blank">
<img class="ci-badge" src="https://circleci.com/gh/RealOrangeOne/theorangeone.net.svg?style=svg"/>
</a>
</div>
</div>
</div>
</footer>
{% endif %}
<script type="text/javascript" src="{% static 'js/libs.js' %}"></script>
<script type="text/javascript" src="{% static 'js/utils.js' %}"></script>
<script type="text/javascript" src="{% static 'js/app.js' %}"></script>
{% if js_redirect %}
<noscript>
<style> html, body { display:none; }</style>
<meta http-equiv="refresh" content="0.0;url={% url 'pages:no-js' %}">
<meta http-equiv="refresh" content="0.0;url=/no-js">
</noscript>
{% endif %}
</body>
</html>

18
templates/blog/post.html Normal file
View file

@ -0,0 +1,18 @@
{% extends 'content_base.html' %}
{% block pageTitle %}{{ html_title }}{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-9">
{{ blog.content | safe }}
</div>
<div class="col-sm-3">
<h5>Published: {{ blog.date }}</h5>
<h5><i class="icon ion-thumbsup"></i> {{ blog.like_count }}</h5>
<h5><a href="{{ blog.URL }}">View Post</a></h5>
</div>
</div>
</div>
{% endblock %}

View file

@ -1,60 +0,0 @@
{% extends 'base.html' %}
{% load staticfiles %}
{% block htmltitle %}Attack on Blocks{% endblock %}
{% block headercontent %}
<div class="row">
<h1>Attack on Blocks</h1>
</div>
<div class="row">
<h4>It's like the classic game 'Space Invaders', just with better music, customizable texture packs, and a couple of easter eggs...</h4>
</div>
{% endblock %}
{% block content%}
<div class="container">
<p>
Attack on Blocks is a space invaders style game that I wrote for my IT coursework, for the games development unit. We were allowed to make any game that we wanted, provided it could be done within the time limits, be very easy to play, and easily run on the college computer (which were pretty terrible). I had never written a game before, so I knew this was going to be a challenge.</p>
<p>
I decided to write the game in Python, seeing as there were other people in the class that could help me bug report and test features, and because it was easy to run on the college computers. I used PyGame for the graphics library, even though I had never used it before, because it was really simple to use, and there was a lot of support and documentation online.
</p>
</div>
<div class="container">
<h2>The Easter Eggs</h2>
<p>
One of the key features of this take on space invaders (and unfortunately the thing I spent the most time on), is the easter eggs. There are a few dotted around the game, which make the game either much easier, or way more fun! At the moment, there are 3 main easter eggs, the first enabling the other 2. If you would like to know what they are, click the button below. If not, pay the game and try and find them, or search through the source to find them (it's not too hard through the source).
</p>
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<div class="panel-primary">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
See Easter Eggs...
</a>
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body panel black-text">
<h4></h4>
<p></p>
<h4></h4>
<p></p>
<h4></h4>
<p></p>
</div>
</div>
</div>
</div>
<p>
As you will see (If and when you find the easter eggs), most of them are completely useless, and completely unrelated to the game or anything else. The main reason they were put in was because i'm friends with people that pester to the point it's just easier to give in. Hence there are some really very odd ones!
</p>
</div>
<div class="container">
<div class="btn-group btn-group-justified">
<p class="center-text">
<a class="btn btn-primary btn-lg" href="" download="Attack-on-blocks.zip">Download Attack on Blocks</a>
<a class="btn btn-default btn-lg" href="https://github.com/RealOrangeOne/attack-on-blocks">View on Github <i class="icon ion-social-github"></i></a>
</p>
</div>
</div>
{% endblock %}

View file

@ -1,40 +0,0 @@
{% extends 'base.html' %}
{% load staticfiles %}
{% block htmltitle %}Student Server | College{% endblock %}
{% block headercontent %}
<div class="row">
<h1>Student Server</h1>
</div>
<div class="row">
<h4>The first server I ever properly ran, and surprisingly it didn't really break, that much!</h4>
</div>
{% endblock %}
{% block content%}
<div class="container">
<p>
Back when I was in college, we needed a server for computing students to learn how to FTP, and script on a server using python CGI and <a href="Link to tonys php toolbox analagy">PHP</a>, as well as possibly for some students coursework. Fortunately, the college already had one, running the IT students microsite for extra course information. The problem was that it was majorly out of date, and no one really new how to use it properly. It was up to me and my friend Alex to bring the server up to date, and make it ready for the students who needed it.
</p>
</div>
<div class="container">
<p>
The original plan was to update the server's OS (at that stage running Ubuntu 12.04 LTS), install the python and PHP backends, add the users, and then make sure they couldn't edit eachothers documents. In the end Alex did a server backup, and then fully reinstalled the server OS from scratch, and then pushed the documents back on, which made our lives a lot easier.
</p>
<p>
Because he had worked with servers a lot in the past, and was already very fluent with the ubuntu terminal, he installed the software that was needed, and got it all configured properly, whilst I worked on the student logins and permission structure.
</p>
</div>
<div class="container">
<h3>User Creation</h3>
<p>
I knew we would need user accounts for the computing teachers, for the students doing A2 computing, and for updating the IT site, but I wasnt expecting this to amount to over 50 user accounts that needed to be created, and permissions setup for their accounts. It was then that I realied that I would need to write a script to do this in any useful amount of time. Fortunately Alex had started writing one with a small amount of logic, so I had something to work off to get this done, as this was my first major linux project.
</p>
<p>
The basis of the script was to load information about the users from a database I had created with all the required students in, create users based on this information, and configure the permissions for their user and their home directory. The script also allowed for manual entering of users with the same permission template, in case single users needed to be created. An additional feature that I added which has proved useful now that i've left is the ability to delete users manually, and from that original database, to make sure that no student will have access to the server once they have left, well, other than me that is!
</p>
<p>
The script I used to create these files can be found below, hosted as a gist on github. Unfortunately some of the information has been redacted to prevent giving too much information that could be considered a security threat to the server. The script may not work in this redacted state, however all the core logic has been kept.
</p>
</div>
{% endblock %}

View file

@ -0,0 +1,15 @@
# Student Server
Back when I was in college, we needed a server for computing students to learn how to use FTP, and script on a server using python CGI and [PHP](http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/#an-analogy), as well as possibly for some students coursework. Fortunately, the college already had one, running the IT students microsite for extra course information. The problem was that it was majorly out of date, and no one really new how to use it properly. It was up to me and my friend Alex to bring the server up to date, and get it ready for the students who needed it.
The original plan was to update the server's OS (at that stage running Ubuntu 12.04 LTS), install python and [PHP](http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/#an-analogy) backends, add student users, and then make sure they couldn't edit each others documents. In the end, because we had no idea how the server worked, because it was setup a long time ago, we decided it was just easier to backup what we needed, then do a complete fresh install. Meaning we could set things up exactly how we wanted them, and install the tools we needed.
## User Creation
I knew we would need user accounts for all the computing teachers, the students doing A2 computing. I wasn't expecting this to amount to over 50 user accounts that needed to be created, and permissions setup for their accounts. Fortunately Alex had started writing a basic script for this, which I quickly modified.
The basis of the script was to load information about the users from a database I had created (by hand) with all the required students in, create users based on this information, and configure the permissions for the user and their home directory. The script also allowed for manual entering of users with the same permission template, in case single users needed to be created. An additional feature that I added which has proved useful now that I've left is the ability to delete users manually, and from that original database, to make sure that no student will have access to the server once they have left, well, other than me that is!
### The script
Because a lot of the accounts are still active, and that new user accounts are being created in the same way the exact script cannot be shown, for security reasons.
## What next?
Now that I've left college, I've passed on the server to other people, although I do still have an account. From what I hear, fewer students are using the server. However, they have made the microsite look infinitely better!

Some files were not shown because too many files have changed in this diff Show more