diff --git a/app/assets/stylesheets/intro.css.scss b/app/assets/stylesheets/intro.css.scss index 855421e2f..606b98980 100644 --- a/app/assets/stylesheets/intro.css.scss +++ b/app/assets/stylesheets/intro.css.scss @@ -87,194 +87,132 @@ body { height: 100%; } -div.header { - overflow-x: hidden; -} - -.activities { - float: right; -} - -.vert-text { - display: table-cell; - vertical-align: middle; - text-align: center; - padding: 20px; -} - -@media (min-width: 768px) { - .vert-text { - padding: 200px; +.navbar { + .nav-item .nav-link { + color: #000000; + + &.active { + color: #bb8400 !important; + font-weight: bold; + } } -} - -#sidebar-wrapper { - position: fixed; - right: 0; - z-index: 1000; - overflow-y: auto; - margin-right: -250px; - width: 250px; - height: 100%; - background: #000; - -webkit-transition: all 0.4s ease 0s; - -moz-transition: all 0.4s ease 0s; - -ms-transition: all 0.4s ease 0s; - -o-transition: all 0.4s ease 0s; - transition: all 0.4s ease 0s; -} - -.sidebar-nav { - position: absolute; - top: 0; - margin: 0; - padding: 0; - width: 250px; - list-style: none; -} - -.sidebar-nav li { - text-indent: 20px; - line-height: 40px; -} - -.sidebar-nav li a { - display: block; - color: #999999; - text-decoration: none; -} - -.sidebar-nav li a:hover { - background: rgb(255, 255, 255); /* Fallback color */ - background: rgba(255, 255, 255, 0.2); - color: #fff; - text-decoration: none; -} - -.sidebar-nav li a:active, -.sidebar-nav li a:focus { - text-decoration: none; -} - -.sidebar-nav > .sidebar-brand { - height: 55px; - font-size: 18px; - line-height: 55px; -} - -.sidebar-nav > .sidebar-brand a { - color: #999999; -} - -.sidebar-nav > .sidebar-brand a:hover { - background: none; - color: #fff; -} - -#menu-toggle { - position: fixed; - top: 0; - right: 0; - z-index: 1; -} -#sidebar-wrapper.active { - right: 250px; - width: 250px; - -webkit-transition: all 0.4s ease 0s; - -moz-transition: all 0.4s ease 0s; - -ms-transition: all 0.4s ease 0s; - -o-transition: all 0.4s ease 0s; - transition: all 0.4s ease 0s; -} + #intro-nav { + justify-content: space-between; + } -.toggle { - margin: 5px 5px 0 0; + .language-select { + float: right; + } } .header { - display: table; + display: flex; width: 100%; height: 100%; - position: relative; - background: url(image_path('bg.jpg')) no-repeat center center fixed; - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; - overflow-x: hidden; -} -@media (max-width: 768px) { - .header { - background: url(image_path('bg.jpg')) no-repeat center center scroll; + & { + &-bg { + position: fixed; + top: 0; + left: 0; + z-index: -1; + width: 100%; + height: 100%; + background: image-url("bg.jpg") no-repeat center center; + background-size: cover; + } + + &-message { + display: flex; + align-items: center; + max-width: 2000px; + + &-container { + padding: 20px; + + h1 { + color: #fff; + text-shadow: #000 0 3px 3px; + } + } + } } } -.about, -.enroll { +.about { background-color: #ffffff; } .services { background: #bb8400; color: #ffffff; -} -.services .service-item { - margin-bottom: 15px; -} - -.services i.service-icon { - display: inline-block; - width: 140px; - height: 140px; - vertical-align: middle; - text-align: center; - font-size: 56px; - line-height: 136px; -} - -.vert-text { - text-align: left; -} + .container-fluid { + max-width: 2000px; + } -.header { - background: transparent; + .service-item { + margin-bottom: 15px; + + i.service-icon { + display: inline-block; + width: 140px; + height: 140px; + vertical-align: middle; + text-align: center; + font-size: 56px; + line-height: 136px; + } + } } -.header h1 { - color: #fff; - text-shadow: #000 0 3px 3px; -} +.enroll { + background-color: #ffffff; -.header-bg { - position: fixed; - top: 0; - left: 0; - z-index: -1; - width: 100%; - height: 100%; - background: image-url("bg.jpg") no-repeat center center; - background-size: cover; + .form-header { + display: flex; + align-items: center; + gap: 15px; + + .form-header { + &-spacer { + flex: 1; + height: 1px; + background-color: #ced4da; + } + + &-icon { + display: flex; + font-size: 14px; + background: #bb8400; + width: 30px; + height: 30px; + border-radius: 50%; + align-items: center; + justify-content: center; + color: #ffffff; + } + } + } } footer { color: #fff; background-color: #444; padding: 10px 0 10px 0; -} -footer div { - align-items: center; -} + div { + align-items: center; + } -footer a { - color: #fff; - padding: 0 5px 0 5px; -} + a { + color: #fff; + padding: 0 5px 0 5px; -footer a:hover { - color: #777; - text-decoration: none; -} + &:hover { + color: #777; + text-decoration: none; + } + } +} \ No newline at end of file diff --git a/app/javascript/src/intro.js b/app/javascript/src/intro.js index ad561d7e1..d736d7484 100644 --- a/app/javascript/src/intro.js +++ b/app/javascript/src/intro.js @@ -1,190 +1,215 @@ import $ from "jquery"; import jQuery from "jquery"; import I18n from "./translations.js"; -import {setup_intl_tel_input} from "./intl_tel_number"; +import { setup_intl_tel_input } from "./intl_tel_number"; $(document).on("ready page:load turbolinks:load", function () { - let disabledStudyOptions = []; - const studyBlockers = { - 1: 3, - 3: 1, - }; - - $("#menu-close").on("click", function (e) { - e.preventDefault(); - $("#sidebar-wrapper").toggleClass("active"); - }); - - $(".alert .close").on("click", function () { - $(this).closest(".alert").remove(); - }); - - $("a[href*='#']").on("click", function () { - if ( - location.pathname.replace(/^\//, "") === - this.pathname.replace(/^\//, "") || - location.hostname === this.hostname - ) { - let target = $(this.hash); - target = target.length ? target : $(`[name=${this.hash.slice(1)}]`); - if (target.length) { - $("html,body").animate( - { - scrollTop: target.offset().top, - }, - 1000, - ); - return false; - } - } - }); - - jQuery.validator.addMethod( - "phone", - function (value) { - return value && (value.trim().empty() || /^\+?(?:[0-9] ?){6,14}[0-9]$/.test(value.trim())); - }, - "Invalid phone number", - ); + setup_popup_close(); + setup_smooth_scroll(); + setup_form_validation(); + setup_form_payment_method_watcher(); + setup_form_studies_watcher(); + setup_background_parallax(); + + setup_intl_tel_input(); +}); - $("form").validate({ - rules: { - "member[first_name]": "required", - "member[last_name]": "required", - "member[birth_date]": "required", - "member[address]": "required", - "member[house_number]": { - required: true, - digits: true, - }, - "member[postal_code]": "required", - "member[city]": "required", - "member[phone_number]": { - required: true, - phone: true, - }, - "member[emergency_phone_number]": { - required: { - depends: function () { - // get max birth date to be 18 years old, ignoring time - const maxDate = new Date(); - maxDate.setUTCHours(0, 0, 0, 0); - maxDate.setFullYear(maxDate.getFullYear() - 18); - - const birthDate = new Date($("#member_birth_date").val()); - - // field is valid if member is 18 years or if it's not empty - return birthDate < maxDate; - } - }, - phone: true, - }, - "member[email]": { - required: true, - email: true, - }, - "member[student_id]": "required", - bank: { - required: { - depends: function () { - return $("select#method").val() === "IDEAL"; - }, - }, - }, +function setup_popup_close() { + $("#notice > .popup").on("click", function () { + $("#notice").fadeOut(); + }); +} + +function setup_smooth_scroll() { + $("a[href*='#']").on("click", function () { + if ( + location.pathname.replace(/^\//, "") === + this.pathname.replace(/^\//, "") || + location.hostname === this.hostname + ) { + let target = $(this.hash); + target = target.length ? target : $(`[name=${this.hash.slice(1)}]`); + if (target.length) { + const navbarOffset = $(".navbar").outerHeight(); + + $("html,body").animate( + { + scrollTop: Math.ceil( + Math.max(target.offset().top - navbarOffset, 0), + ), + }, + 1000, + ); + return false; + } + } + }); +} + +function setup_background_parallax() { + let jumboHeight = $(window).height(); + const headerBackground = $(".header-bg"); + + $(window).on("resize", function () { + jumboHeight = $(window).height(); + }); + + $(window).on("scroll resize", function () { + const scrolled = $(window).scrollTop(); + headerBackground.css("height", jumboHeight - scrolled + "px"); + }); +} + +function setup_form_validation() { + jQuery.validator.addMethod( + "phone", + function (value) { + return ( + value && + (value.trim().empty() || + /^\+?(?:[0-9] ?){6,14}[0-9]$/.test(value.trim())) + ); + }, + "Invalid phone number", + ); + + $("form").validate({ + rules: { + "member[first_name]": "required", + "member[last_name]": "required", + "member[birth_date]": "required", + "member[address]": "required", + "member[house_number]": { + required: true, + digits: true, + }, + "member[postal_code]": "required", + "member[city]": "required", + "member[phone_number]": { + required: true, + phone: true, + }, + "member[emergency_phone_number]": { + required: { + depends: function () { + // get max birth date to be 18 years old, ignoring time + const maxDate = new Date(); + maxDate.setUTCHours(0, 0, 0, 0); + maxDate.setFullYear(maxDate.getFullYear() - 18); + + const birthDate = new Date($("#member_birth_date").val()); + + // field is valid if member is 18 years or if it's not empty + return birthDate < maxDate; + }, }, - errorClass: "is-invalid", - errorElement: "div", - errorPlacement: function (error, element) { - error.addClass("invalid-feedback").appendTo(element.closest(".field")); + phone: true, + }, + "member[email]": { + required: true, + email: true, + }, + "member[student_id]": "required", + bank: { + required: { + depends: function () { + return $("select#method").val() === "IDEAL"; + }, }, - messages: { - "member[first_name]": I18n.t("form.required_field"), - "member[last_name]": I18n.t("form.required_field"), - "member[birth_date]": I18n.t("form.required_field"), - "member[address]": I18n.t("form.required_field"), - "member[house_number]": { - required: I18n.t("form.required_field"), - digits: I18n.t("form.digits_field"), - }, - "member[postal_code]": I18n.t("form.required_field"), - "member[city]": I18n.t("form.required_field"), - "member[phone_number]": { - required: I18n.t("form.required_field"), - phone: I18n.t("form.invalid_phone_number"), - }, - "member[emergency_phone_number]": { - required: I18n.t("form.required_field"), - phone: I18n.t("form.invalid_phone_number"), - }, - "member[email]": { - required: I18n.t("form.required_field"), - email: I18n.t("form.invalid_email"), - }, - "member[student_id]": { - required: I18n.t("form.required_field"), - }, - bank: { - required: I18n.t("form.required_field"), - }, - } - }); - - $("select#method").on("change", function () { - $("select#bank").prop('disabled', $(this).val() === "Cash/PIN") - }); - - $(".studies select").on("change", function () { - const selected = $(this).find("option:selected"); - - if (selected.data("masters")) { - $(".activities").hide(); - } else { - $(".activities").show(); - } - - if (!$(this).closest('.form-group').is(':first-of-type')) { - return; - } - - if (disabledStudyOptions.length > 0) { - $.each(disabledStudyOptions, function (_, v) { - v.prop("disabled", false); - }); - disabledStudyOptions = []; - } - - disabledStudyOptions.push($(this) - .closest(".studies") - .children() - .last() - .find(`option[value=${selected.val()}]`)); - - const blockedId = studyBlockers[selected.val()]; - if (typeof blockedId !== "undefined") { - disabledStudyOptions.push($(this) - .closest(".studies") - .children() - .last() - .find(`option[value=${blockedId}]`)); - } - - $.each(disabledStudyOptions, function (_, v) { - v.prop("disabled", true); - }); - }); - - $("#notice > .popup").on('click', function () { - $("#notice").fadeOut(); - }) - - const jumboHeight = $(".header").outerHeight(); + }, + }, + errorClass: "is-invalid", + errorElement: "div", + errorPlacement: function (error, element) { + error.addClass("invalid-feedback").appendTo(element.closest(".field")); + }, + messages: { + "member[first_name]": I18n.t("form.required_field"), + "member[last_name]": I18n.t("form.required_field"), + "member[birth_date]": I18n.t("form.required_field"), + "member[address]": I18n.t("form.required_field"), + "member[house_number]": { + required: I18n.t("form.required_field"), + digits: I18n.t("form.digits_field"), + }, + "member[postal_code]": I18n.t("form.required_field"), + "member[city]": I18n.t("form.required_field"), + "member[phone_number]": { + required: I18n.t("form.required_field"), + phone: I18n.t("form.invalid_phone_number"), + }, + "member[emergency_phone_number]": { + required: I18n.t("form.required_field"), + phone: I18n.t("form.invalid_phone_number"), + }, + "member[email]": { + required: I18n.t("form.required_field"), + email: I18n.t("form.invalid_email"), + }, + "member[student_id]": { + required: I18n.t("form.required_field"), + }, + bank: { + required: I18n.t("form.required_field"), + }, + }, + }); +} + +function setup_form_payment_method_watcher() { + $("select#method").on("change", function () { + $("select#bank").prop("disabled", $(this).val() === "Cash/PIN"); + }); +} + +function setup_form_studies_watcher() { + let disabledStudyOptions = []; + const studyBlockers = { + 1: 3, + 3: 1, + }; + + $(".studies select").on("change", function () { + const selected = $(this).find("option:selected"); + + if (selected.data("masters")) { + $(".activities").hide(); + } else { + $(".activities").show(); + } + + if (!$(this).closest(".form-group").is(":first-of-type")) { + return; + } + + if (disabledStudyOptions.length > 0) { + $.each(disabledStudyOptions, function (_, v) { + v.prop("disabled", false); + }); + disabledStudyOptions = []; + } + + disabledStudyOptions.push( + $(this) + .closest(".studies") + .children() + .last() + .find(`option[value=${selected.val()}]`), + ); - $(window).on("scroll", function (e) { - const header = $(".header-bg"); - const scrolled = $(window).scrollTop(); - header.css("height", jumboHeight - scrolled + "px"); - header.css("height", jumboHeight - scrolled + "px"); + const blockedId = studyBlockers[selected.val()]; + if (typeof blockedId !== "undefined") { + disabledStudyOptions.push( + $(this) + .closest(".studies") + .children() + .last() + .find(`option[value=${blockedId}]`), + ); + } + + $.each(disabledStudyOptions, function (_, v) { + v.prop("disabled", true); }); - - setup_intl_tel_input(); -}); + }); +} diff --git a/app/views/public/home/index.html.haml b/app/views/public/home/index.html.haml index f190cb42f..91de8d32f 100644 --- a/app/views/public/home/index.html.haml +++ b/app/views/public/home/index.html.haml @@ -10,7 +10,7 @@ = javascript_pack_tag 'intro', 'data-turbolinks-track': 'reload' = csrf_meta_tags - %body{ :data => { :spy => 'scroll', :target => '.navbar' } } + %body{ :data => { :spy => 'scroll', :target => '.navbar', :offset => '56' } } - if flash[:notice] #notice.container{ :style => 'position: fixed; z-index: 99; width: 100%; top: 70px;' } .bd-callout.bd-callout-success.popup{ :style => 'width: 500px; background: #ffffff; cursor: pointer;' } @@ -18,13 +18,6 @@ .navbar.navbar-expand-sm.navbar-light.bg-light.fixed-top.shadow-sm .container - .dropdown - %button.btn.dropdown-toggle{ :data => { :toggle => 'dropdown' } } - %i.fa.fa-globe - .dropdown-menu - = link_to "Nederlands", {:l => 'nl'}, :class => 'dropdown-item' - = link_to "English", {:l => 'en'}, :class => 'dropdown-item' - %button.navbar-toggler{:type => 'button', :data => {:toggle => 'collapse', :target => '#intro-nav'}} %span.navbar-toggler-icon #intro-nav.collapse.navbar-collapse @@ -37,12 +30,19 @@ = link_to I18n.t(:activities, scope: 'headers'), '#services', { :class => 'nav-link' } %li.nav-item = link_to I18n.t(:subscribe, scope: 'headers'), '#enroll', { :class => 'nav-link' } + .dropdown.language-select + %button.btn.dropdown-toggle{ :data => { :toggle => 'dropdown' } } + %i.fa.fa-globe + .dropdown-menu.dropdown-menu-right + = link_to 'Nederlands', {:l => 'nl'}, :class => 'dropdown-item' + = link_to 'English', {:l => 'en'}, :class => 'dropdown-item' - .header-bg #top.header - .vert-text - %h1.display-2= I18n.t(:title) - = link_to I18n.t(:subscribe, scope: 'headers'), '#enroll', { :class => 'btn btn-warning btn-lg' } + .header-bg + .header-message.container-fluid + .header-message-container + %h1.display-2= I18n.t(:title) + = link_to I18n.t(:subscribe, scope: 'headers'), '#enroll', { :class => 'btn btn-warning btn-lg' } #about.about.py-5 .container @@ -98,9 +98,11 @@ - if flash[:error] %li= flash[:error] - %h4 - %i.fa.fa-user - = I18n.t(:general, scope: 'form') + %h4.form-header + .form-header-label= I18n.t(:general, scope: 'form') + .form-header-spacer + .form-header-icon + %i.fa.fa-user .form-group = f.hidden_field :join_date, :value => Time.new @@ -155,9 +157,11 @@ = f.email_field :email, :value => @member.email, :class => 'form-control' %small.text-muted= I18n.t('email', scope: 'activerecord.annotations.member') - %h4 - %i.fa.fa-envelope - = I18n.t(:mailinglists, scope: 'activerecord.annotations.member') + %h4.form-header + .form-header-label= I18n.t(:mailinglists, scope: 'activerecord.annotations.member') + .form-header-spacer + .form-header-icon + %i.fa.fa-envelope .form-group .row @@ -190,9 +194,12 @@ .row .col-lg-6 - %h4 - %i.fa.fa-graduation-cap - = I18n.t(:study, scope: 'form') + %h4.form-header + .form-header-label= I18n.t(:study, scope: 'form') + .form-header-spacer + .form-header-icon + %i.fa.fa-graduation-cap + %small.text-muted= I18n.t(:study, scope: 'activerecord.annotations.member') .form-group.field @@ -208,11 +215,13 @@ .form-group .row .col-lg-12.field - = fs.select :study_id, options_for_select(Study.where( :active => true ).map{|s| [ I18n.t(s.code.downcase, scope: 'activerecord.attributes.study.names'), s.id, { 'data-masters' => s.masters }]}, education.study_id), { :include_blank => "--" }, { :class => "form-control" } + = fs.select :study_id, options_for_select(Study.where( :active => true ).map{|s| [ I18n.t(s.code.downcase, scope: 'activerecord.attributes.study.names'), s.id, { 'data-masters' => s.masters }]}, education.study_id), { :include_blank => '--' }, { :class => 'form-control' } .col-lg-6.activities - %h4 - %i.fa.fa-ticket-alt - = I18n.t(:payment, scope: 'form') + %h4.form-header + .form-header-label= I18n.t(:payment, scope: 'form') + .form-header-spacer + .form-header-icon + %i.fa.fa-ticket-alt .row .col-lg-6 .form-group @@ -258,9 +267,9 @@ .col-lg-4.text-center - if I18n.locale == :nl - = link_to I18n.t(:privacy, scope: 'footer'), '//public.svsticky.nl/privacystatement.pdf', :target => '_blank' + = link_to I18n.t(:privacy, scope: 'footer'), '//public.svsticky.nl/privacystatement.pdf', { :target => '_blank' } - else - = link_to I18n.t(:privacy, scope: 'footer'), '//public.svsticky.nl/privacystatement_english.pdf', :target => '_blank' + = link_to I18n.t(:privacy, scope: 'footer'), '//public.svsticky.nl/privacystatement_english.pdf', { :target => '_blank' } - if @member.errors.any? || !flash[:error].nil? :javascript