$elementor->widgets_manager->register_widget_type( new Widgets\PageHeading() );
$elementor->widgets_manager->register_widget_type( new Widgets\HeroBlock() );
+ $elementor->widgets_manager->register_widget_type( new Widgets\BackgroundImage() );
$elementor->widgets_manager->register_widget_type( new Widgets\TextBlock() );
$elementor->widgets_manager->register_widget_type( new Widgets\Heading() );
$elementor->widgets_manager->register_widget_type( new Widgets\Timeline() );
--- /dev/null
+<?php
+
+namespace Cube\Elementor\Widgets;
+
+use Elementor\Widget_Base;
+use Elementor\Controls_Manager;
+use Elementor\Utils;
+
+
+class BackgroundImage extends Widget_Base {
+
+ protected $_has_template_content = false; // Tell Elementor that content is all rendered dynamically
+
+ // Widget name / ID
+ public function get_name() {
+ return 'cube-bg-image';
+ }
+
+ // Elementor widget title
+ public function get_title() {
+ return __( 'Flexible Image', 'cube' );
+ }
+
+ // Elementor interface icon
+ public function get_icon() {
+ return 'eicon-image';
+ }
+
+ // Where to display the widget in the Elementor interface
+ public function get_categories() {
+ return [ 'theme-elements' ];
+ }
+
+ /**
+ * List of scripts the widget depends on.
+ * Used to set scripts dependencies required to run the widget.
+ *
+ * @since 1.0.0
+ * @access public
+ * @return array Widget scripts dependencies.
+ */
+ public function get_script_depends() {
+ return [];
+ }
+ /**
+ * Register the widget controls.
+ * Adds different input fields to allow the user to change and customize the widget settings.
+ *
+ * @since 1.0.0
+ * @access protected
+ */
+ protected function _register_controls() {
+
+ $this->start_controls_section(
+ 'section_image',
+ [
+ 'label' => __( 'Flexible Background Image', 'cube' ),
+ ]
+ );
+
+ $this->add_control(
+ 'image',
+ [
+ 'label' => __( 'Choose Image', 'elementor' ),
+ 'type' => Controls_Manager::MEDIA,
+ 'default' => [
+ 'url' => Utils::get_placeholder_image_src(),
+ ],
+ ]
+ );
+
+ $this->add_control(
+ 'background_position',
+ [
+ 'label' => __( 'Background Position', 'cube' ),
+ 'type' => Controls_Manager::SELECT,
+ 'default' => 'center',
+ 'options' => [
+ 'top left' => __( 'Top Left', 'cube' ),
+ 'top center' => __( 'Top Center', 'cube' ),
+ 'top right' => __( 'Top Right', 'cube' ),
+ 'center' => __( 'Center', 'cube' ),
+ 'bottom left' => __( 'Bottom Left', 'cube' ),
+ 'bottom center' => __( 'Bottom Center', 'cube' ),
+ 'bottom right' => __( 'Bottom Right', 'cube' ),
+ ],
+ ]
+ );
+
+ $this->end_controls_section();
+ }
+ /**
+ * Render the widget output on the frontend.
+ * Written in PHP and used to generate the final HTML.
+ *
+ * @since 1.0.0
+ * @access protected
+ */
+ protected function render() {
+
+ $image = $this->get_settings('image');
+ $bg_position = $this->get_settings('background_position');
+ $meta = wp_get_attachment_metadata($image['id']);
+ $ratio = $meta['height'] / $meta['width'] * 100 .'%';
+
+ echo '<div class="bg-image" style="background-image: url('. $image['url'] .'); background-position: '. $bg_position .'"><div class="bg-image-sizer" style="padding-bottom: '. $ratio .'"></div></div>';
+
+ }
+}
import SmoothScroll from 'smooth-scroll';
+import sidr from 'sidr/dist/jquery.sidr'; // eslint-disable-line
export default {
init() {
// JavaScript to be fired on all pages
- new SmoothScroll('a[href*="#"]', {
- speed: 300,
- offset: 0,
- });
+
+ // Mobile Menu setup
+ $('#mobile-menu-opener').sidr({
+ name: 'offcanvas-menu',
+ source: '.nav-primary',
+ side: 'right',
+ speed: 500, // Animation speed
+ displace: true, // Push body content when opening?
+ renaming: false, // Rename existing classes / IDs?
+ });
+
+ $('#offcanvas-menu').prepend($('.header-logo')[0].outerHTML);
+
+ // Add menu overlay element
+ $('<div id="offcanvas-menu-overlay"></div>').appendTo('body');
+
+ // Auto-close mobile menu when links are clicked or we click on the overlay
+ $('#offcanvas-menu-overlay, #offcanvas-menu a').on('click', function(event) {
+ $.sidr('close', 'offcanvas-menu'); // close the div with the ID of "offcanvas-menu"
+
+ // Don't follow empty links (eg. close button)
+ if ($(this).attr('href') === '#') {
+ event.preventDefault();
+ }
+ });
+
+ // Menu toggle
+ $('#full-menu-opener').on('click', function(event) {
+
+ // On larger screens, the menu button just hides the menu
+ //if ($(window).width() < 1024) {
+ $.sidr('open', 'offcanvas-menu');
+ //} else {
+ // $('.nav-primary').toggleClass('nav-hidden');
+ //}
+
+ event.preventDefault();
+ });
+
+ // Disable clicks on top level menu links that have sub-menus
+ $(document).on('click', '.nav-primary .menu-item-has-children > a', function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ return false;
+ });
+
+ // Set up smooth scrolling to anchor links
+ new SmoothScroll('a[href*="#"]', {
+ speed: 300,
+ offset: 0,
+ });
+
},
finalize() {
// JavaScript to be fired on all pages, after page specific JS is fired
box-sizing: border-box
height: 100%
font-size: $font-size-base // This value won't be converted to REMs due to exception in font-size() mixin
- +below(1400px)
- font-size: 18px
+below(1250px)
- font-size: 17px
- +below(1100px)
- font-size: 16px
- +below(900px)
font-size: 15px
- +below(600px)
+ +below(1024px)
font-size: 14px
*,
p:not(:last-of-type)
margin-bottom: 1.5em
+// Make sure widget has height when column flex align-items is set
+// This is for widgets that don't take up height on their own, like
+// the flexible background image. Ideally the parent column shouldn't
+// have an alignment set (so it stretches) but this doesn't seem to do any
+// harm and it's more intuitive behaviour...
+.elementor-widget-wrap
+ height: 100%
+
.content-inner,
.elementor-section-boxed > .elementor-container
horizontal-spacing()
+// Font size helpers
+for textSizeName, textSize in $font-size
+ .text-{textSizeName}
+ font-size: textSize
+
+
.vertical-spacing
vertical-spacing()
constrain(padding-left, 7.5vw)
.pr-7\\.5vw
constrain(padding-right, 7.5vw)
+.pt-7\\.5vw
+ constrain(padding-top, 7.5vw)
+.pb-7\\.5vw
+ constrain(padding-bottom, 7.5vw)
.font-smoothing
font-smoothing()
// Fonts
$font = 'Muli', sans-serif
+// TODO: replace any $font-size-xxx variable references with $font-size array below
// Font sizing
$font-size-base = 16px // Size of 1rem
$font-size-small = 24px // h4
$font-size-extra-small = 12px //
+$font-size = {
+ 'sm': 12px,
+ 'base': 16px,
+ 'lg': 24px, // h4
+ 'xl': 36px, // h3
+ '2xl': 54px, // h2
+ '3xl': 81px, // h1
+}
+// See utilities.styl for font-size helpers (can't be done here because we need the mixins to be included first)
+
// Breakpoints in Rupture (https://github.com/jescalan/rupture)
rupture.scale = 0 400px 768px 1024px
rupture.scale-names = 'small' 'medium' 'large'
background-color: $colors.light-grey
&-success
- display: none // Don't display the message since we will be redirecting...
- //background-color: #e8f5e9
- //color: #4caf50
+ //display: none // Don't display the message since we will be redirecting...
+ background-color: #e8f5e9
+ color: #4caf50
// ParsleyJS validation
.parsley-errors-list
-// Source of the off-canvas menu
-.nav-full
- display: none
+$sidebar-width = 260px
-// Actual menu built by Sidr plugin
#offcanvas-menu
- background-color: #fff
- horizontal-spacing(5vw)
- vertical-spacing(2.5vw)
- width: 35%
- max-width: 590px
- min-width: 320px
+ background-color: #222
+ color: #fff
+ display: block
+ position: fixed
+ top: 0
+ height: 100%
+ z-index: 999999
+ width: $sidebar-width
+ overflow-x: hidden
+ overflow-y: auto
- // The default Sidr CSS has fixed offsets for hiding the menu so we need to fix that...
&.right
- right: -100%
+ left: auto
+ right: - $sidebar-width
+
&.left
- left: -100%
+ left: - $sidebar-width
+ right: auto
+
+ .header-logo
+ margin-top: 1em
+ border-bottom: none
- a
&:hover
- color: $colors.orange
+ background-color: transparent
- .close
- position: absolute
- constrain(top, 2.5vw)
- constrain(right, 2.5vw)
+ &-svg
+ width: 60px
- .menu-close-icon
- width: 3rem
- height: @width
+ ul
+ list-style-type: none
+ padding-left: 0
+ white-space: normal
- .estimate-button
- width: 100%
- text-align: center
- margin-bottom: 1em
- white-space: nowrap
+ li
+ display: block
+ margin-right: 0
+ ul a // Second level links
+ padding-left: 40px
+ color: #bbb
+ font-weight: normal
+ text-transform: none
+
+ a
+ font-smoothing()
+ display: block
+ padding: 10px 20px
+ border-bottom: 1px solid #333
+ text-transform: uppercase
+ font-weight: 700
+ color: #fff
&:hover
+ background: $colors.orange
+ text-decoration: none
color: #fff
- &-wrapper
- padding-right: 4rem // Leave space for close button
-
- // Nav lists
- .nav-list
- reset-list()
-
- .menu-item
- padding: 0.5em 0
- border-bottom: 1px solid #D4D4D4
-
- .nav-offers-title
- text-transform: uppercase
- margin-top: 1.5em
- font-weight: 500
// Content overlay when menu is open
height: auto
-@media (min-width: 30rem)
- .alignleft
- float: left
- margin-right: 1rem
-
+//@media (min-width: 30rem)
+.alignleft
+ float: left
+ margin-right: 1rem
+
- .alignright
- float: right
- margin-left: 1rem
+.alignright
+ float: right
+ margin-left: 1rem
-$breakpoint-footer-cols-2 = 880px // When to break to 2 col view
+$breakpoint-footer-cols-2 = 980px // When to break to 2 col view
+$breakpoint-footer-medium = 800px // Layout with logo + address on same line / other items stacked below
$breakpoint-footer-cols-1 = 710px // When to break to 1 col view
.footer
constrain(padding-right, 2.5vw)
margin: 0.75em 0
+ +below($breakpoint-footer-medium)
+ &:nth-child(n+3) // leave just the first 2 cols side by side
+ flex-basis: 100%
+
+below($breakpoint-footer-cols-1)
flex-basis: 100%
justify-content: center !important
+.elementor-section.elementor-section-full_width
+ //--- Columns responsiveness
+ // Full width sections have columns stacked but no margin is placed between them
+ // This is to accommodate the flexible background image blocks
+
+ // TODO: consider adding a "no gap" option to the section when wrapping? Then it can be applied to full width or boxed sections...
+
+
+ +below($breakpoint-columns)
+ .elementor-column
+ width: 100% !important
+
+
.elementor-section.elementor-section-boxed
//--- Columns responsiveness - stack all standard columns below breakpoint
--- /dev/null
+.bg-image
+ background-size: cover
+ background-repeat: no-repeat
+ background-position: center
+
+ &-sizer
+ // The sizer is only needed when in one column mode.
+ // The rest of the time it should just fill the height
+ // required by the other column's content...
+ +above($breakpoint-columns)
+ display: none
+
+// Ensure full height on element so the image always covers the full area
+.elementor-widget-cube-bg-image, .elementor-widget-container, .bg-image
+ height: 100%
// Text block widget (Elementor defaults)
-// Padding is applied here so it can be overridden by Elementor
-.elementor-widget-cube-text .elementor-widget-container
+.elementor-widget-cube-text //.elementor-widget-container
horizontal-spacing(7.5vw)
vertical-spacing(10vw)
max-width: 480px
+ width: 100%
box-sizing: content-box // So padding doesn't influence max-width
// When in a "default" section layout, add some padding