# Misc
+.uploads-proxy
.DS_Store
.idea
_doc
# Application
web/app/plugins/*
!web/app/plugins/.gitkeep
+web/app/mu-plugins/wp-migrate-db-pro-compatibility.php
web/app/mu-plugins/*/
!web/app/mu-plugins/cube
web/app/upgrade
$elementor->widgets_manager->register_widget_type( new Widgets\TextBlock() );
$elementor->widgets_manager->register_widget_type( new Widgets\IntroCarousel() );
$elementor->widgets_manager->register_widget_type( new Widgets\Circle() );
+ $elementor->widgets_manager->register_widget_type( new Widgets\BackgroundLayer() );
$elementor->widgets_manager->register_widget_type( new Widgets\ImageMap() );
$elementor->widgets_manager->register_widget_type( new Widgets\TeamGrid() );
- $elementor->widgets_manager->register_widget_type( new Widgets\Realisations() );
+ $elementor->widgets_manager->register_widget_type( new Widgets\LatestRealisations() );
+ $elementor->widgets_manager->register_widget_type( new Widgets\LatestNews() );
}
$element->add_render_attribute('_wrapper', 'data-cols', $cols);
-// echo "<h2>COLS: $cols</h2>";
-// echo "<pre>";
-// /* @var \Elementor\Element_Column $el */
-// foreach ($children as $child) {
-// print_r($child->get_data()['settings']);
-// }
-// echo "</pre>";
+ //echo "<h2>COLS: $cols</h2>";
+ //echo "<pre>";
+ ///* @var \Elementor\Element_Column $el */
+ //foreach ($children as $child) {
+ // print_r($child->get_data()['settings']);
+ //}
+ //echo "</pre>";
$settings = $element->get_settings();
--- /dev/null
+<?php
+
+namespace Cube\Elementor\Widgets;
+
+use Elementor\Controls_Manager;
+
+
+class BackgroundLayer extends _Base {
+
+ // Widget name / ID
+ public function get_name() {
+ return 'cube-bg-layer';
+ }
+
+ // Elementor widget title
+ public function get_title() {
+ return __( 'Fond Détaché', 'cube' );
+ }
+
+ // Elementor interface icon
+ public function get_icon() {
+ return 'eicon-navigator';
+ }
+
+ /**
+ * 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_content',
+ [
+ 'label' => __( 'Fond Détaché', 'cube' ),
+ ]
+ );
+
+ $this->add_control(
+ 'bg_color',
+ [
+ 'label' => __( 'Couleur', 'cube' ),
+ 'type' => Controls_Manager::COLOR,
+ 'default' => '',
+ 'selectors' => [
+ '{{WRAPPER}} .cube-bg-layer' => 'background-color: {{VALUE}};',
+ ],
+ ]
+ );
+
+
+ $this->add_control(
+ '_z_index', // A more convenient version than the one in the advanced settings
+ [
+ 'label' => __( 'Z-Index', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '0',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'z-index: {{VALUE}};',
+ ],
+ ]
+ );
+
+ $this->add_control(
+ '_css_classes', // A more convenient version than the one in the advanced settings
+ [
+ 'label' => __( 'CSS Classes', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '',
+ 'prefix_class' => '',
+ ]
+ );
+
+ $this->add_control(
+ 'top',
+ [
+ 'label' => __( 'Top Offset', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '0',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'top: {{VALUE}};',
+ ],
+ ]
+ );
+
+ $this->add_control(
+ 'bottom',
+ [
+ 'label' => __( 'Bottom Offset', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '0',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'bottom: {{VALUE}};',
+ ],
+ ]
+ );
+
+ $this->add_control(
+ 'left',
+ [
+ 'label' => __( 'Left Offset', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '0',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'left: {{VALUE}};',
+ ],
+ ]
+ );
+
+ $this->add_control(
+ 'right',
+ [
+ 'label' => __( 'Left Offset', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '0',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'right: {{VALUE}};',
+ ],
+ ]
+ );
+
+ $this->add_control(
+ 'width',
+ [
+ 'label' => __( 'Width', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => 'auto',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'width: {{VALUE}};',
+ ],
+ ]
+ );
+
+ $this->add_control(
+ 'height',
+ [
+ 'label' => __( 'Height', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => 'auto',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'height: {{VALUE}};',
+ ],
+ ]
+ );
+
+ $this->add_control(
+ 'margin_bottom',
+ [
+ 'label' => __( 'Bottom Margin', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '0',
+ 'selectors' => [
+ '{{WRAPPER}}' => 'margin-bottom: {{VALUE}} !important;',
+ ],
+ ]
+ );
+
+// $this->add_control(
+// 'width',
+// [
+// 'label' => __( 'Largeur', 'cube' ),
+// 'type' => Controls_Manager::TEXT,
+// 'default' => '100%',
+// 'selectors' => [
+// '{{WRAPPER}} .bg-layer' => 'width: {{VALUE}};',
+// ],
+// ]
+// );
+
+
+
+ $this->end_controls_section();
+
+ $this->common_controls();
+ }
+ /**
+ * 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() {
+ echo '<div class="cube-bg-layer bg-light w-full h-full" style="min-height: 1px"></div>';
+ }
+}
--- /dev/null
+<?php
+
+namespace Cube\Elementor\Widgets;
+
+use Elementor\Controls_Manager;
+
+use function Roots\view;
+
+
+class LatestNews extends _Base {
+
+ protected $_has_template_content = false; // Tell Elementor that content is all rendered dynamically
+
+ // Widget name / ID
+ public function get_name() {
+ return 'cube-latest-news';
+ }
+
+ // Elementor widget title
+ public function get_title() {
+ return __( 'Dernières Actualités', 'cube' );
+ }
+
+ // Elementor interface icon
+ public function get_icon() {
+ return 'eicon-post-list';
+ }
+
+ /**
+ * 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_content',
+ [
+ 'label' => __( 'Dernières Actualités', 'cube' ),
+ ]
+ );
+
+ $this->add_control(
+ 'widget_description',
+ [
+ 'raw' => __( 'Ce widget affichera les actualités les plus récentes', 'cube' ),
+ 'type' => Controls_Manager::RAW_HTML,
+ 'content_classes' => 'elementor-descriptor',
+ ]
+ );
+
+ /*
+ $this->add_control(
+ 'posts_limit',
+ [
+ 'label' => __( 'Number of posts to display', 'cube' ),
+ 'type' => Controls_Manager::NUMBER,
+ 'default' => 3,
+ ]
+ );
+ */
+
+ $this->end_controls_section();
+
+ $this->common_controls();
+ }
+ /**
+ * 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() {
+
+ $posts_limit = 3; //$this->get_settings('posts_limit');
+
+ $news_posts = wp_get_recent_posts([
+ 'numberposts' => $posts_limit,
+ 'orderby' => 'post_date',
+ 'order' => 'DESC',
+ 'post_type' => 'post',
+ 'post_status' => 'publish',
+ 'suppress_filters' => true
+ ]);
+
+ if ($news_posts) {
+ echo view('widgets.latest-news', compact('news_posts'));
+ }
+
+ }
+}
--- /dev/null
+<?php
+
+namespace Cube\Elementor\Widgets;
+
+use Elementor\Controls_Manager;
+
+use function Roots\view;
+
+
+class LatestRealisations extends _Base {
+
+ protected $_has_template_content = false; // Tell Elementor that content is all rendered dynamically
+
+ // Widget name / ID
+ public function get_name() {
+ return 'cube-latest-realisations';
+ }
+
+ // Elementor widget title
+ public function get_title() {
+ return __( 'Dernières Réalisations', 'cube' );
+ }
+
+ // Elementor interface icon
+ public function get_icon() {
+ return 'eicon-post-list';
+ }
+
+ /**
+ * 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_content',
+ [
+ 'label' => __( 'Dernières Réalisations', 'cube' ),
+ ]
+ );
+
+ $this->add_control(
+ 'widget_description',
+ [
+ 'raw' => __( 'Ce widget affichera les réalisations les plus récentes', 'cube' ),
+ 'type' => Controls_Manager::RAW_HTML,
+ 'content_classes' => 'elementor-descriptor',
+ ]
+ );
+
+ /*
+ $this->add_control(
+ 'posts_limit',
+ [
+ 'label' => __( 'Number of posts to display', 'cube' ),
+ 'type' => Controls_Manager::NUMBER,
+ 'default' => 3,
+ ]
+ );
+ */
+
+ $this->end_controls_section();
+
+ $this->common_controls();
+ }
+ /**
+ * 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() {
+
+ $posts_limit = 3; //$this->get_settings('posts_limit');
+
+ $realisation_posts = wp_get_recent_posts([
+ 'numberposts' => $posts_limit,
+ 'orderby' => 'post_date',
+ 'order' => 'DESC',
+ 'post_type' => 'realisation',
+ 'post_status' => 'publish',
+ 'suppress_filters' => true
+ ]);
+
+ if ($realisation_posts) {
+ echo '<div class="latest-realisations">';
+ foreach ($realisation_posts as $realisation_post) {
+ echo view('partials.content-realisation', compact('realisation_post'));
+ }
+ echo '</div>';
+ }
+
+ }
+}
+++ /dev/null
-<?php
-
-namespace Cube\Elementor\Widgets;
-
-use Elementor\Controls_Manager;
-
-use function Roots\view;
-
-
-class Realisations extends _Base {
-
- protected $_has_template_content = false; // Tell Elementor that content is all rendered dynamically
-
- // Widget name / ID
- public function get_name() {
- return 'cube-realisations';
- }
-
- // Elementor widget title
- public function get_title() {
- return __( 'Réalisations', 'cube' );
- }
-
- // Elementor interface icon
- public function get_icon() {
- return 'eicon-post-list';
- }
-
- /**
- * 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_content',
- [
- 'label' => __( 'Réalisations', 'cube' ),
- ]
- );
-
- $this->add_control(
- 'widget_description',
- [
- 'raw' => __( 'This widget will display the most recent réalisation posts.', 'cube' ),
- 'type' => Controls_Manager::RAW_HTML,
- 'content_classes' => 'elementor-descriptor',
- ]
- );
-
- $this->add_control(
- 'posts_limit',
- [
- 'label' => __( 'Number of posts to display', 'cube' ),
- 'type' => Controls_Manager::NUMBER,
- 'default' => 10,
- ]
- );
-
- $this->end_controls_section();
-
- $this->common_controls();
- }
- /**
- * 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() {
-
- $posts_limit = $this->get_settings('posts_limit');
-
- $realisation_posts = wp_get_recent_posts([
- 'numberposts' => $posts_limit,
- 'orderby' => 'post_date',
- 'order' => 'DESC',
- 'post_type' => 'realisation',
- 'post_status' => 'publish',
- 'suppress_filters' => true
- ]);
-
- if ($realisation_posts) {
- foreach ($realisation_posts as $realisation_post) {
- echo view('partials.content-realisation', compact('realisation_post'));
- }
- }
-
- }
-}
]
);
+ $this->add_responsive_control(
+ 'width',
+ [
+ 'label' => __( 'Width', 'elementor' ),
+ 'type' => Controls_Manager::TEXT,
+ 'default' => '100%',
+ 'selectors' => [
+ '{{WRAPPER}} .text-block' => 'width: {{VALUE}};',
+ ],
+ ]
+ );
+
$this->add_control(
'max_width',
[
elementorFrontend.hooks.addAction('frontend/element_ready/cube-intro-carousel.default', function ($scope) {
// Inspired by: https://www.sitepoint.com/make-a-simple-javascript-slideshow-without-jquery/
- const slides = $scope.find('.intro-carousel-image');
+ const slides = $scope.find('.intro-carousel-slide');
const slideInterval = setInterval(nextSlide, 4000);
let currentSlide = 0;
- initSlideshow();
-
- function initSlideshow() {
- let slideshowDots = document.createElement('ul');
- slideshowDots.className = 'intro-carousel-dots';
-
- // Build dots navigation
- slides.each(function (index) {
- let item = document.createElement('li');
- item.setAttribute('data-slide', index);
- if (index === 0) {
- item.className = 'active';
- }
- slideshowDots.appendChild(item);
- });
-
- $scope.append(slideshowDots);
-
- $(document).on('click', '.intro-carousel-dots li', function() {
- clearInterval(slideInterval); // Stop autoplay
- showSlide($(this).data('slide'));
- });
- }
+ showSlide(0);
function showSlide(index) {
$(slides[currentSlide]).removeClass('showing');
showSlide(currentSlide - 1);
}
-
-
});
});
})(jQuery);
//=== Burger menu icon + animation
&-opener
- position: fixed
+ position: absolute
width: 30px
height: @width
top: @width
--- /dev/null
+.elementor-widget-cube-bg-layer
+ position: absolute
+ margin-bottom: 0
+
+ .elementor-widget-container
+ min-height: 1px // Prevent Elementor editor from thinking this is empty because it only contains absolute positioned elements
+ height: 100%
--- /dev/null
+$breakpoint-carousel = 768px
+
+
+.intro-carousel
+ @apply flex flex-row-reverse items-center
+
+ +below($breakpoint-carousel)
+ @apply flex-col-reverse
+
+ &-text
+ flex-basis: 40%
+
+ +below(1600px)
+ flex-basis: 50%
+ +below(1350px)
+ flex-basis: 60%
+
+ &-slides
+ flex-basis: 60%
+
+ +below($breakpoint-carousel)
+ width: 100%
+ margin-right: 2.5vw
+ margin-bottom: 5vw
+
+ &-slide
+ position: relative
+ z-index: 1
+ opacity: 0
+ transition: opacity 1s
+
+ &.showing
+ opacity: 1
+ z-index: 2
+
+
+ &-caption
+ position: absolute
+ bottom: 6%
+ left: 3%
+ right: 60%
+ text-align: right
+
+ +below(1600px)
+ font-size: 1.1vw
+ +below(1350px)
+ font-size: 0.9vw
+ +below($breakpoint-carousel)
+ font-size: 2vw
--- /dev/null
+.latest-news
+ display: grid
+ grid-template-columns: repeat(3, 1fr)
+ constrain(grid-gap, 5vw)
+
+ +below(1024px)
+ @apply text-sm
+ grid-gap: 2.5vw
+
+ +below(500px)
+ grid-template-columns: 1fr
+ grid-gap: 7.5vw
--- /dev/null
+.latest-realisations
+ display: grid
+ grid-template-columns: repeat(3, 1fr)
+ constrain(grid-gap, 5vw)
+
+ +below(1024px)
+ @apply text-sm
+ grid-gap: 2.5vw
+
+ +below(500px)
+ grid-template-columns: 1fr
+ grid-gap: 7.5vw
+
+ article
+ padding-top: 0 !important
+
+ article
+ &:nth-child(1)
+ constrain(padding-top, 2.5vw)
+ &:nth-child(3)
+ constrain(padding-top, 5vw)
+
+ &.mt-2v
+ margin-top: 0
@section('content')
- <h2 class="text-2xl text-center my-2v mx-1v">L'actu mobilier & déco</h2>
+ <h2 class="text-2xl text-center my-2v mx-1v">L’actu mobilier & déco</h2>
{{-- Applying 1px vertical padding here so margins take effect at top and bottom (can't use overflow:hidden due to background decorations) --}}
<div class="container relative my-2v" style="padding: 1px 0">
// exists outside the loop, we are sometimes getting data that is passed in and other times relying on
// the global loop context. As a result, the code had to be modified a bit to work in both situations.
$postID = isset($realisation_post) ? $realisation_post['ID'] : $post->ID;
- $thumbnail = carbon_get_post_meta($postID, 'thumbnail');
+ $thumbnail = get_post_meta($postID, '_thumbnail', true);
$thumbnail_image = $thumbnail ? wp_get_attachment_image($thumbnail, 'large') : '';
- $thumbnail_caption = carbon_get_post_meta($postID, 'thumbnail_caption');
+ $thumbnail_caption = get_post_meta($postID, '_thumbnail_caption', true);
@endphp
<article <?php post_class('mt-2v sm:mt-12', $postID) ?>>
<a href="{{ get_permalink($postID) }}">{!! $thumbnail_image !!}</a>
- <div class="text-center mt-6">{{ $thumbnail_caption }}</div>
+ <div class="mx-1v px-2 text-center mt-6">{{ $thumbnail_caption }}</div>
</article>
<p class="leading-7">{!! nl2br(get_option('contact_footer_text')) !!}</p>
<div class="flex flex-col spaced text-left mx-auto" style="max-width: 180px">
- <a class="flex items-center" href="tel:{{ $contact_phone_link }}">
+ <a class="flex items-center" href="{{ $contact_phone_link }}">
@svg('images/icons/phone', 'fill-current h-10 mr-4')
{{ $contact_phone }}
</a>
<h3 class="font-medium uppercase text-base mt-8 mb-1">Des promos & des news !</h3>
<p class="mb-6">Inscrivez-vous à notre newsletter</p>
- <div class="footer-newsletter-form flex mx-auto" style="max-width: 300px">
- {{-- TODO: add HTMLForms shortcode here? --}}
- <input type="email" name="email" placeholder="Votre email" class="flex-1 text-dark leading-8 rounded-full focus:outline-none focus:ring-2 focus:ring-opacity-50 focus:ring-dark px-4 mr-3">
- <input type="submit" value="Ok" class="font-medium bg-red text-white rounded-full w-10 h-10 focus:outline-none focus:ring-2 focus:ring-opacity-50 focus:ring-dark">
- </div>
+ {!! do_shortcode('[hf_form slug="newsletter"]') !!}
</div>
</div>
</div>
</div>
- <a href="{{ $contact_phone_link }}" class="absolute right-0 mr-1v top-1/2 transform -translate-y-1/2 flex items-center pb-12 sm:hidden">
+ <a href="{{ $contact_phone_link }}" class="absolute right-0 mr-1v top-1/2 transform -translate-y-1/2 flex items-center -mt-6 sm:hidden">
<span class="font-semibold text-right text-sm">
{{ get_option('contact_header_text') }}<br/>
<span class="text-lg">{{ $contact_phone }}</span>
@section('content')
{{-- H2 tag here because the post has a H1 for the title --}}
- <h2 class="text-2xl text-center my-2v mx-1v">L'actu mobilier & déco</h2>
+ <h2 class="text-2xl text-center my-2v mx-1v">L’actu mobilier & déco</h2>
<div class="container-content relative py-2v">
{{-- INTRO CAROUSEL --}}
-<div class="intro-carousel flex flex-row-reverse items-center" id="{{ $id }}">
+<div class="intro-carousel" id="{{ $id }}">
- <div style="flex-basis: 40%">
+ <div class="intro-carousel-text">
<div class="mx-1v" style="max-width: 624px">
<h1 class="relative text-2xl md:text-xl font-semibold leading-tight mb-8">
{{ $title }}
</div>
</div>
- <div class="intro-carousel-slides" style="flex-basis: 60%">
+ <div class="intro-carousel-slides">
<div class="intro-carousel-slides-sizer relative ml-1v" style="padding-bottom: 71.287%">
@foreach ($slides as $slide)
- <div class="intro-carousel-slide absolute top-0 left-0 w-full h-full @if(!$loop->first)hidden @endif">
+ <div class="intro-carousel-slide absolute top-0 left-0 w-full h-full">
<img src="{{ $slide['background_image']['url'] }}" class="absolute top-0 right-0">
<img src="{{ $slide['image']['url'] }}" class="absolute" style="border-radius: 999px; max-width: 69.475%; top: 2.35%; right: 4.575%">
- <div class="intro-carousel-slide-caption">{{ $caption }}</div>
+ <div class="intro-carousel-slide-caption">{{ $slide['caption'] }}</div>
</div>
@endforeach
</div>
--- /dev/null
+<div class="latest-news">
+ @foreach ($news_posts as $post)
+ <article @php(post_class(null, $post['ID']))>
+
+ {{-- Featured Image --}}
+ <div class="post-featured-image bg-cover" style="background-image: url({{ get_the_post_thumbnail_url($post['ID']) }})">
+ <a class="block pb-100%" href="{{ get_permalink($post['ID']) }}">
+ {{-- Link acts as a proportional sizer thanks to the padding --}}
+ </a>
+ </div>
+
+ {{-- Post Category and Title --}}
+ <div class="mt-1v mx-1v px-2 text-center">
+ <a href="{{ get_permalink() }}">{!! $post['post_title'] !!}</a>
+ </div>
+
+ </article>
+ @endforeach
+</div>
'./app/View/**/*.php',
'./resources/views/**/*.php',
'./resources/assets/**/*.js',
+ './.purgecss-whitelist',
],
options: {
// Todo: make a script to generate a list of all custom classes used in Elementor content