diff --git a/brain/app.js b/brain/app.js
index a2de3f2..2492f9a 100644
--- a/brain/app.js
+++ b/brain/app.js
@@ -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'));
diff --git a/brain/routes/dash/index.js b/brain/routes/dash/index.js
index 151c213..f84d2cb 100644
--- a/brain/routes/dash/index.js
+++ b/brain/routes/dash/index.js
@@ -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);
});
});
diff --git a/brain/views/email/base.pug b/brain/views/email/base.pug
new file mode 100644
index 0000000..8c0005a
--- /dev/null
+++ b/brain/views/email/base.pug
@@ -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}
diff --git a/brain/views/frame.pug b/brain/views/frame.pug
new file mode 100644
index 0000000..a95d392
--- /dev/null
+++ b/brain/views/frame.pug
@@ -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")
+
+
diff --git a/brain/views/index.pug b/brain/views/index.pug
new file mode 100644
index 0000000..9841fe8
--- /dev/null
+++ b/brain/views/index.pug
@@ -0,0 +1,9 @@
+extends frame
+block main-content
+ #dash-index
+ #dash-index-wrapper
+ -if(!status)
+ include partials/login
+ -else
+ include partials/front
+
diff --git a/brain/views/navigation.pug b/brain/views/navigation.pug
new file mode 100644
index 0000000..2573c64
--- /dev/null
+++ b/brain/views/navigation.pug
@@ -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
+
diff --git a/brain/views/partials/dash-nav.pug b/brain/views/partials/dash-nav.pug
new file mode 100644
index 0000000..e966ec9
--- /dev/null
+++ b/brain/views/partials/dash-nav.pug
@@ -0,0 +1,4 @@
+#dash-menu
+ a#settings(href="/@/dashboard/settings") Settings
+ | .
+ a#navigation(href="/@/dashboard/navigation") Navigation
diff --git a/brain/views/partials/editor.pug b/brain/views/partials/editor.pug
new file mode 100644
index 0000000..4db0c58
--- /dev/null
+++ b/brain/views/partials/editor.pug
@@ -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')
+
+
\ No newline at end of file
diff --git a/brain/views/partials/front.pug b/brain/views/partials/front.pug
new file mode 100644
index 0000000..c6b0395
--- /dev/null
+++ b/brain/views/partials/front.pug
@@ -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
+
diff --git a/brain/views/partials/login.pug b/brain/views/partials/login.pug
new file mode 100644
index 0000000..7919208
--- /dev/null
+++ b/brain/views/partials/login.pug
@@ -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
+
\ No newline at end of file
diff --git a/brain/views/partials/mailforms.pug b/brain/views/partials/mailforms.pug
new file mode 100644
index 0000000..9b7932d
--- /dev/null
+++ b/brain/views/partials/mailforms.pug
@@ -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)
\ No newline at end of file
diff --git a/brain/views/post-edit.pug b/brain/views/post-edit.pug
new file mode 100644
index 0000000..e2a2b82
--- /dev/null
+++ b/brain/views/post-edit.pug
@@ -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}
+
+
+
+
+
+
+
diff --git a/brain/views/posts-index.pug b/brain/views/posts-index.pug
new file mode 100644
index 0000000..fc6ff78
--- /dev/null
+++ b/brain/views/posts-index.pug
@@ -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')
+
diff --git a/brain/views/settings.pug b/brain/views/settings.pug
new file mode 100644
index 0000000..fc1c789
--- /dev/null
+++ b/brain/views/settings.pug
@@ -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
+
+
+
diff --git a/init.js b/init.js
index 65ec607..871dc78 100644
--- a/init.js
+++ b/init.js
@@ -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);
}
diff --git a/package.json b/package.json
index 6b199ed..4648449 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/src/com/Base.js b/src/com/Base.js
new file mode 100644
index 0000000..4c7fead
--- /dev/null
+++ b/src/com/Base.js
@@ -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);
+ });
+ }
+}
diff --git a/src/com/Start.js b/src/com/Start.js
new file mode 100644
index 0000000..8811183
--- /dev/null
+++ b/src/com/Start.js
@@ -0,0 +1,6 @@
+import Base from './Base'
+
+document.addEventListener('DOMContentLoaded', function() {
+
+ var base = new Base();
+}, false);
diff --git a/src/com/actions/Mailer.js b/src/com/actions/Mailer.js
new file mode 100644
index 0000000..0b3e335
--- /dev/null
+++ b/src/com/actions/Mailer.js
@@ -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
+ //--------------------------
+}
diff --git a/src/com/actions/NavActions.js b/src/com/actions/NavActions.js
new file mode 100644
index 0000000..7dc8384
--- /dev/null
+++ b/src/com/actions/NavActions.js
@@ -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
+ //--------------------------
+}
diff --git a/src/com/actions/PostActions.js b/src/com/actions/PostActions.js
new file mode 100644
index 0000000..59f2f3d
--- /dev/null
+++ b/src/com/actions/PostActions.js
@@ -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
+ //--------------------------
+}
diff --git a/src/com/actions/SettingsActions.js b/src/com/actions/SettingsActions.js
new file mode 100644
index 0000000..9500fb4
--- /dev/null
+++ b/src/com/actions/SettingsActions.js
@@ -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
+ //--------------------------
+}
diff --git a/src/com/controllers/DashManager.js b/src/com/controllers/DashManager.js
new file mode 100644
index 0000000..8e6e163
--- /dev/null
+++ b/src/com/controllers/DashManager.js
@@ -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
+ //--------------------------
+}
diff --git a/src/com/controllers/NavIndex.js b/src/com/controllers/NavIndex.js
new file mode 100644
index 0000000..34cf900
--- /dev/null
+++ b/src/com/controllers/NavIndex.js
@@ -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;
+ }
+ }
+}
diff --git a/src/com/controllers/PostEditor.js b/src/com/controllers/PostEditor.js
new file mode 100644
index 0000000..2ae8813
--- /dev/null
+++ b/src/com/controllers/PostEditor.js
@@ -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 = [
+ ''
+ ].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 = [];
diff --git a/src/com/controllers/PostIndex.js b/src/com/controllers/PostIndex.js
new file mode 100644
index 0000000..3d6157f
--- /dev/null
+++ b/src/com/controllers/PostIndex.js
@@ -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
+ //--------------------------
+}
diff --git a/src/com/controllers/SettingsIndex.js b/src/com/controllers/SettingsIndex.js
new file mode 100644
index 0000000..b2a5ff5
--- /dev/null
+++ b/src/com/controllers/SettingsIndex.js
@@ -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)
+ });
+ }
+}
diff --git a/src/libraries/highlight.pack.js b/src/libraries/highlight.pack.js
new file mode 100644
index 0000000..836670d
--- /dev/null
+++ b/src/libraries/highlight.pack.js
@@ -0,0 +1,2 @@
+/*! highlight.js v9.13.1 | BSD3 License | git.io/hljslicense */
+!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=M.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function c(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function c(e){l+=""+t(e)+">"}function u(e){("start"===e.event?o:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substring(s,g[0].offset)),s=g[0].offset,g===e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function l(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):B(a.k).forEach(function(e){c(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.endSameAsBegin&&(a.e=a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return s("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=u.length?t(u.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function c(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t].endSameAsBegin&&(n.c[t].eR=o(n.c[t].bR.exec(e)[0])),n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function s(e,n){return!a&&r(n.iR,e)}function p(e,n){var t=R.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function d(e,n,t,r){var a=r?"":j.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=p(E,r),e?(M+=e[1],a+=d(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function b(){var e="string"==typeof E.sL;if(e&&!L[E.sL])return n(k);var t=e?f(E.sL,k,!0,B[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(B[E.sL]=t.top),d(t.language,t.value,!1,!0)}function v(){y+=null!=E.sL?b():h(),k=""}function m(e){y+=e.cN?d(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function N(e,n){if(k+=e,null==n)return v(),0;var t=c(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),v(),t.rB||t.eB||(k=n)),m(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),v(),a.eE&&(k=n));do E.cN&&(y+=I),E.skip||E.sL||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.eR=r.eR),m(r.starts,"")),a.rE?0:n.length}if(s(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var R=w(e);if(!R)throw new Error('Unknown language: "'+e+'"');l(R);var x,E=i||R,B={},y="";for(x=E;x!==R;x=x.parent)x.cN&&(y=d(x.cN,"",!0)+y);var k="",M=0;try{for(var C,A,S=0;;){if(E.t.lastIndex=S,C=E.t.exec(t),!C)break;A=N(t.substring(S,C.index),C[0]),S=C.index+A}for(N(t.substr(S)),x=E;x.parent;x=x.parent)x.cN&&(y+=I);return{r:M,value:y,language:e,top:E}}catch(O){if(O.message&&-1!==O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function g(e,t){t=t||j.languages||B(L);var r={r:0,value:n(e)},a=r;return t.filter(w).filter(x).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return j.tabReplace||j.useBR?e.replace(C,function(e,n){return j.useBR&&"\n"===e?"
":j.tabReplace?n.replace(/\t/g,j.tabReplace):""}):e}function d(e,n,t){var r=n?y[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n,t,r,o,s,l=i(e);a(l)||(j.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/
/g,"\n")):n=e,s=n.textContent,r=l?f(l,s,!0):g(s),t=c(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=u(t,c(o),s)),r.value=p(r.value),e.innerHTML=r.value,e.className=d(e.className,l,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){j=o(j,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,h)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=L[n]=t(e);r.aliases&&r.aliases.forEach(function(e){y[e]=n})}function R(){return B(L)}function w(e){return e=(e||"").toLowerCase(),L[e]||L[y[e]]}function x(e){var n=w(e);return n&&!n.disableAutodetect}var E=[],B=Object.keys,L={},y={},k=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,C=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,I="",j={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=h,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.autoDetection=x,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b:/,e:/(\/\w+|\w+\/)>/,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/,r:0,c:[{cN:"attr",b:e,r:0},{b:/=\s*/,r:0,c:[{cN:"string",endsParent:!0,v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s"'=<>`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"meta",b:/<\?xml/,e:/\?>/,r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0},{b:'b"',e:'"',skip:!0},{b:"b'",e:"'",skip:!0},s.inherit(s.ASM,{i:null,cN:null,c:null,skip:!0}),s.inherit(s.QSM,{i:null,cN:null,c:null,skip:!0})]},{cN:"tag",b:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}});
\ No newline at end of file
diff --git a/src/styles/dash.styl b/src/styles/dash.styl
new file mode 100644
index 0000000..ba92805
--- /dev/null
+++ b/src/styles/dash.styl
@@ -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'
diff --git a/src/styles/main/_calendar.styl b/src/styles/main/_calendar.styl
new file mode 100644
index 0000000..cfd3fba
--- /dev/null
+++ b/src/styles/main/_calendar.styl
@@ -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%)
\ No newline at end of file
diff --git a/src/styles/main/_colors.styl b/src/styles/main/_colors.styl
new file mode 100644
index 0000000..89b678c
--- /dev/null
+++ b/src/styles/main/_colors.styl
@@ -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
diff --git a/src/styles/main/_editor-highlight.styl b/src/styles/main/_editor-highlight.styl
new file mode 100644
index 0000000..0161aa1
--- /dev/null
+++ b/src/styles/main/_editor-highlight.styl
@@ -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
diff --git a/src/styles/main/_editor.styl b/src/styles/main/_editor.styl
new file mode 100644
index 0000000..0fd3547
--- /dev/null
+++ b/src/styles/main/_editor.styl
@@ -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
+
diff --git a/src/styles/main/_forms.styl b/src/styles/main/_forms.styl
new file mode 100644
index 0000000..c9181fc
--- /dev/null
+++ b/src/styles/main/_forms.styl
@@ -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
diff --git a/src/styles/main/_index.styl b/src/styles/main/_index.styl
new file mode 100644
index 0000000..8be08e3
--- /dev/null
+++ b/src/styles/main/_index.styl
@@ -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
diff --git a/src/styles/main/_mixins.styl b/src/styles/main/_mixins.styl
new file mode 100644
index 0000000..92fc286
--- /dev/null
+++ b/src/styles/main/_mixins.styl
@@ -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)
diff --git a/src/styles/main/_navigation.styl b/src/styles/main/_navigation.styl
new file mode 100644
index 0000000..4bffd84
--- /dev/null
+++ b/src/styles/main/_navigation.styl
@@ -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
diff --git a/src/styles/main/_normalize.styl b/src/styles/main/_normalize.styl
new file mode 100644
index 0000000..87daf2c
--- /dev/null
+++ b/src/styles/main/_normalize.styl
@@ -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
diff --git a/src/styles/main/_posts.styl b/src/styles/main/_posts.styl
new file mode 100644
index 0000000..d920f80
--- /dev/null
+++ b/src/styles/main/_posts.styl
@@ -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%
diff --git a/src/styles/main/_settings.styl b/src/styles/main/_settings.styl
new file mode 100644
index 0000000..2c0b8df
--- /dev/null
+++ b/src/styles/main/_settings.styl
@@ -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
\ No newline at end of file
diff --git a/src/styles/main/_structure.styl b/src/styles/main/_structure.styl
new file mode 100644
index 0000000..2c30449
--- /dev/null
+++ b/src/styles/main/_structure.styl
@@ -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%
diff --git a/src/styles/main/_typography.styl b/src/styles/main/_typography.styl
new file mode 100644
index 0000000..3788c75
--- /dev/null
+++ b/src/styles/main/_typography.styl
@@ -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
+