ソースを参照

feat: markdown rendering

Nicolas Giard 6 年 前
コミット
076aeaf749

+ 4 - 0
client/components/editor.vue

@@ -22,6 +22,7 @@
           outline
           color='red'
           :class='{ "is-icon": $vuetify.breakpoint.mdAndDown }'
+          @click.native.stop='exit'
           )
           v-icon(color='red', :left='$vuetify.breakpoint.lgAndUp') close
           span.white--text(v-if='$vuetify.breakpoint.lgAndUp') {{ $t('common:actions.discard') }}
@@ -285,6 +286,9 @@ export default {
         })
       }
       this.hideProgressDialog()
+    },
+    exit() {
+
     }
   }
 }

+ 5 - 3
client/components/editor/editor-markdown.vue

@@ -58,7 +58,7 @@
       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')
+          .editor-code-preview-content.contents(ref='editorPreview', v-html='previewHTML')
 
       v-speed-dial(v-model='fabInsertMenu', :open-on-hover='true', direction='top', transition='slide-y-reverse-transition', fixed, left, bottom)
         v-btn(color='blue', fab, dark, v-model='fabInsertMenu', slot='activator')
@@ -97,6 +97,7 @@ import 'codemirror/addon/search/match-highlighter.js'
 
 // Markdown-it
 import MarkdownIt from 'markdown-it'
+import mdAttrs from 'markdown-it-attrs'
 import mdEmoji from 'markdown-it-emoji'
 import mdTaskLists from 'markdown-it-task-lists'
 import mdExpandTabs from 'markdown-it-expand-tabs'
@@ -126,8 +127,9 @@ const md = new MarkdownIt({
     return `<pre class="line-numbers"><code class="language-${lang}">${str}</code></pre>`
   }
 })
+  .use(mdAttrs)
   .use(mdEmoji)
-  .use(mdTaskLists)
+  .use(mdTaskLists, {label: true, labelAfter: true})
   .use(mdExpandTabs)
   .use(mdAbbr)
   .use(mdSup)
@@ -323,7 +325,7 @@ export default {
     &-content {
       height: calc(100vh - 112px);
       overflow-y: scroll;
-      padding: 30px 1rem 1rem 1rem;
+      padding: 1rem 1rem 1rem 0;
       width: calc(100% + 1rem + 17px)
       // -ms-overflow-style: none;
 

+ 0 - 1
client/scss/app.scss

@@ -6,7 +6,6 @@
 @import "../libs/animate/animate";
 @import '~vue2-animate/src/sass/vue2-animate';
 
-@import 'components/markdown-content';
 @import 'components/v-btn';
 @import 'components/v-data-table';
 @import 'components/v-dialog';

+ 0 - 100
client/scss/components/markdown-content.scss

@@ -1,100 +0,0 @@
-.markdown-content {
-  font-size: 1rem;
-  color: mc('blue-grey', '800');
-
-  // --------------------------------------------
-  // Headers
-  // --------------------------------------------
-
-  h1, h2, h3, h4, h5, h6 {
-    color: mc('blue-grey', '700');
-    font-weight: 500;
-  }
-
-  > * + h1, > * + h2, > * + h3, > * + h4 {
-    margin-top: 3rem;
-  }
-  h1 {
-    font-size: 1.5rem;
-    border-bottom: 2px solid mc('blue-grey', '100');
-    margin-bottom: 1rem;
-  }
-  h2 {
-    font-size: 1.25rem;
-    border-bottom: 1px solid mc('blue-grey', '100');
-    margin-bottom: .75rem;
-  }
-  h3 {
-    font-size: 1.15rem;
-    border-bottom: 1px dotted mc('blue-grey', '100');
-    margin-bottom: .5rem;
-    color: mc('blue-grey', '500');
-  }
-  h4 {
-    font-size: 1.1rem;
-  }
-  h5 {
-    font-size: 1.05rem;
-  }
-  h6 {
-    font-size: 1.025rem;
-  }
-
-  // --------------------------------------------
-  // Paragraphs
-  // --------------------------------------------
-  p + p {
-    margin-top: 1rem;
-  }
-
-  // --------------------------------------------
-  // Lists
-  // --------------------------------------------
-  ul, ol {
-    & + p {
-      margin-top: .5rem;
-    }
-  }
-
-  ul {
-    list-style-type: square;
-    list-style-position: inside;
-  }
-
-  ol {
-    list-style-type: decimal;
-    list-style-position: inside;
-  }
-
-  // --------------------------------------------
-  // Code Blocks
-  // --------------------------------------------
-  > pre {
-    border: none;
-    border-radius: 5px;
-    box-shadow: initial;
-    background-color: mc('blue-grey', '900');
-    padding: 1rem 1rem 1rem 3rem;
-
-    > code {
-      box-shadow: initial;
-      display: block;
-      font-size: .85rem;
-      font-family: 'Source Code Pro', monospace;
-
-      &:after, &:before {
-        content: initial;
-        letter-spacing: initial;
-      }
-    }
-  }
-
-  .task-list-item {
-    display: flex;
-    align-items: center;
-
-    &-checkbox {
-      margin-right: .5rem;
-    }
-  }
-}

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

@@ -4,6 +4,10 @@
   color: mc('grey', '800');
   padding-bottom: 50px;
 
+  // ---------------------------------
+  // HEADERS
+  // ---------------------------------
+
   h1, h2, h3, h4, h5, h6 {
     position: relative;
 
@@ -81,14 +85,74 @@
     }
   }
 
+  // ---------------------------------
+  // PARAGRAPHS
+  // ---------------------------------
+
   p {
     padding: 1rem 24px 0 24px;
     margin: 0;
     text-align: justify;
   }
 
+  blockquote {
+    padding: 0 0 1rem 0;
+    border: 1px solid mc('blue', '500');
+    border-radius: .5rem;
+    margin: 1rem;
+
+    &.is-info {
+      background-color: mc('blue', '50');
+      background-image: radial-gradient(ellipse at top, mc('blue', '50'), lighten(mc('blue', '50'), 5%));
+      border-color: mc('blue', '100');
+      box-shadow: 0 0 2px 0 mc('blue', '100');
+
+      code {
+        background-color: mc('blue', '50');
+        color: mc('blue', '800');
+      }
+    }
+    &.is-warning {
+      background-color: mc('orange', '50');
+      background-image: radial-gradient(ellipse at top, mc('orange', '50'), lighten(mc('orange', '50'), 5%));
+      border-color: mc('orange', '100');
+      box-shadow: 0 0 2px 0 mc('orange', '100');
+
+      code {
+        background-color: mc('orange', '50');
+        color: mc('orange', '800');
+      }
+    }
+    &.is-danger {
+      background-color: mc('red', '50');
+      background-image: radial-gradient(ellipse at top, mc('red', '50'), lighten(mc('red', '50'), 5%));
+      border-color: mc('red', '100');
+      box-shadow: 0 0 2px 0 mc('red', '100');
+
+      code {
+        background-color: mc('red', '50');
+        color: mc('red', '800');
+      }
+    }
+    &.is-success {
+      background-color: mc('green', '50');
+      background-image: radial-gradient(ellipse at top, mc('green', '50'), lighten(mc('green', '50'), 5%));
+      border-color: mc('green', '100');
+      box-shadow: 0 0 2px 0 mc('green', '100');
+
+      code {
+        background-color: mc('green', '50');
+        color: mc('green', '800');
+      }
+    }
+  }
+
+  // ---------------------------------
+  // CODE
+  // ---------------------------------
+
   code {
-    background-color: rgba(mc('indigo', '50'), 1);
+    background-color: mc('indigo', '50');
     padding: 0 5px;
     color: mc('indigo', '800');
     font-family: 'Source Code Pro', monospace;
@@ -134,4 +198,41 @@
     }
   }
 
+  // ---------------------------------
+  // TASK LISTS
+  // ---------------------------------
+
+  .task-list-item {
+    position: relative;
+
+    &-checkbox[disabled] {
+      display: none;
+
+      & + label {
+        padding-left: 1.4rem;
+      }
+
+      & + label::before {
+        position: absolute;
+        left: 1rem;
+        top: 2px;
+        content: ' ';
+        display: block;
+        width: 1.1rem;
+        height: 1.1rem;
+        background-color: #FFF;
+        border: 1px solid mc('grey', '400');
+        border-radius: 2px;
+        font-weight: bold;
+        font-size: .8rem;
+        line-height: 1rem;
+        text-align: center;
+      }
+
+      &[checked] + label::before  {
+        content: '✓';
+      }
+    }
+  }
+
 }

+ 3 - 0
server/modules/rendering/markdown-core/renderer.js

@@ -1,5 +1,6 @@
 const md = require('markdown-it')
 const mdAnchor = require('markdown-it-anchor')
+const mdAttrs = require('markdown-it-attrs')
 const _ = require('lodash')
 const uslug = require('uslug')
 
@@ -39,6 +40,8 @@ module.exports = {
       permalinkBefore: true
     })
 
+    mkdown.use(mdAttrs)
+
     for (let child of this.children) {
       const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
       renderer.init(mkdown, child.config)

+ 1 - 1
server/modules/rendering/markdown-tasklists/renderer.js

@@ -6,6 +6,6 @@ const mdTaskLists = require('markdown-it-task-lists')
 
 module.exports = {
   init (md, conf) {
-    md.use(mdTaskLists)
+    md.use(mdTaskLists, {label: true, labelAfter: true})
   }
 }