admin-theme.vue 8.83 KB
Newer Older
1
<template lang='pug'>
2
  v-container(fluid, grid-list-lg)
3 4
    v-layout(row wrap)
      v-flex(xs12)
5
        .admin-header
Nick's avatar
Nick committed
6
          img.animated.fadeInUp(src='/svg/icon-paint-palette.svg', alt='Theme', style='width: 80px;')
7
          .admin-header-title
Nick's avatar
Nick committed
8
            .headline.primary--text.animated.fadeInLeft {{$t('admin:theme.title')}}
9
            .subtitle-1.grey--text.animated.fadeInLeft.wait-p2s {{$t('admin:theme.subtitle')}}
10
          v-spacer
Nick's avatar
Nick committed
11
          v-btn.animated.fadeInRight(color='success', depressed, @click='save', large, :loading='loading')
12
            v-icon(left) mdi-check
13
            span {{$t('common:actions.apply')}}
14 15 16
        v-form.pt-3
          v-layout(row wrap)
            v-flex(lg6 xs12)
Nick's avatar
Nick committed
17
              v-card.animated.fadeInUp
18
                v-toolbar(color='primary', dark, dense, flat)
19
                  v-toolbar-title.subtitle-1 {{$t('admin:theme.title')}}
20
                v-card-text
21 22
                  v-select(
                    :items='themes'
23 24
                    outlined
                    prepend-icon='mdi-palette'
25
                    v-model='config.theme'
Nick's avatar
Nick committed
26
                    :label='$t(`admin:theme.siteTheme`)'
27
                    persistent-hint
Nick's avatar
Nick committed
28
                    :hint='$t(`admin:theme.siteThemeHint`)'
29
                    )
30
                    template(slot='item', slot-scope='data')
31
                      v-list-item-avatar
32
                        v-icon.blue--text(dark) mdi-image-filter-frames
33 34 35
                      v-list-item-content
                        v-list-item-title(v-html='data.item.text')
                        v-list-item-sub-title(v-html='data.item.author')
36 37
                  v-select.mt-3(
                    :items='iconsets'
38 39
                    outlined
                    prepend-icon='mdi-paw'
40 41 42 43 44
                    v-model='config.iconset'
                    :label='$t(`admin:theme.iconset`)'
                    persistent-hint
                    :hint='$t(`admin:theme.iconsetHint`)'
                    )
45
                  v-divider.mt-3
46 47
                  v-switch(
                    v-model='darkMode'
Nick's avatar
Nick committed
48
                    :label='$t(`admin:theme.darkMode`)'
49 50
                    color='primary'
                    persistent-hint
Nick's avatar
Nick committed
51
                    :hint='$t(`admin:theme.darkModeHint`)'
52
                    )
53

Nick's avatar
Nick committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
              //- v-card.mt-3.animated.fadeInUp.wait-p1s
              //-   v-toolbar(color='primary', dark, dense, flat)
              //-     v-toolbar-title.subtitle-1 {{$t(`admin:theme.options`)}}
              //-     v-spacer
              //-     v-chip(label, color='white', small).primary--text coming soon
              //-   v-card-text
              //-     v-select(
              //-       :items='iconsets'
              //-       outlined
              //-       prepend-icon='mdi-border-vertical'
              //-       v-model='config.iconset'
              //-       label='Table of Contents Position'
              //-       persistent-hint
              //-       hint='Select whether the table of contents is shown on the left, right or not at all.'
              //-       )

              v-card.mt-3.animated.fadeInUp.wait-p2s
71
                v-toolbar(color='primary', dark, dense, flat)
72
                  v-toolbar-title.subtitle-1 {{$t(`admin:theme.codeInjection`)}}
73 74
                v-card-text
                  v-textarea(
75
                    v-model='config.injectCSS'
Nick's avatar
Nick committed
76
                    :label='$t(`admin:theme.cssOverride`)'
77
                    outlined
78 79
                    color='primary'
                    persistent-hint
Nick's avatar
Nick committed
80
                    :hint='$t(`admin:theme.cssOverrideHint`)'
81 82
                    auto-grow
                    )
83 84 85 86
                  i18next.caption.pl-2.ml-1(path='admin:theme.cssOverrideWarning', tag='div')
                    strong.red--text(place='caution') {{$t('admin:theme.cssOverrideWarningCaution')}}
                    code(place='cssClass') .contents
                  v-textarea.mt-3(
87
                    v-model='config.injectHead'
Nick's avatar
Nick committed
88
                    :label='$t(`admin:theme.headHtmlInjection`)'
89
                    outlined
90 91
                    color='primary'
                    persistent-hint
Nick's avatar
Nick committed
92
                    :hint='$t(`admin:theme.headHtmlInjectionHint`)'
93 94 95
                    auto-grow
                    )
                  v-textarea.mt-2(
96
                    v-model='config.injectBody'
Nick's avatar
Nick committed
97
                    :label='$t(`admin:theme.bodyHtmlInjection`)'
98
                    outlined
99 100
                    color='primary'
                    persistent-hint
Nick's avatar
Nick committed
101
                    :hint='$t(`admin:theme.bodyHtmlInjectionHint`)'
102 103
                    auto-grow
                    )
104
            v-flex(lg6 xs12)
Nick's avatar
Nick committed
105
              v-card.animated.fadeInUp.wait-p2s
106
                v-toolbar(color='teal', dark, dense, flat)
107
                  v-toolbar-title.subtitle-1 {{$t('admin:theme.downloadThemes')}}
108 109
                  v-spacer
                  v-chip(label, color='white', small).teal--text coming soon
110 111 112
                v-data-table(
                  :headers='headers',
                  :items='themes',
113
                  hide-default-footer,
114
                  item-key='value',
115
                  :items-per-page='1000'
116
                )
Nick's avatar
Nick committed
117
                  template(v-slot:item='thm')
118 119 120 121 122 123 124
                    td
                      strong {{thm.item.text}}
                    td
                      span {{ thm.item.author }}
                    td.text-xs-center
                      v-progress-circular(v-if='thm.item.isDownloading', indeterminate, color='blue', size='20', :width='2')
                      v-btn(v-else-if='thm.item.isInstalled && thm.item.installDate < thm.item.updatedAt', icon)
125
                        v-icon.blue--text mdi-cached
126
                      v-btn(v-else-if='thm.item.isInstalled', icon)
Nick's avatar
Nick committed
127
                        v-icon.green--text mdi-check-bold
128
                      v-btn(v-else, icon)
129
                        v-icon.grey--text mdi-cloud-download
130 131 132
</template>

<script>
133
import _ from 'lodash'
NGPixel's avatar
NGPixel committed
134
import { sync } from 'vuex-pathify'
135

136
import themeConfigQuery from 'gql/admin/theme/theme-query-config.gql'
137
import themeSaveMutation from 'gql/admin/theme/theme-mutation-save.gql'
138

139 140 141
export default {
  data() {
    return {
142
      loading: false,
143
      themes: [
144
        { text: 'Default', author: 'requarks.io', value: 'default', isInstalled: true, installDate: '', updatedAt: '' }
145
      ],
146
      iconsets: [
147
        { text: 'Material Design Icons (default)', value: 'mdi' },
148
        { text: 'Font Awesome 5', value: 'fa' },
149
        { text: 'Font Awesome 4', value: 'fa4' }
150
      ],
151 152 153
      config: {
        theme: 'default',
        darkMode: false,
154
        iconset: '',
155 156 157 158 159
        injectCSS: '',
        injectHead: '',
        injectBody: ''
      },
      darkModeInitial: false
160
    }
NGPixel's avatar
NGPixel committed
161
  },
NGPixel's avatar
NGPixel committed
162
  computed: {
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    darkMode: sync('site/dark'),
    headers() {
      return [
        {
          text: this.$t('admin:theme.downloadName'),
          align: 'left',
          value: 'text'
        },
        {
          text: this.$t('admin:theme.downloadAuthor'),
          align: 'left',
          value: 'author'
        },
        {
          text: this.$t('admin:theme.downloadDownload'),
          align: 'center',
          value: 'value',
          sortable: false,
          width: 100
        }
      ]
    }
185
  },
186 187 188 189 190
  watch: {
    'darkMode' (newValue, oldValue) {
      this.$vuetify.theme.dark = newValue
    }
  },
191 192 193 194
  mounted() {
    this.darkModeInitial = this.darkMode
  },
  beforeDestroy() {
NGPixel's avatar
NGPixel committed
195
    this.darkMode = this.darkModeInitial
196
    this.$vuetify.theme.dark = this.darkModeInitial
197 198 199 200 201 202 203 204 205
  },
  methods: {
    async save () {
      this.loading = true
      this.$store.commit(`loadingStart`, 'admin-theme-save')
      try {
        const respRaw = await this.$apollo.mutate({
          mutation: themeSaveMutation,
          variables: {
206
            theme: this.config.theme,
207
            iconset: this.config.iconset,
208 209 210 211
            darkMode: this.darkMode,
            injectCSS: this.config.injectCSS,
            injectHead: this.config.injectHead,
            injectBody: this.config.injectBody
212 213 214 215 216 217 218 219 220 221 222 223 224 225
          }
        })
        const resp = _.get(respRaw, 'data.theming.setConfig.responseResult', {})
        if (resp.succeeded) {
          this.darkModeInitial = this.darkMode
          this.$store.commit('showNotification', {
            message: 'Theme settings updated successfully.',
            style: 'success',
            icon: 'check'
          })
        } else {
          throw new Error(resp.message)
        }
      } catch (err) {
226
        this.$store.commit('pushGraphError', err)
227 228 229
      }
      this.$store.commit(`loadingStop`, 'admin-theme-save')
      this.loading = false
NGPixel's avatar
NGPixel committed
230
    }
231 232 233 234 235 236 237 238 239 240
  },
  apollo: {
    config: {
      query: themeConfigQuery,
      fetchPolicy: 'network-only',
      update: (data) => data.theming.config,
      watchLoading (isLoading) {
        this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-theme-refresh')
      }
    }
241 242 243 244 245 246 247
  }
}
</script>

<style lang='scss'>

</style>