feat: Color Theme page logic
This commit is contained in:
		
							
								
								
									
										130
									
								
								client/js/app.js
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								client/js/app.js
									
									
									
									
									
								
							| @@ -17,37 +17,6 @@ import 'jquery-simple-upload' | |||||||
| import 'jquery-smooth-scroll' | import 'jquery-smooth-scroll' | ||||||
| import 'jquery-sticky' | 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 | // Load Helpers | ||||||
| // ==================================== | // ==================================== | ||||||
| @@ -81,43 +50,11 @@ import treeComponent from './components/tree.vue' | |||||||
| import adminEditUserComponent from './pages/admin-edit-user.component.js' | import adminEditUserComponent from './pages/admin-edit-user.component.js' | ||||||
| import adminProfileComponent from './pages/admin-profile.component.js' | import adminProfileComponent from './pages/admin-profile.component.js' | ||||||
| import adminSettingsComponent from './pages/admin-settings.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 contentViewComponent from './pages/content-view.component.js' | ||||||
| import editorComponent from './components/editor.component.js' | import editorComponent from './components/editor.component.js' | ||||||
| import sourceViewComponent from './pages/source-view.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 | // Initialize Vue Modules | ||||||
| // ==================================== | // ==================================== | ||||||
| @@ -125,9 +62,44 @@ const _ = { | |||||||
| Vue.use(VueResource) | Vue.use(VueResource) | ||||||
| Vue.use(VueClipboards) | Vue.use(VueClipboards) | ||||||
| Vue.use(VueI18Next) | Vue.use(VueI18Next) | ||||||
| Vue.use(VueLodash, _) | Vue.use(VueLodash, helpers._) | ||||||
| Vue.use(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 | i18next | ||||||
|   .use(i18nextXHR) |   .use(i18nextXHR) | ||||||
|   .init({ |   .init({ | ||||||
| @@ -166,33 +138,7 @@ $(() => { | |||||||
|   const i18n = new VueI18Next(i18next) |   const i18n = new VueI18Next(i18next) | ||||||
|   window.wikijs = new Vue({ |   window.wikijs = new Vue({ | ||||||
|     mixins: [helpers], |     mixins: [helpers], | ||||||
|     components: { |     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 |  | ||||||
|     }, |  | ||||||
|     store, |     store, | ||||||
|     i18n, |     i18n, | ||||||
|     el: '#root', |     el: '#root', | ||||||
|   | |||||||
| @@ -1,12 +1,12 @@ | |||||||
| <template lang="pug"> | <template lang="pug"> | ||||||
|   .colorpicker |   .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> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
|   export default { |   export default { | ||||||
|     name: 'color-picker', |     name: 'color-picker', | ||||||
|     props: ['currentColor'], |     props: ['value'], | ||||||
|     data () { |     data () { | ||||||
|       return { |       return { | ||||||
|         colors: [ |         colors: [ | ||||||
| @@ -34,7 +34,7 @@ | |||||||
|     }, |     }, | ||||||
|     methods: { |     methods: { | ||||||
|       setColor(color) { |       setColor(color) { | ||||||
|         this.currentColor = color |         this.$emit('input', color) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| <template lang="pug"> | <template lang="pug"> | ||||||
|   .toggle(:class='{ "is-active": currentValue }', @click='changeToggle') |   .toggle(:class='{ "is-active": value }', @click='changeToggle') | ||||||
|     .toggle-container |     .toggle-container | ||||||
|       .toggle-pin |       .toggle-pin | ||||||
|     .toggle-text {{ desc }} |     .toggle-text {{ desc }} | ||||||
| @@ -8,13 +8,13 @@ | |||||||
| <script> | <script> | ||||||
|   export default { |   export default { | ||||||
|     name: 'toggle', |     name: 'toggle', | ||||||
|     props: ['currentValue', 'desc'], |     props: ['value', 'desc'], | ||||||
|     data () { |     data () { | ||||||
|       return { } |       return { } | ||||||
|     }, |     }, | ||||||
|     methods: { |     methods: { | ||||||
|       changeToggle() { |       changeToggle() { | ||||||
|         this.currentValue = !this.currentValue |         this.$emit('input', !this.value) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| 'use strict' | 'use strict' | ||||||
|  |  | ||||||
| const helpers = { | const helpers = { | ||||||
|  |   _: require('./lodash'), | ||||||
|   common: require('./common'), |   common: require('./common'), | ||||||
|   form: require('./form'), |   form: require('./form'), | ||||||
|   pages: require('./pages') |   pages: require('./pages') | ||||||
|   | |||||||
							
								
								
									
										65
									
								
								client/js/helpers/lodash.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								client/js/helpers/lodash.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								client/js/pages/admin-theme.component.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								client/js/pages/admin-theme.component.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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() | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -9,7 +9,12 @@ | |||||||
|     "passwordverify": "Verify Password", |     "passwordverify": "Verify Password", | ||||||
|     "provider": "Provider", |     "provider": "Provider", | ||||||
|     "savechanges": "Save Changes", |     "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": { |   "stats": { | ||||||
|     "subtitle": "General site-wide statistics", |     "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!", |     "flushsessionstext": "All users will be logged out and forced to login again. Your current session will also be affected!", | ||||||
|     "flushsessionsbtn": "Flush Sessions" |     "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": { |   "users": { | ||||||
|     "createauthorize": "Create / Authorize User", |     "createauthorize": "Create / Authorize User", | ||||||
|     "subtitle": "Manage users and access rights", |     "subtitle": "Manage users and access rights", | ||||||
| @@ -48,4 +72,4 @@ | |||||||
|     "edituser": "Edit User", |     "edituser": "Edit User", | ||||||
|     "uniqueid": "Unique ID" |     "uniqueid": "Unique ID" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -33,6 +33,7 @@ | |||||||
|     "settings": "Settings", |     "settings": "Settings", | ||||||
|     "source": "Source", |     "source": "Source", | ||||||
|     "stats": "Stats", |     "stats": "Stats", | ||||||
|  |     "sysinfo": "System Info", | ||||||
|     "syssettings": "System Settings", |     "syssettings": "System Settings", | ||||||
|     "theme": "Color Theme", |     "theme": "Color Theme", | ||||||
|     "users": "Users", |     "users": "Users", | ||||||
| @@ -47,4 +48,4 @@ | |||||||
|     "source": "Loading source...", |     "source": "Loading source...", | ||||||
|     "editor": "Loading editor..." |     "editor": "Loading editor..." | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -46,7 +46,7 @@ block content | |||||||
|                     span= t('nav.users') |                     span= t('nav.users') | ||||||
|                 li |                 li | ||||||
|                   a(href='/admin/theme') |                   a(href='/admin/theme') | ||||||
|                     i.nc-icon-outline.design_paint-37 |                     i.nc-icon-outline.ui-1_drop | ||||||
|                     span= t('nav.theme') |                     span= t('nav.theme') | ||||||
|                 li |                 li | ||||||
|                   a(href='/admin/settings') |                   a(href='/admin/settings') | ||||||
|   | |||||||
| @@ -4,25 +4,29 @@ block adminContent | |||||||
|   .hero |   .hero | ||||||
|     h1.title#title= t('nav.theme') |     h1.title#title= t('nav.theme') | ||||||
|     h2.subtitle= t('admin:theme.subtitle') |     h2.subtitle= t('admin:theme.subtitle') | ||||||
|     i.pageicon.nc-icon-outline.design_paint-37 |     i.pageicon.nc-icon-outline.ui-1_drop | ||||||
|   .form-sections |   admin-theme(inline-template, themedata=JSON.stringify(appconfig.theme)) | ||||||
|     section |     .form-sections | ||||||
|       label.label= t('admin:theme.primarycolor') |       section | ||||||
|       color-picker(current-color=appconfig.theme.primary) |         label.label= t('admin:theme.primarycolor') | ||||||
|       span.desc Used for top navigation bar, headers, links, etc. |         color-picker(v-model='primary') | ||||||
|     section |         span.desc= t('admin:theme.primarycolordesc') | ||||||
|       label.label= t('admin:theme.altcolor') |       section | ||||||
|       color-picker(current-color=appconfig.theme.alt) |         label.label= t('admin:theme.altcolor') | ||||||
|       span.desc Used for the sidebar (in a darker tone) |         color-picker(v-model='alt') | ||||||
|     section |         span.desc= t('admin:theme.altcolordesc') | ||||||
|       label.label= t('admin:theme.footercolor') |       section | ||||||
|       color-picker(current-color=appconfig.theme.footer) |         label.label= t('admin:theme.footercolor') | ||||||
|       span.desc Used for the foter (in a lighter tone) |         color-picker(v-model='footer') | ||||||
|     section |         span.desc= t('admin:theme.footercolordesc') | ||||||
|       label.label= t('admin:theme.codeblock') |       section | ||||||
|       toggle(:current-value=appconfig.theme.code.dark.toString(), desc='Use Dark Theme') |         label.label= t('admin:theme.codeblock.title') | ||||||
|       toggle(:current-value=appconfig.theme.code.colorize.toString(), desc='Colorize code syntax') |         toggle(v-model='codedark', desc=t('admin:theme.codeblock.dark')) | ||||||
|     section |         toggle(v-model='codecolorize', desc=t('admin:theme.codeblock.colorize')) | ||||||
|       button.button.is-green(@click='saveUser') |       section | ||||||
|         i.nc-icon-outline.ui-1_check |         button.button.is-grey(@click='resetTheme') | ||||||
|         span= t('admin:profile.savechanges') |           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') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user