瀏覽代碼

feat: login page UI

NGPixel 7 年之前
父節點
當前提交
52630127cd

二進制
assets/images/bg.jpg


二進制
assets/images/bg_1.jpg


二進制
assets/images/bg_2.jpg


二進制
assets/images/bg_3.jpg


+ 2 - 15
client/index.js

@@ -1,17 +1,4 @@
 'use strict'
 
-let logic = document.documentElement.dataset.logic
-
-switch (logic) {
-  case 'error':
-    require('./scss/error.scss')
-    break
-  case 'login':
-    require('./scss/login.scss')
-    require('./js/login.js')
-    break
-  default:
-    require('./scss/app.scss')
-    require('./js/app.js')
-    break
-}
+require('./scss/app.scss')
+require('./js/app.js')

+ 8 - 30
client/js/app.js

@@ -1,28 +1,21 @@
 'use strict'
 
-/* global $, siteRoot */
+/* global siteConfig */
 /* eslint-disable no-new */
 
 import Vue from 'vue'
 import VueResource from 'vue-resource'
 import VueClipboards from 'vue-clipboards'
-import VueLodash from 'vue-lodash'
 import store from './store'
-import io from 'socket-io-client'
 import i18next from 'i18next'
 import i18nextXHR from 'i18next-xhr-backend'
 import VueI18Next from '@panter/vue-i18next'
-import 'jquery-contextmenu'
-import 'jquery-simple-upload'
-import 'jquery-smooth-scroll'
-import 'jquery-sticky'
 
 // ====================================
 // Load Helpers
 // ====================================
 
 import helpers from './helpers'
-import _ from './helpers/lodash'
 
 // ====================================
 // Load Vue Components
@@ -63,7 +56,6 @@ import sourceViewComponent from './pages/source-view.component.js'
 Vue.use(VueResource)
 Vue.use(VueClipboards)
 Vue.use(VueI18Next)
-Vue.use(VueLodash, _)
 Vue.use(helpers)
 
 // ====================================
@@ -105,39 +97,27 @@ i18next
   .use(i18nextXHR)
   .init({
     backend: {
-      loadPath: siteRoot + '/js/i18n/{{lng}}.json'
+      loadPath: siteConfig.path + '/js/i18n/{{lng}}.json'
     },
-    lng: siteLang,
-    fallbackLng: siteLang
+    lng: siteConfig.lang,
+    fallbackLng: siteConfig.lang
   })
 
-$(() => {
+document.addEventListener('DOMContentLoaded', ev => {
   // ====================================
   // Notifications
   // ====================================
 
-  $(window).bind('beforeunload', () => {
+  window.addEventListener('beforeunload', () => {
     store.dispatch('startLoading')
   })
-  $(document).ajaxSend(() => {
-    store.dispatch('startLoading')
-  }).ajaxComplete(() => {
-    store.dispatch('stopLoading')
-  })
-
-  // ====================================
-  // Establish WebSocket connection
-  // ====================================
-
-  let socket = io(window.location.origin)
-  window.socket = socket
 
   // ====================================
   // Bootstrap Vue
   // ====================================
 
   const i18n = new VueI18Next(i18next)
-  window.wikijs = new Vue({
+  window.wiki = new Vue({
     mixins: [helpers],
     components: {},
     store,
@@ -151,9 +131,7 @@ $(() => {
       }
     },
     mounted() {
-      $('a:not(.toc-anchor)').smoothScroll({ speed: 500, offset: -50 })
-      $('#header').sticky({ topSpacing: 0 })
-      $('.sidebar-pagecontents').sticky({ topSpacing: 15, bottomSpacing: 75 })
+
     }
   })
 })

+ 153 - 0
client/js/app.old.js

@@ -0,0 +1,153 @@
+'use strict'
+
+/* global $, siteConfig */
+/* eslint-disable no-new */
+
+import Vue from 'vue'
+import VueResource from 'vue-resource'
+import VueClipboards from 'vue-clipboards'
+import VueLodash from 'vue-lodash'
+import store from './store'
+import i18next from 'i18next'
+import i18nextXHR from 'i18next-xhr-backend'
+import VueI18Next from '@panter/vue-i18next'
+import 'jquery-contextmenu'
+import 'jquery-simple-upload'
+import 'jquery-smooth-scroll'
+import 'jquery-sticky'
+
+// ====================================
+// Load Helpers
+// ====================================
+
+import helpers from './helpers'
+import _ from './helpers/lodash'
+
+// ====================================
+// Load Vue Components
+// ====================================
+
+import alertComponent from './components/alert.vue'
+import anchorComponent from './components/anchor.vue'
+import colorPickerComponent from './components/color-picker.vue'
+import editorCodeblockComponent from './components/editor-codeblock.vue'
+import editorFileComponent from './components/editor-file.vue'
+import editorVideoComponent from './components/editor-video.vue'
+import historyComponent from './components/history.vue'
+import loadingSpinnerComponent from './components/loading-spinner.vue'
+import modalCreatePageComponent from './components/modal-create-page.vue'
+import modalCreateUserComponent from './components/modal-create-user.vue'
+import modalDeleteUserComponent from './components/modal-delete-user.vue'
+import modalDiscardPageComponent from './components/modal-discard-page.vue'
+import modalMovePageComponent from './components/modal-move-page.vue'
+import modalProfile2faComponent from './components/modal-profile-2fa.vue'
+import modalUpgradeSystemComponent from './components/modal-upgrade-system.vue'
+import pageLoaderComponent from './components/page-loader.vue'
+import searchComponent from './components/search.vue'
+import toggleComponent from './components/toggle.vue'
+import treeComponent from './components/tree.vue'
+
+import adminEditUserComponent from './pages/admin-edit-user.component.js'
+import adminProfileComponent from './pages/admin-profile.component.js'
+import adminSettingsComponent from './pages/admin-settings.component.js'
+import adminThemeComponent from './pages/admin-theme.component.js'
+import contentViewComponent from './pages/content-view.component.js'
+import editorComponent from './components/editor.component.js'
+import sourceViewComponent from './pages/source-view.component.js'
+
+// ====================================
+// Initialize Vue Modules
+// ====================================
+
+Vue.use(VueResource)
+Vue.use(VueClipboards)
+Vue.use(VueI18Next)
+Vue.use(VueLodash, _)
+Vue.use(helpers)
+
+// ====================================
+// Register Vue Components
+// ====================================
+
+Vue.component('alert', alertComponent)
+Vue.component('adminEditUser', adminEditUserComponent)
+Vue.component('adminProfile', adminProfileComponent)
+Vue.component('adminSettings', adminSettingsComponent)
+Vue.component('adminTheme', adminThemeComponent)
+Vue.component('anchor', anchorComponent)
+Vue.component('colorPicker', colorPickerComponent)
+Vue.component('contentView', contentViewComponent)
+Vue.component('editor', editorComponent)
+Vue.component('editorCodeblock', editorCodeblockComponent)
+Vue.component('editorFile', editorFileComponent)
+Vue.component('editorVideo', editorVideoComponent)
+Vue.component('history', historyComponent)
+Vue.component('loadingSpinner', loadingSpinnerComponent)
+Vue.component('modalCreatePage', modalCreatePageComponent)
+Vue.component('modalCreateUser', modalCreateUserComponent)
+Vue.component('modalDeleteUser', modalDeleteUserComponent)
+Vue.component('modalDiscardPage', modalDiscardPageComponent)
+Vue.component('modalMovePage', modalMovePageComponent)
+Vue.component('modalProfile2fa', modalProfile2faComponent)
+Vue.component('modalUpgradeSystem', modalUpgradeSystemComponent)
+Vue.component('pageLoader', pageLoaderComponent)
+Vue.component('search', searchComponent)
+Vue.component('sourceView', sourceViewComponent)
+Vue.component('toggle', toggleComponent)
+Vue.component('tree', treeComponent)
+
+// ====================================
+// Load Localization strings
+// ====================================
+
+i18next
+  .use(i18nextXHR)
+  .init({
+    backend: {
+      loadPath: siteConfig.path + '/js/i18n/{{lng}}.json'
+    },
+    lng: siteConfig.lang,
+    fallbackLng: siteConfig.lang
+  })
+
+$(() => {
+  // ====================================
+  // Notifications
+  // ====================================
+
+  $(window).bind('beforeunload', () => {
+    store.dispatch('startLoading')
+  })
+  $(document).ajaxSend(() => {
+    store.dispatch('startLoading')
+  }).ajaxComplete(() => {
+    store.dispatch('stopLoading')
+  })
+
+  // ====================================
+  // Bootstrap Vue
+  // ====================================
+
+  const i18n = new VueI18Next(i18next)
+  if (document.querySelector('#root')) {
+    window.wikijs = new Vue({
+      mixins: [helpers],
+      components: {},
+      store,
+      i18n,
+      el: '#root',
+      methods: {
+        changeTheme(opts) {
+          this.$el.className = `has-stickynav is-primary-${opts.primary} is-alternate-${opts.alt}`
+          this.$refs.header.className = `nav is-${opts.primary}`
+          this.$refs.footer.className = `footer is-${opts.footer}`
+        }
+      },
+      mounted() {
+        $('a:not(.toc-anchor)').smoothScroll({ speed: 500, offset: -50 })
+        $('#header').sticky({ topSpacing: 0 })
+        $('.sidebar-pagecontents').sticky({ topSpacing: 15, bottomSpacing: 75 })
+      }
+    })
+  }
+})

+ 1 - 0
client/js/helpers/index.js

@@ -1,6 +1,7 @@
 'use strict'
 
 const helpers = {
+  _: require('./lodash'),
   common: require('./common'),
   form: require('./form'),
   pages: require('./pages')

+ 0 - 7
client/js/login.js

@@ -1,7 +0,0 @@
-'use strict'
-
-/* global $ */
-
-$(() => {
-  $('#login-user').focus()
-})

+ 2 - 1
client/scss/app.scss

@@ -42,6 +42,7 @@ $primary: 'indigo';
 @import 'layout/_header';
 @import 'layout/_loader';
 
-@import 'pages/_welcome';
+@import 'pages/login';
+@import 'pages/welcome';
 
 @import 'base/print';

+ 8 - 2
client/scss/components/button.scss

@@ -4,7 +4,7 @@
 	border: 1px solid mc('orange','700');
 	border-radius: 3px;
 	display: inline-flex;
-	height: 30px;
+	height: 40px;
 	align-items: center;
 	padding: 0 15px;
 	font-size: 13px;
@@ -74,7 +74,13 @@
 
 	&.is-featured {
 		animation: btnInvertedPulse .6s ease alternate infinite;
-	}
+  }
+
+  &.is-fullwidth {
+    width: 100%;
+    text-align: center;
+    justify-content: center;
+  }
 
 	&.is-disabled, &:disabled {
 		background-color: mc('grey', '300');

+ 160 - 305
client/scss/pages/_login.scss

@@ -1,306 +1,161 @@
-
-body {
-	padding: 0;
-	margin: 0;
-	font-family: $core-font-standard;
-	font-size: 14px;
-}
-
-a {
-	color: #FFF;
-	transition: color 0.4s ease;
-	text-decoration: none;
-
-	&:hover {
-		color: mc('orange','600');
-		text-decoration: underline;
-	}
-
-}
-
-#bg {
-	position: fixed;
-	top: 0;
-	left: 0;
-	width: 100%;
-	height: 100%;
-	z-index: 1;
-	background-color: #000;
-
-	> div {
-		background-size: cover;
-		background-position: center center;
-		width: 100%;
-		height: 100%;
-		position: absolute;
-		top: 0;
-		left: 0;
-		opacity: 0;
-		visibility: hidden;
-		transition: opacity 3s ease, visibility 3s;
-		animation: bg 30s linear infinite;
-
-		&:nth-child(1) {
-			animation-delay: 10s;
-		}
-
-		&:nth-child(2) {
-			animation-delay: 20s;
-		}
-
-	}
-
-}
-
-#root {
-	position: fixed;
-	top: 15vh;
-	left: 10vw;
-	z-index: 2;
-	color: #FFF;
-	display: flex;
-	flex-direction: column;
-
-	h1 {
-		font-size: 4rem;
-		font-weight: bold;
-		color: #FFF;
-		padding: 0;
-		margin: 0;
-		animation: headerIntro 3s ease;
-	}
-
-	h2 {
-		font-size: 1.5rem;
-		font-weight: normal;
-		color: rgba(255,255,255,0.7);
-		padding: 0;
-		margin: 0 0 25px 0;
-		animation: headerIntro 3s ease;
-	}
-
-	h3 {
-		font-size: 1.25rem;
-		font-weight: normal;
-		color: #FB8C00;
-		padding: 0;
-		margin: 0;
-		animation: shake 1s ease;
-
-		> .fa {
-			margin-right: 7px;
-		}
-
-	}
-
-	h4 {
-		font-size: 0.8rem;
-		font-weight: normal;
-		color: rgba(255,255,255,0.7);
-		padding: 0;
-		margin: 0 0 15px 0;
-		animation: fadeIn 3s ease;
-	}
-
-	form {
-		display: flex;
-		flex-direction: column;
-	}
-
-	input[type=text], input[type=password] {
-		width: 350px;
-		max-width: 80vw;
-		border: 1px solid rgba(255,255,255,0.3);
-		border-radius: 3px;
-		background-color: rgba(0,0,0,0.2);
-		padding: 0 15px;
-		height: 40px;
-		margin: 0 0 10px 0;
-		color: #FFF;
-		font-weight: bold;
-		font-size: 14px;
-		transition: all 0.4s ease;
-
-		&:focus {
-			outline: none;
-			border-color: mc('orange','600');
-		}
-
-	}
-
-	button {
-		background-color: mc('orange','600');
-		color: #FFF;
-		border: 1px solid lighten(mc('orange','600'), 10%);
-		border-radius: 3px;
-		height: 40px;
-		width: 125px;
-		padding: 0;
-		font-weight: bold;
-		margin: 15px 0 0 0;
-		transition: all 0.4s ease;
-		cursor: pointer;
-
-		span {
-			font-weight: bold;
-		}
-
-		&:focus {
-			outline: none;
-			border-color: #FFF;
-		}
-
-		&:hover {
-			background-color: darken(mc('orange','600'), 10%);
-		}
-
-	}
-
-	#social {
-		margin-top: 25px;
-
-		> span {
-			display: block;
-			font-weight: bold;
-			color: rgba(255,255,255,0.7);
-		}
-
-		button {
-			margin-right: 5px;
-			width: auto;
-			padding: 0 15px;
-
-			> i {
-				margin-right: 10px;
-				font-size: 16px;
-			}
-
-			&.ms {
-				background-color: mc('blue','600');
-				border-color: lighten(mc('blue','600'), 10%);
-
-				&:focus {
-					border-color: #FFF;
-				}
-
-				&:hover {
-					background-color: darken(mc('blue','600'), 10%);
-				}
-
-			}
-
-			&.google {
-				background-color: mc('light-blue','600');
-				border-color: lighten(mc('light-blue','600'), 10%);
-
-				&:focus {
-					border-color: #FFF;
-				}
-
-				&:hover {
-					background-color: darken(mc('light-blue','600'), 10%);
-				}
-
-			}
-
-			&.facebook {
-				background-color: mc('indigo','600');
-				border-color: lighten(mc('indigo','600'), 10%);
-
-				&:focus {
-					border-color: #FFF;
-				}
-
-				&:hover {
-					background-color: darken(mc('indigo','600'), 10%);
-				}
-
-			}
-
-      &.github {
-				background-color: mc('blue-grey','700');
-				border-color: lighten(mc('blue-grey','700'), 10%);
-
-				&:focus {
-					border-color: #FFF;
-				}
-
-				&:hover {
-					background-color: darken(mc('blue-grey','700'), 10%);
-				}
-			}
-
-      &.slack {
-				background-color: mc('purple','700');
-				border-color: lighten(mc('purple','700'), 10%);
-
-				&:focus {
-					border-color: #FFF;
-				}
-
-				&:hover {
-					background-color: darken(mc('purple','700'), 10%);
-				}
-			}
-
-		}
-
-	}
-
-}
-
-#copyright {
-	display: flex;
-	align-items: center;
-	justify-content: flex-start;
-	position: absolute;
-	left: 10vw;
-	bottom: 10vh;
-	z-index: 2;
-	color: rgba(255,255,255,0.5);
-	font-weight: bold;
-
-	.icon {
-		font-size: 1.2rem;
-		margin: 0 8px;
-	}
-
-	a {
-		opacity: 0.75;
-	}
-
-}
-
-@include keyframes(bg) {
-	0% {
-		@include prefix(transform, scale(1,1));
-		visibility: visible;
-		opacity: 0;
-	},
-	5% {
-		opacity: 0.5;
-	},
-	33% {
-		opacity: 0.5;
-	},
-	38% {
-		@include prefix(transform, scale(1.2, 1.2));
-		opacity: 0;
-	},
-	39% {
-		visibility: hidden;
-	}
-	100% {
-		visibility: hidden;
-		opacity: 0;
-	}
-}
-
-@include keyframes(headerIntro) {
-	0% {
-		opacity: 0;
-	}
-	100% {
-		opacity: 1;
-	}
+.login {
+  background-size: cover;
+  background-position: center center;
+  background-image: url('../images/bg.jpg');
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+
+  &-container {
+    display: flex;
+    width: 650px;
+    align-items: stretch;
+    box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
+  }
+
+  &-providers {
+    display: flex;
+    flex-direction: column;
+    width: 200px;
+    border: 1px solid #FFF;
+    background-color: mc('grey', '900');
+    z-index: 1;
+
+    button {
+      flex: 1 1;
+      padding: 0 15px;
+      border: none;
+      color: #FFF;
+      background-color: mc('grey', '800');
+      border-top: 1px solid mc('grey', '900');
+      font-family: $core-font-standard;
+      font-weight: 600;
+      text-align: left;
+      min-height: 40px;
+
+      &:first-child {
+        border-top: none;
+      }
+
+      &.is-active {
+        background-color: mc('grey', '100');
+        background-image: radial-gradient(circle at top left, rgba(mc('grey', '200'),1) 0%,rgba(255,255,255,1) 100%);
+        color: mc('grey', '700');
+      }
+
+      i {
+        margin-right: 10px;
+        font-size: 16px;
+      }
+
+      span {
+        font-weight: 600;
+      }
+    }
+  }
+
+  &-frame {
+    background-image: radial-gradient(circle at top left, rgba(255,255,255,1) 0%,rgba(240,240,240,.6) 100%);
+    border: 1px solid #FFF;
+    width: 450px;
+    padding: 1rem;
+    color: mc('grey', '700');
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+    text-align: center;
+
+    h1 {
+      font-size: 2rem;
+      font-weight: 600;
+      color: mc('grey', '700');
+      padding: 0;
+      margin: 0;
+    }
+
+    h2 {
+      font-size: 1.5rem;
+      font-weight: 300;
+      color: mc('grey', '700');
+      padding: 0;
+      margin: 0 0 25px 0;
+    }
+
+    h3 {
+      font-size: 1.25rem;
+      font-weight: normal;
+      color: #FB8C00;
+      padding: 0;
+      margin: 0;
+      animation: shake 1s ease;
+
+      > .fa {
+        margin-right: 7px;
+      }
+
+    }
+
+    h4 {
+      font-size: .8rem;
+      font-weight: normal;
+      color: rgba(255,255,255,0.7);
+      padding: 0;
+      margin: 0 0 15px 0;
+      animation: fadeIn 3s ease;
+    }
+
+    form {
+      display: flex;
+      flex-direction: column;
+    }
+
+    input[type=text], input[type=password] {
+      width: 100%;
+      border: 1px solid #FFF;
+      border-radius: 3px;
+      background-color: rgba(255,255,255,.7);
+      padding: 0 15px;
+      height: 40px;
+      margin: 0 0 10px 0;
+      color: mc('grey', '700');
+      font-weight: 600;
+      font-size: .8rem;
+      transition: all 0.4s ease;
+      text-align: center;
+
+      &:focus {
+        outline: none;
+        border-color: mc('grey','400');
+      }
+
+    }
+
+  }
+
+  &-copyright {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: absolute;
+    left: 0;
+    bottom: 10vh;
+    width: 100%;
+    z-index: 2;
+    color: #FFF;
+    font-weight: 400;
+    text-shadow: 1px 1px 0 #000;
+
+    .icon {
+      font-size: 1.2rem;
+      margin: 0 8px;
+    }
+
+    a {
+      font-weight: 600;
+      color: #FFF;
+    }
+
+  }
 }

+ 15 - 15
package.json

@@ -42,8 +42,8 @@
     "axios": "0.16.2",
     "bcryptjs-then": "1.0.1",
     "bluebird": "3.5.0",
-    "body-parser": "1.17.2",
-    "bull": "3.0.0",
+    "body-parser": "1.18.0",
+    "bull": "3.1.0",
     "bunyan": "1.8.12",
     "cheerio": "1.0.0-rc.2",
     "child-process-promise": "2.2.1",
@@ -63,7 +63,7 @@
     "follow-redirects": "1.2.4",
     "fs-extra": "4.0.1",
     "git-wrapper2-promise": "0.2.9",
-    "graphql": "0.11.2",
+    "graphql": "0.11.3",
     "graphql-tools": "1.2.2",
     "highlight.js": "9.12.0",
     "i18next": "9.0.0",
@@ -73,7 +73,7 @@
     "ioredis": "3.1.4",
     "jimp": "0.2.28",
     "js-yaml": "3.9.1",
-    "jsonwebtoken": "7.4.3",
+    "jsonwebtoken": "8.0.0",
     "klaw": "2.1.0",
     "levelup": "1.3.9",
     "lodash": "4.17.4",
@@ -88,7 +88,7 @@
     "markdown-it-mathjax": "2.0.0",
     "markdown-it-task-lists": "2.0.1",
     "mathjax-node": "1.2.0",
-    "memdown": "1.2.4",
+    "memdown": "1.2.7",
     "mime-types": "2.1.17",
     "moment": "2.18.1",
     "moment-timezone": "0.5.13",
@@ -108,24 +108,24 @@
     "passport.socketio": "3.7.0",
     "pg": "7.3.0",
     "pg-hstore": "2.3.2",
-    "pg-promise": "6.5.1",
+    "pg-promise": "6.5.2",
     "pm2": "2.6.1",
-    "pug": "2.0.0-rc.3",
+    "pug": "2.0.0-rc.4",
     "read-chunk": "2.1.0",
     "remove-markdown": "0.2.2",
     "request": "2.81.0",
     "search-index-adder": "0.3.9",
     "search-index-searcher": "0.2.10",
     "semver": "5.4.1",
-    "sequelize": "4.8.0",
+    "sequelize": "4.8.2",
     "serve-favicon": "2.4.3",
     "simplemde": "1.11.2",
     "socket.io": "2.0.3",
-    "stopword": "0.1.6",
+    "stopword": "0.1.7",
     "stream-to-promise": "2.2.0",
     "tar": "4.0.1",
     "through2": "2.0.3",
-    "validator": "8.1.0",
+    "validator": "8.2.0",
     "validator-as-promised": "1.0.2",
     "winston": "2.3.1",
     "yargs": "8.0.2"
@@ -134,7 +134,7 @@
     "@glimpse/glimpse": "0.22.15",
     "@panter/vue-i18next": "0.5.1",
     "babel-cli": "6.26.0",
-    "babel-jest": "21.0.0",
+    "babel-jest": "21.0.2",
     "babel-plugin-transform-object-assign": "6.22.0",
     "babel-preset-es2015": "6.24.1",
     "brace": "0.10.0",
@@ -146,18 +146,18 @@
     "eslint-plugin-node": "5.1.1",
     "eslint-plugin-promise": "3.5.0",
     "eslint-plugin-standard": "3.0.1",
-    "fuse-box": "2.2.3",
+    "fuse-box": "^2.2.31",
     "i18next-xhr-backend": "1.4.2",
-    "jest": "21.0.0",
+    "jest": "21.0.2",
     "jquery": "3.2.1",
-    "jquery-contextmenu": "2.5.0",
+    "jquery-contextmenu": "2.6.2",
     "jquery-simple-upload": "1.0.0",
     "jquery-smooth-scroll": "2.2.0",
     "jquery-sticky": "1.0.4",
     "lodash-cli": "4.17.4",
     "lodash-es": "4.17.4",
     "node-sass": "4.5.3",
-    "nodemon": "1.11.0",
+    "nodemon": "1.12.0",
     "pug-lint": "2.5.0",
     "twemoji-awesome": "1.0.6",
     "typescript": "2.5.2",

+ 2 - 2
server/master.js

@@ -136,10 +136,10 @@ module.exports = Promise.join(
   // ----------------------------------------
 
   app.locals._ = require('lodash')
-  app.locals.t = wiki.lang.t.bind(wiki.config.site.lang)
+  app.locals.t = wiki.lang.t.bind(wiki.lang)
   app.locals.moment = require('moment')
   app.locals.moment.locale(wiki.config.site.lang)
-  app.locals.appconfig = wiki.config
+  app.locals.config = wiki.config
   app.use(mw.flash)
 
   // ----------------------------------------

+ 3 - 3
server/modules/config.js

@@ -47,11 +47,11 @@ module.exports = {
       appconfig.port = process.env.PORT || 80
     }
 
-  // Convert booleans
+    // Convert booleans
 
-  appconfig.public = (appconfig.public === true || _.toLower(appconfig.public) === 'true')
+    appconfig.public = (appconfig.public === true || _.toLower(appconfig.public) === 'true')
 
-  // List authentication strategies
+    // List authentication strategies
     wiki.config = appconfig
     wiki.data = appdata
   },

+ 52 - 73
server/views/auth/login.pug

@@ -1,75 +1,54 @@
-doctype html
-html(data-logic='login')
-  head
-    meta(http-equiv='X-UA-Compatible', content='IE=edge')
-    meta(charset='UTF-8')
-    meta(name='viewport', content='width=device-width, initial-scale=1')
-    meta(name='theme-color', content='#009688')
-    meta(name='msapplication-TileColor', content='#009688')
-    meta(name='msapplication-TileImage', content='/favicons/ms-icon-144x144.png')
-    title= appconfig.title
-
-    // Favicon
-    each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
-      link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href='/favicons/apple-icon-' + favsize + 'x' + favsize + '.png')
-    link(rel='icon', type='image/png', sizes='192x192', href='/favicons/android-icon-192x192.png')
-    each favsize in [32, 96, 16]
-      link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
-    link(rel='manifest', href='/manifest.json')
-
-    // JS / CSS
-    script(type='text/javascript', src=appconfig.host + '/js/vendor.js')
-    script(type='text/javascript', src=appconfig.host + '/js/app.js')
+extends ../master.pug
 
+block body
   body
-    #bg
-      each bg in _.sampleSize([1, 2, 3],3)
-        div(style='background-image:url(/images/bg_' + bg + '.jpg);')
-    #root
-      h1= appconfig.title
-      h2= t('auth:loginrequired')
-      if appflash.length > 0
-        h3
-          i.icon-warning-outline
-          = appflash[0].title
-        h4= appflash[0].message
-      if appconfig.auth.local.enabled
-        form(method='post', action='/login')
-          input#login-user(type='text', name='email', placeholder=t('auth:fields.emailuser'))
-          input#login-pass(type='password', name='password', placeholder=t('auth:fields.password'))
-          button(type='submit')= t('auth:actions.login')
-      if appconfig.authStrategies.socialEnabled
-        #social
-          if appconfig.auth.local.enabled
-            span= t('auth:loginusingalt')
-          else
-            span= t('auth:loginusing')
-          if appconfig.auth.microsoft && appconfig.auth.microsoft.enabled
-            button.ms(onclick='window.location.assign("/login/ms")')
-              i.icon-windows2
-              span= t('auth:providers.windowslive')
-          if appconfig.auth.azure && appconfig.auth.azure.enabled
-            button.ms(onclick='window.location.assign("/login/azure")')
-              i.icon-windows2
-              span= t('auth:providers.azure')
-          if appconfig.auth.google && appconfig.auth.google.enabled
-            button.google(onclick='window.location.assign("/login/google")')
-              i.icon-google
-              span= t('auth:providers.google')
-          if appconfig.auth.facebook && appconfig.auth.facebook.enabled
-            button.facebook(onclick='window.location.assign("/login/facebook")')
-              i.icon-facebook
-              span= t('auth:providers.facebook')
-          if appconfig.auth.github && appconfig.auth.github.enabled
-            button.github(onclick='window.location.assign("/login/github")')
-              i.icon-github
-              span= t('auth:providers.github')
-          if appconfig.auth.slack && appconfig.auth.slack.enabled
-            button.slack(onclick='window.location.assign("/login/slack")')
-              i.icon-slack
-              span= t('auth:providers.slack')
-    #copyright
-      = t('footer.poweredby') + ' '
-      a.icon(href='https://github.com/Requarks/wiki')
-        i.icon-github
-      a(href='https://wiki.requarks.io/') Wiki.js
+    .login#root
+      .login-container
+        if config.authStrategies.socialEnabled
+          .login-providers
+            button.is-active(onclick='window.location.assign("/login/ms")')
+              i.nc-icon-outline.ui-1_database
+              span= t('auth:providers.local')
+            if config.auth.microsoft && config.auth.microsoft.enabled
+              button(onclick='window.location.assign("/login/ms")')
+                i.icon-windows2
+                span= t('auth:providers.windowslive')
+            if config.auth.azure && config.auth.azure.enabled
+              button(onclick='window.location.assign("/login/azure")')
+                i.icon-windows2
+                span= t('auth:providers.azure')
+            if config.auth.google && config.auth.google.enabled
+              button(onclick='window.location.assign("/login/google")')
+                i.icon-google
+                span= t('auth:providers.google')
+            if config.auth.facebook && config.auth.facebook.enabled
+              button(onclick='window.location.assign("/login/facebook")')
+                i.icon-facebook
+                span= t('auth:providers.facebook')
+            if config.auth.github && config.auth.github.enabled
+              button(onclick='window.location.assign("/login/github")')
+                i.icon-github
+                span= t('auth:providers.github')
+            if config.auth.slack && config.auth.slack.enabled
+              button(onclick='window.location.assign("/login/slack")')
+                i.icon-slack
+                span= t('auth:providers.slack')
+        .login-frame
+          h1= config.site.title
+          h2= t('auth:loginrequired')
+          if appflash.length > 0
+            h3
+              i.icon-warning-outline
+              = appflash[0].title
+            h4= appflash[0].message
+          if config.auth.local.enabled
+            form(method='post', action='/login')
+              input#login-user(type='text', name='email', placeholder=t('auth:fields.emailuser'))
+              input#login-pass(type='password', name='password', placeholder=t('auth:fields.password'))
+              button.button.is-light-green.is-fullwidth(type='submit')
+                span= t('auth:actions.login')
+      .login-copyright
+        = t('footer.poweredby') + ' '
+        a.icon(href='https://github.com/Requarks/wiki')
+          i.icon-github
+        a(href='https://wiki.requarks.io/') Wiki.js

+ 4 - 24
server/views/error.pug

@@ -1,32 +1,12 @@
-doctype html
-html(data-logic='error')
-  head
-    meta(http-equiv='X-UA-Compatible', content='IE=edge')
-    meta(charset='UTF-8')
-    meta(name='viewport', content='width=device-width, initial-scale=1')
-    meta(name='theme-color', content='#009688')
-    meta(name='msapplication-TileColor', content='#009688')
-    meta(name='msapplication-TileImage', content=appconfig.host + '/favicons/ms-icon-144x144.png')
-    title= appconfig.title
-
-    // Favicon
-    each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
-      link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href=appconfig.host + '/favicons/apple-icon-' + favsize + 'x' + favsize + '.png')
-    link(rel='icon', type='image/png', sizes='192x192', href=appconfig.host + '/favicons/android-icon-192x192.png')
-    each favsize in [32, 96, 16]
-      link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href=appconfig.host + '/favicons/favicon-' + favsize + 'x' + favsize + '.png')
-    link(rel='manifest', href=appconfig.host + '/manifest.json')
-
-    // JS / CSS
-    script(type='text/javascript', src=appconfig.host + '/js/vendor.js')
-    script(type='text/javascript', src=appconfig.host + '/js/app.js')
+extends ./master.pug
 
+block body
   body(class='is-error')
     .container
-      a(href='/'): img(src=appconfig.host + '/images/logo.png')
+      a(href='/'): img(src=config.site.path + '/images/logo.png')
       h1= message
       h2= t('errors:generic')
-      a.button.is-amber.is-inverted.is-featured(href=appconfig.host + '/')= t('errors:actions.gohome')
+      a.button.is-amber.is-inverted.is-featured(href=config.site.path+ '/')= t('errors:actions.gohome')
 
       if error.stack
         h3= t('errors:debugmsg')

+ 2 - 29
server/views/layout.pug

@@ -1,33 +1,6 @@
-doctype html
-html
-  head
-    meta(http-equiv='X-UA-Compatible', content='IE=edge')
-    meta(charset='UTF-8')
-    meta(name='viewport', content='width=device-width, initial-scale=1')
-    meta(name='theme-color', content='#009688')
-    meta(name='msapplication-TileColor', content='#009688')
-    meta(name='msapplication-TileImage', content=appconfig.host + '/favicons/ms-icon-144x144.png')
-    title= appconfig.title
-
-    //- Favicon
-    each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
-      link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href=appconfig.host + '/favicons/apple-icon-' + favsize + 'x' + favsize + '.png')
-    link(rel='icon', type='image/png', sizes='192x192', href=appconfig.host + '/favicons/android-icon-192x192.png')
-    each favsize in [32, 96, 16]
-      link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href=appconfig.host + '/favicons/favicon-' + favsize + 'x' + favsize + '.png')
-    link(rel='manifest', href=appconfig.host + '/manifest.json')
-
-    //- Site Lang
-    script.
-      var siteLang = '!{appconfig.lang}';
-      var siteRoot = '!{appconfig.host}';
-
-    //- JS / CSS
-    script(type='text/javascript', src=appconfig.host + '/js/vendor.js')
-    script(type='text/javascript', src=appconfig.host + '/js/app.js')
-
-    block head
+extends ./master.pug
 
+block body
   body
     #root.has-stickynav(class=['is-primary-' + appconfig.theme.primary, 'is-alternate-' + appconfig.theme.alt])
       include ./common/header.pug

+ 30 - 0
server/views/master.pug

@@ -0,0 +1,30 @@
+doctype html
+html
+  head
+    meta(http-equiv='X-UA-Compatible', content='IE=edge')
+    meta(charset='UTF-8')
+    meta(name='viewport', content='width=device-width, initial-scale=1')
+    meta(name='theme-color', content='#009688')
+    meta(name='msapplication-TileColor', content='#009688')
+    meta(name='msapplication-TileImage', content=config.site.path + '/favicons/ms-icon-144x144.png')
+    title= config.title
+
+    //- Favicon
+    each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
+      link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href=config.site.path + '/favicons/apple-icon-' + favsize + 'x' + favsize + '.png')
+    link(rel='icon', type='image/png', sizes='192x192', href=config.site.path + '/favicons/android-icon-192x192.png')
+    each favsize in [32, 96, 16]
+      link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href=config.site.path + '/favicons/favicon-' + favsize + 'x' + favsize + '.png')
+    link(rel='manifest', href=config.site.path + '/manifest.json')
+
+    //- Site Lang
+    script.
+      var siteConfig = !{JSON.stringify(config.site)}
+
+    //- JS / CSS
+    script(type='text/javascript', src=config.site.path + '/js/vendor.js')
+    script(type='text/javascript', src=config.site.path + '/js/app.js')
+
+    block head
+
+  block body

+ 2 - 1
tools/fuse.js

@@ -126,7 +126,8 @@ globalTasks.then(() => {
 
   switch (mode) {
     case 'dev':
-      bundleApp.watch()
+      bundleApp.hmr().watch()
+      fuse.dev({ httpServer: false })
       break
     case 'dev-configure':
       bundleSetup.watch()

文件差異過大導致無法顯示
+ 351 - 234
yarn.lock


部分文件因文件數量過多而無法顯示