diff --git a/src/js/ui/captcha.js b/src/js/ui/captcha.js new file mode 100644 index 0000000..ffc0378 --- /dev/null +++ b/src/js/ui/captcha.js @@ -0,0 +1,74 @@ +import Events from '../_events' + +const CaptchaUI = ((window) => { + const NAME = 'js-captcha' + + const init = () => { + console.log(`${NAME}: init`) + + const submitListener = (e) => { + console.log(`${NAME}: Validating Captcha ...`) + const field = e.currentTarget.querySelectorAll(`.${NAME}, .g-recaptcha`).forEach((el) => { + grecaptcha.execute(el.dataset.widgetid) + }) + } + + const attachCaptcha = () => { + console.log(`${NAME}: Rendering Captcha ...`) + + const fields = document.querySelectorAll(`.${NAME}, .g-recaptcha`) + const grecaptcha = window.grecaptcha + + fields.forEach((el, i) => { + if (el.dataset.widgetid || el.innerHTML !== '') { + // already initialized + return + } + + const form = el.closest(form) + const widgetid = grecaptcha.render(el, el.dataset) + el.dataset.widgetid = widgetid + + if(el.dataset.size === 'invisible' && !el.dataset.callback){ + grecaptcha.execute(widgetid) + form.addEventListener('submit', submitListener) + } + + el.classList.add(`${NAME}-active`) + el.dispatchEvent(new Event(`${NAME}-ready`)) + }) + } + + const loadScript = (callback) => { + if(typeof window.grecaptcha !== 'undefined'){ + callback() + } + + console.log(`${NAME}: Loading Captcha API ...`) + + const script = document.createElement('script'); + script.id = 'captchaAPI'; + script.src = 'https://www.google.com/recaptcha/api.js?render=explicit&hl=' + document.querySelector('html').getAttribute('lang').substr(0,2) + script.async = true + script.onload = function() { + console.log(`${NAME}: Captcha API is loaded.`) + callback() + } + + document.body.append(script) + } + + if(document.querySelectorAll('.g-recaptcha').length){ + loadScript(attachCaptcha); + }else{ + console.log(`${NAME}: No Captcha fields.`) + } + + window.noCaptchaFieldRender = attachCaptcha + } + + window.addEventListener(`${Events.LODEDANDREADY}`, init) + window.addEventListener(`${Events.AJAX}`, init) +})(window) + +export default CaptchaUI diff --git a/src/js/ui/carousel.js b/src/js/ui/carousel.js index a0e2b04..8d0b45a 100644 --- a/src/js/ui/carousel.js +++ b/src/js/ui/carousel.js @@ -187,6 +187,7 @@ const CarouselUI = ((window) => { el.dataset.ui = el.ui el.classList.add(`${NAME}-active`) + el.dispatchEvent(new Event(`${NAME}-ready`)) }) } diff --git a/src/js/ui/dropdown.js b/src/js/ui/dropdown.js index fc2820f..9595984 100644 --- a/src/js/ui/dropdown.js +++ b/src/js/ui/dropdown.js @@ -22,22 +22,22 @@ const DropdownHoverUI = ((window) => { const Toggle = (el) => { HideAll() - if (el.querySelector('.dropdown-menu').classList.contains('show')) { - Hide(el) - } else { - Show(el) - } + el.querySelector('.dropdown-menu').classList.toggle('show') } - const Show = (el) => { + const Show = (e) => { + e.stopPropagation() + const el = e.currentTarget + el.classList.add(...ACTIVECLS) - el.closest('.dropdown').classList.add(...ACTIVECLS) el.querySelector('.dropdown-menu').classList.add('show') } - const Hide = (el) => { + const Hide = (e) => { + e.stopPropagation() + const el = e.currentTarget + el.classList.remove(...ACTIVECLS) - el.closest('.dropdown').classList.remove(...ACTIVECLS) el.querySelector('.dropdown-menu').classList.remove('show') } @@ -48,14 +48,8 @@ const DropdownHoverUI = ((window) => { const hoverableEls = document.querySelectorAll('[data-bs-toggle="hover"]') const attachHoverEvents = (el) => { - el.addEventListener('mouseover', (e) => { - e.stopPropagation() - Show(e.currentTarget) - }, false) - el.addEventListener('mouseleave', (e) => { - e.stopPropagation() - Hide(e.currentTarget) - }, false) + el.addEventListener('mouseover', Show, false) + el.addEventListener('mouseleave', Hide, false) el.classList.add(`${NAME}-active`) } diff --git a/src/scss/_mixings.scss b/src/scss/_mixings.scss index f2b4a86..616eaad 100755 --- a/src/scss/_mixings.scss +++ b/src/scss/_mixings.scss @@ -2,226 +2,246 @@ @import "~bootstrap/scss/mixins"; -@mixin hover-disabled() { - &:not(.disabled) { - &.active, - &:active, - &:hover, - &:focus { - @content; - } +/// Remove the unit of a length +/// @param {Number} $number - Number to remove unit from +/// @return {Number} - Unitless number +@function strip-unit($number) { + @if type-of($number) == 'number' and not unitless($number) { + @return $number / ($number * 0 + 1); } + + @return $number; +} + +@function rem($pxValue) { + @return #{strip-unit($pxValue) / strip-unit($html-font-size)}rem; +} + +/*.component { + font-size: rem(14px); // or rem(14) +}*/ + +@mixin hover-disabled() { + &:not(.disabled) { + &.active, + &:active, + &:hover, + &:focus { + @content; + } + } } @mixin pseudo($display: block, $pos: absolute, $content: "") { - content: $content; - display: $display; - position: $pos; + position: $pos; + display: $display; + content: $content; } @mixin responsive-ratio($x, $y, $pseudo: false) { - $padding: unquote(math.div($y, $x) * 100 + "%"); + $padding: unquote(math.div($y, $x) * 100 + "%"); - @if $pseudo { - &:before { - @include pseudo($pos: relative); - padding-top: $padding; - width: 100%; + @if $pseudo { + &:before { + width: 100%; + padding-top: $padding; + + @include pseudo($pos: relative); + } + } @else { + padding-top: $padding; } - } @else { - padding-top: $padding; - } } @mixin input-placeholder { - &.placeholder { - @content; - } + &.placeholder { + @content; + } - &:-moz-placeholder { - @content; - } + &:-moz-placeholder { + @content; + } - &::-moz-placeholder { - @content; - } + &::-moz-placeholder { + @content; + } - &:-ms-input-placeholder { - @content; - } + &:-ms-input-placeholder { + @content; + } - &::-webkit-input-placeholder { - @content; - } + &::-webkit-input-placeholder { + @content; + } } @mixin truncate($truncation-boundary) { - max-width: $truncation-boundary; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + overflow: hidden; + max-width: $truncation-boundary; + white-space: nowrap; + text-overflow: ellipsis; } @mixin fix-bold() { - display: inline-flex; - flex-direction: column; + display: inline-flex; + flex-direction: column; - &:before { - content: attr(data-text); - content: attr(data-text) / ""; - font-weight: bold; - height: 0; - overflow: hidden; - pointer-events: none; - user-select: none; - visibility: hidden; - } + &:before { + font-weight: bold; + visibility: hidden; + overflow: hidden; + height: 0; + content: attr(data-text); + content: attr(data-text) / ""; + user-select: none; + pointer-events: none; + } } @mixin dropdowns-dark() { - .navbar-dark { - .nav-link { - @include hover-focus { - background: $navbar-dark-hover-background; - } + .navbar-dark { + .nav-link { + @include hover-focus { + background: $navbar-dark-hover-background; + } + } + + .active > .nav-link, + .nav-link.active { + background: $navbar-dark-active-background; + } + + .nav-link.show, + .navbar-nav .show > .nav-link { + color: $navbar-dark-show-color; + background: $navbar-dark-show-background; + } } - .active > .nav-link, - .nav-link.active { - background: $navbar-dark-active-background; + .dropdown-menu.bg-dark { + border-color: $dark; + + .nav-link { + color: $navbar-dark-color; + + @include hover-focus { + color: $navbar-dark-hover-color; + } + + &.disabled { + cursor: default; + color: $navbar-dark-disabled-color; + } + } + + .show > .nav-link, + .active > .nav-link, + .nav-link.show, + .nav-link.active { + color: $navbar-dark-active-color; + } + + .dropdown-item { + @include hover-focus { + color: $navbar-dark-hover-color; + background: $navbar-dark-hover-background; + } + + &.active, + &:active { + background: $navbar-dark-active-background; + } + + .nav-link { + background: none; + } + } } - - .nav-link.show, - .navbar-nav .show > .nav-link { - background: $navbar-dark-show-background; - color: $navbar-dark-show-color; - } - } - - .dropdown-menu.bg-dark { - border-color: $dark; - - .nav-link { - color: $navbar-dark-color; - - @include hover-focus { - color: $navbar-dark-hover-color; - } - - &.disabled { - color: $navbar-dark-disabled-color; - cursor: default; - } - } - - .show > .nav-link, - .active > .nav-link, - .nav-link.show, - .nav-link.active { - color: $navbar-dark-active-color; - } - - .dropdown-item { - @include hover-focus { - background: $navbar-dark-hover-background; - color: $navbar-dark-hover-color; - } - - &.active, - &:active { - background: $navbar-dark-active-background; - } - - .nav-link { - background: none; - } - } - } } @mixin dropdown-hovers() { - .dropdown.show { - .dropdown { - &:hover, - &.active, - &:focus { - > .dropdown-menu { - display: block; + .dropdown.show { + .dropdown { + &:hover, + &.active, + &:focus { + > .dropdown-menu { + display: block; + } + } } - } - } - } - - @media only screen and (min-width: map-get($grid-breakpoints, "md")) { - .dropdown-hover ul li { - position: relative; } - .dropdown-hover ul li { - &:hover, - &.active, - &:focus { - > .dropdown-toggle::after { - transform: rotate(-90deg); + @media only screen and (min-width: map-get($grid-breakpoints, "md")) { + .dropdown-hover ul li { + position: relative; } - > ul { - display: block; + .dropdown-hover ul li { + &:hover, + &.active, + &:focus { + > .dropdown-toggle::after { + transform: rotate(-90deg); + } + + > ul { + display: block; + } + } } - } - } - .dropdown-hover ul ul { - display: none; - left: 0; - min-width: 250px; - position: absolute; - top: 100%; - } - - .dropdown-hover ul ul li { - position: relative; - } - - .dropdown-hover ul ul li { - &:hover, - &.active, - &:focus { - > ul { - display: block; + .dropdown-hover ul ul { + position: absolute; + top: 100%; + left: 0; + display: none; + min-width: 250px; } - } - } - .dropdown-hover ul ul ul { - display: none; - left: 100%; - min-width: 250px; - position: absolute; - top: 0; - } - - .dropdown-hover ul ul ul li { - position: relative; - } - - .dropdown-hover ul ul ul li { - &:hover, - &.active, - &:focus { - ul { - display: block; + .dropdown-hover ul ul li { + position: relative; } - } - } - .dropdown-hover ul ul ul ul { - display: none; - left: -100%; - min-width: 250px; - position: absolute; - top: 0; - z-index: 1; + .dropdown-hover ul ul li { + &:hover, + &.active, + &:focus { + > ul { + display: block; + } + } + } + + .dropdown-hover ul ul ul { + position: absolute; + top: 0; + left: 100%; + display: none; + min-width: 250px; + } + + .dropdown-hover ul ul ul li { + position: relative; + } + + .dropdown-hover ul ul ul li { + &:hover, + &.active, + &:focus { + ul { + display: block; + } + } + } + + .dropdown-hover ul ul ul ul { + position: absolute; + z-index: 1; + top: 0; + left: -100%; + display: none; + min-width: 250px; + } } - } } diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss index 3555331..b6b686e 100755 --- a/src/scss/_variables.scss +++ b/src/scss/_variables.scss @@ -27,108 +27,78 @@ $container-max-widths: ( xxxl: 1536px, xxxxl: 1836px, ) !default; - $font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; $font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; - $font-family-base: "Roboto", $font-family-sans-serif !default; - +$html-font-size: 14px!default; $spacer: 1rem !default; $headings-margin-bottom: $spacer !default; - $enable-rounded: false !default; $enable-shadows: true !default; - $enable-gradients: false !default; - $enable-transitions: true !default; $enable-reduced-motion: true !default; - $enable-caret: false !default; - $enable-grid-classes: true !default; $enable-button-pointers: true !default; $enable-rfs: true !default; - $enable-validation-icons: true !default; $enable-negative-margins: true !default; - $enable-deprecation-messages: true !default; - $enable-important-utilities: true !default; $breadcrumb-divider: quote("/") !default; // ui framework settings $body-gutter-x: $spacer !default; $body-gutter-y: $spacer !default; - $body-double-gutter-x: $body-gutter-x * 2 !default; $body-double-gutter-y: $body-gutter-y * 2 !default; - -$body-gutter-reduced-x: $body-gutter-x * 0.5 !default; -$body-gutter-reduced-y: $body-gutter-y * 0.5 !default; - -$body-gutter-reduced-d-x: $body-gutter-x * 0.25 !default; -$body-gutter-reduced-d-y: $body-gutter-y * 0.25 !default; - +$body-gutter-reduced-x: $body-gutter-x * .5 !default; +$body-gutter-reduced-y: $body-gutter-y * .5 !default; +$body-gutter-reduced-d-x: $body-gutter-x * .25 !default; +$body-gutter-reduced-d-y: $body-gutter-y * .25 !default; $form-spacer-x: $spacer !default; $form-spacer-y: $spacer !default; - $element-spacer-x: map.get($spacers, 3) !default; $element-spacer-y: map.get($spacers, 3) !default; - $element-reduced-spacer-x: map.get($spacers, 2) !default; $element-reduced-spacer-y: map.get($spacers, 2) !default; - $element-reduced-d-spacer-x: map.get($spacers, 1) !default; $element-reduced-d-spacer-y: map.get($spacers, 1) !default; - $body-bg: #fff !default; $body-color: #212529 !default; // site specific variables $extra-large-screen: 2000px !default; - $full-body-min-width: map-get($grid-breakpoints, "lg") !default; $typography-breakpoint: map-get($grid-breakpoints, "sm") - 1 !default; - $header-bg: var(--bs-dark) !default; $header-color: var(--bs-light) !default; $header-link: var(--bs-white) !default; - $main-nav-link-color: var(--bs-white) !default; $main-nav-link-bg: none !default; - $main-nav-toggler-size: 2rem !default; - $main-nav-link-hover-bg: none !default; $main-nav-link-hover-color: var(--bs-cyan) !default; - $main-nav-dropdown-bg: $header-bg !default; $main-nav-dropdown-color: $header-link !default; $main-nav-dropdown-hover-bg: var(--bs-black) !default; $main-nav-dropdown-hover-color: $main-nav-link-hover-color !default; - $sidebar-nav-link-hover-color: var(--bs-indigo) !default; - $footer-bg: $header-bg !default; $footer-color: $header-color !default; $footer-link: $header-link !default; - $footer-footer-bg: $main-nav-dropdown-hover-bg !default; - $sliderelement-carousel-slide-max-y: 70vh !default; $sliderelement-carousel-slide-bg: $header-bg !default; $sliderelement-carousel-slide-ratio-x: 16 !default; $sliderelement-carousel-slide-ratio-y: 9 !default; - $carousel-title-color: $white !default; $carousel-slide-min-height: 4rem !default; $carousel-text-shadow: 1px 1px $black !default; $carousel-controls-font-size: 3rem; $carousel-controls-zindex: 11 !default; $carousel-controls-shadow: 1px 1px $black !default; -$carousel-controls-hover-bg: transparentize($black, 0.4) !default; +$carousel-controls-hover-bg: transparentize($black, .4) !default; $carousel-slide-img-loading-max-height: 70vh !default; - -$breadcrumb-active-color: $sidebar-nav-link-hover-color; +$breadcrumb-active-color: $sidebar-nav-link-hover-color;