moved admin views to brain, seperated front end code and styles to seperate src folder

This commit is contained in:
Ro 2019-11-21 22:36:18 -08:00
parent 4bde21599e
commit 18ba90b310
42 changed files with 3067 additions and 4 deletions

View file

@ -11,7 +11,7 @@ var theme = 'default-dark';
var app = express();
//var request = require('request');
// view engine setup
app.set('views', path.join(__dirname, '../content/themes'));
app.set('views', path.join(__dirname, './views'));
app.set('view engine', 'pug');
app.use(logger('dev'));

View file

@ -16,7 +16,7 @@ router.get('/', function(req, res) {
pageData = { title: settings.title, status: false, pages: result };
}
res.render(settings.admin_theme + '/index', pageData);
res.render('index', pageData);
});
});

View file

@ -0,0 +1,94 @@
doctype strict
head
meta(http-equiv='Content-Type' content='text/html; charset=utf-8')
meta(name='viewport' content='width=device-width, initial-scale=1.0')
title #{title}
style(type='text/css').
/* reset */
#outlook a {
padding: 0;
}
/* Force Outlook to provide a "view in browser" menu link. */
.ExternalClass {
width: 100%;
}
/* Force Hotmail to display emails at full width */
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
/* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
p {
margin: 0;
padding: 0;
font-size: 0px;
line-height: 0px;
}
/* squash Exact Target injected paragraphs */
table td {
border-collapse: collapse;
}
/* Outlook 07, 10 padding issue fix */
table {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
/* remove spacing around Outlook 07, 10 tables */
/* bring inline */
img {
display: block;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
a img {
border: none;
}
a {
text-decoration: none;
color: #000001;
}
/* text link */
a.phone {
text-decoration: none;
color: #000001 !important;
pointer-events: auto;
cursor: default;
}
/* phone link, use as wrapper on phone numbers */
span {
font-size: 13px;
line-height: 17px;
font-family: monospace;
color: #000001;
}
//if gte mso 9
style.
/* Target Outlook 2007 and 2010 */
// body wrapper
table(cellpadding='0' cellspacing='0' border='0' style='margin:0; padding:0; width:100%; line-height: 100% !important;')
tr
td(valign='top')
// edge wrapper
table(cellpadding='0' cellspacing='0' border='0' align='center' width='600' style='background: #374857;')
tr
td(valign='top' style='vertical-align: top;')
// /////////////////////////////////////////////////////
table(cellpadding='0' cellspacing='0' border='0' align='center' style='width:100%')
tr
td(valign='top' style='vertical-align: top;text-align: center; padding: 10px')
span(style='font-family: Arial,Helvetica Neue,Helvetica,sans-serif; color:#f5ab35; font-size:20px; font-weight: bold;')
| #{header}
tr
td(valign='top' style='vertical-align: top; background: #161d23; padding:10px;')
span(style='font-family: Arial,Helvetica Neue,Helvetica,sans-serif; color:#cecece; font-size:16px;')
| #{content}
tr
td(valign='top' style='vertical-align: top; padding: 10px;')
span(style='font-family: Arial,Helvetica Neue,Helvetica,sans-serif; color:#b2cce5; font-size:12px;')
| #{footer}

28
brain/views/frame.pug Normal file
View file

@ -0,0 +1,28 @@
doctype html
html(xmlns='http://www.w3.org/1999/xhtml', lang='en', xml:lang="en")
head
title= title
meta(content="text/html;charset=utf-8", http-equiv="Content-Type")
meta(meta content="utf-8", http-equiv="encoding")
meta(name='viewport', content='width=device-width, initial-scale=1.0')
meta(name="keywords" content="creative technoglogist, graphic design, web development, designer developer, social thought, political discussion, music producer, creative culture, black creative, black geek")
meta(name="description" content="The home site of Creative Technologist, music maker, and social philoshoper, Ro. Ha, I know. Me too.")
meta(http-equiv="content-type", content="text/html; charset=utf-8")
//meta(property="og:image" content="https://thetwelfth.house/base-assets/images/current.png")
//meta(name="twitter:image" content="https://thetwelfth.house/base-assets/images/current.png")
link(rel='stylesheet', href="/assets/css/dash.css", type='text/css')
body
#loader
i.fa.fa-cog.fa-spin.fa-4x.fa-fw
.main-container#main-content
section#dash-index-content
header#header
#wrapper
#left
a(href="/@/dashboard")
img#the-logo(src="/assets/images/global/the-logo.svg")
block main-content
script(src='/assets/scripts/dashkit.min.js' type="text/javascript")
script(src='/assets/scripts/dash.min.js' type="text/javascript")

9
brain/views/index.pug Normal file
View file

@ -0,0 +1,9 @@
extends frame
block main-content
#dash-index
#dash-index-wrapper
-if(!status)
include partials/login
-else
include partials/front

View file

@ -0,0 +1,16 @@
extends frame
block main-content
#nav-index
#nav-index-wrapper
#nav-pages
- var index = 0;
- for ( index; index < pages.length; index++)
.nav-item(id=pages[index].id, data-slug=pages[index].slug, data-uuid=pages[index].uuid)
svg#item-arrows(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-select-arrows')
label
= pages[index].title
#nav-btns
button.nav-btn#edit-item(data-id=pages[index].uuid) EDIT
button.nav-btn#remove-item(data-id=pages[index].id) REMOVE

View file

@ -0,0 +1,4 @@
#dash-menu
a#settings(href="/@/dashboard/settings") Settings
| .
a#navigation(href="/@/dashboard/navigation") Navigation

View file

@ -0,0 +1,37 @@
#edit-control
button#edit-bold.content-editor-btn-text.editor-button(title="bold")
| B
button#edit-italic.content-editor-btn-text.editor-button(title="italics")
| I
button#edit-strikethrough.content-editor-btn-text.editor-button(title="strikethrough")
| S
button#edit-link.content-editor-btn-icon.editor-button(title="insert link")
svg#edit-link(viewBox="0 0 20 20" class="icons")
use#edit-link(xlink:href='/dash/assets/images/sprite.svg#entypo-link')
button#edit-header1.content-editor-btn-text.editor-button(title="header 1")
| H1
button#edit-header2.content-editor-btn-text.editor-button(title="header 2")
| H2
button#edit-header3.content-editor-btn-text.editor-button(title="header 3")
| H3
button#edit-image.content-editor-btn-icon.editor-button(title='insert image')
svg#edit-image(viewBox="0 0 20 20" class="icons")
use#edit-image(xlink:href='/dash/assets/images/sprite.svg#entypo-image')
if(edit)
button#edit-update.post-sumbit-btn.submit-start.editor-button(data-action='blog-update' data-id=post.id type='submit')
svg#submit-update(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/dash/assets/images/sprite.svg#entypo-save' data-action='blog-update' data-id=post.id)
svg#submit-good.icon-hide(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-thumbs-up')
svg#submit-error.icon-hide(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-thumbs-down')
button#edit-delete.content-editor-btn-icon.editor-button.submit-delete(for="post-delete" title='delete post')
svg#edit-delete(viewBox="0 0 20 20" class="icons")
use#edit-delete(xlink:href='/dash/assets/images/sprite.svg#entypo-cross')
else
button#edit-save.post-sumbit-btn.submit-start.editor-button(data-action='blog-add' type='submit')
svg#submit-save(viewBox="0 0 20 20" class="icons")
use#submit-save(xlink:href='/dash/assets/images/sprite.svg#entypo-plus' data-action='blog-add')

View file

@ -0,0 +1,20 @@
#dash-recent
#recent-list
.recent-header
h3 Recent
.index-menu
a(href='/@/dashboard/posts/list') View Posts
| .
a(href='/@/dashboard/posts/add/new') Create Post
br
- var index = 0;
- var cap = 5; // number of posts to display, get rid of this and put it in the config
if(pages.length == 0)
label this is empty
else
- for ( index; index < pages.length; index++)
a.post-link(href="/@/dashboard/posts/edit/"+pages[index].metadata.uuid id=pages[index].metadata.uuid style="background:url("+pages[index].metadata.feature+") no-repeat center center / cover")
div
label= pages[index].metadata.title
span= pages[index].metadata.created

View file

@ -0,0 +1,7 @@
#dash-login
.dash-form#dash-form
form(id="login" class='login', name="login" action="/@/dashboard/login" method="POST")
input(type='text', name='handle' class='form-control', placeholder='handle', required, autofocus)
input(type='password', name='password' class='form-control', placeholder='password', required)
button(id="login-btn", class='login-btn', type='submit') SUBMIT YOUR STUFF

View file

@ -0,0 +1,25 @@
-if(settings.email.active == "option-smtp")
#mail-smtp(data-enabled='true')
input(type='text', name='smtp-domain' id='smtp-domain', placeholder='domain', value=settings.email.smtp.domain autofocus)
input(type='text', name='smtp-email' id='smtp-email', placeholder='email', value=settings.email.smtp.email , autofocus)
input(type='text', name='smtp-pass' id='smtp-pass', placeholder='password', value=settings.email.smtp.password , autofocus)
#mail-mg(data-enabled='false')
input(type='text', name='mg-domain' id='mg-domain', placeholder='domain', value=settings.email.mailgun.domain autofocus)
input(type='text', name='mg-key' id='mg-key', placeholder='api key', value=settings.email.mailgun['api-key'] , autofocus)
-else if(settings.email.active == "option-mg")
#mail-smtp(data-enabled='false')
input(type='text', name='smtp-domain' id='smtp-domain', placeholder='domain', value=settings.email.smtp.domain autofocus)
input(type='text', name='smtp-email' id='smtp-email', placeholder='email', value=settings.email.smtp.email , autofocus)
input(type='text', name='smtp-pass' id='smtp-pass', placeholder='password', value=settings.email.smtp.password , autofocus)
#mail-mg(data-enabled='mg')
input(type='text', name='mg-domain' id='mg-domain', placeholder='domain', value=settings.email.mailgun.domain autofocus)
input(type='text', name='mg-key' id='mg-key', placeholder='api key', value=settings.email.mailgun['api-key'] , autofocus)
-else
#mail-smtp(data-enabled='false')
input(type='text', name='smtp-domain' id='smtp-domain', placeholder='domain', value=settings.email.smtp.domain autofocus)
input(type='text', name='smtp-email' id='smtp-email', placeholder='email', value=settings.email.smtp.email , autofocus)
input(type='text', name='smtp-pass' id='smtp-pass', placeholder='password', value=settings.email.smtp.password , autofocus)
#mail-mg(data-enabled='false')
input(type='text', name='mg-domain' id='mg-domain', placeholder='domain', value=settings.email.mailgun.domain autofocus)
input(type='text', name='mg-key' id='mg-key', placeholder='api key', value=settings.email.mailgun['api-key'] , autofocus)

75
brain/views/post-edit.pug Normal file
View file

@ -0,0 +1,75 @@
extends frame
block main-content
// move this to backend
-var post_title = ''
-var post_plaintext = ''
-var post_feature = 'null'
-var post_tags = ''
-var post_id = ''
-var post_date = date
-var post_status = ['false', 'false', 'false',]
if(edit)
-post_title = post.title
-post_plaintext = post.plaintext
-post_feature = feature
-post_tags = post.tags
-post_date = date
-post_status = status
#post-edit-index(data-index=id)
#post-edit-index-wrapper
//h2 EDIT
=post_title
#post-feature
//label FEATURE IMAGE
if(post_feature == 'null')
#featured-image-drop
| DRAG AND DROP IMAGE OR
label(for="featured-image-upload") CLICK TO CHOOSE
else
#featured-new-image-btn
button#new-feature-upload
svg#new-feature-upload(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-image-inverted')
#featured-image-drop
img(src=post_feature)
#post-header.columns
#post-title.column
textarea(id="post_title" type='text', name='post_title' class='post-edit', placeholder='title', required, autofocus)
=post_title
#calendar-icon
svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-calendar')
input(id="post-date" type="text" value=post_date)
#post-options
button#option-page.option-inactive.post-option-btn(data-active= status[0])
svg#option-page-icon(viewBox="0 0 20 20" class="icons")
use#option-page-icon(xlink:href='/dash/assets/images/sprite.svg#entypo-pin')
button#option-feature.option-inactive.post-option-btn(data-active= status[1])
svg#option-feature-icon(viewBox="0 0 20 20" class="icons")
use#option-feature-icon(xlink:href='/dash/assets/images/sprite.svg#entypo-star')
button#option-published.option-inactive.post-option-btn(data-active= status[2])
svg#option-published-icon(viewBox="0 0 20 20" class="icons")
use#option-published-icon(xlink:href='/dash/assets/images/sprite.svg#entypo-globe')
button#option-preview.option-inactive(data-active="false")
svg#option-preview-icon(viewBox="0 0 20 20" class="icons")
use#option-preview-icon(xlink:href='/dash/assets/images/sprite.svg#entypo-eye')
#post-meta.column
textarea(id='post_tags' type='text', name='post_tags' class='form-control', placeholder='tags [comma seperated]', autofocus)
=post_tags
include partials/editor
input(id="featured-image-upload" type="file" name="featured-image-upload")
input(id="post-image-upload" type="file" name="post-image-upload")
#edit-post
#edit-post-wrapper
pre
code#edit-post-text(contenteditable="true") !{colored}

View file

@ -0,0 +1,48 @@
extends frame
block main-content
#post-index
#post-index-wrapper
#post-index-menu
- if(postFilter=='all')
a.current-filter(href="/@/dashboard/posts/list/all")= "All Posts ("+page_info.all+")"
- else
a(href="/@/dashboard/posts/list/all")= "All Posts ("+page_info.all+")"
| .
- if(postFilter=='published')
a.current-filter(href="/@/dashboard/posts/list/published")= "Published ("+page_info.published+")"
- else
a(href="/@/dashboard/posts/list/published")= "Published ("+page_info.published+")"
| .
- if(postFilter=='deleted')
a.current-filter(href="/@/dashboard/posts/list/deleted")= "Deleted ("+page_info.deleted+")"
- else
a(href="/@/dashboard/posts/list/deleted")= "Deleted ("+page_info.deleted+")"
a.add-new-post(href="/@/dashboard/posts/add/new") +
label Create New Post
#posts-list
- var index = 0;
- for ( index; index < items.length; index++)
a.post-link(href="/@/dashboard/posts/edit/"+items[index].post.uuid id=items[index].post.uuid)
div.post-bg(style="background: #fc6399 url("+items[index].post.feature.substr(8)+") no-repeat center center / cover")
label= items[index].post.title
span= items[index].post.created
p= items[index].post.plaintext.substr(0, 200)+"..."
- var next = parseInt(page_index, 10) + 1
- var prev = parseInt(page_index, 10) - 1
- if(next > page_count) next = 1
- if(prev <= 0) prev = page_count
br
a.page-btns(href="/@/dashboard/posts/list/"+postFilter+"/"+prev)
svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-chevron-left')
span.paginate= "PAGE "+page_index+" OF "+page_count
a.page-btns(href="/@/dashboard/posts/list/"+postFilter+"/"+next)
svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-chevron-right')

63
brain/views/settings.pug Normal file
View file

@ -0,0 +1,63 @@
extends frame
block main-content
#site-background
label FEATURE SITE IMAGE
img#background(src=settings.background, alt="image for site background", for="background-upload")
input(id="background-upload" type="file" name="backgrond-upload")
#settings-index
#settings-index-wrapper
#member-settings.columns
#member-settings-1.column
label AVATAR
#member-avatar-drop
img#avatar(src=member.avi, for="avatar-upload")
button#save-toggle SAVE SETTINGS
input(id="avatar-upload" type="file" name="avatar-upload")
#member-settings-2.column
label INFO
#member-info
input(type='text', name='handle' id='settings-handle', placeholder='handle', value=member.handle, autofocus)
input(type='text', name='email' id='settings-email', placeholder='email', value=member.email, autofocus)
input(type='text', name='base-url' id='settings-url', placeholder='url', value=settings.url, autofocus)
input(type='text', name='base-title' id='settings-title', placeholder='site title', value=settings.title, autofocus)
textarea(id="settings-desc" type='text', name='settings_desc' class='settings-dec', placeholder='description stuff', autofocus)
=settings.description
button#privacy-toggle(data-private=settings.private)
-if (settings.private == 'false')
| SITE IS PRIVATE
-else
| SITE IS PUBLIC
#option-settings.columns
#theme-settings.column
label THEMES
br
- var index = 0;
- for ( index; index < themes.length; index++)
-if(themes[index].current == "true")
a.theme-select(href="#" id=themes[index].theme.name, data-enabled="true")
= themes[index].theme["display-name"]
//svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-check')
-else
a.theme-select(href="#" id=themes[index].theme.name, data-enabled="false")
= themes[index].theme["display-name"]
#mail-settings.column
label E-MAIL
-if(settings.email.active == "option-none")
a.mail-option#option-none(href="#", data-enabled='true') NONE
-else
a.mail-option#option-none(href="#", data-enabled='false') NONE
-if(settings.email.active == "option-mg")
a.mail-option#option-mg(href="#", data-enabled='true') MAILGUN
-else
a.mail-option#option-mg(href="#", data-enabled='false') MAILGUN
-if(settings.email.active == "option-smtp")
a.mail-option#option-smtp(href="#", data-enabled='true') SMTP
-else
a.mail-option#option-smtp(href="#", data-enabled='false') SMTP
include partials/mailforms
button#send-mail TEST MAIL

View file

@ -81,5 +81,6 @@ function onError(error) {
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
console.log('Up and runnin on port: ' + addr.port);
debug('Listening on ' + bind);
}

View file

@ -12,8 +12,8 @@
"debug": "nodemon inspect -r esm init.js --ignore node_modules/ -e js",
"watch-front": "stylus -w -m -o themes/$npm_package_theme/assets/css themes/$npm_package_theme/src/styles/base.styl & parcel watch themes/$npm_package_theme/src/com/Start.js --out-dir themes/$npm_package_theme/assets/js --out-file start.min.js --public-url /$npm_package_theme/assets/js",
"build-front-kit": "uglifyjs node_modules/scramble-text/dist/ScrambleText.min.js node_modules/animejs/anime.min.js node_modules/reframe.js/dist/reframe.min.js -c -o themes/$npm_package_theme/assets/js/toolkit.min.js",
"watch-back": "stylus -w -m -o public/assets/css content/themes/dash/src/styles/dash.styl & parcel watch content/themes/dash/src/com/Start.js --out-dir public/assets/scripts --out-file dash.min.js --public-url /assets/scripts",
"build-back-kit": "uglifyjs themes/dash/src/libraries/highlight.pack.js node_modules/sortablejs/Sortable.min.js node_modules/scramble-text/dist/ScrambleText.min.js node_modules/animejs/anime.min.js node_modules/reframe.js/dist/reframe.min.js -c -o themes/dash/assets/js/dashkit.min.js"
"watch-back": "stylus -w -m -o public/assets/css src/styles/dash.styl & parcel watch src/com/Start.js --out-dir public/assets/scripts --out-file dash.min.js --public-url /assets/scripts",
"build-back-kit": "uglifyjs src/libraries/highlight.pack.js node_modules/sortablejs/Sortable.min.js node_modules/scramble-text/dist/ScrambleText.min.js node_modules/animejs/anime.min.js node_modules/reframe.js/dist/reframe.min.js -c -o themes/dash/assets/js/dashkit.min.js"
},
"engines": {
"node": ">=10.16.0"

63
src/com/Base.js Normal file
View file

@ -0,0 +1,63 @@
import DataUtils, { REQUEST_TYPE_POST, CONTENT_TYPE_JSON } from '../../brain/utils/tools/DataUtils';
import * as DataEvent from '../../brain/utils/events/DataEvent';
import DashManager from './controllers/DashManager';
//import DBUtils from '../../../../../brain/utils/tools/DBUtils';
const dataUtils = new DataUtils();
export default class Base {
//--------------------------
// constructor
//--------------------------
constructor() {
this.start();
}
//--------------------------
// methods
//--------------------------
start() {
if (document.getElementById('dash-form')) {
document
.getElementById('login-btn')
.addEventListener('click', e => this.handleLogin(e));
} else {
let dm = new DashManager();
}
}
//--------------------------
// event handlers
//--------------------------
handleLogin(e) {
e.stopPropagation();
e.preventDefault();
let authForm = dataUtils.formDataToJSON(document.getElementById('login'));
dataUtils
.request(
'/api/v1/auth/login',
DataEvent.AUTH_STATUS,
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON,
authForm
)
.then(r => {
let response = JSON.parse(r.request['response']);
if (response.type === DataEvent.REQUEST_LAME) {
e.target.innerHTML = response.message;
setTimeout(() => {
e.target.innerHTML = 'TRY IT AGAIN, HOMIE';
}, 1500);
//console.log('NOPE', response.message);
//self.dashManager = new DashManager();
} else {
e.target.innerHTML = response.message;
setTimeout(() => {
window.location = '/@/dashboard';
}, 500);
}
})
.catch(err => {
//console.log(err);
});
}
}

6
src/com/Start.js Normal file
View file

@ -0,0 +1,6 @@
import Base from './Base'
document.addEventListener('DOMContentLoaded', function() {
var base = new Base();
}, false);

39
src/com/actions/Mailer.js Normal file
View file

@ -0,0 +1,39 @@
import DataUtils, {
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON
} from '../../../brain/utils/tools/DataUtils';
import * as DataEvent from '../../../brain/utils/events/DataEvent';
export default class Mailer {
//--------------------------
// constructor
//--------------------------
constructor() {
this.dataUtils = new DataUtils();
}
//--------------------------
// methods
//--------------------------
sendMail() {
var self = this;
let mailData = {
content: 'This is a test email'
};
self.dataUtils
.request(
'/api/mail',
DataEvent.SETTINGS_UPDATED,
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON,
mailData
)
.then(() => {
//console.log(response);
})
.catch(() => {
//console.log(err);
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -0,0 +1,62 @@
import DataUtils, {
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON
} from '../../../brain/utils/tools/DataUtils';
import DateUtils from '../../../brain/utils/tools/DateUtils';
import * as DataEvent from '../../../brain/utils/events/DataEvent';
import DBUtils from '../../../brain/utils/tools/DBUtils';
export default class NavActions {
//--------------------------
// constructor
//--------------------------
constructor() {
this.dataUtils = new DataUtils();
this.dateUtils = new DateUtils();
this.dbutils = new DBUtils();
}
//--------------------------
// methods
//--------------------------
save() {
let self = this;
let navData = [];
let items = document.getElementById('nav-pages').children;
for (let index = 0; index < items.length; index++) {
navData.push({
title: items[index].getElementsByTagName('label')[0].innerHTML,
id: items[index].id,
slug: items[index].getAttribute('data-slug'),
uuid: items[index].getAttribute('data-uuid')
});
}
return new Promise(function(resolve, reject) {
self.dataUtils
.request(
'/api/settings/nav-sync',
DataEvent.SETTINGS_UPDATED,
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON,
navData
)
.then(response => {
resolve(response);
})
.catch(err => {
reject(err);
});
});
}
removeItem(id) {
let self = this;
this.dbutils.getPost(id).then(post => {
post.post.page = 'false';
self.dbutils.modify(id, post.post).then(() => {
document.getElementById('nav-pages').removeChild(document.getElementById(id));
self.save();
});
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -0,0 +1,155 @@
import DataUtils, {
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON
} from '../../../brain/utils/tools/DataUtils';
import StringUtils from '../../../brain/utils/tools/StringUtils';
import DateUtils from '../../../brain/utils/tools/DateUtils';
import DBUtils from '../../../brain/utils/tools/DBUtils';
var uuidv4 = require('uuid/v4');
import * as DataEvent from '../../../brain/utils/events/DataEvent';
export default class PostActions {
//--------------------------
// constructor
//--------------------------
constructor() {
this.dataUtils = new DataUtils();
this.dateUtils = new DateUtils();
this.dbUtils = new DBUtils();
}
//--------------------------
// methods
//--------------------------
update(id, data, files, lastKey) {
let self = this;
let freshData;
return new Promise(function(resolve, reject) {
let txt = document.createElement('textarea');
txt.innerHTML = document.getElementById('edit-post-text').innerHTML;
let html = txt.value;
html = html.replace(/<\/?span[^>]*>/g, ''); //removes highightjs styling
html = html.replace(/<\/?br[^>]*>/g, '\n'); //convert back to encoded line break for storage
data.title = document.getElementById('post_title').value;
data.slug = new StringUtils().cleanString(document.getElementById('post_title').value);
data.plaintext = html;
data.html = html;
data.created = document.getElementById('post-date').value;
data.tags = document.getElementById('post_tags').value;
data.page = document.getElementById('option-page').getAttribute('data-active');
data.featured = document.getElementById('option-feature').getAttribute('data-active');
data.published = document
.getElementById('option-published')
.getAttribute('data-active');
if (files.length != 0) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
// Check the file type.
if (!file.type.match('image.*')) {
continue;
}
data.feature =
'/content/blog-images/' +
self.dateUtils.getDate('year', new Date()) +
'/' +
self.dateUtils.getDate('month', new Date()) +
'/' +
file.name;
}
} else {
if (typeof data.feature == 'undefined') data.feature = '';
}
if (id == null) {
freshData = {
id: lastKey + 1,
post: {
uuid: uuidv4(),
title: data.title,
slug: data.slug,
plaintext: data.plaintext,
html: data.html,
feature: data.feature,
created: data.created,
tags: data.tags,
page: data.page,
featured: data.featured,
published: data.published,
deleted: '',
author: 'user'
}
};
} else {
freshData = data;
}
self.dbUtils
.modify(id, freshData)
.then(response => {
resolve(response);
if (id != null)
freshData.page == 'true'
? self.updateNav(true, id, freshData)
: self.updateNav(false, id, freshData);
})
.catch(err => {
reject(err);
});
});
}
deletePost(id, body) {
let self = this;
body.deleted = new Date().toString();
return new Promise(function(resolve, reject) {
self.dbUtils
.archivePost(id, body)
.then(response => {
//console.log(response);
resolve(response);
})
.catch(err => {
//console.log(err);
reject(err);
});
});
}
updateNav(add, id, post) {
var self = this;
this.dataUtils
.request('/api/settings/nav', DataEvent.SETTINGS_LOADED)
.then(response => {
let menu = JSON.parse(response.request['response']);
let item = {
id: id,
uuid: post.uuid,
title: post.title,
slug: post.slug
};
if (add) {
menu.push(item);
} else {
for (let index = 0; index < menu.length; index++) {
if (menu[index].id == id) {
menu.splice(index, 1);
}
}
}
self.dataUtils
.request(
'/api/settings/nav-sync',
DataEvent.SETTINGS_UPDATED,
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON,
menu
)
.then(() => {
//console.log(response);
})
.catch(() => {
//console.log(err);
});
})
.catch(() => {
//console.log(err);
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -0,0 +1,88 @@
import DataUtils, {
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON
} from '../../../brain/utils/tools/DataUtils';
import DateUtils from '../../../brain/utils/tools/DateUtils';
import * as DataEvent from '../../../brain/utils/events/DataEvent';
export default class SettingsActions {
//--------------------------
// constructor
//--------------------------
constructor() {
this.dataUtils = new DataUtils();
this.dateUtils = new DateUtils();
}
//--------------------------
// methods
//--------------------------
save() {
let self = this;
let handle = document.getElementById('settings-handle').value;
let email = document.getElementById('settings-email').value;
let url = document.getElementById('settings-url').value;
let title = document.getElementById('settings-title').value;
let desc = document.getElementById('settings-desc').innerHTML;
let privacy = document.getElementById('privacy-toggle').getAttribute('data-private');
let background = document.getElementById('background').src;
let selected = '';
let selects = document.querySelectorAll('.theme-select');
let smtpDomain = document.getElementById('smtp-domain').value;
let smtpEmail = document.getElementById('smtp-email').value;
let smtpPass = document.getElementById('smtp-pass').value;
let mgDomain = document.getElementById('mg-domain').value;
let mgKey = document.getElementById('mg-key').value;
let mailActive = '';
let mailOptions = document.querySelectorAll('.mail-option');
var i, count;
for (i = 0, count = selects.length; i < count; i++) {
if (selects[i].getAttribute('data-enabled') == 'true') selected = selects[i].id;
}
for (i = 0, count = mailOptions.length; i < count; i++) {
if (mailOptions[i].getAttribute('data-enabled') == 'true')
mailActive = mailOptions[i].id;
}
let settingsData = {
handle: handle,
email: email,
url: url,
title: title,
descriptions: desc,
background: background,
private: privacy,
theme: selected,
mailSettings: {
activeProtocol: mailActive,
smtp: {
domain: smtpDomain,
email: smtpEmail,
password: smtpPass
},
mailgun: {
domain: mgDomain,
key: mgKey
}
}
};
return new Promise(function(resolve, reject) {
self.dataUtils
.request(
'/api/settings/sync',
DataEvent.SETTINGS_UPDATED,
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON,
settingsData
)
.then(response => {
//console.log("RESPONSE", response)
resolve(response);
})
.catch(err => {
reject(err);
});
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -0,0 +1,41 @@
import PostIndex from './PostIndex';
import SettingsIndex from './SettingsIndex';
import NaviIndex from './NavIndex';
export default class DashManager {
//--------------------------
// constructor
//--------------------------
constructor() {
this.currentDisplay = '';
this.urlPieces = document.URL.split('/');
this.chooseDisplay(this.urlPieces[5], this.urlPieces[6]);
}
//--------------------------
// methods
//--------------------------
start() {}
chooseDisplay(section, page) {
this.currentDisplay = '';
switch (section) {
case 'posts':
this.currentDisplay = new PostIndex(page);
break;
case 'settings':
this.currentDisplay = new SettingsIndex();
break;
case 'navigation':
this.currentDisplay = new NaviIndex();
break;
default:
//just chill
break;
}
this.start();
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -0,0 +1,48 @@
import NavActions from '../actions/NavActions';
import DBUtils from '../../../brain/utils/tools/DBUtils';
export default class NavIndex {
//--------------------------
// constructor
//--------------------------
constructor() {
this.start();
//this.dataUtils = new DataUtils();
this.dbutils = new DBUtils();
}
//--------------------------
// methods
//--------------------------
start() {
Sortable.create(document.getElementById('nav-pages'), {
onUpdate: () => {
new NavActions()
.save()
.then(() => {
//console.log(r);
})
.catch(() => {
//console.log(err);
});
}
});
var nav = document.querySelectorAll('.nav-btn');
for (var i = 0, length = nav.length; i < length; i++) {
nav[i].addEventListener('click', e => this.handleNavButton(e), false);
}
}
//--------------------------
// event handlers
//--------------------------
handleNavButton(e) {
let id = '';
switch (e.target.id) {
case 'remove-item':
id = e.target.getAttribute('data-id');
new NavActions().removeItem(id);
break;
case 'edit-item':
window.location = '/@/dashboard/posts/edit/' + e.target.getAttribute('data-id');
break;
}
}
}

View file

@ -0,0 +1,254 @@
//TOOLS
import DataUtils, {
REQUEST_TYPE_POST,
CONTENT_TYPE_FORM
} from '../../../brain/utils/tools/DataUtils';
import * as DataEvent from '../../../brain/utils/events/DataEvent';
import PostActions from '../actions/PostActions';
import * as EditorEvent from '../../../brain/utils/events/EditorEvent';
import TinyDatePicker from 'tiny-date-picker';
import DateUtils from '../../../brain/utils/tools/DateUtils';
import TextEditor from '../../../brain/utils/ui/TextEditor';
import DBUtils, { FINAL_KEY } from '../../../brain/utils/tools/DBUtils';
export default class PostEditor {
//TODO - FIX POST FEATURE URLS IN DB
//--------------------------
// constructor
//--------------------------
constructor() {
let self = this;
this.dataUtils = new DataUtils();
this.dateUtils = new DateUtils();
this.urlPieces = document.URL.split('/');
this.dbUtils = new DBUtils();
this.post = [];
this.postID = null;
if (document.getElementById('post-edit-index').getAttribute('data-index')) {
this.postID = document.getElementById('post-edit-index').getAttribute('data-index');
this.dbUtils
.getPost(this.postID)
.then(body => {
self.post = body.post;
this.start();
})
.catch();
} else {
this.start();
}
if (document.getElementById('edit-post-text')) {
this.editor = new TextEditor(
document.getElementById('edit-post-text'),
document.getElementById('header').offsetHeight +
document.getElementById('post-header').offsetHeight +
document.getElementById('post-feature').offsetHeight
);
this.editor.addListener(
EditorEvent.EDITOR_DELETE,
() => this.handleEditorOptions(EditorEvent.EDITOR_DELETE),
false
);
this.editor.addListener(
EditorEvent.EDITOR_UPLOAD_POST_IMAGE,
() => this.handleEditorOptions(EditorEvent.EDITOR_UPLOAD_POST_IMAGE),
false
);
this.editor.addListener(
EditorEvent.EDITOR_UPDATE,
() => this.handleEditorOptions(EditorEvent.EDITOR_UPDATE),
false
);
this.editor.addListener(
EditorEvent.EDITOR_SAVE,
() => this.handleEditorOptions(EditorEvent.EDITOR_SAVE),
false
);
document.getElementById('post-image-upload').addEventListener(
'change',
e => {
self.handleImageUpload(e.target.id, e.target.files);
},
false
);
TinyDatePicker(document.getElementById('post-date'), {
mode: 'dp-below',
format(date) {
return self.dateUtils.getDate('origin', date);
}
});
}
}
//--------------------------
// methods
//--------------------------
start() {
if (document.getElementById('featured-image-drop')) {
document
.getElementById('featured-image-drop')
.addEventListener('dragover', this.handleImageActions, false);
document
.getElementById('featured-image-drop')
.addEventListener('drop', this.handleImageActions, false);
document
.getElementById('featured-image-upload')
.addEventListener('change', e => this.handleImageActions(e), false);
if (document.getElementById('new-feature-upload')) {
document.getElementById('new-feature-upload').addEventListener('click', () => {
document.getElementById('featured-image-upload').click();
});
}
var optionButtons = document.querySelectorAll('.post-option-btn');
for (var i = 0, length = optionButtons.length; i < length; i++) {
optionButtons[i].addEventListener('click', e => this.handlePostOptions(e), false);
}
}
}
//--------------------------
// event handlers
//--------------------------
handlePostOptions(e) {
let currentOption;
switch (e.target.id) {
case 'option-page-icon':
case 'option-page':
currentOption = document.getElementById('option-page');
break;
case 'option-feature-icon':
case 'option-feature':
currentOption = document.getElementById('option-feature');
break;
case 'option-published-icon':
case 'option-published':
currentOption = document.getElementById('option-published');
break;
}
let active = currentOption.getAttribute('data-active');
active == 'false'
? currentOption.setAttribute('data-active', 'true')
: currentOption.setAttribute('data-active', 'false');
}
handleEditorOptions(e) {
let self = this;
switch (e) {
case EditorEvent.EDITOR_SAVE:
new PostActions()
.update(this.postID, this.post, PostEditor.uploadFiles, FINAL_KEY)
.then(response => {
setTimeout(() => {
self.dbUtils.getPost(Number(response.response.newPost)).then(r => {
window.location = '/@/dashboard/posts/edit/' + r.post.uuid;
});
}, 100);
})
.catch(() => {
//console.log("ERROR", err)
});
break;
case EditorEvent.EDITOR_UPDATE:
new PostActions()
.update(this.postID, this.post, PostEditor.uploadFiles, FINAL_KEY)
.then(() => {
this.editor.notify(DataEvent.POST_UPDATED, this.postID);
})
.catch(() => {
//console.log("ERRORZ", err)
});
break;
case EditorEvent.EDITOR_DELETE:
if (confirm("Aye! You know you're deleting this post, right?")) {
new PostActions()
.deletePost(this.postID, this.post)
.then(() => {
setTimeout(() => {
window.location = '/@/dashboard/posts/';
}, 100);
})
.catch(() => {});
} else {
// Do nothing!
}
break;
case EditorEvent.EDITOR_UPLOAD_POST_IMAGE:
document.getElementById('post-image-upload').click();
break;
}
}
handleImageActions(e) {
e.stopPropagation();
e.preventDefault();
switch (e.type) {
case 'dragover':
e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
break;
case 'change':
case 'drop':
e.type == 'drop'
? (PostEditor.uploadFiles = e.dataTransfer.files)
: (PostEditor.uploadFiles = e.target.files);
for (var i = 0, f; (f = PostEditor.uploadFiles[i]); i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(f) {
// Render thumbnail.
var image = document.createElement('img');
image.src = f.target.result;
image.title = escape(theFile.name);
var span = document.createElement('div');
span.innerHTML = [
'<img src="',
f.target.result,
'" title="',
escape(theFile.name),
'"/>'
].join('');
document.getElementById('featured-image-drop').innerHTML = '';
document.getElementById('featured-image-drop').appendChild(image);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
if (e.target.id == 'featured-image-upload')
this.handleImageUpload(e.target.id, PostEditor.uploadFiles);
break;
}
}
handleImageUpload(type, files) {
let url = '';
let eventType = '';
let self = this;
type == 'featured-image-upload'
? (url = '/api/post/add-feature-image')
: (url = '/api/post/add-post-image');
type == 'featured-image-upload'
? (eventType = DataEvent.FEATURE_IMAGE_ADDED)
: (eventType = DataEvent.POST_IMAGE_ADDED);
var imageData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
// Check the file type.
if (!file.type.match('image.*')) {
continue;
}
type == 'featured-image-upload'
? imageData.append('feature_image', file, file.name)
: imageData.append('post_image', file, file.name);
}
this.dataUtils
.request(url, eventType, REQUEST_TYPE_POST, CONTENT_TYPE_FORM, imageData)
.then(response => {
let r = JSON.parse(response.request['response']);
if (r.message == DataEvent.POST_IMAGE_ADDED)
self.editor.notify(EditorEvent.EDITOR_UPLOAD_POST_IMAGE, r.url);
})
.catch(() => {
//console.log(err)
});
}
}
PostEditor.uploadFiles = [];

View file

@ -0,0 +1,30 @@
import PostEditor from './PostEditor';
export default class PostIndex {
//--------------------------
// constructor
//--------------------------
constructor(page) {
this.currentPage = null;
this.choosePage(page);
this.start();
}
//--------------------------
// methods
//--------------------------
start() {}
choosePage(page) {
this.currentPage = '';
switch (page) {
case 'edit':
case 'add':
this.currentPage = new PostEditor();
break;
default:
//just chill
break;
}
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -0,0 +1,152 @@
import SettingsActions from '../actions/SettingsActions';
import DataUtils, {
REQUEST_TYPE_POST,
CONTENT_TYPE_FORM
} from '../../../brain/utils/tools/DataUtils';
import * as DataEvent from '../../../brain/utils/events/DataEvent';
import Mailer from '../actions/Mailer';
export default class SettingsIndex {
//--------------------------
// constructor
//--------------------------
constructor() {
this.start();
this.dataUtils = new DataUtils();
this.mailer = new Mailer();
}
//--------------------------
// methods
//--------------------------
start() {
let self = this;
//handle save button
document.getElementById('save-toggle').addEventListener('click', () =>
new SettingsActions()
.save()
.then(() => {
//console.log(response);
})
.catch(() => {
//console.log(err);
})
);
//handle set up image uploads
document.getElementById('avatar').addEventListener('click', () => {
document.getElementById('avatar-upload').click();
});
document.getElementById('background').addEventListener('click', () => {
document.getElementById('background-upload').click();
});
document.getElementById('avatar-upload').addEventListener(
'change',
e => {
self.handleImageUpload(e.target.id, e.target.files);
},
false
);
document.getElementById('background-upload').addEventListener(
'change',
e => {
self.handleImageUpload(e.target.id, e.target.files);
},
false
);
//handle privacy toggle
document
.getElementById('privacy-toggle')
.addEventListener('click', e => this.togglePrivacy(e));
document.getElementById('send-mail').addEventListener('click', e => this.handleMailer(e));
//handle theme toggle
let themeBtns = document.querySelectorAll('.theme-select');
for (var i = 0, length = themeBtns.length; i < length; i++) {
themeBtns[i].addEventListener('click', e => this.handleThemes(e));
}
//handle mail options
let mailBtn = document.querySelectorAll('.mail-option');
for (i = 0, length = mailBtn.length; i < length; i++) {
mailBtn[i].addEventListener('click', e => this.handleMailOptions(e));
}
}
//--------------------------
// event handlers
//--------------------------
togglePrivacy(e) {
e.stopPropagation();
e.preventDefault();
if (e.target.getAttribute('data-private') == 'false') {
e.target.setAttribute('data-private', 'true');
e.target.innerHTML = 'SITE IS PUBLIC';
} else {
e.target.setAttribute('data-private', 'false');
e.target.innerHTML = 'SITE IS PRIVATE';
}
}
handleMailer() {
this.mailer.sendMail();
}
handleThemes(e) {
e.stopPropagation();
e.preventDefault();
let themes = document.querySelectorAll('.theme-select');
for (var i = 0, length = themes.length; i < length; i++) {
e.target.id == themes[i].id
? themes[i].setAttribute('data-enabled', 'true')
: themes[i].setAttribute('data-enabled', 'false');
}
}
handleMailOptions(e) {
e.preventDefault();
e.stopPropagation();
let smtp = document.getElementById('mail-smtp');
let mailgun = document.getElementById('mail-mg');
let mail = document.querySelectorAll('.mail-option');
for (var i = 0, length = mail.length; i < length; i++) {
if (e.target.id == mail[i].id) {
mail[i].setAttribute('data-enabled', 'true');
if (e.target.id == 'option-smtp') {
smtp.setAttribute('data-enabled', 'true');
mailgun.setAttribute('data-enabled', 'false');
} else if (e.target.id == 'option-none') {
smtp.setAttribute('data-enabled', 'false');
mailgun.setAttribute('data-enabled', 'false');
} else {
smtp.setAttribute('data-enabled', 'false');
mailgun.setAttribute('data-enabled', 'true');
}
} else {
mail[i].setAttribute('data-enabled', 'false');
}
}
}
handleImageUpload(type, files) {
let url = '';
let eventType = '';
type == 'avatar-upload'
? (url = '/api/settings/add-avatar')
: (url = '/api/settings/add-feature-background');
var imageData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
// Check the file type.
if (!file.type.match('image.*')) {
continue;
}
type == 'avatar-upload'
? imageData.append('avatar_upload', file, file.name)
: imageData.append('background_upload', file, file.name);
}
this.dataUtils
.request(url, eventType, REQUEST_TYPE_POST, CONTENT_TYPE_FORM, imageData)
.then(response => {
let r = JSON.parse(response.request['response']);
if (r.message == DataEvent.AVATAR_UPLOADED) {
document.getElementById('avatar').src = r.url;
} else {
document.getElementById('background').src = r.url;
}
})
.catch(() => {
//console.log(err)
});
}
}

File diff suppressed because one or more lines are too long

75
src/styles/dash.styl Normal file
View file

@ -0,0 +1,75 @@
/**
-------------------------------
-- Bulma
-------------------------------
* */
@import '../../node_modules/bulma.styl/stylus/utilities/_all'
@import '../../node_modules/bulma.styl/stylus/grid/columns'
/**
-------------------------------
-- Colors
-------------------------------
* */
@import 'main/_colors'
/**
-------------------------------
-- Mixins
-------------------------------
* */
@import 'main/_mixins'
/**
-------------------------------
-- Normalize
-------------------------------
* */
@import 'main/_normalize'
/**
-------------------------------
-- Typography
-------------------------------
* */
@import 'main/_typography'
/**
-------------------------------
-- Main Structure
-------------------------------
* */
@import 'main/_structure'
/**
-------------------------------
-- Index
-------------------------------
* */
@import 'main/_index'
/**
-------------------------------
-- Settings
-------------------------------
* */
@import 'main/_settings'
/**
-------------------------------
-- Navigation
-------------------------------
* */
@import 'main/_navigation'
/**
-------------------------------
-- Forms
-------------------------------
* */
@import 'main/_forms'
/**
-------------------------------
-- Blog
-------------------------------
* */
@import 'main/_posts'
/**
-------------------------------
-- Editor
-------------------------------
* */
@import 'main/_calendar'
@import 'main/_editor'
@import 'main/_editor-highlight'

View file

@ -0,0 +1,245 @@
// TINY DATE
.dp-modal
position fixed
top 0
left 0
right 0
bottom 0
// background rgba(255, 255, 255, 0.75)
background-opacity($primary - 70%, 0.75)
z-index 2000
.dp
position relative
background $primary // #FFF
box-shadow 2px 2px 16px rgba(0, 0, 0, 0.25)
line-height 1.4
border-radius 4px
max-height 400px
z-index 5000
padding-top 6px
overflow hidden
-webkit-tap-highlight-color transparent
.dp:before
content ' '
height 6px
position absolute
top 0
left 0
right 0
background $highlight
// background linear-gradient(-90deg, #3B99FC 0%, #8AEFC8 100%)
.dp-permanent .dp
padding-top 0
border 1px solid #EEE
box-shadow none
.dp-permanent .dp:before
display none
.dp-cal
min-height 300px
.dp-below
position absolute
font-size 0.8em
width 400px
max-width 90vw
.dp-permanent
position relative
font-size 0.8em
width 400px
max-width 100vw
.dp-permanent .dp
z-index 0
.dp-modal .dp
position absolute
top 50%
left 50%
max-width 600px
width calc(100% - 4em)
transform translate(-50%, -50%)
animation slide-up 0.3s forwards
.dp-months
padding 24px
.dp-years
box-sizing border-box
max-height 400px
padding 8px 0
overflow auto !important /* HACK for Chrome on Android */
.dp-cal-month, .dp-cal-year, .dp-day, .dp-month, .dp-year
box-sizing border-box
text-align center
text-decoration none
position relative
color $white
border-radius 2px
border 0
background transparent
.dp-cal-header
position relative
text-align center
padding-bottom 16px
background $primary - 10%
.dp-next, .dp-prev
position absolute
width 30px
height 30px
overflow hidden
top 14px
color $primary - 50%
border-radius 2px
border 0
background transparent
.dp-next:focus, .dp-prev:focus, .dp-next:hover, .dp-prev:hover
outline none
color inherit
.dp-prev
left 24px
.dp-next
right 24px
.dp-prev:before, .dp-next:before
content ''
border 2px solid
width 10px
height 10px
display inline-block
transform rotate(-45deg)
transition border-color 0.2s
margin 9px 0 40px 4px
.dp-prev:before
border-right 0
border-bottom 0
.dp-next:before
border-left 0
border-top 0
margin-left 0
margin-right 4px
.dp-cal-month, .dp-cal-year
display inline-block
font-size 1.4em
padding 16px 8px 8px
outline none
.dp-cal-footer
text-align center
background $primary - 10%
.dp-day-today:after
content ''
height 0
width 0
border 7px solid $highlight
border-bottom-color transparent
border-left-color transparent
position absolute
top 0
right 0
.dp-close, .dp-clear, .dp-today
box-sizing border-box
display inline-block
width 33%
padding 8px
text-decoration none
color $primary - 50%
border 0
background transparent
.dp-permanent .dp-close, .dp-permanent .dp-clear
display none
.dp-close:active, .dp-clear:active, .dp-today:active, .dp-next:active, .dp-prev:active, .dp-cal-month:active, .dp-cal-year:active
background $highlight
color $white
@media screen and (min-device-width: 1200px)
.dp-close:hover, .dp-close:focus, .dp-clear:hover, .dp-clear:focus, .dp-today:hover, .dp-today:focus, .dp-next:hover, .dp-next:focus, .dp-prev:hover, .dp-prev:focus, .dp-cal-month:focus, .dp-cal-month:hover, .dp-cal-year:hover, .dp-cal-year:focus
background $highlight
color $white
.dp-col-header, .dp-day
width 14.28571429%
display inline-block
padding 8px
text-align center
.dp-col-header
color #AAA
text-transform uppercase
font-weight 300
font-size 0.8em
padding 8px 0
.dp-month
width 33%
display inline-block
padding 8px
.dp-year
display block
padding 8px 40px
width 100%
.dp-edge-day
color #AAA
.dp-day:hover, .dp-month:hover, .dp-year:hover, .dp-current:focus, .dp-current, .dp-day:focus, .dp-month:focus, .dp-year:focus
outline none
background $primary - 40%
color $white
.dp-selected:hover, .dp-selected:focus, .dp-selected
background $highlight
color $primary - 60%
.dp-day-disabled
background transparent
color #DDD
.dp-day-disabled:focus, .dp-day-disabled:hover
background #DDD
.dp-focuser
position absolute
z-index 0
top 50%
left 50%
/**
-------------------------------
-- Responsive
-------------------------------
* */
@media (max-width: 480px), (max-height: 480px)
.dp-modal .dp
font-size 0.9em
width auto
width 100%
.dp-day-of-week, .dp-day
padding 8px
@keyframes slide-up
0%
transform translate(-50%, 100%)
100%
transform translate(-50%, -50%)

View file

@ -0,0 +1,19 @@
$primary = #374857;
//$primary = #200317; deep sexy purple
$secondary = #b2cce5;
$tertiary = #f5ab35;
$highlight = #fc6399;
$white = #f2f1ef;
$grey = #abb7b7;
$black = #32302f;
//editor colors
$eventCool = #32cd32
$eventLame = #F64747
$editorPrimary = #bebebe;
$editorSecondary = #ffa07a;
$editorTertiary = #89c4f4;
$editorString = #f6dd74;
//Bulma overrides

View file

@ -0,0 +1,46 @@
.hljs
display block
overflow-x auto
padding 0.5em
background $primary - 5%
.hljs, .hljs-subst
color #ebdbb2
.hljs-deletion, .hljs-formula, .hljs-keyword .hljs-selector-tag
color $editorPrimary
font-style italic
.hljs-link
color $highlight
.hljs-built_in, .hljs-emphasis, .hljs-name, .hljs-quote, .hljs-strong, .hljs-title, .hljs-variable
color $editorSecondary
.hljs-attr, .hljs-params, .hljs-template-tag, .hljs-type
color $editorTertiary
.hljs-builtin-name, .hljs-doctag, .hljs-literal, .hljs-number
color #8f3f71
.hljs-code, .hljs-meta, .hljs-regexp, .hljs-selector-id, .hljs-template-variable
color $tertiary
.hljs-addition, .hljs-meta-string, .hljs-section, .hljs-selector-attr, .hljs-selector-class, .hljs-string, .hljs-symbol
color $editorString
.hljs-attribute, .hljs-bullet, .hljs-class, .hljs-function, .hljs-function .hljs-keyword, .hljs-meta-keyword, .hljs-selector-pseudo, .hljs-tag
color $primary + 50%
.hljs-comment
color #928374
.hljs-link_label, .hljs-literal, .hljs-number
color #d3869b
.hljs-comment, .hljs-emphasis
font-style italic
.hljs-section, .hljs-strong, .hljs-tag
font-weight normal

View file

@ -0,0 +1,94 @@
#edit-control
// margin 10px
top 1px
border-radius 3px
// background-opacity($primary - 10%, 0.50)
width 100%
max-width 425px
z-index 2000
button:nth-child(1)
border-radius 3px 0 0 3px
button:nth-child(10)
border-radius 0 3px 3px 0
button
background $secondary
width 10%
height 39px
object-transitions(0.3s)
margin 0
border-radius 0
display inline-block
vertical-align top
text-align center
button:hover
background: $secondary - 20%
#option-update
padding 5px 5px 1px 5px
display inline-block
vertical-align top
text-align center
.icon-hide
display none
visibility hidden
.submit-start
background $white
svg
fill $eventCool
.submit-cool
background $eventCool
svg
fill $white
.submit-delete
background $eventLame !important
svg
fill $white !important
#option-date
height 30px
padding-top 6px
svg
margin -13px 5px 0 0
display inline-block
vertical-align top
fill $white
.content-editor-btn-icon
padding 5px 5px 1px 5px
// border-radius 20px
color $primary
svg
fill $primary
.content-editor-btn-text
padding 5px
// border-radius 20px
color $primary
#option-bold
font-weight bold
text-decoration none
#option-italic
font-weight bold
text-decoration none
font-style italic
#option-strikethrough
font-weight bold
text-decoration line-through
font-style italic

View file

@ -0,0 +1,53 @@
form
display inline-block
input[type=email], input[type=password], input[type=text]
border 0
border-radius 3px
padding 5px
font 1em 'Apercu-Mono'
display inline-block
background-color $primary - 60%
color $secondary
textarea
border 0
border-radius 3px
color $type02
font 15px 'Apercu-Mono'
button, input[type=submit]
background $highlight
color $primary - 60%
font 1em 'Apercu-Mono'
border-radius 3px
position relative
cursor pointer
border 0
select
font 1em 'Apercu-Mono'
border 1px solid $secondary
-webkit-appearance none
-moz-appearance none
appearance none
// background: url(http://www.stackoverflow.com/favicon.ico) 96% / 15% no-repeat #000;
color $primary
::-webkit-input-placeholder
font 1em 'Apercu-Mono'
color $secondary
:-moz-placeholder
/* Firefox 18- */
font 1em 'Apercu-Mono'
color $secondary
::-moz-placeholder
/* Firefox 19+ */
font 1em 'Apercu-Mono'
color $secondary
:-ms-input-placeholder
font 1em 'Apercu-Mono'
color $secondary

195
src/styles/main/_index.styl Normal file
View file

@ -0,0 +1,195 @@
#dash-index-content
width 100%
height 100%
margin 0 auto
#dash-index
width 100%
height 100%
z-index 10
position relative
#dash-index-wrapper
width 100%
height 100%
margin 0 auto
#dash-login
width 100%
max-width 900px
margin 0 auto
#dash-form
width 300px
padding 0.75em
background $primary
border-radius 3px
input
width 290px
margin 0 0 10px 0
height 30px
button
width 300px
#dash-menu
padding 10px
width 90%
max-width 900px
margin 50px auto
a
display inline-block
vertical-align top
background $primary - 60%
width 30%
padding 5px
border-radius 3px
color $white
margin 0 10px 10px 0
&:hover
background $primary - 50%
svg
display inline-block
vertical-align top
fill $white
label
display inline-block
margin-top 5px
width 85%
text-align center
cursor pointer
#dash-recent
width 100%
max-width 900px
height 100%
padding 5px 0 0 0
margin 0 auto
#recent-list
padding 0.75em
position relative
.recent-header
height 50px
h3
vertical-align top
display inline-block
width 50%
.index-menu
width 50%
text-align right
vertical-align top
display inline-block
margin 24px 0 24px 0
right 10px
color $white
a
text-decoration-color $highlight
a.post-link
font-size 1.5em
font-weight 300
display inline-block
border-radius 3px
vertical-align top
text-decoration none
position relative
label
font-size 0.7em
font-weight 700
color $primary - 60%
padding 5px
vertical-align top
display inline-block
width 60%
span
float right
vertical-align top
display inline-block
font-family 'Apercu-mono'
font-size 0.5em
padding 7px
color $primary - 60%
div
width 100%
background $white
position absolute
bottom 0
border-radius 0 0 3px 3px
a:nth-child(3)
width 100%
margin-bottom 20px
height 500px
a:nth-child(4)
width 49%
height 275px
margin 0 15px 15px 0
a:nth-child(5)
width 49%
height 550px
a:nth-child(6)
width 49%
height 550px
margin -260px 15px 0 0
a:nth-child(7)
width 49%
height 275px
margin 15px 0 0 0
/**
-------------------------------
-- Responsive
-------------------------------
* */
@media only screen and (max-width: 768px)
#dash-index-content
#dash-index
#dash-index-wrapper
#dash-recent
#recent-list
a:nth-child(4), a:nth-child(6)
width 48.9%
@media only screen and (max-width: 640px)
#dash-index-content
#dash-index
#dash-index-wrapper
#dash-recent
#recent-list
a:nth-child(4), a:nth-child(6)
width 48.5%
@media only screen and (max-width: 480px)
#dash-index-content
#dash-index
#dash-index-wrapper
#dash-recent
#recent-list
.recent-header
h3
width 40%
.index-menu
width 60%
a:nth-child(3), a:nth-child(4), a:nth-child(5), a:nth-child(6), a:nth-child(7)
width 100%
margin 15px 0 0 0
height 400px

View file

@ -0,0 +1,11 @@
text-drop-shadow(rgb-value, opacity, offsetX, offsetY, blur)
text-shadow offsetX offsetY blur rgba(rgb-value, opacity)
object-transitions(rate)
-moz-transition all rate linear
-webkit-transition all rate linear
-o-transition all rate linear
transition all rate linear
background-opacity(rgb-value, opacity)
background rgba(rgb-value, opacity)

View file

@ -0,0 +1,62 @@
#nav-index
width 100%
max-width 900px
margin 0 auto
#nav-index-wrapper
padding 0.75rem
#nav-pages
.nav-item
display block
width 98%
background $primary
border-radius 3px
color $white
height 30px
padding 10px
margin 0 0 10px 0
font-size 1.5em
cursor move
label
display inline-block
vertical-align middle
padding 0
margin -15px 0 0 10px
cursor move
#nav-btns
float right
button
font-size 0.8em
margin 0 0 0 10px
@media only screen and (max-width: 375px)
#nav-index
#nav-index-wrapper
#nav-pages
.nav-item
width 94.5%
font-size 1em
label
width 47%
vertical-align top
margin-top 0px
line-height 1em
@media only screen and (max-width: 320px)
#nav-index
#nav-index-wrapper
#nav-pages
.nav-item
width 94.5%
font-size 1em
label
width 37%
vertical-align top
margin-top 0px
line-height 1em

View file

@ -0,0 +1,196 @@
html
line-height 1.15
-ms-text-size-adjust 100%
-webkit-text-size-adjust 100%
body
margin 0
article,
aside,
footer,
header,
nav,
section
display block
h1
font-size 2em
margin 0.67em 0
figcaption,
figure,
main
display block
figure
margin 1em 40px
hr
box-sizing content-box
height 0
overflow visible
pre
font-family monospace, monospace
font-size 1em
a
background-color transparent
-webkit-text-decoration-skip objects
a:active,
a:hover
outline-width 0
abbr[title]
border-bottom none
text-decoration underline
text-decoration underline dotted
b,
strong
font-weight inherit
font-weight bolder
code,
kbd,
samp
font-family monospace, monospace
font-size 1em
dfn
font-style italic
mark
background-color #ff0
color #000
small
font-size 80%
sub,
sup
font-size 60%
line-height 0
position relative
vertical-align baseline
sub
bottom -0.25em
sup
top -0.55em
background lightness($primary, 80%)
color $primary
border-radius: 2px;
padding 0 2px 0 2px
margin: 0 2px 0 0
audio,
video
display inline-block
audio
&:not([controls])
display none
height 0
img
border-style none
svg
&:not(:root)
overflow hidden
button,
input,
optgroup,
select,
textarea
font-family sans-serif
font-size 100%
line-height 1.15
margin 0
button,
input
overflow visible
button,
select
text-transform none
button, html [type="button"],
[type="reset"],
[type="submit"]
-webkit-appearance button
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner,
button::-moz-focus-inner
border-style none
padding 0
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring,
button:-moz-focusring
outline 1px dotted ButtonText
fieldset
border 1px solid #c0c0c0
margin 0 2px
padding 0.35em 0.625em 0.75em
legend
box-sizing border-box
color inherit
display table
max-width 100%
padding 0
white-space normal
progress
display inline-block
vertical-align baseline
textarea
overflow auto
[type="checkbox"],
[type="radio"]
box-sizing border-box
padding 0
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button
height auto
[type="search"]
-webkit-appearance textfield
outline-offset -2px
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration
-webkit-appearance none
::-webkit-file-upload-button
-webkit-appearance button
font inherit
details,
menu
display block
summary
display list-item
canvas
display inline-block
template
display none
[hidden]
display none

325
src/styles/main/_posts.styl Normal file
View file

@ -0,0 +1,325 @@
#post-index
width 100%
max-width 900px
margin 0 auto
#post-index-wrapper
padding 0.75rem
overflow hidden
#post-index-menu
color $white
a
text-decoration-color $highlight
a.add-new-post
display inline-block
background $highlight
border-radius 3px
padding 3px
color $white
text-align center
margin-bottom 10px
float right
.current-filter
color $highlight
text-decoration-color $secondary
#posts-list
margin 20px 0 0 0
a.post-link
background $white
display inline-block
vertical-align top
width 100%
text-decoration none
margin 0 0 20px 0
border-radius 3px
overflow hidden
color $primary - 60%
label
font-size 2em
font-weight 500
padding 10px
display inline-block
vertical-align top
width 100%
span
display inline-block
vertical-align top
font-size 0.8em
font-family 'Apercu-Mono'
width 50%
padding 0 0 0 10px
div.post-bg
width 100%
height 350px
background-color $highlight
p
padding 5px 10px 5px 10px
font-size 1.2em
font-weight 400
#post-edit-index
width 100%
overflow hidden
#post-edit-index-wrapper
width 100%
#post-header
// width 100%
max-width 900px
margin 0 auto
padding 0.75rem
#post-title
#post_title
background $primary - 4%
font-family 'Apercu'
width 97.6%
height 140px
font-size 1.5em
color $white
padding 5px
margin 0 0 5px 0
#post-date
background $primary - 10%
border-radius 0 3px 3px 0
width 39.5%
font-family 'Apercu'
color $highlight
height 30px
vertical-align top
text-align center
#calendar-icon
background $primary - 15%
border-radius 3px 0 0 3px
display inline-block
padding 2.9px
color $secondary
#post-options
display inline-block
vertical-align top
width 49%
padding 0 0 0 3px
button:nth-child(1)
border-radius 3px 0 0 3px
button:nth-child(4)
border-radius 0 3px 3px 0
button
width 25%
height 39px
object-transitions(0.3s)
margin 0
border-radius 0
display inline-block
vertical-align top
text-align center
button[data-active='false']
background $secondary
svg
fill $primary
button[data-active='true']
background $tertiary
svg
fill $tertiary - 70%
#post-meta
#post_tags
background $primary - 4%
font-family 'Apercu'
width 97.6%
height 140px
color $secondary
padding 5px
margin 0 0 5px 0
#featured-image-upload, #post-image-upload
display none
#post-feature
width 100%
#featured-image-drop
display flex
align-items center
justify-content center
width 100%
min-height 200px
background $primary - 50%
color $primary
vertical-align middle
font-family 'Apercu-Mono'
label
cursor pointer
img
width 100%
margin 0
padding 0
#featured-new-image-btn
position absolute
margin 20px
#new-feature-upload
padding-top 4px
background $white
svg
fill $highlight
#edit-post
width 100%
max-width 900px
margin 0 auto
#edit-post-wrapper
width 98%
max-width 900px
margin 0 auto
border-radius 5px
background $primary - 10%
pre
code
font-family 'Apercu-Mono'
padding 5px
border-radius 5px
line-height 1.6em
font-size 1.25em
color $editorPrimary
word-wrap normal
white-space pre-wrap
line-break normal
-webkit-line-break normal
-o-line-break normal
-moz-line-break normal
display inline-block
width 100%
max-width 900px
/**
-------------------------------
-- Responsive
-------------------------------
* */
@media only screen and (max-width: 800px)
#post-edit-index
#post-edit-index-wrapper
#post-header
#post-title
#post-date
width 37.6%
@media only screen and (max-width: 768px)
#post-edit-index
#post-edit-index-wrapper
#post-header
#post-title
#post-date
width 43.1%
#post-meta
#edit-control
max-width 100%
button
width 9.91%
@media only screen and (max-width: 640px)
#post-edit-index
#post-edit-index-wrapper
#post-header
#post-title
#post-date
width 42%
@media only screen and (max-width: 480px)
#post-index
#post-index-wrapper
#post-index-menu
a
font-size 0.95em
label
display none
visibility hidden
#post-edit-index
#post-edit-index-wrapper
#post-header
#post-title
#post-options
margin 5px 0 0 0
width 100%
padding 0
#post-date
width 89.2%
#post-meta
#edit-control
button
width 9.91%
@media only screen and (max-width: 320px)
#post-index
#post-index-wrapper
#post-index-menu
a
font-size 0.95em
label
display none
visibility hidden
#post-edit-index
#post-edit-index-wrapper
#post-header
#post-title
#post_title
width 96.4%
#post-options
margin 5px 0 0 0
width 100%
padding 0
#post-date
width 83.1%
#post-meta
#post_tags
width 96.4%
#edit-control
.content-editor-btn-icon
svg.icons
width 20px
.post-sumbit-btn
svg.icons
width 20px
button
width 10%

View file

@ -0,0 +1,134 @@
#site-background
margin 0 0 10px 0
img
width 100%
// border 5px solid $white
border-radius 0
overflow hidden
cursor pointer
label
position absolute
color $white
margin 5px
background $primary - 60%
padding 5px
border-radius 3px
input
visibility hidden
display none
#settings-index
width 94%
max-width 900px
margin 0 auto
#settings-index-wrapper
padding 0.75rem
button
margin-top 5px
width 100%
height 45px
#member-settings, #site-settings, #option-settings
background $primary
padding 5px
border-radius 5px 0 5px 0
label
font-family 'Apercu-Mono'
color $white
input
width 95%
margin 0 5px 10px 0
height 30px
padding 10px
width 100%
margin 20px auto
#member-avatar-drop
display inline-block
margin 0 0 10px 0
img
width 100%
// border 5px solid $white
border-radius 5px
overflow hidden
cursor pointer
input
visibility hidden
display none
#member-info
vertical-align top
display inline-block
width 100%
input
width 95%
margin 0 5px 10px 0
textarea
background $primary - 60%
width 95%
height 155px
color $secondary
padding 10px
#option-settings
#theme-settings
a
width 95%
margin 0 5px 5px 0
height 25px
padding 10px
display inline-block
a[data-enabled='false']
background $primary - 60%
color $secondary
border-radius 3px
a[data-enabled='true']
background $secondary
color $primary
border-radius 3px
svg
fill $primary
display inline-block
float right
#mail-settings
min-height 240px
a.mail-option
float right
font-family 'Apercu-Mono'
font-size 0.9em
border-radius 3px
text-decoration none
margin 0 0 0 5px
// padding: 1px
a.mail-option[data-enabled='true']
color $highlight
a.mail-option[data-enabled='false']
color $white
input
// width 94%
margin 0 5px 5px 0
vertical-align top
div[data-enabled='false']
display none
visibility hidden

View file

@ -0,0 +1,123 @@
html, body
background-color $primary - 60%
font 400 1em $baseType
height 100%
a
font 300 1em $baseType
color $secondary
text-decoration underline
object-transitions(0.1s)
&:hover
color $secondary + 10%
svg.icons
width 30px
fill $secondary
#loader
position fixed
z-index 2000
height 100%
width 100%
display flex
align-items center
justify-content center
display none
visibility hidden
i
color $tertiary
.blog-container
width 100%
.main-container
margin 0 auto
z-index 10
position relative
section
header
width 100%
max-width 900px
margin 0 auto
#wrapper
padding 0.75rem
#left, #right
width 50%
display inline-block
vertical-align top
#the-logo
width 40px
#right
text-align right
color $white
a
text-decoration-color $highlight
label#the-title
font-size 1.2em
font-weight 400
color $tertiary
text-decoration none
display block
line-height 0.8
// word-break: break-all;
#dash-menu
text-align right
/* Mozilla based browsers */
::-moz-selection
background-color $highlight
color $white
/* Works in Safari */
::selection
background-color $highlight
color $white
/* Works in Opera */
::-o-selection
background-color $highlight
color $white
::-ms-selection
background-color $highlight
color $white
/* Works in Internet Explorer */
::-webkit-selection
background-color $highlight
color $white
/**
-------------------------------
-- Responsive
-------------------------------
* */
@media only screen and (max-width: 800px)
.main-container
section
header
#wrapper
#left, #right
display inline-block
@media only screen and (max-width: 480px)
.main-container
section
header
#wrapper
#left
width 30%
#right
width 70%

View file

@ -0,0 +1,118 @@
@font-face
font-weight 300
font-style normal
font-family 'Apercu'
src url('fonts/Apercu-Light.eot'),
url('fonts/Apercu-Light.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-Light.woff2') format('woff2'),
url('fonts/Apercu-Light.woff') format('woff'),
url('fonts/Apercu-Light.ttf') format('truetype'),
url('fonts/Apercu-Light.svg?#Apercu') format('svg')
@font-face
font-weight 300
font-style italic
font-family 'Apercu'
src url('fonts/Apercu-LightItalic.eot'),
url('fonts/Apercu-LightItalic.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-LightItalic.woff2') format('woff2'),
url('fonts/Apercu-LightItalic.woff') format('woff'),
url('fonts/Apercu-LightItalic.ttf') format('truetype'),
url('fonts/Apercu-LightItalic.svg?#Apercu') format('svg')
@font-face
font-weight 400
font-style normal
font-family 'Apercu'
src url('fonts/Apercu.eot'),
url('fonts/Apercu.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu.woff2') format('woff2'),
url('fonts/Apercu.woff') format('woff'),
url('fonts/Apercu.ttf') format('truetype'),
url('fonts/Apercu.svg?#Apercu') format('svg')
@font-face
font-weight 400
font-style italic
font-family 'Apercu'
src url('fonts/Apercu-Italic.eot'),
url('fonts/Apercu-Italic.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-Italic.woff2') format('woff2'),
url('fonts/Apercu-Italic.woff') format('woff'),
url('fonts/Apercu-Italic.ttf') format('truetype'),
url('fonts/Apercu-Italic.svg?#Apercu') format('svg')
@font-face
font-weight 500
font-style normal
font-family 'Apercu'
src url('fonts/Apercu-Medium.eot'),
url('fonts/Apercu-Medium.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-Medium.woff2') format('woff2'),
url('fonts/Apercu-Medium.woff') format('woff'),
url('fonts/Apercu-Medium.ttf') format('truetype'),
url('fonts/Apercu-Medium.svg?#Apercu') format('svg')
@font-face
font-weight 500
font-style italic
font-family 'Apercu'
src url('fonts/Apercu-MediumItalic.eot'),
url('fonts/Apercu-MediumItalic.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-MediumItalic.woff2') format('woff2'),
url('fonts/Apercu-MediumItalic.woff') format('woff'),
url('fonts/Apercu-MediumItalic.ttf') format('truetype'),
url('fonts/Apercu-MediumItalic.svg?#Apercu') format('svg')
@font-face
font-weight 600
font-style normal
font-weight bold
font-family 'Apercu'
src url('fonts/Apercu-Bold.eot'),
url('fonts/Apercu-Bold.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-Bold.woff2') format('woff2'),
url('fonts/Apercu-Bold.woff') format('woff'),
url('fonts/Apercu-Bold.ttf') format('truetype'),
url('fonts/Apercu-Bold.svg?#Apercu') format('svg')
@font-face
font-weight 600
font-style italic
font-weight bold
font-family 'Apercu'
src url('fonts/Apercu-BoldItalic.eot'),
url('fonts/Apercu-BoldItalic.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-BoldItalic.woff2') format('woff2'),
url('fonts/Apercu-BoldItalic.woff') format('woff'),
url('fonts/Apercu-BoldItalic.ttf') format('truetype'),
url('fonts/Apercu-Bold.svg?#Apercu') format('svg')
@font-face
font-weight 400
font-style normal
font-family 'Apercu-Mono'
src url('fonts/Apercu-Mono.eot'),
url('fonts/Apercu-Mono.eot?#iefix') format('embedded-opentype'),
url('fonts/Apercu-Mono.woff2') format('woff2'),
url('fonts/Apercu-Mono.woff') format('woff'),
url('fonts/Apercu-Mono.ttf') format('truetype'),
url('fonts/Apercu-Mono.svg?#Apercu') format('svg')
$baseType = 'Apercu', Helvetica, Arial, sans-serif;
h1, h2, h3
color $white
h1
font-size 2em
font-weight 400
h2
font-size 1.75em
font-weight 400
h3
font-size 1.5em
font-weight 300