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,63 @@
.control-assetlist p.no-data{padding:22px;margin:0;color:#666;font-size:14px;text-align:center;font-weight:400;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
.control-assetlist p.parent,
.control-assetlist ul li{font-weight:300;line-height:150%;margin-bottom:0}
.control-assetlist p.parent.active a,
.control-assetlist ul li.active a{background:#ddd;position:relative}
.control-assetlist p.parent.active a:after,
.control-assetlist ul li.active a:after{position:absolute;height:100%;width:4px;left:0;top:0;background:#2da7c7;display:block;content:' '}
.control-assetlist p.parent a.link,
.control-assetlist ul li a.link{display:block;position:relative;word-wrap:break-word;padding:10px 50px 10px 20px;outline:none;font-weight:400;color:#405261;font-size:14px}
.control-assetlist p.parent a.link:hover,
.control-assetlist ul li a.link:hover,
.control-assetlist p.parent a.link:focus,
.control-assetlist ul li a.link:focus,
.control-assetlist p.parent a.link:active,
.control-assetlist ul li a.link:active{text-decoration:none}
.control-assetlist p.parent a.link span,
.control-assetlist ul li a.link span{display:block}
.control-assetlist p.parent a.link span.description,
.control-assetlist ul li a.link span.description{color:#8f8f8f;font-size:12px;font-weight:400;word-wrap:break-word}
.control-assetlist p.parent a.link span.description strong,
.control-assetlist ul li a.link span.description strong{color:#405261;font-weight:400}
.control-assetlist p.parent.directory a.link,
.control-assetlist ul li.directory a.link,
.control-assetlist p.parent.parent a.link,
.control-assetlist ul li.parent a.link{padding-left:40px}
.control-assetlist p.parent.directory a.link:after,
.control-assetlist ul li.directory a.link:after,
.control-assetlist p.parent.parent a.link:after,
.control-assetlist ul li.parent a.link:after{display:block;position:absolute;width:10px;height:10px;top:10px;left:20px;font-family:"Font Awesome 6 Free";font-weight:900;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal;font-variant:normal;text-rendering:auto;content:"\f07b";color:#a1aab1;font-size:14px}
.control-assetlist p.parent.parent a.link,
.control-assetlist ul li.parent a.link{padding-left:41px;background-color:#fff;word-wrap:break-word}
.control-assetlist p.parent.parent a.link:before,
.control-assetlist ul li.parent a.link:before{content:'';display:block;position:absolute;left:0;top:0;width:100%;height:1px;background:#ecf0f1}
.control-assetlist p.parent.parent a.link:after,
.control-assetlist ul li.parent a.link:after{font-size:13px;color:#103141;width:18px;height:18px;top:11px;left:22px;opacity:0.5;filter:alpha(opacity=50);font-family:"Font Awesome 6 Free";font-weight:900;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal;font-variant:normal;text-rendering:auto;content:"\f053"}
.control-assetlist p.parent a.link:hover{background:#ddd !important}
.control-assetlist p.parent a.link:hover:after{opacity:1;filter:alpha(opacity=100)}
.control-assetlist p.parent a.link:hover:before{display:none}
.control-assetlist ul{padding:0;margin:0}
.control-assetlist ul li{font-weight:300;line-height:150%;position:relative;list-style:none}
.control-assetlist ul li.active a.link,
.control-assetlist ul li a.link:hover{background:#ddd}
.control-assetlist ul li.active a.link{position:relative}
.control-assetlist ul li.active a.link:after{position:absolute;height:100%;width:4px;left:0;top:0;background:#2da7c7;display:block;content:' '}
.control-assetlist ul li div.controls{position:absolute;right:45px;top:10px}
.control-assetlist ul li div.controls .dropdown{width:14px;height:21px}
.control-assetlist ul li div.controls .dropdown.open a.control{display:block!important}
.control-assetlist ul li div.controls .dropdown.open a.control:before{visibility:visible;display:block}
.control-assetlist ul li div.controls a.control{color:#405261;font-size:14px;visibility:hidden;overflow:hidden;width:14px;height:21px;display:none;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}
.control-assetlist ul li div.controls a.control:before{visibility:visible;display:block;margin-right:0}
.control-assetlist ul li div.controls a.control:hover{opacity:1;filter:alpha(opacity=100)}
.control-assetlist ul li:hover{background:#ddd}
.control-assetlist ul li:hover div.controls,
.control-assetlist ul li:hover a.control{display:block!important}
.control-assetlist ul li:hover div.controls>a.control,
.control-assetlist ul li:hover a.control>a.control{display:block!important}
.control-assetlist ul li .checkbox{position:absolute;top:-5px;right:-5px}
.control-assetlist ul li .checkbox label{margin-right:0}
.control-assetlist ul li .checkbox label:before{border-color:#ccc}
.control-assetlist div.list-container{position:relative;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}
.control-assetlist div.list-container.animate ul{-webkit-transition:all 0.2s ease;transition:all 0.2s ease}
.control-assetlist div.list-container.goForward ul{-webkit-transform:translate(-350px,0);-ms-transform:translate(-350px,0);transform:translate(-350px,0)}
.control-assetlist div.list-container.goBackward ul{-webkit-transform:translate(350px,0);-ms-transform:translate(350px,0);transform:translate(350px,0)}

View File

@@ -0,0 +1,184 @@
/*
* Asset list
*/
+function ($) { "use strict";
var AssetList = function (form, alias) {
this.$form = $(form)
this.alias = alias
this.$form.on('ajaxSuccess', $.proxy(this.onAjaxSuccess, this))
this.$form.on('click', 'ul.list > li.directory > a', $.proxy(this.onDirectoryClick, this))
this.$form.on('click', 'ul.list > li.file > a', $.proxy(this.onFileClick, this))
this.$form.on('click', 'p.parent > a', $.proxy(this.onDirectoryClick, this))
this.$form.on('click', 'a[data-control=delete-asset]', $.proxy(this.onDeleteClick, this))
this.$form.on('oc.list.setActiveItem', $.proxy(this.onSetActiveItem, this))
this.setupUploader()
}
// Event handlers
// =================
AssetList.prototype.onDirectoryClick = function(e) {
this.gotoDirectory(
$(e.currentTarget).data('path'),
$(e.currentTarget).parent().hasClass('parent')
)
return false;
}
AssetList.prototype.gotoDirectory = function(path, gotoParent) {
var $container = $('div.list-container', this.$form),
self = this
if (gotoParent !== undefined && gotoParent)
$container.addClass('goBackward')
else
$container.addClass('goForward')
$.wn.stripeLoadIndicator.show()
this.$form.request(this.alias+'::onOpenDirectory', {
data: {
path: path,
d: 0.2
},
complete: function() {
self.updateUi()
$container.trigger('oc.scrollbar.gotoStart')
},
error: function(jqXHR, textStatus, errorThrown) {
$container.removeClass('goForward goBackward')
alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText)
}
}).always(function(){
$.wn.stripeLoadIndicator.hide()
})
}
AssetList.prototype.onDeleteClick = function(e) {
var $el = $(e.currentTarget),
self = this
if (!confirm($el.data('confirmation')))
return false
this.$form.request(this.alias+'::onDeleteFiles', {
success: function(data) {
if (data.error !== undefined && $.type(data.error) === 'string' && data.error.length)
$.wn.flashMsg({text: data.error, 'class': 'error'})
},
complete: function() {
self.refresh()
}
})
return false
}
AssetList.prototype.onAjaxSuccess = function() {
this.updateUi()
}
AssetList.prototype.onUploadFail = function(file, message) {
if (file.xhr.status === 413) {
message = 'Server rejected the file because it was too large, try increasing post_max_size';
}
if (!message) {
message = 'Error uploading file'
}
$.wn.alert(message)
this.refresh()
}
AssetList.prototype.onUploadSuccess = function(file, data) {
if (data !== 'success') {
$.wn.alert(data)
}
}
AssetList.prototype.onUploadComplete = function(file, data) {
$.wn.stripeLoadIndicator.hide()
this.refresh()
}
AssetList.prototype.onUploadStart = function() {
$.wn.stripeLoadIndicator.show()
}
AssetList.prototype.onFileClick = function(event) {
var $link = $(event.currentTarget),
$li = $link.parent()
var e = $.Event('open.oc.list', {relatedTarget: $li.get(0), clickEvent: event})
this.$form.trigger(e, this)
if (e.isDefaultPrevented())
return false;
}
AssetList.prototype.onSetActiveItem = function(event, dataId) {
$('ul li.file', this.$form).removeClass('active')
if (dataId)
$('ul li.file[data-id="'+dataId+'"]', this.$form).addClass('active')
}
// Service functions
// =================
AssetList.prototype.updateUi = function() {
$('button[data-control=asset-tools]', self.$form).trigger('oc.triggerOn.update')
}
AssetList.prototype.refresh = function() {
var self = this;
this.$form.request(this.alias+'::onRefresh', {
complete: function() {
self.updateUi()
}
})
}
AssetList.prototype.setupUploader = function() {
var self = this,
$link = $('[data-control="upload-assets"]', this.$form),
uploaderOptions = {
method: 'POST',
url: window.location,
paramName: 'file_data',
previewsContainer: $('<div />').get(0),
clickable: $link.get(0),
timeout: 0,
headers: {}
}
/*
* Add CSRF token to headers
*/
var token = $('meta[name="csrf-token"]').attr('content')
if (token) {
uploaderOptions.headers['X-CSRF-TOKEN'] = token
}
var dropzone = new Dropzone($('<div />').get(0), uploaderOptions)
dropzone.on('error', $.proxy(self.onUploadFail, self))
dropzone.on('success', $.proxy(self.onUploadSuccess, self))
dropzone.on('complete', $.proxy(self.onUploadComplete, self))
dropzone.on('sending', function(file, xhr, formData) {
$.each(self.$form.serializeArray(), function (index, field) {
formData.append(field.name, field.value)
})
xhr.setRequestHeader('X-WINTER-REQUEST-HANDLER', self.alias + '::onUpload')
self.onUploadStart()
})
}
$(document).ready(function(){
new AssetList($('#asset-list-container').closest('form'), $('#asset-list-container').data('alias'))
})
}(window.jQuery);

View File

@@ -0,0 +1,236 @@
@import "../../../../../backend/assets/less/core/boot.less";
.control-assetlist {
p.no-data {
padding: 22px;
margin: 0;
color: @color-filelist-norecords-text;
font-size: 14px;
text-align: center;
font-weight: 400;
.border-radius(@border-radius-base);
}
p.parent, ul li {
font-weight: 300;
line-height: 150%;
margin-bottom: 0;
&.active a {
background: @color-list-active;
position: relative;
&:after {
position: absolute;
height: 100%;
width: 4px;
left: 0;
top: 0;
background: @color-list-active-border;
display: block;
content: ' ';
}
}
a.link {
display: block;
position: relative;
word-wrap: break-word;
padding: 10px 50px 10px 20px;
outline: none;
font-weight: 400;
color: @color-text-title;
font-size: 14px;
&:hover, &:focus, &:active {text-decoration: none;}
span {
display: block;
&.description {
color: @color-text-description;
font-size: 12px;
font-weight: 400;
word-wrap: break-word;
strong {
color: @color-text-title;
font-weight: 400;
}
}
}
}
&.directory, &.parent {
a.link {
padding-left: 40px;
&:after {
display: block;
position: absolute;
width: 10px;
height: 10px;
top: 10px;
left: 20px;
.icon(@folder);
color: @color-list-icon;
font-size: 14px;
}
}
}
&.parent {
a.link {
padding-left: 41px;
background-color: @color-list-parent-bg;
word-wrap: break-word;
&:before {
content: '';
height: 1px;
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
background: #ecf0f1;
}
&:after {
font-size: 13px;
color: @color-list-nav-arrow;
width: 18px;
height: 18px;
top: 11px;
left: 22px;
.opacity(0.5);
.icon(@chevron-left);
}
}
}
}
p.parent a.link:hover {
background: @color-list-active!important;
&:after {
.opacity(1);
}
&:before {
display: none;
}
}
ul {
padding: 0;
margin: 0;
li {
font-weight: 300;
line-height: 150%;
position: relative;
list-style: none;
&.active a.link, a.link:hover {background: @color-list-active;}
&.active a.link {
position: relative;
&:after {
position: absolute;
height: 100%;
width: 4px;
left: 0;
top: 0;
background: @color-list-active-border;
display: block;
content: ' ';
}
}
div.controls {
position: absolute;
right: 45px;
top: 10px;
.dropdown {
width: 14px;
height: 21px;
&.open a.control {
display: block!important;
&:before {
visibility: visible;
display: block;
}
}
}
a.control {
color: @color-text-title;
font-size: 14px;
visibility: hidden;
overflow: hidden;
width: 14px;
height: 21px;
display: none;
text-decoration: none;
cursor: pointer;
.opacity(0.5);
&:before {
visibility: visible;
display: block;
margin-right: 0;
}
&:hover {
.opacity(1);
}
}
}
&:hover {
background: @color-list-active;
div.controls, a.control {
display: block!important;
> a.control {
display: block!important;
}
}
}
.checkbox {
position: absolute;
top: -5px;
right: -5px;
label {
margin-right: 0;
&:before {
border-color: @color-filelist-cb-border;
}
}
}
}
}
div.list-container {
position: relative;
.translate(0, 0);
&.animate ul {
.transition(all 0.2s ease);
}
&.goForward ul {
.translate(-350px, 0);
}
&.goBackward ul {
.translate(350px, 0);
}
}
}