Преглед на файлове

Create mode + Source view + UI enhancements

NGPixel преди 8 години
родител
ревизия
16f300f0d5

+ 2 - 2
README.md

@@ -19,8 +19,8 @@
 - [ ] Assets Management
 - [ ] Assets Management
 - [ ] Authentication
 - [ ] Authentication
 - [x] Caching
 - [x] Caching
-- [ ] Create Entry
-- [ ] Edit Entry
+- [x] Create Entry
+- [x] Edit Entry
 - [x] Git Management
 - [x] Git Management
 - [ ] History Management
 - [ ] History Management
 - [ ] Markdown Editor
 - [ ] Markdown Editor

Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
assets/css/app.css


Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
assets/js/app.js


Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
assets/js/libs.js


+ 4 - 0
client/content/create.md

@@ -0,0 +1,4 @@
+<!-- TITLE: {TITLE} -->
+<!-- SUBTITLE: A quick summary of {TITLE} -->
+
+# Header

+ 7 - 1
client/js/app.js

@@ -56,6 +56,12 @@ jQuery( document ).ready(function( $ ) {
 	// Pages logic
 	// Pages logic
 	// ====================================
 	// ====================================
 
 
+	//=include pages/view.js
+	//=include pages/create.js
 	//=include pages/edit.js
 	//=include pages/edit.js
+	//=include pages/source.js
 
 
-});
+});
+
+//=include helpers/form.js
+//=include helpers/pages.js

+ 16 - 0
client/js/helpers/form.js

@@ -0,0 +1,16 @@
+
+function setInputSelection(input, startPos, endPos) {
+    input.focus();
+    if (typeof input.selectionStart != "undefined") {
+        input.selectionStart = startPos;
+        input.selectionEnd = endPos;
+    } else if (document.selection && document.selection.createRange) {
+        // IE branch
+        input.select();
+        var range = document.selection.createRange();
+        range.collapse(true);
+        range.moveEnd("character", endPos);
+        range.moveStart("character", startPos);
+        range.select();
+    }
+}

+ 11 - 0
client/js/helpers/pages.js

@@ -0,0 +1,11 @@
+
+function makeSafePath(rawPath) {
+
+	let rawParts = _.split(_.trim(rawPath), '/');
+	rawParts = _.map(rawParts, (r) => {
+		return _.kebabCase(_.deburr(_.trim(r)));
+	});
+
+	return _.join(_.filter(rawParts, (r) => { return !_.isEmpty(r); }), '/');
+
+}

+ 32 - 0
client/js/pages/create.js

@@ -0,0 +1,32 @@
+
+if($('#page-type-create').length) {
+
+	//-> Discard
+
+	$('.btn-create-discard').on('click', (ev) => {
+		$('#modal-create-discard').toggleClass('is-active');
+	});
+
+	//-> Save
+
+	$('.btn-create-save').on('click', (ev) => {
+
+		$.ajax(window.location.href, {
+			data: {
+				markdown: mde.value()
+			},
+			dataType: 'json',
+			method: 'PUT'
+		}).then((rData, rStatus, rXHR) => {
+			if(rData.ok) {
+				window.location.assign('/' + $('#page-type-create').data('entrypath'));
+			} else {
+				alerts.pushError('Something went wrong', rData.error);
+			}
+		}, (rXHR, rStatus, err) => {
+			alerts.pushError('Something went wrong', 'Save operation failed.');
+		});
+
+	});
+
+}

+ 12 - 0
client/js/pages/source.js

@@ -0,0 +1,12 @@
+
+if($('#page-type-source').length) {
+
+	var scEditor = ace.edit("source-display");
+  scEditor.setTheme("ace/theme/tomorrow_night");
+  scEditor.getSession().setMode("ace/mode/markdown");
+  scEditor.setReadOnly(true);
+  scEditor.renderer.updateFull();
+
+  console.log(scEditor.getSession().getLength());
+
+}

+ 34 - 0
client/js/pages/view.js

@@ -0,0 +1,34 @@
+
+if($('#page-type-view').length) {
+
+	let currentBasePath = ($('#page-type-view').data('entrypath') !== 'home') ? $('#page-type-view').data('entrypath') + '/' : '';
+	let suggestedCreatePath = currentBasePath + 'new-page';
+
+	//-> Create New Document
+
+	$('.btn-create-prompt').on('click', (ev) => {
+		$('#txt-create-prompt').val(suggestedCreatePath);
+		$('#modal-create-prompt').toggleClass('is-active');
+		setInputSelection($('#txt-create-prompt').get(0), currentBasePath.length, suggestedCreatePath.length);
+		$('#txt-create-prompt').removeClass('is-danger').next().addClass('is-hidden');
+	});
+
+	$('#txt-create-prompt').on('keypress', (ev) => {
+		if(ev.which === 13) {
+			$('.btn-create-go').trigger('click');
+		}
+	});
+
+	$('.btn-create-go').on('click', (ev) => {
+
+		let newDocPath = makeSafePath($('#txt-create-prompt').val());
+		if(_.isEmpty(newDocPath)) {
+			$('#txt-create-prompt').addClass('is-danger').next().removeClass('is-hidden');
+		} else {
+			$('#txt-create-prompt').parent().addClass('is-loading');
+			window.location.assign('/create/' + newDocPath);
+		}
+
+	});
+
+}

+ 13 - 0
client/scss/components/_editor.scss

@@ -5,4 +5,17 @@
 
 
 .editor-toolbar .fa {
 .editor-toolbar .fa {
 	font-size: 14px;
 	font-size: 14px;
+}
+
+.ace-container {
+	position: relative;
+	min-height: 95vh;
+}
+
+#source-display {
+	position: absolute;
+	top: 0;
+	left: 0;
+	bottom: 0;
+	right: 0;
 }
 }

+ 1 - 1
client/scss/layout/_content.scss

@@ -16,7 +16,7 @@
 		border-bottom: 1px dotted $grey-light;
 		border-bottom: 1px dotted $grey-light;
 		padding-bottom: 4px;
 		padding-bottom: 4px;
 		font-weight: 400;
 		font-weight: 400;
-		color: $grey-dark;
+		color: desaturate(darken($purple, 15%), 10%);
 	}
 	}
 
 
 	a.toc-anchor {
 	a.toc-anchor {

+ 4 - 0
client/scss/layout/_header.scss

@@ -1,4 +1,8 @@
 
 
+#header {
+	z-index: 5;
+}
+
 h2.nav-item {
 h2.nav-item {
 	font-size: 150%;
 	font-size: 150%;
 	color: $orange;
 	color: $orange;

+ 91 - 5
controllers/pages.js

@@ -58,14 +58,95 @@ router.put('/edit/*', (req, res, next) => {
 // CREATE MODE
 // CREATE MODE
 // ==========================================
 // ==========================================
 
 
-router.get('/new/*', (req, res, next) => {
-	res.send('CREATE MODE');
+router.get('/create/*', (req, res, next) => {
+
+	if(_.some(['create','edit','account','source','history','mk'], (e) => { return _.startsWith(req.path, '/create/' + e); })) {
+		return res.render('error', {
+			message: 'You cannot create a document with this name as it is reserved by the system.',
+			error: {}
+		});
+	}
+	
+	let safePath = entries.parsePath(_.replace(req.path, '/create', ''));
+
+	entries.exists(safePath).then((docExists) => {
+		if(!docExists) {
+			entries.getStarter(safePath).then((contents) => {
+
+				let pageData = {
+					markdown: contents,
+					meta: {
+						title: _.startCase(safePath),
+						path: safePath
+					}
+				};
+				return res.render('pages/create', { pageData });
+
+			}).catch((err) => {
+				throw new Error('Could not load starter content!');
+			});
+		} else {
+			throw new Error('This entry already exists!');
+		}
+	}).catch((err) => {
+		res.render('error', {
+			message: err.message,
+			error: {}
+		});
+	});
+
+});
+
+router.put('/create/*', (req, res, next) => {
+
+	let safePath = entries.parsePath(_.replace(req.path, '/create', ''));
+
+	entries.create(safePath, req.body.markdown).then(() => {
+		res.json({
+			ok: true
+		});
+	}).catch((err) => {
+		res.json({
+			ok: false,
+			error: err.message
+		});
+	});
+
 });
 });
 
 
 // ==========================================
 // ==========================================
 // VIEW MODE
 // VIEW MODE
 // ==========================================
 // ==========================================
 
 
+/**
+ * View source of a document
+ */
+router.get('/source/*', (req, res, next) => {
+
+	let safePath = entries.parsePath(_.replace(req.path, '/source', ''));
+
+	entries.fetchOriginal(safePath, {
+		parseMarkdown: false,
+		parseMeta: true,
+		parseTree: false,
+		includeMarkdown: true,
+		includeParentInfo: false,
+		cache: false
+	}).then((pageData) => {
+		if(pageData) {
+			return res.render('pages/source', { pageData });
+		} else {
+			throw new Error('Invalid page path.');
+		}
+	}).catch((err) => {
+		res.render('error', {
+			message: err.message,
+			error: {}
+		});
+	});
+
+});
+
 /**
 /**
  * View document
  * View document
  */
  */
@@ -77,11 +158,16 @@ router.get('/*', (req, res, next) => {
 		if(pageData) {
 		if(pageData) {
 			return res.render('pages/view', { pageData });
 			return res.render('pages/view', { pageData });
 		} else {
 		} else {
-			return next();
+			res.render('error', {
+				message: err.message,
+				error: {}
+			});
 		}
 		}
 	}).catch((err) => {
 	}).catch((err) => {
-		winston.error(err);
-		next();
+		res.render('error', {
+			message: err.message,
+			error: {}
+		});
 	});
 	});
 
 
 });
 });

+ 9 - 6
gulpfile.js

@@ -19,12 +19,15 @@ var include = require("gulp-include");
  */
  */
 var paths = {
 var paths = {
 	scriptlibs: [
 	scriptlibs: [
-	  	'./node_modules/lodash/lodash.min.js',
-      './node_modules/jquery/dist/jquery.min.js',
-      './node_modules/vue/dist/vue.min.js',
-      './node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js',
-      './node_modules/sticky-js/dist/sticky.min.js',
-      './node_modules/simplemde/dist/simplemde.min.js'
+		'./node_modules/jquery/dist/jquery.min.js',
+		'./node_modules/vue/dist/vue.min.js',
+		'./node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js',
+		'./node_modules/sticky-js/dist/sticky.min.js',
+		'./node_modules/simplemde/dist/simplemde.min.js',
+		'./node_modules/ace-builds/src-min-noconflict/ace.js',
+		'./node_modules/ace-builds/src-min-noconflict/mode-markdown.js',
+		'./node_modules/ace-builds/src-min-noconflict/theme-tomorrow_night.js',
+		'./node_modules/lodash/lodash.min.js'
 	],
 	],
 	scriptapps: [
 	scriptapps: [
 		'./client/js/components/*.js',
 		'./client/js/components/*.js',

+ 71 - 1
models/entries.js

@@ -33,6 +33,31 @@ module.exports = {
 
 
 	},
 	},
 
 
+	/**
+	 * Check if a document already exists
+	 *
+	 * @param      {String}  entryPath  The entry path
+	 * @return     {Promise<Boolean>}  True if exists, false otherwise
+	 */
+	exists(entryPath) {
+
+		let self = this;
+
+		return self.fetchOriginal(entryPath, {
+			parseMarkdown: false,
+			parseMeta: false,
+			parseTree: false,
+			includeMarkdown: false,
+			includeParentInfo: false,
+			cache: false
+		}).then(() => {
+			return true;
+		}).catch((err) => {
+			return false;
+		});
+
+	},
+
 	/**
 	/**
 	 * Fetch a document from cache, otherwise the original
 	 * Fetch a document from cache, otherwise the original
 	 *
 	 *
@@ -145,6 +170,8 @@ module.exports = {
 			} else {
 			} else {
 				return false;
 				return false;
 			}
 			}
+		}).catch((err) => {
+			return Promise.reject(new Error('Entry ' + entryPath + ' does not exist!'));
 		});
 		});
 
 
 	},
 	},
@@ -253,7 +280,33 @@ module.exports = {
 				return Promise.reject(new Error('Entry does not exist!'));
 				return Promise.reject(new Error('Entry does not exist!'));
 			}
 			}
 		}).catch((err) => {
 		}).catch((err) => {
-			return new Error('Entry does not exist!');
+			return Promise.reject(new Error('Entry does not exist!'));
+		});
+
+	},
+
+	/**
+	 * Create a new document
+	 *
+	 * @param      {String}            entryPath  The entry path
+	 * @param      {String}            contents   The markdown-formatted contents
+	 * @return     {Promise<Boolean>}  True on success, false on failure
+	 */
+	create(entryPath, contents) {
+
+		let self = this;
+
+		return self.exists(entryPath).then((docExists) => {
+			if(!docExists) {
+				return self.makePersistent(entryPath, contents).then(() => {
+					return self.fetchOriginal(entryPath, {});
+				});
+			} else {
+				return Promise.reject(new Error('Entry already exists!'));
+			}
+		}).catch((err) => {
+			winston.error(err);
+			return Promise.reject(new Error('Something went wrong.'));
 		});
 		});
 
 
 	},
 	},
@@ -274,6 +327,23 @@ module.exports = {
 			return git.commitDocument(entryPath);
 			return git.commitDocument(entryPath);
 		});
 		});
 
 
+	},
+
+	/**
+	 * Generate a starter page content based on the entry path
+	 *
+	 * @param      {String}           entryPath  The entry path
+	 * @return     {Promise<String>}  Starter content
+	 */
+	getStarter(entryPath) {
+
+		let self = this;
+		let formattedTitle = _.startCase(_.last(_.split(entryPath, '/')));
+
+		return fs.readFileAsync(path.join(ROOTPATH, 'client/content/create.md'), 'utf8').then((contents) => {
+			return _.replace(contents, new RegExp('{TITLE}', 'g'), formattedTitle);
+		});
+
 	}
 	}
 
 
 };
 };

+ 2 - 3
models/markdown.js

@@ -11,7 +11,6 @@ var Promise = require('bluebird'),
 	mdExpandTabs = require('markdown-it-expand-tabs'),
 	mdExpandTabs = require('markdown-it-expand-tabs'),
 	mdAttrs = require('markdown-it-attrs'),
 	mdAttrs = require('markdown-it-attrs'),
 	hljs = require('highlight.js'),
 	hljs = require('highlight.js'),
-	slug = require('slug'),
 	cheerio = require('cheerio'),
 	cheerio = require('cheerio'),
 	_ = require('lodash');
 	_ = require('lodash');
 
 
@@ -81,10 +80,10 @@ const parseTree = (content) => {
 			let anchor = "";
 			let anchor = "";
 			if (heading.children && heading.children[0].type === "link_open") {
 			if (heading.children && heading.children[0].type === "link_open") {
 			 content = heading.children[1].content;
 			 content = heading.children[1].content;
-			 anchor = slug(content, {lower: true});
+			 anchor = _.kebabCase(content);
 			} else {
 			} else {
 			 content = heading.content
 			 content = heading.content
-			 anchor = slug(heading.children.reduce((acc, t) => acc + t.content, ""), {lower: true});
+			 anchor = _.kebabCase(heading.children.reduce((acc, t) => acc + t.content, ""));
 			}
 			}
 
 
 			tocArray.push({
 			tocArray.push({

+ 5 - 5
package.json

@@ -35,7 +35,6 @@
     "bluebird": "^3.4.1",
     "bluebird": "^3.4.1",
     "body-parser": "^1.15.2",
     "body-parser": "^1.15.2",
     "bson": "^0.5.4",
     "bson": "^0.5.4",
-    "bulma": "^0.1.2",
     "cheerio": "^0.22.0",
     "cheerio": "^0.22.0",
     "child-process-promise": "^2.1.3",
     "child-process-promise": "^2.1.3",
     "compression": "^1.6.2",
     "compression": "^1.6.2",
@@ -55,7 +54,6 @@
     "i18next": "^3.4.1",
     "i18next": "^3.4.1",
     "i18next-express-middleware": "^1.0.1",
     "i18next-express-middleware": "^1.0.1",
     "i18next-node-fs-backend": "^0.1.2",
     "i18next-node-fs-backend": "^0.1.2",
-    "jquery-smooth-scroll": "^2.0.0",
     "js-yaml": "^3.6.1",
     "js-yaml": "^3.6.1",
     "lodash": "^4.15.0",
     "lodash": "^4.15.0",
     "lokijs": "^1.4.1",
     "lokijs": "^1.4.1",
@@ -77,15 +75,14 @@
     "search-index": "^0.8.15",
     "search-index": "^0.8.15",
     "serve-favicon": "^2.3.0",
     "serve-favicon": "^2.3.0",
     "simplemde": "^1.11.2",
     "simplemde": "^1.11.2",
-    "slug": "^0.9.1",
-    "sticky-js": "^1.0.5",
-    "twemoji-awesome": "^1.0.4",
     "validator": "^5.5.0",
     "validator": "^5.5.0",
     "validator-as-promised": "^1.0.2",
     "validator-as-promised": "^1.0.2",
     "winston": "^2.2.0"
     "winston": "^2.2.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
+    "ace-builds": "^1.2.5",
     "babel-preset-es2015": "^6.13.2",
     "babel-preset-es2015": "^6.13.2",
+    "bulma": "^0.1.2",
     "chai": "^3.5.0",
     "chai": "^3.5.0",
     "chai-as-promised": "^5.3.0",
     "chai-as-promised": "^5.3.0",
     "codacy-coverage": "^2.0.0",
     "codacy-coverage": "^2.0.0",
@@ -104,11 +101,14 @@
     "gulp-zip": "^3.2.0",
     "gulp-zip": "^3.2.0",
     "istanbul": "^0.4.5",
     "istanbul": "^0.4.5",
     "jquery": "^3.1.0",
     "jquery": "^3.1.0",
+    "jquery-smooth-scroll": "^2.0.0",
     "merge-stream": "^1.0.0",
     "merge-stream": "^1.0.0",
     "mocha": "^3.0.2",
     "mocha": "^3.0.2",
     "mocha-lcov-reporter": "^1.2.0",
     "mocha-lcov-reporter": "^1.2.0",
     "nodemon": "^1.10.2",
     "nodemon": "^1.10.2",
+    "twemoji-awesome": "^1.0.4",
     "snyk": "^1.18.1",
     "snyk": "^1.18.1",
+    "sticky-js": "^1.0.5",
     "vue": "^1.0.26"
     "vue": "^1.0.26"
   }
   }
 }
 }

+ 4 - 4
views/common/footer.pug

@@ -4,7 +4,7 @@ footer.footer
 			p
 			p
 				= t('footer.poweredby') + ' '
 				= t('footer.poweredby') + ' '
 				a(href='https://github.com/Requarks/wiki') Requarks Wiki
 				a(href='https://github.com/Requarks/wiki') Requarks Wiki
-				| .
-				p
-					a.icon(href='https://github.com/Requarks/wiki')
-						i.fa.fa-github
+			p
+				a.icon(href='https://github.com/Requarks/wiki')
+					i.fa.fa-github
+					

+ 5 - 5
views/common/header.pug

@@ -1,5 +1,5 @@
 
 
-nav.nav.has-shadow.stickyscroll
+nav.nav.has-shadow.stickyscroll#header
 	.nav-left
 	.nav-left
 		block rootNavLeft
 		block rootNavLeft
 			a.nav-item.is-brand(href='/')
 			a.nav-item.is-brand(href='/')
@@ -17,16 +17,16 @@ nav.nav.has-shadow.stickyscroll
 	.nav-right.nav-menu
 	.nav-right.nav-menu
 		block rootNavRight
 		block rootNavRight
 			i.nav-item#notifload
 			i.nav-item#notifload
-			a.nav-item(href='#')
+			a.nav-item(href='/history/' + pageData.meta.path)
 				| History
 				| History
-			a.nav-item(href='#')
+			a.nav-item(href='/source/' + pageData.meta.path)
 				| Source
 				| Source
 			span.nav-item
 			span.nav-item
-				a.button
+				a.button(href='/edit/' + pageData.meta.path)
 					span.icon
 					span.icon
 						i.fa.fa-edit
 						i.fa.fa-edit
 					span Edit
 					span Edit
-				a.button.is-primary(href='#', onclick='$(".modal").addClass("is-active");')
+				a.button.is-primary.btn-create-prompt
 					span.icon
 					span.icon
 						i.fa.fa-plus
 						i.fa.fa-plus
 					span Create
 					span Create

+ 17 - 0
views/modals/create.pug

@@ -0,0 +1,17 @@
+
+.modal#modal-create-prompt
+	.modal-background
+	.modal-container
+		.modal-content
+			.card.is-fullwidth
+				header.card-header
+					p.card-header-title Create New Page
+				.card-content
+					.content
+						label.label Enter the new document path:
+						p.control
+							input.input(type='text', placeholder='page-name')#txt-create-prompt
+							span.help.is-danger.is-hidden This document path is invalid!
+				footer.card-footer
+					a.card-footer-item.btn-create-prompt Discard
+					a.card-footer-item.btn-create-go Create

+ 14 - 0
views/modals/edit.pug

@@ -0,0 +1,14 @@
+
+.modal#modal-edit-discard
+	.modal-background
+	.modal-container
+		.modal-content
+			.card.is-fullwidth
+				header.card-header.is-warning
+					p.card-header-title Discard?
+				.card-content
+					.content
+						| Are you sure you want to leave this page and loose any modifications?
+				footer.card-footer
+					a.card-footer-item.btn-edit-discard Stay on page
+					a.card-footer-item(href='/' + pageData.meta.path) Discard

+ 36 - 0
views/pages/create.pug

@@ -0,0 +1,36 @@
+extends ../layout
+
+block rootNavCenter
+	h2.nav-item Create New Document
+
+block rootNavRight
+	i.nav-item#notifload
+	span.nav-item
+		a.button.is-warning.btn-create-discard
+			span.icon
+				i.fa.fa-times
+			span Discard
+		a.button.is-success.btn-create-save
+			span.icon
+				i.fa.fa-check
+			span Save Document
+
+block content
+
+	#page-type-create(data-entrypath=pageData.meta.path)
+		section.section.is-small
+			textarea#mk-editor= pageData.markdown
+
+	.modal#modal-create-discard
+		.modal-background
+		.modal-container
+			.modal-content
+				.card.is-fullwidth
+					header.card-header.is-warning
+						p.card-header-title Discard?
+					.card-content
+						.content
+							| Are you sure you want to leave this page and loose anything you wrote so far?
+					footer.card-footer
+						a.card-footer-item.btn-create-discard Stay on page
+						a.card-footer-item(href='/') Discard

+ 3 - 15
views/pages/edit.pug

@@ -5,9 +5,9 @@ block rootNavCenter
 
 
 block rootNavRight
 block rootNavRight
 	i.nav-item#notifload
 	i.nav-item#notifload
-	a.nav-item(href='#')
+	a.nav-item(href='/history/' + pageData.meta.path, target='_blank')
 		| History
 		| History
-	a.nav-item(href='#')
+	a.nav-item(href='/source/' + pageData.meta.path, target='_blank')
 		| Source
 		| Source
 	span.nav-item
 	span.nav-item
 		a.button.is-warning.btn-edit-discard
 		a.button.is-warning.btn-edit-discard
@@ -25,16 +25,4 @@ block content
 		section.section.is-small
 		section.section.is-small
 			textarea#mk-editor= pageData.markdown
 			textarea#mk-editor= pageData.markdown
 
 
-	.modal#modal-edit-discard
-		.modal-background
-		.modal-container
-			.modal-content
-				.card.is-fullwidth
-					header.card-header.is-warning
-						p.card-header-title Discard?
-					.card-content
-						.content
-							| Are you sure you want to leave this page and loose any modifications?
-					footer.card-footer
-						a.card-footer-item.btn-edit-discard Stay on page
-						a.card-footer-item(href='/' + pageData.meta.path) Discard
+	include ../modals/edit

+ 9 - 0
views/pages/source.pug

@@ -0,0 +1,9 @@
+extends ../layout
+
+block content
+
+	#page-type-source(data-entrypath=pageData.meta.path)
+		.ace-container
+			#source-display= pageData.markdown
+
+	include ../modals/create

+ 4 - 18
views/pages/view.pug

@@ -10,16 +10,16 @@ mixin tocMenu(ti)
 
 
 block rootNavRight
 block rootNavRight
 	i.nav-item#notifload
 	i.nav-item#notifload
-	a.nav-item(href='#')
+	a.nav-item(href='/history/' + pageData.meta.path)
 		| History
 		| History
-	a.nav-item(href='#')
+	a.nav-item(href='/source/' + pageData.meta.path)
 		| Source
 		| Source
 	span.nav-item
 	span.nav-item
 		a.button(href='/edit/' + pageData.meta.path)
 		a.button(href='/edit/' + pageData.meta.path)
 			span.icon
 			span.icon
 				i.fa.fa-edit
 				i.fa.fa-edit
 			span Edit
 			span Edit
-		a.button.is-primary(href='#', onclick='$(".modal").addClass("is-active");')
+		a.button.is-primary.btn-create-prompt
 			span.icon
 			span.icon
 				i.fa.fa-plus
 				i.fa.fa-plus
 			span Create
 			span Create
@@ -61,18 +61,4 @@ block content
 						.content.mkcontent
 						.content.mkcontent
 							!= pageData.html
 							!= pageData.html
 
 
-	.modal
-		.modal-background
-		.modal-container
-			.modal-content
-				.card.is-fullwidth
-					header.card-header
-						p.card-header-title Create New Page
-					.card-content
-						.content
-							label.label Enter the new document name:
-							p.control
-								input.input(type='text', placeholder='page-name')
-					footer.card-footer
-						a.card-footer-item(onclick='$(".modal").removeClass("is-active");') Discard
-						a.card-footer-item.featured Create
+	include ../modals/create

Някои файлове не бяха показани, защото твърде много файлове са промени