Test module
This commit is contained in:
13
modules/project_pro_news/config.xml
Normal file
13
modules/project_pro_news/config.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<module>
|
||||
<name>project_pro_news</name>
|
||||
<displayName><![CDATA[Project Pro: News slider (category products)]]></displayName>
|
||||
<version><![CDATA[1.0.1]]></version>
|
||||
<author><![CDATA[Custom]]></author>
|
||||
<tab><![CDATA[front_office_features]]></tab>
|
||||
<description><![CDATA[Shows products from selected category as a slider with configurable title, subtitle and button (multilanguage).]]></description>
|
||||
<confirmUninstall><![CDATA[Are you sure you want to uninstall?]]></confirmUninstall>
|
||||
<is_configurable>1</is_configurable>
|
||||
<need_instance>0</need_instance>
|
||||
<limited_countries></limited_countries>
|
||||
</module>
|
||||
10
modules/project_pro_news/index.php
Normal file
10
modules/project_pro_news/index.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../');
|
||||
exit;
|
||||
BIN
modules/project_pro_news/logo.png
Normal file
BIN
modules/project_pro_news/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
405
modules/project_pro_news/project_pro_news.php
Normal file
405
modules/project_pro_news/project_pro_news.php
Normal file
@@ -0,0 +1,405 @@
|
||||
<?php
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use PrestaShop\PrestaShop\Adapter\Image\ImageRetriever;
|
||||
use PrestaShop\PrestaShop\Adapter\Product\PriceFormatter;
|
||||
use PrestaShop\PrestaShop\Adapter\Product\ProductColorsRetriever;
|
||||
use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductPresenterFactory;
|
||||
use PrestaShop\PrestaShop\Adapter\Product\ProductAssembler;
|
||||
use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductListingPresenter;
|
||||
|
||||
class Project_Pro_News extends Module
|
||||
{
|
||||
const CFG_CATEGORY_ID = 'PROJECT_PRO_NEWS_CATEGORY_ID';
|
||||
const CFG_MAX_PRODUCTS = 'PROJECT_PRO_NEWS_MAX_PRODUCTS';
|
||||
const CFG_TITLE = 'PROJECT_PRO_NEWS_TITLE';
|
||||
const CFG_SUBTITLE = 'PROJECT_PRO_NEWS_SUBTITLE';
|
||||
const CFG_BUTTON_LABEL = 'PROJECT_PRO_NEWS_BUTTON_LABEL';
|
||||
const CFG_BUTTON_URL = 'PROJECT_PRO_NEWS_BUTTON_URL';
|
||||
const CFG_PRICE_SUFFIX = 'PROJECT_PRO_NEWS_PRICE_SUFFIX';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->name = 'project_pro_news';
|
||||
$this->tab = 'front_office_features';
|
||||
$this->version = '1.0.1';
|
||||
$this->author = 'RomekDev';
|
||||
$this->need_instance = 0;
|
||||
$this->bootstrap = true;
|
||||
|
||||
parent::__construct();
|
||||
|
||||
$this->displayName = $this->l('Project Pro: News slider (category products)');
|
||||
$this->description = $this->l('Shows products from selected category as a slider with configurable title, subtitle and button (multilanguage).');
|
||||
|
||||
$this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
|
||||
}
|
||||
|
||||
public function install()
|
||||
{
|
||||
return parent::install()
|
||||
&& $this->registerHook('displayHome')
|
||||
&& $this->registerHook('displayHeader')
|
||||
&& $this->setDefaultConfig();
|
||||
}
|
||||
|
||||
public function uninstall()
|
||||
{
|
||||
$this->deleteConfig();
|
||||
return parent::uninstall();
|
||||
}
|
||||
|
||||
private function setDefaultConfig()
|
||||
{
|
||||
$langs = Language::getLanguages(false);
|
||||
$title = [];
|
||||
$subtitle = [];
|
||||
$btn = [];
|
||||
$suffix = [];
|
||||
|
||||
foreach ($langs as $lang) {
|
||||
$id = (int)$lang['id_lang'];
|
||||
$title[$id] = 'Nowości';
|
||||
$subtitle[$id] = 'znajdź swoją inspirację';
|
||||
$btn[$id] = 'Zobacz więcej';
|
||||
$suffix[$id] = ''; // наприклад: '/m²'
|
||||
}
|
||||
|
||||
Configuration::updateValue(self::CFG_CATEGORY_ID, 0);
|
||||
Configuration::updateValue(self::CFG_MAX_PRODUCTS, 12);
|
||||
Configuration::updateValue(self::CFG_BUTTON_URL, '');
|
||||
|
||||
Configuration::updateValue(self::CFG_TITLE, $title, true);
|
||||
Configuration::updateValue(self::CFG_SUBTITLE, $subtitle, true);
|
||||
Configuration::updateValue(self::CFG_BUTTON_LABEL, $btn, true);
|
||||
Configuration::updateValue(self::CFG_PRICE_SUFFIX, $suffix, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function deleteConfig()
|
||||
{
|
||||
Configuration::deleteByName(self::CFG_CATEGORY_ID);
|
||||
Configuration::deleteByName(self::CFG_MAX_PRODUCTS);
|
||||
Configuration::deleteByName(self::CFG_TITLE);
|
||||
Configuration::deleteByName(self::CFG_SUBTITLE);
|
||||
Configuration::deleteByName(self::CFG_BUTTON_LABEL);
|
||||
Configuration::deleteByName(self::CFG_BUTTON_URL);
|
||||
Configuration::deleteByName(self::CFG_PRICE_SUFFIX);
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
$output = '';
|
||||
|
||||
if (Tools::isSubmit('submitProjectProNews')) {
|
||||
try {
|
||||
$categoryId = (int)Tools::getValue(self::CFG_CATEGORY_ID);
|
||||
$max = (int)Tools::getValue(self::CFG_MAX_PRODUCTS);
|
||||
$buttonUrl = trim((string)Tools::getValue(self::CFG_BUTTON_URL));
|
||||
|
||||
if ($max <= 0) {
|
||||
$max = 12;
|
||||
}
|
||||
|
||||
$langs = Language::getLanguages(false);
|
||||
$title = [];
|
||||
$subtitle = [];
|
||||
$btn = [];
|
||||
$suffix = [];
|
||||
|
||||
foreach ($langs as $lang) {
|
||||
$id = (int)$lang['id_lang'];
|
||||
|
||||
$title[$id] = (string)Tools::getValue(self::CFG_TITLE . '_' . $id);
|
||||
$subtitle[$id] = (string)Tools::getValue(self::CFG_SUBTITLE . '_' . $id);
|
||||
$btn[$id] = (string)Tools::getValue(self::CFG_BUTTON_LABEL . '_' . $id);
|
||||
$suffix[$id] = (string)Tools::getValue(self::CFG_PRICE_SUFFIX . '_' . $id);
|
||||
|
||||
// на всяк випадок обрізаємо (щоб не вбити конфіг через дуже довгий текст)
|
||||
$title[$id] = Tools::substr($title[$id], 0, 255);
|
||||
$subtitle[$id] = Tools::substr($subtitle[$id], 0, 255);
|
||||
$btn[$id] = Tools::substr($btn[$id], 0, 255);
|
||||
$suffix[$id] = Tools::substr($suffix[$id], 0, 64);
|
||||
}
|
||||
|
||||
if (!Configuration::updateValue(self::CFG_CATEGORY_ID, $categoryId)) {
|
||||
throw new Exception('Cannot save category id');
|
||||
}
|
||||
if (!Configuration::updateValue(self::CFG_MAX_PRODUCTS, $max)) {
|
||||
throw new Exception('Cannot save max products');
|
||||
}
|
||||
if (!Configuration::updateValue(self::CFG_BUTTON_URL, $buttonUrl)) {
|
||||
throw new Exception('Cannot save button url');
|
||||
}
|
||||
|
||||
if (!Configuration::updateValue(self::CFG_TITLE, $title, true)) {
|
||||
throw new Exception('Cannot save title');
|
||||
}
|
||||
if (!Configuration::updateValue(self::CFG_SUBTITLE, $subtitle, true)) {
|
||||
throw new Exception('Cannot save subtitle');
|
||||
}
|
||||
if (!Configuration::updateValue(self::CFG_BUTTON_LABEL, $btn, true)) {
|
||||
throw new Exception('Cannot save button label');
|
||||
}
|
||||
if (!Configuration::updateValue(self::CFG_PRICE_SUFFIX, $suffix, true)) {
|
||||
throw new Exception('Cannot save price suffix');
|
||||
}
|
||||
|
||||
$output .= $this->displayConfirmation($this->l('Settings saved.'));
|
||||
} catch (Exception $e) {
|
||||
$output .= $this->displayError('Save error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $output . $this->renderForm();
|
||||
}
|
||||
|
||||
private function renderForm()
|
||||
{
|
||||
$defaultLang = (int)Configuration::get('PS_LANG_DEFAULT');
|
||||
|
||||
$categories = Category::getCategories($defaultLang, true, false);
|
||||
$categoryOptions = $this->flattenCategoriesForSelect($categories);
|
||||
|
||||
$fieldsForm = [
|
||||
'form' => [
|
||||
'legend' => [
|
||||
'title' => $this->l('Project Pro News: settings'),
|
||||
'icon' => 'icon-cogs',
|
||||
],
|
||||
'input' => [
|
||||
[
|
||||
'type' => 'select',
|
||||
'label' => $this->l('Category (source products)'),
|
||||
'name' => self::CFG_CATEGORY_ID,
|
||||
'options' => [
|
||||
'query' => $categoryOptions,
|
||||
'id' => 'id',
|
||||
'name' => 'name',
|
||||
],
|
||||
'required' => true,
|
||||
'desc' => $this->l('Select category that contains the products (e.g. Nowości).'),
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Max products'),
|
||||
'name' => self::CFG_MAX_PRODUCTS,
|
||||
'class' => 'fixed-width-sm',
|
||||
'required' => true,
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Title'),
|
||||
'name' => self::CFG_TITLE,
|
||||
'lang' => true,
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Subtitle'),
|
||||
'name' => self::CFG_SUBTITLE,
|
||||
'lang' => true,
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Button label'),
|
||||
'name' => self::CFG_BUTTON_LABEL,
|
||||
'lang' => true,
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Button URL'),
|
||||
'name' => self::CFG_BUTTON_URL,
|
||||
'desc' => $this->l('Leave empty to link to selected category automatically.'),
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Price suffix (optional)'),
|
||||
'name' => self::CFG_PRICE_SUFFIX,
|
||||
'lang' => true,
|
||||
'desc' => $this->l('Example: /m²'),
|
||||
],
|
||||
],
|
||||
'submit' => [
|
||||
'title' => $this->l('Save'),
|
||||
'name' => 'submitProjectProNews',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$helper = new HelperForm();
|
||||
$helper->show_toolbar = false;
|
||||
$helper->table = $this->table;
|
||||
$helper->module = $this;
|
||||
$helper->default_form_language = $defaultLang;
|
||||
$helper->allow_employee_form_lang = (int)Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG');
|
||||
$helper->identifier = $this->identifier;
|
||||
$helper->submit_action = 'submitProjectProNews';
|
||||
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
|
||||
$helper->token = Tools::getAdminTokenLite('AdminModules');
|
||||
|
||||
$helper->languages = $this->context->controller->getLanguages();
|
||||
$helper->id_language = (int)$this->context->language->id;
|
||||
|
||||
$helper->fields_value[self::CFG_CATEGORY_ID] = (int)Configuration::get(self::CFG_CATEGORY_ID);
|
||||
$helper->fields_value[self::CFG_MAX_PRODUCTS] = (int)Configuration::get(self::CFG_MAX_PRODUCTS);
|
||||
$helper->fields_value[self::CFG_BUTTON_URL] = (string)Configuration::get(self::CFG_BUTTON_URL);
|
||||
|
||||
$langs = Language::getLanguages(false);
|
||||
foreach ($langs as $lang) {
|
||||
$id = (int)$lang['id_lang'];
|
||||
$helper->fields_value[self::CFG_TITLE][$id] = (string)Configuration::get(self::CFG_TITLE, $id);
|
||||
$helper->fields_value[self::CFG_SUBTITLE][$id] = (string)Configuration::get(self::CFG_SUBTITLE, $id);
|
||||
$helper->fields_value[self::CFG_BUTTON_LABEL][$id] = (string)Configuration::get(self::CFG_BUTTON_LABEL, $id);
|
||||
$helper->fields_value[self::CFG_PRICE_SUFFIX][$id] = (string)Configuration::get(self::CFG_PRICE_SUFFIX, $id);
|
||||
}
|
||||
|
||||
return $helper->generateForm([$fieldsForm]);
|
||||
}
|
||||
|
||||
private function flattenCategoriesForSelect($categoriesTree, $depth = 0, &$out = [])
|
||||
{
|
||||
foreach ($categoriesTree as $node) {
|
||||
if (!isset($node['id_category'], $node['name'])) {
|
||||
continue;
|
||||
}
|
||||
$prefix = str_repeat('—', max(0, $depth));
|
||||
$out[] = [
|
||||
'id' => (int)$node['id_category'],
|
||||
'name' => trim($prefix . ' ' . $node['name']),
|
||||
];
|
||||
if (!empty($node['children'])) {
|
||||
$this->flattenCategoriesForSelect($node['children'], $depth + 1, $out);
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function hookDisplayHeader()
|
||||
{
|
||||
$this->context->controller->registerStylesheet(
|
||||
'project_pro_news_swiper_css',
|
||||
'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.css',
|
||||
['media' => 'all', 'priority' => 150]
|
||||
);
|
||||
|
||||
$this->context->controller->registerStylesheet(
|
||||
'project_pro_news_css',
|
||||
'modules/' . $this->name . '/views/css/project_pro_news.css',
|
||||
['media' => 'all', 'priority' => 151]
|
||||
);
|
||||
|
||||
$this->context->controller->registerJavascript(
|
||||
'project_pro_news_swiper_js',
|
||||
'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.js',
|
||||
['position' => 'bottom', 'priority' => 150]
|
||||
);
|
||||
|
||||
$this->context->controller->registerJavascript(
|
||||
'project_pro_news_js',
|
||||
'modules/' . $this->name . '/views/js/project_pro_news.js',
|
||||
['position' => 'bottom', 'priority' => 151]
|
||||
);
|
||||
}
|
||||
|
||||
public function hookDisplayHome($params)
|
||||
{
|
||||
return $this->renderWidget('displayHome', []);
|
||||
}
|
||||
|
||||
public function renderWidget($hookName = null, array $configuration = [])
|
||||
{
|
||||
$categoryId = (int)Configuration::get(self::CFG_CATEGORY_ID);
|
||||
$max = (int)Configuration::get(self::CFG_MAX_PRODUCTS);
|
||||
if ($max <= 0) {
|
||||
$max = 12;
|
||||
}
|
||||
|
||||
if ($categoryId <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$idLang = (int)$this->context->language->id;
|
||||
|
||||
$title = (string)Configuration::get(self::CFG_TITLE, $idLang);
|
||||
$subtitle = (string)Configuration::get(self::CFG_SUBTITLE, $idLang);
|
||||
$buttonLabel = (string)Configuration::get(self::CFG_BUTTON_LABEL, $idLang);
|
||||
$buttonUrl = trim((string)Configuration::get(self::CFG_BUTTON_URL));
|
||||
$priceSuffix = (string)Configuration::get(self::CFG_PRICE_SUFFIX, $idLang);
|
||||
|
||||
$category = new Category($categoryId, $idLang);
|
||||
if (!Validate::isLoadedObject($category)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($buttonUrl === '') {
|
||||
$buttonUrl = $this->context->link->getCategoryLink($category);
|
||||
}
|
||||
|
||||
$products = $this->getCategoryProductsPresented($categoryId, $max);
|
||||
|
||||
$this->context->smarty->assign([
|
||||
'ppn_title' => $title,
|
||||
'ppn_subtitle' => $subtitle,
|
||||
'ppn_button_label' => $buttonLabel,
|
||||
'ppn_button_url' => $buttonUrl,
|
||||
'ppn_price_suffix' => $priceSuffix,
|
||||
'ppn_products' => $products,
|
||||
]);
|
||||
|
||||
return $this->fetch('module:' . $this->name . '/views/templates/hook/project_pro_news.tpl');
|
||||
}
|
||||
|
||||
public function getWidgetVariables($hookName = null, array $configuration = [])
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
private function getCategoryProductsPresented($categoryId, $limit)
|
||||
{
|
||||
$idLang = (int)$this->context->language->id;
|
||||
|
||||
$rawProducts = Category::getProducts(
|
||||
(int)$categoryId,
|
||||
$idLang,
|
||||
1,
|
||||
(int)$limit,
|
||||
'position',
|
||||
'asc'
|
||||
);
|
||||
|
||||
if (empty($rawProducts)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$assembler = new ProductAssembler($this->context);
|
||||
$presenterFactory = new ProductPresenterFactory($this->context);
|
||||
|
||||
$presentationSettings = $presenterFactory->getPresentationSettings();
|
||||
$imageRetriever = new ImageRetriever($this->context->link);
|
||||
$priceFormatter = new PriceFormatter();
|
||||
$colorsRetriever = new ProductColorsRetriever();
|
||||
|
||||
$listingPresenter = new ProductListingPresenter(
|
||||
$imageRetriever,
|
||||
$this->context->link,
|
||||
$priceFormatter,
|
||||
$colorsRetriever,
|
||||
$this->getTranslator()
|
||||
);
|
||||
|
||||
$products = [];
|
||||
foreach ($rawProducts as $raw) {
|
||||
$assembled = $assembler->assembleProduct($raw);
|
||||
$products[] = $listingPresenter->present(
|
||||
$presentationSettings,
|
||||
$assembled,
|
||||
$this->context->language
|
||||
);
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
}
|
||||
133
modules/project_pro_news/views/css/project_pro_news.css
Normal file
133
modules/project_pro_news/views/css/project_pro_news.css
Normal file
@@ -0,0 +1,133 @@
|
||||
.project-pro-news {
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
.project-pro-news__header {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.project-pro-news__title {
|
||||
font-size: 42px;
|
||||
line-height: 1.1;
|
||||
margin: 0 0 6px 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.project-pro-news__subtitle {
|
||||
font-size: 44px;
|
||||
line-height: 1.1;
|
||||
font-weight: 300;
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
.project-pro-news__slider {
|
||||
position: relative;
|
||||
padding: 10px 0 0 0;
|
||||
}
|
||||
|
||||
.project-pro-news__card {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.project-pro-news__image {
|
||||
display: block;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.project-pro-news__image img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.project-pro-news__meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 14px 2px 0 2px;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.project-pro-news__name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.project-pro-news__price {
|
||||
font-size: 16px;
|
||||
opacity: .7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.project-pro-news__priceSuffix {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.project-pro-news__footer {
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.project-pro-news__more {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
text-decoration: none;
|
||||
opacity: .75;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.project-pro-news__more:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 28px;
|
||||
height: 1px;
|
||||
background: currentColor;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.project-pro-news__nav .project-pro-news__prev,
|
||||
.project-pro-news__nav .project-pro-news__next {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
transform: translateY(-50%);
|
||||
cursor: pointer;
|
||||
opacity: .6;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.project-pro-news__nav .project-pro-news__prev { left: -10px; }
|
||||
.project-pro-news__nav .project-pro-news__next { right: -10px; }
|
||||
|
||||
.project-pro-news__nav .project-pro-news__prev:after,
|
||||
.project-pro-news__nav .project-pro-news__next:after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-right: 2px solid currentColor;
|
||||
border-bottom: 2px solid currentColor;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.project-pro-news__nav .project-pro-news__prev:after {
|
||||
transform: translate(-50%, -50%) rotate(135deg);
|
||||
}
|
||||
|
||||
.project-pro-news__nav .project-pro-news__next:after {
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.project-pro-news__title { font-size: 34px; }
|
||||
.project-pro-news__subtitle { font-size: 34px; }
|
||||
.project-pro-news__nav .project-pro-news__prev { left: 0; }
|
||||
.project-pro-news__nav .project-pro-news__next { right: 0; }
|
||||
}
|
||||
19
modules/project_pro_news/views/js/project_pro_news.js
Normal file
19
modules/project_pro_news/views/js/project_pro_news.js
Normal file
@@ -0,0 +1,19 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var el = document.querySelector('.project-pro-news__slider.swiper');
|
||||
if (!el || typeof Swiper === 'undefined') return;
|
||||
|
||||
new Swiper(el, {
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 26,
|
||||
loop: false,
|
||||
navigation: {
|
||||
nextEl: '.project-pro-news__next',
|
||||
prevEl: '.project-pro-news__prev'
|
||||
},
|
||||
breakpoints: {
|
||||
0: { slidesPerView: 1.15, spaceBetween: 16 },
|
||||
576: { slidesPerView: 2, spaceBetween: 18 },
|
||||
992: { slidesPerView: 3, spaceBetween: 26 }
|
||||
}
|
||||
});
|
||||
});
|
||||
13
modules/project_pro_news/views/lib/swiper/swiper-bundle.min.css
vendored
Normal file
13
modules/project_pro_news/views/lib/swiper/swiper-bundle.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7661
modules/project_pro_news/views/lib/swiper/swiper-bundle.min.js
vendored
Normal file
7661
modules/project_pro_news/views/lib/swiper/swiper-bundle.min.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
<section class="project-pro-news">
|
||||
<div class="project-pro-news__header">
|
||||
{if $ppn_title}
|
||||
<h2 class="project-pro-news__title">{$ppn_title|escape:'htmlall':'UTF-8'}</h2>
|
||||
{/if}
|
||||
|
||||
{if $ppn_subtitle}
|
||||
<div class="project-pro-news__subtitle">{$ppn_subtitle|escape:'htmlall':'UTF-8'}</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{if $ppn_products|count > 0}
|
||||
<div class="project-pro-news__slider swiper">
|
||||
<div class="swiper-wrapper">
|
||||
{foreach from=$ppn_products item=product}
|
||||
<div class="swiper-slide">
|
||||
<article class="project-pro-news__card">
|
||||
<a class="project-pro-news__image" href="{$product.url}" title="{$product.name|escape:'htmlall':'UTF-8'}">
|
||||
{if isset($product.cover.bySize.home_default.url)}
|
||||
<img src="{$product.cover.bySize.home_default.url}" alt="{$product.name|escape:'htmlall':'UTF-8'}" loading="lazy">
|
||||
{elseif isset($product.cover.large.url)}
|
||||
<img src="{$product.cover.large.url}" alt="{$product.name|escape:'htmlall':'UTF-8'}" loading="lazy">
|
||||
{/if}
|
||||
</a>
|
||||
|
||||
<div class="project-pro-news__meta">
|
||||
<a class="project-pro-news__name" href="{$product.url}">
|
||||
{$product.name|escape:'htmlall':'UTF-8'}
|
||||
</a>
|
||||
|
||||
{if isset($product.price) && $product.price}
|
||||
<div class="project-pro-news__price">
|
||||
{$product.price}
|
||||
{if $ppn_price_suffix}
|
||||
<span class="project-pro-news__priceSuffix">{$ppn_price_suffix|escape:'htmlall':'UTF-8'}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
|
||||
<div class="project-pro-news__nav">
|
||||
<div class="project-pro-news__prev" aria-label="Prev"></div>
|
||||
<div class="project-pro-news__next" aria-label="Next"></div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if $ppn_button_label && $ppn_button_url}
|
||||
<div class="project-pro-news__footer">
|
||||
<a class="project-pro-news__more" href="{$ppn_button_url|escape:'htmlall':'UTF-8'}">
|
||||
{$ppn_button_label|escape:'htmlall':'UTF-8'}
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
Reference in New Issue
Block a user