--- /dev/null
+<?php
+
+namespace Cube\Elementor\Widgets;
+
+use Elementor\Controls_Manager;
+use Elementor\Utils;
+
+use function Roots\view;
+
+
+class PhotoGrid extends _Base {
+
+ // Widget name / ID
+ public function get_name() {
+ return 'cube-photo-grid';
+ }
+
+ // Elementor widget title
+ public function get_title() {
+ return __( 'Photo Grid', 'cube' );
+ }
+
+ // Elementor interface icon
+ public function get_icon() {
+ return 'eicon-posts-grid';
+ }
+
+ /**
+ * 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' => __( 'Photo Grid', 'cube' ),
+ ]
+ );
+
+ $this->add_control(
+ 'items',
+ [
+ 'label' => __( 'Photos', 'cube' ),
+ 'type' => Controls_Manager::REPEATER,
+ 'fields' => [
+ [
+ 'name' => 'image',
+ 'label' => __('Photo', 'cube'),
+ 'label_block' => true,
+ 'type' => Controls_Manager::MEDIA,
+ 'default' => [
+ 'url' => Utils::get_placeholder_image_src(),
+ ],
+ ],
+ [
+ 'name' => 'caption',
+ 'label' => __( 'Caption', 'cube' ),
+ 'type' => Controls_Manager::TEXTAREA,
+ 'label_block' => true,
+ 'default' => '',
+ ],
+ ],
+ 'title_field' => '{{{ caption }}}',
+ ]
+ );
+ $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() {
+ $items = $this->get_settings('items');
+ echo view('widgets/photo-grid', compact('items'));
+ }
+}
--- /dev/null
+.photo-grid
+ display: grid
+ grid-template-columns: repeat(3, 1fr)
+ constrain(grid-gap, 5vw)
+
+ +below(768px)
+ grid-template-columns: repeat(2, 1fr)
+ +below(450px)
+ grid-template-columns: repeat(1, 1fr)
+
+ &-image
+ @apply bg-contain bg-center bg-no-repeat
+
+ &-sizer
+ padding-bottom: 100% // Ratio based sizing to make a square
+
+ &-caption
+ @apply text-center italic mx-auto
+ max-width: 320px
+
+ &:before
+ @apply bg-pink
+ content: ''
+ display: block
+ width: 48px
+ height: 5px
+ margin: 1em auto