diff --git a/client/app.js b/client/app.js
index 8f8e7130..44f856b9 100644
--- a/client/app.js
+++ b/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'))
diff --git a/client/components/admin-general.vue b/client/components/admin-general.vue
index 90954d7e..9449bc84 100644
--- a/client/components/admin-general.vue
+++ b/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 ---
diff --git a/client/components/admin-locale.vue b/client/components/admin-locale.vue
new file mode 100644
index 00000000..0b410916
--- /dev/null
+++ b/client/components/admin-locale.vue
@@ -0,0 +1,84 @@
+
+ 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
+
+
+
+
+
diff --git a/client/components/admin-system.vue b/client/components/admin-system.vue
new file mode 100644
index 00000000..133b9b39
--- /dev/null
+++ b/client/components/admin-system.vue
@@ -0,0 +1,114 @@
+
+ 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
+
+
+
+
+
+
diff --git a/client/components/admin-theme.vue b/client/components/admin-theme.vue
new file mode 100644
index 00000000..26a9b02c
--- /dev/null
+++ b/client/components/admin-theme.vue
@@ -0,0 +1,49 @@
+
+ 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 & 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
+
+
+
+
+
diff --git a/client/components/admin-users.vue b/client/components/admin-users.vue
new file mode 100644
index 00000000..dc37be9b
--- /dev/null
+++ b/client/components/admin-users.vue
@@ -0,0 +1,76 @@
+
+ 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')
+
+
+
+
+
diff --git a/client/components/admin.vue b/client/components/admin.vue
index 81bad056..cc73c50f 100644
--- a/client/components/admin.vue
+++ b/client/components/admin.vue
@@ -1,29 +1,6 @@
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
@@ -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 {
diff --git a/client/components/editor-code.vue b/client/components/editor-code.vue
index e3911516..df3b2f7b 100644
--- a/client/components/editor-code.vue
+++ b/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;
}
// ==========================================
diff --git a/client/components/nav-header.vue b/client/components/nav-header.vue
new file mode 100644
index 00000000..3e21f7a2
--- /dev/null
+++ b/client/components/nav-header.vue
@@ -0,0 +1,36 @@
+
+ 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
+
+
+
+
+
diff --git a/client/scss/base/icons.scss b/client/scss/base/icons.scss
index 08736adc..5fe99c5a 100644
--- a/client/scss/base/icons.scss
+++ b/client/scss/base/icons.scss
@@ -32,4 +32,8 @@
}
}
-}
\ No newline at end of file
+}
+
+.material-design-icon {
+ display: inline-flex;
+}
diff --git a/dev/webpack/webpack.common.js b/dev/webpack/webpack.common.js
index 23593548..07aa27a4 100644
--- a/dev/webpack/webpack.common.js
+++ b/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')
diff --git a/package.json b/package.json
index 27f1d837..c5021e41 100644
--- a/package.json
+++ b/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",
diff --git a/server/modules/search/algolia.js b/server/modules/search/algolia.js
new file mode 100644
index 00000000..e69de29b
diff --git a/server/modules/search/db.js b/server/modules/search/db.js
new file mode 100644
index 00000000..e69de29b
diff --git a/server/modules/search/elasticsearch.js b/server/modules/search/elasticsearch.js
new file mode 100644
index 00000000..e69de29b
diff --git a/server/modules/search/solr.js b/server/modules/search/solr.js
new file mode 100644
index 00000000..e69de29b
diff --git a/server/views/master.pug b/server/views/master.pug
index feca4896..83a10716 100644
--- a/server/views/master.pug
+++ b/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')
+
//- JS
script(type='text/javascript', src=config.site.path + 'js/runtime.js')
diff --git a/yarn.lock b/yarn.lock
index f7ae887e..9d1879ee 100644
--- a/yarn.lock
+++ b/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"