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,119 @@
/*
* RecordFinder plugin
*
* Data attributes:
* - data-control="recordfinder" - enables the plugin on an element
* - data-option="value" - an option with a value
*
* JavaScript API:
* $('a#someElement').recordFinder({ option: 'value' })
*
* Dependences:
* - Some other plugin (filename.js)
*/
+function ($) { "use strict";
var Base = $.wn.foundation.base,
BaseProto = Base.prototype
// RECORDFINDER CLASS DEFINITION
// ============================
var RecordFinder = function(element, options) {
this.$el = $(element)
this.options = options || {}
$.wn.foundation.controlUtils.markDisposable(element)
Base.call(this)
this.init()
}
RecordFinder.prototype = Object.create(BaseProto)
RecordFinder.prototype.constructor = RecordFinder
RecordFinder.prototype.init = function() {
this.$el.on('dblclick', this.proxy(this.onDoubleClick))
this.$el.one('dispose-control', this.proxy(this.dispose))
}
RecordFinder.prototype.dispose = function() {
this.$el.off('dblclick', this.proxy(this.onDoubleClick))
this.$el.off('dispose-control', this.proxy(this.dispose))
this.$el.removeData('oc.recordfinder')
this.$el = null
// In some cases options could contain callbacks,
// so it's better to clean them up too.
this.options = null
BaseProto.dispose.call(this)
}
RecordFinder.DEFAULTS = {
refreshHandler: null,
dataLocker: null
}
RecordFinder.prototype.onDoubleClick = function(linkEl, recordId) {
$('.btn.find-record', this.$el).trigger('click')
}
RecordFinder.prototype.updateRecord = function(linkEl, recordId) {
if (!this.options.dataLocker) return
// Selector name must be used because by the time success runs
// - this.options will be disposed
// - $locker element will be replaced
var locker = this.options.dataLocker
$(locker).val(recordId)
this.$el.loadIndicator({ opaque: true })
this.$el.request(this.options.refreshHandler, {
success: function(data) {
this.success(data)
$(locker).trigger('change')
}
})
$(linkEl).closest('.recordfinder-popup').popup('hide')
}
// RECORDFINDER PLUGIN DEFINITION
// ============================
var old = $.fn.recordFinder
$.fn.recordFinder = function (option) {
var args = Array.prototype.slice.call(arguments, 1), result
this.each(function () {
var $this = $(this)
var data = $this.data('oc.recordfinder')
var options = $.extend({}, RecordFinder.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('oc.recordfinder', (data = new RecordFinder(this, options)))
if (typeof option == 'string') result = data[option].apply(data, args)
if (typeof result != 'undefined') return false
})
return result ? result : this
}
$.fn.recordFinder.Constructor = RecordFinder
// RECORDFINDER NO CONFLICT
// =================
$.fn.recordFinder.noConflict = function () {
$.fn.recordFinder = old
return this
}
// RECORDFINDER DATA-API
// ===============
$(document).render(function () {
$('[data-control="recordfinder"]').recordFinder()
})
}(window.jQuery);

View File

@@ -0,0 +1,11 @@
<?php if ($this->previewMode && !$value): ?>
<span class="form-control" disabled="disabled"><?= e(trans('backend::lang.form.preview_no_record_message')) ?></span>
<?php else: ?>
<div class="recordfinder-widget" id="<?= $this->getId('container') ?>">
<?= $this->makePartial('recordfinder') ?>
</div>
<?php endif ?>

View File

@@ -0,0 +1,63 @@
<?php
$previewMode = false;
if ($this->previewMode || $field->readOnly) {
$previewMode = true;
}
?>
<div
id="<?= $this->getId() ?>"
class="field-recordfinder loading-indicator-container size-input-text"
data-control="recordfinder"
data-refresh-handler="<?= $this->getEventHandler('onRefresh') ?>"
data-data-locker="#<?= $field->getId() ?>">
<span class="form-control"
<?= $previewMode ? 'disabled="disabled"' : '' ?>
<?php if (!$previewMode): ?>
style="cursor:pointer"
data-control="popup"
data-size="huge"
data-handler="<?= $this->getEventHandler('onFindRecord') ?>"
data-request-data="recordfinder_flag: 1"
<?php endif ?>
>
<?php if ($value): ?>
<span class="primary"><?= e($nameValue) ?: 'Undefined' ?></span>
<?php if ($descriptionValue): ?>
<span class="secondary"> - <?= e($descriptionValue) ?></span>
<?php endif ?>
<?php else: ?>
<span class="text-muted"><?= $prompt ?></span>
<?php endif ?>
</span>
<?php if (!$previewMode): ?>
<?php if ($value): ?>
<button
type="button"
class="btn btn-default clear-record"
data-request="<?= $this->getEventHandler('onClearRecord') ?>"
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>"
data-request-success="var $locker = $('#<?= $field->getId() ?>'); $locker.val(''); $locker.trigger('change')"
aria-label="Remove">
<i class="icon-times"></i>
</button>
<?php endif ?>
<button
id="<?= $this->getId('popupTrigger') ?>"
class="btn btn-default find-record"
data-control="popup"
data-size="huge"
data-handler="<?= $this->getEventHandler('onFindRecord') ?>"
data-request-data="recordfinder_flag: 1"
type="button">
<i class="icon-th-list"></i>
</button>
<?php endif ?>
<input
type="hidden"
name="<?= $field->getName() ?>"
id="<?= $field->getId() ?>"
value="<?= e($value) ?>"
/>
</div>

View File

@@ -0,0 +1,29 @@
<div id="<?= $this->getId('popup') ?>" class="recordfinder-popup">
<?= Form::open(['data-request-parent' => "#{$parentElementId}"]) ?>
<div class="modal-header">
<button type="button" class="close" data-dismiss="popup">&times;</button>
<h4 class="modal-title"><?= e(trans($title)) ?></h4>
</div>
<div class="recordfinder-list list-flush" data-request-data="recordfinder_flag: 1">
<?= $searchWidget->render() ?>
<?= $listWidget->render() ?>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-default"
data-dismiss="popup">
<?= e(trans('backend::lang.recordfinder.cancel')) ?>
</button>
</div>
<?= Form::close() ?>
</div>
<script>
setTimeout(
function(){ $('#<?= $this->getId('popup') ?> input.form-control:first').focus() },
310
)
</script>