diff --git a/addons/website/__manifest__.py b/addons/website/__manifest__.py index 6f4ec0e5bd3..b70e143a8cc 100644 --- a/addons/website/__manifest__.py +++ b/addons/website/__manifest__.py @@ -41,7 +41,6 @@ 'views/snippets/s_card.xml', 'views/snippets/s_share.xml', 'views/snippets/s_rating.xml', - 'views/snippets/s_btn.xml', 'views/snippets/s_hr.xml', 'views/snippets/s_facebook_page.xml', 'views/snippets/s_image_gallery.xml', @@ -58,6 +57,18 @@ 'views/snippets/s_chart.xml', 'views/snippets/s_parallax.xml', 'views/snippets/s_quotes_carousel.xml', + 'views/snippets/s_numbers.xml', + 'views/snippets/s_masonry_block.xml', + 'views/snippets/s_media_list.xml', + 'views/snippets/s_showcase.xml', + 'views/snippets/s_timeline.xml', + 'views/snippets/s_process_steps.xml', + 'views/snippets/s_text_highlight.xml', + 'views/snippets/s_progress_bar.xml', + 'views/snippets/s_blockquote.xml', + 'views/snippets/s_badge.xml', + 'views/snippets/s_color_blocks_2.xml', + 'views/snippets/s_product_list.xml', 'views/snippets/s_mega_menu_multi_menus.xml', 'views/snippets/s_mega_menu_menu_image_menu.xml', 'views/website_views.xml', @@ -69,6 +80,9 @@ 'views/res_partner_views.xml', 'wizard/base_language_install_views.xml', 'wizard/website_robots.xml', + + # Old snippets + 'views/snippets/s_btn.xml', ], 'demo': [ 'data/website_demo.xml', diff --git a/addons/website/data/website_data.xml b/addons/website/data/website_data.xml index 8c72901a317..2304a8b3a7e 100644 --- a/addons/website/data/website_data.xml +++ b/addons/website/data/website_data.xml @@ -25,13 +25,9 @@
-
+
-
-
-

Contact us

-
-
+

Contact us

@@ -77,14 +73,10 @@
-
+
-
-
-

About us

-

Great products for great people

-
-
+

About us

+

Great products for great people

@@ -381,6 +373,66 @@ url /website/static/src/img/snippets_demo/s_cover.jpg + + + s_masonry_block_default_image_1.jpg + url + /website/static/src/img/snippets_demo/s_masonry_block_1.jpg + + + + s_media_list_default_image_1.jpg + url + /website/static/src/img/snippets_demo/s_media_list_1.jpg + + + + s_media_list_default_image_2.jpg + url + /website/static/src/img/snippets_demo/s_media_list_2.jpg + + + + s_media_list_default_image_3.jpg + url + /website/static/src/img/snippets_demo/s_media_list_3.jpg + + + + s_product_list_default_image_1.jpg + url + /website/static/src/img/snippets_demo/s_product_list_1.jpg + + + + s_product_list_default_image_2.jpg + url + /website/static/src/img/snippets_demo/s_product_list_1.jpg + + + + s_product_list_default_image_3.jpg + url + /website/static/src/img/snippets_demo/s_product_list_1.jpg + + + + s_product_list_default_image_4.jpg + url + /website/static/src/img/snippets_demo/s_product_list_1.jpg + + + + s_product_list_default_image_5.jpg + url + /website/static/src/img/snippets_demo/s_product_list_1.jpg + + + + s_product_list_default_image_6.jpg + url + /website/static/src/img/snippets_demo/s_product_list_1.jpg + s_quotes_carousel_image_01.jpg diff --git a/addons/website/static/src/img/blocks/twitter_scroll.png b/addons/website/static/src/img/blocks/twitter_scroll.png deleted file mode 100644 index b8d602d519a..00000000000 Binary files a/addons/website/static/src/img/blocks/twitter_scroll.png and /dev/null differ diff --git a/addons/website/static/src/img/snippets_demo/s_masonry_block_1.jpg b/addons/website/static/src/img/snippets_demo/s_masonry_block_1.jpg new file mode 100644 index 00000000000..b46aba6ee28 Binary files /dev/null and b/addons/website/static/src/img/snippets_demo/s_masonry_block_1.jpg differ diff --git a/addons/website/static/src/img/snippets_demo/s_media_list_1.jpg b/addons/website/static/src/img/snippets_demo/s_media_list_1.jpg new file mode 100755 index 00000000000..b048d41405d Binary files /dev/null and b/addons/website/static/src/img/snippets_demo/s_media_list_1.jpg differ diff --git a/addons/website/static/src/img/snippets_demo/s_media_list_2.jpg b/addons/website/static/src/img/snippets_demo/s_media_list_2.jpg new file mode 100755 index 00000000000..f569175053b Binary files /dev/null and b/addons/website/static/src/img/snippets_demo/s_media_list_2.jpg differ diff --git a/addons/website/static/src/img/snippets_demo/s_media_list_3.jpg b/addons/website/static/src/img/snippets_demo/s_media_list_3.jpg new file mode 100644 index 00000000000..b46aba6ee28 Binary files /dev/null and b/addons/website/static/src/img/snippets_demo/s_media_list_3.jpg differ diff --git a/addons/website/static/src/img/snippets_demo/s_product_list_1.jpg b/addons/website/static/src/img/snippets_demo/s_product_list_1.jpg new file mode 100644 index 00000000000..7dd29701958 Binary files /dev/null and b/addons/website/static/src/img/snippets_demo/s_product_list_1.jpg differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_badge.png b/addons/website/static/src/img/snippets_thumbs/s_badge.png new file mode 100644 index 00000000000..bf8c87bd28d Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_badge.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_blockquote.png b/addons/website/static/src/img/snippets_thumbs/s_blockquote.png new file mode 100644 index 00000000000..a0dc97ed190 Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_blockquote.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_button.png b/addons/website/static/src/img/snippets_thumbs/s_button.png deleted file mode 100755 index 3fb1b920a9b..00000000000 Binary files a/addons/website/static/src/img/snippets_thumbs/s_button.png and /dev/null differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_button_channel_subscribe.png b/addons/website/static/src/img/snippets_thumbs/s_channel.png similarity index 100% rename from addons/website/static/src/img/snippets_thumbs/s_button_channel_subscribe.png rename to addons/website/static/src/img/snippets_thumbs/s_channel.png diff --git a/addons/website/static/src/img/snippets_thumbs/s_color_blocks_2.png b/addons/website/static/src/img/snippets_thumbs/s_color_blocks_2.png new file mode 100644 index 00000000000..01ede5f31b3 Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_color_blocks_2.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_faq.png b/addons/website/static/src/img/snippets_thumbs/s_faq_collapse.png similarity index 100% rename from addons/website/static/src/img/snippets_thumbs/s_faq.png rename to addons/website/static/src/img/snippets_thumbs/s_faq_collapse.png diff --git a/addons/website/static/src/img/snippets_thumbs/s_separator.png b/addons/website/static/src/img/snippets_thumbs/s_hr.png similarity index 100% rename from addons/website/static/src/img/snippets_thumbs/s_separator.png rename to addons/website/static/src/img/snippets_thumbs/s_hr.png diff --git a/addons/website/static/src/img/snippets_thumbs/s_masonry_block.png b/addons/website/static/src/img/snippets_thumbs/s_masonry_block.png new file mode 100644 index 00000000000..25bc2ec7d8f Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_masonry_block.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_media_list.png b/addons/website/static/src/img/snippets_thumbs/s_media_list.png new file mode 100644 index 00000000000..8dd856eaca4 Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_media_list.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_numbers.png b/addons/website/static/src/img/snippets_thumbs/s_numbers.png new file mode 100644 index 00000000000..ce3c5978a0d Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_numbers.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_process_steps.png b/addons/website/static/src/img/snippets_thumbs/s_process_steps.png new file mode 100644 index 00000000000..a3911eb709c Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_process_steps.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_product_list.png b/addons/website/static/src/img/snippets_thumbs/s_product_list.png new file mode 100644 index 00000000000..adfa1656dc7 Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_product_list.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_progress_bar.png b/addons/website/static/src/img/snippets_thumbs/s_progress_bar.png new file mode 100644 index 00000000000..21a9a948a71 Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_progress_bar.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_showcase.png b/addons/website/static/src/img/snippets_thumbs/s_showcase.png new file mode 100644 index 00000000000..48e28374c07 Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_showcase.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_text_highlight.png b/addons/website/static/src/img/snippets_thumbs/s_text_highlight.png new file mode 100644 index 00000000000..c4c76f5ca1f Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_text_highlight.png differ diff --git a/addons/website/static/src/img/snippets_thumbs/s_timeline.png b/addons/website/static/src/img/snippets_thumbs/s_timeline.png new file mode 100644 index 00000000000..be5ae96c1a6 Binary files /dev/null and b/addons/website/static/src/img/snippets_thumbs/s_timeline.png differ diff --git a/addons/website/static/src/img/s_website_form.png b/addons/website/static/src/img/snippets_thumbs/s_website_form.png similarity index 100% rename from addons/website/static/src/img/s_website_form.png rename to addons/website/static/src/img/snippets_thumbs/s_website_form.png diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index 0dbe26b024f..9765bc57473 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -393,119 +393,6 @@ options.registry.CarouselItem = options.Class.extend({ }, }); -options.registry.navTabs = options.Class.extend({ - /** - * @override - */ - start: function () { - this._findLinksAndPanes(); - return this._super.apply(this, arguments); - }, - /** - * @override - */ - onBuilt: function () { - this._generateUniqueIDs(); - }, - /** - * @override - */ - onClone: function () { - this._generateUniqueIDs(); - }, - - //-------------------------------------------------------------------------- - // Options - //-------------------------------------------------------------------------- - - /** - * Creates a new tab and tab-pane. - * - * @see this.selectClass for parameters - */ - addTab: function (previewMode, widgetValue, params) { - var $activeItem = this.$navLinks.filter('.active').parent(); - var $activePane = this.$tabPanes.filter('.active'); - - var $navItem = $activeItem.clone(); - var $navLink = $navItem.find('.nav-link').removeClass('active show'); - var $tabPane = $activePane.clone().removeClass('active show'); - $navItem.insertAfter($activeItem); - $tabPane.insertAfter($activePane); - this._findLinksAndPanes(); - this._generateUniqueIDs(); - - $navLink.tab('show'); - }, - /** - * Removes the current active tab and its content. - * - * @see this.selectClass for parameters - */ - removeTab: function (previewMode, widgetValue, params) { - var self = this; - - var $activeLink = this.$navLinks.filter('.active'); - var $activePane = this.$tabPanes.filter('.active'); - - var $next = this.$navLinks.eq((this.$navLinks.index($activeLink) + 1) % this.$navLinks.length); - - return new Promise(resolve => { - $next.one('shown.bs.tab', function () { - $activeLink.parent().remove(); - $activePane.remove(); - self._findLinksAndPanes(); - resolve(); - }); - $next.tab('show'); - }); - }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * @override - */ - _computeWidgetVisibility: async function (widgetName, params) { - if (widgetName === 'remove_tab_opt') { - return (this.$tabPanes.length > 2); - } - return this._super(...arguments); - }, - /** - * @private - */ - _findLinksAndPanes: function () { - this.$navLinks = this.$target.find('.nav-link'); - var $el = this.$target; - do { - $el = $el.parent(); - this.$tabPanes = $el.find('.tab-pane'); - } while (this.$tabPanes.length === 0 && !$el.is('body')); - }, - /** - * @private - */ - _generateUniqueIDs: function () { - for (var i = 0; i < this.$navLinks.length; i++) { - var id = _.now() + '_' + _.uniqueId(); - var idLink = 'nav_tabs_link_' + id; - var idContent = 'nav_tabs_content_' + id; - this.$navLinks.eq(i).attr({ - 'id': idLink, - 'href': '#' + idContent, - 'aria-controls': idContent, - }); - this.$tabPanes.eq(i).attr({ - 'id': idContent, - 'aria-labelledby': idLink, - }); - } - }, -}); - options.registry.sizing_x = options.registry.sizing.extend({ /** * @override @@ -1171,6 +1058,17 @@ options.registry.SnippetMove = options.Class.extend({ return this._super(...arguments); }, + /** + * @override + */ + onFocus: function () { + // TODO improve this: hack to hide options section if snippet move is + // the only one. + const $allOptions = this.$el.parent(); + if ($allOptions.find('we-customizeblock-option').length <= 1) { + $allOptions.addClass('d-none'); + } + }, //-------------------------------------------------------------------------- // Options @@ -1182,12 +1080,20 @@ options.registry.SnippetMove = options.Class.extend({ * @see this.selectClass for parameters */ moveSnippet: function (previewMode, widgetValue, params) { + const isNavItem = this.$target[0].classList.contains('nav-item'); + const $tabPane = isNavItem ? $(this.$target.find('.nav-link')[0].hash) : null; switch (widgetValue) { case 'prev': this.$target.prev().before(this.$target); + if (isNavItem) { + $tabPane.prev().before($tabPane); + } break; case 'next': this.$target.next().after(this.$target); + if (isNavItem) { + $tabPane.next().after($tabPane); + } break; } }, diff --git a/addons/website/static/src/scss/primary_variables.scss b/addons/website/static/src/scss/primary_variables.scss index d6b84ff52e0..367188a8053 100644 --- a/addons/website/static/src/scss/primary_variables.scss +++ b/addons/website/static/src/scss/primary_variables.scss @@ -39,6 +39,8 @@ $o-social-colors: ( 'youtube': #ff0000, 'github': #1a1e22, 'instagram': #cf2872, + 'whatsapp': #25d366, + 'pinterest': #C8232C, ); $o-theme-figcaption-opacity: 0.6; diff --git a/addons/website/static/src/scss/website.scss b/addons/website/static/src/scss/website.scss index be5a350092e..b2b51c732ee 100644 --- a/addons/website/static/src/scss/website.scss +++ b/addons/website/static/src/scss/website.scss @@ -199,6 +199,12 @@ font[class*='bg-'] { border-top-left-radius: $size; border-bottom-right-radius: $size; } + &.rounded-empty-circle { + @extend .rounded-circle; + border-width: ceil(1.4 * $border-width); + border-style: solid; + background: transparent; + } } // Smaller container .o_container_small { @@ -380,6 +386,11 @@ table.table_desc tr td { @extend .o_half_screen_height; } +// Allows custom border radius without contents overflowing. +.card { + overflow: hidden; +} + // // Snippets // @@ -626,7 +637,6 @@ table.table_desc tr td { } } - // // Layout // diff --git a/addons/website/static/src/snippets/s_badge/000.scss b/addons/website/static/src/snippets/s_badge/000.scss new file mode 100644 index 00000000000..d7fdffcb43e --- /dev/null +++ b/addons/website/static/src/snippets/s_badge/000.scss @@ -0,0 +1,10 @@ + +.s_badge { + padding: $s-badge-padding; + margin: $s-badge-margin; + border-radius: if($s-badge-border-radius != null, $s-badge-border-radius, $border-radius); + font-size: $font-size-sm; + .fa { + margin: $s-badge-i-margin; + } +} diff --git a/addons/website/static/src/snippets/s_badge/000_variables.scss b/addons/website/static/src/snippets/s_badge/000_variables.scss new file mode 100644 index 00000000000..b6bc19298e5 --- /dev/null +++ b/addons/website/static/src/snippets/s_badge/000_variables.scss @@ -0,0 +1,4 @@ +$s-badge-border-radius: null; +$s-badge-padding: .5rem; +$s-badge-margin: .5rem .5rem .5rem 0; +$s-badge-i-margin: 0 .3rem 0 0; diff --git a/addons/website/static/src/snippets/s_blockquote/000.scss b/addons/website/static/src/snippets/s_blockquote/000.scss new file mode 100644 index 00000000000..d349d128ddc --- /dev/null +++ b/addons/website/static/src/snippets/s_blockquote/000.scss @@ -0,0 +1,41 @@ +.s_blockquote { + .s_blockquote_icon { + float: left; + } + .s_blockquote_content { + overflow: hidden; + padding: $grid-gutter-width/2; + text-align: left; + footer { + background-color: initial; + } + } + .blockquote-footer { + img { + max-height: 40px; + } + } + // Don't use `&:.s_blockquote_classic`, same but not retro-compatible + &:not(.s_blockquote_cover):not(.s_blockquote_minimalist) { + .blockquote-footer { + &:before { + display: none; + } + } + } + &.s_blockquote_minimalist { + border-radius: 5px; + .s_blockquote_content { + padding: $grid-gutter-width/2.5; + p { + margin: 0; + &:before { + content: '\00AB\00a0'; + } + &:after { + content: '\00a0\00BB'; + } + } + } + } +} diff --git a/addons/website/static/src/snippets/s_blockquote/options.js b/addons/website/static/src/snippets/s_blockquote/options.js new file mode 100644 index 00000000000..ee3cefd5650 --- /dev/null +++ b/addons/website/static/src/snippets/s_blockquote/options.js @@ -0,0 +1,52 @@ +odoo.define('website.s_blockquote_options', function (require) { +'use strict'; + +const options = require('web_editor.snippets.options'); + +options.registry.Blockquote = options.Class.extend({ + + //-------------------------------------------------------------------------- + // Options + //-------------------------------------------------------------------------- + + /** + * Changes the position of the progressbar text. + * + * @see this.selectClass for parameters + */ + display: function (previewMode, widgetValue, params) { + this.$target.find('.s_blockquote_icon') + .toggleClass('d-none', widgetValue !== 'classic'); + + const $content = this.$target.find('.s_blockquote_content'); + $content.find('.quote_char').remove(); + if (widgetValue === 'cover') { + this.$target.find('.s_blockquote_content > p').before( + $('').addClass('quote_char fa fa-quote-left font-italic') + ); + } + + // Text style + $content.toggleClass('text-center', widgetValue === 'cover'); + $content.toggleClass('font-italic', widgetValue !== 'classic'); + + // Bg Img + if (widgetValue === 'cover') { + this.$target.css({'background-image': "url('/web/image/website.s_parallax_default_image')"}); + this.$target.css({'background-position': "50%"}); + $content.css({'background-color': "rgba(0, 0, 0, 0.5)"}); + } else { + this.$target.css({'background-image': "unset"}); + $content.css({'background-color': "unset"}); + } + + // Blockquote Footer + const $footer = this.$target.find('footer'); + $footer.toggleClass('text-white', widgetValue === 'cover'); + this.$target.toggleClass('text-white', widgetValue === 'cover'); + $footer.toggleClass('d-none', widgetValue === 'minimalist'); + this.$target.find('.s_blockquote_avatar') + .toggleClass('d-none', widgetValue !== 'classic'); + }, +}); +}); diff --git a/addons/website/static/src/snippets/s_color_blocks_2/000.scss b/addons/website/static/src/snippets/s_color_blocks_2/000.scss new file mode 100644 index 00000000000..70d476a3308 --- /dev/null +++ b/addons/website/static/src/snippets/s_color_blocks_2/000.scss @@ -0,0 +1,27 @@ +.s_color_blocks_2 { + .row { + display: flex; + flex-flow: row wrap; + + // Fix for safari browser as it 'supports' flex but not with the right + // behavior + &::before, &::after { + width: 0; + } + } + [class*="col-lg-"] { + padding: 8% 5%; + padding-top: 8vw; // A flex item cannot have % padding top and bottom (even if it works on chrome) + padding-bottom: 8vw; // Solution is vw units but we keep 8% as a fallback + } + @include media-breakpoint-down(md) { + [class*="col-lg-"] { + flex: 1 1 100%; + } + } + + img { + max-width: 100%; + height: auto; + } +} diff --git a/addons/website/static/src/snippets/s_hr/000.scss b/addons/website/static/src/snippets/s_hr/000.scss index ec548e3c555..d7b5c0f57aa 100644 --- a/addons/website/static/src/snippets/s_hr/000.scss +++ b/addons/website/static/src/snippets/s_hr/000.scss @@ -4,21 +4,7 @@ hr { padding: 0; border: 0; - border-top-color: inherit; + border-top: 1px solid inherit; margin: 0; } - // Style - .s_hr_dashed { border-top-style: dashed; } - .s_hr_double { border-top-style: double; } - .s_hr_dotted { border-top-style: dotted; } - .s_hr_solid { border-top-style: solid; } - // Thickness - $count: 5; - $base-width: 1px; - @while $count > 0 { - .s_hr_#{$base-width * $count} { - border-top-width: $base-width * $count; - } - $count: $count - 1; - } } diff --git a/addons/website/static/src/snippets/s_masonry_block/000.scss b/addons/website/static/src/snippets/s_masonry_block/000.scss new file mode 100644 index 00000000000..19e10320971 --- /dev/null +++ b/addons/website/static/src/snippets/s_masonry_block/000.scss @@ -0,0 +1,93 @@ +.s_masonry_block:not([data-vcss]) { + .row, .row > div { + display: flex; + } + + .row > div { + padding-bottom: $grid-gutter-width/2; + padding-top: $grid-gutter-width/2; + justify-content: center; + flex-flow: column wrap; + } + + .container-fluid > .row { + flex-flow: row nowrap; + + @include media-breakpoint-down(md) { + flex-flow: column nowrap; + } + + > div.s_masonry_block_pseudo_col { + flex: 1 1 auto; + padding:0; + + > .row { + flex-flow: row wrap; + min-height: 100%; + margin: 0; + + @include media-breakpoint-down(sm) { + flex-flow: column nowrap; + } + + > div { + min-height: 50%; + flex: 1 1 auto; + } + } + } + } + + &.s_ratio_2_1 { + .row > div { + padding-top: $grid-gutter-width; + padding-bottom: $grid-gutter-width; + } + } +} + +html[data-no-flex] .s_masonry_block:not([data-vcss]) { + min-height: 340px; + > div { + height: 100%; + } + + .row { + height: 100%; + + > div { + position: relative; + height: 100%; + min-height: 170px; + padding-top: 0; + padding-left: 0; + } + } + + .content { + @include clearfix; + } + + @include media-breakpoint-up(md) { + .row .row > div { + height: 50%; + } + } + + @include media-breakpoint-up(lg) { + height: 0px; // hack to force height chain + &.s_ratio_2_1 { + position: relative; + padding: 0 0 50% 0; // to have 2:1 aspect ratio + > div { + padding-top: 0; + padding-bottom:0; + @include o-position-absolute(0, 0, 0, 0); + } + } + + .content { + @include o-position-absolute($s-masonry-block-content-top, $s-masonry-block-content-right, $s-masonry-block-content-bottom, $s-masonry-block-content-left); + } + } +} diff --git a/addons/website/static/src/snippets/s_masonry_block/000_variables.scss b/addons/website/static/src/snippets/s_masonry_block/000_variables.scss new file mode 100644 index 00000000000..2261e63a896 --- /dev/null +++ b/addons/website/static/src/snippets/s_masonry_block/000_variables.scss @@ -0,0 +1,4 @@ +$s-masonry-block-content-top: 35%; +$s-masonry-block-content-right: 25%; +$s-masonry-block-content-bottom: 35%; +$s-masonry-block-content-left: 25%; diff --git a/addons/website/static/src/snippets/s_masonry_block/001.scss b/addons/website/static/src/snippets/s_masonry_block/001.scss new file mode 100644 index 00000000000..f5020295fa4 --- /dev/null +++ b/addons/website/static/src/snippets/s_masonry_block/001.scss @@ -0,0 +1,5 @@ +.s_masonry_block[data-vcss='001'] .row > div { + display: flex; + flex-direction: column; + justify-content: center; +} diff --git a/addons/website/static/src/snippets/s_media_list/000.scss b/addons/website/static/src/snippets/s_media_list/000.scss new file mode 100644 index 00000000000..f9492b55df3 --- /dev/null +++ b/addons/website/static/src/snippets/s_media_list/000.scss @@ -0,0 +1,27 @@ + +.s_media_list { + .row { + margin: $grid-gutter-width 0; + } + [class*="col-"] { + padding: 0; + } + .s_media_list_body { + background-color: #fff; + padding: $grid-gutter-width; + } + .s_media_list_options { + @include o-position-absolute(auto,0,0,0); + display: flex; + border-top: 1px solid gray('400'); + .s_media_list_option { + flex: 1 1 auto; + padding: $grid-gutter-width/3 0; + border-right: 1px solid gray('400'); + text-align: center; + &:last-child { + border-right: 0; + } + } + } +} diff --git a/addons/website/static/src/snippets/s_process_steps/000.scss b/addons/website/static/src/snippets/s_process_steps/000.scss new file mode 100644 index 00000000000..a0b7f942b06 --- /dev/null +++ b/addons/website/static/src/snippets/s_process_steps/000.scss @@ -0,0 +1,75 @@ +.s_process_steps { + .s_process_step_icon { + margin: $grid-gutter-width 0; + span { + display: block; + overflow: hidden; + } + .fa { + display: block; + } + } + .s_process_step_content { + padding: 0 $grid-gutter-width/2; + } + @include media-breakpoint-up(lg) { + overflow-x: hidden; + .s_process_step { + .s_process_step_icon { + position: relative; + z-index: 1; + span:after { + content: ''; + z-index: -1; + border-top: 1px solid gray('500'); + @include o-position-absolute(50%, 0, 0, auto); + } + } + &:not(:first-child):not(:last-child) .s_process_step_icon { + span:after { + width: 100%; + } + } + &:first-child .s_process_step_icon, + &:last-child .s_process_step_icon { + span:after { + width: 1000%; + } + .fa { + &:after { + content: ''; + z-index: -1; + @include o-position-absolute(50%, auto, 0, auto); + width: 100%; + border-top: 1px solid gray('500'); + } + &.mx-auto:after { + width: 50%; + } + } + } + &:first-child .s_process_step_icon { + .fa:after { right: 0; } + .fa.float-right:after { width: 0; } + } + &:last-child .s_process_step_icon { + span:after { left: 0; } + .fa { + &:after { left: 0; } + &.float-left:after { width: 0; } + } + } + } + } + + $s_process_step_line_fw: true; + + @if $s_process_step_line_fw == true { + .s_process_step:first-child, + .s_process_step:last-child { + .s_process_step_icon > span:after { + display: none; + } + } + } +} diff --git a/addons/website/static/src/snippets/s_product_list/000.scss b/addons/website/static/src/snippets/s_product_list/000.scss new file mode 100644 index 00000000000..c952d5bfbe5 --- /dev/null +++ b/addons/website/static/src/snippets/s_product_list/000.scss @@ -0,0 +1,46 @@ + +.s_product_list { + padding: 15px; + + > div > .row > div { + margin-bottom: 20px; // without this style the columns go directly to the top of the bellow ones. + + height: 200px; + text-align: center; + + a { + display: block; + } + + img { + margin: auto; + max-height: 130px; + @include s-product-list-img-hook; + } + + .s_product_list_item_link { + @include o-position-absolute($left: 10%, $bottom: 0, $right: 10%); + + > .btn { + width: 100%; + padding: 5px !important; + font-size: 16px; + text-transform: uppercase; + + @media only screen and (max-width : 1280px) { // FIXME + font-size: 12px; + } + + .fa { + font-size: 18px; + padding-right: 5px; + + @media only screen and (max-width : 1024px) { // FIXME + display: block; + font-size: 25px; + } + } + } + } + } +} diff --git a/addons/website/static/src/snippets/s_product_list/000_variables.scss b/addons/website/static/src/snippets/s_product_list/000_variables.scss new file mode 100644 index 00000000000..8ce4e819854 --- /dev/null +++ b/addons/website/static/src/snippets/s_product_list/000_variables.scss @@ -0,0 +1 @@ +@mixin s-product-list-img-hook {} diff --git a/addons/website/static/src/snippets/s_progress_bar/options.js b/addons/website/static/src/snippets/s_progress_bar/options.js new file mode 100644 index 00000000000..06644e3f168 --- /dev/null +++ b/addons/website/static/src/snippets/s_progress_bar/options.js @@ -0,0 +1,113 @@ +odoo.define('website.s_progress_bar_options', function (require) { +'use strict'; + +const core = require('web.core'); +const options = require('web_editor.snippets.options'); + +const _t = core._t; + +options.registry.progress = options.Class.extend({ + /** + * @override + */ + start: function () { + if (this.$overlay) { + this._bindMoveProgress(); + } + this._super(); + }, + + //-------------------------------------------------------------------------- + // Options + //-------------------------------------------------------------------------- + + /** + * Changes the position of the progressbar text. + * + * @see this.selectClass for parameters + */ + display: function (previewMode, widgetValue, params) { + // retro-compatibility + if (this.$target.hasClass('progress')) { + this.$target.removeClass('progress'); + this.$target.find('.progress-bar').wrap($('
', { + class: 'progress', + })); + this.$target.find('.progress-bar span').addClass('s_progress_bar_text'); + } + + let $text = this.$target.find('.s_progress_bar_text'); + if (!$text.length) { + $text = $('').addClass('s_progress_bar_text').html(_t('80% Development')); + } + + if (widgetValue === 'inline') { + $text.appendTo(this.$target.find('.progress-bar')); + } else { + $text.insertBefore(this.$target.find('.progress')); + } + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _computeWidgetState: function (methodName, params) { + switch (methodName) { + case 'display': { + const isInline = this.$target.find('.s_progress_bar_text') + .parent('.progress-bar').length; + return isInline ? 'inline' : 'below'; + } + } + return this._super(...arguments); + }, + /** + * Binds the editor padding feature to the progress bar width. + */ + _bindMoveProgress: function () { + var self = this; + var $e = this.$overlay.find(".o_handle.e").removeClass("readonly"); + const $progressBar = this.$target.find('.progress-bar'); + const $parent = $progressBar.parent(); + var pos = $parent.offset(); + var width = $parent.width(); + var time; + function move(event) { + clearTimeout(time); + time = setTimeout(function () { + var value = (event.clientX - pos.left) / width * 100 | 0; + if (value > 100) { + value = 100; + } + if (value < 0) { + value = 0; + } + const $progressBarText = self.$target.find('.s_progress_bar_text'); + // Target precisely the XX% not only XX to not replace wrong element + // eg 'Since 1978 we have completed 45%' <- don't replace 1978 + $progressBarText.text($progressBarText.text().replace(/[0-9]+%/, value + '%')); + $progressBar.attr("data-value", value); + $progressBar.attr("aria-valuenow", value); + if (value < 3) { + value = 3; + } + $progressBar.css("width", value + "%"); + }, 5); + } + $e.on("mousedown", function () { + self.$overlay.addClass('d-none'); + $(document) + .on("mousemove", move) + .one("mouseup", function () { + self.$overlay.removeClass('d-none'); + $(document).off("mousemove", move); + self.trigger_up('cover_update'); + }); + }); + }, +}); +}); diff --git a/addons/website/static/src/snippets/s_share/000.scss b/addons/website/static/src/snippets/s_share/000.scss index a7e12a2a4da..e02e2711cab 100644 --- a/addons/website/static/src/snippets/s_share/000.scss +++ b/addons/website/static/src/snippets/s_share/000.scss @@ -10,16 +10,36 @@ > a + a { margin-left: .4rem; } - .s_share_facebook { - &, &:hover, &:focus { color: #3b5998; } - } - .s_share_twitter { - &, &:hover, &:focus { color: #1da1f2; } - } - .s_share_linkedin { - &, &:hover, &:focus { color: #0077b5; } - } - .s_share_google { - &, &:hover, &:focus { color: #db4437; } + &:not(.no_icon_color) { + .s_share_facebook { + &, &:hover, &:focus { + @extend .text-facebook; + } + } + .s_share_twitter { + &, &:hover, &:focus { + @extend .text-twitter; + } + } + .s_share_linkedin { + &, &:hover, &:focus { + @extend .text-linkedin; + } + } + .s_share_google { + &, &:hover, &:focus { + @extend .text-google-plus; + } + } + .s_share_whatsapp { + &, &:hover, &:focus { + @extend .text-whatsapp; + } + } + .s_share_pinterest { + &, &:hover, &:focus { + @extend .text-pinterest; + } + } } } diff --git a/addons/website/static/src/snippets/s_showcase/000.scss b/addons/website/static/src/snippets/s_showcase/000.scss new file mode 100644 index 00000000000..8970e7e262b --- /dev/null +++ b/addons/website/static/src/snippets/s_showcase/000.scss @@ -0,0 +1,77 @@ + +#wrapwrap .s_showcase:not([data-vcss]) { + @include media-breakpoint-up(lg) { + .container, .container-fluid { + position: relative; + + &:before { + content: " "; + display: block; + @include o-position-absolute($left: 50%); + height: 100%; + border-right: 1px solid gray('200'); + } + } + } + + .fa { + opacity: 0.5; + } + + .text-right{ + .fa { + float: right; + margin-left: .5em; + } + p { + float: right; + display: block; + } + } + .text-left{ + .fa { + float: left; + margin-right: .5em; + } + p { + float: left; + } + } + .row { + margin-top: 1em; + } + .feature p { + max-width: 300px; + margin-top: 0.6em; + clear: both; + } +} + +@include media-breakpoint-down(md) { + #wrapwrap .s_showcase:not([data-vcss]) { + .text-right, .text-left { + text-align: center; + + .fa { + font-size: 2em; + opacity: 0.5; + float: none; + display: block; + position: relative; + margin-left: auto; + margin-right: auto; + } + } + .feature { + margin-bottom: 3em; + + p { + float: none; + display: block; + position: relative; + margin-left: auto; + margin-right: auto; + } + } + } +} diff --git a/addons/website/static/src/snippets/s_showcase/001.scss b/addons/website/static/src/snippets/s_showcase/001.scss new file mode 100644 index 00000000000..4ef99f5eb1c --- /dev/null +++ b/addons/website/static/src/snippets/s_showcase/001.scss @@ -0,0 +1,47 @@ +.s_showcase[data-vcss='001'] { + @include media-breakpoint-up(lg) { + // Left-right separator + .container, .container-fluid { + position: relative; + + &:before { + content: " "; + display: block; + @include o-position-absolute($left: 50%); + height: 100%; + border-right: 1px solid gray('200'); + } + } + // Features + .row > div { + // Items on left + &:nth-child(odd) { + text-align: right; + + .s_showcase_icon, p { + float: right; + } + + .s_showcase_icon { + margin-right: 0; + margin-left: 15px; + } + } + // Items on right + &:nth-child(even) { + text-align: left; + + .s_showcase_icon, p { + float: left; + } + } + } + } + + .s_showcase_icon { + // Make the default margin the one for the left aligned icon, as it's what we want on mobile + margin-right: 15px; + opacity: .5; + font-size: 36px; + } +} diff --git a/addons/website/static/src/snippets/s_tabs/001.scss b/addons/website/static/src/snippets/s_tabs/001.scss new file mode 100644 index 00000000000..6e132e91f31 --- /dev/null +++ b/addons/website/static/src/snippets/s_tabs/001.scss @@ -0,0 +1,25 @@ +// Tabs +.s_tabs[data-vcss="001"] { + .s_tabs_content { + &.s_tabs_slide_up, &.s_tabs_slide_down, &.s_tabs_slide_left, &.s_tabs_slide_right { + > .tab-pane.fade { + transition: all 0.2s; + } + > .tab-pane.fade.show { + transform: translateX(0rem) translateY(0rem); + } + } + &.s_tabs_slide_up > .tab-pane.fade { + transform: translateY(-1rem); + } + &.s_tabs_slide_down > .tab-pane.fade { + transform: translateY(1rem); + } + &.s_tabs_slide_left > .tab-pane.fade { + transform: translateX(-1rem); + } + &.s_tabs_slide_right > .tab-pane.fade { + transform: translateX(1rem); + } + } +} diff --git a/addons/website/static/src/snippets/s_tabs/options.js b/addons/website/static/src/snippets/s_tabs/options.js new file mode 100644 index 00000000000..b10a7619f85 --- /dev/null +++ b/addons/website/static/src/snippets/s_tabs/options.js @@ -0,0 +1,167 @@ +odoo.define('website.s_tabs_options', function (require) { +'use strict'; + +const options = require('web_editor.snippets.options'); + +options.registry.NavTabs = options.Class.extend({ + isTopOption: true, + + /** + * @override + */ + start: function () { + this._findLinksAndPanes(); + return this._super.apply(this, arguments); + }, + /** + * @override + */ + onBuilt: function () { + this._generateUniqueIDs(); + }, + /** + * @override + */ + onClone: function () { + this._generateUniqueIDs(); + }, + + //-------------------------------------------------------------------------- + // Options + //-------------------------------------------------------------------------- + + /** + * Creates a new tab and tab-pane. + * + * @see this.selectClass for parameters + */ + addTab: function (previewMode, widgetValue, params) { + var $activeItem = this.$navLinks.filter('.active').parent(); + var $activePane = this.$tabPanes.filter('.active'); + + var $navItem = $activeItem.clone(); + var $navLink = $navItem.find('.nav-link').removeClass('active show'); + var $tabPane = $activePane.clone().removeClass('active show'); + $navItem.insertAfter($activeItem); + $tabPane.insertAfter($activePane); + this._findLinksAndPanes(); + this._generateUniqueIDs(); + + $navLink.tab('show'); + }, + /** + * Removes the current active tab and its content. + * + * @see this.selectClass for parameters + */ + removeTab: function (previewMode, widgetValue, params) { + var self = this; + + var $activeLink = this.$navLinks.filter('.active'); + var $activePane = this.$tabPanes.filter('.active'); + + var $next = this.$navLinks.eq((this.$navLinks.index($activeLink) + 1) % this.$navLinks.length); + + return new Promise(resolve => { + $next.one('shown.bs.tab', function () { + $activeLink.parent().remove(); + $activePane.remove(); + self._findLinksAndPanes(); + resolve(); + }); + $next.tab('show'); + }); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _computeWidgetVisibility: async function (widgetName, params) { + if (widgetName === 'remove_tab_opt') { + return (this.$tabPanes.length > 2); + } + return this._super(...arguments); + }, + /** + * @private + */ + _findLinksAndPanes: function () { + this.$navLinks = this.$target.find('.nav:first .nav-link'); + this.$tabPanes = this.$target.find('.tab-content:first .tab-pane'); + }, + /** + * @private + */ + _generateUniqueIDs: function () { + for (var i = 0; i < this.$navLinks.length; i++) { + var id = _.now() + '_' + _.uniqueId(); + var idLink = 'nav_tabs_link_' + id; + var idContent = 'nav_tabs_content_' + id; + this.$navLinks.eq(i).attr({ + 'id': idLink, + 'href': '#' + idContent, + 'aria-controls': idContent, + }); + this.$tabPanes.eq(i).attr({ + 'id': idContent, + 'aria-labelledby': idLink, + }); + } + }, +}); +options.registry.NavTabsStyle = options.Class.extend({ + + //-------------------------------------------------------------------------- + // Options + //-------------------------------------------------------------------------- + + /** + * Set the style of the tabs. + * + * @see this.selectClass for parameters + */ + setStyle: function (previewMode, widgetValue, params) { + const $nav = this.$target.find('.s_tabs_nav:first .nav'); + const isPills = widgetValue === 'pills'; + $nav.toggleClass('nav-tabs card-header-tabs', !isPills); + $nav.toggleClass('nav-pills', isPills); + this.$target.find('.s_tabs_nav:first').toggleClass('card-header', !isPills).toggleClass('mb-3', isPills); + this.$target.toggleClass('card', !isPills); + this.$target.find('.s_tabs_content:first').toggleClass('card-body', !isPills); + }, + /** + * Horizontal/vertical nav. + * + * @see this.selectClass for parameters + */ + setDirection: function (previewMode, widgetValue, params) { + const isVertical = widgetValue === 'vertical'; + this.$target.toggleClass('row s_col_no_resize s_col_no_bgcolor', isVertical); + this.$target.find('.s_tabs_nav:first .nav').toggleClass('flex-column', isVertical); + this.$target.find('.s_tabs_nav:first > .nav-link').toggleClass('py-2', isVertical); + this.$target.find('.s_tabs_nav:first').toggleClass('col-md-3', isVertical); + this.$target.find('.s_tabs_content:first').toggleClass('col-md-9', isVertical); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _computeWidgetState: function (methodName, params) { + switch (methodName) { + case 'setStyle': + return this.$target.find('.s_tabs_nav:first .nav').hasClass('nav-pills') ? 'pills' : 'tabs'; + case 'setDirection': + return this.$target.find('.s_tabs_nav:first .nav').hasClass('flex-column') ? 'vertical' : 'horizontal'; + } + return this._super(...arguments); + }, +}); +}); diff --git a/addons/website/static/src/snippets/s_text_highlight/000.scss b/addons/website/static/src/snippets/s_text_highlight/000.scss new file mode 100644 index 00000000000..7728cff487e --- /dev/null +++ b/addons/website/static/src/snippets/s_text_highlight/000.scss @@ -0,0 +1,5 @@ +.s_text_highlight { + padding: 12px 8px 18px; + border-radius: 5px; + border: 1px solid rgba(white, 0.2); +} diff --git a/addons/website/static/src/snippets/s_three_columns/000.scss b/addons/website/static/src/snippets/s_three_columns/000.scss index d0df614aede..24e5224ec87 100644 --- a/addons/website/static/src/snippets/s_three_columns/000.scss +++ b/addons/website/static/src/snippets/s_three_columns/000.scss @@ -1,5 +1,5 @@ -.s_three_columns { - .align-items-stretch .card { +.s_three_columns:not([data-vcss]) { + .align-items-stretch > .card { height: 100%; } } diff --git a/addons/website/static/src/snippets/s_timeline/000.scss b/addons/website/static/src/snippets/s_timeline/000.scss new file mode 100644 index 00000000000..0e47e8a58f0 --- /dev/null +++ b/addons/website/static/src/snippets/s_timeline/000.scss @@ -0,0 +1,45 @@ +.s_timeline { + .s_timeline_line { + position: relative; + &:before { + content: ''; + position: absolute; + width: 1px; + top: 10px; + bottom: 10px; + left: 50%; + background-color: gray('800'); + z-index: 1; + } + } + .s_timeline_row { + align-items: center; + .s_timeline_content { + align-items: center; + justify-content: flex-end; + width: 100%; + ~ .s_timeline_content { + justify-content: flex-start; + } + } + &.flex-row-reverse { + .s_timeline_content { + flex-direction: row-reverse; + } + } + } + .s_timeline_date { + z-index: 2; + span:not(.fa) { + display: inline-block; + padding: 5px; + } + .fa { + margin: 0 $grid-gutter-width/2; + } + } + .s_timeline_icon { + flex: 0 0 auto; + margin: $grid-gutter-width/2; + } +} diff --git a/addons/website/static/src/snippets/s_title/000.scss b/addons/website/static/src/snippets/s_title/000.scss index 12d932c630c..a4e76dcadd5 100644 --- a/addons/website/static/src/snippets/s_title/000.scss +++ b/addons/website/static/src/snippets/s_title/000.scss @@ -1,5 +1,5 @@ -.s_title { +.s_title:not([data-vcss]) { .s_title_boxed { > * { display: inline-block; diff --git a/addons/website/views/assets.xml b/addons/website/views/assets.xml index 80e65be488b..3eaf292837f 100644 --- a/addons/website/views/assets.xml +++ b/addons/website/views/assets.xml @@ -115,6 +115,9 @@