Merge pull request #7 from RealOrangeOne/contact-page
Add basic contact page
This commit is contained in:
commit
34cab118cf
11 changed files with 124 additions and 39 deletions
|
@ -49,13 +49,13 @@ accounts:
|
|||
- fa-trello
|
||||
|
||||
freenode:
|
||||
- Freenode IRC
|
||||
- Freenode
|
||||
- TheOrangeOne
|
||||
- https://webchat.freenode.net/
|
||||
- fa-rss
|
||||
|
||||
atomio:
|
||||
- AtomIO Slack
|
||||
- Atom Slack
|
||||
- TheOrangeOne
|
||||
- https://atomio.slack.com/
|
||||
- fa-slack
|
||||
|
@ -69,14 +69,14 @@ accounts:
|
|||
codepen:
|
||||
- CodePen
|
||||
- TheOrangeOne
|
||||
- https://codepen.io/~{0}/
|
||||
- https://codepen.io/{0}/
|
||||
- fa-codepen
|
||||
|
||||
npm:
|
||||
- npm
|
||||
- TheOrangeOne
|
||||
- https://www.npmjs.com/~{0}/
|
||||
- fa-file-code-io
|
||||
- fa-file-code-o
|
||||
|
||||
footer_accounts:
|
||||
- github
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<head>
|
||||
<meta name="slug" content="about" />
|
||||
<meta name="title" content="About" />
|
||||
<meta name="title" content="About Me" />
|
||||
<meta name="no_container" content="true" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -14,36 +13,40 @@
|
|||
</div>
|
||||
<script async defer src="//cdn.jsdelivr.net/github-cards/latest/widget.js"></script>
|
||||
</section>
|
||||
<section class="bg-primary" id="website">
|
||||
<section class="bg-primary">
|
||||
<div class="container">
|
||||
<h2>Website</h2>
|
||||
<h2 class="section-heading">Personal Data</h2>
|
||||
<p>
|
||||
My website is the culmination of all my knowledge, compiled into 1 place. It not only contains all my projects, but is itself is a project.
|
||||
In the interest of privacy, there's very little personal information here.
|
||||
</p>
|
||||
<p>
|
||||
The site is primarily built with <a href="http://getpelican.com">Pelican</a>, a static site generator. This allows me to write nice clean, <i>DRY</i> content, and have it come out as clean, minified HTML.
|
||||
</p>
|
||||
<p>
|
||||
The Javascript is built using <a href="http://browserify.org/">Browserify</a>, and the CSS is built using <a href="https://github.com/sass/node-sass">node-SCSS</a>. Both are run as a build step when pelican builds.
|
||||
The information that is here is eitther not personal enough to bother protecting, or has been selectively chosen as nothing bad.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="server">
|
||||
<section>
|
||||
<div class="container">
|
||||
<h2>Server</h2>
|
||||
<h2 class="section-heading">Accounts</h2>
|
||||
<p>
|
||||
The website is hosted on part of my dedicated server from <a href="https://www.soyoustart.com/en/">SoYouStart</a>, running an Ubuntu Server VM with <a href="http://dokku.viewdocs.io/dokku/">Dokku</a> installed.
|
||||
These are all the accounts I run, all to do with various things. Take a look!
|
||||
</p>
|
||||
<p>
|
||||
The prebuilt static files are served using a <a href="https://github.com/RealOrangeOne/tstatic">custom Express server</a>, to make the site as fast and effective as possible.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="text-center">
|
||||
<div class="container">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-github btn-xl" href="https://github.com/RealOrangeOne/theorangeone.net"><i class="fa fa-github fa-lg"></i> View Source</a>
|
||||
<div class="row text-center">
|
||||
{% for key, account in ACCOUNTS.items() %}
|
||||
<div class="col-sm-3 col-xs-6">
|
||||
<div class="service-box account">
|
||||
<a href="{{ account.url }}" class="no-underline">
|
||||
<i class="fa fa-4x {{ account.icon }}"></i>
|
||||
<h3>{{ account.site }}</h3>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="bg-primary text-center">
|
||||
<div class="container">
|
||||
<a class="btn btn-primary-dark btn-xl" href="/contact/">Contact Me</a>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
|
|
27
content/pages/contact.html
Normal file
27
content/pages/contact.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
<head>
|
||||
<meta name="title" content="Contact Me" />
|
||||
<meta name="no_container" content="true" />
|
||||
</head>
|
||||
<body>
|
||||
<section>
|
||||
<div class="container">
|
||||
<p>
|
||||
The fastest way to contact me is through twitter. Just tag me or send me a message and I'll respond as soon as possible!
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="bg-primary">
|
||||
<div class="container">
|
||||
<h2 class="section-heading">Need something more formal?</h2>
|
||||
<p>
|
||||
If you need to contact me in a more formal capacity, send me an email! I aim to respond to all emails within 3 days.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="text-center">
|
||||
<div class="container">
|
||||
<a class="btn btn-primary btn-xl margin protected-mailto" data-value="{{ CONTACT_EMAIL|encode_text }}">Send me an email!</a>
|
||||
<a class="btn btn-primary btn-xl margin" href="{{ ACCOUNTS.twitter.url }}">View Twitter</a>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
|
@ -7,6 +7,7 @@ sys.path.insert(0, os.path.realpath('./'))
|
|||
AUTHOR = "Jake Howard"
|
||||
SITENAME = "TheOrangeOne"
|
||||
SITEURL = "https://theorangeone.net"
|
||||
CONTACT_EMAIL = "info@theorangeone.net"
|
||||
PATH = 'content'
|
||||
TIMEZONE = "Europe/London"
|
||||
DEFAULT_LANG = "en"
|
||||
|
@ -111,7 +112,8 @@ JINJA_FILTERS = {
|
|||
"limit": filters.limit,
|
||||
"get_title": filters.get_title,
|
||||
"get_html_title": filters.get_html_title,
|
||||
"get_image": filters.get_image
|
||||
"get_image": filters.get_image,
|
||||
"encode_text": filters.encode_text
|
||||
}
|
||||
|
||||
JINJA_ENVIRONMENT = {
|
||||
|
|
|
@ -39,3 +39,7 @@ def get_html_title(instance):
|
|||
|
||||
def get_image(instance):
|
||||
return get_attribute(instance, 'image') or (hasattr(instance, 'page') and get_attribute(instance.page, 'name')) or ''
|
||||
|
||||
|
||||
def encode_text(text):
|
||||
return " ".join([str(ord(c)) for c in text])
|
||||
|
|
|
@ -9,7 +9,7 @@ class TestClient:
|
|||
def get(self, path, JS=True):
|
||||
file_path = self.build_path(path)
|
||||
content = "".join(open(file_path).readlines())
|
||||
if path.endswith('html'):
|
||||
if file_path.endswith('html'):
|
||||
content = BeautifulSoup(content, 'html.parser')
|
||||
if JS:
|
||||
for script in content(["noscript"]): # Remove noscript tags
|
||||
|
@ -19,6 +19,8 @@ class TestClient:
|
|||
def build_path(self, path):
|
||||
if path.startswith('/'):
|
||||
path = path[1:]
|
||||
if path.endswith('/'):
|
||||
path += 'index.html'
|
||||
return os.path.join(self.output_path, path)
|
||||
|
||||
def exists(self, path):
|
||||
|
|
|
@ -96,5 +96,11 @@ class TestClientTestCase(TestCase):
|
|||
def test_file_exists(self):
|
||||
self.assertTrue(self.client.exists('index.html'))
|
||||
|
||||
def test_build_path_without_index(self):
|
||||
self.assertEqual(
|
||||
self.client.build_path('foo/'),
|
||||
self.client.build_path('foo/index.html')
|
||||
)
|
||||
|
||||
def test_file_doesnt_exist(self):
|
||||
self.assertFalse(self.client.exists('foo.bar'))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from tests import TestCase
|
||||
from config import social as social_settings
|
||||
import pelicanconf as settings
|
||||
import os.path
|
||||
|
||||
|
||||
|
@ -47,18 +48,6 @@ class AboutPageTestCase(TestCase):
|
|||
self.assertHeaderTitle(content, 'About')
|
||||
self.assertTitle(content, 'About')
|
||||
|
||||
def test_website_section(self):
|
||||
content = self.client.get('about/index.html')
|
||||
section = content.find('section', id='website')
|
||||
subtitle = section.find('h2')
|
||||
self.assertEqual('Website', self.get_children(subtitle))
|
||||
|
||||
def test_server_section(self):
|
||||
content = self.client.get('about/index.html')
|
||||
section = content.find('section', id='server')
|
||||
subtitle = section.find('h2')
|
||||
self.assertEqual('Server', self.get_children(subtitle))
|
||||
|
||||
def test_github_card(self):
|
||||
content = self.client.get('about/index.html')
|
||||
tags = content.find_all('div', class_='github-card')
|
||||
|
@ -67,6 +56,33 @@ class AboutPageTestCase(TestCase):
|
|||
self.assertEqual('medium', tag.attrs['data-theme'])
|
||||
self.assertEqual(social_settings['accounts']['github'][1], tag.attrs['data-github'])
|
||||
|
||||
def test_accounts(self):
|
||||
content = self.client.get('about/index.html')
|
||||
accounts = content.find_all('div', class_='account')
|
||||
defined_accounts = [s for k, s in settings.ACCOUNTS.items()]
|
||||
self.assertEqual(len(accounts), len(defined_accounts))
|
||||
site_names = [s['site'] for s in defined_accounts]
|
||||
urls = [s['url'] for s in defined_accounts]
|
||||
icons = [s['icon'] for s in defined_accounts]
|
||||
for account in accounts:
|
||||
self.assertIn(account.find('a').attrs['href'], urls)
|
||||
self.assertIn(account.find('i').attrs['class'][-1], icons)
|
||||
self.assertIn(self.get_children(account.find('h3')), site_names)
|
||||
|
||||
|
||||
class ContactPageTestCase(TestCase):
|
||||
def test_title(self):
|
||||
content = self.client.get('contact/')
|
||||
self.assertHeaderTitle(content, 'Contact Me')
|
||||
self.assertTitle(content, 'Contact Me')
|
||||
|
||||
def test_contact_links(self):
|
||||
content = self.client.get('contact/')
|
||||
links = content.find_all('section')[2].find_all('a')
|
||||
self.assertEqual(links[1].attrs['href'], settings.ACCOUNTS['twitter']['url'])
|
||||
decoded_value = ''.join([chr(int(c)) for c in links[0].attrs['data-value'].split(' ')])
|
||||
self.assertEqual(decoded_value, settings.CONTACT_EMAIL)
|
||||
|
||||
|
||||
class Page404TestCase(TestCase):
|
||||
def test_title(self):
|
||||
|
|
|
@ -30,3 +30,14 @@ $('.navbar-brand').bind('click', function (event) {
|
|||
}
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
|
||||
$('.protected-mailto').bind('click', function (evt) {
|
||||
evt.preventDefault();
|
||||
var char_codes = $(this).data('value').split(' ');
|
||||
var plain_text = [];
|
||||
for (var i = 0; i < char_codes.length; i++) {
|
||||
plain_text.push(String.fromCharCode(parseInt(char_codes[i], 10)));
|
||||
}
|
||||
window.location = 'mailto:' + plain_text.join('');
|
||||
});
|
||||
|
|
|
@ -16,3 +16,7 @@
|
|||
|
||||
padding: 0 $grid-gutter-width / 2;
|
||||
}
|
||||
|
||||
a.no-underline:hover {
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
|
|
@ -110,3 +110,13 @@ header#header {
|
|||
.github-card-container > iframe {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.protected-mailto {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.service-box.account {
|
||||
a:hover {
|
||||
color: $brand-orange-dark;
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue