├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── package-lock.json ├── package.json ├── public ├── css │ └── wpc-styles.min.css ├── js │ ├── wpc-scripts.asset.php │ ├── wpc-scripts.js │ └── wpc-scripts.js.map └── vendor │ ├── css │ ├── animate.min.css │ ├── font-awesome.min.css │ ├── hover.min.css │ └── tinyslider.min.css │ ├── js │ ├── scrollreveal.min.js │ └── tinyslider.min.js │ └── webfonts │ ├── fa-brands-400.eot │ ├── fa-brands-400.svg │ ├── fa-brands-400.ttf │ ├── fa-brands-400.woff │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.eot │ ├── fa-regular-400.svg │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.eot │ ├── fa-solid-900.svg │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff │ └── fa-solid-900.woff2 ├── src ├── Ajax.php ├── Boot.php ├── Build.php ├── assets │ ├── atoms │ │ ├── author.less │ │ ├── breadcrumbs.less │ │ ├── button.less │ │ ├── cart.less │ │ ├── cart.ts │ │ ├── comments.less │ │ ├── image.less │ │ ├── list.less │ │ ├── logo.less │ │ ├── map.less │ │ ├── map.ts │ │ ├── menu.less │ │ ├── menu.ts │ │ ├── modal.less │ │ ├── modal.ts │ │ ├── pagination.less │ │ ├── rate.less │ │ ├── rate.ts │ │ ├── scroll.less │ │ ├── scroll.ts │ │ ├── search.less │ │ ├── search.ts │ │ ├── share.less │ │ ├── share.ts │ │ ├── social.less │ │ ├── tabs.less │ │ ├── tabs.ts │ │ ├── termlist.less │ │ ├── terms.less │ │ └── video.less │ ├── molecules │ │ ├── footer.less │ │ ├── header.less │ │ ├── header.ts │ │ ├── post-footer.less │ │ ├── post-header.less │ │ ├── posts.less │ │ ├── posts.ts │ │ ├── section.less │ │ ├── slider.less │ │ └── slider.ts │ ├── other │ │ ├── animations.less │ │ ├── colors.less │ │ ├── global.less │ │ ├── grid.less │ │ ├── modules.ts │ │ ├── social.less │ │ └── utils.ts │ ├── scripts.ts │ ├── styles.less │ └── types │ │ ├── ajax-data.ts │ │ ├── component.ts │ │ └── sibling-types.ts ├── components │ ├── atoms │ │ ├── archive-title.php │ │ ├── author.php │ │ ├── breadcrumbs.php │ │ ├── button.php │ │ ├── callback.php │ │ ├── cart.php │ │ ├── comments.php │ │ ├── compatible │ │ │ ├── comments.php │ │ │ └── index.php │ │ ├── content.php │ │ ├── copyright.php │ │ ├── date.php │ │ ├── description.php │ │ ├── image.php │ │ ├── list.php │ │ ├── logo.php │ │ ├── map.php │ │ ├── menu.php │ │ ├── meta.php │ │ ├── modal.php │ │ ├── pagination.php │ │ ├── rate.php │ │ ├── scroll.php │ │ ├── search.php │ │ ├── share.php │ │ ├── sidebar.php │ │ ├── social.php │ │ ├── string.php │ │ ├── tabs.php │ │ ├── termlist.php │ │ ├── terms.php │ │ ├── title.php │ │ ├── type.php │ │ └── video.php │ └── molecules │ │ ├── footer.php │ │ ├── header.php │ │ ├── posts.php │ │ ├── section.php │ │ └── slider.php └── includes │ └── functions.php ├── tsconfig.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.git 3 | *.gitmodules 4 | *.gitignore 5 | *git/ 6 | 7 | node_modules/ 8 | /.htaccess 9 | /license.txt 10 | /readme.html 11 | /sitemap.xml 12 | /sitemap.xml.gz -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wp-components 2 | Many frameworks use a modular approach for designing applications. While developing WordPress websites, we found out we're writing similar code a lot of times, even with existing frameworks and themes. That's why we developed WP Components, a set of common components with minimal styling but many functionalities. 3 | 4 | WP Components contains common components that may be used in WordPress development. This helps to speed up development greatly, because the components doens't have to be redeveloped. It is aimed at WordPress Developers. 5 | 6 | The components are seperated in two classes, namely atoms which are single components and molecules which are consisting of multiple atoms. 7 | * An atom is for example a set of **sharing buttons**, a **title**, a **button**, a **search field**, **breadcrumbs** and so forth. 8 | * A molecule is for example a **site header**, a **grid of posts**, a **slider**, a **header** within an article, and so forth. 9 | 10 | WP Components is maintained by [Make it WorkPress](https://makeitwork.press/scripts/wp-components/). 11 | 12 |   13 | ## Installation 14 | 15 | Require the Ajax.php, Boot.php and Build.php files in your theme functions.php or a custom plugin. Additionaly, you could also use an autoloader or include it as a repository using Composer. You can read more about autoloading in [the readme of wp-autoload](https://github.com/makeitworkpress/wp-autoload). 16 | 17 |   18 | ## Usage 19 | 20 | ### Booting Components 21 | Before building components, you should boot the general script which enqueues the styles and scripts by the components. 22 | 23 | 24 | ```php 25 | $components = new MakeitWorkPress\WP_Components\Boot(); 26 | ``` 27 | 28 | If you don't want to include the scripts (which breaks some of the components), you can insert configurations in the component like this: 29 | 30 | ```php 31 | $components = new MakeitWorkPress\WP_Components\Boot( ['css' => false, 'js' => false] ); 32 | ``` 33 | 34 | ### Rendering an atom 35 | If you want to render an atom, you have to utilize the Build class, the name of the atom, the properties and eventually if you want to render this atom or return it as a string. 36 | 37 | ```php 38 | MakeitWorkPress\WP_Components\Build::atom( string $name, array $properties, boolean $render = true ); 39 | ``` 40 | 41 | For example, rendering an image atom, where the attachment ID of the image is 71, is done in the following manner: 42 | 43 | ```php 44 | MakeitWorkPress\WP_Components\Build::atom( 'image', ['image' => 71] ); 45 | ``` 46 | 47 | There is also a shorter function available: 48 | 49 | ```php 50 | wpc_atom( 'image', ['image' => 71] ); 51 | ``` 52 | 53 | ### Rendering a molecule 54 | If you want to render a molecule, you have to utilize the Build class and use the name of the molecule, the properties and eventually if you want to render the molecule or return it as a string. 55 | 56 | ```php 57 | MakeitWorkPress\WP_Components\Build::molecule( string $name, array $properties, boolean $render = true ); 58 | ``` 59 | 60 | For example, rendering the header molecule is done in the following manner: 61 | 62 | ```php 63 | MakeitWorkPress\WP_Components\Build::molecule( 'header', ['fixed' => true, 'transparent' => true] ); 64 | ``` 65 | 66 | There is also a shorter function available: 67 | 68 | ```php 69 | wpc_molecule( 'header', ['fixed' => true, 'transparent' => true] ); 70 | ``` 71 | 72 | ### Common Properties 73 | Each component (atom or molecule) can have custom properties and has a set of predefined properties, such as alignment, attributes, background, border, color, float, height, parallax, rounded, width and so forth. 74 | These are explained in [the wiki](https://github.com/makeitworkpress/wp-components/wiki/Common-Properties). 75 | 76 |   77 | ## WP Components WIKI 78 | You can find more information on using components and all the properties that may be used for each component in [our wiki](https://github.com/makeitworkpress/wp-components/wiki). 79 | 80 |   81 | ## Compatibility 82 | WP Components works with PHP 7.3+ and is tested with WordPress 5.8.3 and higher. 83 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "makeitworkpress/wp-components", 3 | "description": "WP Components contains a wide selection of common elements that can be found on WordPress websites and can be used to speed up development.", 4 | "license": "GPL", 5 | "require": { 6 | "php": ">=5.3" 7 | }, 8 | "autoload": { 9 | "psr-4": { 10 | "MakeitWorkPress\\WP_Components\\": "src" 11 | } 12 | }, 13 | "homepage": "https://github.com/makeitworkpress/wp-components", 14 | "authors": [ 15 | { 16 | "name": "Make it WorkPress", 17 | "email": "michiel@makeitworkpress.com", 18 | "homepage": "https://www.makeitworkpress.com" 19 | 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wp-components", 3 | "version": "1.0.0", 4 | "author": "Make it WorkPress", 5 | "description": "The package for WP-Components", 6 | "devDependencies": { 7 | "@wordpress/scripts": "^24.6.0", 8 | "ts-loader": "^9.2.6", 9 | "typescript": "^4.5.4" 10 | }, 11 | "scripts": { 12 | "build": "wp-scripts build", 13 | "start": "wp-scripts start" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /public/js/wpc-scripts.asset.php: -------------------------------------------------------------------------------- 1 | array(), 'version' => '75b2634c9a632ed6fe10'); 2 | -------------------------------------------------------------------------------- /public/vendor/css/tinyslider.min.css: -------------------------------------------------------------------------------- 1 | .tns-outer{padding:0 !important}.tns-outer [hidden]{display:none !important}.tns-outer [aria-controls],.tns-outer [data-action]{cursor:pointer}.tns-slider{-webkit-transition:all 0s;-moz-transition:all 0s;transition:all 0s}.tns-slider>.tns-item{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.tns-horizontal.tns-subpixel{white-space:nowrap}.tns-horizontal.tns-subpixel>.tns-item{display:inline-block;vertical-align:top;white-space:normal}.tns-horizontal.tns-no-subpixel:after{content:'';display:table;clear:both}.tns-horizontal.tns-no-subpixel>.tns-item{float:left}.tns-horizontal.tns-carousel.tns-no-subpixel>.tns-item{margin-right:-100%}.tns-no-calc{position:relative;left:0}.tns-gallery{position:relative;left:0;min-height:1px}.tns-gallery>.tns-item{position:absolute;left:-100%;-webkit-transition:transform 0s, opacity 0s;-moz-transition:transform 0s, opacity 0s;transition:transform 0s, opacity 0s}.tns-gallery>.tns-slide-active{position:relative;left:auto !important}.tns-gallery>.tns-moving{-webkit-transition:all 0.25s;-moz-transition:all 0.25s;transition:all 0.25s}.tns-autowidth{display:inline-block}.tns-lazy-img{-webkit-transition:opacity 0.6s;-moz-transition:opacity 0.6s;transition:opacity 0.6s;opacity:0.6}.tns-lazy-img.tns-complete{opacity:1}.tns-ah{-webkit-transition:height 0s;-moz-transition:height 0s;transition:height 0s}.tns-ovh{overflow:hidden}.tns-visually-hidden{position:absolute;left:-10000em}.tns-transparent{opacity:0;visibility:hidden}.tns-fadeIn{opacity:1;filter:alpha(opacity=100);z-index:0}.tns-normal,.tns-fadeOut{opacity:0;filter:alpha(opacity=0);z-index:-1}.tns-vpfix{white-space:nowrap}.tns-vpfix>div,.tns-vpfix>li{display:inline-block}.tns-t-subp2{margin:0 auto;width:310px;position:relative;height:10px;overflow:hidden}.tns-t-ct{width:2333.3333333%;width:-webkit-calc(100% * 70 / 3);width:-moz-calc(100% * 70 / 3);width:calc(100% * 70 / 3);position:absolute;right:0}.tns-t-ct:after{content:'';display:table;clear:both}.tns-t-ct>div{width:1.4285714%;width:-webkit-calc(100% / 70);width:-moz-calc(100% / 70);width:calc(100% / 70);height:10px;float:left} -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /public/vendor/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makeitworkpress/wp-components/7c0018d16c7a6b7d3b1d47688de6ba3b15aa3e74/public/vendor/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /src/Ajax.php: -------------------------------------------------------------------------------- 1 | $min ) { 58 | 59 | $count = intval( get_post_meta($id, 'components_rating_count', true) ); 60 | $rating = floatval( get_post_meta($id, 'components_rating', true) ); 61 | 62 | $newCount = $count ? $count + 1 : 1; 63 | $newRating = ($rating * $count + $user_rating)/$newCount; 64 | 65 | update_post_meta($id, 'components_rating_count', $newCount); 66 | update_post_meta($id, 'components_rating', $newRating); 67 | 68 | wp_send_json_success( ['rating' => $newRating, 'count' => $newCount] ); 69 | 70 | } 71 | 72 | } 73 | 74 | /** 75 | * Loads posts that are searched 76 | */ 77 | public function public_search(): void { 78 | 79 | // Check nonce 80 | check_ajax_referer('cucumber', 'nonce'); 81 | 82 | if( empty($_POST['search']) || ! is_numeric($_POST['number']) ) { 83 | wp_send_json_error(); 84 | } 85 | 86 | // Some initial vars 87 | $none = sanitize_text_field( $_POST['none'] ); 88 | $types = isset($_POST['types']) && $_POST['types'] ? explode(',', sanitize_text_field($_POST['types'])) : false; 89 | 90 | // Developers can filter the arguments 91 | $args = apply_filters( 'components_ajax_search_posts_args', [ 92 | 'query_args' => [ 93 | 'ep_integrate' => true, 94 | 'posts_per_page' => intval( $_POST['number'] ), 95 | 'post_type' => $types ? $types : 'any', 96 | 'post_status' => 'publish', 97 | 's' => sanitize_text_field( $_POST['search'] ) 98 | ], 99 | 'none' => $none ? $none : __('Bummer! No posts found.', WP_COMPONENTS_LANGUAGE), 100 | 'pagination' => false, 101 | 'post_properties' => [ 102 | 'appear' => sanitize_text_field( $_POST['appear'] ), 103 | 'content_atoms' => [], 104 | 'footer_atoms' => [], 105 | 'header_atoms' => [ 106 | 'title' => ['atom' => 'title', 'properties' => ['tag' => 'h4', 'link' => 'post']], 107 | 'type' => ['atom' => 'type', 'properties' => []] 108 | ], 109 | 'image' => ['link' => 'post', 'size' => 'thumbnail', 'rounded' => true] 110 | ] 111 | ] ); 112 | 113 | $list = Build::molecule( 'posts', $args , false ); 114 | 115 | // Return search results 116 | if( $list ) { 117 | wp_send_json_success( $list ); 118 | } 119 | 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /src/Boot.php: -------------------------------------------------------------------------------- 1 | configurations = wp_parse_args( $configurations, [ 33 | 'animate' => false, // Whether to load animate.css or not 34 | 'css' => true, // Load standard css 35 | 'fontawesome' => true, // Loads the fontawesome css 36 | 'hover' => false, // Whether to load hover.css or not 37 | 'js' => true, // Load standard js 38 | 'language' => 'wp-components', // The default language domain 39 | 'maps' => '', // The API key for Google Maps. 40 | 'scrollreveal' => true, // Loads the scrollreveal JS 41 | 'tinyslider' => true // Loads the slider js and css 42 | ] ); 43 | 44 | // Define Constants 45 | // $folder = wp_normalize_path( substr( dirname(__DIR__, 1), strpos(__FILE__, 'wp-content') + strlen('wp-content') ) ); 46 | $root_dir = dirname(__DIR__, 1); 47 | $is_in_plugin = str_contains($root_dir, WP_PLUGIN_DIR) ? true : false; 48 | $root_path = $is_in_plugin ? substr($root_dir, strpos($root_dir, '/plugins')) : substr($root_dir, strpos($root_dir, '/themes')); 49 | 50 | defined( 'WP_COMPONENTS_ASSETS' ) or define( 'WP_COMPONENTS_ASSETS', content_url() . $root_path . '/public/' ); 51 | defined( 'WP_COMPONENTS_PATH' ) or define( 'WP_COMPONENTS_PATH', $root_dir . '/src/' ); 52 | defined( 'WP_COMPONENTS_LANGUAGE' ) or define( 'WP_COMPONENTS_LANGUAGE', $this->configurations['language'] ); 53 | 54 | // Register our ajax actions 55 | $this->ajax = new Ajax(); 56 | 57 | // Load our functions 58 | require_once( WP_COMPONENTS_PATH . 'includes/functions.php' ); 59 | 60 | // Register Hooks 61 | $this->hook(); 62 | 63 | } 64 | 65 | 66 | /** 67 | * Contains our standaard hooks 68 | */ 69 | private function hook(): void { 70 | 71 | add_action( 'wp_enqueue_scripts', function(): void { 72 | 73 | // Enqueue tinyslider CSS and JS 74 | if( $this->configurations['tinyslider'] ) { 75 | wp_enqueue_style( 'tinyslider-css', WP_COMPONENTS_ASSETS . 'vendor/css/tinyslider.min.css'); 76 | wp_enqueue_script( 'tinyslider-js', WP_COMPONENTS_ASSETS . 'vendor/js/tinyslider.min.js', [], NULL, true); 77 | } 78 | 79 | // Enqueue scrollreveal JS 80 | if( $this->configurations['scrollreveal'] ) { 81 | wp_enqueue_script( 'scrollreveal-js', WP_COMPONENTS_ASSETS . 'vendor/js/scrollreveal.min.js', [], NULL, true); 82 | } 83 | 84 | // Enqueue our default components CSS 85 | if( $this->configurations['css'] ) { 86 | wp_enqueue_style( 'wpc-css', WP_COMPONENTS_ASSETS . 'css/wpc-styles.min.css'); 87 | } 88 | 89 | if( $this->configurations['fontawesome'] ) { 90 | wp_enqueue_style( 'wpc-font-awesome', WP_COMPONENTS_ASSETS . 'vendor/css/font-awesome.min.css'); 91 | } 92 | 93 | // Enqueue our animate CSS 94 | if( $this->configurations['animate'] ) { 95 | wp_enqueue_style( 'wpc-animate-css', WP_COMPONENTS_ASSETS . 'vendor/css/animate.min.css'); 96 | } 97 | 98 | // Enqueue our hover CSS 99 | if( $this->configurations['hover'] ) { 100 | wp_enqueue_style( 'wpc-hover-css', WP_COMPONENTS_ASSETS . 'vendor/css/hover.min.css'); 101 | } 102 | 103 | // Registers the maps script 104 | if( $this->configurations['maps'] ) { 105 | wp_register_script( 'google-maps-js', 'https://maps.googleapis.com/maps/api/js?key=' . $this->configurations['maps'], [], '3', true); 106 | } 107 | 108 | // Enqueue our default components JS 109 | if( $this->configurations['js'] ) { 110 | 111 | wp_enqueue_script( 'wpc-js', WP_COMPONENTS_ASSETS . 'js/wpc-scripts.js', [], NULL, true ); 112 | 113 | // Localize our script 114 | wp_localize_script( 'wpc-js', 'wpc', [ 115 | 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 116 | 'restUrl' => esc_url_raw( rest_url() ), 117 | 'debug' => defined('WP_DEBUG') && WP_DEBUG ? true : false, 118 | 'nonce' => wp_create_nonce( 'cucumber' ), 119 | ]); 120 | 121 | } 122 | 123 | } ); 124 | 125 | // Specific WooCommerce Based Actions 126 | if( class_exists('WooCommerce') ) { 127 | // Counter that updates the mini cart with ajax 128 | add_filter('woocommerce_add_to_cart_fragments', function($fragments) { 129 | $fragments['span.atom-cart-count'] = '' . WC()->cart->get_cart_contents_count() . ''; 130 | 131 | return $fragments; 132 | }); 133 | } 134 | 135 | } 136 | 137 | } -------------------------------------------------------------------------------- /src/assets/atoms/author.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the tabs atom 5 | */ 6 | .atom-author { 7 | overflow: hidden; 8 | } -------------------------------------------------------------------------------- /src/assets/atoms/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the buttons 5 | */ 6 | .atom-breadcrumbs { 7 | ol { 8 | list-style: none; 9 | margin: 0; 10 | padding: 0; 11 | } 12 | li { 13 | display: inline-block; 14 | } 15 | } 16 | 17 | .atom-breadcrumbs-seperator { 18 | margin-left: 0.2em; 19 | } -------------------------------------------------------------------------------- /src/assets/atoms/button.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the buttons 5 | */ 6 | .atom-button { 7 | border-radius: 4px; 8 | display: inline-block; 9 | padding: 12px 24px; 10 | text-decoration: none; 11 | transition: all 350ms ease-out; 12 | .atom-button-label { 13 | display: inline-block; 14 | transition: all 350ms ease-out; 15 | } 16 | &.atom-button-none { 17 | background: none; 18 | border: none; 19 | padding: 0; 20 | } 21 | &.atom-button-small { 22 | font-size: 0.9em; 23 | padding: 8px 16px; 24 | } 25 | &.atom-button-large { 26 | font-size: 1.2em; 27 | padding: 16px 32px; 28 | } 29 | &:hover { 30 | opacity: 0.9; 31 | } 32 | &.atom-button-hover { 33 | i { 34 | opacity: 0; 35 | transition: all 350ms ease-out; 36 | } 37 | &:hover { 38 | .atom-button-label { 39 | transform: translateX(-2px); 40 | } 41 | i { 42 | opacity: 1; 43 | transform: translateX(-8px); 44 | } 45 | span ~ i { 46 | transform: translateX(4px); 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/assets/atoms/cart.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Cart for WooCommerce 5 | */ 6 | .atom-cart { 7 | border-left: 1px solid #eee; 8 | border-right: 1px solid #eee; 9 | position: relative; 10 | z-index: 9; 11 | i.fa { 12 | font-size: 1.2em; 13 | margin-left: 0; 14 | } 15 | .woocommerce-mini-cart .woocommerce-mini-cart-item { 16 | border-bottom: 1px solid #eee; 17 | overflow: hidden; 18 | padding: 8px 0 8px 24px; 19 | position: relative; 20 | a { 21 | padding: 0; 22 | } 23 | .remove { 24 | color: @red; 25 | font-size: 24px; 26 | font-weight: bold; 27 | left: 0; 28 | line-height: 26px; 29 | position: absolute; 30 | top: 50%; 31 | transform: translate(0, -50%); 32 | } 33 | .quantity { 34 | display: block; 35 | font-size: 0.9em; 36 | } 37 | &:last-child { 38 | margin-bottom: 8px; 39 | } 40 | img { 41 | float: left; 42 | margin-right: 8px; 43 | width: 48px; 44 | } 45 | } 46 | .checkout { 47 | float: right; 48 | } 49 | .total { 50 | font-size: 1.1em; 51 | } 52 | } 53 | 54 | .atom-cart-icon { 55 | padding: 8px 12px; 56 | position: relative; 57 | } 58 | 59 | .atom-cart-count { 60 | background: @red; 61 | color: #fff; 62 | border-radius: 50%; 63 | height: 1.5em; 64 | display: block; 65 | font-size: 0.7em; 66 | line-height: 1.5em; 67 | position: absolute; 68 | right: 0.25em; 69 | text-align: center; 70 | top: 0; 71 | width: 1.5em; 72 | } 73 | 74 | .atom-cart-content { 75 | background: #fff; 76 | line-height: normal; 77 | min-width: 280px; 78 | padding: 16px; 79 | .atom-cart-collapsed & { 80 | display: none; 81 | position: absolute; 82 | top: 100%; 83 | .components-right-float& { 84 | right: 0; 85 | } 86 | } 87 | ul { 88 | margin: 0; 89 | } 90 | } -------------------------------------------------------------------------------- /src/assets/atoms/cart.ts: -------------------------------------------------------------------------------- 1 | import { FadeToggle } from "../other/utils"; 2 | import Component from "../types/component"; 3 | 4 | /** 5 | * Defines a social share element 6 | */ 7 | const Cart: Component = { 8 | elements: document.getElementsByClassName('atom-cart-icon') as HTMLCollectionOf, 9 | init(): void { 10 | if( ! this.elements || this.elements.length < 1) { 11 | return; 12 | } 13 | 14 | for(const cartElement of this.elements) { 15 | this.cartHandler(cartElement); 16 | } 17 | }, 18 | 19 | /** 20 | * Handles any cart related actions 21 | * 22 | * @param cart HTMLElement The passed cart element 23 | */ 24 | cartHandler(cart: HTMLElement): void { 25 | cart.addEventListener('click', (event) => { 26 | event.preventDefault(); 27 | const cartContent = cart.nextElementSibling as HTMLElement; 28 | FadeToggle(cartContent); 29 | }); 30 | } 31 | 32 | } 33 | 34 | export default Cart; -------------------------------------------------------------------------------- /src/assets/atoms/comments.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the buttons 5 | */ 6 | .atom-comments { 7 | label { 8 | display: block; 9 | } 10 | ol, ul { 11 | margin: 0; 12 | } 13 | li { 14 | list-style: none; 15 | margin: 1.5em 0; 16 | } 17 | .avatar { 18 | float: left; 19 | margin-right: 16px; 20 | width: 32px; 21 | } 22 | .says { 23 | display: none; 24 | } 25 | .comment-metadata { 26 | font-size: 15px; 27 | time { 28 | color: #999; 29 | } 30 | } 31 | .comment-content, .reply, .children, .comment .comment-respond, .comment-awaiting-moderation { 32 | padding-left: 48px; 33 | } 34 | .comment-awaiting-moderation { 35 | display: block; 36 | } 37 | .reply { 38 | margin-top: 1em; 39 | } 40 | input + label { 41 | display: inline; 42 | font-weight: 400; 43 | } 44 | } -------------------------------------------------------------------------------- /src/assets/atoms/image.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the image element 5 | */ 6 | .atom-image { 7 | margin: 0; 8 | a { 9 | display: block; 10 | } 11 | img { 12 | height: auto; 13 | max-width: 100%; 14 | vertical-align: middle; 15 | } 16 | } 17 | 18 | .atom-image-enlarge { 19 | overflow: hidden; 20 | &.components-rounded { 21 | overflow: visible; 22 | } 23 | img { 24 | transition: all 350ms ease-out; 25 | } 26 | &:hover img { 27 | transform: scale(1.05); 28 | } 29 | } -------------------------------------------------------------------------------- /src/assets/atoms/list.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the list atom 5 | */ 6 | .components-list-card { 7 | list-style: none; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | .components-list-item { 13 | .components-list-card & { 14 | background: #fff; 15 | padding: 32px; 16 | margin-bottom: 16px; 17 | } 18 | i { 19 | float: left; 20 | margin-right: 16px; 21 | } 22 | } 23 | 24 | .components-list-item-content { 25 | overflow: hidden; 26 | } 27 | 28 | .components-list-item-title { 29 | clear: none; 30 | margin: -0.15rem 0 0 0; 31 | ~ p { 32 | margin: 0.15rem 0 0 0; 33 | } 34 | } -------------------------------------------------------------------------------- /src/assets/atoms/logo.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the logo element 5 | */ 6 | .atom-logo { 7 | display: block; 8 | position: relative; 9 | img { 10 | transition: opacity 350ms ease-out; 11 | } 12 | } 13 | 14 | /** 15 | * Transparent Logo's 16 | */ 17 | .atom-logo-default_transparent, .atom-logo-tablet_transparent, .atom-logo-mobile_transparent { 18 | display: none; 19 | opacity: 0; 20 | left: 0; 21 | position: absolute; 22 | top: 0; 23 | } 24 | 25 | .molecule-header-transparent { 26 | .atom-logo-default, .atom-logo-tablet, .atom-logo-mobile { 27 | opacity: 0; 28 | } 29 | .atom-logo-default_transparent { 30 | display: block; 31 | opacity: 1; 32 | .molecule-header-scrolled& { 33 | opacity: 0; 34 | } 35 | } 36 | .atom-logo-tablet_transparent { 37 | @media screen and (min-width: 768px) and (max-width: 1080px) { 38 | display: block; 39 | opacity: 1; 40 | ~ .atom-logo-default_transparent { 41 | display: none; 42 | } 43 | .molecule-header-scrolled& { 44 | opacity: 0; 45 | } 46 | } 47 | } 48 | .atom-logo-mobile_transparent { 49 | @media screen and (max-width: 767px) { 50 | display: block; 51 | opacity: 1; 52 | ~ .atom-logo-default_transparent { 53 | display: none; 54 | } 55 | .molecule-header-scrolled& { 56 | opacity: 0; 57 | } 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * Default behaviour 64 | */ 65 | .atom-logo-default { 66 | .molecule-header-scrolled & { 67 | opacity: 1; 68 | } 69 | } 70 | 71 | .atom-logo-mobile { 72 | display: none; 73 | @media screen and (max-width: 767px) { 74 | display: block; 75 | ~ .atom-logo-default { 76 | display: none; 77 | } 78 | .molecule-header-scrolled & { 79 | opacity: 1; 80 | } 81 | } 82 | } 83 | 84 | .atom-logo-tablet { 85 | display: none; 86 | @media screen and (min-width: 768px) and (max-width: 1080px) { 87 | display: block; 88 | ~ .atom-logo-default { 89 | display: none; 90 | } 91 | .molecule-header-scrolled & { 92 | opacity: 1; 93 | } 94 | } 95 | } 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/assets/atoms/map.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the map atom 5 | */ 6 | .components-maps-canvas { 7 | height: 400px; 8 | } -------------------------------------------------------------------------------- /src/assets/atoms/map.ts: -------------------------------------------------------------------------------- 1 | import Component from "../types/component"; 2 | 3 | /** 4 | * Creates a Google Map 5 | */ 6 | const CustomMap: Component = { 7 | elements: document.getElementsByClassName('atom-map') as HTMLCollectionOf, 8 | init(): void { 9 | 10 | if( ! this.elements || this.elements.length < 1) { 11 | return; 12 | } 13 | 14 | for(const mapElement of this.elements) { 15 | this.setupMap(mapElement); 16 | } 17 | }, 18 | 19 | /** 20 | * Setup a map 21 | * @param map The element for the map container 22 | */ 23 | setupMap(mapElement: HTMLElement): void { 24 | 25 | if(typeof window.google === 'undefined') { 26 | return; 27 | } 28 | 29 | const canvas = mapElement.querySelector('.components-maps-canvas') as HTMLElement; 30 | 31 | if( ! canvas ) { 32 | return; 33 | } 34 | 35 | const attributes = window[canvas.dataset.id]; 36 | const center = new google.maps.LatLng(parseFloat(attributes.center.lat), parseFloat(attributes.center.lng)) 37 | const mapInstance = new google.maps.Map(canvas, { 38 | center, 39 | scrollwheel: false, 40 | styles: typeof attributes.styles !== 'undefined' ? attributes.styles : '', 41 | zoom: parseInt(attributes.zoom) 42 | }); 43 | 44 | // The map instance is accessible through the global scope 45 | window[canvas.dataset.id].map = mapInstance; 46 | 47 | if( attributes.markers ) { 48 | this.setupMapMarkers(mapInstance, attributes.markers, attributes.fit, center); 49 | } 50 | 51 | }, 52 | 53 | /** 54 | * Setup markers in a map 55 | * 56 | * @param map The map instance 57 | * @param markers The unformatted marker input 58 | * @param fit Whether the markers should fit inside the map canvas 59 | * @param center The map center 60 | */ 61 | setupMapMarkers(map: any, markers: any, fit: any, center: any): void { 62 | const bounds = new google.maps.LatLngBounds(); 63 | const markerInstances: any = []; 64 | 65 | markers.forEach( (marker: any, index: number) => { 66 | let geocoder = null; 67 | let markerLatLng = null; 68 | 69 | markerInstances[index] = new google.maps.Marker({ 70 | draggable: false, 71 | icon: typeof marker.icon !== 'undefined' ? marker.icon : '', 72 | map 73 | }); 74 | 75 | // Geocode our marker when it has an address 76 | if(typeof marker.address !== 'undefined' && marker.address) { 77 | geocoder = geocoder !== null ? geocoder : new google.maps.Geocoder(); 78 | geocoder.geocode({'address': marker.address}, (results: any, status: string) => { 79 | if(status === 'OK') { 80 | markerLatLng = results[0].geometry.location; 81 | } else if( status !== 'OK' && window.wpc.debug) { 82 | console.log('Geocoding of a map marker was not successfull: ' + status); 83 | } 84 | }); 85 | } else if(marker.lat && marker.lng) { 86 | markerLatLng = new google.maps.LatLng(parseFloat(marker.lat), parseFloat(marker.lng)); 87 | } 88 | 89 | if( markerLatLng !== null ) { 90 | markerInstances[index].setPosition( markerLatLng ); 91 | bounds.extend(markerLatLng); 92 | } 93 | 94 | }); 95 | 96 | if( markerInstances.length < 1 || ! fit ) { 97 | return; 98 | } 99 | 100 | bounds.extend(center); 101 | map.fitBounds(bounds); 102 | 103 | // Define the minimum zoom to 15, even after bounds have changed 104 | google.maps.event.addListenerOnce(map, 'bounds_changed', () => { 105 | if(map.getZoom() > 15) { 106 | map.setZoom(15); 107 | } 108 | }); 109 | } 110 | }; 111 | 112 | export default CustomMap; -------------------------------------------------------------------------------- /src/assets/atoms/menu.ts: -------------------------------------------------------------------------------- 1 | import { SlideToggle, ToggleClass } from "../other/utils"; 2 | import Component from "../types/component"; 3 | 4 | /** 5 | * Defines the custom menu scripts 6 | */ 7 | const Menu: Component = { 8 | elements: document.getElementsByClassName('atom-menu') as HTMLCollectionOf, 9 | init(): void { 10 | 11 | if( ! this.elements || this.elements.length < 1) { 12 | return; 13 | } 14 | 15 | for(const menu of this.elements) { 16 | this.setupHamburgerMenu(menu); 17 | this.setupCollapsedMenu(menu) 18 | } 19 | }, 20 | 21 | /** 22 | * Sets the click handler for the hamburger menu 23 | * @param menu The given menu element 24 | */ 25 | setupHamburgerMenu(menu: HTMLElement): void { 26 | 27 | const hamburgerMenu = menu.querySelector('.atom-menu-hamburger') as HTMLAnchorElement; 28 | const menuWrapper = menu.querySelector('.menu') as HTMLElement; 29 | 30 | if( ! hamburgerMenu ) { 31 | return; 32 | } 33 | 34 | hamburgerMenu.addEventListener('click', (event) => { 35 | event.preventDefault(); 36 | menu.classList.toggle('atom-menu-expanded'); 37 | hamburgerMenu.classList.toggle('active'); 38 | menuWrapper.classList.toggle('active'); 39 | }); 40 | 41 | }, 42 | 43 | /** 44 | * Sets up the handlers for collapsed menus 45 | * @param menu The given menu element 46 | */ 47 | setupCollapsedMenu(menu: HTMLElement): void { 48 | 49 | if( ! menu.classList.contains('atom-menu-collapse') ) { 50 | return; 51 | } 52 | 53 | const menuItemsWithChildren = menu.querySelectorAll('.menu-item-has-children > a') as NodeListOf 54 | 55 | for(const menuItemAnchor of menuItemsWithChildren) { 56 | 57 | const subMenu = menuItemAnchor.parentElement?.querySelector('.sub-menu') as HTMLElement; 58 | 59 | menuItemAnchor.addEventListener('click', (event) => { 60 | event.preventDefault(); 61 | ToggleClass(menuItemAnchor, 'active'); 62 | SlideToggle(subMenu); 63 | }); 64 | } 65 | } 66 | }; 67 | 68 | export default Menu; -------------------------------------------------------------------------------- /src/assets/atoms/modal.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the modal element 5 | */ 6 | .atom-modal { 7 | background: rgba(0, 0, 0, 0.8); 8 | display: none; 9 | height: 100%; 10 | left: 0; 11 | position: fixed; 12 | top: 0; 13 | width: 100%; 14 | z-index: 999; 15 | } 16 | 17 | .atom-modal-container { 18 | height:100%; 19 | padding: 48px; 20 | width: 100%; 21 | } 22 | 23 | .atom-modal-content { 24 | background: #fff; 25 | height: 100%; 26 | padding: 32px; 27 | width: 100%; 28 | } 29 | 30 | .atom-modal-close { 31 | color: #fff; 32 | right: 8px; 33 | position: absolute; 34 | top: 8px; 35 | } -------------------------------------------------------------------------------- /src/assets/atoms/modal.ts: -------------------------------------------------------------------------------- 1 | import { FadeOut } from "../other/utils"; 2 | import Component from "../types/component"; 3 | 4 | /** 5 | * Defines the custom header scripts 6 | */ 7 | const Modal: Component = { 8 | elements: document.getElementsByClassName('atom-modal') as HTMLCollectionOf, 9 | init(): void { 10 | 11 | if( ! this.elements || this.elements.length < 1) { 12 | return; 13 | } 14 | 15 | for(const modal of this.elements) { 16 | this.setupClickHandler(modal); 17 | } 18 | }, 19 | /** 20 | * Setup the click handler for closing modal 21 | * 22 | * @param modal The modal element 23 | */ 24 | setupClickHandler(modal: HTMLElement): void { 25 | const closeModal = modal.querySelector('.atom-modal-close') as HTMLAnchorElement; 26 | 27 | closeModal.addEventListener('click', (event) => { 28 | event.preventDefault() 29 | FadeOut(modal); 30 | }); 31 | } 32 | }; 33 | 34 | export default Modal; 35 | -------------------------------------------------------------------------------- /src/assets/atoms/pagination.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the pagination element 5 | */ 6 | .atom-pagination-post { 7 | display: flex; 8 | flex-wrap: wrap; 9 | justify-content: space-between; 10 | a { 11 | width: 47.5%; 12 | @media screen and (max-width: 767px) { 13 | margin-bottom: 16px; 14 | width: 100%; 15 | } 16 | span { 17 | display: block; 18 | } 19 | } 20 | a[rel="next"] { 21 | text-align: right; 22 | } 23 | } -------------------------------------------------------------------------------- /src/assets/atoms/rate.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the rating element 5 | */ 6 | .atom-rate { 7 | overflow: hidden; 8 | .atom-rate-anchor { 9 | display: inline-flex; 10 | overflow: hidden; 11 | } 12 | // Reverses the direction of items, so we can select 'previous' items with CSS 13 | &.atom-rate-can .atom-rate-anchor:hover { 14 | flex-direction: row-reverse; 15 | justify-content: flex-end; 16 | i { 17 | font-weight: 400; 18 | &:before { 19 | content: "\f005"; 20 | } 21 | } 22 | i:hover, i:hover ~ i { 23 | font-weight: 900; // Triggers FontAwesome to adapt to solid styling 24 | } 25 | } 26 | .fa-star-half { 27 | position: relative; 28 | &:after { 29 | content: "\f005"; 30 | font-weight: 400; 31 | left: 0; 32 | position: absolute; 33 | } 34 | } 35 | .fa-circle-notch { 36 | display: none; 37 | } 38 | } -------------------------------------------------------------------------------- /src/assets/atoms/rate.ts: -------------------------------------------------------------------------------- 1 | import { AjaxApi, FadeIn, FadeOut } from "../other/utils"; 2 | import Component from "../types/component"; 3 | 4 | /** 5 | * Defines the custom header scripts 6 | */ 7 | const Rate: Component = { 8 | elements: document.getElementsByClassName("atom-rate") as HTMLCollectionOf, 9 | init() { 10 | if (!this.elements || this.elements.length < 1) { 11 | return; 12 | } 13 | 14 | for (const element of this.elements) { 15 | this.setupClickHandler(element); 16 | } 17 | }, 18 | 19 | /** 20 | * Setup the click handler for sending rating requests to the back-end 21 | * @param element The specific rating element 22 | */ 23 | setupClickHandler(element: HTMLElement): void { 24 | let isRating = false; 25 | const ratingAnchor = element.querySelector( 26 | ".atom-rate-can .atom-rate-anchor" 27 | ) as HTMLAnchorElement; 28 | 29 | ratingAnchor.addEventListener("click", async (event) => { 30 | event.preventDefault(); 31 | 32 | if (isRating) { 33 | return; 34 | } 35 | 36 | const { id = "", max = 5, min = 1 } = element.dataset; 37 | const starElements = ratingAnchor.querySelectorAll(".atom-rate-star"); 38 | let rating: number = 0; 39 | 40 | for (const starElement of starElements) { 41 | if (getComputedStyle(starElement).fontWeight === "900") { 42 | rating++; 43 | } 44 | } 45 | 46 | const loadingSpinner = element.querySelector( 47 | ".atom-rate-can .fa-circle-notch" 48 | ) as HTMLAnchorElement; 49 | FadeIn(loadingSpinner, "inline-block"); 50 | 51 | // Actual rating functions 52 | isRating = true; 53 | 54 | const response = await AjaxApi<{ 55 | success: boolean; 56 | data: { rating: number; count: number }; 57 | }>({ 58 | action: "public_rate", 59 | id: id, 60 | max: +max, 61 | min: +min, 62 | rating: rating, 63 | }); 64 | 65 | // Modify our stars according to the rating 66 | if (response.success && response.data.rating) { 67 | this.updateStarElementClasses(starElements, response.data.rating); 68 | } 69 | 70 | setTimeout(() => { 71 | FadeOut(loadingSpinner); 72 | isRating = false; 73 | }, 1500); 74 | }); 75 | }, 76 | 77 | /** 78 | * Updates the star element classes according to the new rating, without needing to replace the element 79 | */ 80 | updateStarElementClasses(starElements: NodeListOf, rating: number) { 81 | let starKey = 0; 82 | let ceiledRating = Math.ceil(rating); 83 | 84 | for (const starElement of starElements) { 85 | starKey++; 86 | if (starKey < ceiledRating) { 87 | starElement.classList.add("fas", "fa-star"); 88 | starElement.classList.remove("far", "fa-star-half"); 89 | } else if (starKey === ceiledRating) { 90 | const fraction = rating - Math.floor(rating); 91 | if (fraction > 0.25 && fraction < 0.75) { 92 | starElement.classList.add("fas", "fa-star-half"); 93 | starElement.classList.remove("far", "fa-star"); 94 | } else if (fraction > 0.75) { 95 | starElement.classList.remove("far", "fa-star-half"); 96 | starElement.classList.add("fas", "fa-star"); 97 | } 98 | } else { 99 | starElement.classList.add("far", "fa-star"); 100 | starElement.classList.remove("fas", "fa-star-half"); 101 | } 102 | } 103 | }, 104 | }; 105 | 106 | export default Rate; 107 | -------------------------------------------------------------------------------- /src/assets/atoms/scroll.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the scroll element 5 | */ 6 | .atom-scroll { 7 | animation: fadeInDown 2000ms ease-in-out infinite; 8 | background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9Ik1vdXNlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDMzOS4zIDUxNi41IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAzMzkuMyA1MTYuNTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTI5Mi44LDUzLjZDMjY1LDIxLDIyMi43LDQuNSwxNjcsNC41UzY5LDIxLDQxLjIsNTMuNkMxMy4zLDg2LjQsOS4xLDEyNC44LDkuMSwxNDQuOHYyMzEuNGMwLDIwLDQuMiw1OC40LDMyLjEsOTEuMkM2OSw1MDAsMTExLjMsNTE2LjUsMTY3LDUxNi41czk4LTE2LjUsMTI1LjgtNDkuMWMyNy45LTMyLjgsMzIuMS03MS4yLDMyLjEtOTEuMlYxNDQuOEMzMjQuOSwxMjQuOCwzMjAuNyw4Ni40LDI5Mi44LDUzLjZ6IE0yOTMsMzYzLjZjMCwxOC40LTYuMSwxMTAuMy0xMjYsMTEwLjNTNDEsMzgyLDQxLDM2My42VjE1Ny40YzAtMTgsNS44LTEwNi41LDExOC42LTExMC4ydjQ0LjFjLTE0LjksMy40LTI2LDE2LjctMjYsMzIuNXY0MGMwLDE1LjksMTEuMSwyOS4yLDI2LDMyLjV2NzguM2MwLDQuMSwzLjMsNy40LDcuNCw3LjRzNy40LTMuMyw3LjQtNy40di03OC4zYzE0LjktMy40LDI2LTE2LjcsMjYtMzIuNXYtNDBjMC0xNS45LTExLjEtMjkuMi0yNi0zMi41VjQ3LjJDMjg3LjIsNTAuOSwyOTMsMTM5LjQsMjkzLDE1Ny40VjM2My42eiIvPjwvc3ZnPg==) center no-repeat; 9 | bottom: 16px; 10 | height: 32px; 11 | left: 0; 12 | line-height: 32px; 13 | position: absolute; 14 | text-align: center; 15 | width: 100%; 16 | z-index: 9; 17 | &.atom-scroll-hasicon { 18 | background: none; 19 | color: #fff; 20 | text-shadow: 0 0 2px rgba(0, 0, 0, 0.6); 21 | } 22 | &.atom-scroll-top { 23 | animation: none; 24 | bottom: 32px; 25 | display: none; 26 | height: 48px; 27 | left: 32px; 28 | line-height: 48px; 29 | position: fixed; 30 | width: 48px; 31 | @media screen and (max-width: 767px) { 32 | bottom: 16px; 33 | left: 16px; 34 | } 35 | } 36 | &:hover { 37 | cursor: pointer; 38 | } 39 | } -------------------------------------------------------------------------------- /src/assets/atoms/scroll.ts: -------------------------------------------------------------------------------- 1 | import { FadeIn, FadeOut } from '../other/utils'; 2 | import Component from '../types/component'; 3 | 4 | const Scroll: Component = { 5 | elements: document.getElementsByClassName('atom-scroll') as HTMLCollectionOf, 6 | init() { 7 | if( ! this.elements || this.elements.length < 1) { 8 | return; 9 | } 10 | 11 | for( const element of this.elements ) { 12 | this.setupScrollHandler(element); 13 | } 14 | 15 | this.setupwindowHandler(); 16 | }, 17 | 18 | /** 19 | * Setup our scroll button 20 | * @param element The scroll element 21 | */ 22 | setupScrollHandler(element: HTMLAnchorElement): void { 23 | const parent = element.parentElement as HTMLElement; 24 | let destination: number; 25 | 26 | element.addEventListener('click', (event) => { 27 | event.preventDefault(); 28 | 29 | if( element.classList.contains('atom-scroll-top') ) { 30 | destination = 0; 31 | } else { 32 | destination = parent?.clientHeight + parent.getBoundingClientRect().top + window.scrollY; 33 | } 34 | 35 | window.scrollTo({ top: destination, behavior: 'smooth'}); 36 | 37 | }); 38 | }, 39 | 40 | /** 41 | * Setup the handler for the window functions 42 | */ 43 | setupwindowHandler() { 44 | 45 | let scrolled = false; 46 | 47 | window.addEventListener('scroll', () => { 48 | let scrollPosition = window.scrollY; 49 | 50 | for( const element of this.elements ) { 51 | if( element.classList.contains('atom-scroll-top') ) { 52 | if( scrollPosition > window.innerHeight) { 53 | FadeIn(element); 54 | scrolled = true; 55 | } else if(scrolled && scrollPosition < window.innerHeight ) { 56 | FadeOut(element); 57 | scrolled = false; 58 | } 59 | } 60 | } 61 | }); 62 | } 63 | } 64 | 65 | export default Scroll; -------------------------------------------------------------------------------- /src/assets/atoms/search.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the search atom 5 | */ 6 | .atom-search { 7 | position: relative; 8 | .screen-reader-text { 9 | display: none; 10 | } 11 | .fa-circle-notch { 12 | display: none; 13 | position: absolute; 14 | left: -24px; 15 | top: 12px; 16 | } 17 | input[type="search"] { 18 | min-width: 200px; 19 | } 20 | label { 21 | display: inline-block; 22 | } 23 | } 24 | 25 | .atom-search-collapse { 26 | align-items: center; 27 | display: flex; 28 | justify-content: flex-end; 29 | .atom-search-form { 30 | display: none; 31 | min-width: ~"calc(100% - 48px)"; 32 | position: relative; 33 | z-index: 999; 34 | label, input[type="search"] { 35 | width: 100%; 36 | } 37 | input[type="submit"] { 38 | position: absolute; 39 | right: 0; 40 | top: 0; 41 | } 42 | } 43 | } 44 | 45 | .atom-search-expand { 46 | padding: 8px 16px; 47 | text-align: center; 48 | width: 48px; 49 | z-index: 1; 50 | } 51 | 52 | .atom-search-results { 53 | background: #fff; 54 | border: 1px solid #eee; 55 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); 56 | display: none; 57 | min-width: 248px; 58 | padding: 16px; 59 | position: absolute; 60 | top: 100%; 61 | right: 48px; 62 | width: ~"calc(100% - 48px)"; 63 | z-index: 100; 64 | @media screen and (min-width: 480px) { 65 | min-width: 320px; 66 | } 67 | &.components-loading { 68 | position: absolute; 69 | } 70 | .molecule-post { 71 | border-bottom: 1px solid #eee; 72 | margin: 0 0 16px 0; 73 | overflow: hidden; 74 | padding: 0 0 16px 0; 75 | > .atom-image { 76 | float: left; 77 | margin-right: 16px; 78 | width: 48px; 79 | } 80 | .entry-header { 81 | overflow: hidden; 82 | } 83 | h4 { 84 | clear: none; 85 | margin-bottom: 0.25em; 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/assets/atoms/search.ts: -------------------------------------------------------------------------------- 1 | import { InitScrollReveal } from "../other/modules"; 2 | import { ToggleClass, FadeToggle, FadeOut, AjaxApi, FadeIn } from "../other/utils"; 3 | import Component from "../types/component"; 4 | 5 | declare let sr: any; 6 | 7 | /** 8 | * Custom scripts for a search element 9 | * If enabled, the script will loads results through ajax 10 | */ 11 | const Search: Component = { 12 | elements: document.getElementsByClassName('atom-search') as HTMLCollectionOf, 13 | init() { 14 | if( ! this.elements || this.elements.length < 1) { 15 | return; 16 | } 17 | for( const element of this.elements ) { 18 | this.setupSearch(element); 19 | } 20 | }, 21 | 22 | /** 23 | * Setups the tabs for each element existing on a page 24 | * @param element The search element 25 | */ 26 | setupSearch(element: HTMLElement): void { 27 | 28 | if( element.classList.contains('atom-search-ajax') ) { 29 | this.setupAjaxSearch(element) 30 | } 31 | 32 | this.setupToggleSearch(element); 33 | 34 | }, 35 | 36 | /** 37 | * Setups the ajax search functionality for the given element 38 | * @param element The search element 39 | */ 40 | setupAjaxSearch(element: HTMLElement): void { 41 | const { appear = 'bottom', delay = 300, length = 3, none = '', number = 5, types = '' } = element.dataset; 42 | const searchForm = element.querySelector('.search-form') as HTMLElement; 43 | const searchField = element.querySelector('.search-field') as HTMLInputElement; 44 | const moreAnchor = element.querySelector('.atom-search-all') as HTMLAnchorElement; 45 | const results = element.querySelector('.atom-search-results') as HTMLElement; 46 | const loadingIcon = element.querySelector('.fa-circle-notch') as HTMLElement; 47 | 48 | let timer: NodeJS.Timeout; 49 | let value: string; 50 | 51 | if( ! element.classList.contains('atom-search-ajax') ) { 52 | FadeOut(results); 53 | return; 54 | } 55 | 56 | searchField.addEventListener('keyup', (event) => { 57 | 58 | clearTimeout(timer); 59 | const currentSearchField = event.currentTarget as HTMLInputElement; 60 | 61 | if( currentSearchField.value.length <= (length as number) || value === currentSearchField.value ) { 62 | return; 63 | } 64 | 65 | timer = setTimeout( async () => { 66 | value = currentSearchField.value; 67 | moreAnchor.href = moreAnchor.href + encodeURI(value); 68 | 69 | results.classList.add('components-loading'); 70 | results.querySelector('.atom-search-all')?.remove(); 71 | 72 | const response = await AjaxApi<{ success: boolean; data: string }>({ 73 | action: 'public_search', 74 | appear: appear, 75 | none: none, 76 | number: number, 77 | search: value, 78 | types: types 79 | }); 80 | 81 | if( response.success ) { 82 | FadeIn(results); 83 | results.innerHTML = response.data; 84 | results.append(moreAnchor); 85 | 86 | if( typeof sr !== 'undefined') { 87 | if( sr.initialized === false ) { 88 | InitScrollReveal(); 89 | } 90 | sr.sync(); 91 | } 92 | } 93 | 94 | setTimeout( () => { 95 | FadeOut(loadingIcon); 96 | results.classList.remove('components-loading'); 97 | }, 500); 98 | 99 | }, +delay); 100 | 101 | }); 102 | 103 | }, 104 | 105 | /** 106 | * Allows the search-form to be toggled from a single icon 107 | * @param element The search element 108 | */ 109 | setupToggleSearch(element: HTMLElement): void { 110 | 111 | const searchExpandElement = element.querySelector('.atom-search-expand'); 112 | 113 | if( ! searchExpandElement ) { 114 | return; 115 | } 116 | 117 | const searchForm = element.querySelector('.atom-search-form') as HTMLElement; 118 | const searchField = searchForm.querySelector('.search-field') as HTMLInputElement; 119 | 120 | searchExpandElement.addEventListener('click', (event) => { 121 | event.preventDefault(); 122 | 123 | ToggleClass(element, 'atom-search-expanded'); 124 | ToggleClass(searchExpandElement.querySelector('.fas'), ['fa-search', 'fa-times']); 125 | 126 | FadeToggle(searchForm); 127 | 128 | const searchResults = element.querySelector('.atom-search-results') as HTMLElement; 129 | 130 | if (searchResults.style.display === 'block') { 131 | (searchForm.querySelector('.search-field') as HTMLInputElement).value = ''; 132 | FadeOut(searchResults) 133 | } 134 | 135 | // Close search results when not expanding 136 | searchField.focus(); 137 | 138 | }); 139 | 140 | } 141 | 142 | }; 143 | 144 | export default Search; -------------------------------------------------------------------------------- /src/assets/atoms/share.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the social share atom 5 | */ 6 | .atom-share { 7 | overflow: hidden; 8 | a { 9 | box-sizing: border-box; 10 | display: inline-block; 11 | line-height: 48px; 12 | height: 48px; 13 | width: 48px; 14 | padding: 0 8px; 15 | text-align: center; 16 | transition: all 350ms ease-out; 17 | vertical-align: top; 18 | &:hover { 19 | width: 64px; 20 | } 21 | } 22 | } 23 | 24 | .atom-share-title { 25 | display: inline-block; 26 | font-size: 0.8em; 27 | margin-top: 12px; 28 | max-width: 128px; 29 | opacity: 0.8; 30 | text-align: center; 31 | text-transform: uppercase; 32 | width: 64px; 33 | .atom-share-fixed & { 34 | font-size: 0.7em; 35 | width: 48px; 36 | @media screen and (max-width: 767px) { 37 | display: none; 38 | } 39 | } 40 | } 41 | 42 | .atom-share-fixed { 43 | display: none; 44 | left: 0; 45 | opacity: 0; 46 | position: fixed; 47 | top: 50%; 48 | transform: translate(0, -50%); 49 | z-index: 999; 50 | a { 51 | display: block; 52 | } 53 | @media screen and (max-width: 767px) { 54 | align-items: flex-end; 55 | bottom: 0; 56 | display: flex; 57 | transform: none; 58 | top: inherit; 59 | width: 100%; 60 | a { 61 | display: inline; 62 | width: 100%; 63 | &:hover { 64 | height: 64px; 65 | line-height: 64px; 66 | width: 100%; 67 | } 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/assets/atoms/share.ts: -------------------------------------------------------------------------------- 1 | import { FadeIn, FadeOut } from "../other/utils"; 2 | import Component from "../types/component"; 3 | 4 | /** 5 | * Defines a social share element 6 | */ 7 | const Share: Component = { 8 | elements: document.getElementsByClassName('atom-share-fixed') as HTMLCollectionOf, 9 | init(): void { 10 | if( ! this.elements || this.elements.length < 1) { 11 | return; 12 | } 13 | 14 | this.setupShare(); 15 | }, 16 | 17 | /** 18 | * Setup our sharing functionalities 19 | */ 20 | setupShare(): void { 21 | 22 | if( document.documentElement.scrollHeight < window.innerHeight ) { 23 | return; 24 | } 25 | 26 | let scrolled = false; 27 | 28 | window.addEventListener('scroll', () => { 29 | let scrollPosition = window.scrollY; 30 | 31 | if( scrollPosition > 5 && ! scrolled ) { 32 | for( const element of this.elements ) { 33 | FadeIn(element); 34 | } 35 | scrolled = true; 36 | } else if(scrollPosition < 5 && scrolled) { 37 | scrolled = false; 38 | for( const element of this.elements ) { 39 | FadeOut(element); 40 | } 41 | } 42 | 43 | }); 44 | 45 | } 46 | 47 | } 48 | 49 | export default Share; -------------------------------------------------------------------------------- /src/assets/atoms/social.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the social atom 5 | */ 6 | .atom-social { 7 | a { 8 | display: inline-block; 9 | line-height: 32px; 10 | min-height: 32px; 11 | min-width: 32px; 12 | padding: 0 8px; 13 | text-align: center; 14 | transition: all 350ms ease-out; 15 | vertical-align: middle; 16 | &:hover { 17 | opacity: 0.8; 18 | } 19 | } 20 | &:after { 21 | clear: both; 22 | content: ''; 23 | display: table; 24 | } 25 | } -------------------------------------------------------------------------------- /src/assets/atoms/tabs.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the tabs atom 5 | */ 6 | .atom-tabs { 7 | overflow: hidden; 8 | &.atom-tabs-left, &.atom-tabs-right { 9 | display: flex; 10 | } 11 | } 12 | 13 | .atom-tabs-navigation { 14 | list-style: none; 15 | margin: 0; 16 | padding: 0; 17 | .atom-tabs-left &, .atom-tabs-right & { 18 | li { 19 | display: block; 20 | a { 21 | margin: 0 -1px 0 0; 22 | &.active, &:hover { 23 | border: 1px solid #eee; 24 | border-right: 1px solid transparent; 25 | } 26 | } 27 | } 28 | } 29 | .atom-tabs-right & { 30 | order: 2; 31 | li a { 32 | margin: 0 0 0 -1px; 33 | &.active, &:hover { 34 | border: 1px solid #eee; 35 | border-left: 1px solid transparent; 36 | } 37 | } 38 | } 39 | li { 40 | display: inline-block; 41 | vertical-align: top; 42 | a { 43 | border: 1px solid transparent; 44 | display: block; 45 | margin: 0 0 -1px 0; 46 | padding: 8px 16px; 47 | transition: all 100ms ease-out; 48 | &.active, &:hover { 49 | background: #fff; 50 | border: 1px solid #eee; 51 | border-bottom: 1px solid transparent; 52 | } 53 | } 54 | } 55 | } 56 | 57 | .atom-tabs-content { 58 | border: 1px solid #eee; 59 | padding: 16px; 60 | .atom-tabs-left &, .atom-tabs-right & { 61 | flex-grow: 1; 62 | } 63 | .atom-tabs-right & { 64 | order: 1; 65 | } 66 | section { 67 | animation: fadeIn 500ms ease-in-out; 68 | display: none; 69 | &.active { 70 | display: block; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/assets/atoms/tabs.ts: -------------------------------------------------------------------------------- 1 | import Component from '../types/component'; 2 | 3 | const Tabs: Component = { 4 | elements: document.getElementsByClassName('atom-tabs') as HTMLCollectionOf, 5 | init() { 6 | if( ! this.elements || this.elements.length < 1) { 7 | return; 8 | } 9 | for( const element of this.elements ) { 10 | this.setupTabs(element); 11 | } 12 | }, 13 | 14 | /** 15 | * Setups the tabs for each element existing on a page 16 | * @param element The tab element 17 | */ 18 | setupTabs(element: HTMLElement): void { 19 | const buttons = element.querySelectorAll('.atom-tabs-navigation a') as NodeListOf; 20 | 21 | for( const button of buttons ) { 22 | button.addEventListener('click', (event) => { 23 | this.clickHandler(event, buttons, element) 24 | }); 25 | } 26 | }, 27 | 28 | /** 29 | * Handles clicking a tab 30 | * 31 | * @param event The event for the click 32 | * @param buttons The list of all buttons 33 | * @param element The parent element 34 | */ 35 | clickHandler(event: MouseEvent, buttons: NodeListOf, element: HTMLElement): void { 36 | 37 | const clickedButton = event.currentTarget as HTMLAnchorElement; 38 | 39 | // The tab links to a regular url 40 | if( clickedButton.href.slice(-1) !== '#' ) { 41 | return; 42 | } 43 | 44 | event.preventDefault(); 45 | 46 | const sections = element.querySelectorAll('.atom-tabs-content section') as NodeListOf; 47 | const targetSection = element.querySelector('.atom-tabs-content section[data-id="' + clickedButton.dataset.target + '"]') as HTMLElement; 48 | 49 | // Reset other buttons and classes 50 | for( const section of sections ) { 51 | section.classList.remove('active'); 52 | } 53 | 54 | for( const button of buttons ) { 55 | button.classList.remove('active'); 56 | } 57 | 58 | // Make our targets active 59 | clickedButton.classList.add('active'); 60 | targetSection.classList.add('active'); 61 | 62 | } 63 | }; 64 | 65 | export default Tabs; -------------------------------------------------------------------------------- /src/assets/atoms/termlist.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the termlist element 5 | */ 6 | .atom-termlist-item { 7 | display: inline-block; 8 | margin-right: 7px; 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/atoms/terms.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the terms atom 5 | */ 6 | .atom-terms { 7 | align-items: center; 8 | display: flex; 9 | flex-wrap: wrap; 10 | list-style: none; 11 | margin: 0; 12 | padding: 0; 13 | li { 14 | display: inline-block; 15 | margin: 0 0.5em 0.5em 0; 16 | vertical-align: top; 17 | &:first-child { 18 | margin-left: 0; 19 | } 20 | a { 21 | display: block; 22 | } 23 | } 24 | span { 25 | display: inline-block; 26 | vertical-align: middle; 27 | } 28 | } 29 | 30 | .atom-term-style-button { 31 | background: @light; 32 | padding: 0.5em 1em; 33 | } -------------------------------------------------------------------------------- /src/assets/atoms/video.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Video Styles 5 | */ 6 | .atom-video-placer { 7 | position: relative; 8 | padding-bottom: 56.25%; /* 16:9 */ 9 | padding-top: 25px; 10 | height: 0; 11 | video, embed, iframe { 12 | position: absolute; 13 | top: 0; 14 | left: 0; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | } -------------------------------------------------------------------------------- /src/assets/molecules/footer.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the footer 5 | */ 6 | .molecule-footer { 7 | clear: both; 8 | position: relative; 9 | } 10 | 11 | .molecule-footer-socket, .molecule-footer .components-container { 12 | overflow: hidden; 13 | } -------------------------------------------------------------------------------- /src/assets/molecules/header.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the header 5 | */ 6 | .molecule-header { 7 | background: #fff; 8 | clear: both; 9 | left: 0; 10 | position: relative; 11 | top: 0; 12 | transition: all 350ms ease-out; 13 | width: 100%; 14 | z-index: 100; 15 | .molecule-header-top-atoms, .molecule-header-socket-atoms, .molecule-header-atoms { 16 | &:after { 17 | clear: both; 18 | content: ""; 19 | display: table; 20 | width: 100%; 21 | } 22 | } 23 | &.molecule-header-transparent { 24 | background: transparent; 25 | border: none; 26 | &.molecule-header-scrolled { 27 | background: #fff; 28 | } 29 | } 30 | .atom-menu .menu > li { 31 | line-height: inherit; 32 | } 33 | .atom-search-collapse { 34 | .atom-search-form { 35 | position: absolute; 36 | right: 8px; 37 | top: 100%; 38 | @media screen and (min-width: 480px) { 39 | min-width: 320px; 40 | } 41 | } 42 | .atom-search-results { 43 | right: 8px; 44 | top: ~"calc(100% + 48px)"; 45 | } 46 | } 47 | .atom-search-results, .search-form { 48 | line-height: normal; 49 | } 50 | .atom-search-expand { 51 | padding: 0 16px; 52 | } 53 | .atom-cart-content { 54 | border: 1px solid #eee; 55 | } 56 | } 57 | 58 | .molecule-header-transparent { 59 | position: absolute; 60 | + .main { 61 | padding-top: 0 !important; 62 | } 63 | } 64 | 65 | .molecule-header-atoms { 66 | line-height: 80px; 67 | .molecule-header-shrink & { 68 | transition: all 350ms ease-out; 69 | } 70 | .molecule-header-scrolled.molecule-header-shrink & { 71 | line-height: 64px; 72 | } 73 | } 74 | 75 | .molecule-header-top-atoms, 76 | .molecule-header-atoms, 77 | .molecule-header-socket-atoms { 78 | width: 100%; 79 | } 80 | 81 | .molecule-header-fixed { 82 | position: fixed; 83 | } -------------------------------------------------------------------------------- /src/assets/molecules/header.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines the custom header scripts 3 | */ 4 | import Component from "../types/component"; 5 | import { SlideToggle, FadeToggle } from "../other/utils"; 6 | 7 | const Header: Component = { 8 | 9 | elements: document.getElementsByClassName('molecule-header') as HTMLCollectionOf, 10 | carts: document.querySelectorAll('.molecule-header .atom-cart-icon') as NodeListOf, 11 | position: window.scrollY, 12 | 13 | init() { 14 | 15 | if( ! this.elements || this.elements.length < 1 ) { 16 | return; 17 | } 18 | 19 | for(const header of this.elements) { 20 | this.cssHandler(header); 21 | this.scrollHandler(header); 22 | } 23 | 24 | 25 | }, 26 | 27 | /** 28 | * Set-up necessary css adjustments 29 | * 30 | * @param header HTML Element The passed header 31 | */ 32 | cssHandler(header: HTMLElement): void { 33 | 34 | /** 35 | * Adapts the top-padding for the main section that follows the header, so it won't overlap 36 | */ 37 | if( header.classList.contains('molecule-header-fixed') ) { 38 | const height: number = header.clientHeight; 39 | const mainElement = header.nextElementSibling as HTMLElement 40 | 41 | if( mainElement.tagName === 'main' || mainElement.tagName === 'MAIN' ) { 42 | mainElement.style.paddingTop = height + 'px'; 43 | } 44 | 45 | } 46 | }, 47 | 48 | /** 49 | * Handles any scroll-related events to the selected header 50 | * @param header HTMLElement The given header 51 | */ 52 | scrollHandler(header: HTMLElement): void { 53 | 54 | let up: boolean = false; 55 | 56 | window.addEventListener('scroll', () => { 57 | let positionFromTop:number = window.scrollY; 58 | 59 | if( header.classList.contains('molecule-header-fixed') ) { 60 | if( positionFromTop > 5 ) { 61 | header.classList.add('molecule-header-scrolled'); 62 | header.classList.remove('molecule-header-top'); 63 | } else { 64 | header.classList.remove('molecule-header-scrolled'); 65 | header.classList.add('molecule-header-top'); 66 | } 67 | } 68 | 69 | if( header.classList.contains('molecule-header-headroom') ) { 70 | if( positionFromTop > this.position && ! up ) { 71 | up = ! up; 72 | SlideToggle(header); 73 | } else if( positionFromTop < this.position && up ) { 74 | up = ! up; 75 | SlideToggle(header); 76 | } 77 | 78 | this.position = positionFromTop; 79 | } 80 | }); 81 | } 82 | 83 | }; 84 | 85 | 86 | 87 | export default Header; -------------------------------------------------------------------------------- /src/assets/molecules/post-footer.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the post-header 5 | */ 6 | .molecule-post-footer { 7 | clear: both; 8 | position: relative; 9 | } 10 | 11 | .molecule-post-footer-atoms { 12 | width: 100%; 13 | } -------------------------------------------------------------------------------- /src/assets/molecules/post-header.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the post-header 5 | */ 6 | .molecule-post-header { 7 | clear: both; 8 | position: relative; 9 | } 10 | 11 | .molecule-post-header-atoms { 12 | width: 100%; 13 | } -------------------------------------------------------------------------------- /src/assets/molecules/posts.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the posts 5 | */ 6 | 7 | /* Grid display of posts */ 8 | .molecule-posts-grid { 9 | .molecule-post { 10 | background: #fafafa; 11 | background-position: center; 12 | background-size: cover; 13 | box-sizing: border-box; 14 | overflow: hidden; 15 | padding: 32px; 16 | position: relative; 17 | > .atom-image { 18 | height: 100%; 19 | left: 0; 20 | position: absolute; 21 | top: 0; 22 | width: 100%; 23 | z-index: 0; 24 | a { 25 | height: 100%; 26 | &:after { 27 | background: linear-gradient(to bottom, #000, rgba(0,0,0,0)); 28 | content: ''; 29 | height: 100%; 30 | left: 0; 31 | position: absolute; 32 | top: 0; 33 | width: 100%; 34 | } 35 | } 36 | img { 37 | left: 50%; 38 | max-width: none; 39 | min-height: 100%; 40 | min-width: 100%; 41 | position: absolute; 42 | top: 50%; 43 | transform: translate(-50%, -50%); 44 | width: auto; 45 | } 46 | } 47 | &:hover > .atom-image-enlarge img { 48 | transform: translate(-50%, -50%) scale(1.05); 49 | } 50 | .entry-header, .entry-content, .entry-footer { 51 | position: relative; 52 | z-index: 1; 53 | } 54 | } 55 | .has-post-thumbnail { 56 | color: #fff; 57 | a:not(.atom-button) { 58 | color: #fff; 59 | } 60 | } 61 | } 62 | 63 | .molecule-posts-list { 64 | .molecule-post > .atom-image img { 65 | margin-bottom: 1.5rem; 66 | } 67 | } -------------------------------------------------------------------------------- /src/assets/molecules/posts.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines the custom posts scripts 3 | */ 4 | import Component from '../types/component'; 5 | declare let sr: any; 6 | 7 | const Posts: Component = { 8 | parser: new DOMParser, 9 | elements: document.getElementsByClassName('molecule-posts') as HTMLCollectionOf, 10 | init() { 11 | 12 | if( ! this.elements || this.elements.length < 1) { 13 | return; 14 | } 15 | 16 | for( const element of this.elements ) { 17 | this.setupInfiniteScroll(element); 18 | this.setupPagination(element); 19 | } 20 | 21 | }, 22 | 23 | /** 24 | * Setups infinite scroll for the posts element 25 | * @param element The post wrapper element 26 | */ 27 | setupInfiniteScroll(element: HTMLElement): void { 28 | 29 | if( ! element.classList.contains('molecule-posts-infinite') ) { 30 | return; 31 | } 32 | 33 | const pagination = element.querySelector('.atom-pagination') as HTMLElement; 34 | if( pagination ) { 35 | pagination.style.display = "none"; 36 | } 37 | 38 | const paginationNumberElements = element.querySelectorAll('.atom-pagination .page-numbers') as NodeListOf; 39 | const containerId = element.dataset.id; 40 | const containerPosition = element.getBoundingClientRect().top; 41 | 42 | let pageNumber = 1; 43 | let loading = false; // Determines if we are loading or when all pages are load. 44 | 45 | window.addEventListener('scroll', () => { 46 | 47 | let url = ''; 48 | 49 | if( loading ) { 50 | return; 51 | } 52 | 53 | let windowPosition = window.innerHeight + window.scrollY; 54 | let postsPosition = element.clientHeight + containerPosition; 55 | 56 | if( windowPosition < postsPosition || paginationNumberElements.length < 1 ) { 57 | return; 58 | } 59 | 60 | pageNumber++; 61 | 62 | for(let key in paginationNumberElements ) { 63 | 64 | if( ! paginationNumberElements[key].textContent ) { 65 | continue; 66 | } 67 | 68 | const paginationNumber = paginationNumberElements[key].textContent as string; 69 | if( parseInt(paginationNumber) === pageNumber ) { 70 | url = paginationNumberElements[key].href; 71 | loading = true; 72 | } 73 | 74 | } 75 | 76 | if( ! url.includes(window.location.origin) ) { 77 | return; 78 | } 79 | 80 | // No more pages to load 81 | if( ! url ) { 82 | loading = true; 83 | return; 84 | } 85 | 86 | fetch(url, {}) 87 | .then( (response) => { 88 | return response.text(); 89 | }) 90 | .then( (response) => { 91 | 92 | const posts = this.parser.parseFromString(response, 'text/html').querySelectorAll('.molecule-posts[data-id="' + containerId + '"] .molecule-post'); 93 | const postsWrapper = element.querySelector('.molecule-posts-wrapper') as HTMLElement; 94 | 95 | for( let post of posts ) { 96 | postsWrapper.appendChild(post); 97 | } 98 | 99 | loading = false; 100 | 101 | if( typeof sr !== 'undefined' ) { 102 | sr.sync(); 103 | } 104 | 105 | }); 106 | 107 | }); 108 | 109 | }, 110 | 111 | /** 112 | * Setup regular, dynamic pagination for the post wrapper element 113 | * @param element The post wrapper element 114 | */ 115 | setupPagination(element: HTMLElement): void { 116 | 117 | if( ! element.classList.contains('molecule-posts-ajax') ) { 118 | return; 119 | } 120 | 121 | const paginationAnchors = element.querySelectorAll('.atom-pagination a') as NodeListOf; 122 | 123 | if( paginationAnchors.length < 1 ) { 124 | return; 125 | } 126 | 127 | for( let anchorElement of paginationAnchors ) { 128 | anchorElement.addEventListener('click', (event) => { 129 | event.preventDefault(); 130 | this.paginationClickHandler(element, anchorElement); 131 | }); 132 | } 133 | 134 | }, 135 | 136 | /** 137 | * Adds the click handler to any generated content 138 | * @param element The parent element to which the button belongs 139 | * @param anchor The button that is clicked 140 | */ 141 | paginationClickHandler(element: HTMLElement, anchor: HTMLAnchorElement): void { 142 | 143 | const target = anchor.href; 144 | 145 | if( ! target.includes(window.location.origin) ) { 146 | return; 147 | } 148 | 149 | element.classList.add('components-loading'); 150 | 151 | // Fetch the target page 152 | fetch(target) 153 | .then( (response) => { 154 | return response.text(); 155 | }) 156 | .then( (response) => { 157 | const responseDom = this.parser.parseFromString(response, 'text/html'); 158 | const oldPagination = element.querySelector('.atom-pagination'); 159 | const oldPosts = element.querySelector('.molecule-posts-wrapper'); 160 | const newPagination = responseDom.querySelector('.molecule-posts[data-id="' + element.dataset.id + '"] .atom-pagination'); 161 | const newPosts = responseDom.querySelector('.molecule-posts[data-id="' + element.dataset.id + '"] .molecule-posts-wrapper'); 162 | 163 | element.classList.remove('components-loading'); 164 | 165 | // Older Posts 166 | if(oldPosts && newPosts) { 167 | oldPosts.remove(); 168 | element.append(newPosts); 169 | } 170 | 171 | if(oldPagination && newPagination) { 172 | oldPagination.remove(); 173 | element.append(newPagination); 174 | } 175 | 176 | // Jquery animate alternative 177 | setTimeout( () => { 178 | window.scrollBy({ 179 | top: element.getBoundingClientRect().top, 180 | behavior: 'smooth' 181 | }) 182 | }, 500); 183 | 184 | // Sync our scroll-reveal from the global object 185 | if( typeof sr !== "undefined" ) { 186 | sr.sync(); 187 | } 188 | 189 | // Because our dom is reconstructed, we need to setup pagination again for the given element 190 | this.setupPagination(element); 191 | 192 | }); 193 | 194 | } 195 | 196 | } 197 | 198 | export default Posts; -------------------------------------------------------------------------------- /src/assets/molecules/section.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the section molecule 5 | */ 6 | .molecule-section { 7 | clear: both; 8 | position: relative; 9 | } 10 | 11 | .molecule-section-components { 12 | width: 100%; 13 | } -------------------------------------------------------------------------------- /src/assets/molecules/slider.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Styling for the slider molecule 5 | */ 6 | .molecule-slider { 7 | img, video, iframe, embed { 8 | display: block; 9 | } 10 | ul, ol { 11 | margin: 0; 12 | padding: 0; 13 | list-style: none; 14 | } 15 | .tns-outer { 16 | max-width: 100%; 17 | position: relative; 18 | width: 100%; 19 | } 20 | .tns-nav { 21 | text-align: center; 22 | button { 23 | appearance: none; 24 | -webkit-appearance: none; 25 | background: #ccc; 26 | border-radius: 50%; 27 | display: inline-block; 28 | height: 16px; 29 | line-height: 0; 30 | margin: 4px; 31 | padding: 0; 32 | width: 16px; 33 | &:focus { 34 | outline: none; 35 | } 36 | &.tns-nav-active, &:hover { 37 | background: #000; 38 | } 39 | } 40 | } 41 | .tns-controls { 42 | button { 43 | background: none; 44 | border: none; 45 | color: #000; 46 | font-size: 2em; 47 | margin-top: -48px; 48 | padding: 8px; 49 | position: absolute; 50 | top: 50%; 51 | z-index: 10; 52 | } 53 | button[data-controls="prev"] { 54 | left: -32px; 55 | } 56 | button[data-controls="next"] { 57 | right: -32px; 58 | } 59 | } 60 | .slider-thumbnails li { 61 | display: inline-block; 62 | margin: 4px 4px 4px 0; 63 | vertical-align: top; 64 | &:hover { 65 | cursor: pointer; 66 | } 67 | &:last-child { 68 | margin-right: 0; 69 | } 70 | } 71 | } 72 | 73 | .molecule-slide-wrapper { 74 | background-position: center center; 75 | background-repeat: no-repeat; 76 | background-size: cover; 77 | .components-full-height & { 78 | min-height: 100vh; 79 | } 80 | .components-normal-height & { 81 | min-height: 75vh; 82 | } 83 | .components-half-height & { 84 | min-height: 50vh; 85 | } 86 | .components-third-height & { 87 | min-height: 33vh; 88 | } 89 | .components-quarter-height & { 90 | min-height: 25vh; 91 | } 92 | } 93 | 94 | .molecule-slide-caption { 95 | margin: 32px; 96 | } 97 | -------------------------------------------------------------------------------- /src/assets/molecules/slider.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines the scripts slider 3 | */ 4 | import Component from "../types/component"; 5 | 6 | const Slider: Component = { 7 | elements: document.getElementsByClassName('molecule-slider') as HTMLCollectionOf, 8 | instances: {}, 9 | init(): void { 10 | 11 | if( ! this.elements || this.elements.length < 1 ) { 12 | return; 13 | } 14 | 15 | for( const elements of this.elements ) { 16 | this.createInstance(elements); 17 | } 18 | 19 | }, 20 | 21 | /** 22 | * Creates a slider instance from a HTMLElemenmt 23 | * @param slider The slider wrapper 24 | */ 25 | createInstance(slider: HTMLElement): void { 26 | 27 | if (typeof window.tns === "undefined") { 28 | return; 29 | } 30 | 31 | const id = slider.dataset.id as string; 32 | 33 | if( ! id ) { 34 | return; 35 | } 36 | 37 | const options = window['slider' + id]; 38 | 39 | if (typeof options === "undefined") { 40 | return; 41 | } 42 | 43 | this.instances[id] = tns(options); 44 | 45 | } 46 | 47 | } 48 | 49 | export default Slider; -------------------------------------------------------------------------------- /src/assets/other/animations.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Default animations 5 | */ 6 | @speed: 1000ms; 7 | 8 | // FadeIn 9 | .fadeIn-frames { 10 | from { opacity: 0; } to { opacity: 1; } 11 | } 12 | @keyframes fadeIn {.fadeIn-frames;} 13 | 14 | // FadeInDown 15 | .fadeInDown-frames { 16 | 0% { opacity: 0; transform: translateY(-20px); } 17 | 80% { opacity: 1; } 18 | 100% { opacity: 0; transform: translateY(0); } 19 | } 20 | @keyframes fadeInDown {.fadeInDown-frames;} 21 | 22 | 23 | // SlideInRight 24 | .slideInRight-frames { 25 | from { transform: translate(100%, 0); } to { transform: translate(0); } 26 | } 27 | @keyframes slideInRight {.slideInRight-frames;} 28 | 29 | // SlideInLeft 30 | .slideInLeft-frames { 31 | from { transform: translate(-100%, 0); } to { transform: translate(0); } 32 | } 33 | @keyframes slideInLeft {.slideInLeft-frames;} 34 | 35 | /** 36 | * Animation classes 37 | */ 38 | .components-fadein-animation { 39 | animation: fadeIn @speed ease-in-out; 40 | } 41 | 42 | .components-fadeindown-animation { 43 | animation: fadeInDown @speed ease-in-out; 44 | } 45 | 46 | .components-slideinright-animation { 47 | animation: slideInRight @speed ease-in-out; 48 | } 49 | 50 | .components-slideinleft-animation { 51 | animation: slideInLeft @speed ease-in-out; 52 | } -------------------------------------------------------------------------------- /src/assets/other/colors.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Colored areas 5 | */ 6 | @blue: #3498db; 7 | @dark: #2c3e50; 8 | @green: #2ecc71; 9 | @grey: #95a5a6; 10 | @light: #ecf0f1; 11 | @orange: #f39c12; 12 | @purple: #8e44ad; 13 | @red: #e74c3c; 14 | @magenta: #ff3f72; 15 | @marine: #1abc9c; 16 | @yellow: #f1c40f; 17 | @white: #fff; 18 | 19 | /* Image Backgrounds */ 20 | .components-image-background { 21 | background-position: center; 22 | background-size: cover; 23 | } 24 | 25 | 26 | /* Parallax */ 27 | .components-parallax { 28 | overflow: hidden; 29 | } 30 | 31 | /* Colored Backgrounds */ 32 | .components-blue-background { 33 | background-color: @blue; 34 | transition: all 350ms ease-out; 35 | } 36 | 37 | .components-dark-background { 38 | background-color: @dark; 39 | } 40 | 41 | .components-green-background { 42 | background-color: @green; 43 | } 44 | 45 | .components-grey-background { 46 | background-color: @grey; 47 | } 48 | 49 | .components-light-background { 50 | background-color: @light; 51 | } 52 | 53 | .components-magenta-background { 54 | background-color: @magenta; 55 | } 56 | 57 | .components-marine-background { 58 | background-color: @marine; 59 | } 60 | 61 | .components-orange-background { 62 | background-color: @orange; 63 | } 64 | 65 | .components-purple-background { 66 | background-color: @purple; 67 | } 68 | 69 | .components-red-background { 70 | background-color: @red; 71 | } 72 | 73 | .components-yellow-background { 74 | background-color: @yellow; 75 | } 76 | 77 | .components-white-background { 78 | background-color: @white; 79 | } 80 | 81 | /* Borders */ 82 | .components-blue-border { 83 | border: 2px solid @blue; 84 | } 85 | 86 | .components-dark-border { 87 | border: 2px solid @dark; 88 | } 89 | 90 | .components-green-border { 91 | border: 2px solid @green; 92 | } 93 | 94 | .components-grey-border { 95 | border: 2px solid @grey; 96 | } 97 | 98 | .components-light-border { 99 | border: 2px solid @light; 100 | } 101 | 102 | .components-magenta-border { 103 | border: 2px solid @magenta; 104 | } 105 | 106 | .components-marine-border { 107 | border: 2px solid @marine; 108 | } 109 | 110 | .components-orange-border { 111 | border: 2px solid @orange; 112 | } 113 | 114 | .components-purple-border { 115 | border: 2px solid @purple; 116 | } 117 | 118 | .components-red-border { 119 | border: 2px solid @red; 120 | } 121 | 122 | .components-yellow-border { 123 | border: 2px solid @yellow; 124 | } 125 | 126 | .components-white-border { 127 | border: 2px solid @white; 128 | } 129 | 130 | /* Colors */ 131 | .components-blue-color { 132 | color: @blue; 133 | } 134 | 135 | .components-dark-color { 136 | color: @dark; 137 | } 138 | 139 | .components-green-color { 140 | color: @green; 141 | } 142 | 143 | .components-grey-color { 144 | color: @grey; 145 | } 146 | 147 | .components-light-color { 148 | color: @light; 149 | } 150 | 151 | .components-magenta-color { 152 | color: @magenta; 153 | } 154 | 155 | .components-marine-color { 156 | color: @marine; 157 | } 158 | 159 | .components-orange-color { 160 | color: @orange; 161 | } 162 | 163 | .components-purple-color { 164 | color: @purple; 165 | } 166 | 167 | .components-red-color { 168 | color: @red; 169 | } 170 | 171 | .components-yellow-color { 172 | color: @yellow; 173 | } 174 | 175 | .components-white-color { 176 | color: @white; 177 | } -------------------------------------------------------------------------------- /src/assets/other/global.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Global classes 5 | */ 6 | .components-structured-data { 7 | display: none; 8 | } 9 | 10 | /* Appearing classes */ 11 | .components-bottom-appear, 12 | .components-left-appear, 13 | .components-right-appear, 14 | .components-top-appear { 15 | visibility: hidden; 16 | } 17 | 18 | .components-transition { 19 | transition: all 350ms ease-out; 20 | } 21 | 22 | /* Heights */ 23 | .components-full-height { 24 | min-height: 100vh; 25 | } 26 | 27 | .components-normal-height { 28 | min-height: 75vh; 29 | } 30 | 31 | .components-two-third-height { 32 | min-height: 67vh; 33 | } 34 | 35 | .components-half-height { 36 | min-height: 50vh; 37 | } 38 | 39 | .components-third-height { 40 | min-height: 33vh; 41 | } 42 | 43 | .components-quarter-height { 44 | min-height: 25vh; 45 | } 46 | 47 | .components-full-height, 48 | .components-normal-height, 49 | .components-two-third-height, 50 | .components-half-height, 51 | .components-third-height, 52 | .components-quarter-height { 53 | align-items: center; 54 | display: flex; 55 | padding: 32px 0; 56 | } 57 | 58 | /* Aligns */ 59 | .components-center-align { 60 | text-align: center; 61 | .components-left-float, .components-right-float { 62 | float: none; 63 | display: inline-block; 64 | vertical-align: top; 65 | } 66 | } 67 | 68 | .components-left-align { 69 | text-align: left; 70 | } 71 | 72 | .components-right-align { 73 | text-align: right; 74 | } 75 | 76 | /* Floats */ 77 | .components-center-float { 78 | align-items: flex-start; 79 | clear: both; 80 | display: flex; 81 | justify-content: center; 82 | } 83 | 84 | .components-left-float { 85 | float: left; 86 | margin-right: 16px; 87 | } 88 | 89 | .components-right-float { 90 | float: right; 91 | margin-left: 16px; 92 | } 93 | 94 | /* Display */ 95 | .components-block-display { 96 | display: block; 97 | } 98 | 99 | .components-hidden-display { 100 | visibility: hidden; 101 | } 102 | 103 | .components-inline-display { 104 | display: inline; 105 | } 106 | 107 | .components-inline-block-display { 108 | display: inline-block; 109 | } 110 | 111 | .components-none-display { 112 | display: none; 113 | } 114 | 115 | /* Loading Areas */ 116 | .components-loading { 117 | position: relative; 118 | &:after { 119 | background: rgba(255, 255, 255, 0.5); 120 | content: ''; 121 | display: block; 122 | height: 100%; 123 | left: 0; 124 | position: absolute; 125 | top: 0; 126 | width: 100%; 127 | z-index: 999; 128 | } 129 | } 130 | 131 | .components-loading-element { 132 | left: 50%; 133 | position: absolute; 134 | top: 50%; 135 | transform: translate(-50%, -50%); 136 | z-index: 999; 137 | } 138 | 139 | /** 140 | * Rounded values 141 | */ 142 | .components-rounded { 143 | border-radius: 50px; 144 | &.atom-social, &.atom-share { 145 | border-radius: 0; 146 | } 147 | .atom-network { 148 | border-radius: 25px; 149 | } 150 | .atom-term { 151 | border-radius: 50px; 152 | } 153 | img { 154 | border-radius: 50%; 155 | } 156 | } 157 | 158 | /** 159 | * Positions. @todo someday, make this dry! 160 | */ 161 | .components-bottom-center-position, .components-bottom-center-position .molecule-slide-wrapper { 162 | align-items: flex-end; 163 | display: flex; 164 | justify-content: center; 165 | } 166 | 167 | .components-bottom-left-position, .components-bottom-left-position .molecule-slide-wrapper { 168 | align-items: flex-end; 169 | display: flex; 170 | justify-content: flex-start; 171 | } 172 | 173 | .components-bottom-right-position, .components-bottom-right-position .molecule-slide-wrapper { 174 | align-items: flex-end; 175 | display: flex; 176 | justify-content: flex-end; 177 | } 178 | 179 | .components-middle-center-position, .components-middle-center-position .molecule-slide-wrapper { 180 | align-items: center; 181 | display: flex; 182 | justify-content: center; 183 | } 184 | 185 | .components-middle-left-position, .components-middle-left-position .molecule-slide-wrapper { 186 | align-items: center; 187 | display: flex; 188 | justify-content: flex-start; 189 | } 190 | 191 | .components-middle-right-position, .components-middle-right-position .molecule-slide-wrapper { 192 | align-items: center; 193 | display: flex; 194 | justify-content: flex-end; 195 | } 196 | 197 | .components-top-center-position, .components-top-center-position .molecule-slide-wrapper { 198 | align-items: flex-start; 199 | display: flex; 200 | justify-content: center; 201 | } 202 | 203 | .components-top-left-position, .components-top-left-position .molecule-slide-wrapper { 204 | align-items: flex-start; 205 | display: flex; 206 | justify-content: flex-start; 207 | } 208 | 209 | .components-top-right-position, .components-top-right-position .molecule-slide-wrapper { 210 | align-items: flex-start; 211 | display: flex; 212 | justify-content: flex-end; 213 | } 214 | 215 | /** 216 | * Box Shadows with various blur values 217 | */ 218 | .components-custom-boxshadow { 219 | box-shadow: attr(data-x, 0) attr(data-y, 0) attr(data-blur, 15px) attr(data-spread, 0) attr(data-type, initial); 220 | } 221 | 222 | .boxshadow(@step; @index: 1) when(@index =< 20) { 223 | @blurvalue: (@step * @index); 224 | .boxshadow(@step; (@index+1)); 225 | .components-blur@{blurvalue}-boxshadow { 226 | box-shadow: 0 0 (@blurvalue*1px) rgba(0, 0, 0, 0.25); 227 | } 228 | } 229 | 230 | .boxshadow(5); 231 | 232 | /** 233 | * Overlays with various opacities 234 | */ 235 | .components-overlay { 236 | position: relative; 237 | > * { 238 | position: relative; 239 | z-index: 2; 240 | } 241 | &:after, .components-overlay-background { 242 | background-color: #000; 243 | content: ''; 244 | height: 100%; 245 | left: 0; 246 | opacity: 0.5; 247 | position: absolute; 248 | top: 0; 249 | z-index: 1; 250 | width: 100%; 251 | } 252 | } 253 | 254 | .overlay(@step; @index: 1) when (@index =< 20) { 255 | @value: (@step * @index); 256 | .overlay(@step; (@index+1)); 257 | 258 | .components-opacity@{value}-overlay:after { 259 | opacity: ((@step * @index)/100); 260 | } 261 | 262 | } 263 | 264 | .overlay(5); 265 | 266 | // Custom overlays (expirimental - now solved with js) 267 | .components-custom-overlay:after { 268 | background-color: attr(data-overlay-color, #000); 269 | display: none; 270 | opacity: attr(data-overlay-opacity, 0.5); 271 | } 272 | 273 | 274 | /** 275 | * Video Backgrounds 276 | */ 277 | .components-video-background { 278 | position: relative; 279 | > * { 280 | position: relative; 281 | z-index: 2; 282 | } 283 | .components-video-background-container { 284 | z-index: 0; 285 | } 286 | } 287 | 288 | .components-video-background-container { 289 | left: 0; 290 | height: 100%; 291 | overflow: hidden; 292 | position: absolute; 293 | top: 0; 294 | width: 100%; 295 | } 296 | 297 | .components-video-background-src { 298 | left: 50%; 299 | position: absolute; 300 | top: 50%; 301 | transform: translate(-50%,-50%); 302 | width: 100%; 303 | } -------------------------------------------------------------------------------- /src/assets/other/grid.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Container with clearfix 5 | */ 6 | .components-container { 7 | box-sizing: border-box; 8 | margin: 0 auto; 9 | max-width: 1200px; 10 | width: 100%; 11 | &:after { 12 | clear: both; 13 | content: ''; 14 | display: table; 15 | width: 100%; 16 | } 17 | } 18 | 19 | /** 20 | * Grid Columns 21 | */ 22 | 23 | /* Wrapper */ 24 | .components-grid-wrapper { 25 | display: flex; 26 | flex-wrap: wrap; 27 | justify-content: space-between; 28 | } 29 | 30 | /* Grids with alternating column widths */ 31 | .components-full-grid { 32 | width: 100%; 33 | } 34 | 35 | // The default for the wrapper, also a back-up for websites that do not use the new set-up. 36 | @columns: wrapper 2%, none 0%, tiny 0.5%, small 1%, medium 3%, large 4%, huge 5%; 37 | 38 | // for loop to iterate over array 39 | .each(@array, @i: 1) when (@i <= length(@array)) { 40 | 41 | // Extract names and colors 42 | @pair: extract(@array, @i); 43 | @name: extract(@pair, 1); 44 | @marge: extract(@pair, 2); 45 | 46 | // Columns 47 | @half: (100% - @marge)*0.5; 48 | @three-fourth: @fourth * 3 + @marge * 2; 49 | @third: (100% - 2*@marge)*0.33333333333333333; 50 | @two-third: @third * 2 + @marge; 51 | @fourth: (100% - 3*@marge)*0.25; 52 | @fifth: (100% - 4*@marge)*0.2; 53 | 54 | // selector based on href name 55 | .components-grid-@{name} { 56 | .components-three-fourth-grid { 57 | width: @three-fourth; 58 | } 59 | .components-half-grid { 60 | width: @half; 61 | } 62 | .components-third-grid { 63 | width: @third; 64 | } 65 | .components-two-third-grid { 66 | width: @two-third; 67 | } 68 | .components-fourth-grid { 69 | width: @fourth; 70 | } 71 | .components-fifth-grid { 72 | width: @fifth; 73 | @media screen and (min-width: 1081px) and (max-width: 1365px) { 74 | width: @fourth; 75 | } 76 | } 77 | .components-full-grid, .components-half-grid, .components-third-grid, .components-two-third-grid, .components-fourth-grid, .components-three-fourth-grid, .components-fifth-grid { 78 | margin-bottom: @marge; 79 | } 80 | .components-third-grid, .components-two-third-grid, .components-fourth-grid, .components-three-fourth-grid, .components-fifth-grid { 81 | @media screen and (max-width: 1080px) { 82 | width: @half; 83 | } 84 | } 85 | } 86 | 87 | .each(@array, @i + 1); 88 | } 89 | 90 | .each(@columns); 91 | 92 | /* General Queries */ 93 | .components-grid-wrapper { 94 | .components-full-grid, .components-half-grid, .components-third-grid, .components-two-third-grid, .components-fourth-grid, .components-three-fourth-grid, .components-fifth-grid { 95 | @media screen and (max-width: 767px) { 96 | width: 100%; 97 | } 98 | } 99 | } 100 | 101 | /* Fillers */ 102 | span { 103 | &.components-full-grid, 104 | &.components-half-grid, 105 | &.components-third-grid, 106 | &.components-two-third-grid, 107 | &.components-fourth-grid, 108 | &.components-three-fourth-grid 109 | &.components-fifth-grid { 110 | margin: 0 !important; 111 | } 112 | } -------------------------------------------------------------------------------- /src/assets/other/modules.ts: -------------------------------------------------------------------------------- 1 | declare let ScrollReveal: any; 2 | 3 | export function InitScrollReveal() { 4 | if( typeof ScrollReveal !== "undefined" ) { 5 | 6 | window.sr = ScrollReveal(); 7 | 8 | window.sr.reveal( '.components-bottom-appear', { origin: 'bottom'}, 50 ); 9 | window.sr.reveal( '.components-left-appear', { origin: 'left'}, 50 ); 10 | window.sr.reveal( '.components-right-appear', { origin: 'right'}, 50 ); 11 | window.sr.reveal( '.components-top-appear', { origin: 'top'}, 50 ); 12 | } 13 | } 14 | 15 | export function InitParallax() { 16 | window.addEventListener('scroll', () => { 17 | let scrollPosition: number = window.scrollY; 18 | const parallaxSections = document.getElementsByClassName('components-parallax') as HTMLCollectionOf; 19 | 20 | if( parallaxSections.length > 0 ) { 21 | for( let section of parallaxSections ) { 22 | section.style.backgroundPosition = 'calc(50%) ' + 'calc(50% + ' + (scrollPosition/5) + "px" + ')'; 23 | } 24 | } 25 | 26 | }); 27 | } 28 | 29 | /** 30 | * Adds custom overlays to any section that has one defined 31 | * This function deprecates once attr is sufficiently supported by CSS 32 | */ 33 | export function InitOverlays() { 34 | const overlayedElements = document.getElementsByClassName('components-custom-overlay') as HTMLCollectionOf; 35 | 36 | if( overlayedElements.length < 1 ) { 37 | return; 38 | } 39 | 40 | for( let element of overlayedElements ) { 41 | const { color = '#000', opacity = '0.5' } = element.dataset; 42 | const overlay = document.createElement('div'); 43 | 44 | overlay.classList.add('components-overlay-background'); 45 | overlay.style.backgroundColor = color; 46 | overlay.style.opacity = opacity; 47 | 48 | element.append(overlay); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /src/assets/other/social.less: -------------------------------------------------------------------------------- 1 | // main: ../styles.less 2 | 3 | /** 4 | * Social Networks. 5 | * Because these classes are used in multiple atoms, these are prefixed with components. 6 | */ 7 | @phone: #333333; 8 | @email: #F8694D; 9 | @facebook: #3B5998; 10 | @instagram: #405de6; 11 | @twitter: #32CCFE; 12 | @linkedin: #0274B3; 13 | @google-plus: #D44036; 14 | @youtube: #FF0000; 15 | @pinterest: #CB2028; 16 | @reddit: #CEE3F8; 17 | @pocket: #EF4056; 18 | @github: #6e5494; 19 | @stumbleupon: #EB4924; 20 | @behance: #1769ff; 21 | @dribbble: #ea4c89; 22 | @whatsapp: #25d366; 23 | 24 | .components-telephone { 25 | color: @phone; 26 | .components-background & { 27 | background: @phone; 28 | color: #fff; 29 | } 30 | } 31 | 32 | .components-email { 33 | color: @email; 34 | .components-background & { 35 | background: @email; 36 | color: #fff; 37 | } 38 | } 39 | 40 | .components-facebook { 41 | color: @facebook; 42 | .components-background & { 43 | background: @facebook; 44 | color: #fff; 45 | } 46 | } 47 | 48 | .components-instagram { 49 | color: @instagram; 50 | .components-background & { 51 | background: @instagram; 52 | color: #fff; 53 | } 54 | } 55 | 56 | .components-twitter { 57 | color: @twitter; 58 | .components-background & { 59 | background: @twitter; 60 | color: #fff; 61 | } 62 | } 63 | 64 | .components-linkedin { 65 | color: @linkedin; 66 | .components-background & { 67 | background: @linkedin; 68 | color: #fff; 69 | } 70 | } 71 | 72 | .components-google-plus { 73 | color: @google-plus; 74 | .components-background & { 75 | background: @google-plus; 76 | color: #fff; 77 | } 78 | } 79 | 80 | .components-youtube { 81 | color: @youtube; 82 | .components-background & { 83 | background: @youtube; 84 | color: #fff; 85 | } 86 | } 87 | 88 | .components-pinterest { 89 | color: @pinterest; 90 | .components-background & { 91 | background: @pinterest; 92 | color: #fff; 93 | } 94 | } 95 | 96 | .components-reddit { 97 | color: @reddit; 98 | .components-background & { 99 | background: @reddit; 100 | color: #fff; 101 | } 102 | } 103 | 104 | .components-github { 105 | color: @github; 106 | .components-background & { 107 | background: @github; 108 | color: #fff; 109 | } 110 | } 111 | 112 | .components-dribbble { 113 | color: @dribbble; 114 | .components-background & { 115 | background: @dribbble; 116 | color: #fff; 117 | } 118 | } 119 | 120 | .components-behance { 121 | color: @dribbble; 122 | .components-background & { 123 | background: @behance; 124 | color: #fff; 125 | } 126 | } 127 | 128 | .components-pocket { 129 | color: @pocket; 130 | .components-background & { 131 | background: @pocket; 132 | color: #fff; 133 | } 134 | } 135 | 136 | .components-stumbleupon { 137 | color: @stumbleupon; 138 | .components-background & { 139 | background: @stumbleupon; 140 | color: #fff; 141 | } 142 | } 143 | 144 | .components-whatsapp { 145 | color: @whatsapp; 146 | .components-background & { 147 | background: @whatsapp; 148 | color: #fff; 149 | } 150 | } -------------------------------------------------------------------------------- /src/assets/other/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains utility functions 3 | */ 4 | import AjaxData from "../types/ajax-data"; 5 | import { SiblingTypes } from "../types/sibling-types"; 6 | 7 | declare let wpc: any; 8 | 9 | /** 10 | * Sends a post request to the default WordPress Ajax API endpoint 11 | * 12 | * @param data The data that needs to passed to the ajax endpoint 13 | * @returns Promise The json response from the fetched resource 14 | */ 15 | export async function AjaxApi(data: AjaxData): Promise { 16 | 17 | if( typeof data.nonce === 'undefined' ) { 18 | data.nonce = wpc.nonce; 19 | } 20 | 21 | // Non-rest api calls using admin-ajax use FormData. 22 | const body = new FormData(); 23 | 24 | for( const key in data ) { 25 | body.append(key, data[key]); 26 | } 27 | 28 | const response = await fetch(wpc.ajaxUrl, { 29 | method: 'POST', 30 | credentials: 'same-origin', 31 | body 32 | }); 33 | 34 | const jsonResponse = response.json(); 35 | 36 | if( wpc.debug ) { 37 | console.log(jsonResponse); 38 | } 39 | 40 | return jsonResponse; 41 | } 42 | 43 | /** 44 | * Toggles the display of an HTML Element by sliding its height 45 | * 46 | * @param element An HTML Element that needs to slide 47 | * @param displayStyle The display value that needs to used for displaying the item 48 | */ 49 | export function SlideToggle(element: HTMLElement | null, displayStyle: string = 'block'): void { 50 | 51 | if( ! element ) { 52 | return; 53 | } 54 | 55 | if( getComputedStyle(element).display === 'none' ) { 56 | SlideOut(element, displayStyle); 57 | } else { 58 | SlideIn(element); 59 | } 60 | 61 | } 62 | 63 | /** 64 | * Exposes the display of an HTML Element by sliding its height out 65 | * 66 | * @param element An HTML Element that needs to slide 67 | * @param displayStyle The display value that needs to used for displaying the item 68 | */ 69 | export function SlideOut(element: HTMLElement | null, displayStyle: string = 'block'): void { 70 | 71 | if( ! element ) { 72 | return; 73 | } 74 | 75 | element.classList.add('components-transition'); 76 | element.style.display = displayStyle; 77 | element.style.removeProperty('height'); 78 | 79 | // Grab and reset the height and opacity 80 | let elementHeight = element.clientHeight; 81 | element.style.height = '0px'; 82 | element.style.opacity = '0'; 83 | 84 | setTimeout( () => { 85 | element.style.opacity = '1'; 86 | element.style.height = elementHeight + 'px'; 87 | }, 0); 88 | 89 | } 90 | 91 | /** 92 | * Hides the display of an HTML Element by sliding its height in 93 | * 94 | * @param element An HTML Element that needs to slide 95 | */ 96 | export function SlideIn(element: HTMLElement | null): void { 97 | 98 | if( ! element ) { 99 | return; 100 | } 101 | 102 | element.classList.add('components-transition'); 103 | element.style.opacity = '1'; 104 | 105 | setTimeout( () => { 106 | element.style.height = '0px'; 107 | element.style.opacity = '0'; 108 | }, 0); 109 | 110 | setTimeout( () => { 111 | element.style.display = 'none'; 112 | element.classList.remove('components-transition'); 113 | }, 350); 114 | } 115 | 116 | /** 117 | * Toggles the display of an HTML Element by adjusting it's opacity 118 | * 119 | * @param element An HTML Element that needs to slide 120 | * @param displayStyle The display value that needs to used for displaying the item 121 | */ 122 | export function FadeToggle(element: HTMLElement | null, displayStyle: string = 'block'): void { 123 | 124 | if( ! element ) { 125 | return; 126 | } 127 | 128 | // FadeIn 129 | if( getComputedStyle(element).display === 'none' ) { 130 | FadeIn(element, displayStyle); 131 | } else { 132 | FadeOut(element); 133 | } 134 | 135 | } 136 | 137 | /** 138 | * Toggles the display of an HTML Element by fading out 139 | * 140 | * @param element An HTML Element that needs to slide 141 | */ 142 | export function FadeOut(element: HTMLElement | null): void { 143 | 144 | if( ! element ) { 145 | return; 146 | } 147 | 148 | element.classList.add('components-transition'); 149 | element.style.opacity = "0"; 150 | setTimeout( () => { 151 | element.style.display = "none"; 152 | element.classList.remove('components-transition'); 153 | }, 350); 154 | 155 | } 156 | 157 | /** 158 | * Toggles the display of an HTML Element by fading in. 159 | * The element should previously be faded out. 160 | * 161 | * @param element An HTML Element that needs to slide 162 | * @param displayStyle The display value that needs to used for displaying the item 163 | */ 164 | export function FadeIn(element: HTMLElement | null, displayStyle: string = 'block'): void { 165 | 166 | if( ! element ) { 167 | return; 168 | } 169 | 170 | element.style.display = displayStyle; 171 | element.style.opacity = "0"; 172 | element.classList.add('components-transition'); 173 | setTimeout( () => { 174 | element.style.opacity = "1"; 175 | }, 0); 176 | 177 | } 178 | 179 | /** 180 | * Toggles the class(es) for a given HTML element 181 | * @param element The element for which the class should be toggled 182 | * @param className The name of the given class, or array of names 183 | */ 184 | export function ToggleClass(element: HTMLElement | Element | null, className: string | string[]): void { 185 | 186 | if( ! element ) { 187 | return; 188 | } 189 | 190 | if( Array.isArray(className) ) { 191 | className.forEach(name => { 192 | element.classList.toggle(name); 193 | }); 194 | } else { 195 | element.classList.toggle(className); 196 | } 197 | 198 | } 199 | 200 | /** 201 | * Get all siblings for a given element 202 | * 203 | * @param element The element to look for siblings 204 | * @param mode The type of siblings to look for (previous or next) 205 | */ 206 | export function GetElementSiblings(element: HTMLElement | Element | null, mode: SiblingTypes = SiblingTypes.Next): Element[] { 207 | 208 | if( ! element) { 209 | return []; 210 | } 211 | 212 | const siblings = []; 213 | 214 | if(mode === SiblingTypes.Previous) { 215 | while (element = element.previousElementSibling) { 216 | siblings.push(element); 217 | } 218 | } else if(mode === SiblingTypes.Next) { 219 | while (element = element.nextElementSibling) { 220 | siblings.push(element); 221 | } 222 | } 223 | 224 | return siblings; 225 | } -------------------------------------------------------------------------------- /src/assets/scripts.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * All front-end modules are bundled into one application 3 | */ 4 | import Cart from "./atoms/cart"; 5 | import CustomMap from "./atoms/map"; 6 | import Menu from "./atoms/menu"; 7 | import Modal from "./atoms/modal"; 8 | import Rate from "./atoms/rate"; 9 | import Scroll from "./atoms/scroll"; 10 | import Search from "./atoms/search"; 11 | import Share from "./atoms/share"; 12 | import Tabs from "./atoms/tabs"; 13 | import Header from "./molecules/header"; 14 | import Posts from "./molecules/posts"; 15 | import Slider from "./molecules/slider"; 16 | import { InitParallax, InitScrollReveal, InitOverlays } from "./other/modules"; 17 | import Component from "./types/component"; 18 | 19 | /** 20 | * Core class responsible for booting the application 21 | */ 22 | class WPC_App { 23 | 24 | private modules: Component[]; 25 | 26 | constructor() { 27 | this.modules = [ 28 | Header, Slider, Posts, Tabs, Search, Scroll, Rate, Modal, Menu, CustomMap, Share, Cart 29 | ]; 30 | this.initialize(); 31 | } 32 | 33 | /** 34 | * Executes all code after the DOM has loaded 35 | */ 36 | private initialize() { 37 | document.addEventListener('DOMContentLoaded', () => { 38 | for( const key in this.modules ) { 39 | this.modules[key].init(); 40 | } 41 | 42 | InitOverlays(); 43 | InitParallax(); 44 | InitScrollReveal(); 45 | }); 46 | } 47 | 48 | }; 49 | 50 | new WPC_App(); -------------------------------------------------------------------------------- /src/assets/styles.less: -------------------------------------------------------------------------------- 1 | // out: ../../public/css/wpc-styles.min.css, compress: true 2 | 3 | // General 4 | @import 'other/animations.less'; 5 | @import 'other/grid.less'; 6 | 7 | // Atoms 8 | @import 'atoms/author.less'; 9 | @import 'atoms/breadcrumbs.less'; 10 | @import 'atoms/button.less'; 11 | @import 'atoms/cart.less'; 12 | @import 'atoms/comments.less'; 13 | @import 'atoms/image.less'; 14 | @import 'atoms/list.less'; 15 | @import 'atoms/logo.less'; 16 | @import 'atoms/map.less'; 17 | @import 'atoms/menu.less'; 18 | @import 'atoms/modal.less'; 19 | @import 'atoms/pagination.less'; 20 | @import 'atoms/rate.less'; 21 | @import 'atoms/scroll.less'; 22 | @import 'atoms/share.less'; 23 | @import 'atoms/social.less'; 24 | @import 'atoms/tabs.less'; 25 | @import 'atoms/termlist.less'; 26 | @import 'atoms/terms.less'; 27 | @import 'atoms/search.less'; 28 | @import 'atoms/video.less'; 29 | 30 | // Molecules 31 | @import 'molecules/header.less'; 32 | @import 'molecules/footer.less'; 33 | @import 'molecules/post-header.less'; 34 | @import 'molecules/post-footer.less'; 35 | @import 'molecules/posts.less'; 36 | @import 'molecules/section.less'; 37 | @import 'molecules/slider.less'; 38 | 39 | // Global 40 | @import 'other/global.less'; 41 | @import 'other/colors.less'; 42 | @import 'other/social.less'; -------------------------------------------------------------------------------- /src/assets/types/ajax-data.ts: -------------------------------------------------------------------------------- 1 | type AjaxData = { 2 | action: string; 3 | nonce?: string; 4 | [key: string]: any; 5 | } 6 | 7 | export default AjaxData; -------------------------------------------------------------------------------- /src/assets/types/component.ts: -------------------------------------------------------------------------------- 1 | interface Component { 2 | properties?: object; 3 | elements: HTMLCollectionOf; 4 | init(): void; 5 | [key: string]: any; 6 | } 7 | 8 | export default Component; -------------------------------------------------------------------------------- /src/assets/types/sibling-types.ts: -------------------------------------------------------------------------------- 1 | export enum SiblingTypes { 2 | Previous = 'previous', 3 | Next = 'next' 4 | }; -------------------------------------------------------------------------------- /src/components/atoms/archive-title.php: -------------------------------------------------------------------------------- 1 | '', 10 | 'types' => [ 11 | 'author' => __( 'Posts Author Archive: %s', WP_COMPONENTS_LANGUAGE ), 12 | 'category' => single_cat_title( '', false ), 13 | 'day' => sprintf( __( 'Daily Archives: %s', WP_COMPONENTS_LANGUAGE ), '' . get_the_date() . '' ), 14 | 'default' => isset(get_queried_object()->labels->name) ? get_queried_object()->labels->name : __( 'Blog Archives', WP_COMPONENTS_LANGUAGE ), 15 | 'home' => isset(get_queried_object()->post_title) ? get_queried_object()->post_title : __( 'Blog Archives', WP_COMPONENTS_LANGUAGE ), 16 | 'month' => sprintf( __( 'Monthly Archives: %s', WP_COMPONENTS_LANGUAGE ), '' . get_the_date('F Y') . '' ), 17 | 'search' => sprintf( 18 | _n( '%1$s result for: %2$s', '%1$s results for: %2$s', $wp_query->found_posts, WP_COMPONENTS_LANGUAGE ), 19 | '' . number_format_i18n( $wp_query->found_posts ) . '', 20 | '' . get_search_query() . '' 21 | ), 22 | 'tag' => sprintf( __( 'Posts tagged: %s', WP_COMPONENTS_LANGUAGE ) , '' . single_tag_title( '', false ) . '' ), 23 | 'tax' => single_term_title( '', false ), 24 | 'year' => sprintf( __( 'Yearly Archives: %s', WP_COMPONENTS_LANGUAGE ), get_the_date('Y') ), 25 | ] 26 | ] ); 27 | 28 | 29 | $archive_title = ''; 30 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 31 | 32 |

> 33 | $title ) { 38 | 39 | // Condition for showing the archive 40 | $condition = 'is_' . $type; 41 | 42 | if( function_exists($condition) && $condition() ) { 43 | 44 | if( $type == 'author' ) { 45 | $current = get_query_var('author_name') ? get_user_by('slug', get_query_var('author_name') ) : get_userdata( get_query_var('author') ); 46 | $title = sprintf( __( 'Posts written by: %s', WP_COMPONENTS_LANGUAGE ), '' . $current->display_name . ''); 47 | } 48 | 49 | $archive_title = $title; 50 | 51 | } 52 | 53 | } 54 | 55 | if( ! $archive_title ) { 56 | $archive_title = $atom['types']['default']; 57 | } 58 | 59 | if( $atom['custom'] ) { 60 | $archive_title = $atom['custom']; 61 | } 62 | 63 | echo $archive_title; 64 | 65 | ?> 66 |

-------------------------------------------------------------------------------- /src/components/atoms/author.php: -------------------------------------------------------------------------------- 1 | 'image_float', 'imageRounded' => 'image_rounded', 'jobTitle' => 'job_title']); 13 | 14 | // Atom values 15 | $atom = MakeitWorkPress\WP_Components\Build::multi_parse_args( $atom, [ 16 | 'attributes' => [ 17 | 'itemprop' => 'author', 18 | 'itemscope' => 'itemscope', 19 | 'itemtype' => 'http://schema.org/Person' 20 | ], 21 | 'avatar' => get_avatar( $post->post_author, 100 ), 22 | 'description' => get_the_author_meta( 'description', $post->post_author ), 23 | 'image_float' => 'none', 24 | 'image_rounded' => true, 25 | 'job_title' => '', 26 | 'name' => get_the_author(), 27 | 'prepend' => '', // Prepend the author name with a custom description 28 | 'schema' => true, // If schema microdata are used or not 29 | 'url' => esc_url( get_author_posts_url( $post->post_author ) ) 30 | ] ); 31 | 32 | $atom['image_rounded'] = $atom['image_rounded'] ? 'components-rounded' : ''; 33 | 34 | if( ! $atom['schema'] ) { 35 | unset($atom['attributes']['itemprop']); 36 | unset($atom['attributes']['itemscope']); 37 | unset($atom['attributes']['itemtype']); 38 | } 39 | 40 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 41 | 42 |
> 43 | 44 | 45 | 46 |
47 | 50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 |
58 | 59 | 60 |

itemprop="name">

61 | 62 | 63 | 64 |

itemprop="jobTitle">

65 | 66 | 67 | 68 |

69 | 70 | 71 |
72 | 73 | 74 | 75 |
-------------------------------------------------------------------------------- /src/components/atoms/button.php: -------------------------------------------------------------------------------- 1 | 'icon_after', 'iconBefore' => 'icon_before', 'iconVisible' => 'icon_visible']); 8 | 9 | // Atom values 10 | $atom = MakeitWorkPress\WP_Components\Build::multi_parse_args( $atom, [ 11 | 'attributes' => [ 12 | 'href' => 'post', 13 | 'target' => '_self' 14 | ], 15 | 'icon_after' => '', // Icon before the button 16 | 'icon_before' => '', // Icon after the button 17 | 'icon_visible' => 'standard', // When the icon becomes visible. Accepts standard or hover 18 | 'label' => '', // The button label 19 | 'size' => '' // Defines the size of the button. If set to none, displays a button without background, border and padding. 20 | ] ); 21 | 22 | // Buttons should have a label 23 | if( ! $atom['label'] ) { 24 | return; 25 | } 26 | 27 | // Icon visibility, but only if an icon is defined 28 | if( $atom['icon_visible'] && ($atom['icon_after'] || $atom['icon_before']) ) { 29 | $atom['attributes']['class'] .= ' atom-button-' . $atom['icon_visible']; 30 | } 31 | 32 | // Default background 33 | if( ! isset($atom['background']) ) { 34 | $atom['attributes']['class'] .= ' components-light-background'; 35 | } 36 | 37 | // Adjusted class for the size 38 | if( $atom['size'] ) { 39 | $atom['attributes']['class'] .= ' atom-button-' . $atom['size']; 40 | } 41 | 42 | // If we are still using the link attribute 43 | if( isset($atom['link']) ) { 44 | $atom['attributes']['href'] = $atom['link']; 45 | } 46 | 47 | // Custom link to a post 48 | if( $atom['attributes']['href'] == 'post' ) { 49 | $atom['attributes']['href'] = esc_url( get_permalink() ); 50 | } 51 | 52 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 53 | 54 | > 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/components/atoms/callback.php: -------------------------------------------------------------------------------- 1 | 2 | '' // Either a string or an array for class methods 8 | ] ); 9 | 10 | if( ! $atom['callback'] ) { 11 | return; 12 | } 13 | 14 | call_user_func( $atom['callback'] ); -------------------------------------------------------------------------------- /src/components/atoms/cart.php: -------------------------------------------------------------------------------- 1 | true, // Whether to show the cart content or not 7 | 'collapse' => true, // Determines the behaviour of the cart. If we collapse, the cart is hidden by default. 8 | 'icon' => true // Shows a cart icon. Needed if we have collapsed our cart. 9 | ] ); 10 | 11 | if( $atom['collapse'] ) { 12 | $atom['attributes']['class'] .= ' atom-cart-collapsed'; 13 | } 14 | 15 | // Woocommerce should be active 16 | if( ! class_exists('WooCommerce') ) { 17 | return; 18 | } 19 | 20 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 21 | 22 |
> 23 | cart->get_cart_contents_count(); 28 | 29 | ?> 30 | 31 | 32 | 0 ) { ?> 33 | 34 | 35 | 36 | 46 |
47 |
48 |
49 | 52 |
-------------------------------------------------------------------------------- /src/components/atoms/comments.php: -------------------------------------------------------------------------------- 1 | 'closed_text', 'hasComments' => 'has_comments']); 8 | 9 | // Atom values 10 | $atom = MakeitWorkPress\WP_Components\Build::multi_parse_args( $atom, array( 11 | 'attributes' => [ 12 | 'id' => 'comments' 13 | ], 14 | 'closed' => ! comments_open(), 15 | 'closed_text' => __('Comments are closed.', WP_COMPONENTS_LANGUAGE), // May contain a string for the closed text 16 | 'form' => true, 17 | 'has_comments' => get_comments_number(), 18 | 'pagination' => true, 19 | 'seperate' => false, // If comments should be seperated by type 20 | 'template' => '', // Loads a custom template 21 | 'title' => sprintf( 22 | _n( 'One Response to %2$s', '%1$s Responses to %2$s', get_comments_number(), WP_COMPONENTS_LANGUAGE ), 23 | number_format_i18n( get_comments_number() ), 24 | get_the_title() 25 | ) 26 | ) ); 27 | 28 | // Return if a password is required 29 | if ( post_password_required() ) { 30 | return; 31 | } 32 | 33 | // Use forward slash for file directories (windows uses backwards) 34 | $file_path = str_replace('\\', '/', dirname(__FILE__) ); 35 | $theme_path = str_replace('\\', '/', TEMPLATEPATH ); 36 | $child_path = str_replace('\\', '/', STYLESHEETPATH ); 37 | 38 | // When the component is overwritten, we use a different file 39 | if( $atom['template'] ) { 40 | $file = $atom['template']; 41 | } elseif( strpos($file_path, $theme_path) === 0 ) { 42 | $file = str_replace( $theme_path, '', $file_path ) . '/compatible/comments.php'; 43 | } elseif( strpos($file_path, $child_path) === 0 ) { 44 | $file = str_replace( $child_path, '', $file_path ) . '/compatible/comments.php'; 45 | } 46 | 47 | // Store our atom in a global variable so that we can access it later in the template file 48 | $GLOBALS['atom'] = $atom; 49 | 50 | /** 51 | * The following code is needed because of the way WordPress currently loads comments using the comments_template function. 52 | */ 53 | comments_template( $file, $atom['seperate'] ); ?> -------------------------------------------------------------------------------- /src/components/atoms/compatible/comments.php: -------------------------------------------------------------------------------- 1 | 15 |
> 16 | 17 | 18 |

19 | 20 | 21 | 22 | 23 | 24 | 25 |

26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
    34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 50 | 51 |
52 | 53 | -------------------------------------------------------------------------------- /src/components/atoms/compatible/index.php: -------------------------------------------------------------------------------- 1 | [ 10 | 'itemprop' => 'text' 11 | ], 12 | 'content' => '', // Allows developers to set their own string of content 13 | 'pages' => wp_link_pages( ['echo' => false] ), 14 | 'schema' => true, // If microdata is rendered or not 15 | 'type' => 'content' // Accepts content, excerpt; 16 | ] ); 17 | 18 | if( ! $atom['content'] ) { 19 | 20 | if( $atom['type'] == 'excerpt' ) { 21 | 22 | global $post; 23 | 24 | if( is_numeric($post) ) { 25 | $post = get_post($post); 26 | } 27 | 28 | // Set our more to zero and retrieve the text before the more tag 29 | if( strpos($post->post_content, '') >= 1 ) { 30 | global $more; $more = 0; 31 | $atom['content'] = wpautop( get_the_content() ); 32 | } else { 33 | $atom['content'] = wpautop( get_the_excerpt($post) ); 34 | } 35 | 36 | } elseif( $atom['type'] == 'content' ) { 37 | $atom['content'] = apply_filters( 'the_content', get_the_content() ); 38 | } 39 | 40 | } 41 | 42 | if( ! $atom['schema'] ) { 43 | unset($atom['attributes']['itemprop']); 44 | } 45 | 46 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 47 | 48 |
> 49 | 50 | 51 | 52 | 60 | 61 | 62 | 63 |
-------------------------------------------------------------------------------- /src/components/atoms/copyright.php: -------------------------------------------------------------------------------- 1 | '©', 9 | 'date' => date('Y'), 10 | 'itemtype' => 'http://schema.org/Organization', 11 | 'name' => '' 12 | ] ); 13 | 14 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 15 | 16 |
> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
-------------------------------------------------------------------------------- /src/components/atoms/date.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'datetime' => get_the_date('c'), 10 | 'itemprop' => 'datePublished' 11 | ], 12 | 'date' => get_the_date(), 13 | 'schema' => true, // If microdata is rendered or not 14 | 'icon' => '', 15 | ] ); 16 | 17 | if( ! $atom['schema'] ) { 18 | unset($atom['attributes']['itemprop']); 19 | } 20 | 21 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 22 | 23 | -------------------------------------------------------------------------------- /src/components/atoms/description.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'itemprop' => 'description' 10 | ], 11 | 'description' => '', 12 | 'schema' => true, // If microdata is rendered or not 13 | 'tag' => 'p' 14 | ] ); 15 | 16 | if( ! $atom['description'] ) { 17 | return; 18 | } 19 | 20 | if( ! $atom['schema'] ) { 21 | unset($atom['attributes']['itemprop']); 22 | } 23 | 24 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 25 | 26 | < > 27 | 28 | > -------------------------------------------------------------------------------- /src/components/atoms/image.php: -------------------------------------------------------------------------------- 1 | false, 9 | 'image' => '', // Expects a custom image tag for the image, including the html or an id to an image. Also accepts custom string to look for the image id in a meta field 10 | 'link' => '', // A custom link from the image. Also accepts 'post' to load the permalink for the post 11 | 'post' => null, 12 | 'schema' => true, // If microdata is rendered or not 13 | 'size' => 'large' 14 | ] ); 15 | 16 | // Custom link to a post 17 | if( $atom['link'] == 'post' ) { 18 | $atom['link'] = is_numeric( $atom['post'] ) || is_object( $atom['post'] ) ? esc_url( get_permalink( $atom['post'] ) ) : esc_url( get_permalink() ); 19 | } 20 | 21 | if( $atom['enlarge'] ) { 22 | $atom['attributes']['class'] .= ' atom-image-enlarge'; 23 | } 24 | 25 | 26 | $args = ['itemprop' => 'image']; 27 | 28 | if( ! $atom['schema'] ) { 29 | unset($args['itemprop']); 30 | } 31 | 32 | // Now, load our image based upon what we have in the image parameter 33 | if( is_numeric($atom['image']) ) { 34 | $atom['image'] = wp_get_attachment_image( $atom['image'], $atom['size'], false, $args ); 35 | } elseif( is_string($atom['image']) && strlen($atom['image']) > 3 && strpos( $atom['image'], ' 2 ) { 38 | $id = get_post_meta( get_the_ID(), $atom['image'], true); 39 | $atom['image'] = wp_get_attachment_image( $id , $atom['size'], false, $args ); 40 | } elseif( empty($atom['image']) && isset($atom['post']) ) { 41 | $atom['image'] = get_the_post_thumbnail( $atom['post'], $atom['size'], $args ); 42 | } else { 43 | global $post; 44 | $atom['image'] = get_the_post_thumbnail( $post, $atom['size'], $args ); 45 | } 46 | 47 | // We should have an image 48 | if( ! $atom['image'] ) { 49 | return ''; 50 | } 51 | 52 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 53 | 54 |
> 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
-------------------------------------------------------------------------------- /src/components/atoms/list.php: -------------------------------------------------------------------------------- 1 | 'grid_gap', 'hoverItem' => 'hover_item', 'titleTag' => 'title_tag']); 9 | 10 | // Atom values 11 | $atom = MakeitWorkPress\WP_Components\Build::multi_parse_args( $atom, [ 12 | 'grid' => false, // Displays the list in a grid, 13 | 'grid_gap' => 'default', // Accepts a certain gridgap 14 | 'hover_item' => '', // Allows a hover.css class applied to each item. Requires hover to be set true in Boot(). 15 | 'items' => [], // Accepts an array with list items, keyed with icon, title, description, link and column 16 | 'style' => 'default', // Accepts 'default' or 'card' to display a card like list 17 | 'title_tag' => 'h4' // The title tag for the list title 18 | ] ); 19 | 20 | if( ! $atom['items'] ) { 21 | return; 22 | } 23 | 24 | // Additional classes 25 | $atom['attributes']['class'] .= ' components-list-' . $atom['style']; 26 | 27 | if( $atom['grid'] ) { 28 | $atom['attributes']['class'] .= ' components-grid-wrapper components-grid-' . $atom['grid_gap']; 29 | } 30 | 31 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 32 | 33 |
    > 34 | 35 | 36 | 37 |
  • 38 | 39 | 40 | 41 | 42 | 43 |
    44 | 45 | < class="components-list-item-title"> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | > 58 | 59 | 60 |

    61 | 62 | 63 |
    64 | 65 |
  • 66 | 67 | 68 | 69 |
-------------------------------------------------------------------------------- /src/components/atoms/logo.php: -------------------------------------------------------------------------------- 1 | 'default_transparent', 10 | 'mobileTransparent' => 'mobile_transparent', 11 | 'tabletTransparent' => 'tablet_transparent' 12 | ]); 13 | 14 | // Atom values 15 | $atom = MakeitWorkPress\WP_Components\Build::multi_parse_args( $atom, [ 16 | 'attributes' => [ 17 | 'href' => esc_url( home_url('/') ), 18 | 'itemscope' => 'itemscope', 19 | 'itemtype' => 'http://schema.org/Organization', 20 | ], 21 | 'alt' => __('Logo', WP_COMPONENTS_LANGUAGE), 22 | 'default' => get_theme_mod( 'custom_logo' ), // The default logo src. Also accepts an image id 23 | 'default_transparent' => ['src' => '', 'height' => '', 'width' => ''], // The logo src for transparent headers 24 | 'mobile' => ['src' => '', 'height' => '', 'width' => ''], // The logo src for mobile display 25 | 'mobile_transparent' => ['src' => '', 'height' => '', 'width' => ''], // The logo src for mobile display for transparent headers 26 | 'mode' => 'logo', // Accepts 'logo' (displays the site logo) or 'title' (displays a the site title) 27 | 'schema' => true, // If microdata is rendered or not 28 | 'size' => 'medium', // The default size of the fetched logo 29 | 'tablet' => ['src' => '', 'height' => '', 'width' => ''], // The logo src for tablet display 30 | 'tablet_transparent' => ['src' => '', 'height' => '', 'width' => ''], // The logo src for tablet display for transparent headers 31 | 'title' => esc_attr( get_bloginfo('name') ), 32 | 'url' => esc_url( get_bloginfo('url') ) 33 | ] ); 34 | 35 | if( $atom['mode'] === 'logo' && ! is_numeric($atom['default']) && ! isset($atom['default']['src']) ) { 36 | return; 37 | } 38 | 39 | if( ! $atom['schema'] ) { 40 | unset($atom['attributes']['itemscope']); 41 | unset($atom['attributes']['itemtype']); 42 | } 43 | 44 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 45 | 46 | > 47 | 48 | 49 | $itemprop, 'class' => 'atom-logo-' . $image, 'alt' => $atom['alt']]; 63 | if( ! $atom['schema'] ) { 64 | unset($args['itemprop']); 65 | } 66 | echo wp_get_attachment_image( $atom[$image], $atom['size'], false, $args ); 67 | 68 | } else if( isset($atom[$image]['src']) && $atom[$image]['src'] && isset($atom[$image]['width']) && $atom[$image]['width'] && isset($atom[$image]['height']) && $atom[$image]['height'] ) { 69 | 70 | $itemprop = $atom['schema'] ? 'itemprop="' . $itemprop . '"' : ''; 71 | echo '' . $atom['alt']. ''; 72 | 73 | } 74 | 75 | } 76 | } ?> 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/components/atoms/map.php: -------------------------------------------------------------------------------- 1 | ['lat' => '52.090736', 'lng' => '5.121420'], 9 | 'fit' => true, 10 | 'id' => 'wpcDefaultMap', // Default ID to which map configurations are saved 11 | 'markers' => [], // Use ['lat' => $lat, 'lng' => $lng, 'icon' => 'icon.png'] or ['address' => $address, 'icon' => 'icon.png'] 12 | 'styles' => '[]', // Custom map styles 13 | 'zoom' => 12 14 | ] ); 15 | 16 | // Enqueue our slider script 17 | if( ! wp_script_is('google-maps-js') && apply_filters('components_maps_script', true) ) { 18 | wp_enqueue_script('google-maps-js'); 19 | } 20 | 21 | // Localize 22 | add_action('wp_footer', function() use($atom) { 23 | echo ''; 32 | }); 33 | 34 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 35 | 36 |
> 37 |
38 |
-------------------------------------------------------------------------------- /src/components/atoms/menu.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'itemtype' => 'http://schema.org/SiteNavigationElement', 10 | 'itemscope' => 'itemscope' 11 | ], 12 | 'args' => [], // The wp_nav_menu arguments 13 | 'collapse' => false, // If you want to collapse to the mobile menu by default, and expandable with clicking 14 | 'dropdown' => true, // If you want to remove dropdowns, set this to false 15 | 'hamburger' => 'mobile', // Accepts mobile (767px), tablet (1080px) always (always hamburger) or false (never hamburger) 16 | 'indicator' => true, // Shows a submenu indicator if an menu item has a submenu 17 | 'menu' => '', // Pass a wordpress menu - overrides any args 18 | 'view' => 'default', // Accepts dark to display a dark mobile menu, fixed, left or right to display the hamburger with a special menu 19 | ] ); 20 | 21 | // By default, we don't echo the menu 22 | $atom['args']['echo'] = false; 23 | 24 | if( $atom['collapse'] ) { 25 | $atom['attributes']['class'] .= ' atom-menu-collapse'; 26 | } 27 | 28 | if( ! $atom['dropdown'] ) { 29 | $atom['attributes']['class'] .= ' atom-menu-plain'; 30 | } 31 | 32 | if( $atom['hamburger'] && ! in_array($atom['view'], ['fixed', 'left', 'right']) ) { 33 | $atom['attributes']['class'] .= ' atom-menu-' . $atom['hamburger'] . '-hamburger'; 34 | } 35 | 36 | if( $atom['indicator'] ) { 37 | $atom['attributes']['class'] .= ' atom-menu-indicator'; 38 | } 39 | 40 | if( $atom['view'] ) { 41 | $atom['attributes']['class'] .= ' atom-menu-' . $atom['view']; 42 | } 43 | 44 | // A menu can be set manually if preferred 45 | if( ! $atom['menu'] ) { 46 | $atom['menu'] = wp_nav_menu( $atom['args'] ); 47 | } 48 | 49 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 50 | 51 | -------------------------------------------------------------------------------- /src/components/atoms/meta.php: -------------------------------------------------------------------------------- 1 | '', // Custom string echoed before the meta information 9 | 'before' => '', // Custom string echoed after the meta information 10 | 'key' => '', // Key for retrieving meta information 11 | 'id' => get_the_ID(), // The post id 12 | 'meta' => '' //The meta information it self 13 | ] ); 14 | 15 | if( ! $atom['meta'] && $atom['key'] ) { 16 | $atom['meta'] = get_post_meta( $atom['id'], $atom['key'], true ); 17 | } 18 | 19 | // Return if we do not have a meta value 20 | if( ! $atom['meta'] ) { 21 | return; 22 | } 23 | 24 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 25 | 26 |
> 27 | 39 |
-------------------------------------------------------------------------------- /src/components/atoms/modal.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'data' => ['id' => uniqid()] 10 | ], 11 | 'content' => '' 12 | ] ); 13 | 14 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 15 | 16 |
> 17 |
18 | 19 |
20 | 21 |
22 | 23 |
24 | 25 |
-------------------------------------------------------------------------------- /src/components/atoms/pagination.php: -------------------------------------------------------------------------------- 1 | '/page/%#%', 10 | 'next' => '›', 11 | 'pagination' => '', 12 | 'prev' => '‹', 13 | 'size' => 2, 14 | 'type' => 'numbers', // Accepts arrows, numbers or post (for in post navigation) 15 | 'query' => $wp_query 16 | ] ); 17 | 18 | // Pagination with numbers 19 | if( $atom['type'] == 'numbers' && ! $atom['pagination'] ) { 20 | 21 | $atom['pagination'] = paginate_links( array( 22 | 'base' => str_replace( 999999999, '%#%', get_pagenum_link( 999999999 ) ), 23 | 'current' => isset($atom['query']->query_vars['paged']) && $atom['query']->query_vars['paged'] ? $atom['query']->query_vars['paged'] : max( 1, get_query_var('paged') ), 24 | 'format' => $atom['format'], 25 | 'mid_size' => $atom['size'], 26 | 'next_text' => $atom['next'], 27 | 'prev_text' => $atom['prev'], 28 | 'total' => $atom['query']->max_num_pages 29 | )); 30 | 31 | } 32 | 33 | // Set our type as a class 34 | $atom['attributes']['class'] .= ' atom-pagination-' . $atom['type']; 35 | 36 | // Pagination with next and previous posts links. Only works in archives where a query is already set. 37 | if( $atom['type'] == 'arrows' && ! $atom['pagination'] ) { 38 | 39 | $atom['pagination'] = get_previous_posts_link( $atom['prev'] ); 40 | $atom['pagination'] .= get_next_posts_link( $atom['next'] ); 41 | 42 | } 43 | 44 | // Pagination with next and previous posts links within a post 45 | if( $atom['type'] == 'post' && ! $atom['pagination'] ) { 46 | 47 | if( $atom['next'] == '›' ) 48 | $atom['next'] = '%title '; 49 | 50 | if( $atom['prev'] == '‹' ) 51 | $atom['prev'] = ' %title'; 52 | 53 | $atom['pagination'] = get_previous_post_link( '%link', $atom['prev'] ); 54 | $atom['pagination'] .= get_next_post_link( '%link', $atom['next'] ); 55 | 56 | } 57 | 58 | // If our atom is empty, we just return 59 | if( ! $atom['pagination'] ) { 60 | return; 61 | } 62 | 63 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 64 | 65 | -------------------------------------------------------------------------------- /src/components/atoms/rate.php: -------------------------------------------------------------------------------- 1 | 'author_type']); 10 | 11 | // Atom values 12 | $atom = MakeitWorkPress\WP_Components\Build::multi_parse_args( $atom, [ 13 | 'attributes' => [ 14 | 'itemprop' => 'aggregateRating', 15 | 'itemscope' => 'itemscope', 16 | 'itemtype' => 'http://schema.org/AggregateRating' 17 | ], 18 | 'author' => '', 19 | 'author_type' => 'http://schema.org/Person', 20 | 'count' => get_post_meta($id, 'components_rating_count', true), 21 | 'id' => $id, // The id for the given post 22 | 'max' => 5, 23 | 'min' => 0, 24 | 'rate' => true, // Allows visitors to rate 25 | 'reviewed' => '', // Allows to add the title for the item reviewed 26 | 'schema' => true, // If microdata is rendered or not. Also removes schematic attributes 27 | 'value' => get_post_meta($id, 'components_rating', true) ? get_post_meta($id, 'components_rating', true) : 0 28 | ] ); 29 | 30 | // Rating fractions 31 | $floor = floor( $atom['value'] ); 32 | $fraction = $atom['value'] - $floor; 33 | 34 | $fullStars = $fraction >= 0.75 ? round( $atom['value'] ) : $floor; 35 | $halfStars = $fraction < 0.75 && $fraction > 0.25 ? 1 : 0; 36 | $emptyStars = $atom['max'] - $fullStars - $halfStars; 37 | 38 | // If we allow users to rate, we need to add a class so our JS can pick it up 39 | $atom['attributes']['class'] .= $atom['rate'] ? ' atom-rate-can' : ''; 40 | 41 | if( ! $atom['schema'] ) { 42 | unset($atom['attributes']['itemprop']); 43 | unset($atom['attributes']['itemscope']); 44 | unset($atom['attributes']['itemtype']); 45 | } 46 | 47 | if( $atom['rate'] ) { 48 | $atom['attributes']['data']['id'] = $id; 49 | $atom['attributes']['data']['max'] = $atom['max']; 50 | $atom['attributes']['data']['min'] = $atom['min']; 51 | } 52 | 53 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 54 | 55 |
> 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | '; 82 | } 83 | 84 | if( $halfStars ) { 85 | echo ''; 86 | } 87 | 88 | for( $i = 1; $i <= $emptyStars; $i++ ) { 89 | echo ''; 90 | } 91 | 92 | ?> 93 | 94 | 95 |
-------------------------------------------------------------------------------- /src/components/atoms/scroll.php: -------------------------------------------------------------------------------- 1 | '', 9 | 'top' => false // Makes it a scroll to top atom 10 | ] ); 11 | 12 | // Scrolls to top 13 | if( $atom['top'] ) { 14 | $atom['attributes']['class'] .= ' atom-scroll-top'; 15 | } 16 | 17 | if( $atom['top'] && ! $atom['icon'] ) { 18 | $atom['icon'] = 'fas fa-angle-up'; 19 | } 20 | 21 | // If we have a custom icon, we add an style 22 | if( $atom['icon'] ) { 23 | $atom['attributes']['class'] .= ' atom-scroll-hasicon'; 24 | } 25 | 26 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 27 | 28 | > 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/components/atoms/search.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'data' => [ 10 | 'appear' => 'bottom', // Determines from which direction posts apear, using scroll-reveal. Accepts bottom, top, left or right 11 | 'delay' => 500, // Delay to start searching after typing 12 | 'length' => 3, // The length of the search string to start querying with ajax 13 | 'none' => __('Bummer! No results found', WP_COMPONENTS_LANGUAGE), 14 | 'number' => 5, // The amount of posts to query with ajax 15 | 'types' => '' // Option post types to search for, seperated by , 16 | ] 17 | ], 18 | 'ajax' => false, // Enables the ajax live search action, 19 | 'all' => __('View all search results', WP_COMPONENTS_LANGUAGE), 20 | 'collapse' => false, // If collapsed, only shows a search icon that opens a form upon click 21 | 'form' => get_search_form(false), 22 | 'link' => esc_url( get_search_link('') ), 23 | 'types' => [], // Post types to include in search 24 | ] ); 25 | 26 | if( $atom['collapse'] ) { 27 | $atom['attributes']['class'] .= ' atom-search-collapse'; 28 | } 29 | 30 | if( $atom['ajax'] ) { 31 | $atom['attributes']['class'] .= ' atom-search-ajax'; 32 | } 33 | 34 | /** 35 | * Modify search for certain post types 36 | */ 37 | $types = isset($_GET['post_type']) && $_GET['post_type'] ? sanitize_text_field($_GET['post_type']) : false; 38 | if( $atom['types'] ) { 39 | $types = $types ? $types : implode(',', $atom['types']); 40 | } 41 | 42 | if( $types ) { 43 | $atom['attributes']['data']['types'] = $types; 44 | 45 | // A bit ugly, but adds a hidden input field for post types 46 | $atom['form'] = str_replace( 47 | '', 48 | '', 49 | $atom['form'] 50 | ); 51 | } 52 | 53 | // Generate attributes 54 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 55 | 56 |
> 57 | 58 |
59 | 60 | 61 |
62 | 63 | 64 |
65 | 66 | 67 | 68 | 69 | 70 |
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
-------------------------------------------------------------------------------- /src/components/atoms/share.php: -------------------------------------------------------------------------------- 1 | 'color_background', 'hoverItem' => 'hover_item']); 24 | 25 | // Atom properties - for this atom, wp_parse_args should be used 26 | $atom = wp_parse_args( $atom, [ 27 | 'color_background' => true, 28 | 'enabled' => ['facebook', 'twitter', 'linkedin', 'pinterest', 'reddit', 'stumbleupon', 'pocket', 'whatsapp'], 29 | 'fixed' => false, 30 | 'hover_item' => '', // Allows a hover.css class applied to each item. Requires hover to be set true in Boot(). 31 | 'networks' => [ 32 | 'facebook' => ['url' => 'http://www.facebook.com/sharer.php?u=' . $url, 'icon' => 'facebook'], 33 | 'twitter' => ['url' => 'http://twitter.com/share?url=' . $url . '&text=' . $title . '&via=' . $via, 'icon' => 'twitter'], 34 | 'linkedin' => [ 35 | 'url' => 'http://www.linkedin.com/shareArticle?mini=true&url=' . $url . '&title=' . $title . '&source=' . $source, 36 | 'icon' => 'linkedin' 37 | ], 38 | 'pinterest' => [ 39 | 'url' => 'http://pinterest.com/pin/create/button/?url=' . $url . '&description=' . $title . '&media=' . $image, 40 | 'icon' => 'pinterest' 41 | ], 42 | 'reddit' => ['url' => 'http://www.reddit.com/submit?url=' . $url . '&title=' . $title, 'icon' => 'reddit-alien'], 43 | 'stumbleupon' => ['url' => 'http://stumbleupon.com/submit?url=' . $url . '&title=' . $title, 'icon' => 'stumbleupon'], 44 | 'pocket' => ['url' => 'https://getpocket.com/edit.php?url=' . $url, 'icon' => 'get-pocket'], 45 | 'whatsapp' => ['url' => 'whatsapp://send?text=' . $title . ' ' . $url, 'icon' => 'whatsapp'] 46 | ], 47 | 'share' => __('Share:', WP_COMPONENTS_LANGUAGE) // Adds a label with share 48 | ] ); 49 | 50 | if( $atom['fixed'] ) { 51 | $atom['attributes']['class'] .= ' atom-share-fixed'; 52 | } 53 | 54 | if( $atom['color_background'] ) { 55 | $atom['attributes']['class'] .= ' components-background'; 56 | } 57 | 58 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 59 | 60 |
> 61 | 62 | 63 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 |
-------------------------------------------------------------------------------- /src/components/atoms/sidebar.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'itemscope' => 'itemscope', 10 | 'itemtype' => 'http://www.schema.org/WPSideBar' 11 | ], 12 | 'sidebars' => [] // Accepts an array with the sidebar names as values 13 | ] ); 14 | 15 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 16 | 17 | -------------------------------------------------------------------------------- /src/components/atoms/social.php: -------------------------------------------------------------------------------- 1 | 'color_background', 'hoverItem' => 'hover_item']); 8 | 9 | // Atom values 10 | $atom = wp_parse_args( $atom, [ 11 | 'color_background' => true, 12 | 'icons' => [ 13 | 'email' => 'far fa-envelope', 14 | 'telephone' => 'fas fa-phone', 15 | 'facebook' => 'fab fa-facebook', 16 | 'instagram' => 'fab fa-instagram', 17 | 'twitter' => 'fab fa-twitter', 18 | 'linkedin' => 'fab fa-linkedin', 19 | 'youtube' => 'fab fa-youtube', 20 | 'pinterest' => 'fab fa-pinterest', 21 | 'dribbble' => 'fab fa-dribbble', 22 | 'github' => 'fab fa-github', 23 | 'behance' => 'fab fa-behance', 24 | 'reddit' => 'fab fa-reddit-alien', 25 | 'stumbleupon' => 'fab fa-stumbleupon', 26 | 'whatsapp' => 'fab fa-whatsapp' 27 | ], 28 | 'hover_item' => '', // Allows a hover.css class applied to each item. Requires hover to be set true in Boot(). 29 | 'urls' => [], // Array of networks, consisting of network => url. 30 | 'titles' => [] 31 | ] ); 32 | 33 | if( $atom['color_background'] ) { 34 | $atom['attributes']['class'] .= ' components-background'; 35 | } 36 | 37 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 38 | 39 |
> 40 | 41 | $url ) { ?> 42 | 43 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
-------------------------------------------------------------------------------- /src/components/atoms/string.php: -------------------------------------------------------------------------------- 1 | '' 7 | ] ); 8 | 9 | if( $atom['string'] ) { 10 | echo $atom['string']; 11 | } -------------------------------------------------------------------------------- /src/components/atoms/tabs.php: -------------------------------------------------------------------------------- 1 | 'hover_item']); 8 | 9 | // Atom values 10 | $atom = wp_parse_args( $atom, [ 11 | 'hover_item' => '', // Allows a hover.css class applied to each item. Requires hover to be set true in Boot(). 12 | 'position' => 'top', 13 | 'tabs' => [] // Accepts an array with tab ids as keys, with an array with content, icon, link or title 14 | ] ); 15 | 16 | // Return if we do not have tabs 17 | if( ! $atom['tabs'] ) { 18 | return; 19 | } 20 | 21 | // Our tabs position 22 | $atom['attributes']['class'] .= ' atom-tabs-' . $atom['position']; 23 | 24 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 25 | 26 |
> 27 | 54 |
55 | $tab ) { 58 | $active = $count === 0 ? ' active' : ''; 59 | $count++; 60 | ?> 61 |
62 | 67 |
68 | 71 |
72 |
-------------------------------------------------------------------------------- /src/components/atoms/termlist.php: -------------------------------------------------------------------------------- 1 | get_the_ID(), 9 | 'schema' => true, // Whether to incorporate schema.org microdata or not 10 | 'taxonomies' => [] // Accepts the following format: 'category' => ['after' => '', 'before' => '','icon' => 'folder', 'schema' => 'genre', 'seperator' => ', '] 11 | ] ); 12 | 13 | // Show our default taxonomies if the standard array is empty 14 | if( empty($atom['taxonomies']) ) { 15 | 16 | if( ! $atom['id'] ) { 17 | global $post; 18 | $atom['id'] = isset($post) ? $post->ID : 0; 19 | } 20 | 21 | $taxonomies = get_post_taxonomies( $atom['id'] ); 22 | 23 | if( is_array($taxonomies) ) { 24 | 25 | foreach( $taxonomies as $taxonomy ) { 26 | 27 | // Skip polylang taxonomies 28 | if( in_array($taxonomy, ['language', 'post_translations']) ) { 29 | continue; 30 | } 31 | 32 | // Scheme 33 | $schema = ''; 34 | if( $taxonomy == 'category ' ) { 35 | $schema = 'genre'; 36 | } elseif( $taxonomy == 'post_tag' ) { 37 | $schema = 'keywords'; 38 | } 39 | 40 | // Icons 41 | $icon = $taxonomy == 'post_tag' ? 'fas fa-tag' : 'fas fa-dot-circle'; 42 | 43 | $atom['taxonomies'][$taxonomy] = ['after' => '', 'before' => '','icon' => $icon, 'schema' => $schema, 'seperator' => ', ']; 44 | 45 | } 46 | 47 | } 48 | 49 | } 50 | 51 | // Retrieve our lists 52 | $hasTerms = false; 53 | foreach( $atom['taxonomies'] as $taxonomy => $properties ) { 54 | $termlist = get_the_term_list( $atom['id'], $taxonomy, $properties['before'], $properties['seperator'], $properties['after'] ); 55 | if( $termlist && ! is_wp_error($termlist) ) { 56 | $atom['taxonomies'][$taxonomy]['list'] = $termlist; 57 | $hasTerms = true; 58 | } 59 | } 60 | 61 | // Don't output html if no terms are found 62 | if( ! $hasTerms ) { 63 | return; 64 | } 65 | 66 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 67 | 68 |
> 69 | $properties ) { ?> 70 | 71 |
> 72 | 73 | 74 | 75 | 78 |
79 | 80 | 81 |
-------------------------------------------------------------------------------- /src/components/atoms/terms.php: -------------------------------------------------------------------------------- 1 | 'hover_item', 'termStyle' => 'term_style']); 8 | 9 | // Atom values 10 | $atom = wp_parse_args( $atom, [ 11 | 'after' => '', // Content after each term 12 | 'args' => ['taxonomy' => 'post_tag'], // Arguments for retrieving the tags 13 | 'before' => '', // Content before each term 14 | 'hover_item' => '', // Allows a hover.css class applied to each item. Requires hover to be set true in Boot(). 15 | 'seperator' => '/', // Content that seperates terms 16 | 'terms' => [], // Accepts a custom array of terms 17 | 'term_style' => 'normal' // Accepts a custom style, such as 'button' 18 | ] ); 19 | 20 | if( ! $atom['terms'] ) { 21 | $atom['terms'] = get_terms( $atom['args'] ); 22 | } 23 | 24 | // Return if we do not have a video 25 | if( ! $atom['terms'] ) { 26 | return; 27 | } 28 | 29 | if( $atom['term_style'] ) { 30 | $atom['term_style'] = ' atom-term-style-' . $atom['term_style']; 31 | } 32 | 33 | // Get the queried object so we can see active terms 34 | $query = get_queried_object(); 35 | $active = isset($query->term_id) && $query->term_id ? $query->term_id : 0; 36 | 37 | // Save the taxonomy for possible filtering 38 | $atom['attributes']['data']['taxonomy'] = $atom['args']['taxonomy']; 39 | 40 | // So we can check our seprator 41 | $count = count($atom['terms']); 42 | $i = 0; 43 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 44 | 45 |
    > 46 | 47 | 48 | 49 | term_id ) { 55 | $term_class .= ' atom-term-active'; 56 | } 57 | 58 | if( $atom['hover_item'] ) { 59 | $term_class .= ' hvr-' . $atom['hover_item']; 60 | } 61 | ?> 62 | 63 |
  • 64 | 65 | 70 | 71 | 72 | name; ?> 73 | 74 | 75 | 80 | 81 |
  • 82 | 83 | ' . $atom['seperator'] . ''; 92 | 93 | } 94 | 95 | ?> 96 | 97 | 98 | 99 |
-------------------------------------------------------------------------------- /src/components/atoms/title.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'itemprop' => 'name', 10 | ], 11 | 'link' => '', // Custom link or 'post' to link to the post directly 12 | 'tag' => 'h1', 13 | 'title' => get_the_title(), 14 | 'schema' => true // If microdata is rendered or not. Also removes schematic attributes 15 | ] ); 16 | 17 | if( ! $atom['schema'] ) { 18 | unset($atom['attributes']['itemprop']); 19 | } 20 | 21 | // Custom link to a post 22 | $atom['link'] = $atom['link'] == 'post' ? esc_url( get_permalink() ) : esc_url( $atom['link'] ); 23 | 24 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 25 | 26 | < > 27 | 28 | itemprop="url" title=""> 29 | 30 | 31 | 32 | 33 | 34 | > -------------------------------------------------------------------------------- /src/components/atoms/type.php: -------------------------------------------------------------------------------- 1 | '', 9 | 'type' => get_post_type() 10 | ] ); 11 | 12 | // Return if we do not have a type 13 | if( ! $atom['type'] ) 14 | return; 15 | 16 | // Format our label 17 | if( ! $atom['name'] ) { 18 | $postObject = get_post_type_object( $atom['type'] ); 19 | $atom['name'] = $postObject->labels->singular_name; 20 | } 21 | 22 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 23 | 24 |
> 25 | 26 |
-------------------------------------------------------------------------------- /src/components/atoms/video.php: -------------------------------------------------------------------------------- 1 | 'video_height', 'videoWidth' => 'video_width']); 8 | 9 | // Atom values 10 | $atom = MakeitWorkPress\WP_Components\Build::multi_parse_args( $atom, [ 11 | 'attributes' => [ 12 | 'itemprop' => 'video' 13 | ], 14 | 'date' => '', // The schematic data for a video 15 | 'description' => '', // The schematic description for the video 16 | 'name' => '', // The schematic name for the video 17 | 'placer' => 'atom-video-placer', // Our container class for the video, uses the 56.25% padding rule to make the video responsive 18 | 'schema' => true, // If microdata is rendered or not. Also removes schematic attributes 19 | 'thumbnail' => '', // The schematic thumbnail url for the video 20 | 'video' => '', // Expects an embed code for a video object or a video html tag or a src 21 | 'video_height' => '' , // A custom height for the video 22 | 'video_width' => '' // A custom width for the video 23 | ] ); 24 | 25 | // Return if we do not have a video 26 | if( ! $atom['video'] ) { 27 | return; 28 | } 29 | 30 | // Format our video if it's just an url 31 | if( strpos($atom['video'], 'http') === 0 ) { 32 | $height = $atom['video_height'] ? ' height="' . intval($atom['video_height']) . '"' : ''; 33 | $width = $atom['video_width'] ? ' width="' . intval($atom['video_width']) . '"' : ''; 34 | $atom['video'] = do_shortcode('[video src="' . $atom['video'] . '"' . $height . $width . ']'); 35 | $atom['placer'] = 'atom-video-wp'; 36 | } 37 | 38 | if( ! $atom['schema'] ) { 39 | unset($atom['attributes']['itemprop']); 40 | } 41 | 42 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($atom['attributes']); ?> 43 | 44 |
> 45 |
itemscope="itemscope" itemtype="http://schema.org/VideoObject"> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
62 |
-------------------------------------------------------------------------------- /src/components/molecules/footer.php: -------------------------------------------------------------------------------- 1 | 'grid_gap']); 8 | 9 | // Atom values 10 | $molecule = MakeitWorkPress\WP_Components\Build::multi_parse_args( $molecule, [ 11 | 'attributes' => [ 12 | 'itemscope' => 'itemscope', 13 | 'itemtype' => 'http://schema.org/WPFooter' 14 | ], 15 | 'atoms' => [], // Adds an array of elements to the footer socket 16 | 'container' => true, // Wrap this component in a container 17 | 'grid_gap' => 'default', 18 | 'sidebars' => [], // Accepts an array with the sidebar name as key and the grid for the value 19 | 'video' => '' // Expects the url for a video for display a video background 20 | ] ); 21 | 22 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($molecule['attributes']); ?> 23 | 24 |
> 25 | 26 | 27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 | 35 | 62 | 63 | 64 | 65 | 86 | 87 | 88 | 89 | 90 |
-------------------------------------------------------------------------------- /src/components/molecules/header.php: -------------------------------------------------------------------------------- 1 | 'socket_atoms', 'topAtoms' => 'top_atoms']); 8 | 9 | // Molecule values 10 | $molecule = MakeitWorkPress\WP_Components\Build::multi_parse_args( $molecule, [ 11 | 'atoms' => [], // Accepts a multidimensional array with the each of the atoms 12 | 'attributes' => [ 13 | 'class' => 'molecule-header-top', 14 | 'ítemscope' => 'itemscope', 15 | 'itemtype' => 'http://schema.org/WPHeader' 16 | ], 17 | 'container' => true, // Wrap this component in a container 18 | 'fixed' => true, // If we have a fixed header 19 | 'headroom' => false, // If we apply a headroom effect to the header 20 | 'shrink' => false, // Shrink the header when scrolling 21 | 'socket_atoms' => [], // An extra bottom part in the header 22 | 'transparent' => false, // If the header is transparent 23 | 'top_atoms' => [], // An extra top part in the header 24 | 'video' => '' // Expects the url for a video for display a video background 25 | ] ); 26 | 27 | if( $molecule['fixed'] ) { 28 | $molecule['attributes']['class'] .= ' molecule-header-fixed'; 29 | } 30 | 31 | if( $molecule['headroom'] ) { 32 | $molecule['attributes']['class'] .= ' molecule-header-headroom'; 33 | } 34 | 35 | if( $molecule['shrink'] ) { 36 | $molecule['attributes']['class'] .= ' molecule-header-shrink'; 37 | } 38 | 39 | if( $molecule['transparent'] ) { 40 | $molecule['attributes']['class'] .= ' molecule-header-transparent'; 41 | } 42 | 43 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($molecule['attributes']); ?> 44 | 45 |
> 46 | 47 | 48 | 49 | 50 |
51 | 52 |
53 | 54 | 55 | ['class' => 'components-background-video', 'itemprop' => ''], 61 | 'schema' => false, 62 | 'src' => esc_url($molecule['video']) 63 | ] 64 | ); 65 | } 66 | ?> 67 | 68 | 69 |
70 | 71 | 72 |
73 | 74 | 75 | 84 | 85 | 86 |
87 | 88 | 89 |
90 | 91 | 92 | 93 | 94 |
95 | 96 | 97 |
98 | 99 | 100 | 109 | 110 | 111 |
112 | 113 | 114 |
115 | 116 | 117 | 118 | 119 |
120 | 121 | 122 |
123 | 124 | 125 | 134 | 135 | 136 |
137 | 138 | 139 |
140 | 141 | 142 | 143 | 144 |
-------------------------------------------------------------------------------- /src/components/molecules/section.php: -------------------------------------------------------------------------------- 1 | 'grid_gap']); 8 | 9 | // Arguments 10 | $molecule = MakeitWorkPress\WP_Components\Build::multi_parse_args( $molecule, [ 11 | 'atoms' => [], // Can render atoms if necessary 12 | 'columns' => [], // Columns to display with their corresponding width and containing atoms or molecules. Use ['column' => 'half', 'atoms' => [['atom' => 'atom']]] 13 | 'container' => true, // Wrap this component in a container 14 | 'custom_action' => '', // Adds a custom add_action hook next to the default section hooks. This value is sanitized. Also ensures backwards compatibility 15 | 'grid' => false, // Whether to display a grid 16 | 'grid_gap' => 'default', // The gridgap, if a grid is enabled 17 | 'molecules' => [], // Can render molecules if necessary 18 | 'tag' => 'section', // A tag for the section. Supports section, header, footer, main and div 19 | 'scroll' => false, // Renders a scroll down button if set to true. 20 | 'video' => '' // Expects the url for a video for display a video background 21 | ] ); 22 | 23 | // Prevents the use of unsupported tags 24 | if( ! in_array($molecule['tag'], ['div', 'footer', 'header', 'main', 'section']) ) { 25 | $molecule['tag'] = 'div'; 26 | } 27 | 28 | // Adds wrapper classes if we don't have a container 29 | if( ! $molecule['container'] && $molecule['grid'] ) { 30 | $molecule['attributes']['class'] .= ' components-grid-wrapper components-grid-' . $molecule['grid_gap']; 31 | } 32 | 33 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($molecule['attributes']); ?> 34 | 35 | < > 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 | 46 |
47 | 48 | 49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 | 77 |
78 | 79 | 80 | 81 |
82 | 83 | 84 | 97 | 98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
110 | 111 | 112 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | > -------------------------------------------------------------------------------- /src/components/molecules/slider.php: -------------------------------------------------------------------------------- 1 | 'thumbnail_size']); 8 | 9 | // Molecule values 10 | $molecule = MakeitWorkPress\WP_Components\Build::multi_parse_args( $molecule, [ 11 | 'attributes' => [ 12 | 'data' => [ 13 | 'id' => substr( str_shuffle(str_repeat("abcdefghijklmnopqrstuvwxyz", 5)), 0, 8 ) // Used to link the slider to it's variables 14 | ] 15 | ], 16 | 'options' => [ 17 | 'arrowKeys' => true, 18 | 'autoHeight' => true, 19 | 'controlsText' => ['', ''], 20 | 'navPosition' => 'bottom', 21 | 'mode' => 'carousel', // Type of animation 22 | 'mouseDrag' => true, 23 | 'speed' => 500, // Speed of animation 24 | ], 25 | 'schema' => true, 26 | 'scroll' => false, // Adds a scrolldown button 27 | 'slides' => [], // Supports a array with video, image and atoms as keys and the attributes key with common html attributes and common supported properties 28 | 'thumbnail_size' => '' // The default size for thumbnails. If set, this will also enable thumbnails. The images should be attachment ids and slides should have an image. 29 | 30 | ] ); 31 | 32 | // Set our container id so each script is initialized properly 33 | $molecule['options']['container'] = '#' . $molecule['attributes']['data']['id'] . 'Container'; 34 | 35 | // Set our additional slider options 36 | if( $molecule['options'] ) { 37 | 38 | // Set our control navigation option 39 | if( $molecule['thumbnail_size'] ) { 40 | $molecule['options']['navAsThumbnails'] = true; 41 | $molecule['options']['navContainer'] = '#' . $molecule['attributes']['data']['id'] . 'NavContainer'; 42 | } 43 | 44 | // Add our scripts variables 45 | add_action( 'wp_footer', function() use($molecule) { 46 | echo ''; 47 | } ); 48 | 49 | } 50 | 51 | // Enqueue our slider script 52 | if( ! wp_script_is('tinyslider') && apply_filters('components_slider_script', true) ) { 53 | wp_enqueue_script('tinyslider'); 54 | } 55 | 56 | $attributes = MakeitWorkPress\WP_Components\Build::attributes($molecule['attributes']); ?> 57 | 58 |
> 59 | 60 | 61 | 62 |
    63 | 64 | '', 74 | 'itemscope' => $molecule['schema'] ? 'itemscope' : false, 75 | 'itemtype' => $molecule['schema'] ? 'http://www.schema.org/CreativeWork' : false 76 | ]); 77 | 78 | // Always add the slide-wrapper class 79 | $slide['attributes']['class'] .= ' molecule-slide-wrapper'; 80 | 81 | // Determine the attributes and default properties 82 | $slideProperties = MakeitWorkPress\WP_Components\Build::set_default_properties('slide', $slide); 83 | $slideAttributes = MakeitWorkPress\WP_Components\Build::attributes($slideProperties['attributes']); ?> 84 | 85 |
  • 86 | 87 |
    > 88 | 89 | 95 | 96 |
    97 | 98 | 105 | 106 |
    107 | 108 | 109 | 123 | 124 |
    125 | 126 |
  • 127 | 128 | 129 | 130 |
131 | 132 | 140 | 141 | 145 |
    146 | 147 | 148 |
  • 149 | 150 | 151 |
152 | 153 | 154 | 155 | 156 |
-------------------------------------------------------------------------------- /src/includes/functions.php: -------------------------------------------------------------------------------- 1 |