feat: login component, icon svg symbols, project structure
This commit is contained in:
		@@ -12,7 +12,7 @@ import { ApolloClient } from 'apollo-client'
 | 
			
		||||
import { HttpLink } from 'apollo-link-http'
 | 
			
		||||
import { InMemoryCache } from 'apollo-cache-inmemory'
 | 
			
		||||
import store from './store'
 | 
			
		||||
import icons from '../svg/nc-icons.svg'
 | 
			
		||||
import icons from '../svg/icons.svg'
 | 
			
		||||
 | 
			
		||||
// ====================================
 | 
			
		||||
// Load Modules
 | 
			
		||||
@@ -47,6 +47,7 @@ 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 navigatorComponent from './components/navigator.vue'
 | 
			
		||||
import pageLoaderComponent from './components/page-loader.vue'
 | 
			
		||||
import searchComponent from './components/search.vue'
 | 
			
		||||
import toggleComponent from './components/toggle.vue'
 | 
			
		||||
@@ -127,6 +128,7 @@ Vue.component('modalDiscardPage', modalDiscardPageComponent)
 | 
			
		||||
Vue.component('modalMovePage', modalMovePageComponent)
 | 
			
		||||
Vue.component('modalProfile2fa', modalProfile2faComponent)
 | 
			
		||||
Vue.component('modalUpgradeSystem', modalUpgradeSystemComponent)
 | 
			
		||||
Vue.component('navigator', navigatorComponent)
 | 
			
		||||
Vue.component('pageLoader', pageLoaderComponent)
 | 
			
		||||
Vue.component('search', searchComponent)
 | 
			
		||||
Vue.component('setup', setupComponent)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								client/js/compatibility.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								client/js/compatibility.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
// =======================================
 | 
			
		||||
// Intl polyfill
 | 
			
		||||
// =======================================
 | 
			
		||||
// Requirement: Safari 9 and below
 | 
			
		||||
 | 
			
		||||
if (!global.Intl) {
 | 
			
		||||
  require('intl')
 | 
			
		||||
  require('intl/locale-data/jsonp/en')
 | 
			
		||||
  require('intl/locale-data/jsonp/fr')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// =======================================
 | 
			
		||||
// Promise polyfill
 | 
			
		||||
// =======================================
 | 
			
		||||
// Requirement: IE 11 and below
 | 
			
		||||
 | 
			
		||||
if (!window.Promise) {
 | 
			
		||||
  window.Promise = require('bluebird')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// =======================================
 | 
			
		||||
// Array.from polyfill
 | 
			
		||||
// =======================================
 | 
			
		||||
// Requirement: IE 11 and below
 | 
			
		||||
 | 
			
		||||
if (!Array.from) {
 | 
			
		||||
  require('./polyfills/array-from')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// =======================================
 | 
			
		||||
// Fetch polyfill
 | 
			
		||||
// =======================================
 | 
			
		||||
// Requirement: Safari 9 and below, IE 11 and below
 | 
			
		||||
 | 
			
		||||
if (!window.fetch) {
 | 
			
		||||
  require('whatwg-fetch')
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +1,18 @@
 | 
			
		||||
<template lang="pug">
 | 
			
		||||
  .login(:class='{ "is-error": error }')
 | 
			
		||||
    .login-container(:class='{ "is-expanded": strategies.length > 1 }')
 | 
			
		||||
      .login-error(v-if='error')
 | 
			
		||||
        strong
 | 
			
		||||
          i.icon-warning-outline
 | 
			
		||||
          | {{ error.title }}
 | 
			
		||||
        span {{ error.message }}
 | 
			
		||||
      .login-providers(v-show='strategies.length > 1')
 | 
			
		||||
        button(v-for='strategy in strategies', :class='{ "is-active": strategy.key === selectedStrategy }', @click='selectStrategy(strategy.key, strategy.useForm)', :title='strategy.title')
 | 
			
		||||
          em(v-html='strategy.icon')
 | 
			
		||||
          span {{ strategy.title }}
 | 
			
		||||
        .login-providers-fill
 | 
			
		||||
      .login-frame
 | 
			
		||||
        h1 {{ siteTitle }}
 | 
			
		||||
        h2 {{ $t('auth:loginrequired') }}
 | 
			
		||||
        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-blue.is-fullwidth(type='submit')
 | 
			
		||||
            span {{ $t('auth:actions.login') }}
 | 
			
		||||
        input(type='text', name='email', :placeholder='$t("auth:fields.emailuser")')
 | 
			
		||||
        input(type='password', name='password', :placeholder='$t("auth:fields.password")')
 | 
			
		||||
        button.button.is-orange.is-fullwidth(@click='login')
 | 
			
		||||
          span {{ $t('auth:actions.login') }}
 | 
			
		||||
    .login-copyright
 | 
			
		||||
      span {{ $t('footer.poweredby') }}
 | 
			
		||||
      a(href='https://wiki.js.org', rel='external', title='Wiki.js') Wiki.js
 | 
			
		||||
@@ -62,9 +57,17 @@ export default {
 | 
			
		||||
      }).catch(err => {
 | 
			
		||||
        console.error(err)
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    login() {
 | 
			
		||||
      this.$store.dispatch('alert', {
 | 
			
		||||
        style: 'error',
 | 
			
		||||
        icon: 'gg-warning',
 | 
			
		||||
        msg: 'Email or password is invalid'
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.$store.commit('navigator/subtitleStatic', 'Login')
 | 
			
		||||
    this.refreshStrategies()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								client/js/components/navigator.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								client/js/components/navigator.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
<template lang="pug">
 | 
			
		||||
  .navigator
 | 
			
		||||
    .navigator-bar
 | 
			
		||||
      .navigator-fab
 | 
			
		||||
        .navigator-fab-button(@click='toggleMainMenu')
 | 
			
		||||
          svg.icons.is-24(role='img')
 | 
			
		||||
            title Navigation
 | 
			
		||||
            use(xlink:href='#gg-apps-grid')
 | 
			
		||||
      .navigator-title
 | 
			
		||||
        h1 {{ siteTitle }}
 | 
			
		||||
      .navigator-subtitle(:class='subtitleClass')
 | 
			
		||||
 | 
			
		||||
        svg.icons.is-24(role='img', v-if='subtitleIcon')
 | 
			
		||||
          title {{subtitleText}}
 | 
			
		||||
          use(:xlink:href='subtitleIconClass')
 | 
			
		||||
        h2 {{subtitleText}}
 | 
			
		||||
      .navigator-action
 | 
			
		||||
        .navigator-action-item
 | 
			
		||||
          svg.icons.is-32(role='img')
 | 
			
		||||
            title User
 | 
			
		||||
            use(xlink:href='#nc-user-circle')
 | 
			
		||||
    .navigator-row
 | 
			
		||||
      .navigator-nav
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
/* global CONSTANTS, graphQL, siteConfig */
 | 
			
		||||
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'navigator',
 | 
			
		||||
  data() {
 | 
			
		||||
    return { }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState('navigator', [
 | 
			
		||||
      'subtitleShown',
 | 
			
		||||
      'subtitleStyle',
 | 
			
		||||
      'subtitleText',
 | 
			
		||||
      'subtitleIcon'
 | 
			
		||||
    ]),
 | 
			
		||||
    siteTitle() {
 | 
			
		||||
      return siteConfig.title
 | 
			
		||||
    },
 | 
			
		||||
    subtitleClass() {
 | 
			
		||||
      return {
 | 
			
		||||
        'is-active': this.subtitleShown,
 | 
			
		||||
        'is-error': this.subtitleStyle === 'error',
 | 
			
		||||
        'is-warning': this.subtitleStyle === 'warning',
 | 
			
		||||
        'is-success': this.subtitleStyle === 'success',
 | 
			
		||||
        'is-info': this.subtitleStyle === 'info'
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    subtitleIconClass() { return '#' + this.subtitleIcon }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    toggleMainMenu() {
 | 
			
		||||
      this.$store.dispatch('navigator/alert', {
 | 
			
		||||
        style: 'success',
 | 
			
		||||
        icon: 'nc-check-simple',
 | 
			
		||||
        msg: 'Changes were saved successfully!'
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										78
									
								
								client/js/polyfills/array-from.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								client/js/polyfills/array-from.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
// Production steps of ECMA-262, Edition 6, 22.1.2.1
 | 
			
		||||
if (!Array.from) {
 | 
			
		||||
  Array.from = (function () {
 | 
			
		||||
    var toStr = Object.prototype.toString
 | 
			
		||||
    var isCallable = function (fn) {
 | 
			
		||||
      return typeof fn === 'function' || toStr.call(fn) === '[object Function]'
 | 
			
		||||
    }
 | 
			
		||||
    var toInteger = function (value) {
 | 
			
		||||
      var number = Number(value)
 | 
			
		||||
      if (isNaN(number)) { return 0 }
 | 
			
		||||
      if (number === 0 || !isFinite(number)) { return number }
 | 
			
		||||
      return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number))
 | 
			
		||||
    }
 | 
			
		||||
    var maxSafeInteger = Math.pow(2, 53) - 1
 | 
			
		||||
    var toLength = function (value) {
 | 
			
		||||
      var len = toInteger(value)
 | 
			
		||||
      return Math.min(Math.max(len, 0), maxSafeInteger)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The length property of the from method is 1.
 | 
			
		||||
    return function from (arrayLike/*, mapFn, thisArg */) {
 | 
			
		||||
      // 1. Let C be the this value.
 | 
			
		||||
      var C = this
 | 
			
		||||
 | 
			
		||||
      // 2. Let items be ToObject(arrayLike).
 | 
			
		||||
      var items = Object(arrayLike)
 | 
			
		||||
 | 
			
		||||
      // 3. ReturnIfAbrupt(items).
 | 
			
		||||
      if (arrayLike == null) {
 | 
			
		||||
        throw new TypeError('Array.from requires an array-like object - not null or undefined')
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // 4. If mapfn is undefined, then let mapping be false.
 | 
			
		||||
      var mapFn = arguments.length > 1 ? arguments[1] : void undefined
 | 
			
		||||
      var T
 | 
			
		||||
      if (typeof mapFn !== 'undefined') {
 | 
			
		||||
        // 5. else
 | 
			
		||||
        // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
 | 
			
		||||
        if (!isCallable(mapFn)) {
 | 
			
		||||
          throw new TypeError('Array.from: when provided, the second argument must be a function')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
 | 
			
		||||
        if (arguments.length > 2) {
 | 
			
		||||
          T = arguments[2]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // 10. Let lenValue be Get(items, "length").
 | 
			
		||||
      // 11. Let len be ToLength(lenValue).
 | 
			
		||||
      var len = toLength(items.length)
 | 
			
		||||
 | 
			
		||||
      // 13. If IsConstructor(C) is true, then
 | 
			
		||||
      // 13. a. Let A be the result of calling the [[Construct]] internal method
 | 
			
		||||
      // of C with an argument list containing the single item len.
 | 
			
		||||
      // 14. a. Else, Let A be ArrayCreate(len).
 | 
			
		||||
      var A = isCallable(C) ? Object(new C(len)) : new Array(len)
 | 
			
		||||
 | 
			
		||||
      // 16. Let k be 0.
 | 
			
		||||
      var k = 0
 | 
			
		||||
      // 17. Repeat, while k < len… (also steps a - h)
 | 
			
		||||
      var kValue
 | 
			
		||||
      while (k < len) {
 | 
			
		||||
        kValue = items[k]
 | 
			
		||||
        if (mapFn) {
 | 
			
		||||
          A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k)
 | 
			
		||||
        } else {
 | 
			
		||||
          A[k] = kValue
 | 
			
		||||
        }
 | 
			
		||||
        k += 1
 | 
			
		||||
      }
 | 
			
		||||
      // 18. Let putStatus be Put(A, "length", len, true).
 | 
			
		||||
      A.length = len
 | 
			
		||||
      // 20. Return A.
 | 
			
		||||
      return A
 | 
			
		||||
    }
 | 
			
		||||
  }())
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import Vuex from 'vuex'
 | 
			
		||||
 | 
			
		||||
import alert from './modules/alert'
 | 
			
		||||
import anchor from './modules/anchor'
 | 
			
		||||
import editor from './modules/editor'
 | 
			
		||||
import editorCodeblock from './modules/editor-codeblock'
 | 
			
		||||
@@ -15,6 +14,7 @@ import modalDiscardPage from './modules/modal-discard-page'
 | 
			
		||||
import modalMovePage from './modules/modal-move-page'
 | 
			
		||||
import modalProfile2fa from './modules/modal-profile-2fa'
 | 
			
		||||
import modalUpgradeSystem from './modules/modal-upgrade-system'
 | 
			
		||||
import navigator from './modules/navigator'
 | 
			
		||||
import pageLoader from './modules/page-loader'
 | 
			
		||||
 | 
			
		||||
Vue.use(Vuex)
 | 
			
		||||
@@ -27,12 +27,12 @@ export default new Vuex.Store({
 | 
			
		||||
    loadingChange: (state, loadingState) => { state.loading = loadingState }
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    alert({ dispatch }, opts) { dispatch('navigator/alert', opts) },
 | 
			
		||||
    startLoading({ commit }) { commit('loadingChange', true) },
 | 
			
		||||
    stopLoading({ commit }) { commit('loadingChange', false) }
 | 
			
		||||
  },
 | 
			
		||||
  getters: {},
 | 
			
		||||
  modules: {
 | 
			
		||||
    alert,
 | 
			
		||||
    anchor,
 | 
			
		||||
    editor,
 | 
			
		||||
    editorCodeblock,
 | 
			
		||||
@@ -46,6 +46,7 @@ export default new Vuex.Store({
 | 
			
		||||
    modalMovePage,
 | 
			
		||||
    modalProfile2fa,
 | 
			
		||||
    modalUpgradeSystem,
 | 
			
		||||
    navigator,
 | 
			
		||||
    pageLoader
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
'use strict'
 | 
			
		||||
 | 
			
		||||
import debounce from 'lodash/debounce'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  state: {
 | 
			
		||||
    shown: false,
 | 
			
		||||
    style: 'green',
 | 
			
		||||
    icon: 'check',
 | 
			
		||||
    msg: ''
 | 
			
		||||
  },
 | 
			
		||||
  getters: {},
 | 
			
		||||
  mutations: {
 | 
			
		||||
    alertChange: (state, opts) => {
 | 
			
		||||
      state.shown = (opts.shown === true)
 | 
			
		||||
      state.style = opts.style || 'green'
 | 
			
		||||
      state.icon = opts.icon || 'check'
 | 
			
		||||
      state.msg = opts.msg || ''
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    alert({ commit, dispatch }, opts) {
 | 
			
		||||
      opts.shown = true
 | 
			
		||||
      commit('alertChange', opts)
 | 
			
		||||
      dispatch('alertDismiss')
 | 
			
		||||
    },
 | 
			
		||||
    alertDismiss: debounce(({ commit }) => {
 | 
			
		||||
      let opts = { shown: false }
 | 
			
		||||
      commit('alertChange', opts)
 | 
			
		||||
    }, 3000)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								client/js/store/modules/navigator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								client/js/store/modules/navigator.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
import debounce from 'lodash/debounce'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state: {
 | 
			
		||||
    subtitleShown: false,
 | 
			
		||||
    subtitleStyle: '',
 | 
			
		||||
    subtitleIcon: false,
 | 
			
		||||
    subtitleText: '',
 | 
			
		||||
    subtitleStatic: 'Welcome'
 | 
			
		||||
  },
 | 
			
		||||
  getters: {},
 | 
			
		||||
  mutations: {
 | 
			
		||||
    subtitleChange (state, opts) {
 | 
			
		||||
      state.subtitleShown = (opts.shown === true)
 | 
			
		||||
      state.subtitleStyle = opts.style || ''
 | 
			
		||||
      state.subtitleIcon = opts.icon || false
 | 
			
		||||
      state.subtitleText = opts.msg || ''
 | 
			
		||||
    },
 | 
			
		||||
    subtitleStatic (state, text) {
 | 
			
		||||
      state.subtitleText = text
 | 
			
		||||
      state.subtitleStatic = text
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    alert ({ commit, dispatch }, opts) {
 | 
			
		||||
      opts.shown = true
 | 
			
		||||
      commit('subtitleChange', opts)
 | 
			
		||||
      dispatch('alertDismiss')
 | 
			
		||||
    },
 | 
			
		||||
    alertDismiss: debounce(({ commit, state }) => {
 | 
			
		||||
      let opts = {
 | 
			
		||||
        shown: false,
 | 
			
		||||
        style: state.subtitleStyle,
 | 
			
		||||
        msg: state.subtitleStatic
 | 
			
		||||
      }
 | 
			
		||||
      commit('subtitleChange', opts)
 | 
			
		||||
    }, 5000)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user