feat: editor props scripts + styles code editor

This commit is contained in:
NGPixel 2020-06-19 21:00:44 -04:00
parent 0a16929a57
commit 718c14dd74
7 changed files with 197 additions and 121 deletions

View File

@ -203,7 +203,7 @@ export default {
this.checkoutDateActive = this.checkoutDate this.checkoutDateActive = this.checkoutDate
if (this.effectivePermissions) { if (this.effectivePermissions) {
this.$store.set('page/effectivePermissions',JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString())) this.$store.set('page/effectivePermissions', JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString()))
} }
}, },
mounted() { mounted() {

View File

@ -936,86 +936,6 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
.CodeMirror-selection-highlight-scrollbar { .CodeMirror-selection-highlight-scrollbar {
background-color: mc('green', '600'); background-color: mc('green', '600');
} }
.cm-s-wikijs-dark.CodeMirror {
background: darken(mc('grey','900'), 3%);
color: #e0e0e0;
}
.cm-s-wikijs-dark div.CodeMirror-selected {
background: mc('blue','800');
}
.cm-s-wikijs-dark .cm-matchhighlight {
background: mc('blue','800');
}
.cm-s-wikijs-dark .CodeMirror-line::selection, .cm-s-wikijs-dark .CodeMirror-line > span::selection, .cm-s-wikijs-dark .CodeMirror-line > span > span::selection {
background: mc('amber', '500');
}
.cm-s-wikijs-dark .CodeMirror-line::-moz-selection, .cm-s-wikijs-dark .CodeMirror-line > span::-moz-selection, .cm-s-wikijs-dark .CodeMirror-line > span > span::-moz-selection {
background: mc('amber', '500');
}
.cm-s-wikijs-dark .CodeMirror-gutters {
background: darken(mc('grey','900'), 6%);
border-right: 1px solid mc('grey','900');
}
.cm-s-wikijs-dark .CodeMirror-guttermarker {
color: #ac4142;
}
.cm-s-wikijs-dark .CodeMirror-guttermarker-subtle {
color: #505050;
}
.cm-s-wikijs-dark .CodeMirror-linenumber {
color: mc('grey','800');
}
.cm-s-wikijs-dark .CodeMirror-cursor {
border-left: 1px solid #b0b0b0;
}
.cm-s-wikijs-dark span.cm-comment {
color: mc('orange','800');
}
.cm-s-wikijs-dark span.cm-atom {
color: #aa759f;
}
.cm-s-wikijs-dark span.cm-number {
color: #aa759f;
}
.cm-s-wikijs-dark span.cm-property, .cm-s-wikijs-dark span.cm-attribute {
color: #90a959;
}
.cm-s-wikijs-dark span.cm-keyword {
color: #ac4142;
}
.cm-s-wikijs-dark span.cm-string {
color: #f4bf75;
}
.cm-s-wikijs-dark span.cm-variable {
color: #90a959;
}
.cm-s-wikijs-dark span.cm-variable-2 {
color: #6a9fb5;
}
.cm-s-wikijs-dark span.cm-def {
color: #d28445;
}
.cm-s-wikijs-dark span.cm-bracket {
color: #e0e0e0;
}
.cm-s-wikijs-dark span.cm-tag {
color: #ac4142;
}
.cm-s-wikijs-dark span.cm-link {
color: #aa759f;
}
.cm-s-wikijs-dark span.cm-error {
background: #ac4142;
color: #b0b0b0;
}
.cm-s-wikijs-dark .CodeMirror-activeline-background {
background: mc('grey','900');
}
.cm-s-wikijs-dark .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}
} }
// HINT DROPDOWN // HINT DROPDOWN

View File

@ -17,12 +17,13 @@
v-icon(left) mdi-check v-icon(left) mdi-check
span {{ $t('common:actions.ok') }} span {{ $t('common:actions.ok') }}
v-card(tile) v-card(tile)
v-tabs(color='white', background-color='blue darken-1', dark, centered) v-tabs(color='white', background-color='blue darken-1', dark, centered, v-model='currentTab')
v-tab {{$t('editor:props.info')}} v-tab {{$t('editor:props.info')}}
v-tab {{$t('editor:props.scheduling')}} v-tab {{$t('editor:props.scheduling')}}
v-tab(disabled) {{$t('editor:props.scripts')}} v-tab(:disabled='!hasScriptPermission') {{$t('editor:props.scripts')}}
v-tab {{$t('editor:props.social')}} v-tab {{$t('editor:props.social')}}
v-tab-item v-tab(:disabled='!hasStylePermission') {{$t('editor:props.styles')}}
v-tab-item(transition='fade-transition', reverse-transition='fade-transition')
v-card-text.pt-5 v-card-text.pt-5
.overline.pb-5 {{$t('editor:props.pageInfo')}} .overline.pb-5 {{$t('editor:props.pageInfo')}}
v-text-field( v-text-field(
@ -88,16 +89,15 @@
hide-no-data hide-no-data
:search-input.sync='newTagSearch' :search-input.sync='newTagSearch'
) )
v-tab-item v-tab-item(transition='fade-transition', reverse-transition='fade-transition')
v-card-text v-card-text
.overline.pb-5 {{$t('editor:props.publishState')}} #[v-chip.ml-3(label, color='grey', small, outlined).white--text coming soon] .overline {{$t('editor:props.publishState')}}
v-switch( v-switch(
:label='$t(`editor:props.publishToggle`)' :label='$t(`editor:props.publishToggle`)'
v-model='isPublished' v-model='isPublished'
color='primary' color='primary'
:hint='$t(`editor:props.publishToggleHint`)' :hint='$t(`editor:props.publishToggleHint`)'
persistent-hint persistent-hint
disabled
inset inset
) )
v-divider v-divider
@ -111,7 +111,7 @@
v-model='isPublishStartShown' v-model='isPublishStartShown'
:return-value.sync='publishStartDate' :return-value.sync='publishStartDate'
width='460px' width='460px'
:disabled='!isPublished || true' :disabled='!isPublished'
) )
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-text-field( v-text-field(
@ -124,7 +124,7 @@
clearable clearable
:hint='$t(`editor:props.publishStartHint`)' :hint='$t(`editor:props.publishStartHint`)'
persistent-hint persistent-hint
:disabled='!isPublished || true' :disabled='!isPublished'
) )
v-date-picker( v-date-picker(
v-model='publishStartDate' v-model='publishStartDate'
@ -152,7 +152,7 @@
v-model='isPublishEndShown' v-model='isPublishEndShown'
:return-value.sync='publishEndDate' :return-value.sync='publishEndDate'
width='460px' width='460px'
:disabled='!isPublished || true' :disabled='!isPublished'
) )
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-text-field( v-text-field(
@ -165,7 +165,7 @@
clearable clearable
:hint='$t(`editor:props.publishEndHint`)' :hint='$t(`editor:props.publishEndHint`)'
persistent-hint persistent-hint
:disabled='!isPublished || true' :disabled='!isPublished'
) )
v-date-picker( v-date-picker(
v-model='publishEndDate' v-model='publishEndDate'
@ -187,35 +187,21 @@
@click='$refs.menuPublishEnd.save(publishEndDate)' @click='$refs.menuPublishEnd.save(publishEndDate)'
) {{$t('common:actions.ok')}} ) {{$t('common:actions.ok')}}
v-tab-item v-tab-item(:transition='false', :reverse-transition='false')
v-card-text .editor-props-codeeditor
.overline.pb-3 {{$t('editor:props.js')}} textarea(ref='codejs')
v-textarea( .editor-props-codeeditor-hint
outlined .caption {{$t('editor:props.jsHint')}}
rows='5'
:hint='$t(`editor:props.jsHint`)'
persistent-hint
)
v-divider
v-card-text.grey.pt-5(:class='$vuetify.theme.dark ? `darken-3-d3` : `lighten-5`')
.overline.pb-3 {{$t('editor:props.css')}}
v-textarea(
outlined
rows='5'
:hint='$t(`editor:props.cssHint`)'
persistent-hint
)
v-tab-item v-tab-item(transition='fade-transition', reverse-transition='fade-transition')
v-card-text v-card-text
.overline.pb-5 {{$t('editor:props.socialFeatures')}} #[v-chip.ml-3(label, color='grey', small, outlined).white--text coming soon] .overline {{$t('editor:props.socialFeatures')}}
v-switch( v-switch(
:label='$t(`editor:props.allowComments`)' :label='$t(`editor:props.allowComments`)'
v-model='isPublished' v-model='isPublished'
color='primary' color='primary'
:hint='$t(`editor:props.allowCommentsHint`)' :hint='$t(`editor:props.allowCommentsHint`)'
persistent-hint persistent-hint
disabled
inset inset
) )
v-switch( v-switch(
@ -233,7 +219,6 @@
color='primary' color='primary'
:hint='$t(`editor:props.displayAuthorHint`)' :hint='$t(`editor:props.displayAuthorHint`)'
persistent-hint persistent-hint
disabled
inset inset
) )
v-switch( v-switch(
@ -242,10 +227,15 @@
color='primary' color='primary'
:hint='$t(`editor:props.displaySharingBarHint`)' :hint='$t(`editor:props.displaySharingBarHint`)'
persistent-hint persistent-hint
disabled
inset inset
) )
v-tab-item(:transition='false', :reverse-transition='false')
.editor-props-codeeditor
textarea(ref='codecss')
.editor-props-codeeditor-hint
.caption {{$t('editor:props.cssHint')}}
page-selector(:mode='pageSelectorMode', v-model='pageSelectorShown', :path='path', :locale='locale', :open-handler='setPath') page-selector(:mode='pageSelectorMode', v-model='pageSelectorShown', :path='path', :locale='locale', :open-handler='setPath')
</template> </template>
@ -254,6 +244,11 @@ import _ from 'lodash'
import { sync, get } from 'vuex-pathify' import { sync, get } from 'vuex-pathify'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import CodeMirror from 'codemirror'
import 'codemirror/lib/codemirror.css'
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/mode/css/css.js'
/* global siteLangs, siteConfig */ /* global siteLangs, siteConfig */
export default { export default {
@ -263,7 +258,7 @@ export default {
default: false default: false
} }
}, },
data() { data () {
return { return {
isPublishStartShown: false, isPublishStartShown: false,
isPublishEndShown: false, isPublishEndShown: false,
@ -271,7 +266,9 @@ export default {
namespaces: siteLangs.length ? siteLangs.map(ns => ns.code) : [siteConfig.lang], namespaces: siteLangs.length ? siteLangs.map(ns => ns.code) : [siteConfig.lang],
newTag: '', newTag: '',
newTagSuggestions: [], newTagSuggestions: [],
newTagSearch: '' newTagSearch: '',
currentTab: 0,
cm: null
} }
}, },
computed: { computed: {
@ -288,20 +285,23 @@ export default {
isPublished: sync('page/isPublished'), isPublished: sync('page/isPublished'),
publishStartDate: sync('page/publishStartDate'), publishStartDate: sync('page/publishStartDate'),
publishEndDate: sync('page/publishEndDate'), publishEndDate: sync('page/publishEndDate'),
scriptJs: sync('page/scriptJs'),
scriptCss: sync('page/scriptCss'),
hasScriptPermission: get('page/effectivePermissions@pages.script'),
hasStylePermission: get('page/effectivePermissions@pages.style'),
pageSelectorMode () { pageSelectorMode () {
return (this.mode === 'create') ? 'create' : 'move' return (this.mode === 'create') ? 'create' : 'move'
} }
}, },
watch: { watch: {
value(newValue, oldValue) { value (newValue, oldValue) {
if (newValue) { if (newValue) {
_.delay(() => { _.delay(() => {
this.$refs.iptTitle.focus() this.$refs.iptTitle.focus()
// this.$tours['editorPropertiesTour'].start()
}, 500) }, 500)
} }
}, },
newTag(newValue, oldValue) { newTag (newValue, oldValue) {
const tagClean = _.trim(newValue || '').toLowerCase() const tagClean = _.trim(newValue || '').toLowerCase()
if (tagClean && tagClean.length > 0) { if (tagClean && tagClean.length > 0) {
if (!_.includes(this.tags, tagClean)) { if (!_.includes(this.tags, tagClean)) {
@ -311,6 +311,24 @@ export default {
this.newTag = null this.newTag = null
}) })
} }
},
currentTab (newValue, oldValue) {
if (this.cm) {
this.cm.toTextArea()
}
if (newValue === 2) {
this.$nextTick(() => {
setTimeout(() => {
this.loadEditor(this.$refs.codejs, 'javascript')
}, 100)
})
} else if (newValue === 4) {
this.$nextTick(() => {
setTimeout(() => {
this.loadEditor(this.$refs.codecss, 'css')
}, 100)
})
}
} }
}, },
methods: { methods: {
@ -326,6 +344,42 @@ export default {
setPath({ path, locale }) { setPath({ path, locale }) {
this.locale = locale this.locale = locale
this.path = path this.path = path
},
loadEditor(ref, mode) {
this.cm = CodeMirror.fromTextArea(ref, {
tabSize: 2,
mode: `text/${mode}`,
theme: 'wikijs-dark',
lineNumbers: true,
lineWrapping: true,
line: true,
styleActiveLine: true,
viewportMargin: 50,
inputStyle: 'contenteditable',
direction: 'ltr'
})
switch (mode) {
case 'javascript':
this.cm.setValue(this.scriptJs)
this.cm.on('change', c => {
this.scriptJs = c.getValue()
})
break
case 'css':
this.cm.setValue(this.scriptCss)
this.cm.on('change', c => {
this.scriptCss = c.getValue()
})
break
default:
console.warn('Invalid Editor Mode')
break
}
this.cm.setSize(null, '500px')
this.$nextTick(() => {
this.cm.refresh()
this.cm.focus()
})
} }
}, },
apollo: { apollo: {
@ -355,4 +409,20 @@ export default {
<style lang='scss'> <style lang='scss'>
.editor-props-codeeditor {
background-color: mc('grey', '900');
min-height: 500px;
> textarea {
visibility: hidden;
}
&-hint {
background-color: mc('grey', '900');
border-top: 1px solid lighten(mc('grey', '900'), 5%);
color: mc('grey', '500');
padding: 5px 10px;
}
}
</style> </style>

View File

@ -8,6 +8,7 @@
@import '~katex/dist/katex.min.css'; @import '~katex/dist/katex.min.css';
@import '~diff2html/bundles/css/diff2html.min.css'; @import '~diff2html/bundles/css/diff2html.min.css';
@import 'components/codemirror';
@import 'components/katex'; @import 'components/katex';
@import 'components/v-btn'; @import 'components/v-btn';
@import 'components/v-data-table'; @import 'components/v-data-table';

View File

@ -0,0 +1,79 @@
.cm-s-wikijs-dark.CodeMirror {
background: darken(mc('grey','900'), 3%);
color: #e0e0e0;
}
.cm-s-wikijs-dark div.CodeMirror-selected {
background: mc('blue','800');
}
.cm-s-wikijs-dark .cm-matchhighlight {
background: mc('blue','800');
}
.cm-s-wikijs-dark .CodeMirror-line::selection, .cm-s-wikijs-dark .CodeMirror-line > span::selection, .cm-s-wikijs-dark .CodeMirror-line > span > span::selection {
background: mc('amber', '500');
}
.cm-s-wikijs-dark .CodeMirror-line::-moz-selection, .cm-s-wikijs-dark .CodeMirror-line > span::-moz-selection, .cm-s-wikijs-dark .CodeMirror-line > span > span::-moz-selection {
background: mc('amber', '500');
}
.cm-s-wikijs-dark .CodeMirror-gutters {
background: darken(mc('grey','900'), 6%);
border-right: 1px solid mc('grey','900');
}
.cm-s-wikijs-dark .CodeMirror-guttermarker {
color: #ac4142;
}
.cm-s-wikijs-dark .CodeMirror-guttermarker-subtle {
color: #505050;
}
.cm-s-wikijs-dark .CodeMirror-linenumber {
color: mc('grey','800');
}
.cm-s-wikijs-dark .CodeMirror-cursor {
border-left: 1px solid #b0b0b0;
}
.cm-s-wikijs-dark span.cm-comment {
color: mc('orange','800');
}
.cm-s-wikijs-dark span.cm-atom {
color: #aa759f;
}
.cm-s-wikijs-dark span.cm-number {
color: #aa759f;
}
.cm-s-wikijs-dark span.cm-property, .cm-s-wikijs-dark span.cm-attribute {
color: #90a959;
}
.cm-s-wikijs-dark span.cm-keyword {
color: #ac4142;
}
.cm-s-wikijs-dark span.cm-string {
color: #f4bf75;
}
.cm-s-wikijs-dark span.cm-variable {
color: #90a959;
}
.cm-s-wikijs-dark span.cm-variable-2 {
color: #6a9fb5;
}
.cm-s-wikijs-dark span.cm-def {
color: #d28445;
}
.cm-s-wikijs-dark span.cm-bracket {
color: #e0e0e0;
}
.cm-s-wikijs-dark span.cm-tag {
color: #ac4142;
}
.cm-s-wikijs-dark span.cm-link {
color: #aa759f;
}
.cm-s-wikijs-dark span.cm-error {
background: #ac4142;
color: #b0b0b0;
}
.cm-s-wikijs-dark .CodeMirror-activeline-background {
background: mc('grey','900');
}
.cm-s-wikijs-dark .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}

View File

@ -15,6 +15,8 @@ const state = {
title: '', title: '',
updatedAt: '', updatedAt: '',
mode: '', mode: '',
scriptJs: '',
scriptCss: '',
effectivePermissions: { effectivePermissions: {
comments: { comments: {
read: false, read: false,
@ -30,7 +32,9 @@ const state = {
pages: { pages: {
write: false, write: false,
manage: false, manage: false,
delete: false delete: false,
script: false,
style: false
}, },
system: { system: {
manage: false manage: false

View File

@ -23,7 +23,9 @@ const getPageEffectivePermissions = (req, page) => {
pages: { pages: {
write: WIKI.auth.checkAccess(req.user, ['write:pages'], page), write: WIKI.auth.checkAccess(req.user, ['write:pages'], page),
manage: WIKI.auth.checkAccess(req.user, ['manage:pages'], page), manage: WIKI.auth.checkAccess(req.user, ['manage:pages'], page),
delete: WIKI.auth.checkAccess(req.user, ['delete:pages'], page) delete: WIKI.auth.checkAccess(req.user, ['delete:pages'], page),
script: WIKI.auth.checkAccess(req.user, ['write:scripts'], page),
style: WIKI.auth.checkAccess(req.user, ['write:styles'], page)
}, },
system: { system: {
manage: WIKI.auth.checkAccess(req.user, ['manage:system'], page) manage: WIKI.auth.checkAccess(req.user, ['manage:system'], page)