feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
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:
328
modules/backend/models/Preference.php
Normal file
328
modules/backend/models/Preference.php
Normal file
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
namespace Backend\Models;
|
||||
|
||||
use Backend\Facades\BackendAuth;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use DirectoryIterator;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Winter\Storm\Database\Model;
|
||||
use Winter\Storm\Support\Facades\Config;
|
||||
|
||||
/**
|
||||
* Backend preferences for the backend user
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class Preference extends Model
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\Validation;
|
||||
|
||||
const DEFAULT_THEME = 'twilight.tmTheme';
|
||||
|
||||
/**
|
||||
* @var array Behaviors implemented by this model.
|
||||
*/
|
||||
public $implement = [
|
||||
\Backend\Behaviors\UserPreferencesModel::class
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string Unique code
|
||||
*/
|
||||
public $settingsCode = 'backend::backend.preferences';
|
||||
|
||||
/**
|
||||
* @var mixed Settings form field defitions
|
||||
*/
|
||||
public $settingsFields = 'fields.yaml';
|
||||
|
||||
/**
|
||||
* @var array Validation rules
|
||||
*/
|
||||
public $rules = [];
|
||||
|
||||
/**
|
||||
* Initialize the seed data for this model. This only executes when the
|
||||
* model is first created or reset to default.
|
||||
* @return void
|
||||
*/
|
||||
public function initSettingsData()
|
||||
{
|
||||
$config = App::make('config');
|
||||
$this->locale = $config->get('app.locale', 'en');
|
||||
$this->fallback_locale = $this->getFallbackLocale($this->locale);
|
||||
$this->timezone = $config->get('cms.backendTimezone', $config->get('app.timezone'));
|
||||
|
||||
$this->editor_font_size = $config->get('editor.font_size', 12);
|
||||
$this->editor_word_wrap = $config->get('editor.word_wrap', 'fluid');
|
||||
$this->editor_code_folding = $config->get('editor.code_folding', 'manual');
|
||||
// @deprecated v1.3.0
|
||||
$this->editor_enable_folding = $config->get('editor.enable_folding', $config->get('editor.code_folding', 'manual') !== 'manual');
|
||||
$this->editor_tab_size = $config->get('editor.tab_size', 4);
|
||||
$this->editor_theme = $config->get('editor.theme', static::DEFAULT_THEME);
|
||||
$this->editor_show_invisibles = $config->get('editor.show_invisibles', false);
|
||||
$this->editor_highlight_active_line = $config->get('editor.highlight_active_line', true);
|
||||
$this->editor_use_hard_tabs = $config->get('editor.use_hard_tabs', false);
|
||||
$this->editor_show_gutter = $config->get('editor.show_gutter', true);
|
||||
$this->editor_auto_closing = $config->get('editor.auto_closing', false);
|
||||
$this->editor_autocompletion = $config->get('editor.editor_autocompletion', 'manual');
|
||||
$this->editor_enable_snippets = $config->get('editor.enable_snippets', false);
|
||||
$this->editor_display_indent_guides = $config->get('editor.display_indent_guides', false);
|
||||
$this->editor_show_print_margin = $config->get('editor.show_print_margin', false);
|
||||
$this->editor_show_minimap = $config->get('editor.show_minimap', true);
|
||||
$this->editor_bracket_colors = $config->get('editor.bracket_colors', false);
|
||||
$this->editor_show_colors = $config->get('editor.show_colors', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the application's locale based on the user preference.
|
||||
* @return void
|
||||
*/
|
||||
public static function setAppLocale()
|
||||
{
|
||||
if (Session::has('locale')) {
|
||||
App::setLocale(Session::get('locale'));
|
||||
}
|
||||
elseif (
|
||||
($user = BackendAuth::getUser()) &&
|
||||
($locale = static::get('locale'))
|
||||
) {
|
||||
Session::put('locale', $locale);
|
||||
App::setLocale($locale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as setAppLocale except for the fallback definition.
|
||||
* @return void
|
||||
*/
|
||||
public static function setAppFallbackLocale()
|
||||
{
|
||||
if (Session::has('fallback_locale')) {
|
||||
Lang::setFallback(Session::get('fallback_locale'));
|
||||
}
|
||||
elseif (
|
||||
($user = BackendAuth::getUser()) &&
|
||||
($locale = static::get('fallback_locale'))
|
||||
) {
|
||||
Session::put('fallback_locale', $locale);
|
||||
Lang::setFallback($locale);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Events
|
||||
//
|
||||
|
||||
public function beforeValidate()
|
||||
{
|
||||
$this->fallback_locale = $this->getFallbackLocale($this->locale);
|
||||
}
|
||||
|
||||
public function afterSave()
|
||||
{
|
||||
Session::put('locale', $this->locale);
|
||||
Session::put('fallback_locale', $this->fallback_locale);
|
||||
}
|
||||
|
||||
//
|
||||
// Utils
|
||||
//
|
||||
|
||||
/**
|
||||
* Called when this model is reset to default by the user.
|
||||
* @return void
|
||||
*/
|
||||
public function resetDefault()
|
||||
{
|
||||
parent::resetDefault();
|
||||
Session::forget('locale');
|
||||
Session::forget('fallback_locale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the config with the user's preference.
|
||||
* @return void
|
||||
*/
|
||||
public static function applyConfigValues()
|
||||
{
|
||||
$settings = self::instance();
|
||||
Config::set('app.locale', $settings->locale);
|
||||
Config::set('app.fallback_locale', $settings->fallback_locale);
|
||||
}
|
||||
|
||||
//
|
||||
// Getters
|
||||
//
|
||||
|
||||
/**
|
||||
* Attempt to extract the language from the locale,
|
||||
* otherwise use the configuration.
|
||||
* @return string
|
||||
*/
|
||||
protected function getFallbackLocale($locale)
|
||||
{
|
||||
if ($position = strpos($locale, '-')) {
|
||||
$target = substr($locale, 0, $position);
|
||||
$available = $this->getLocaleOptions();
|
||||
if (isset($available[$target])) {
|
||||
return $target;
|
||||
}
|
||||
}
|
||||
|
||||
return Config::get('app.fallback_locale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns available options for the "locale" attribute.
|
||||
* @return array
|
||||
*/
|
||||
public function getLocaleOptions()
|
||||
{
|
||||
$localeOptions = [
|
||||
'ar' => [Lang::get('system::lang.locale.ar'), 'flag-sa'],
|
||||
'be' => [Lang::get('system::lang.locale.be'), 'flag-by'],
|
||||
'bg' => [Lang::get('system::lang.locale.bg'), 'flag-bg'],
|
||||
'ca' => [Lang::get('system::lang.locale.ca'), 'flag-es-ct'],
|
||||
'cs' => [Lang::get('system::lang.locale.cs'), 'flag-cz'],
|
||||
'da' => [Lang::get('system::lang.locale.da'), 'flag-dk'],
|
||||
'de' => [Lang::get('system::lang.locale.de'), 'flag-de'],
|
||||
'el' => [Lang::get('system::lang.locale.el'), 'flag-gr'],
|
||||
'en' => [Lang::get('system::lang.locale.en'), 'flag-us'],
|
||||
'en-au' => [Lang::get('system::lang.locale.en-au'), 'flag-au'],
|
||||
'en-ca' => [Lang::get('system::lang.locale.en-ca'), 'flag-ca'],
|
||||
'en-gb' => [Lang::get('system::lang.locale.en-gb'), 'flag-gb'],
|
||||
'es' => [Lang::get('system::lang.locale.es'), 'flag-es'],
|
||||
'es-ar' => [Lang::get('system::lang.locale.es-ar'), 'flag-ar'],
|
||||
'et' => [Lang::get('system::lang.locale.et'), 'flag-ee'],
|
||||
'fa' => [Lang::get('system::lang.locale.fa'), 'flag-ir'],
|
||||
'fi' => [Lang::get('system::lang.locale.fi'), 'flag-fi'],
|
||||
'fr' => [Lang::get('system::lang.locale.fr'), 'flag-fr'],
|
||||
'fr-ca' => [Lang::get('system::lang.locale.fr-ca'), 'flag-ca'],
|
||||
'hu' => [Lang::get('system::lang.locale.hu'), 'flag-hu'],
|
||||
'id' => [Lang::get('system::lang.locale.id'), 'flag-id'],
|
||||
'it' => [Lang::get('system::lang.locale.it'), 'flag-it'],
|
||||
'ja' => [Lang::get('system::lang.locale.ja'), 'flag-jp'],
|
||||
'kr' => [Lang::get('system::lang.locale.kr'), 'flag-kr'],
|
||||
'lt' => [Lang::get('system::lang.locale.lt'), 'flag-lt'],
|
||||
'lv' => [Lang::get('system::lang.locale.lv'), 'flag-lv'],
|
||||
'nb-no' => [Lang::get('system::lang.locale.nb-no'), 'flag-no'],
|
||||
'nl' => [Lang::get('system::lang.locale.nl'), 'flag-nl'],
|
||||
'pl' => [Lang::get('system::lang.locale.pl'), 'flag-pl'],
|
||||
'pt-br' => [Lang::get('system::lang.locale.pt-br'), 'flag-br'],
|
||||
'pt-pt' => [Lang::get('system::lang.locale.pt-pt'), 'flag-pt'],
|
||||
'ro' => [Lang::get('system::lang.locale.ro'), 'flag-ro'],
|
||||
'rs' => [Lang::get('system::lang.locale.rs'), 'flag-rs'],
|
||||
'ru' => [Lang::get('system::lang.locale.ru'), 'flag-ru'],
|
||||
'sk' => [Lang::get('system::lang.locale.sk'), 'flag-sk'],
|
||||
'sl' => [Lang::get('system::lang.locale.sl'), 'flag-si'],
|
||||
'sv' => [Lang::get('system::lang.locale.sv'), 'flag-se'],
|
||||
'th' => [Lang::get('system::lang.locale.th'), 'flag-th'],
|
||||
'tr' => [Lang::get('system::lang.locale.tr'), 'flag-tr'],
|
||||
'uk' => [Lang::get('system::lang.locale.uk'), 'flag-ua'],
|
||||
'vn' => [Lang::get('system::lang.locale.vn'), 'flag-vn'],
|
||||
'zh-cn' => [Lang::get('system::lang.locale.zh-cn'), 'flag-cn'],
|
||||
'zh-tw' => [Lang::get('system::lang.locale.zh-tw'), 'flag-tw'],
|
||||
];
|
||||
|
||||
$locales = Config::get('app.localeOptions', $localeOptions);
|
||||
|
||||
// Sort locales alphabetically
|
||||
asort($locales);
|
||||
|
||||
return $locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available timezone options.
|
||||
* @return array
|
||||
*/
|
||||
public function getTimezoneOptions()
|
||||
{
|
||||
$timezoneIdentifiers = DateTimeZone::listIdentifiers();
|
||||
$utcTime = new DateTime('now', new DateTimeZone('UTC'));
|
||||
|
||||
$tempTimezones = [];
|
||||
foreach ($timezoneIdentifiers as $timezoneIdentifier) {
|
||||
$currentTimezone = new DateTimeZone($timezoneIdentifier);
|
||||
|
||||
$tempTimezones[] = [
|
||||
'offset' => (int) $currentTimezone->getOffset($utcTime),
|
||||
'identifier' => $timezoneIdentifier
|
||||
];
|
||||
}
|
||||
|
||||
// Sort the array by offset, identifier ascending
|
||||
usort($tempTimezones, function ($a, $b) {
|
||||
return $a['offset'] === $b['offset']
|
||||
? strcmp($a['identifier'], $b['identifier'])
|
||||
: $a['offset'] - $b['offset'];
|
||||
});
|
||||
|
||||
$timezoneList = [];
|
||||
foreach ($tempTimezones as $tz) {
|
||||
$sign = $tz['offset'] > 0 ? '+' : '-';
|
||||
$offset = gmdate('H:i', abs($tz['offset']));
|
||||
$timezoneList[$tz['identifier']] = '(UTC ' . $sign . $offset . ') ' . $tz['identifier'];
|
||||
}
|
||||
|
||||
return $timezoneList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the theme options for the backend editor.
|
||||
* Supports both legacy tmTheme (XML) and modern JSON theme formats.
|
||||
*/
|
||||
public function getEditorThemeOptions(): array
|
||||
{
|
||||
$themeDir = new DirectoryIterator('modules/backend/formwidgets/codeeditor/assets/themes/');
|
||||
$themes = [];
|
||||
|
||||
// Iterate through the themes
|
||||
foreach ($themeDir as $node) {
|
||||
if (!$node->isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extension = $node->getExtension();
|
||||
|
||||
// Support both tmTheme (legacy) and JSON (modern) formats
|
||||
if ($extension === 'tmTheme' || $extension === 'json') {
|
||||
// Theme ID includes the file extension (e.g., "twilight.tmTheme", "one-dark-pro.json")
|
||||
$themeId = $node->getBasename();
|
||||
// Display name strips the extension for user-friendly presentation
|
||||
$themeNameBase = $node->getBasename('.' . $extension);
|
||||
$themeName = ucwords(str_replace(['_', '-'], ' ', $themeNameBase));
|
||||
|
||||
// Add the values to the themes array
|
||||
if ($themeId != static::DEFAULT_THEME) {
|
||||
$themes[$themeId] = $themeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the theme alphabetically, and push the default theme
|
||||
asort($themes);
|
||||
// Strip extension from default theme for display name
|
||||
$defaultThemeName = ucwords(str_replace(['_', '-'], ' ', pathinfo(static::DEFAULT_THEME, PATHINFO_FILENAME)));
|
||||
return [static::DEFAULT_THEME => $defaultThemeName] + $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the word wrap options for the backend editor.
|
||||
*/
|
||||
public function getEditorWordWrapOptions(): array
|
||||
{
|
||||
return [
|
||||
'off' => Lang::get('backend::lang.editor.mode_off'),
|
||||
'40' => Lang::get('backend::lang.editor.40_characters'),
|
||||
'80' => Lang::get('backend::lang.editor.80_characters'),
|
||||
'fluid' => Lang::get('backend::lang.editor.mode_fluid'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user