feat: GraphQL translations + login form
This commit is contained in:
@@ -6,10 +6,14 @@
|
||||
import Vue from 'vue'
|
||||
import VueResource from 'vue-resource'
|
||||
import VueClipboards from 'vue-clipboards'
|
||||
import { ApolloClient, createBatchingNetworkInterface } from 'apollo-client'
|
||||
import store from './store'
|
||||
import i18next from 'i18next'
|
||||
import i18nextXHR from 'i18next-xhr-backend'
|
||||
import VueI18Next from '@panter/vue-i18next'
|
||||
|
||||
// ====================================
|
||||
// Load Modules
|
||||
// ====================================
|
||||
|
||||
import localization from './modules/localization'
|
||||
|
||||
// ====================================
|
||||
// Load Helpers
|
||||
@@ -29,6 +33,7 @@ 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 loginComponent from './components/login.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'
|
||||
@@ -49,13 +54,24 @@ import contentViewComponent from './pages/content-view.component.js'
|
||||
import editorComponent from './components/editor.component.js'
|
||||
import sourceViewComponent from './pages/source-view.component.js'
|
||||
|
||||
// ====================================
|
||||
// Initialize Apollo Client (GraphQL)
|
||||
// ====================================
|
||||
|
||||
window.apollo = new ApolloClient({
|
||||
networkInterface: createBatchingNetworkInterface({
|
||||
uri: window.location.protocol + '//' + window.location.host + siteConfig.path + '/graphql'
|
||||
}),
|
||||
connectToDevTools: true
|
||||
})
|
||||
|
||||
// ====================================
|
||||
// Initialize Vue Modules
|
||||
// ====================================
|
||||
|
||||
Vue.use(VueResource)
|
||||
Vue.use(VueClipboards)
|
||||
Vue.use(VueI18Next)
|
||||
Vue.use(localization.VueI18Next)
|
||||
Vue.use(helpers)
|
||||
|
||||
// ====================================
|
||||
@@ -76,6 +92,7 @@ Vue.component('editorFile', editorFileComponent)
|
||||
Vue.component('editorVideo', editorVideoComponent)
|
||||
Vue.component('history', historyComponent)
|
||||
Vue.component('loadingSpinner', loadingSpinnerComponent)
|
||||
Vue.component('login', loginComponent)
|
||||
Vue.component('modalCreatePage', modalCreatePageComponent)
|
||||
Vue.component('modalCreateUser', modalCreateUserComponent)
|
||||
Vue.component('modalDeleteUser', modalDeleteUserComponent)
|
||||
@@ -89,20 +106,6 @@ 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
|
||||
})
|
||||
|
||||
document.addEventListener('DOMContentLoaded', ev => {
|
||||
// ====================================
|
||||
// Notifications
|
||||
@@ -116,13 +119,13 @@ document.addEventListener('DOMContentLoaded', ev => {
|
||||
// Bootstrap Vue
|
||||
// ====================================
|
||||
|
||||
const i18n = new VueI18Next(i18next)
|
||||
const i18n = localization.init()
|
||||
window.wiki = new Vue({
|
||||
mixins: [helpers],
|
||||
components: {},
|
||||
store,
|
||||
i18n,
|
||||
el: '#root',
|
||||
el: '#app',
|
||||
methods: {
|
||||
changeTheme(opts) {
|
||||
this.$el.className = `has-stickynav is-primary-${opts.primary} is-alternate-${opts.alt}`
|
||||
|
50
client/js/components/login.vue
Normal file
50
client/js/components/login.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<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.is-active(:title='$t("auth:providers.local")')
|
||||
i.nc-icon-outline.ui-1_database
|
||||
span {{ $t('auth:providers.local') }}
|
||||
button(v-for='strategy in strategies', @onclick='selectProvider(strategy.key, strategy.useForm)', :title='strategy.title')
|
||||
//-!= strategy.icon
|
||||
span {{ strategy.title }}
|
||||
.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') }}
|
||||
.login-copyright
|
||||
span {{ $t('footer.poweredby') }}
|
||||
a(href='https://wiki.js.org', rel='external', title='Wiki.js') Wiki.js
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'login',
|
||||
data() {
|
||||
return {
|
||||
error: false,
|
||||
strategies: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
siteTitle() {
|
||||
return siteConfig.title
|
||||
}
|
||||
}
|
||||
methods: {
|
||||
selectProvider(key, useForm) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
57
client/js/modules/localization.js
Normal file
57
client/js/modules/localization.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import i18next from 'i18next'
|
||||
import i18nextXHR from 'i18next-xhr-backend'
|
||||
import i18nextCache from 'i18next-localstorage-cache'
|
||||
import gql from 'graphql-tag'
|
||||
import VueI18Next from '@panter/vue-i18next'
|
||||
import loSet from 'lodash/set'
|
||||
|
||||
/* global siteConfig */
|
||||
|
||||
module.exports = {
|
||||
VueI18Next,
|
||||
init() {
|
||||
i18next
|
||||
.use(i18nextXHR)
|
||||
.use(i18nextCache)
|
||||
.init({
|
||||
backend: {
|
||||
loadPath: '{{lng}}/{{ns}}',
|
||||
parse: (data) => data,
|
||||
ajax: (url, opts, cb, data) => {
|
||||
let langParams = url.split('/')
|
||||
console.info(langParams)
|
||||
window.apollo.query({
|
||||
query: gql`
|
||||
{
|
||||
translations(locale:"${langParams[0]}", namespace:"${langParams[1]}") {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
`
|
||||
}).then(resp => {
|
||||
let ns = {}
|
||||
if (resp.data.translations.length > 0) {
|
||||
resp.data.translations.forEach(entry => {
|
||||
loSet(ns, entry.key, entry.value)
|
||||
})
|
||||
}
|
||||
return cb(ns, {status: '200'})
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
return cb(null, {status: '404'})
|
||||
})
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
enabled: true,
|
||||
expiration: 60 * 60 * 1000
|
||||
},
|
||||
defaultNS: 'common',
|
||||
lng: siteConfig.lang,
|
||||
fallbackLng: siteConfig.lang,
|
||||
ns: ['common', 'admin', 'auth']
|
||||
})
|
||||
return new VueI18Next(i18next)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user