[FW][IMP] website_sale: new templates for s_dynamic_snippet_products

This branch add new template for the **s_dynamic_snippet_products** and adapt the current ones.

task-2602978
#75623

closes odoo/odoo#77153

Forward-port-of: odoo/odoo#75623
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
This commit is contained in:
Odoo's Mergebot
2021-09-24 14:35:39 +02:00
committed by GitHub
6 changed files with 322 additions and 37 deletions
+26 -10
View File
@@ -9,18 +9,34 @@
<t t-set="val_integer" t-value="int(rating_avg)"/>
<t t-set="empty_star" t-value="5 - (val_integer+1) if val_decimal else 5 - val_integer"/>
<div class="o_website_rating_static" t-att-style="inline_mode and 'display:inline'" t-att-title="rating_avg">
<t t-foreach="range(0, val_integer)" t-as="num">
<i class="fa fa-star" role="img"></i>
<t t-if="rating_style_compressed">
<t t-if="rating_avg &lt;= 2">
<i class="fa fa-star-o" role="img"></i>
</t>
<t t-elif="rating_avg &gt;= 2.1 and rating_avg &lt;= 3.5">
<i class="fa fa-star-half-o" role="img"></i>
</t>
<t t-else="">
<i class="fa fa-star" role="img"></i>
</t>
<small class="text-muted ml-1">
<t t-esc="rating_avg"/>
</small>
</t>
<t t-if="val_decimal">
<i class="fa fa-star-half-o" role="img"></i>
<t t-else="">
<t t-foreach="range(0, val_integer)" t-as="num">
<i class="fa fa-star" role="img"></i>
</t>
<t t-if="val_decimal">
<i class="fa fa-star-half-o" role="img"></i>
</t>
<t t-foreach="range(0, empty_star)" t-as="num">
<i class="fa fa-star-o" role="img"></i>
</t>
<small class="text-muted ml-1">
(<t t-esc="rating_count"/>)
</small>
</t>
<t t-foreach="range(0, empty_star)" t-as="num">
<i class="fa fa-star text-black-25" role="img"></i>
</t>
<small class="text-muted ml-1">
(<t t-esc="rating_count"/>)
</small>
</div>
</template>
@@ -45,6 +45,15 @@ const dynamicSnippetOptions = options.Class.extend({
if (params.attributeName === 'templateKey' && previewMode === false) {
this._templateUpdated(widgetValue, params.activeValue);
}
if (params.attributeName === 'numberOfRecords' && previewMode === false) {
const dataSet = this.$target.get(0).dataset;
if (dataSet.numberOfElements > dataSet.numberOfRecords) {
dataSet.numberOfElements = dataSet.numberOfRecords;
}
if (dataSet.numberOfElementsSmallDevices > dataSet.numberOfRecords) {
dataSet.numberOfElementsSmallDevices = dataSet.numberOfRecords;
}
}
},
//--------------------------------------------------------------------------
@@ -30,15 +30,46 @@ const DynamicSnippetCarousel = DynamicSnippet.extend({
* options
* @private
*/
_getQWebRenderParams: function () {
_getQWebRenderOptions: function () {
return Object.assign(
this._super.apply(this, arguments),
{
interval : parseInt(this.$target[0].dataset.carouselInterval),
interval: parseInt(this.$target[0].dataset.carouselInterval),
},
);
},
/**
*
* @override
*/
_renderContent: function () {
this._super.apply(this, arguments);
this._computeHeights();
},
/**
*
* Force height of carousel to the higher slide, to avoid flickering.
* @private
*/
_computeHeights: function () {
var maxHeight = 0;
var $items = this.$('.carousel-item');
$items.css('min-height', '');
_.each($items, function (el) {
var $item = $(el);
var isActive = $item.hasClass('active');
$item.addClass('active');
var height = $item.outerHeight();
if (height > maxHeight) {
maxHeight = height;
}
$item.toggleClass('active', isActive);
});
$items.css('min-height', maxHeight);
},
});
publicWidget.registry.dynamic_snippet_carousel = DynamicSnippetCarousel;
@@ -8,13 +8,13 @@
background: radial-gradient($white 50%, transparent 50%);
}
}
.dynamic_snippet_template .card-footer a, .dynamic_snippet_template .card-footer button {
.dynamic_snippet_template .card-footer a, .dynamic_snippet_template .card-footer button, .o_dynamic_snippet_btn_wrapper {
z-index: 2;
}
.dynamic_snippet_template .card-body .card-text {
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
overflow: hidden;
}
@@ -2,25 +2,27 @@
<odoo>
<data noupdate="1">
<!-- Templates for Dynamic Snippet -->
<template id="dynamic_filter_template_product_product_add_to_cart" name="Add Product to Cart">
<template id="dynamic_filter_template_product_product_add_to_cart" name="Classic Card">
<t t-foreach="records" t-as="data">
<t t-set="record" t-value="data['_record']"/>
<div class="o_carousel_product_card card h-100">
<div class="o_carousel_product_card card h-100 w-100">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
<a class="o_carousel_product_img_link" t-att-href="record.website_url">
<img class="o_carousel_product_card_img_top card-img-top" loading="lazy" t-att-src="data['image_512']"
<img class="o_carousel_product_card_img_top card-img-top p-2" loading="lazy" t-att-src="data['image_512']"
t-att-alt="record.display_name"/>
</a>
<i t-if="data.get('_latest_viewed')" class="fa fa-trash o_carousel_product_remove js_remove"></i>
<div class="o_carousel_product_card_body card-body border-top">
<a t-att-href="record.website_url" class="text-decoration-none">
<div class="h6 card-title mb-0 text-truncate" t-field="record.display_name"/>
<div class="h6 card-title mb-0" t-field="record.display_name"/>
</a>
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
<div class="mt-2">
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
</div>
</div>
<div class="o_carousel_product_card_footer card-footer d-flex align-items-center">
<div>
@@ -37,25 +39,27 @@
<template id="dynamic_filter_template_product_product_view_detail" name="Detailed Product">
<t t-foreach="records" t-as="data">
<t t-set="record" t-value="data['_record']"/>
<div class="o_carousel_product_card card h-100" t-att-data-url="record.website_url">
<div class="o_carousel_product_card card h-100 w-100" t-att-data-url="record.website_url">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<a class="o_carousel_product_img_link" t-att-href="record.website_url">
<img class="card-img-top p-3" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
</a>
<div class="o_carousel_product_card_body card-body">
<div class="o_carousel_product_card_body card-body d-flex flex-column justify-content-between">
<div class="card-title h5" t-field="record.display_name"/>
<div class="card-text" t-field="record.description_sale"/>
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
<div class="mt-2">
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
</div>
</div>
<div class="o_carousel_product_card_footer card-footer d-flex align-items-center">
<div>
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
</div>
<a class="btn btn-primary ml-auto" t-att-href="record.website_url">
<i class="fa fa-fw fa-eye"/>
<i class="fa fa-fw fa-search"/>
</a>
</div>
</div>
@@ -77,13 +81,21 @@
<template id="dynamic_filter_template_product_product_mini_price" name="Image with price">
<t t-foreach="records" t-as="data">
<t t-set="record" t-value="data['_record']"/>
<div class="card h-100" t-att-data-url="record.website_url">
<div class="card w-100 text-center o_dynamic_product_hovered p-3 border-0" t-att-data-url="record.website_url">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<a class="o_carousel_product_img_link" t-att-href="record.website_url">
<img class="card-img-top p-3" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
<a class="o_carousel_product_img_link stretched-link" t-att-href="record.website_url">
<img class="card-img-top" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
</a>
<div class="card-text text-center pb-1">
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
<div class="o_carousel_product_card_body mt-2">
<div class="h6">
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
</div>
<div class="d-inline-block rounded-pill bg-primary px-3 py-2 mt-2 text-center h6">
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
</div>
</div>
</div>
</t>
@@ -92,12 +104,180 @@
<template id="dynamic_filter_template_product_product_mini_name" name="Image with name">
<t t-foreach="records" t-as="data">
<t t-set="record" t-value="data['_record']"/>
<div class="card h-100" t-att-data-url="record.website_url">
<div class="card w-100 border-0 o_dynamic_product_hovered" t-att-data-url="record.website_url">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<a class="o_carousel_product_img_link" t-att-href="record.website_url">
<a class="o_carousel_product_img_link stretched-link" t-att-href="record.website_url">
<img class="card-img-top p-3" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
</a>
<div class="h6 card-footer mb-1 px-1 text-center text-truncate" t-field="record.display_name"/>
<div class="h6 text-center mt-2 p-2" t-field="record.display_name"/>
</div>
</t>
</template>
<template id="dynamic_filter_template_product_product_centered" name="Centered Product">
<t t-foreach="records" t-as="data">
<t t-set="record" t-value="data['_record']"/>
<div class="o_carousel_product_card card w-100">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
<a class="o_carousel_product_img_link position-absolute mx-auto" t-att-href="record.website_url">
<img class="card-img-top" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
</a>
<div class="o_carousel_product_card_body card-body d-flex flex-column justify-content-between">
<div class="card-title h5 text-center" t-field="record.display_name"/>
<div class="text-center">
<div class="h5">
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
</div>
<div class="h6 mb-0">
<t t-if="is_view_active('website_sale.product_comment')">
<t t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
</t>
</div>
</div>
</div>
<div class="o_carousel_product_card_footer d-flex align-items-center justify-content-center pb-4">
<a class="btn btn-primary d-block" t-att-href="record.website_url">
View Product
</a>
</div>
</div>
</t>
</template>
<template id="dynamic_filter_template_product_product_borderless_1" name="Borderless Product n°1">
<t t-foreach="records" t-as="data">
<t t-set="record" t-value="data['_record']"/>
<div class="o_carousel_product_card w-100 card border-0 p-3">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
<a class="o_carousel_product_img_link o_dynamic_product_hovered" t-att-href="record.website_url">
<img class="o_carousel_product_card_img_top card-img-top" loading="lazy" t-att-src="data['image_512']"
t-att-alt="record.display_name"/>
</a>
<div class="o_carousel_product_card_body d-flex flex-wrap flex-column justify-content-between h-100">
<a t-att-href="record.website_url" class="o_carousel_product_img_link text-decoration-none">
<div class="h6 card-title mt-4" t-field="record.display_name"/>
</a>
<div>
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
<div class="mt-2">
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="dynamic_filter_template_product_product_borderless_2" name="Borderless Product n°2">
<t t-foreach="records" t-as="data">
<t t-set="record" t-value="data['_record']"/>
<div class="o_carousel_product_card card w-100 border-0">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
<a class="o_carousel_product_img_link o_dynamic_product_hovered" t-att-href="record.website_url">
<img class="card-img-top p-3" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
</a>
<div class="o_carousel_product_card_body px-3 mt-2 h-100 d-flex flex-column justify-content-between">
<div class="d-flex justify-content-between align-items-center flex-wrap mb-2">
<div class="h5 mb-0 mr-4">
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
</div>
<t t-if="is_view_active('website_sale.product_comment')">
<t t-call="portal_rating.rating_widget_stars_static_compressed">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
</t>
<div class="card-title h6 w-100 mt-2" t-field="record.display_name"/>
</div>
<div class="text-right o_dynamic_snippet_btn_wrapper">
<button type="button" role="button" class="btn btn-primary js_add_cart" title="Add to Cart">
Add to Cart <i class="fa fa-fw fa-shopping-cart"/>
</button>
</div>
</div>
</div>
</t>
</template>
<template id="dynamic_filter_template_product_product_banner" name="Large Banner">
<t t-foreach="records" t-as="data" data-number-of-elements="1" data-number-of-elements-sm="1">
<t t-set="record" t-value="data['_record']"/>
<div class="o_carousel_product_card card w-100 p-3">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
<div class="row flex-row-reverse">
<div class="col-lg-6 d-flex align-items-center">
<img class="img img-fluid mx-auto rounded" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
</div>
<div class="col-lg-6">
<div class="o_carousel_product_card_body p-5">
<div class="card-title h1" t-field="record.display_name"/>
<div class="d-flex align-items-center my-4">
<div class="text-primary h4 mb-0 mr-3">
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
</div>
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
</div>
<div class="card-text text-muted" t-field="record.description_sale"/>
<div class="mt-4">
<a class="btn btn-outline-secondary mr-1 mt-1" t-att-href="record.website_url">
View Product
</a>
<button type="button" role="button" class="btn btn-primary js_add_cart mt-1" title="Add to Cart">
Add to Cart <i class="fa fa-fw fa-shopping-cart"/>
</button>
</div>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="dynamic_filter_template_product_product_horizontal_card" name="Horizontal Card">
<t t-foreach="records" t-as="data" data-number-of-elements="3" data-number-of-elements-sm="1">
<t t-set="record" t-value="data['_record']"/>
<div class="o_carousel_product_card card w-100 border-0 bg-light p-3">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
<div class="row h-100">
<div class="col-lg-4 position-static">
<a class="stretched-link" t-att-href="record.website_url">
<img class="img img-fluid mx-auto" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
</a>
</div>
<div class="o_carousel_product_card_body col-lg-8 pl-3 d-flex flex-column justify-content-between">
<div>
<div class="card-title h6" t-field="record.display_name"/>
<div class="mb-2">
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
<t t-set="rating_avg" t-value="record.rating_avg"/>
<t t-set="rating_count" t-value="record.rating_count"/>
</t>
</div>
</div>
<div class="d-flex justify-content-between align-items-center flex-wrap">
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
<div class="o_dynamic_snippet_btn_wrapper">
<button type="button" role="button" class="btn btn-primary js_add_cart" title="Add to Cart">
<i class="fa fa-fw fa-shopping-cart"/>
</button>
</div>
</div>
</div>
</div>
</div>
</t>
</template>
@@ -108,5 +288,12 @@
<del t-if="data.get('has_discounted_price')" class="text-danger ml-1 h6" style="white-space: nowrap;"
t-esc="data['list_price']" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
</template>
<!-- Assets -->
<record id="website_sale.s_dynamic_snippet_products_000_scss" model="ir.asset">
<field name="name">Dynamic snippet products 000 SCSS</field>
<field name="bundle">web.assets_frontend</field>
<field name="path">website_sale/static/src/snippets/s_dynamic_snippet_products/000.scss</field>
</record>
</data>
</odoo>
@@ -0,0 +1,42 @@
// class name are dynamically added.
// If you don't find it with a grep, don't consider it as useless without extra check.
.s_product_product_centered {
.card {
overflow: visible;
margin-top: 6rem;
padding-top: 6rem;
}
.o_carousel_product_img_link {
max-width: 75%;
margin-top: -12rem;
left: 0;
right: 0;
}
}
.s_product_product_banner {
img {
max-height: 400px;
}
}
.s_product_product_horizontal_card img {
img {
height: 100%;
}
}
@include media-breakpoint-down(md) {
.s_product_product_horizontal_card img {
height: 12rem;
}
}
.o_dynamic_product_hovered {
transition: transform 250ms ease;
&:hover {
transform: scale(.95);
}
}