فهرست منبع

feat: admin - general, locale, theme, users, system info UI

NGPixel 7 سال پیش
والد
کامیت
1ae47dde2e

+ 1 - 0
client/app.js

@@ -107,6 +107,7 @@ Vue.prototype.Velocity = Velocity
 Vue.component('admin', () => import(/* webpackChunkName: "admin" */ './components/admin.vue'))
 Vue.component('editor', () => import(/* webpackChunkName: "editor" */ './components/editor.vue'))
 Vue.component('login', () => import(/* webpackMode: "eager" */ './components/login.vue'))
+Vue.component('nav-header', () => import(/* webpackMode: "eager" */ './components/nav-header.vue'))
 Vue.component('navigator', () => import(/* webpackMode: "eager" */ './components/navigator.vue'))
 Vue.component('setup', () => import(/* webpackChunkName: "setup" */ './components/setup.vue'))
 Vue.component('toggle', () => import(/* webpackMode: "eager" */ './components/toggle.vue'))

+ 12 - 7
client/components/admin-general.vue

@@ -10,25 +10,30 @@
               v-card
                 v-toolbar(color='blue', dark, dense, flat)
                   v-toolbar-title
-                  .subheading Site Info
+                    .subheading Site Info
+                  v-btn(fab, absolute, right, bottom, small, light): v-icon save
                 v-card-text
-                  v-text-field(label='Site Title', required, :counter='50')
+                  v-text-field(label='Site Title', required, :counter='50', v-model='siteTitle')
                   v-text-field(label='Site Description', :counter='255')
+                  v-text-field(label='Site Keywords', :counter='255')
+                  v-select(label='Meta Robots', chips, tags, :items='metaRobots', v-model='metaRobotsSelection')
             v-flex(lg6 xs12)
               v-card
                 v-toolbar(color='blue', dark, dense, flat)
                   v-toolbar-title
-                  .subheading Site Branding
-                v-card-text
-                  v-text-field(label='Site Title', required, :counter='50')
-                  v-text-field(label='Site Description', :counter='255')
+                    .subheading Site Branding
+                v-card-text ---
 
 </template>
 
 <script>
 export default {
   data() {
-    return {}
+    return {
+      siteTitle: 'Wiki.js',
+      metaRobotsSelection: ['Index', 'Follow'],
+      metaRobots: ['Index', 'Follow', 'No Index', 'No Follow']
+    }
   }
 }
 </script>

+ 84 - 0
client/components/admin-locale.vue

@@ -0,0 +1,84 @@
+<template lang='pug'>
+  v-container(fluid, fill-height, grid-list-lg)
+    v-layout(row wrap)
+      v-flex(xs12)
+        .headline.blue--text.text--darken-2 Locale
+        .subheading.grey--text Set localization options for your wiki
+        v-form.pt-3
+          v-layout(row wrap)
+            v-flex(lg6 xs12)
+              v-card
+                v-toolbar(color='blue', dark, dense, flat)
+                  v-toolbar-title
+                    .subheading Locale
+                  v-btn(fab, absolute, right, bottom, small, light): v-icon save
+                v-card-text
+                  v-select(:items='locales', prepend-icon='public', v-model='selectedLocale', label='Site Locale', persistent-hint, hint='All UI text elements will be displayed in selected language.')
+                    template(slot='item', slot-scope='data')
+                      v-list-tile-avatar
+                        v-avatar.blue.white--text(tile, size='40', v-html='data.item.value.toUpperCase()')
+                      v-list-tile-content
+                        v-list-tile-title(v-html='data.item.text')
+                        v-list-tile-sub-title(v-html='data.item.original')
+                  v-divider
+                  v-switch(v-model='rtlEnabled', label='RTL Text Display', color='blue darken-2', persistent-hint, hint='For Right-to-Left languages, e.g. Arabic')
+            v-flex(lg6 xs12)
+              v-card
+                v-toolbar(color='blue', dark, dense, flat)
+                  v-toolbar-title
+                    .subheading Download Locale
+                v-list
+                  v-list-tile(@click='')
+                    v-list-tile-avatar
+                      v-avatar.blue.white--text(tile, size='40') ZH
+                    v-list-tile-content
+                      v-list-tile-title Chinese
+                      v-list-tile-sub-title 中文
+                    v-list-tile-action
+                      v-btn(icon)
+                        v-icon.grey--text cloud_download
+                  v-list-tile(@click='')
+                    v-list-tile-avatar
+                      v-avatar.blue.white--text(tile, size='40') EN
+                    v-list-tile-content
+                      v-list-tile-title English
+                      v-list-tile-sub-title English
+                    v-list-tile-action
+                      v-icon.green--text check
+                  v-list-tile(@click='')
+                    v-list-tile-avatar
+                      v-avatar.blue.white--text(tile, size='40') FR
+                    v-list-tile-content
+                      v-list-tile-title French
+                      v-list-tile-sub-title Français
+                    v-list-tile-action
+                      v-icon.green--text check
+                  v-list-tile(@click='')
+                    v-list-tile-avatar
+                      v-avatar.blue.white--text(tile, size='40') RU
+                    v-list-tile-content
+                      v-list-tile-title Russian
+                      v-list-tile-sub-title Русский
+                    v-list-tile-action
+                      v-btn(icon)
+                        v-icon.blue--text update
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      locales: [
+        { text: 'English', original: 'English', value: 'en' },
+        { text: 'French', original: 'Français', value: 'fr' }
+      ],
+      selectedLocale: 'en',
+      rtlEnabled: false
+    }
+  }
+}
+</script>
+
+<style lang='scss'>
+
+</style>

+ 114 - 0
client/components/admin-system.vue

@@ -0,0 +1,114 @@
+<template lang='pug'>
+  v-container(fluid, fill-height, grid-list-lg)
+    v-layout(row, wrap)
+      v-flex(xs12)
+        .headline.blue--text.text--darken-2 System Info
+        .subheading.grey--text Information about your system
+        v-layout.mt-3(row wrap)
+          v-flex(lg6 xs12)
+            v-card
+              v-btn(fab, absolute, right, top, small, light): v-icon refresh
+              v-list(two-line, dense)
+                v-subheader Wiki.js
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-icon.blue.white--text system_update_alt
+                  v-list-tile-content
+                    v-list-tile-title Current Version
+                    v-list-tile-sub-title 2.0.0
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-icon.blue.white--text open_in_browser
+                  v-list-tile-content
+                    v-list-tile-title Latest Version
+                    v-list-tile-sub-title 2.0.0
+                  v-list-tile-action
+                    v-list-tile-action-text Published 4 days ago
+
+                v-divider
+
+                v-subheader Host Information
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-icon.blue-grey.white--text bubble_chart
+                  v-list-tile-content
+                    v-list-tile-title Operating System
+                    v-list-tile-sub-title Linux (linux) 4.4.0-116-generic x64
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-icon.blue-grey.white--text computer
+                  v-list-tile-content
+                    v-list-tile-title Hostname
+                    v-list-tile-sub-title wikijs
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-icon.blue-grey.white--text nfc
+                  v-list-tile-content
+                    v-list-tile-title CPU Cores
+                    v-list-tile-sub-title 8
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-icon.blue-grey.white--text memory
+                  v-list-tile-content
+                    v-list-tile-title Total RAM
+                    v-list-tile-sub-title 16.0 Gb
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-icon.blue-grey.white--text last_page
+                  v-list-tile-content
+                    v-list-tile-title Working Directory
+                    v-list-tile-sub-title /var/wiki
+
+          v-flex(lg6 xs12)
+            v-card.pb-3
+              v-list(dense)
+                v-subheader Node.js
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-avatar.light-green(size='40')
+                      icon-node-js(fillColor='#FFFFFF')
+                  v-list-tile-content
+                    v-list-tile-title v8.9.4
+
+                v-divider
+
+                v-subheader Redis
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-avatar.red(size='40')
+                      icon-cube(fillColor='#FFFFFF')
+                  v-list-tile-content
+                    v-list-tile-title 4.0.8
+
+                v-divider
+
+                v-subheader PostgreSQL
+                v-list-tile(avatar)
+                  v-list-tile-avatar
+                    v-avatar.indigo.darken-1(size='40')
+                      icon-database(fillColor='#FFFFFF')
+                  v-list-tile-content
+                    v-list-tile-title 9.6.8
+
+</template>
+
+<script>
+import IconCube from 'mdi/cube'
+import IconDatabase from 'mdi/database'
+import IconNodeJs from 'mdi/nodejs'
+
+export default {
+  components: {
+    IconCube,
+    IconDatabase,
+    IconNodeJs
+  },
+  data() {
+    return {}
+  }
+}
+</script>
+
+<style lang='scss'>
+
+</style>

+ 49 - 0
client/components/admin-theme.vue

@@ -0,0 +1,49 @@
+<template lang='pug'>
+  v-container(fluid, fill-height, grid-list-lg)
+    v-layout(row wrap)
+      v-flex(xs12)
+        .headline.blue--text.text--darken-2 Theme
+        .subheading.grey--text Modify the look &amp; feel of your wiki
+        v-form.pt-3
+          v-layout(row wrap)
+            v-flex(lg6 xs12)
+              v-card
+                v-toolbar(color='blue', dark, dense, flat)
+                  v-toolbar-title
+                    .subheading Theme
+                  v-btn(fab, absolute, right, bottom, small, light): v-icon save
+                v-card-text
+                  v-select(:items='themes', prepend-icon='palette', v-model='selectedTheme', label='Site Theme', persistent-hint, hint='Themes affect how content pages are displayed. Other site sections (such as the editor or admin area) are not affected.')
+                    template(slot='item', slot-scope='data')
+                      v-list-tile-avatar
+                        v-icon.blue--text(dark) filter_frames
+                      v-list-tile-content
+                        v-list-tile-title(v-html='data.item.text')
+                        v-list-tile-sub-title(v-html='data.item.author')
+                  v-divider
+                  v-switch(v-model='darkMode', label='Dark Mode', color='blue darken-2', persistent-hint, hint='Not recommended for accessibility')
+            v-flex(lg6 xs12)
+              v-card
+                v-toolbar(color='blue', dark, dense, flat)
+                  v-toolbar-title
+                    .subheading Theme Options
+                v-list
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      themes: [
+        { text: 'Default', author: 'requarks.io', value: 'default' }
+      ],
+      selectedTheme: 'default',
+      darkMode: false
+    }
+  }
+}
+</script>
+
+<style lang='scss'>
+
+</style>

+ 76 - 0
client/components/admin-users.vue

@@ -0,0 +1,76 @@
+<template lang='pug'>
+  v-container(fluid, fill-height, grid-list-lg)
+    v-layout(row wrap)
+      v-flex(xs12)
+        .headline.blue--text.text--darken-2 Users
+        .subheading.grey--text Manage users
+        v-card.mt-3.elevation-1
+          v-card-title
+            v-btn() New User
+            v-btn() Authorize User
+            v-spacer
+            v-text-field(append-icon='search', label='Search', single-line, hide-details, v-model='search')
+          v-data-table(
+            v-model='selected'
+            :items='items',
+            :headers='headers',
+            :search='search',
+            :pagination.sync='pagination',
+            select-all,
+            hide-actions
+          )
+            template(slot='items', slot-scope='props')
+              tr(:active='props.selected', @click='props.selected = !props.selected')
+                td
+                  v-checkbox(hide-details, :input-value='props.selected')
+                td.text-xs-right {{ props.item.id }}
+                td {{ props.item.email }}
+                td {{ props.item.name }}
+                td {{ props.item.provider }}
+            template(slot='no-data')
+              v-alert(icon='warning', :value='true') No users to display!
+          .text-xs-center.py-2
+            v-pagination(v-model='pagination.page', :length='pages')
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      selected: [],
+      pagination: {},
+      items: [
+        { id: 1, email: 'user@test.com', name: 'John Doe', provider: 'local' }
+      ],
+      headers: [
+        {
+          text: 'ID',
+          align: 'right',
+          value: 'id',
+          width: 80
+        },
+        { text: 'Email', value: 'email' },
+        { text: 'Name', value: 'name' },
+        { text: 'Provider', value: 'provider' },
+        { text: 'Created On', value: 'createdOn' },
+        { text: 'Updated On', value: 'updatedOn' },
+        { text: 'Actions', value: 'actions', sortable: false }
+      ],
+      search: ''
+    }
+  },
+  computed: {
+    pages () {
+      if (this.pagination.rowsPerPage == null || this.pagination.totalItems == null) {
+        return 0
+      }
+
+      return Math.ceil(this.pagination.totalItems / this.pagination.rowsPerPage)
+    }
+  }
+}
+</script>
+
+<style lang='scss'>
+
+</style>

+ 25 - 27
client/components/admin.vue

@@ -1,29 +1,6 @@
 <template lang='pug'>
   v-app.admin
-    v-toolbar(color='black', dark, app, clipped-left, fixed, flat)
-      v-toolbar-side-icon(@click.native='')
-      v-toolbar-title
-        span.subheading Wiki.js
-      v-spacer
-      v-btn(icon)
-        v-icon(color='grey') search
-      v-btn(icon, @click.native='darkTheme = !darkTheme')
-        v-icon(color='grey') settings
-      v-menu(offset-y, min-width='300')
-        v-btn(icon, slot='activator')
-          v-icon(color='grey') account_circle
-        v-list.py-0
-          v-list-tile.py-3(avatar)
-            v-list-tile-avatar
-              v-avatar.red(:size='40'): span.white--text.subheading JD
-            v-list-tile-content
-              v-list-tile-title John Doe
-              v-list-tile-sub-title john.doe@example.com
-          v-divider.my-0
-          v-list-tile(@click='')
-            v-list-tile-action: v-icon(color='red') exit_to_app
-            v-list-tile-title Logout
-
+    nav-header
     v-navigation-drawer.pb-0(v-model='adminDrawerShown', app, fixed, clipped, left, permanent)
       v-list(dense)
         v-list-tile.pt-2(to='/dashboard')
@@ -65,6 +42,9 @@
         v-list-tile(to='/logging')
           v-list-tile-action: v-icon graphic_eq
           v-list-tile-title Logging
+        v-list-tile(to='/search')
+          v-list-tile-action: v-icon search
+          v-list-tile-title Search Engine
         v-list-tile(to='/storage')
           v-list-tile-action: v-icon storage
           v-list-tile-title Storage
@@ -81,9 +61,10 @@
           v-list-tile-title Developer Tools
 
     v-content
-      router-view
+      transition(name='admin-router')
+        router-view
 
-    v-footer.py-2.justify-center(app, fixed, color='grey lighten-3', inset, height='auto')
+    v-footer.py-2.justify-center(app, absolute, color='grey lighten-3', inset, height='auto')
       .caption.grey--text.text--darken-1 Powered by Wiki.js
 </template>
 
@@ -96,7 +77,11 @@ const router = new VueRouter({
   routes: [
     { path: '/', redirect: '/dashboard' },
     { path: '/dashboard', component: () => import(/* webpackChunkName: "admin" */ './admin-dashboard.vue') },
-    { path: '/general', component: () => import(/* webpackChunkName: "admin" */ './admin-general.vue') }
+    { path: '/general', component: () => import(/* webpackChunkName: "admin" */ './admin-general.vue') },
+    { path: '/locale', component: () => import(/* webpackChunkName: "admin" */ './admin-locale.vue') },
+    { path: '/theme', component: () => import(/* webpackChunkName: "admin" */ './admin-theme.vue') },
+    { path: '/users', component: () => import(/* webpackChunkName: "admin" */ './admin-users.vue') },
+    { path: '/system', component: () => import(/* webpackChunkName: "admin" */ './admin-system.vue') }
   ]
 })
 
@@ -112,4 +97,17 @@ export default {
 
 <style lang='scss'>
 
+.admin-router {
+  &-enter-active, &-leave-active {
+    transition: opacity .25s ease;
+    opacity: 1;
+  }
+  &-enter-active {
+    transition-delay: .25s;
+  }
+  &-enter, &-leave-to {
+    opacity: 0;
+  }
+}
+
 </style>

+ 26 - 6
client/components/editor-code.vue

@@ -59,13 +59,17 @@
           svg.icons.is-18(role='img')
             title Horizontal Bar
             use(xlink:href='#fa-minus')
+
     .editor-code-main
       .editor-code-editor
-        .editor-code-editor-title Editor
+        .editor-code-editor-title(v-if='previewShown', @click='previewShown = false') Editor
+        .editor-code-editor-title(v-else='previewShown', @click='previewShown = true'): v-icon(dark) search
         codemirror(ref='cm', v-model='code', :options='cmOptions', @ready='onCmReady', @input='onCmInput')
-      .editor-code-preview
-        .editor-code-preview-title Preview
-        .editor-code-preview-content.markdown-content(ref='editorPreview', v-html='previewHTML')
+      transition(name='editor-code-preview')
+        .editor-code-preview(v-if='previewShown')
+          .editor-code-preview-title(@click='previewShown = false') Preview
+          .editor-code-preview-content.markdown-content(ref='editorPreview', v-html='previewHTML')
+
       v-speed-dial(v-model='fabInsertMenu', :open-on-hover='true', direction='top', transition='slide-y-reverse-transition', :fixed='true', :right='!isMobile', :left='isMobile', :bottom='true')
         v-btn(color='blue', fab, dark, v-model='fabInsertMenu', slot='activator')
           v-icon add_circle
@@ -196,6 +200,7 @@ export default {
         },
         viewportMargin: 50
       },
+      previewShown: true,
       previewHTML: ''
     }
   },
@@ -256,7 +261,7 @@ export default {
      * Update scroll sync
      */
     scrollSync: _.debounce(function (cm) {
-      if (cm.somethingSelected()) { return }
+      if (!this.previewShown || cm.somethingSelected()) { return }
       let currentLine = cm.getCursor().line
       if (currentLine < 3) {
         this.Velocity(this.$refs.editorPreview, 'stop', true)
@@ -306,6 +311,7 @@ export default {
       z-index: 7;
       text-transform: uppercase;
       font-size: .7rem;
+      cursor: pointer;
 
       @include until($tablet) {
         display: none;
@@ -324,6 +330,19 @@ export default {
       display: none;
     }
 
+    &-enter-active, &-leave-active {
+      transition: max-width .5s ease;
+      max-width: 50vw;
+
+      .editor-code-preview-content {
+        width: 50vw;
+        overflow:hidden;
+      }
+    }
+    &-enter, &-leave-to {
+      max-width: 0;
+    }
+
     &-content {
       height: calc(100vh - 100px);
       overflow-y: scroll;
@@ -352,6 +371,7 @@ export default {
       z-index: 2;
       text-transform: uppercase;
       font-size: .7rem;
+      cursor: pointer;
     }
   }
 
@@ -412,7 +432,7 @@ export default {
   // ==========================================
 
   .speed-dial--fixed {
-    z-index: 5;
+    z-index: 8;
   }
 
   // ==========================================

+ 36 - 0
client/components/nav-header.vue

@@ -0,0 +1,36 @@
+<template lang='pug'>
+  v-toolbar(color='black', dark, app, clipped-left, fixed, flat)
+    v-toolbar-side-icon(@click.native='')
+    v-toolbar-title
+      span.subheading Wiki.js
+    v-spacer
+    v-progress-circular.mr-3(indeterminate, color='blue')
+    v-btn(icon)
+      v-icon(color='grey') search
+    v-btn(icon, @click.native='darkTheme = !darkTheme')
+      v-icon(color='grey') settings
+    v-menu(offset-y, min-width='300')
+      v-btn(icon, slot='activator')
+        v-icon(color='grey') account_circle
+      v-list.py-0
+        v-list-tile.py-3(avatar)
+          v-list-tile-avatar
+            v-avatar.red(:size='40'): span.white--text.subheading JD
+          v-list-tile-content
+            v-list-tile-title John Doe
+            v-list-tile-sub-title john.doe@example.com
+        v-divider.my-0
+        v-list-tile(@click='')
+          v-list-tile-action: v-icon(color='red') exit_to_app
+          v-list-tile-title Logout
+</template>
+
+<script>
+export default {
+
+}
+</script>
+
+<style>
+
+</style>

+ 5 - 1
client/scss/base/icons.scss

@@ -32,4 +32,8 @@
     }
   }
 
-}
+}
+
+.material-design-icon {
+  display: inline-flex;
+}

+ 1 - 0
dev/webpack/webpack.common.js

@@ -234,6 +234,7 @@ module.exports = {
     alias: {
       '@': path.join(process.cwd(), 'client'),
       'vue$': 'vue/dist/vue.esm.js',
+      'mdi': path.resolve(process.cwd(), 'node_modules/vue-material-design-icons'),
       // Duplicates fixes:
       'apollo-link': path.join(process.cwd(), 'node_modules/apollo-link'),
       'apollo-utilities': path.join(process.cwd(), 'node_modules/apollo-utilities')

+ 1 - 0
package.json

@@ -201,6 +201,7 @@
     "vue-codemirror": "4.0.3",
     "vue-hot-reload-api": "2.2.4",
     "vue-loader": "14.1.1",
+    "vue-material-design-icons": "1.1.0",
     "vue-router": "3.0.1",
     "vue-simple-breakpoints": "1.0.3",
     "vue-template-compiler": "2.5.13",

+ 0 - 0
server/modules/search/algolia.js


+ 0 - 0
server/modules/search/db.js


+ 0 - 0
server/modules/search/elasticsearch.js


+ 0 - 0
server/modules/search/solr.js


+ 2 - 0
server/views/master.pug

@@ -24,6 +24,8 @@ html
     //- CSS
     link(type='text/css', rel='stylesheet', href=config.site.path + 'css/bundle.css')
     link(type='text/css', rel='stylesheet', href='https://fonts.googleapis.com/icon?family=Roboto:400,500,700|Source+Code+Pro:400,700|Material+Icons')
+    link(type='text/css', rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0/css/material-design-iconic-font.min.css')
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0/css/material-design-iconic-font.min.css" />
 
     //- JS
     script(type='text/javascript', src=config.site.path + 'js/runtime.js')

+ 4 - 0
yarn.lock

@@ -10412,6 +10412,10 @@ vue-loader@14.1.1:
     vue-style-loader "^4.0.1"
     vue-template-es2015-compiler "^1.6.0"
 
+vue-material-design-icons@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/vue-material-design-icons/-/vue-material-design-icons-1.1.0.tgz#1692bab1ddb2f16369bcb5f7344037fdc3a93d36"
+
 vue-router@3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.1.tgz#d9b05ad9c7420ba0f626d6500d693e60092cc1e9"