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

This commit is contained in:
NGPixel 2018-03-03 01:32:58 -05:00
parent 0ccdf10c9d
commit 1ae47dde2e
18 changed files with 436 additions and 41 deletions

View File

@ -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'))

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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;
}
// ==========================================

View File

@ -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>

View File

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

View File

@ -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')

View File

@ -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",

View File

View File

View File

View File

View File

@ -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')

View File

@ -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"