Преглед на файлове

feat: content rendering improvements + save fix

Nicolas Giard преди 6 години
родител
ревизия
0b5a4e0c63

+ 10 - 3
client/client-app.js

@@ -161,14 +161,15 @@ Vue.component('admin', () => import(/* webpackChunkName: "admin" */ './component
 Vue.component('editor', () => import(/* webpackPrefetch: -100, webpackChunkName: "editor" */ './components/editor.vue'))
 Vue.component('history', () => import(/* webpackChunkName: "history" */ './components/history.vue'))
 Vue.component('login', () => import(/* webpackPrefetch: true, webpackChunkName: "login" */ './components/login.vue'))
-Vue.component('nav-footer', () => import(/* webpackMode: "eager" */ './components/common/nav-footer.vue'))
 Vue.component('nav-header', () => import(/* webpackMode: "eager" */ './components/common/nav-header.vue'))
-Vue.component('nav-sidebar', () => import(/* webpackMode: "eager" */ './components/common/nav-sidebar.vue'))
-Vue.component('page', () => import(/* webpackChunkName: "theme-page" */ './themes/' + process.env.CURRENT_THEME + '/components/app.vue'))
 Vue.component('page-selector', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/page-selector.vue'))
 Vue.component('profile', () => import(/* webpackChunkName: "profile" */ './components/profile.vue'))
 Vue.component('v-card-chin', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-chin.vue'))
 
+Vue.component('nav-footer', () => import(/* webpackChunkName: "theme-page"  */ './themes/' + process.env.CURRENT_THEME + '/components/nav-footer.vue'))
+Vue.component('nav-sidebar', () => import(/* webpackChunkName: "theme-page" */ './themes/' + process.env.CURRENT_THEME + '/components/nav-sidebar.vue'))
+Vue.component('page', () => import(/* webpackChunkName: "theme-page" */ './themes/' + process.env.CURRENT_THEME + '/components/page.vue'))
+
 let bootstrap = () => {
   // ====================================
   // Notifications
@@ -202,6 +203,12 @@ let bootstrap = () => {
 
   window.boot.notify('vue')
 
+  // ====================================
+  // Load theme-specific code
+  // ====================================
+
+  import(/* webpackChunkName: "theme-page"  */ './themes/' + process.env.CURRENT_THEME + '/js/app.js')
+
   // ====================================
   // Load Icons
   // ====================================

+ 4 - 3
client/components/common/nav-header.vue

@@ -17,7 +17,7 @@
         @keyup.enter='searchEnter'
       )
     v-menu(open-on-hover, offset-y, bottom, left, min-width='250')
-      v-toolbar-side-icon(slot='activator')
+      v-toolbar-side-icon.btn-animate-app(slot='activator')
         v-icon view_module
       v-list(dense, :light='!$vuetify.dark').py-0
         v-list-tile(avatar, href='/')
@@ -84,12 +84,12 @@
       )
       v-icon(color='grey') search
     v-tooltip(bottom)
-      v-btn(icon, href='/a', slot='activator')
+      v-btn.btn-animate-rotate(icon, href='/a', slot='activator')
         v-icon(color='grey') settings
       span Admin
     v-menu(offset-y, min-width='300')
       v-tooltip(bottom, slot='activator')
-        v-btn(icon, slot='activator')
+        v-btn.btn-animate-grow(icon, slot='activator', outline, color='grey darken-3')
           v-icon(color='grey') account_circle
         span Account
       v-list.py-0(:light='!$vuetify.dark')
@@ -212,4 +212,5 @@ export default {
 .navHeaderLoading { // To avoid search bar jumping
   width: 22px;
 }
+
 </style>

+ 22 - 17
client/components/editor.vue

@@ -142,6 +142,10 @@ export default {
     initContent: {
       type: String,
       default: null
+    },
+    pageId: {
+      type: Number,
+      default: 0
     }
   },
   data() {
@@ -158,6 +162,7 @@ export default {
     notificationState: sync('notification@isActive')
   },
   created() {
+    this.$store.commit('page/SET_ID', this.pageId)
     this.$store.commit('page/SET_DESCRIPTION', this.description)
     this.$store.commit('page/SET_IS_PUBLISHED', this.isPublished)
     this.$store.commit('page/SET_LOCALE', this.locale)
@@ -212,16 +217,16 @@ export default {
             mutation: createPageMutation,
             variables: {
               content: this.$store.get('editor/content'),
-              description: this.$store.get('editor/description'),
+              description: this.$store.get('page/description'),
               editor: 'markdown',
-              locale: this.$store.get('editor/locale'),
+              locale: this.$store.get('page/locale'),
               isPrivate: false,
-              isPublished: this.$store.get('editor/isPublished'),
-              path: this.$store.get('editor/path'),
-              publishEndDate: this.$store.get('editor/publishEndDate'),
-              publishStartDate: this.$store.get('editor/publishStartDate'),
-              tags: this.$store.get('editor/tags'),
-              title: this.$store.get('editor/title')
+              isPublished: this.$store.get('page/isPublished'),
+              path: this.$store.get('page/path'),
+              publishEndDate: this.$store.get('page/publishEndDate'),
+              publishStartDate: this.$store.get('page/publishStartDate'),
+              tags: this.$store.get('page/tags'),
+              title: this.$store.get('page/title')
             }
           })
           resp = _.get(resp, 'data.pages.create', {})
@@ -244,18 +249,18 @@ export default {
           let resp = await this.$apollo.mutate({
             mutation: updatePageMutation,
             variables: {
-              id: this.$store.get('editor/id'),
+              id: this.$store.get('page/id'),
               content: this.$store.get('editor/content'),
-              description: this.$store.get('editor/description'),
+              description: this.$store.get('page/description'),
               editor: 'markdown',
-              locale: this.$store.get('editor/locale'),
+              locale: this.$store.get('page/locale'),
               isPrivate: false,
-              isPublished: this.$store.get('editor/isPublished'),
-              path: this.$store.get('editor/path'),
-              publishEndDate: this.$store.get('editor/publishEndDate'),
-              publishStartDate: this.$store.get('editor/publishStartDate'),
-              tags: this.$store.get('editor/tags'),
-              title: this.$store.get('editor/title')
+              isPublished: this.$store.get('page/isPublished'),
+              path: this.$store.get('page/path'),
+              publishEndDate: this.$store.get('page/publishEndDate'),
+              publishStartDate: this.$store.get('page/publishStartDate'),
+              tags: this.$store.get('page/tags'),
+              title: this.$store.get('page/title')
             }
           })
           resp = _.get(resp, 'data.pages.update', {})

+ 4 - 4
client/components/editor/editor-markdown.vue

@@ -206,7 +206,7 @@ export default {
         self.$parent.save()
       })
 
-      cm.setSize(null, 'calc(100vh - 100px)')
+      cm.setSize(null, 'calc(100vh - 112px)')
       cm.setOption('extraKeys', keyBindings)
       cm.on('cursorActivity', cm => {
         this.toolbarSync(cm)
@@ -270,7 +270,7 @@ export default {
     background-color: darken(mc('grey', '900'), 4.5%);
     flex: 1 1 50%;
     display: block;
-    height: calc(100vh - 96px);
+    height: calc(100vh - 112px);
     position: relative;
 
     &-title {
@@ -300,7 +300,7 @@ export default {
     flex: 1 1 50%;
     background-color: mc('grey', '100');
     position: relative;
-    height: calc(100vh - 100px);
+    height: calc(100vh - 112px);
     overflow: hidden;
 
     @include until($tablet) {
@@ -321,7 +321,7 @@ export default {
     }
 
     &-content {
-      height: calc(100vh - 100px);
+      height: calc(100vh - 112px);
       overflow-y: scroll;
       padding: 30px 1rem 1rem 1rem;
       width: calc(100% + 1rem + 17px)

+ 8 - 8
client/components/editor/editor-modal-properties.vue

@@ -207,14 +207,14 @@ export default {
   },
   computed: {
     mode: get('editor/mode'),
-    title: sync('editor/title'),
-    description: sync('editor/description'),
-    locale: sync('editor/locale'),
-    tags: sync('editor/tags'),
-    path: sync('editor/path'),
-    isPublished: sync('editor/isPublished'),
-    publishStartDate: sync('editor/publishStartDate'),
-    publishEndDate: sync('editor/publishEndDate')
+    title: sync('page/title'),
+    description: sync('page/description'),
+    locale: sync('page/locale'),
+    tags: sync('page/tags'),
+    path: sync('page/path'),
+    isPublished: sync('page/isPublished'),
+    publishStartDate: sync('page/publishStartDate'),
+    publishEndDate: sync('page/publishEndDate')
   },
   mounted() {
     this.isShown = true

+ 41 - 0
client/scss/components/v-btn.scss

@@ -1,3 +1,44 @@
 .v-btn.is-icon {
   min-width: auto;
 }
+
+.btn-animate-rotate {
+  i {
+    transition: all 4s ease;
+    transform: rotate(0deg);
+  }
+  &:hover i {
+    transform: rotate(360deg);
+  }
+}
+
+.btn-animate-grow {
+  i {
+    transition: all 2s ease;
+    transform: scale(1);
+  }
+  &:hover i {
+    transform: scale(1.25);
+  }
+}
+
+.btn-animate-edit {
+  i {
+    transition: all .7s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+    transform: rotate(0deg);
+  }
+  &:hover i {
+    transform: rotate(-45deg);
+  }
+}
+
+.btn-animate-app {
+  i {
+    transition: all .6s ease;
+    transform: translate3d(0,0,0);
+    transform-style: preserve-3d;
+  }
+  &:hover i {
+    transform: scale(.7) rotateX(-180deg);
+  }
+}

+ 1 - 10
client/store/editor.js

@@ -1,17 +1,8 @@
 import { make } from 'vuex-pathify'
 
 const state = {
-  id: 0,
   content: '',
-  description: '',
-  isPublished: true,
-  locale: 'en',
-  mode: 'create',
-  path: '',
-  publishEndDate: '',
-  publishStartDate: '',
-  tags: [],
-  title: ''
+  mode: 'create'
 }
 
 export default {

+ 0 - 0
client/components/common/nav-footer.vue → client/themes/default/components/nav-footer.vue


+ 0 - 0
client/components/common/nav-sidebar.vue → client/themes/default/components/nav-sidebar.vue


+ 1 - 1
client/themes/default/components/app.vue → client/themes/default/components/page.vue

@@ -47,7 +47,7 @@
               .caption.grey--text.text--darken-1 {{ updatedAt | moment('calendar') }}
             v-spacer
             v-tooltip(left)
-              v-btn(icon, slot='activator', :href='"/e/" + path')
+              v-btn.btn-animate-edit(icon, slot='activator', :href='"/e/" + path')
                 v-icon(color='grey') edit
               span Edit Page
           v-divider

+ 16 - 1
client/themes/default/scss/app.scss

@@ -87,16 +87,28 @@
   }
 
   code {
-    background-color: transparent;
+    background-color: rgba(mc('pink', '500'), .1);
+    padding: 0 5px;
+    color: mc('pink', '800');
     font-family: 'Source Code Pro', monospace;
     font-weight: normal;
     font-size: 1rem;
+    box-shadow: none;
 
     &::before, &::after {
       display: none;
     }
   }
 
+  ol, ul {
+    padding: 1rem 24px 0 24px;
+    list-style-position: inside;
+
+    li + li {
+      margin-top: .5rem;
+    }
+  }
+
   .prismjs{
     border: none;
     border-radius: 5px;
@@ -106,6 +118,9 @@
     margin: 1rem 24px;
 
     > code {
+      background-color: transparent;
+      padding: 0;
+      color: #FFF;
       box-shadow: initial;
       display: block;
       font-size: .85rem;

+ 9 - 0
server/core/db.js

@@ -37,6 +37,15 @@ module.exports = {
       case 'mariadb':
       case 'mysql':
         dbClient = 'mysql2'
+
+        // Fix mysql boolean handling...
+        dbConfig.typeCast = (field, next) => {
+          if (field.type === 'TINY' && field.length === 1) {
+            let value = field.string()
+            return value ? (value === '1') : null
+          }
+          return next()
+        }
         break
       case 'mssql':
         dbClient = 'mssql'

+ 5 - 0
server/graph/resolvers/system.js

@@ -4,6 +4,7 @@ const getos = Promise.promisify(require('getos'))
 const os = require('os')
 const filesize = require('filesize')
 const path = require('path')
+const fs = require('fs-extra')
 
 /* global WIKI */
 
@@ -76,6 +77,10 @@ module.exports = {
         const osInfo = await getos()
         osLabel = `${os.type()} - ${osInfo.dist} (${osInfo.codename || os.platform()}) ${osInfo.release || os.release()} ${os.arch()}`
       }
+      const isDockerized = await fs.pathExists('/.dockerenv')
+      if (isDockerized) {
+        osLabel = `${osLabel} (Docker Container)`
+      }
       return osLabel
     },
     hostname() {

+ 2 - 0
server/models/pageHistory.js

@@ -23,6 +23,7 @@ module.exports = class PageHistory extends Model {
         publishStartDate: {type: 'string'},
         publishEndDate: {type: 'string'},
         content: {type: 'string'},
+        contentType: {type: 'string'},
 
         createdAt: {type: 'string'}
       }
@@ -87,6 +88,7 @@ module.exports = class PageHistory extends Model {
       pageId: opts.id,
       authorId: opts.authorId,
       content: opts.content,
+      contentType: opts.contentType,
       description: opts.description,
       editorKey: opts.editorKey,
       hash: opts.hash,

+ 1 - 0
server/views/editor.pug

@@ -4,6 +4,7 @@ block body
   #root
     v-app
       editor(
+        :page-id=page.id
         locale=page.localeCode
         path=page.path
         title=page.title

+ 1 - 1
server/views/page.pug

@@ -14,6 +14,6 @@ block body
       updated-at=page.updatedAt
       author-name=page.authorName
       :author-id=page.authorId
-      is-published=page.isPublished
+      :is-published=page.isPublished
       )
       template(slot='contents')!= page.render