admin-general.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <template lang='pug'>
  2. v-container(fluid, grid-list-lg)
  3. v-layout(row wrap)
  4. v-flex(xs12)
  5. .admin-header
  6. img.animated.fadeInUp(src='/_assets/svg/icon-categorize.svg', alt='General', style='width: 80px;')
  7. .admin-header-title
  8. .headline.primary--text.animated.fadeInLeft {{ $t('admin:general.title') }}
  9. .subtitle-1.grey--text.animated.fadeInLeft {{ $t('admin:general.subtitle') }}
  10. v-spacer
  11. v-btn.animated.fadeInDown(color='success', depressed, @click='save', large)
  12. v-icon(left) mdi-check
  13. span {{$t('common:actions.apply')}}
  14. v-form.pt-3
  15. v-layout(row wrap)
  16. v-flex(lg6 xs12)
  17. v-form
  18. v-card.animated.fadeInUp
  19. v-toolbar(color='primary', dark, dense, flat)
  20. v-toolbar-title.subtitle-1 {{ $t('admin:general.siteInfo') }}
  21. .overline.grey--text.pa-4 {{$t('admin:general.general')}}
  22. .px-3.pb-3
  23. v-text-field(
  24. outlined
  25. :label='$t(`admin:general.siteUrl`)'
  26. required
  27. :counter='255'
  28. v-model='config.host'
  29. prepend-icon='mdi-label-variant-outline'
  30. :hint='$t(`admin:general.siteUrlHint`)'
  31. persistent-hint
  32. )
  33. v-text-field.mt-3(
  34. outlined
  35. :label='$t(`admin:general.siteTitle`)'
  36. required
  37. :counter='50'
  38. v-model='config.title'
  39. prepend-icon='mdi-earth'
  40. :hint='$t(`admin:general.siteTitleHint`)'
  41. persistent-hint
  42. )
  43. v-divider
  44. .overline.grey--text.pa-4 {{$t('admin:general.logo')}}
  45. .pt-2.pb-7.pl-10.pr-3
  46. .d-flex.align-center
  47. v-avatar(size='100', tile)
  48. v-img(
  49. :src='config.logoUrl'
  50. lazy-src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNcWQ8AAdcBKrJda2oAAAAASUVORK5CYII='
  51. aspect-ratio='1'
  52. )
  53. .ml-4(style='flex: 1 1 auto;')
  54. v-text-field(
  55. outlined
  56. :label='$t(`admin:general.logoUrl`)'
  57. v-model='config.logoUrl'
  58. :hint='$t(`admin:general.logoUrlHint`)'
  59. persistent-hint
  60. append-icon='mdi-folder-image'
  61. @click:append='browseLogo'
  62. @keyup.enter='refreshLogo'
  63. )
  64. v-divider
  65. .overline.grey--text.pa-4 {{$t('admin:general.footerCopyright')}}
  66. .px-3.pb-3
  67. v-text-field(
  68. outlined
  69. :label='$t(`admin:general.companyName`)'
  70. v-model='config.company'
  71. :counter='255'
  72. prepend-icon='mdi-domain'
  73. persistent-hint
  74. :hint='$t(`admin:general.companyNameHint`)'
  75. )
  76. v-select.mt-3(
  77. outlined
  78. :label='$t(`admin:general.contentLicense`)'
  79. :items='contentLicenses'
  80. v-model='config.contentLicense'
  81. prepend-icon='mdi-creative-commons'
  82. :return-object='false'
  83. :hint='$t(`admin:general.contentLicenseHint`)'
  84. persistent-hint
  85. )
  86. v-text-field.mt-3(
  87. outlined
  88. :label='$t(`admin:general.footerOverride`)'
  89. v-model='config.footerOverride'
  90. prepend-icon='mdi-page-layout-footer'
  91. append-icon='mdi-language-markdown'
  92. persistent-hint
  93. :hint='$t(`admin:general.footerOverrideHint`)'
  94. )
  95. v-divider
  96. .overline.grey--text.pa-4 SEO
  97. .px-3.pb-3
  98. v-text-field(
  99. outlined
  100. :label='$t(`admin:general.siteDescription`)'
  101. :counter='255'
  102. v-model='config.description'
  103. prepend-icon='mdi-compass'
  104. :hint='$t(`admin:general.siteDescriptionHint`)'
  105. persistent-hint
  106. )
  107. v-select.mt-3(
  108. outlined
  109. :label='$t(`admin:general.metaRobots`)'
  110. multiple
  111. :items='metaRobots'
  112. v-model='config.robots'
  113. prepend-icon='mdi-compass'
  114. :return-object='false'
  115. :hint='$t(`admin:general.metaRobotsHint`)'
  116. persistent-hint
  117. )
  118. v-flex(lg6 xs12)
  119. v-card.animated.fadeInUp.wait-p4s
  120. v-toolbar(color='indigo', dark, dense, flat)
  121. v-toolbar-title.subtitle-1 Features
  122. v-card-text
  123. //- v-switch(
  124. //- inset
  125. //- label='Asset Image Optimization'
  126. //- color='indigo'
  127. //- v-model='config.featureTinyPNG'
  128. //- persistent-hint
  129. //- hint='Image optimization tool to reduce filesize and bandwidth costs.'
  130. //- disabled
  131. //- )
  132. //- v-text-field.mt-3(
  133. //- outlined
  134. //- label='TinyPNG API Key'
  135. //- :counter='255'
  136. //- v-model='config.description'
  137. //- prepend-icon='mdi-subdirectory-arrow-right'
  138. //- hint='Get your API key at https://tinypng.com/developers'
  139. //- persistent-hint
  140. //- disabled
  141. //- )
  142. //- v-divider.mt-3
  143. //- v-switch(
  144. //- inset
  145. //- label='Page Ratings'
  146. //- color='indigo'
  147. //- v-model='config.featurePageRatings'
  148. //- persistent-hint
  149. //- hint='Allow users to rate pages.'
  150. //- disabled
  151. //- )
  152. //- v-divider.mt-3
  153. v-switch.mt-0(
  154. inset
  155. label='Comments'
  156. color='indigo'
  157. v-model='config.featurePageComments'
  158. persistent-hint
  159. hint='Allow users to leave comments on pages.'
  160. )
  161. //- v-divider.mt-3
  162. //- v-switch(
  163. //- inset
  164. //- label='Personal Wikis'
  165. //- color='indigo'
  166. //- v-model='config.featurePersonalWikis'
  167. //- persistent-hint
  168. //- hint='Allow users to have their own personal wiki.'
  169. //- disabled
  170. //- )
  171. v-card.mt-5.animated.fadeInUp.wait-p6s
  172. v-toolbar(color='primary', dark, dense, flat)
  173. v-toolbar-title.subtitle-1 URL Handling
  174. v-card-text
  175. v-text-field(
  176. outlined
  177. :label='$t(`admin:general.pageExtensions`)'
  178. v-model='config.pageExtensions'
  179. prepend-icon='mdi-format-text-wrapping-overflow'
  180. :hint='$t(`admin:general.pageExtensionsHint`)'
  181. persistent-hint
  182. )
  183. v-card.mt-5.animated.fadeInUp.wait-p7s
  184. v-toolbar(color='primary', dark, dense, flat)
  185. v-toolbar-title.subtitle-1 {{$t('admin:general.editShortcuts')}}
  186. v-card-text
  187. v-switch.mt-0(
  188. inset
  189. :label='$t(`admin:general.editFab`)'
  190. color='primary'
  191. v-model='config.editFab'
  192. persistent-hint
  193. :hint='$t(`admin:general.editFabHint`)'
  194. )
  195. v-divider
  196. .overline.grey--text.pa-4 {{$t('admin:general.editMenuBar')}}
  197. .px-3.pb-3
  198. v-switch.mt-0.ml-1(
  199. inset
  200. :label='$t(`admin:general.displayEditMenuBar`)'
  201. color='primary'
  202. v-model='config.editMenuBar'
  203. persistent-hint
  204. :hint='$t(`admin:general.displayEditMenuBarHint`)'
  205. )
  206. v-switch.mt-4.ml-1(
  207. v-if='config.editMenuBar'
  208. inset
  209. :label='$t(`admin:general.displayEditMenuBtn`)'
  210. color='primary'
  211. v-model='config.editMenuBtn'
  212. persistent-hint
  213. :hint='$t(`admin:general.displayEditMenuBtnHint`)'
  214. )
  215. v-switch.mt-4.ml-1(
  216. v-if='config.editMenuBar'
  217. inset
  218. :label='$t(`admin:general.displayEditMenuExternalBtn`)'
  219. color='primary'
  220. v-model='config.editMenuExternalBtn'
  221. persistent-hint
  222. :hint='$t(`admin:general.displayEditMenuExternalBtnHint`)'
  223. )
  224. template(v-if='config.editMenuBar && config.editMenuExternalBtn')
  225. v-divider
  226. .overline.grey--text.pa-4 External Edit Button
  227. .px-3.pb-3
  228. v-text-field(
  229. outlined
  230. :label='$t(`admin:general.editMenuExternalName`)'
  231. v-model='config.editMenuExternalName'
  232. prepend-icon='mdi-format-title'
  233. :hint='$t(`admin:general.editMenuExternalNameHint`)'
  234. persistent-hint
  235. )
  236. v-text-field.mt-3(
  237. outlined
  238. :label='$t(`admin:general.editMenuExternalIcon`)'
  239. v-model='config.editMenuExternalIcon'
  240. prepend-icon='mdi-dice-5'
  241. :hint='$t(`admin:general.editMenuExternalIconHint`)'
  242. persistent-hint
  243. )
  244. v-text-field.mt-3(
  245. outlined
  246. :label='$t(`admin:general.editMenuExternalUrl`)'
  247. v-model='config.editMenuExternalUrl'
  248. prepend-icon='mdi-near-me'
  249. :hint='$t(`admin:general.editMenuExternalUrlHint`)'
  250. persistent-hint
  251. )
  252. component(:is='activeModal')
  253. </template>
  254. <script>
  255. import _ from 'lodash'
  256. import { sync } from 'vuex-pathify'
  257. import gql from 'graphql-tag'
  258. import editorStore from '../../store/editor'
  259. /* global WIKI */
  260. const titleRegex = /[<>"]/i
  261. WIKI.$store.registerModule('editor', editorStore)
  262. export default {
  263. i18nOptions: { namespaces: 'editor' },
  264. components: {
  265. editorModalMedia: () => import(/* webpackChunkName: "editor", webpackMode: "lazy" */ '../editor/editor-modal-media.vue')
  266. },
  267. data() {
  268. return {
  269. config: {
  270. host: '',
  271. title: '',
  272. description: '',
  273. robots: [],
  274. analyticsService: '',
  275. analyticsId: '',
  276. company: '',
  277. contentLicense: '',
  278. footerOverride: '',
  279. logoUrl: '',
  280. featureAnalytics: false,
  281. featurePageRatings: false,
  282. featurePageComments: false,
  283. featurePersonalWikis: false,
  284. featureTinyPNG: false,
  285. pageExtensions: '',
  286. editFab: false,
  287. editMenuBar: false,
  288. editMenuBtn: false,
  289. editMenuExternalBtn: false,
  290. editMenuExternalName: '',
  291. editMenuExternalIcon: '',
  292. editMenuExternalUrl: ''
  293. },
  294. metaRobots: [
  295. { text: 'Index', value: 'index' },
  296. { text: 'Follow', value: 'follow' },
  297. { text: 'No Index', value: 'noindex' },
  298. { text: 'No Follow', value: 'nofollow' }
  299. ]
  300. }
  301. },
  302. computed: {
  303. siteTitle: sync('site/title'),
  304. logoUrl: sync('site/logoUrl'),
  305. company: sync('site/company'),
  306. contentLicense: sync('site/contentLicense'),
  307. footerOverride: sync('site/footerOverride'),
  308. activeModal: sync('editor/activeModal'),
  309. contentLicenses () {
  310. return [
  311. { value: '', text: this.$t('common:license.none') },
  312. { value: 'alr', text: this.$t('common:license.alr') },
  313. { value: 'cc0', text: this.$t('common:license.cc0') },
  314. { value: 'ccby', text: this.$t('common:license.ccby') },
  315. { value: 'ccbysa', text: this.$t('common:license.ccbysa') },
  316. { value: 'ccbynd', text: this.$t('common:license.ccbynd') },
  317. { value: 'ccbync', text: this.$t('common:license.ccbync') },
  318. { value: 'ccbyncsa', text: this.$t('common:license.ccbyncsa') },
  319. { value: 'ccbyncnd', text: this.$t('common:license.ccbyncnd') }
  320. ]
  321. }
  322. },
  323. methods: {
  324. async save () {
  325. const title = _.get(this.config, 'title', '')
  326. if (titleRegex.test(title)) {
  327. this.$store.commit('showNotification', {
  328. style: 'error',
  329. message: this.$t('admin:general.siteTitleInvalidChars'),
  330. icon: 'alert'
  331. })
  332. return
  333. }
  334. try {
  335. await this.$apollo.mutate({
  336. mutation: gql`
  337. mutation (
  338. $host: String
  339. $title: String
  340. $description: String
  341. $robots: [String]
  342. $analyticsService: String
  343. $analyticsId: String
  344. $company: String
  345. $contentLicense: String
  346. $footerOverride: String
  347. $logoUrl: String
  348. $pageExtensions: String
  349. $featurePageRatings: Boolean
  350. $featurePageComments: Boolean
  351. $featurePersonalWikis: Boolean
  352. $editFab: Boolean
  353. $editMenuBar: Boolean
  354. $editMenuBtn: Boolean
  355. $editMenuExternalBtn: Boolean
  356. $editMenuExternalName: String
  357. $editMenuExternalIcon: String
  358. $editMenuExternalUrl: String
  359. ) {
  360. site {
  361. updateConfig(
  362. host: $host
  363. title: $title
  364. description: $description
  365. robots: $robots
  366. analyticsService: $analyticsService
  367. analyticsId: $analyticsId
  368. company: $company
  369. contentLicense: $contentLicense
  370. footerOverride: $footerOverride
  371. logoUrl: $logoUrl
  372. pageExtensions: $pageExtensions
  373. featurePageRatings: $featurePageRatings
  374. featurePageComments: $featurePageComments
  375. featurePersonalWikis: $featurePersonalWikis
  376. editFab: $editFab
  377. editMenuBar: $editMenuBar
  378. editMenuBtn: $editMenuBtn
  379. editMenuExternalBtn: $editMenuExternalBtn
  380. editMenuExternalName: $editMenuExternalName
  381. editMenuExternalIcon: $editMenuExternalIcon
  382. editMenuExternalUrl: $editMenuExternalUrl
  383. ) {
  384. responseResult {
  385. succeeded
  386. errorCode
  387. slug
  388. message
  389. }
  390. }
  391. }
  392. }
  393. `,
  394. variables: {
  395. host: _.get(this.config, 'host', ''),
  396. title: _.get(this.config, 'title', ''),
  397. description: _.get(this.config, 'description', ''),
  398. robots: _.get(this.config, 'robots', []),
  399. analyticsService: _.get(this.config, 'analyticsService', ''),
  400. analyticsId: _.get(this.config, 'analyticsId', ''),
  401. company: _.get(this.config, 'company', ''),
  402. contentLicense: _.get(this.config, 'contentLicense', ''),
  403. footerOverride: _.get(this.config, 'footerOverride', ''),
  404. logoUrl: _.get(this.config, 'logoUrl', ''),
  405. pageExtensions: _.get(this.config, 'pageExtensions', ''),
  406. featurePageRatings: _.get(this.config, 'featurePageRatings', false),
  407. featurePageComments: _.get(this.config, 'featurePageComments', false),
  408. featurePersonalWikis: _.get(this.config, 'featurePersonalWikis', false),
  409. editFab: _.get(this.config, 'editFab', false),
  410. editMenuBar: _.get(this.config, 'editMenuBar', false),
  411. editMenuBtn: _.get(this.config, 'editMenuBtn', false),
  412. editMenuExternalBtn: _.get(this.config, 'editMenuExternalBtn', false),
  413. editMenuExternalName: _.get(this.config, 'editMenuExternalName', ''),
  414. editMenuExternalIcon: _.get(this.config, 'editMenuExternalIcon', ''),
  415. editMenuExternalUrl: _.get(this.config, 'editMenuExternalUrl', '')
  416. },
  417. watchLoading (isLoading) {
  418. this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-update')
  419. }
  420. })
  421. this.$store.commit('showNotification', {
  422. style: 'success',
  423. message: this.$t('admin:general.saveSuccess'),
  424. icon: 'check'
  425. })
  426. this.siteTitle = this.config.title
  427. this.company = this.config.company
  428. this.contentLicense = this.config.contentLicense
  429. this.footerOverride = this.config.footerOverride
  430. this.logoUrl = this.config.logoUrl
  431. } catch (err) {
  432. this.$store.commit('pushGraphError', err)
  433. }
  434. },
  435. browseLogo () {
  436. this.$store.set('editor/editorKey', 'common')
  437. this.activeModal = 'editorModalMedia'
  438. },
  439. refreshLogo () {
  440. this.$forceUpdate()
  441. }
  442. },
  443. mounted () {
  444. this.$root.$on('editorInsert', opts => {
  445. this.config.logoUrl = opts.path
  446. })
  447. },
  448. beforeDestroy() {
  449. this.$root.$off('editorInsert')
  450. },
  451. apollo: {
  452. config: {
  453. query: gql`
  454. {
  455. site {
  456. config {
  457. host
  458. title
  459. description
  460. robots
  461. analyticsService
  462. analyticsId
  463. company
  464. contentLicense
  465. footerOverride
  466. logoUrl
  467. pageExtensions
  468. featurePageRatings
  469. featurePageComments
  470. featurePersonalWikis
  471. editFab
  472. editMenuBar
  473. editMenuBtn
  474. editMenuExternalBtn
  475. editMenuExternalName
  476. editMenuExternalIcon
  477. editMenuExternalUrl
  478. }
  479. }
  480. }
  481. `,
  482. fetchPolicy: 'network-only',
  483. update: (data) => _.cloneDeep(data.site.config),
  484. watchLoading (isLoading) {
  485. this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-refresh')
  486. }
  487. }
  488. }
  489. }
  490. </script>
  491. <style lang='scss'>
  492. </style>