diff --git a/client/js/app.js b/client/js/app.js index f2a1e8f5..397a399c 100644 --- a/client/js/app.js +++ b/client/js/app.js @@ -17,37 +17,6 @@ import 'jquery-simple-upload' import 'jquery-smooth-scroll' import 'jquery-sticky' -// ==================================== -// Load minimal lodash -// ==================================== - -import cloneDeep from 'lodash/cloneDeep' -import concat from 'lodash/concat' -import debounce from 'lodash/debounce' -import deburr from 'lodash/deburr' -import delay from 'lodash/delay' -import filter from 'lodash/filter' -import find from 'lodash/find' -import findKey from 'lodash/findKey' -import forEach from 'lodash/forEach' -import includes from 'lodash/includes' -import isBoolean from 'lodash/isBoolean' -import isEmpty from 'lodash/isEmpty' -import isNil from 'lodash/isNil' -import join from 'lodash/join' -import kebabCase from 'lodash/kebabCase' -import last from 'lodash/last' -import map from 'lodash/map' -import nth from 'lodash/nth' -import pullAt from 'lodash/pullAt' -import reject from 'lodash/reject' -import slice from 'lodash/slice' -import split from 'lodash/split' -import startCase from 'lodash/startCase' -import toString from 'lodash/toString' -import toUpper from 'lodash/toUpper' -import trim from 'lodash/trim' - // ==================================== // Load Helpers // ==================================== @@ -81,43 +50,11 @@ 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' -// ==================================== -// Build lodash object -// ==================================== - -const _ = { - deburr, - concat, - cloneDeep, - debounce, - delay, - filter, - find, - findKey, - forEach, - includes, - isBoolean, - isEmpty, - isNil, - join, - kebabCase, - last, - map, - nth, - pullAt, - reject, - slice, - split, - startCase, - toString, - toUpper, - trim -} - // ==================================== // Initialize Vue Modules // ==================================== @@ -125,9 +62,44 @@ const _ = { Vue.use(VueResource) Vue.use(VueClipboards) Vue.use(VueI18Next) -Vue.use(VueLodash, _) +Vue.use(VueLodash, helpers._) 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({ @@ -166,33 +138,7 @@ $(() => { const i18n = new VueI18Next(i18next) window.wikijs = new Vue({ mixins: [helpers], - components: { - alert: alertComponent, - adminEditUser: adminEditUserComponent, - adminProfile: adminProfileComponent, - adminSettings: adminSettingsComponent, - anchor: anchorComponent, - colorPicker: colorPickerComponent, - contentView: contentViewComponent, - editor: editorComponent, - editorCodeblock: editorCodeblockComponent, - editorFile: editorFileComponent, - editorVideo: editorVideoComponent, - history: historyComponent, - loadingSpinner: loadingSpinnerComponent, - modalCreatePage: modalCreatePageComponent, - modalCreateUser: modalCreateUserComponent, - modalDeleteUser: modalDeleteUserComponent, - modalDiscardPage: modalDiscardPageComponent, - modalMovePage: modalMovePageComponent, - modalProfile2fa: modalProfile2faComponent, - modalUpgradeSystem: modalUpgradeSystemComponent, - pageLoader: pageLoaderComponent, - search: searchComponent, - sourceView: sourceViewComponent, - toggle: toggleComponent, - tree: treeComponent - }, + components: {}, store, i18n, el: '#root', diff --git a/client/js/components/color-picker.vue b/client/js/components/color-picker.vue index 3f180e63..6abdc445 100644 --- a/client/js/components/color-picker.vue +++ b/client/js/components/color-picker.vue @@ -1,12 +1,12 @@ <template lang="pug"> .colorpicker - .colorpicker-choice(v-for='color in colors', :class='["is-" + color, color === currentColor ? "is-active" : ""]', @click='setColor(color)') + .colorpicker-choice(v-for='color in colors', :class='["is-" + color, color === value ? "is-active" : ""]', @click='setColor(color)') </template> <script> export default { name: 'color-picker', - props: ['currentColor'], + props: ['value'], data () { return { colors: [ @@ -34,7 +34,7 @@ }, methods: { setColor(color) { - this.currentColor = color + this.$emit('input', color) } } } diff --git a/client/js/components/toggle.vue b/client/js/components/toggle.vue index f64fe9d7..15436dbe 100644 --- a/client/js/components/toggle.vue +++ b/client/js/components/toggle.vue @@ -1,5 +1,5 @@ <template lang="pug"> - .toggle(:class='{ "is-active": currentValue }', @click='changeToggle') + .toggle(:class='{ "is-active": value }', @click='changeToggle') .toggle-container .toggle-pin .toggle-text {{ desc }} @@ -8,13 +8,13 @@ <script> export default { name: 'toggle', - props: ['currentValue', 'desc'], + props: ['value', 'desc'], data () { return { } }, methods: { changeToggle() { - this.currentValue = !this.currentValue + this.$emit('input', !this.value) } } } diff --git a/client/js/helpers/index.js b/client/js/helpers/index.js index 6f802e8b..6335809b 100644 --- a/client/js/helpers/index.js +++ b/client/js/helpers/index.js @@ -1,6 +1,7 @@ 'use strict' const helpers = { + _: require('./lodash'), common: require('./common'), form: require('./form'), pages: require('./pages') diff --git a/client/js/helpers/lodash.js b/client/js/helpers/lodash.js new file mode 100644 index 00000000..5373a77b --- /dev/null +++ b/client/js/helpers/lodash.js @@ -0,0 +1,65 @@ +'use strict' + +// ==================================== +// Load minimal lodash +// ==================================== + +import cloneDeep from 'lodash/cloneDeep' +import concat from 'lodash/concat' +import debounce from 'lodash/debounce' +import deburr from 'lodash/deburr' +import delay from 'lodash/delay' +import filter from 'lodash/filter' +import find from 'lodash/find' +import findKey from 'lodash/findKey' +import forEach from 'lodash/forEach' +import includes from 'lodash/includes' +import isBoolean from 'lodash/isBoolean' +import isEmpty from 'lodash/isEmpty' +import isNil from 'lodash/isNil' +import join from 'lodash/join' +import kebabCase from 'lodash/kebabCase' +import last from 'lodash/last' +import map from 'lodash/map' +import nth from 'lodash/nth' +import pullAt from 'lodash/pullAt' +import reject from 'lodash/reject' +import slice from 'lodash/slice' +import split from 'lodash/split' +import startCase from 'lodash/startCase' +import toString from 'lodash/toString' +import toUpper from 'lodash/toUpper' +import trim from 'lodash/trim' + +// ==================================== +// Build lodash object +// ==================================== + +export default { + deburr, + concat, + cloneDeep, + debounce, + delay, + filter, + find, + findKey, + forEach, + includes, + isBoolean, + isEmpty, + isNil, + join, + kebabCase, + last, + map, + nth, + pullAt, + reject, + slice, + split, + startCase, + toString, + toUpper, + trim +} diff --git a/client/js/pages/admin-theme.component.js b/client/js/pages/admin-theme.component.js new file mode 100644 index 00000000..4cbafc2e --- /dev/null +++ b/client/js/pages/admin-theme.component.js @@ -0,0 +1,48 @@ +'use strict' + +export default { + name: 'admin-theme', + props: ['themedata'], + data() { + return { + primary: 'indigo', + alt: 'blue-grey', + footer: 'blue-grey', + codedark: 'true', + codecolorize: 'true' + } + }, + methods: { + saveTheme() { + let self = this + this.$http.post(window.location.href, self.$data).then(resp => { + self.$store.dispatch('alert', { + style: 'green', + icon: 'check', + msg: 'Theme settings have been applied successfully.' + }) + }).catch(err => { + self.$store.dispatch('alert', { + style: 'red', + icon: 'square-cross', + msg: 'Error: ' + err.body.msg + }) + }) + }, + resetTheme() { + this.primary = 'indigo' + this.alt = 'blue-grey' + this.footer = 'blue-grey' + this.codedark = 'true' + this.codecolorize = 'true' + } + }, + mounted() { + let theme = JSON.parse(this.themedata) + this.primary = theme.primary + this.alt = theme.alt + this.footer = theme.footer + this.codedark = theme.code.dark.toString() + this.codecolorize = theme.code.colorize.toString() + } +} diff --git a/server/locales/en/admin.json b/server/locales/en/admin.json index 7a46d992..1df4ed38 100644 --- a/server/locales/en/admin.json +++ b/server/locales/en/admin.json @@ -9,7 +9,12 @@ "passwordverify": "Verify Password", "provider": "Provider", "savechanges": "Save Changes", - "subtitle": "Profile and authentication info" + "subtitle": "Profile and authentication info", + "tfa": "Two-Factor Authentication", + "tfadisable": "Disable 2FA", + "tfadisabled": "Disabled", + "tfaenable": "Enable 2FA", + "tfaenabled": "Enabled" }, "stats": { "subtitle": "General site-wide statistics", @@ -36,6 +41,25 @@ "flushsessionstext": "All users will be logged out and forced to login again. Your current session will also be affected!", "flushsessionsbtn": "Flush Sessions" }, + "system": { + "subtitle": "Information and utilities for your wiki" + }, + "theme": { + "subtitle": "Change the look and feel of your wiki", + "primarycolor": "Primary Color", + "primarycolordesc": "Used for top navigation bar, headers, links, etc.", + "altcolor": "Alternate Color", + "altcolordesc": "Used for the sidebar (in a darker tone)", + "footercolor": "Footer Color", + "footercolordesc": "Used for the foter (in a lighter tone)", + "codeblock": { + "title": "Code Blocks", + "dark": "Use Dark Theme", + "colorize": "Colorize code syntax" + }, + "savechanges": "Save Changes", + "reset": "Revert to Defaults" + }, "users": { "createauthorize": "Create / Authorize User", "subtitle": "Manage users and access rights", @@ -48,4 +72,4 @@ "edituser": "Edit User", "uniqueid": "Unique ID" } -} \ No newline at end of file +} diff --git a/server/locales/en/common.json b/server/locales/en/common.json index 18ce4087..32dd6930 100644 --- a/server/locales/en/common.json +++ b/server/locales/en/common.json @@ -33,6 +33,7 @@ "settings": "Settings", "source": "Source", "stats": "Stats", + "sysinfo": "System Info", "syssettings": "System Settings", "theme": "Color Theme", "users": "Users", @@ -47,4 +48,4 @@ "source": "Loading source...", "editor": "Loading editor..." } -} \ No newline at end of file +} diff --git a/server/views/pages/admin/_layout.pug b/server/views/pages/admin/_layout.pug index d2fe6190..2776c8b9 100644 --- a/server/views/pages/admin/_layout.pug +++ b/server/views/pages/admin/_layout.pug @@ -46,7 +46,7 @@ block content span= t('nav.users') li a(href='/admin/theme') - i.nc-icon-outline.design_paint-37 + i.nc-icon-outline.ui-1_drop span= t('nav.theme') li a(href='/admin/settings') diff --git a/server/views/pages/admin/theme.pug b/server/views/pages/admin/theme.pug index dcd330d5..df4e2dce 100644 --- a/server/views/pages/admin/theme.pug +++ b/server/views/pages/admin/theme.pug @@ -4,25 +4,29 @@ block adminContent .hero h1.title#title= t('nav.theme') h2.subtitle= t('admin:theme.subtitle') - i.pageicon.nc-icon-outline.design_paint-37 - .form-sections - section - label.label= t('admin:theme.primarycolor') - color-picker(current-color=appconfig.theme.primary) - span.desc Used for top navigation bar, headers, links, etc. - section - label.label= t('admin:theme.altcolor') - color-picker(current-color=appconfig.theme.alt) - span.desc Used for the sidebar (in a darker tone) - section - label.label= t('admin:theme.footercolor') - color-picker(current-color=appconfig.theme.footer) - span.desc Used for the foter (in a lighter tone) - section - label.label= t('admin:theme.codeblock') - toggle(:current-value=appconfig.theme.code.dark.toString(), desc='Use Dark Theme') - toggle(:current-value=appconfig.theme.code.colorize.toString(), desc='Colorize code syntax') - section - button.button.is-green(@click='saveUser') - i.nc-icon-outline.ui-1_check - span= t('admin:profile.savechanges') + i.pageicon.nc-icon-outline.ui-1_drop + admin-theme(inline-template, themedata=JSON.stringify(appconfig.theme)) + .form-sections + section + label.label= t('admin:theme.primarycolor') + color-picker(v-model='primary') + span.desc= t('admin:theme.primarycolordesc') + section + label.label= t('admin:theme.altcolor') + color-picker(v-model='alt') + span.desc= t('admin:theme.altcolordesc') + section + label.label= t('admin:theme.footercolor') + color-picker(v-model='footer') + span.desc= t('admin:theme.footercolordesc') + section + label.label= t('admin:theme.codeblock.title') + toggle(v-model='codedark', desc=t('admin:theme.codeblock.dark')) + toggle(v-model='codecolorize', desc=t('admin:theme.codeblock.colorize')) + section + button.button.is-grey(@click='resetTheme') + i.nc-icon-outline.design_paint-37 + span= t('admin:theme.reset') + button.button.is-green(@click='saveTheme') + i.nc-icon-outline.ui-1_check + span= t('admin:theme.savechanges')