feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run

- Base: wintercms/winter branch 1.2 (full framework)
- Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS
- Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication
- Partials: hero (offline-first), features, modes (offline/nube toggle),
  screenshots, pricing (3 planes), comparison, FAQ, CTA
- Plugin VivesPOS.Site with ContactForm
- Dockerfile: PHP 8.2 Apache, port 80, healthcheck
- Added winter/wn-pages, blog, sitemap, seo plugins
- Active theme set to vivespos
This commit is contained in:
2026-08-21 19:29:00 -06:00
commit 1f72193a64
3266 changed files with 531480 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
.field-markdowneditor{width:100%;position:relative;border:1px solid #d1d6d9;background:#fff;-webkit-transition:border-color ease-in-out 0.15s,box-shadow ease-in-out 0.15s;transition:border-color ease-in-out 0.15s,box-shadow ease-in-out 0.15s;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
.field-markdowneditor textarea{opacity:0;filter:alpha(opacity=0)}
.field-markdowneditor .editor-toolbar{border-top-right-radius:5px;border-top-left-radius:5px}
.field-markdowneditor.editor-focus{border:1px solid #d1d6d9}
.field-markdowneditor.size-tiny .editor-write{min-height:50px}
.field-markdowneditor.size-tiny .editor-preview{height:50px}
.field-markdowneditor.size-small .editor-write{min-height:100px}
.field-markdowneditor.size-small .editor-preview{height:100px}
.field-markdowneditor.size-large .editor-write{min-height:200px}
.field-markdowneditor.size-large .editor-preview{height:200px}
.field-markdowneditor.size-huge .editor-write{min-height:250px}
.field-markdowneditor.size-huge .editor-preview{height:250px}
.field-markdowneditor.size-giant .editor-write{min-height:350px}
.field-markdowneditor.size-giant .editor-preview{height:350px}
.field-markdowneditor .editor-write{position:relative}
.field-markdowneditor .editor-preview{padding:15px;overflow:auto}
.field-markdowneditor .editor-preview-loader{display:block;width:20px;height:20px;position:absolute;right:10px;top:10px;margin-top:40px;background-image:url('../../../../../system/assets/ui/images/loader-transparent.svg');background-size:20px 20px;background-position:50% 50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}
.field-markdowneditor.mode-tab .editor-preview{display:none}
.field-markdowneditor.mode-tab.is-preview .editor-write{display:none}
.field-markdowneditor.mode-tab.is-preview .editor-preview{display:block}
.field-markdowneditor.mode-split{overflow:hidden}
.field-markdowneditor.mode-split .editor-preview{float:right;width:50%}
.field-markdowneditor.mode-split .editor-write{float:left;width:50%}
.field-markdowneditor.mode-split .editor-write .editor-code{border-right:2px solid #808C8D}
.field-markdowneditor.stretch,
.field-markdowneditor.stretch .editor-toolbar{border-radius:0 !important}
.field-markdowneditor.stretch .editor-toolbar{height:auto}
.field-markdowneditor.stretch .editor-write{float:none;height:calc(100% - 40px);position:relative}
.field-markdowneditor.stretch .editor-preview{float:none;height:auto;position:absolute;left:0;right:0;top:0;bottom:0;margin-top:40px}
.field-markdowneditor.stretch.mode-split .editor-preview{left:auto}
.field-markdowneditor.stretch.mode-split .editor-write{right:auto}
.field-markdowneditor.is-fullscreen{z-index:600;position:fixed !important;top:0;left:0;width:100%}
.field-markdowneditor.is-fullscreen,
.field-markdowneditor.is-fullscreen .editor-toolbar{border-radius:0 !important;border:none}
.field-markdowneditor.disabled .ace_scroller{cursor:not-allowed}
.field-markdowneditor.disabled .control-toolbar.editor-toolbar .toolbar-item .btn{cursor:not-allowed;color:#bdbdbd}
.field-markdowneditor.disabled .control-toolbar.editor-toolbar .toolbar-item .btn:hover{background-color:transparent;color:#bdbdbd}
.field-markdowneditor.disabled .control-toolbar.editor-toolbar .toolbar-item .btn.wn-autumn-button,
.field-markdowneditor.disabled .control-toolbar.editor-toolbar .toolbar-item .btn.oc-autumn-button{color:#bdbdbd !important}
.field-markdowneditor .editor-preview{color:#515c5d;font-family:"Helvetica",sans-serif;line-height:180%}
.field-markdowneditor .editor-preview h1,
.field-markdowneditor .editor-preview h2,
.field-markdowneditor .editor-preview h3,
.field-markdowneditor .editor-preview h4,
.field-markdowneditor .editor-preview h5,
.field-markdowneditor .editor-preview h6{margin-top:20px;font-weight:bold}
.field-markdowneditor .editor-preview h1:first-child,
.field-markdowneditor .editor-preview h2:first-child,
.field-markdowneditor .editor-preview h3:first-child,
.field-markdowneditor .editor-preview h4:first-child,
.field-markdowneditor .editor-preview h5:first-child,
.field-markdowneditor .editor-preview h6:first-child{margin-top:0}
.field-markdowneditor .editor-preview *:last-child{margin-bottom:0}
.field-markdowneditor .editor-preview h1{font-size:30px}
.field-markdowneditor .editor-preview h2{font-size:26px}
.field-markdowneditor .editor-preview h3{font-size:24px}
.field-markdowneditor .editor-preview h4{font-size:22px}
.field-markdowneditor .editor-preview h5{font-size:20px}
.field-markdowneditor .editor-preview h6{font-size:18px}
.field-markdowneditor .editor-preview p,
.field-markdowneditor .editor-preview ol,
.field-markdowneditor .editor-preview ul{font-size:14px}
.field-markdowneditor .editor-preview h1,
.field-markdowneditor .editor-preview h2,
.field-markdowneditor .editor-preview h3,
.field-markdowneditor .editor-preview h4,
.field-markdowneditor .editor-preview h5,
.field-markdowneditor .editor-preview h6,
.field-markdowneditor .editor-preview p,
.field-markdowneditor .editor-preview ol,
.field-markdowneditor .editor-preview ul{margin-bottom:15px}
.field-markdowneditor .editor-preview pre.prettyprint{border-width:0;padding:13px 16px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;line-height:130%}
.field-markdowneditor .editor-preview img{display:block;max-width:100%;height:auto}

View File

@@ -0,0 +1,869 @@
+function ($) { "use strict";
var Base = $.wn.foundation.base,
BaseProto = Base.prototype
var MarkdownEditor = function (element, options) {
this.$el = $(element)
this.options = options || {}
this.$textarea = $('textarea:first', this.$el)
this.$toolbar = $('.editor-toolbar:first', this.$el)
this.$write = $('.editor-write:first', this.$el)
this.$preview = $('.editor-preview:first', this.$el)
this.$code = null
this.editor = null
this.$form = null
this.$buttons = null
this.$fixedButtons = null
this.$indicator = null
this.editorPadding = 15
this.updatesPaused = false
$.wn.foundation.controlUtils.markDisposable(element)
Base.call(this)
this.init()
}
MarkdownEditor.prototype = Object.create(BaseProto)
MarkdownEditor.prototype.constructor = MarkdownEditor
MarkdownEditor.prototype.init = function() {
this.$el.one('dispose-control', this.proxy(this.dispose))
/*
* Control must have an identifier
*/
if (!this.$el.attr('id')) {
this.$el.attr('id', 'element-' + Math.random().toString(36).substring(7))
}
this.$form = this.$el.closest('form')
this.createCodeContainer()
this.createToolbar()
this.createIndicator()
this.setViewMode(this.options.viewMode)
this.$toolbar.on('click', '.btn, .md-dropdown-button', this.proxy(this.onClickToolbarButton))
this.$form.on('oc.beforeRequest', this.proxy(this.onBeforeRequest))
this.editor.on('change', this.proxy(this.onEditorChange))
this.editor.getSession().on('changeScrollTop', this.proxy(this.onEditorScrollTop))
$('[data-control="tooltip"]', this.$toolbar).tooltip()
$('[data-toggle="dropdown"]', this.$toolbar).dropdown()
}
MarkdownEditor.prototype.dispose = function() {
this.$el.off('dispose-control', this.proxy(this.dispose))
this.$toolbar.off('click', '.btn, .md-dropdown-button', this.proxy(this.onClickToolbarButton))
this.$form.off('oc.beforeRequest', this.proxy(this.onBeforeRequest))
this.editor.off('change', this.proxy(this.onEditorChange))
$(window).off('resize', this.proxy(this.updateFullscreen))
this.$el.removeData('oc.markdownEditor')
this.$el = null
this.$textarea = null
this.$toolbar = null
this.$write = null
this.$preview = null
this.$code = null
this.editor = null
this.$form = null
this.$buttons = null
this.$fixedButtons = null
this.$indicator = null
this.editorPadding = null
this.updatesPaused = null
this.isSplitMode = null
this.isPreview = null
this.isFullscreen = null
this.dataTrackInputTimer = null
this.options = null
BaseProto.dispose.call(this)
}
//
// Events
//
MarkdownEditor.prototype.onClickToolbarButton = function(ev) {
if (this.options.disabled) {
return;
}
var $target = $(ev.target),
$button = $target.is('a') ? $target : $target.closest('.btn'),
action = $button.data('button-action'),
template = $button.data('button-template')
$button.blur()
this.pauseUpdates()
if (template) {
this[action](template)
}
else {
this[action]()
}
this.resumeUpdates()
this.handleChange()
}
MarkdownEditor.prototype.onEditorScrollTop = function(scroll) {
if (!this.isSplitMode) return
var canvasHeight = this.$preview.height(),
editorHeight,
previewHeight,
scrollRatio
if (canvasHeight != this.$el.data('markdowneditor-canvas-height')) {
editorHeight =
(this.editor.getSession().getScreenLength() *
this.editor.renderer.lineHeight) -
canvasHeight
previewHeight = this.$preview.get(0).scrollHeight - canvasHeight
scrollRatio = previewHeight / editorHeight
this.$el.data('markdowneditor-canvas-height', canvasHeight)
this.$el.data('markdowneditor-scroll-ratio', scrollRatio)
}
else {
scrollRatio = this.$el.data('markdowneditor-scroll-ratio')
}
scroll += this.editorPadding
this.$preview.scrollTop(scroll * scrollRatio)
}
MarkdownEditor.prototype.onEditorChange = function() {
var html = this.editor.getSession().getValue()
this.$form.trigger('change')
this.$textarea.trigger('changeContent.oc.markdowneditor', [this, html])
this.handleChange()
}
MarkdownEditor.prototype.onBeforeRequest = function() {
this.$textarea.val(this.editor.getSession().getValue())
}
MarkdownEditor.prototype.onResize = function() {
this.editor.resize()
}
MarkdownEditor.prototype.onBlur = function() {
this.$el.removeClass('editor-focus')
}
MarkdownEditor.prototype.onFocus = function() {
this.$el.addClass('editor-focus')
}
//
// Toolbar
//
MarkdownEditor.prototype.createToolbar = function() {
var self = this,
$button,
$buttons = $('<div class="toolbar-item toolbar-primary" />'),
$fixedButtons = $('<div class="toolbar-item" data-calculate-width />')
$.each($.wn.markdownEditorButtons, function(code, button) {
$button = self.makeToolbarButton(code, button)
if (button.fixed) {
$fixedButtons.append($button)
}
else {
$buttons.append($button)
}
if (button.dropdown) {
$button.attr('data-toggle', 'dropdown')
self.createToolbarDropdown(button, $button)
}
})
$buttons.wrapInner('<div data-control="toolbar" />')
this.$toolbar.append($buttons)
this.$toolbar.append($fixedButtons)
this.$fixedButtons = $fixedButtons
this.$buttons = $buttons
}
MarkdownEditor.prototype.createToolbarDropdown = function(button, $el) {
if (this.options.disabled) {
return;
}
var $dropdown = $('<ul class="dropdown-menu" />'),
$childButton
$dropdown.attr('data-dropdown-title', $.wn.lang.get(button.label))
$.each(button.dropdown, function(code, childButton) {
$childButton = $('<a />').attr({
'href': 'javascript:;',
'class': 'md-dropdown-button',
'tabindex': '-1',
'data-button-code': code,
'data-button-action': childButton.action
})
if (childButton.template) {
$childButton.attr('data-button-template', childButton.template)
}
if (childButton.cssClass) {
$childButton.addClass(childButton.cssClass)
}
$childButton.text($.wn.lang.get(childButton.label))
$dropdown.append($childButton)
$childButton.wrap('<li />')
})
$el.wrap('<div class="dropdown dropdown-fixed" />')
$el.after($dropdown)
}
MarkdownEditor.prototype.makeToolbarButton = function(code, button) {
if (!this.options.useMediaManager && (code == 'medialink' || code == 'mediaimage')) {
return
}
var $button = $('<button />').attr({
'type': "button",
'class': 'btn',
})
if (!this.options.disabled) {
$button.attr({
'title': $.wn.lang.get(button.label),
'data-control': "tooltip",
'data-placement': "bottom",
'data-container': "body",
'data-button-code': code
});
}
if (button.action) {
$button.attr('data-button-action', button.action)
}
if (button.template) {
$button.attr('data-button-template', button.template)
}
if (button.cssClass) {
$button.addClass(button.cssClass)
}
else {
$button.append('<i class="icon-' + button.icon + '"></i>')
}
return $button
}
MarkdownEditor.prototype.addToolbarButton = function(code, button) {
var $button = this.makeToolbarButton(code, button)
var appendCode = button.insertBefore || button.insertAfter
if (appendCode) {
var appendButton = this.findToolbarButton(appendCode)
if (!!appendButton.length && button.insertBefore) {
appendButton.before($button)
}
else if (!!appendButton.length && button.insertAfter) {
appendButton.after($button)
}
}
else {
if (button.fixed) {
this.$fixedButtons.append($button)
}
else {
$('[data-control="toolbar"]', this.$buttons).append($button)
}
}
return $button
}
MarkdownEditor.prototype.findToolbarButton = function(code) {
return $('[data-button-code='+code+']', this.$toolbar)
}
//
// Write
//
MarkdownEditor.prototype.createCodeContainer = function() {
/*
* Create code container
*/
this.$code = $('<div />')
.addClass('editor-code')
.attr('id', this.$el.attr('id') + '-code')
.css({
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0
})
.appendTo(this.$write)
/*
* Initialize ACE editor
*/
var editor = this.editor = ace.edit(this.$code.attr('id'))
// Fixes a weird notice about scrolling
editor.$blockScrolling = Infinity
editor.getSession().setValue(this.$textarea.val())
/*
* Set theme, anticipated languages should be preloaded
*/
assetManager.load({
js:[
this.options.vendorPath + '/theme-github.js'
]
}, function(){
editor.setTheme('ace/theme/github')
})
editor.getSession().setMode({ path: 'ace/mode/markdown' })
editor.setHighlightActiveLine(false)
editor.renderer.setShowGutter(false)
editor.renderer.setShowPrintMargin(false)
editor.getSession().setUseWrapMode(true)
editor.setFontSize(14)
if (this.options.disabled) {
editor.setReadOnly(true);
editor.setHighlightSelectedWord(false);
editor.renderer.$cursorLayer.element.style.display = 'none';
} else {
editor.on('blur', this.proxy(this.onBlur))
editor.on('focus', this.proxy(this.onFocus))
}
// Set the vendor path for Ace's require path
ace.require('ace/config').set('basePath', this.options.vendorPath)
editor.renderer.setPadding(this.editorPadding)
editor.renderer.setScrollMargin(this.editorPadding, this.editorPadding, 0, 0)
setTimeout(function() {
editor.resize()
}, 100)
}
MarkdownEditor.prototype.handleChange = function() {
if (this.updatesPaused)
return
var self = this
if (!this.isSplitMode) return
if (this.loading) {
if (this.dataTrackInputTimer === undefined) {
this.dataTrackInputTimer = window.setInterval(function(){
self.handleChange()
}, 100)
}
return
}
window.clearTimeout(this.dataTrackInputTimer)
this.dataTrackInputTimer = undefined
self.updatePreview()
}
MarkdownEditor.prototype.getEditorObject = function() {
return this.editor
}
MarkdownEditor.prototype.getContent = function() {
return this.editor.getSession().getValue()
}
MarkdownEditor.prototype.setContent = function(html) {
this.editor.getSession().setValue(html)
}
//
// Preview
//
MarkdownEditor.prototype.updatePreview = function() {
var self = this
this.loading = true
this.showIndicator()
this.$el.request(this.options.refreshHandler, {
success: function(data) {
this.success(data)
self.$preview.html(data.preview)
self.initPreview()
}
}).done(function() {
self.hideIndicator()
self.loading = false
})
}
MarkdownEditor.prototype.initPreview = function() {
$('pre', this.$preview).addClass('prettyprint')
prettyPrint()
this.$el.trigger('initPreview.oc.markdowneditor')
}
MarkdownEditor.prototype.pauseUpdates = function() {
this.updatesPaused = true
}
MarkdownEditor.prototype.resumeUpdates = function() {
this.updatesPaused = false
}
//
// Loader
//
MarkdownEditor.prototype.createIndicator = function() {
this.$indicator = $('<div class="editor-preview-loader"></div>')
this.$el.prepend(this.$indicator)
this.$indicator.css('display', 'none')
}
MarkdownEditor.prototype.showIndicator = function() {
this.$indicator.css('display', 'block')
}
MarkdownEditor.prototype.hideIndicator = function() {
this.$indicator.css('display', 'none')
}
//
// View mode
//
MarkdownEditor.prototype.setViewMode = function(value) {
this.isSplitMode = value == 'split'
$('[data-button-code="preview"]', this.$toolbar).toggle(!this.isSplitMode)
this.$el
.removeClass('mode-tab mode-split')
.addClass('mode-' + value)
if (this.isSplitMode) {
this.updatePreview()
}
}
//
// Full screen
//
MarkdownEditor.prototype.setFullscreen = function(value) {
this.isFullscreen = value
this.$el.toggleClass('is-fullscreen', value)
if (value) {
$('body, html').css('overflow', 'hidden')
this.updateFullscreen()
this.setViewMode('split')
$(window).on('resize', this.proxy(this.updateFullscreen))
}
else {
this.setViewMode(this.options.viewMode)
this.$preview.css('height', '')
this.$write.css('height', '')
$('body, html').css('overflow', '')
$(window).off('resize', this.proxy(this.updateFullscreen))
this.editor.resize()
}
$(window).trigger('oc.updateUi')
}
MarkdownEditor.prototype.updateFullscreen = function() {
if (!this.isFullscreen) return
var fullscreenCss = {
height: $(document).height() - this.$toolbar.outerHeight()
}
this.$preview.css(fullscreenCss)
this.$write.css(fullscreenCss)
this.editor.resize()
}
//
// Media Manager
//
MarkdownEditor.prototype.launchMediaManager = function(onSuccess) {
var self = this
new $.wn.mediaManager.popup({
alias: 'ocmediamanager',
cropAndInsertButton: true,
onInsert: function(items) {
if (!items.length) {
alert('Please select image(s) to insert.')
return
}
if (items.length > 1) {
alert('Please select a single item.')
return
}
var path, publicUrl
for (var i=0, len=items.length; i<len; i++) {
path = items[i].path
publicUrl = items[i].publicUrl
}
// Spaces in URLs break Markdown syntax
publicUrl = publicUrl.replace(/\s/g, '%20')
onSuccess(publicUrl)
this.hide()
}
})
}
//
// Button actions
//
MarkdownEditor.prototype.toggleFullscreen = function() {
this.setFullscreen(!this.isFullscreen)
if (this.isPreview) {
this.togglePreview()
}
this.editor.focus()
$('[data-button-code="fullscreen"]', this.$toolbar).toggleClass('active')
}
MarkdownEditor.prototype.togglePreview = function() {
this.isPreview = !this.isPreview
if (this.isPreview) {
this.updatePreview()
}
else {
this.editor.focus()
}
this.$el.toggleClass('is-preview', this.isPreview)
$('.btn', this.$buttons).prop('disabled', this.isPreview)
$('[data-button-code="preview"]', this.$toolbar).toggleClass('active')
}
MarkdownEditor.prototype.insertLine = function(template) {
var editor = this.editor,
pos = this.editor.getCursorPosition()
if (pos.column == 0) {
editor.selection.clearSelection()
}
else {
editor.navigateTo(editor.getSelectionRange().start.row, Number.MAX_VALUE)
}
editor.insert(template)
editor.focus()
}
MarkdownEditor.prototype.formatInline = function(template) {
var editor = this.editor,
pos = this.editor.getCursorPosition(),
text = editor.session.getTextRange(editor.selection.getRange()).trim()
if (!text.length) {
editor.selection.selectWord()
text = editor.session.getTextRange(editor.selection.getRange()).trim()
}
editor.insert(template.replace('$1', text))
editor.moveCursorToPosition(pos)
if (template.indexOf('$1') != -1) {
editor.navigateRight(template.indexOf('$1'))
}
editor.focus()
}
MarkdownEditor.prototype.formatBlock = function(template) {
var editor = this.editor,
pos = this.editor.getCursorPosition(),
text = editor.session.getTextRange(editor.selection.getRange()).trim()
if (!text.length) {
editor.navigateTo(editor.getSelectionRange().start.row, 0)
editor.selection.selectLineEnd()
text = editor.session.getTextRange(editor.selection.getRange()).trim()
}
else {
editor.insert('\n')
}
editor.insert(template.replace('$1', text))
editor.moveCursorToPosition(pos)
if (template.indexOf('$1') != -1) {
editor.navigateRight(template.indexOf('$1'))
}
editor.focus()
}
MarkdownEditor.prototype.formatBlockMulti = function(template) {
var editor = this.editor,
pos = this.editor.getCursorPosition(),
text = editor.session.getTextRange(editor.selection.getRange()).trim()
if (!text.length) {
editor.navigateTo(editor.getSelectionRange().start.row, 0)
editor.selection.selectLineEnd()
}
var range = editor.selection.getRange()
for (var i = range.start.row + 1; i < range.end.row + 2; i++) {
editor.gotoLine(i);
editor.insert(template.replace('$1', ''));
}
editor.moveCursorToPosition(pos)
editor.focus()
}
MarkdownEditor.prototype.formatMediaManager = function(template) {
var self = this,
editor = this.editor,
pos = this.editor.getCursorPosition(),
text = editor.session.getTextRange(editor.selection.getRange()).trim()
if (!text.length) {
editor.selection.selectWord()
text = editor.session.getTextRange(editor.selection.getRange()).trim()
}
this.launchMediaManager(function(path) {
editor.insert(template.replace('$1', text).replace('$2', path));
editor.moveCursorToPosition(pos)
editor.focus()
if (!text.length && template.indexOf('$1') != -1) {
editor.navigateRight(template.indexOf('$1'))
}
})
}
MarkdownEditor.DEFAULTS = {
vendorPath: '/',
refreshHandler: null,
buttons: ['formatting', 'bold', 'italic', 'unorderedlist', 'orderedlist', 'link', 'horizontalrule'],
viewMode: 'tab',
useMediaManager: false,
disabled: false
}
// PLUGIN DEFINITION
// ============================
var old = $.fn.markdownEditor
$.fn.markdownEditor = function (option) {
var args = Array.prototype.slice.call(arguments, 1), items, result
items = this.each(function () {
var $this = $(this)
var data = $this.data('oc.markdownEditor')
var options = $.extend({}, MarkdownEditor.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('oc.markdownEditor', (data = new MarkdownEditor(this, options)))
if (typeof option == 'string') result = data[option].apply(data, args)
if (typeof result != 'undefined') return false
})
return result ? result : items
}
$.fn.markdownEditor.Constructor = MarkdownEditor
$.fn.markdownEditor.noConflict = function () {
$.fn.markdownEditor = old
return this
}
$(document).render(function (){
$('[data-control="markdowneditor"]').markdownEditor()
})
// BUTTON DEFINITIONS
// =================
if ($.wn === undefined)
$.wn = {}
if ($.oc === undefined)
$.oc = $.wn
$.wn.markdownEditorButtons = {
formatting: {
label: 'markdowneditor.formatting',
icon: 'paragraph',
dropdown: {
quote: {
label: 'markdowneditor.quote',
cssClass: 'wn-button wn-icon-quote-right',
action: 'formatBlockMulti',
template: '> $1'
},
code: {
label: 'markdowneditor.code',
cssClass: 'wn-button wn-icon-code',
action: 'formatBlock',
template: '\n```\n$1\n```\n'
},
header1: {
label: 'markdowneditor.header1',
cssClass: 'wn-button wn-icon-header',
action: 'formatBlock',
template: '# $1'
},
header2: {
label: 'markdowneditor.header2',
cssClass: 'wn-button wn-icon-header',
action: 'formatBlock',
template: '## $1'
},
header3: {
label: 'markdowneditor.header3',
cssClass: 'wn-button wn-icon-header',
action: 'formatBlock',
template: '### $1'
},
header4: {
label: 'markdowneditor.header4',
cssClass: 'wn-button wn-icon-header',
action: 'formatBlock',
template: '#### $1'
},
header5: {
label: 'markdowneditor.header5',
cssClass: 'wn-button wn-icon-header',
action: 'formatBlock',
template: '##### $1'
},
header6: {
label: 'markdowneditor.header6',
cssClass: 'wn-button wn-icon-header',
action: 'formatBlock',
template: '###### $1'
}
}
},
bold: {
label: 'markdowneditor.bold',
icon: 'bold',
action: 'formatInline',
template: '**$1**'
},
italic: {
label: 'markdowneditor.italic',
icon: 'italic',
action: 'formatInline',
template: '*$1*'
},
unorderedlist: {
label: 'markdowneditor.unorderedlist',
icon: 'list-ul',
action: 'formatBlockMulti',
template: '* $1'
},
orderedlist: {
label: 'markdowneditor.orderedlist',
icon: 'list-ol',
action: 'formatBlockMulti',
template: '1. $1'
},
link: {
label: 'markdowneditor.link',
icon: 'link',
action: 'formatInline',
template: '[$1](https://)'
},
image: {
label: 'markdowneditor.image',
icon: 'image',
action: 'formatInline',
template: '![$1](https://)'
},
horizontalrule: {
label: 'markdowneditor.horizontalrule',
icon: 'minus',
action: 'insertLine',
template: '\n\n---\n'
},
medialink: {
label: 'mediamanager.insert_link',
cssClass: 'wn-autumn-button wn-icon-link',
action: 'formatMediaManager',
template: '[$1]($2)'
},
mediaimage: {
label: 'mediamanager.insert_image',
cssClass: 'wn-autumn-button wn-icon-image',
action: 'formatMediaManager',
template: '![$1]($2)'
},
fullscreen: {
label: 'markdowneditor.fullscreen',
icon: 'expand',
action: 'toggleFullscreen',
fixed: true
},
preview: {
label: 'markdowneditor.preview',
icon: 'eye',
action: 'togglePreview',
fixed: true
}
}
}(window.jQuery);

View File

@@ -0,0 +1,264 @@
@import "../../../../assets/less/core/boot.less";
@color-markdowneditor-toolbar: #dddddd;
@color-markdowneditor-toolbar-btn-color: #404040;
@color-markdowneditor-toolbar-btn-bg-hover: #999999;
@color-markdowneditor-toolbar-btn-bg-active: #404040;
@color-markdowneditor-toolbar-btn-color-hover: #ffffff;
@markdowneditor-toolbar-height: 40px;
.field-markdowneditor {
width: 100%;
position: relative;
border: 1px solid @color-form-field-border;
background: #fff;
textarea { .opacity(0); }
.transition(@input-transition);
.border-radius(5px);
.editor-toolbar {
.border-top-radius(5px);
}
&.editor-focus { border: 1px solid @color-form-field-border-focus; }
&.size-tiny {
.editor-write { min-height: @size-tiny; }
.editor-preview { height: @size-tiny; }
}
&.size-small {
.editor-write { min-height: @size-small; }
.editor-preview { height: @size-small; }
}
&.size-large {
.editor-write { min-height: @size-large; }
.editor-preview { height: @size-large; }
}
&.size-huge {
.editor-write { min-height: @size-huge; }
.editor-preview { height: @size-huge; }
}
&.size-giant {
.editor-write { min-height: @size-giant; }
.editor-preview { height: @size-giant; }
}
//
// Code
//
.editor-write {
position: relative;
}
//
// Preview
//
.editor-preview {
padding: 15px;
overflow: auto;
}
.editor-preview-loader {
display: block;
width: 20px;
height: 20px;
position: absolute;
right: 10px;
top: 10px;
margin-top: @markdowneditor-toolbar-height;
background-image:url('../../../../../system/assets/ui/images/loader-transparent.svg');
background-size: 20px 20px;
background-position: 50% 50%;
.animation(spin 1s linear infinite);
}
//
// Mode: Tab
//
&.mode-tab {
.editor-preview {
display: none;
}
&.is-preview {
.editor-write { display: none; }
.editor-preview { display: block; }
}
}
//
// Mode: Split
//
&.mode-split {
overflow: hidden; // clearfix
.editor-preview {
float: right;
width: 50%;
}
.editor-write {
float: left;
width: 50%;
.editor-code {
border-right: 2px solid #808C8D;
}
}
}
// Stretch
&.stretch {
&, .editor-toolbar {
border-radius: 0 !important;
}
.editor-toolbar {
height: auto;
}
.editor-write {
float: none;
height: ~"calc(100% - @{markdowneditor-toolbar-height})";
position: relative;
}
.editor-preview {
float: none;
height: auto;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin-top: @markdowneditor-toolbar-height;
}
&.mode-split {
.editor-preview {
left: auto;
}
.editor-write {
right: auto;
}
}
}
//
// Full screen
//
&.is-fullscreen {
z-index: @zindex-dropdown;
position: fixed !important;
top: 0;
left: 0;
width: 100%;
&, .editor-toolbar {
border-radius: 0 !important;
border: none;
}
}
//
// Disabled
//
&.disabled {
.ace_scroller {
cursor: not-allowed;
}
.control-toolbar.editor-toolbar {
.toolbar-item {
.btn {
cursor: not-allowed;
color: #bdbdbd;
&:hover {
background-color: transparent;
color: #bdbdbd;
}
}
.btn.wn-autumn-button,
.btn.oc-autumn-button {
color: #bdbdbd!important;
}
}
}
}
}
//
// Default theme
.field-markdowneditor .editor-preview {
color: #515c5d;
font-family: "Helvetica", sans-serif;
line-height: 180%;
h1, h2, h3, h4, h5, h6 {
margin-top: 20px;
font-weight: bold;
&:first-child {
margin-top: 0;
}
}
*:last-child {
margin-bottom: 0;
}
h1 {
font-size: 30px;
}
h2 {
font-size: 26px;
}
h3 {
font-size: 24px;
}
h4 {
font-size: 22px;
}
h5 {
font-size: 20px;
}
h6 {
font-size: 18px;
}
p, ol, ul {
font-size: 14px;
}
h1, h2, h3, h4, h5, h6, p, ol, ul {
margin-bottom: 15px;
}
pre.prettyprint {
border-width: 0;
padding: 13px 16px;
.border-radius(3px);
line-height: 130%;
}
img {
display: block;
max-width: 100%;
height: auto;
}
}