diff --git a/client/js/app.js b/client/js/app.js
index 73e4881b..eff64a1d 100644
--- a/client/js/app.js
+++ b/client/js/app.js
@@ -29,6 +29,7 @@ import adminUsersCreateComponent from './modals/admin-users-create.vue'
 
 import adminProfileComponent from './pages/admin-profile.component.js'
 import adminSettingsComponent from './pages/admin-settings.component.js'
+import sourceComponent from './pages/source.component.js'
 
 // ====================================
 // Initialize Vue Modules
@@ -83,6 +84,7 @@ $(() => {
       colorPicker: colorPickerComponent,
       loadingSpinner: loadingSpinnerComponent,
       search: searchComponent,
+      sourceView: sourceComponent,
       tree: treeComponent
     },
     store,
diff --git a/client/js/components/alerts.js b/client/js/components/alerts.js
deleted file mode 100644
index cb302334..00000000
--- a/client/js/components/alerts.js
+++ /dev/null
@@ -1,112 +0,0 @@
-'use strict'
-
-import Vue from 'vue'
-import _ from 'lodash'
-
-/**
- * Alerts
- */
-class Alerts {
-  /**
-   * Constructor
-   *
-   * @class
-   */
-  constructor () {
-    let self = this
-
-    self.mdl = new Vue({
-      el: '#alerts',
-      data: {
-        children: []
-      },
-      methods: {
-        acknowledge: (uid) => {
-          self.close(uid)
-        }
-      }
-    })
-
-    self.uidNext = 1
-  }
-
-  /**
-   * Show a new Alert
-   *
-   * @param      {Object}  options  Alert properties
-   * @return     {null}  Void
-   */
-  push (options) {
-    let self = this
-
-    let nAlert = _.defaults(options, {
-      _uid: self.uidNext,
-      class: 'info',
-      message: '---',
-      sticky: false,
-      title: '---'
-    })
-
-    self.mdl.children.push(nAlert)
-
-    if (!nAlert.sticky) {
-      _.delay(() => {
-        self.close(nAlert._uid)
-      }, 5000)
-    }
-
-    self.uidNext++
-  }
-
-  /**
-   * Shorthand method for pushing errors
-   *
-   * @param      {String}  title    The title
-   * @param      {String}  message  The message
-   */
-  pushError (title, message) {
-    this.push({
-      class: 'error',
-      message,
-      sticky: false,
-      title
-    })
-  }
-
-  /**
-   * Shorthand method for pushing success messages
-   *
-   * @param      {String}  title    The title
-   * @param      {String}  message  The message
-   */
-  pushSuccess (title, message) {
-    this.push({
-      class: 'success',
-      message,
-      sticky: false,
-      title
-    })
-  }
-
-  /**
-   * Close an alert
-   *
-   * @param      {Integer}  uid     The unique ID of the alert
-   */
-  close (uid) {
-    let self = this
-
-    let nAlertIdx = _.findIndex(self.mdl.children, ['_uid', uid])
-    let nAlert = _.nth(self.mdl.children, nAlertIdx)
-
-    if (nAlertIdx >= 0 && nAlert) {
-      nAlert.class += ' exit'
-      Vue.set(self.mdl.children, nAlertIdx, nAlert)
-      _.delay(() => {
-        self.mdl.children.splice(nAlertIdx, 1)
-      }, 500)
-    }
-  }
-}
-
-export default Alerts
diff --git a/client/js/pages/source.js b/client/js/pages/source.component.js
similarity index 59%
rename from client/js/pages/source.js
rename to client/js/pages/source.component.js
index 19d3e823..faac5714 100644
--- a/client/js/pages/source.js
+++ b/client/js/pages/source.component.js
@@ -1,14 +1,17 @@
 'use strict'
 
-import $ from 'jquery'
 import * as ace from 'brace'
 import 'brace/theme/tomorrow_night'
 import 'brace/mode/markdown'
 import pageLoader from '../components/page-loader'
 
-module.exports = (alerts) => {
-  if ($('#page-type-source').length) {
-    var scEditor = ace.edit('source-display')
+export default {
+  name: 'source-view',
+  data() {
+    return {}
+  },
+  mounted() {
+    let scEditor = ace.edit('source-display')
     scEditor.setTheme('ace/theme/tomorrow_night')
     scEditor.getSession().setMode('ace/mode/markdown')
     scEditor.setOption('fontSize', '14px')
@@ -16,12 +19,6 @@ module.exports = (alerts) => {
     scEditor.setOption('wrap', true)
     scEditor.setReadOnly(true)
     scEditor.renderer.updateFull()
-
-    let currentBasePath = ($('#page-type-source').data('entrypath') !== 'home') ? $('#page-type-source').data('entrypath') : ''
-
-    require('../modals/create.js')(currentBasePath)
-    require('../modals/move.js')(currentBasePath, alerts)
-
     scEditor.renderer.on('afterRender', () => {
       pageLoader.complete()
     })
diff --git a/client/scss/components/_editor.scss b/client/scss/components/_editor.scss
index c44e78e5..f967c252 100644
--- a/client/scss/components/_editor.scss
+++ b/client/scss/components/_editor.scss
@@ -347,7 +347,7 @@
 	height: 100%;
 }*/
 
-#page-type-source .ace-container {
+main > .ace-container {
 	min-height: 95vh;
 }
 
diff --git a/server/views/pages/source.pug b/server/views/pages/source.pug
index ac40729e..2bdc5696 100644
--- a/server/views/pages/source.pug
+++ b/server/views/pages/source.pug
@@ -4,7 +4,7 @@ block rootNavCenter
   h2.nav-item= pageData.meta.title
 
 block rootNavRight
-  i.nav-item#notifload
+  loading-spinner
   span.nav-item
     if rights.write
       a.button.is-outlined.btn-move-prompt.is-hidden
@@ -23,7 +23,7 @@ block rootNavRight
 
 block content
 
-  #page-type-source(data-entrypath=pageData.meta.path)
+  source-view(inline-template, data-entrypath=pageData.meta.path)
     .ace-container
       #source-display= pageData.markdown