feat: login component, icon svg symbols, project structure

This commit is contained in:
NGPixel
2017-12-30 02:00:49 -05:00
parent 2d5a3203db
commit 8b30d31457
37 changed files with 863 additions and 23300 deletions

View File

@@ -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)

View 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')
}

View File

@@ -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()
}
}

View 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>

View 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
}
}())
}

View File

@@ -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
}
})

View File

@@ -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)
}
}

View 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)
}
}