From d415f671862964f6529d8e5f79c5d926e069cb2a Mon Sep 17 00:00:00 2001 From: Nikolai B Date: Tue, 25 Jan 2022 21:21:31 +0000 Subject: [PATCH] Start implementing new UI in rails --- Gemfile | 1 + Gemfile.lock | 17 + app/assets/javascripts/application.js | 3 +- app/assets/javascripts/application_new_ui.js | 10 + app/assets/javascripts/constants.js.erb | 2 - app/assets/javascripts/new_ui.js | 1059 +++++++++++++++++ .../stylesheets/application_new_ui.scss | 2 + app/assets/stylesheets/new_ui.css | 811 +++++++++++++ app/controllers/new_ui/base_controller.rb | 7 + app/views/layouts/_header.html.erb | 62 + app/views/layouts/application.html.haml | 2 +- app/views/layouts/application_new_ui.html.erb | 32 + package-lock.json | 37 + package.json | 3 + 14 files changed, 2044 insertions(+), 4 deletions(-) create mode 100644 app/assets/javascripts/application_new_ui.js create mode 100644 app/assets/javascripts/new_ui.js create mode 100644 app/assets/stylesheets/application_new_ui.scss create mode 100644 app/assets/stylesheets/new_ui.css create mode 100644 app/controllers/new_ui/base_controller.rb create mode 100644 app/views/layouts/_header.html.erb create mode 100644 app/views/layouts/application_new_ui.html.erb diff --git a/Gemfile b/Gemfile index 304f62133..42fd87d3a 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,7 @@ end # gem 'ruby-debug19', require: 'ruby-debug' # Front-end gems +gem "bootstrap" gem "browserify-rails" gem "chartkick" gem "formtastic" diff --git a/Gemfile.lock b/Gemfile.lock index a90d63ae7..5c2c1173c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -76,6 +76,8 @@ GEM rake (>= 10.4, < 13.0) arel (9.0.0) ast (2.4.0) + autoprefixer-rails (10.4.2.0) + execjs (~> 2) bcrypt (3.1.13) better_errors (2.5.1) coderay (>= 1.0.0) @@ -83,6 +85,10 @@ GEM rack (>= 0.9.0) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) + bootstrap (5.1.3) + autoprefixer-rails (>= 9.1.0) + popper_js (>= 2.9.3, < 3) + sassc-rails (>= 2.0.0) browserify-rails (4.3.0) addressable (>= 2.4.0) railties (>= 4.0.0) @@ -183,6 +189,7 @@ GEM railties (>= 4.2.0) faraday (1.0.0) multipart-post (>= 1.2, < 3) + ffi (1.15.5) flamegraph (0.9.5) font-awesome-rails (4.7.0.5) railties (>= 3.2, < 6.1) @@ -338,6 +345,7 @@ GEM pg_query (1.2.0) pghero (2.7.0) activerecord (>= 5) + popper_js (2.9.3) pr_geohash (1.0.0) progress_bar (1.3.0) highline (>= 1.6, < 3) @@ -508,6 +516,14 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt selenium-webdriver (3.142.4) childprocess (>= 0.5, < 3.0) rubyzip (~> 1.2, >= 1.2.2) @@ -588,6 +604,7 @@ DEPENDENCIES annotate (< 2.7.5) better_errors binding_of_caller + bootstrap browserify-rails bullet (= 5.9.0) capybara diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ae7cbfd48..dc3313e75 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -5,11 +5,12 @@ // the compiled file. // //= require constants -//= require jquery +//= require jquery3 //= require intersection-observer/intersection-observer //= require rails-ujs //= require jquery.selectboxes //= require jquery.extentions +//= require jquery-migrate/dist/jquery-migrate //= require jquery-ui/autocomplete //= require jquery-ui/tabs //= require jquery-ui/datepicker diff --git a/app/assets/javascripts/application_new_ui.js b/app/assets/javascripts/application_new_ui.js new file mode 100644 index 000000000..34b1f7e5c --- /dev/null +++ b/app/assets/javascripts/application_new_ui.js @@ -0,0 +1,10 @@ +//= require constants +//= require jquery3 +//= require popper +//= require bootstrap +//= require rails-ujs +//= require jquery-ui +//= require js-cookie/src/js.cookie +//= require leaflet +//= require jquery-touch-events +//= require new_ui diff --git a/app/assets/javascripts/constants.js.erb b/app/assets/javascripts/constants.js.erb index 784f0a8fa..85e38074c 100644 --- a/app/assets/javascripts/constants.js.erb +++ b/app/assets/javascripts/constants.js.erb @@ -1,5 +1,3 @@ -<%# frozen_string_literal: true - %> window.CONSTANTS = { geocoder: { apiKey: "<%= Geocoder::API_KEY %>", diff --git a/app/assets/javascripts/new_ui.js b/app/assets/javascripts/new_ui.js new file mode 100644 index 000000000..385fb7ac7 --- /dev/null +++ b/app/assets/javascripts/new_ui.js @@ -0,0 +1,1059 @@ +/* jslint browser: true, white: true, single: true, for: true, long: true */ +/* global $, jQuery, console, window, CONSTANTS */ + +var cyclescapeui = (function ($) { + 'use strict' + + // Default settings + var _settings = + { + disactivateCloseSearch: false + } + + var _actions = [ + 'discussions', + 'index', + 'discussion', + 'newIdea', + 'profile', + 'newDiscussion' + ] + + // Class properties + var _currentWizardPage = 0 // Current page on progress div pages i.e. account creation + var _pageScroll = 0 // Save page scroll when opening an overlay on mobile + var _sideContentHtml = '' + const isIOSSafari = !!window.navigator.userAgent.match(/Version\/[\d\.]+.*Safari/) + + var _map = null; // Leaflet map + var _addIdeaMarker = null; // Save the Leaflet marker in newIdea + var _selectedAttachment = null; // Selected attachment in Discussion view + + + return { + + // Main function + initialise: function (page = false) { + // Initialise the UI + cyclescapeui.navBar(); + cyclescapeui.searchBar(); + cyclescapeui.autocomplete(); + cyclescapeui.filterable(); + cyclescapeui.uploadPreview(); + cyclescapeui.autofocus(); + cyclescapeui.tagsAutocomplete(); + cyclescapeui.geocoder(); + cyclescapeui.sideContent(); + cyclescapeui.mapControls(); + cyclescapeui.popovers(); + cyclescapeui.toasts(); + cyclescapeui.segmentedControl(); + cyclescapeui.contentToggle(); + cyclescapeui.enableWizard(); + + + // Initialise each section + if (_actions.includes(page)) { + cyclescapeui[page](); + }; + }, + + + /* + * Nav bar functions + */ + navBar: function () { + // Open nav on click + $('#hamburger').on('click', function () { + cyclescapeui.openNav(); + }); + + // Enable normal "click" close + $('body').on('click', function (event) { + if (event.target.tagName != 'LI') { + if ($('nav').hasClass('open')) { + cyclescapeui.closeNav(); + } + } + }); + + // Enable swipe-to-close + $('nav').on('swipeleft', function () { + if ($('nav').hasClass('open')) { + cyclescapeui.closeNav(); + } + }); + + // Listen for resize, if hamburger is set to hidden but window expands to desktop + $(window).on('resize', function () { + if (isIOSSafari) { return; } + if ($(window).width() > 1000) { + $('nav').show(); + } else { + $('nav').hide(); + } + }); + + // Listen for escape key to close menu + $(document).on('keydown', function (event) { + if (event.key == "Escape") { + if ($('nav').hasClass('open')) { + cyclescapeui.closeNav(); + } + } + }); + }, + + + // Open the nav bar + openNav: function () { + // Add shades + $('#shade').removeClass('white').fadeIn('fast'); + + // Slide the nav out from the left + $('nav').show('slide', { direction: 'left' }, 300, function () { + $('nav').addClass('open'); + }) + }, + + + // Close the nav bar + closeNav: function () { + // Close group change popover + var exampleTriggerEl = document.getElementById('group-popover') + var popover = bootstrap.Popover.getOrCreateInstance(exampleTriggerEl) // Returns a Bootstrap popover instance + popover.hide(); + + // Close menu + $('#shade').fadeOut(); + $('nav').removeClass('open'); + $('nav').hide("slide", { direction: "left" }, 300); + }, + + + // Autofocus inputs contained in Bootstrap modals + autofocus: function () { + $(document).on('shown.bs.modal', function () { + $('input:visible:enabled:first', this).focus(); + }); + }, + + + // Enable preview of photos to be uploaded + thumbWrapper: function (files, selector) { + + thumb(files); + + function thumb(files) { + + if (files == null || files == undefined) { + $(selector).html('

Unable to show a thumbnail, as this web browser is too old to support this.

'); + return false; + } + + for (var i = 0; i < files.length; i++) { + var file = files[i]; + var imageType = /image.*/; + + if (!file.type.match(imageType)) { + continue; + } + + var reader = new FileReader(); + + if (reader != null) { + reader.onload = GetThumbnail; + reader.readAsDataURL(file); + } + } + } + + function GetThumbnail(e) { + + var thumbnailCanvas = document.createElement('canvas'); + var img = new Image(); + img.src = e.target.result; + + img.onload = function () { + + var originalImageWidth = img.width; + var originalImageHeight = img.height; + + thumbnailCanvas.id = 'myTempCanvas'; + thumbnailCanvas.width = $(selector).width(); + thumbnailCanvas.height = $(selector).height(); + + // Scale the thumbnail to fit the box + if (originalImageWidth >= originalImageHeight) { + var scaledWidth = Math.min(thumbnailCanvas.width, originalImageWidth); // Ensure width is no greater than the available size + var scaleFactor = (scaledWidth / originalImageWidth); + var scaledHeight = Math.round(scaleFactor * originalImageHeight); // Scale to same proportion, and round + } else { + var scaledHeight = Math.min(thumbnailCanvas.height, originalImageHeight); + var scaleFactor = (scaledHeight / originalImageHeight); + var scaledWidth = Math.round(scaleFactor * originalImageWidth); + } + + if (thumbnailCanvas.getContext) { + var canvasContext = thumbnailCanvas.getContext('2d'); + canvasContext.drawImage(img, 0, 0, scaledWidth, scaledHeight); + var dataURL = thumbnailCanvas.toDataURL(); + + if (dataURL != null && dataURL != undefined) { + var nImg = document.createElement('img'); + nImg.src = dataURL; + $(selector).html(nImg); + } else { + $(selector).html('

Unable to read the image.

'); + } + } + } + } + }, + + + uploadPreview: function () { + $('#form_photograph').on('change', function () { + cyclescapeui.thumbWrapper(this.files, '#form_thumbnailpreview'); + }); + }, + + + // Set up the search bar + searchBar: function () { + + // Initialise results + var data = [ + { label: 'Discussion', value: 'discussion.html' }, + { label: 'Discussions', value: 'discussions.html' }, + { label: 'Browse issues', value: 'browse-topics.html' }, + { label: 'Profile', value: 'profile.html' } + ]; + + $('#search input').autocomplete({ + appendTo: '#search', + source: data, + focus: function (event, ui) { + $(event.target).val(ui.item.label); + return false; + }, + select: function (event, ui) { + $(event.target).val(ui.item.label); + window.location = ui.item.value; + return false; + } + }); + + // Open the search bar if clicking the icon + $('#search').on('click', function () { + if (!$('#search').hasClass('expanded')) { + $('#search i').toggleClass('fa-search').toggleClass('fa-times-circle'); + $('#search').addClass('expanded'); + + + $('#search input').focus(); + _settings.disactivateCloseSearch = true; + setTimeout(function () { + _settings.disactivateCloseSearch = false; + }, 100); + } + }); + + // Close search box on escape key + document.onkeydown = function (evt) { + evt = evt || window.event; + var isEscape = false; + if ("key" in evt) { + isEscape = (evt.key === "Escape" || evt.key === "Esc"); + } else { + isEscape = (evt.keyCode === 27); + } + if (isEscape) { + cyclescapeui.closeSearchBar(); + } + }; + + // Close the search bar if clicking on the x + $('#search fa-times-circle').on('click', function () { + cyclescapeui.closeSearchBar(); + }); + + // Close the search bar if clicking outside it + $('body').on('click', function (event) { + if (event.target.localName != 'input') { + cyclescapeui.closeSearchBar(); + } + }); + }, + + + // Close search bar + closeSearchBar: function () { + if ($('#search').hasClass('expanded') && _settings.disactivateCloseSearch === false) { + $('#search').removeClass('expanded') + $('#search i').toggleClass('fa-search').toggleClass('fa-times-circle'); + } + }, + + + // Enable geocoder animations + geocoder: function () { + $('.geocoder i').on('click', function () { + $('.geocoder').toggleClass('expanded'); + $('.geocoder i').toggleClass('fa-search').toggleClass('fa-times'); + $('.geocoder input').focus() + }); + }, + + + // Enable autocomplete + // !TODO add real data + autocomplete: function () { + var availableTags = [ + "ActionScript", + "AppleScript", + "Asp", + "BASIC", + "C", + "C++", + "Clojure", + "COBOL", + "ColdFusion", + "Erlang", + "Fortran", + "Groovy", + "Haskell", + "Java", + "JavaScript", + "Lisp", + "Perl", + "PHP", + "Python", + "Ruby", + "Scala", + "Scheme" + ]; + $(".geocoder input").autocomplete({ + appendTo: "#geocoder", + source: availableTags + }); + }, + + + // Enable autocomplete + // !TODO add real data + tagsAutocomplete: function () { + var availableTags = [ + "Cambridge Cycling Campaign", + "Leeds Cycling Campaign", + "London Cycling Campaign", + "Oxford Cycling Campaign", + "Durham Cycling Campaign", + "Manchester Cycling Campaign", + ]; + $("input.group-autocomplete").autocomplete({ + appendTo: ".group-search", + source: availableTags + }); + }, + + + // Enable Bootstrap popovers + popovers: function () { + var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')) + var popoverList = popoverTriggerList.map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }); + }, + + + // Enable Bootstrap toasts + toasts: function () { + var toastElList = [].slice.call(document.querySelectorAll('.toast')) + var toastList = toastElList.map(function (toastEl) { + return new bootstrap.Toast(toastEl, { animation: true, delay: 1500 }) + }); + }, + + + // Set up mobile side-content view + sideContent: function () { + // Handle filter button + $('.show-side-content').on('click', function () { + if ($('.side-content').hasClass('visible')) { + cyclescapeui.closeSideContent(); + } else { + _pageScroll = cyclescapeui.getPageScroll(); + window.scrollTo(0, 0); + $('.show-side-content').html('Done '); + $('#shade').addClass('white').fadeIn('fast'); + $('.side-content').addClass('visible').show() + } + }); + + // If we have hidden the side content and window resizes, CSS doesn't kick it - override + $(window).on('resize', function () { + if (isIOSSafari) { return; } + if ($(window).width() > 768) { + $('.side-content').show(); + } else { + $('.side-content').hide(); + } + }); + }, + + + // Close side content + closeSideContent: function () { + $('.show-side-content').html('Filter '); + $('#shade').fadeOut('fast'); + $('.side-content').removeClass('visible').hide(); + window.scrollTo(0, _pageScroll); + }, + + + // This function simply gets the window scroll position, works in all browsers. + getPageScroll: function () { + var yScroll; + if (self.pageYOffset) { + yScroll = self.pageYOffset; + } else if (document.documentElement && document.documentElement.scrollTop) { + yScroll = document.documentElement.scrollTop; + } else if (document.body) { + yScroll = document.body.scrollTop; + } + return yScroll; + }, + + + // Enable type-to-filter (TTF) in library and other views + filterable: function () { + $('input.filter').on('keyup', function () { + var value = $(this).val().toLowerCase(); + $('.filterable h2').filter(function () { + $(this).closest('li').toggle($(this).text().toLowerCase().indexOf(value) > -1) + }); + }); + }, + + + // Set up mobile side-content view + mapControls: function () { + // Close button + $('#shade>i.close').on('click', function () { + cyclescapeui.closeMapControls(); + cyclescapeui.closeSideContent(); + }); + + + // Handle clicking + $('.map-buttons li').on('click', function () { + $('.map-buttons li').removeClass('active'); + $(this).addClass('active'); + }) + + // Handle filter button + $('.show-map-controls').on('click', function () { + if ($('.map-controls').hasClass('visible')) { + var openText = $(this).data('open-text') + ' ' + cyclescapeui.closeMapControls(openText); + } else { + _pageScroll = cyclescapeui.getPageScroll(); + window.scrollTo(0, 0); + $('.show-map-controls').html($(this).data('close-text') + ' '); + $('#shade').addClass('white').fadeIn('fast') + $('.map-controls').css('z-index', '101').show().addClass('visible'); + } + }); + + // If we have hidden the side content and window resizes, CSS doesn't kick it - override + $(window).on('resize', function () { + if (isIOSSafari) { return; } + if ($(window).width() > 768) { + $('.side-content').show(); + } else { + $('.side-content').hide(); + } + }); + }, + + + closeMapControls: function (buttonLabel = 'Filter ') { + $('.show-map-controls').html(buttonLabel); + $('#shade').fadeOut('fast'); + $('.map-controls').removeClass('visible').hide(); + window.scrollTo(0, _pageScroll); + }, + + + // Segmented control + segmentedControl: function () { + // Constants + const SEGMENTED_CONTROL_BASE_SELECTOR = ".ios-segmented-control"; + const SEGMENTED_CONTROL_INDIVIDUAL_SEGMENT_SELECTOR = ".ios-segmented-control .option input"; + const SEGMENTED_CONTROL_BACKGROUND_PILL_SELECTOR = ".ios-segmented-control .selection"; + + forEachElement(SEGMENTED_CONTROL_BASE_SELECTOR, (elem) => { + elem.addEventListener('change', updatePillPosition); + }); + window.addEventListener('resize', + updatePillPosition + ); // Prevent pill from detaching from element when window resized. Becuase this is rare I haven't bothered with throttling the event + + function updatePillPosition() { + forEachElement(SEGMENTED_CONTROL_INDIVIDUAL_SEGMENT_SELECTOR, (elem, index) => { + if (elem.checked) moveBackgroundPillToElement(elem, index); + }); + } + + function moveBackgroundPillToElement(elem, index) { + document.querySelector(SEGMENTED_CONTROL_BACKGROUND_PILL_SELECTOR).style.transform = 'translateX(' + (elem.offsetWidth * index) + 'px)'; + } + + // Helper functions + function forEachElement(className, fn) { + Array.from(document.querySelectorAll(className)).forEach(fn); + } + + // Watch window width to swap text for icons + $(window).on('resize', function () { + cyclescapeui.setSegmentedControlIcons(); + }); + + // Adjust icons on startup, too + cyclescapeui.setSegmentedControlIcons(); + + // Remember each page's segmented control position + $('#content-view').on('change', function () { + var divId = '#content-' + $('input[name=content-view]:checked', '#content-view').val(); + var pageId = 'cyclescape-' + $('body').attr('class'); + Cookies.set(pageId, divId, { expires: 7 }) + }); + + // On startup, if we have a stored cookie for page view, change to that view + var pageId = 'cyclescape-' + $('body').attr('class'); + var savedCookie = Cookies.get(pageId); + if (savedCookie !== undefined) { + // Uncheck all #content inputs + $.each($('input[name=content-view]'), function (indexInArray, input) { + $(input).attr('checked', false); + }); + + // Check the div referred to in the cookie + // Cookie = #content-list + var desiredId = savedCookie.split('-').pop(); + $('input#' + desiredId).attr('checked', true).trigger('change'); + updatePillPosition(); + } + + }, + + // Function to set icons and text on segmented control + setSegmentedControlIcons: function () { + if ($(window).width() > 1200) { + // Show text + $.each($('.ios-segmented-control.adjustable-icons .option label span'), function (index, span) { + $(span).text(' ' + $(span).data('text')); + }) + } else { + // Show icons + var icon; + $.each($('.ios-segmented-control.adjustable-icons .option label span'), function (index, span) { + icon = $("", { + html: 'Spanned ', + class: "myClass" + }); + $(span).empty().html(""); + }) + } + }, + + + // Searches for a content-view toggle and displays on the checked toggle + changeToSelectedView: function () { + var desiredDivId = '#content-' + $('input[name=content-view]:checked', '#content-view').val(); + $('.content-wrapper').hide(); + $(desiredDivId).show(); + }, + + + // Enable content toggles between main-content divs on the same page + // If a toggle named content-view is found, corresponding divs (named content-#id) will be shown dynamically + contentToggle: function () { + // At page launch, hide all but default content div + if ($('#content-view').length) { + cyclescapeui.changeToSelectedView(); + } + + // Trigger when the segmented control changes + $('#content-view').on('change', function () { + cyclescapeui.changeToSelectedView(); + }); + }, + + + // Enable progress toggles between pages in a progress div + // Ex. account creation wizard + enableWizard: function () { + // At page launch, hide all but default wizard div + if ($('.wizard-content').length) { + cyclescapeui.showWizardDiv(_currentWizardPage); + } + + cyclescapeui.updateWizardBreadcrumbs(); + + // Enable clicking between divs + $('.wizard-content button.next').on('click', function () { + // Advance to next div + _currentWizardPage += 1; + + // Get all divs + var divs = $('.wizard-content>div'); + + // Hide all + divs.hide(); + + // Show the next one + if (_currentWizardPage < divs.length) { + $(divs[_currentWizardPage]).show(); + + // If last div, confetti! + if (_currentWizardPage == (divs.length - 1)) { + const jsConfetti = new JSConfetti(); + jsConfetti.addConfetti(); + } + } + + cyclescapeui.updateWizardBreadcrumbs(); + + // Autofocus on the first field + $('input').first().focus(); + }); + + // Enable clicking on wizard breadcrumps + $('.wizard li').on('click', function () { + var clickedTabIndex = $('.wizard li').index(this); + _currentWizardPage = clickedTabIndex; + cyclescapeui.showWizardDiv(clickedTabIndex); + }); + + // Enable back arrow + $('.wizard-back').on('click', function () { + _currentWizardPage -= 1 + cyclescapeui.showWizardDiv(_currentWizardPage); + }); + }, + + + // Takes a number and shows the corresponding div index + showWizardDiv: function (divIndex) { + // Get all divs + var divs = $('.wizard-content>div'); + + // Hide all + divs.hide(); + + // Show the next one + if (divIndex < divs.length) { + $(divs[divIndex]).show(); + } + + // Autofocus on the first field + $('input').first().focus(); + + cyclescapeui.updateWizardBreadcrumbs(); + }, + + + // Update wizard progress chip coloors + updateWizardBreadcrumbs: function () { + var wizardCrumbs = $('ul.wizard>li>h2') + + // Colour any complete crumbs + for (var i = 0; i < _currentWizardPage; i++) { + $(wizardCrumbs[i]).removeClass('active').addClass('complete'); + } + + // Colour the current crumb + $(wizardCrumbs[_currentWizardPage]).addClass('active'); + }, + + + // Display a notification popup with a message + displayNotification: function (notificationText, imageSrc, callback) { + + // Add this notification to the queue + _notificationQueue.push({ + 'notificationText': notificationText, + 'imageSrc': imageSrc, + 'callback': callback + }); + + // If the display daemon is already working through a queue, let it do its job + if ($('.popup.system-notification').queue('fx').length) { + return; + } + + // Otherwise start to work through the notification queue + cyclescapeui.notificationDaemon(); + }, + + + // Function to work through a queue of notifications. Will exit after the last notification is shown + notificationDaemon: function () { + // If there are items in the queue that haven't been displayed + var notification = null; + if (_notificationQueue.length) { + + // Pop the array + notification = _notificationQueue.shift(); + + // Set the image and text + $('.popup.system-notification img').attr('src', notification.imageSrc); + $('.popup.system-notification p.direction').text(notification.notificationText); + + // If we received a callback, change the click event to this + if (notification.callback) { + $('.notification').one('click', function () { + notification.callback(); + }); + } + + // Slide down the notification, and hide it after a delay + // Upon completetion, call this function again + $('.popup.system-notification').slideDown('slow'); + $('.popup.system-notification').delay(2500).slideUp('slow', cyclescapeui.notificationDaemon); + } + }, + + + // Page-specific initialisation + discussions: function () { + $('.ios-segmented-control div.option').on('click', function () { + var desiredUl = $(this).find('input').prop('id'); + cyclescapeui.setDiscussionsView(desiredUl); + }); + + // Save the side content HTML for toggling on/off + _sideContentHtml = $('.side-content').html() + + // At launch, set to first div + var firstDiv = $('.ios-segmented-control input').first().prop('id'); + cyclescapeui.setDiscussionsView(firstDiv); + + // Set the ordinal of the deadline date + cyclescapeui.setDeadlinesOrdinal(); + + // Ensure redirect to group management + $('ul.discussions ul.tags li').on('click', function (event) { + event.preventDefault(); + window.location.href = "generic-content.html"; + }); + + // Clicking on a star toggles favourite status + // !TODO Implement API call + $('ul.discussions .favourite').on('click', function (event) { + $(this).toggleClass('favourited'); + event.preventDefault(); + + if ($(this).hasClass('favourited')) { + $(this).toggleClass('animate__heartBeat'); + // Add API call + } + }); + }, + + + // Page-specific initialisation + index: function () { + var data = [ + { label: 'Cambridge Cycling Campaign', value: 'group.html' }, + { label: 'Oxford Cycling Campaign', value: 'group.html' }, + { label: 'Durham Cycling Campaign', value: 'group.html' }, + { label: 'Manchester Cycling Campaign', value: 'group.html' }, + { label: 'Cardiff Cycling Campaign', value: 'group.html' }, + ]; + $('#groups').autocomplete({ + source: data, + focus: function (event, ui) { + $(event.target).val(ui.item.label); + return false; + }, + select: function (event, ui) { + $(event.target).val(ui.item.label); + window.location = ui.item.value; + return false; + } + }); + }, + + + // Page-specific initialisation + discussion: function () { + var addContentModal = new bootstrap.Modal(document.getElementById('addContentModal'), {}) + + // Clicking on a star toggles favourite status + // !TODO Implement API call + $('.favourite').on('click', function (event) { + $(this).toggleClass('favourited'); + event.preventDefault(); + + if ($(this).hasClass('favourited')) { + $(this).toggleClass('animate__heartBeat'); + // Add API call + } + }); + + // Clicking a like button likes the post + $('.like').on('click', function () { + $(this).toggleClass('liked'); + + $(this).toggleClass('animate__heartBeat', $(this).hasClass('liked')); + }); + + // Clicking an added piece of rich-content prompts to delete it + $('ul.attachments li.attachment').on('click', function () { + _selectedAttachment = $(this); + $('#deleteModal').modal('toggle') + }); + + // Handler for deleteModal delete button + $('.remove-attachment').on('click', function () { + $('#deleteModal').modal('toggle'); + _selectedAttachment.fadeOut(); + }); + + // Enable rich-content-adding modal + $('body').on('click', 'ul.add-content li', function () { + addContentModal.toggle(); + }); + + // Initialise tinymce + tinymce.init({ + selector: 'textarea', + plugins: 'autoresize', + statusbar: false, + menubar: false, + skin: (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'oxide-dark' : 'oxide'), + content_css: (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'default') + }); + + // Clicking reply adds that text to the editor + $('.post-actions .reply').on('click', function () { + var quotedText = $(this).parent('.post-actions').siblings('.content').find('.post').first().text(); + tinymce.activeEditor.setContent(tinymce.activeEditor.getContent() + '
' + quotedText + '


'); + + // Animate scrolling to bottom + $('html, body').animate({ + scrollTop: $('li.reply').offset().top + }, 1000); + + // Set focus (to last line) in editor + tinyMCE.activeEditor.selection.select(tinyMCE.activeEditor.getBody(), true); + tinyMCE.activeEditor.selection.collapse(false); + tinyMCE.activeEditor.focus(); + + }); + }, + + + // Page-specific initialisation + newIdea: function () { + // Initialise map + _map = L.map('map', { + zoomControl: false, + tap: false // c.f. https://stackoverflow.com/questions/65030691/click-event-fires-twice-for-item-inside-a-loop + }).setView([51.505, -0.09], 13); + + // Add zoom control to bottom right + L.control.zoom({ + position: 'bottomright' + }).addTo(_map); + + // Load in a tile layer + L.tileLayer(`https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=${CONSTANTS.mapboxglAccessToken}`, { + attribution: 'Map data © OpenStreetMap contributors, Imagery © Mapbox', + maxZoom: 18, + id: 'mapbox/streets-v11', + tileSize: 512, + zoomOffset: -1, + accessToken: CONSTANTS.mapboxglAccessToken + }).addTo(_map); + + // On click, add a marker + _map.on('click', function (e) { + console.log(); + // Set a quick marker first, which will be adjusted once the API call comes back + if (_addIdeaMarker) { + _addIdeaMarker.setLatLng(e.latlng).update(); + } else { + _addIdeaMarker = L.marker(e.latlng).addTo(_map); + } + + // Get CycleStreets nearest point to update marker and location name + cyclescapeui.getNearestPoint(e.latlng.lng, e.latlng.lat, function (response) { + cyclescapeui.setMarker([response.features[0].geometry.coordinates[1], response.features[0].geometry.coordinates[0]]); + cyclescapeui.setName(response.features[0].properties.name); + }); + }); + + // Exceptionally, this page has a button to hide/show side-panel when in desktop view + $('.show-side-panel').on('click', function () { + $('.map-controls').slideToggle(); + }); + + // Add in a bunch of dummy markers for testing + var dummyMarkers = [ + [51.5182, -0.057163], + [51.5760, -0.137163], + [51.5672, -0.067163], + [51.5480, -0.060163], + [51.4860, -0.040163], + [51.5252, -0.060163], + [51.5169, -0.072163], + [51.5163, -0.057163], + ]; + + $.each(dummyMarkers, function (indexInArray, latlng) { + L.marker(latlng).addTo(_map).bindPopup(` +
+

Eos odit qui odio molestiae eum ab dolor sit.

+

Enim itaque harum ut aut sed aut et voluptas. Reiciendis et quia voluptate fuga recusandae sequi optio voluptas. Harum vitae alias consequatur ratione. Natus sapiente totam voluptas. Dolor ea qui culpa quo ratione vel.

+
+ + ` + ).on('click', function () { + // Do something + }); + }); + + + }, + + + // Page-specific initialisation + newDiscussion: function () { + // For testing, if submitted with autofill param in URL, autofill. + if (cyclescapeui.getUrlParameter('autofill')) { + $('#title').val('Eos odit qui odio molestiae eum ab dolor sit.'); + $('#description').val('Enim itaque harum ut aut sed aut et voluptas. Reiciendis et quia voluptate fuga recusandae sequi optio voluptas. Harum vitae alias consequatur ratione. Natus sapiente totam voluptas. Dolor ea qui culpa quo ratione vel.'); + } + + // Initialise tinymce + tinymce.init({ + selector: 'textarea', + plugins: 'autoresize', + statusbar: false, + menubar: false, + skin: (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'oxide-dark' : 'oxide'), + content_css: (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'default') + }); + + }, + + getUrlParameter: function (sParam) { + var sPageURL = window.location.search.substring(1), + sURLVariables = sPageURL.split('&'), + sParameterName, + i; + + for (i = 0; i < sURLVariables.length; i++) { + sParameterName = sURLVariables[i].split('='); + + if (sParameterName[0] === sParam) { + return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); + } + } + return false; + }, + + + // Page-specific initialisation + profile: function () { + $('#submit-message').on('click', function (event) { + event.preventDefault() + // !TODO Add APi call + $('#messageModal').modal('toggle'); + + var myToastEl = document.getElementById('toast') + var myToast = bootstrap.Toast.getOrCreateInstance(myToastEl) // Returns a Bootstrap toast instance + myToast.show(); + + }); + }, + + + // Geocode + getNearestPoint: function (lon, lat, callback) { + var apiCallUrl = CONSTANTS.geocoder.csBaseUrl + 'nearestpoint?key=' + CONSTANTS.geocoder.apiKey + '&lonlat=' + lon + ',' + lat; + $.ajax({ + type: "GET", + url: apiCallUrl, + success: function (response) { + callback(response); + } + }); + }, + + + setMarker: function (latLng) { + _addIdeaMarker.setLatLng(latLng).update(); + }, + + + setName: function (locationName) { + $('.location-name').html(' ' + locationName); + }, + + + // Set discussion internal toggle + setDiscussionsView: function (desiredUl) { + $('.main-content>ul').hide(); + $('.main-content>ul.' + desiredUl).show(); + + if (desiredUl == 'deadlines') { + $('.side-content').html(''); + } else { + $('.side-content').html(_sideContentHtml); + if ($(window).width() > 768) { + $('.side-content').show(); + } + } + }, + + + // Returns the ordinal of an inputted number + getOrdinal: function (number) { + if (number == 1) { + return 'st' + } else if (number == 2) { + return 'nd' + } else if (number == 3) { + return 'rd' + } else { + return 'th' + } + }, + + + // Iterate through ul.deadlines and add ordinal to the date numbers + setDeadlinesOrdinal: function () { + $.each($('ul.deadlines .date h3'), function (indexInArray, day) { + $(day).text($(day).text() + cyclescapeui.getOrdinal($(day).text())) + }); + + }, + + + // Function to provide the default notification click behaviour + setDefaultNotificationClickBehaviour: function () { + // Slide up the ride notification on click + $('.notification').on('click', function () { + // If there is a queue of 'fx', we dequeue the current notification immediately, rather than waiting for the delay + $('.notification').dequeue(); + $('.notification').slideUp('slow'); + }); + }, + + }; +}(jQuery)); diff --git a/app/assets/stylesheets/application_new_ui.scss b/app/assets/stylesheets/application_new_ui.scss new file mode 100644 index 000000000..d44fae734 --- /dev/null +++ b/app/assets/stylesheets/application_new_ui.scss @@ -0,0 +1,2 @@ +@import "bootstrap"; +@import "new_ui"; diff --git a/app/assets/stylesheets/new_ui.css b/app/assets/stylesheets/new_ui.css new file mode 100644 index 000000000..4f56bd8cc --- /dev/null +++ b/app/assets/stylesheets/new_ui.css @@ -0,0 +1,811 @@ +/* Typography */ +h1, h2, h3, h4, h5, h6, body, input, select, textarea, label {font-family: 'Helvetica Neue', sans-serif;} +h1 {color: #AC3E27; font-weight: 500;} +h2 {color: #185B3D; font-weight: 500; font-size: 20px; width: fit-content;} +h3 {color: #185B3D; font-size: 20px; margin: 20px 0;} +h3, h4, h5, h6, body, input, select, textarea, label {color: #212322;} +input, select, textarea {font-size: 15px;} +.drop-cap:first-letter {color: #AC3E27;} +.italic {font-style: italic;} +p.light {font-weight: 300;} +p a {color: #AC3E27;} + +.drop-cap:first-child:first-letter {color: #AC3E27; float: left; line-height: 41px; padding-top: 4px; padding-right: 8px; padding-left: 3px;} +p.drop-cap:first-child:first-letter {font-size: 46px;} +h3.drop-cap:first-child:first-letter {font-size: 46px; line-height: 30px;} +a.text {color: #AC3E27;} + +html.fa-events-icons-loading .fa-fw {display: inline-block; width: 1.28571429em;;} +html.fa-events-icons-loading .fa-fw::before {content: "\00a0";} +html.fa-events-icons-loading body {display: none;} + + +/* Basic layout */ +html, body {height: 100%;} +body {display: flex; flex-direction: row; flex-wrap: wrap; width: 100%; padding: 10px; margin: 0;} +#content {display: flex; flex-direction: column; flex-basis: 100%; flex: 1; margin-top: 50px; margin-left: 250px; padding: 10px; max-width: 1300px;} +#shade {display: none; width: 100%; height: 100%; position: fixed; z-index: 100; -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); background-color:rgba(0, 0, 0, 0.158); margin-left: -10px; margin-top: -10px;} +#shade.white {background-color:rgba(255, 255, 255, 0.897); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px);} +#shade i.close {display: none; position: fixed; right: 0; padding: 5px; margin: 10px 5px; font-size: 25px; color: #c76a58; cursor: pointer;} +#shade.white i.close {display: inline-block;} + +.title-wrapper {display: flex; flex-direction: row; flex-wrap: wrap; width: 100%;} +.title-wrapper .section-title {flex-direction: column; flex: 3; padding: 10px; margin-right: 40px; align-items: center; justify-content: center;} +.title-wrapper .section-title h1, .title-wrapper .section-title p.badge {display: inline-block; width: fit-content;} +.title-wrapper .section-title h1 {margin-right: 20px; margin-bottom: 15px;} +.title-wrapper .section-title p.badge {background-color: #eeeeee; color: #AC3E27; padding: 10px; border-radius: 25px; margin: 0 7.5px 0 0; font-size: 14px; font-weight: 300; align-self: center;} +.title-wrapper .action-buttons {display: flex; padding: 10px; max-width: 400px;} + +.content-wrapper {display: flex; flex-direction: row; flex-wrap: wrap; width: 100%;} +.main-content {flex-direction: column; flex: 2; padding: 10px; margin-right: 40px;} +.main-content h2 {margin-top: 10px;} +.main-content.full-screen {margin: 0 10px; height: calc(100vh - 300px); border-radius: 25px; padding: 0;} +.side-content {display: flex; flex-direction: column; flex: 1; padding: 10px; max-width: 300px; z-index: 101;} + +.show-side-content, .show-map-controls {display: none; position: fixed; bottom: 0; right: 5%; padding: 10px; margin: 10px auto; border-radius: 25px; color: white; font-size: 100%; height: 50px; border: none; outline: none; background-color: #AC3E27; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); transition: 0.2s; line-height: 1; z-index: 98} +.show-side-content:hover, .show-map-controls:hover {background-color: #c76a58;} +.show-map-controls, .show-side-content {z-index: 102;} + +.unstyled {text-decoration: none;} +.padding {padding: 10px;} +.inline {display: inline;} +.centered {align-self: center;} +.text-centered {text-align: center;} +.flex {display: flex; flex-direction: row; justify-content: center; flex-wrap: wrap;} + +.full-map {width: 100%; border-radius: 25px;} +.map-controls {float: right; background-color: rgba(255, 255, 255, 0.871); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); border-radius: 25px; padding: 0 10px 10px; margin: 5px;} +.map-controls.left {float: left;} +.map-controls.absolute {position: absolute; top: 210px;} +.map-controls h2 {padding: 10px; text-align: center; margin: 0 auto;} + +#top-menu {display: none; position: fixed; z-index: 98; width: 100%; height: 75px; margin-left: -10px; margin-top: -10px; background-color: rgba(255, 255, 255, 0.671); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); flex-direction: column; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +#top-menu a {display: block; margin: auto; font-style: italic; font-size: 30px;} +#top-menu a h1 {margin: 0; display: inline-block;} +#top-menu img {width: 30px;} +#top-menu img.mobile-logo {width: 25px;} + + +/* Nav */ +nav {position: fixed; display: flex; flex-direction: column; background-color: #eeeeee; height: calc(100vh - 30px); max-width: 260px; border-radius: 25px; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75); z-index: 103; min-height: 469px;} +nav hr {color: white; margin: 12.5px 0 12.5px -10px; height: 2px !important; opacity: .6; width: calc(100% + 20px);} +nav .title img {width: 30px; margin-top: -16px;} +nav .title h1 {display: inline; font-style: italic; font-size: 35px;} +nav .title p {font-style: italic; font-size: 14px; color: #AC3E27; margin-left: 35px;} +nav .title a.group {color: #AC3E27;} +nav .title a.group:hover {text-decoration: underline;} +nav i {padding-left: 10px; padding-right: 30px; color: #939393; font-size: 20px; width: 40px; height: 20px; line-height: 20px;} +nav ul {list-style-type: none; padding: 0; margin: 0;} +nav ul a {text-decoration: none;} +nav li {padding: 10px 2.5px; margin: 5px 0; color: #185B3D; border-radius: 25px; font-size: 17px; cursor: pointer;} +nav li.active {background-color: #FFFFFF; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +nav li:hover {background-color: #ffffffa6;} +nav select {appearance: none; -webkit-appearance: none; outline: 0; border: none; background-color: #eeeeee; color: #185B3D; font-size: 17px; cursor: pointer; width: 190px; padding: 10px 5px; margin: 2.5px 0; border-radius: 25px;} +nav select:hover {background-color: #ffffffa6;} +nav .unread {display: inline-block; width: 30px; margin-left: 5px; margin-right: 7.5px;} +nav .unread p {border-radius: 100%; background-color: white; color: #AC3E27; font-style: italic; font-weight: 500; border: 1px solid #eeeeee; padding: 2px 10px; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75);} +nav li.profile {padding: 2px 0;} +nav .padding.bottom {margin-top: auto;} +button#hamburger {display: none; position: fixed; padding: 10px; margin: 0 5px; border-radius: 100%; color: #AC3E27; font-size: 150%; width: 50px; height: 50px; border: none; outline: none; background-color: #FFFFFF; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); transition: 0.2s; line-height: 1; z-index: 98;} +button#hamburger:hover {background-color: #eeeeee;} + + +/* Search bar */ +div.search {position: fixed; z-index: 102; top: 5px; right: 0; margin-right: 15px; margin-left: 15px; height: 49.25px; width: 56.28px; margin-top: 5px; padding: 5px 15px 5px 12.5px; color: #AC3E27; font-size: 25px; font-weight: 300; border-radius: 25px; border: .5px solid rgba(128, 128, 128, 0.199); transition: box-shadow 1s; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); cursor: pointer; background-color: #FFFFFF;} +div.search:hover {background-color: #eeeeee;} +div.search.expanded {box-shadow: 0 0 0 1000px rgba(0,0,0,.3); box-shadow: 0 0 0 100vmax rgba(0,0,0,.3); padding: 5px 15px; width: 75vw; max-width: 1000px; background-color: white;} +div.search.expanded:hover {background-color: white;} +div.search input {-webkit-appearance: none; border: none; outline: none; font-size: 25px; width: calc(100% - 60px); display: none; transition: 1s;} +div.search.expanded input {display: inline; background-color: #FFFFFF;} + + +/* Geocoder */ +div.geocoder {float: left; margin: 10px; padding: 10px 12px; border-radius: 25px; background-color: #FFFFFF; color: #AC3E27; transition: 0.2s; overflow: hidden;} +div.geocoder:hover {background-color: #eeeeee;} +div.geocoder:active {background-color: #d8d8d8;} +div.geocoder i {font-size: 20px; font-weight: 500;} +div.geocoder input {display: none; width: 300px; border-radius: 25px; padding: 0 10px; border: none; outline: none; font-size: 16px;} +div.geocoder.expanded:hover {background-color: #FFFFFF;} +div.geocoder.expanded input {display: inline-block;} +.modal div.geocoder {float: unset; position: absolute; top: 0;} + + +/* Geocoder autocomplete */ +.ui-autocomplete-loading + .loader {display: inline-block;} +.ui-autocomplete {background-color: white; width: 200px; list-style: none; margin: 10px 0 0 0; padding-left: 0; padding-top: 5px; padding: 5px; border-radius: 10px; z-index: 9999;} +.ui-autocomplete li div {list-style: none; margin: 2.5px; padding: 2.5px 10px; border-radius: 25px;} +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover {background-color: #eeeeee;} +.ui-autocomplete li:first-child a {padding-top: 9px;} +.ui-autocomplete li a {padding: 5px 15px 3px; display: block; color: #4d0026;} +.ui-autocomplete li a span {color: gray; font-size: 0.81em;} +.ui-autocomplete li a.ui-state-active {cursor: pointer; background-color: #fbf6f8; border-radius: 10px;} +.ui-helper-hidden-accessible {display: none;} + + +/* Generic elements */ +button.primary {align-self: flex-start; width: auto; border: none; background-color: #eeeeee; color: #AC3E27; border-radius: 25px; padding: 6px 15px; margin: 5px 7.5px; font-weight: bold; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75); transition: .1s;} +button.primary:hover {background-color: white;} +button.primary i {padding-left: 10px; padding-right: 20px;} +button.disabled {opacity: .8; filter: grayscale(100%); -webkit-filter: grayscale(100%); cursor: not-allowed !important;} +button.social {align-self: flex-start; display: inline-block; width: auto; border: none; background-color: #eeeeee; border-radius: 25px; padding: 5px 10px; margin: 5px; font-size: 11px; font-weight: bold;} +button.social.twitter {background-color: #7ABCFF; color: white;} +button.social.facebook {background-color: #7C9EFF; color: white;} +button.donate {background-color: #FBBE5F; color: white;} +button.donate:hover {color: #FBBE5F;} + +a.action {display: inline-flex; width: 270px; flex-direction: row; border: 1px solid #eeeeee; border-radius: 25px; color: #185B3D; padding: 10px 5px; margin: 7.5px 7.5px 7.5px 0; cursor: pointer; transition: .1s; text-decoration: none; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75); background-color: #eeeeee;} +a.action:hover {background-color: #FFFFFF;} +a.action .icon {display: flex; flex-direction: column; flex-basis: 100%; flex: 1; align-self: center; text-align: center; font-size: 25px; padding: 0 15px;} +a.action .text {display: flex; flex-direction: column; flex-basis: 100%; flex: 4; text-decoration: none;} +a.action .text h2 {font-weight: bold; margin: 0; font-size: 17px;} +a.action .text p {font-size: 14px;} + +ul.unstyled {list-style: none;} + +ul.avatars {padding: 0;} +ul.avatars li a {color: black; text-decoration: none;} +ul.avatars li a i {margin-top: 12.5px; margin-right: 5px; float: right;} +ul.avatars li {margin: 6px 0; padding: 2.5px 10px 2.5px 15px; border: 1px solid transparent; border-radius: 25px; cursor: pointer;} +ul.avatars li:hover {border-color: #eeeeee;} +ul.links li {margin: 5px 0; text-decoration: underline; cursor: pointer;} + +ul.tags {margin: 5px 0; padding: 0;} +ul.tags li.tag {list-style: none; display: inline-block; border-radius: 25px; border: 1px solid #185B3D; color: #185B3D; font-size: 12px; opacity: 0.8; padding: 2px 5px; margin: 0 5px 10px 0; transition: 0.2s; cursor: pointer;} +ul.tags li.tag a {display: inline-block; margin: 0; padding: 0; text-decoration: none; color: #185B3D;} +ul.tags li.tag:hover {opacity: 1; background: rgb(243, 243, 243);} +ul.tags li.large-tag {font-size: 15px; opacity: 0.97;} +ul.tags li.large-tag input {font-size: 200%;} +ul.tags li.large-tag label {color: #185B3D;} +ul.tags li.large-tag::after {padding-left: 5px; font-family: "Font Awesome 5 Pro"; font-weight: 400; content: "\f057";} +ul.tags li.large-tag:last-of-type {margin-bottom: 0;} + +ul.wizard {margin: 5px; padding: 0; height: 35px; background-color: transparent; text-align: center;} +ul.wizard li {display: inline-block; border-radius: 25px; cursor: pointer;} +ul.wizard li h2 {display: inline-block; border-radius: 100%; color: white; background-color: #b3b3b3; padding: 2.5px; width: 30px; height: 30px; text-align: center; margin-left: 10px;} +ul.wizard li h2.complete {background-color: #185B3D;} +ul.wizard li h2.active {background-color: #B2412B;} +ul.wizard li p {display: inline-block; font-size: 16px; margin: 0 20px 0 10px;} +ul.wizard li:hover p {text-decoration: underline;} +ul.wizard hr {width: 100px; margin: 0 auto 5px; display: inline-block;} +i.wizard-back {height: 40px; width: 40px; border: 1px solid #eeeeee; border-radius: 25px; line-height: 38px; font-size: 17px; cursor: pointer;} +i.wizard-back:hover {background-color: #dfdfdf;} +.wizard-content {padding: 0 50px;} + +ul.checkboxes {list-style: none; margin: 0; padding: 0;} + +.widget {border-radius: 25px; margin: 10px 0 5px;} +.widget.standalone {width: 300px; margin: 20px 30px; display: inline-block;} +.widget .title, .widget h2 {background-color: #eeeeee; color: #185B3D; font-size: 18px; border-radius: 25px; padding: 5px 5px 5px 20px;} +.widget .title {box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +.widget h2 {padding: 0 15px 0 0; margin: 0; font-weight: normal; font-size: 18px;} +.widget .widget-content {padding: 10px;} +.widget .widget-content.padded {padding: 10px 12.5px;} +.widget input {margin-bottom: 0;} +.widget button.primary {margin-bottom: 10px;} + +.avatar {width: 40px;} + +hr {margin: 15px 0;} + +.stylised-or {margin: 25px auto; text-align: center;} +.stylised-or hr {width: 100px; margin: 0 auto; display: inline-block; text-align: center;} +.stylised-or p {display: inline-block; border: 1px solid #afafaf; border-radius: 100%; padding: 2.5px; width: 30px; height: 30px; text-align: center; margin: -5px; line-height: 20px;} + +div.controls ul.map-buttons {display: flex; border-radius: 25px; padding: 7.5px; margin: 0; list-style: none; background-color: rgba(255, 255, 255, 0.178); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); margin: 5px; width: -webkit-fill-available;} +div.controls ul.map-buttons li {flex: 1; padding: 10px 0 0 0; border-radius: 25px; margin: 0 2.5px; cursor: pointer;} +div.controls ul.map-buttons li.active {background-color: #FFFFFF; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04)} +div.controls ul.map-buttons li:hover {background-color: #ffffff;} +div.controls ul.map-buttons li i {display: block; text-align: center; color: #B2412B; font-size: 20px; margin: 0 auto;} +div.controls ul.map-buttons li p {text-align: center; font-size: 13px;} + +.pagination {display: block; margin: 15px auto; background-color: #EEEEEE; border-radius: 25px; text-align: center; width: 300px; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75);} +.pagination a {padding: 10px; color: #185B3D; border-radius: 25px;} +.pagination a:hover {background-color: #FFFFFF; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +.pagination p {display: inline-block; color: #185B3D; padding: 10px; margin: 0;} + + +/* Forms */ +form input, form textarea {padding: 10px; outline: none; border: 1px solid #eeeeee; border-radius: 25px; margin: 10px 0 5px;} +form .radio, form .category {display: flex; background-color: #f8f6f6; border-radius: 25px; padding: 5px;} +form .radio input, form .radio label {align-self: center;} +form .radio label {margin: 5px 15px 5px 5px;} +form .radio input {margin-left: 5px;} +form>label.decorated {grid-column: 1 / 2; height: 35px; color: #185B3D; font-weight: bold; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); border-radius: 25px; padding: 5px 20px 5px 20px; background-color: #eeeeee;} +form>label.hidden {opacity: 0;} +form input[type="submit"] {width: fit-content; border: none; background-color: #eeeeee; color: #AC3E27; border-radius: 25px; padding: 6px 15px; font-weight: bold; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75); transition: .1s;} +form input[type="submit"]:hover {background-color: white;} +form input[type="checkbox"] {margin: 5px} +form div.draganddrop {width: calc(300px + 4px + 4px); height: calc(200px + 4px + 4px); border: 2px dashed gray; border-radius: 25px; overflow: hidden;} +form div.draganddrop p {width: 300px; height: 200px; text-align: center; padding: 15px; color: gray;} +form div.draganddrop input {position: absolute; margin: 0; padding: 0; width: 300px; height: 200px; outline: none; opacity: 0;} +.modal-body input, .modal-body textarea {display: block; width: 100%;} + + +/* Modal */ +.modal-content {border-radius: 25px;} +.modal-content .modal-body.unpadded {padding: 0;} +.modal-content .modal-body button.x {position: absolute; top: 0; right: 0; margin: 10px;} +.modal-content .modal-body button.done {position: absolute; bottom: 0; right: 0;} + + +/* Popover */ +.popover {border-radius: 20px;} +.popover-body {padding: .75rem;} +.popover-header {margin-top: 0; border-top-left-radius: 20px; border-top-right-radius: 20px;} +ul.popover-avatar, ul.popover-group {list-style: none; padding: 0; margin: 0;} +ul.popover-avatar li img {width: 50px; height: 50px;} +ul.popover-group li {padding: 2.5px 10px; margin: 2.5px; border: 0.5px solid transparent; border-radius: 25px; cursor: pointer;} +ul.popover-group li:hover {border-color: #eeeeee;} +ul.add-content {list-style: none; padding: 0; margin: 0; width: 300px;} +ul.add-content li {padding: 5px 10px; border: 1px solid transparent; border-radius: 25px; display: inline-block; cursor: pointer;} +ul.add-content li:hover {border-color: #185B3D;} + + +/* iOS style segmented control */ +.ios-segmented-control {background: #eeeeee; border-radius: 30px; margin: 5px; padding: 2px; border: none; outline: none; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); cursor: pointer;} +.ios-segmented-control .option {position: relative; cursor: pointer;} +.ios-segmented-control .option:hover input:not(:checked) + label span, .ios-segmented-control .option:active input:not(:checked) + label span, .ios-segmented-control .option:focus input:not(:checked) + label span {transform: scale(1.1);} +.ios-segmented-control .option:active input:not(:checked) + label span {transform: scale(.95);} +.ios-segmented-control .option label {position: relative; display: block; text-align: center; padding: 3px 0vmin; background: rgba(255,255,255,0); font-weight: 400; color: #287622; font-size: 18px; height: 40px; line-height: 34px; text-overflow: clip; overflow: hidden; cursor: pointer;} +.ios-segmented-control.small .option label {font-size: 13px;} +.ios-segmented-control .option label::before, .ios-segmented-control .option label::after {content: ''; width: 1px; background: rgba(142,142,147,.15); position: absolute; top: 14%; bottom: 14%; will-change: background; -webkit-transition: background .3s ease; transition: background .3s ease;} +.ios-segmented-control .option label::before {left: 0; transform: translateX(-.5px);} +.ios-segmented-control .option label::after {right: 0; transform: translateX(.5px);} +.ios-segmented-control .option:first-of-type {grid-column: 1; grid-row: 1; box-shadow: none;} +.ios-segmented-control .option:first-of-type label::before {opacity: 0;} +.ios-segmented-control .option:last-of-type label::after {opacity: 0;} +.ios-segmented-control .option input {position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 100%; height: 100%; padding: 0; margin: 0; -webkit-appearance: none; -moz-appearance: none; appearance: none; outline: none; border: none; opacity: 0;} +.ios-segmented-control .selection {background: #FFFFFF; border: .5px solid rgba(0,0,0,0.04); box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); border-radius: 30px; grid-column: 1; grid-row: 1; z-index: 2; will-change: transform; -webkit-transition: transform .2s ease; transition: transform .2s ease;} +.ios-segmented-control .option label span {display: block; position: relative; z-index: 2; -webkit-transition: all .2s ease; transition: all .2s ease; will-change: transform;} +.ios-segmented-control .option label span {font-family: 'Font Awesome\ 5 Pro', sans-serif;} +.ios-segmented-control.adjustable-icons .option label span {margin: 10px;} +.ios-segmented-control .option input:checked+label::before, .ios-segmented-control .option input:checked+label::after {background: var(--background);z-index: 1;} +.ios-segmented-control .option input:checked+label {cursor: default;} + + +/* Index */ +.index h4 {color: #AC3E27; font-weight: 500; font-size: 38px;} +.index h1 {font-size: 44px; font-style: italic;} +.index .content-wrapper {z-index: 5;} +.index .section-title {background-color: rgba(255, 255, 255, 0.671); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); display: inline-flex; flex-direction: row; border-radius: 25px; padding: 10px 30px; z-index: 50; margin: 10px 12.5px 0;} +.index .section-title h4 {margin-bottom: 0;} +.index .section-title h4, .index .title-wrapper h1 {display: inline-block;} +.index .title-wrapper img {width: 60px; margin-right: 20px;} +.index .title-wrapper .section-title {flex: unset;} +.index .jumbotron {background-color: #ac3d27df; color: white; padding: 30px; border-radius: 25px; margin-top: 30px; margin-bottom: 30px; max-width: 1200px; backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px);} +.index .jumbotron p.description {font-size: 20px;} +.index a.action {color: white; background-color: #CA7F72;} +.index a.action {margin: 10px; border: transparent; width: 240px; padding-right: 10px;} +.index a.action:hover {background-color: #f3f3f3ad;} +.index a.action .text {flex: 5;} +.index a.action .text h2 {color: white; font-size: 14px;} +.index a.action .text p {font-size: 13px;} +.index input {width: 100%; padding-left: 50px; margin: 10px 0;} +.index img.flow {position: fixed; top: 0; right: -520px; opacity: 0.8;} +.index div.tags {background-color: rgba(255, 255, 255, 0.671); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); display: inline-block; border-radius: 25px; padding: 10px;} +.index ul.tags {list-style: none; max-width: 400px;} +.index ul.tags a {text-decoration: none;} +.index ul.tags li {display: inline-block; border: 1px solid #185B3D; border-radius: 25px; padding: 5px 10px; margin: 7.5px; font-size: small; color: #185B3D; cursor: pointer; transition: 0.2s;} +.index ul.tags li:hover {background-color: rgba(221, 221, 221, 0.787);} + + +/* Group home page */ +.groups .header {height: 300px; width: 100%; border-radius: 25px; background-size: cover; background-position: center center; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75);} +.groups .header .content {width: 100%; height: 100%; background: rgb(150,158,157); background: linear-gradient(180deg, rgba(150,158,157,1) 0%, rgba(150,158,157,0.8785889355742297) 24%, rgba(150,158,157,0.788953081232493) 39%, rgba(255,255,255,0) 100%);; border-radius: 25px; padding: 10px; color: white;} +.groups .header .content h1 {color: white; font-size: 35px;} +.groups .header .content img.logo {margin: 0 20px; width: 50px;} +.groups .header .content .links {display: inline; float: right; padding-right: 10px; margin: 2.5px; font-size: 30px;} +.groups .header .content .links a {color: white; padding: 10px; border: 1px solid transparent; border-radius: 25px; cursor: pointer;} +.groups .header .content .links a:hover {border-color: white;} +.groups .header .minimap {position: relative; float: right; bottom: 100px; right: 50px; height: 200px; width: 200px; border-radius: 25px; background-size: contain; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75);} +.groups #content hr {margin-top: 40px; margin-bottom: 30px; margin-right: 300px;} +.groups #content button.primary {margin: 30px 10px 30px 0;} +.groups #content .side-content {padding-top: 70px;} + + +/* Discussions */ +ul.discussions {padding: 0; margin: 15px 0;} +ul.discussions>h2, ul.deadlines>h2 {display: none; padding: 5px; margin: 5px auto;} +ul.discussions li {display: block; flex-direction: row; flex-wrap: wrap; border-radius: 25px; cursor: pointer; margin: 5px 0;} +ul.discussions li>a {text-decoration: none; display: flex; flex-direction: row; flex-wrap: wrap; border-radius: 25px; cursor: pointer; margin: 5px 0; padding: 0 20px;} +ul.discussions li>a:hover {background: #F6F6F6;} +ul.discussions li div.content {flex-direction: column; align-self: center; flex: 2; padding: 10px;} +ul.discussions li div.content h3 {font-size: 15px;} +ul.discussions li div.content h3, p {margin: 5px 0;} +ul.discussions li div.content p {display: inline-block; line-height: 15px; font-weight: 300; width: fit-content; font-size: 13px; color: black;} +ul.discussions li div.content img {display: inline; padding-left: 20px;} +ul.discussions li div.minimap {flex: 0; padding: 10px; margin: auto;} +ul.discussions li div.minimap .unread {position: absolute; padding-left: 100px;} +ul.discussions li div.minimap .unread p {border-radius: 100%; background-color: white; color: #AC3E27; font-style: italic; font-weight: 500; border: 1px solid #eeeeee; padding: 2px 10px; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75);} +ul.discussions li div.minimap img {border-radius: 25px; width: 120px; height: 120px;} +i.favourite {padding: 10px 20px 10px 10px; align-self: center; font-size: 20px; color: #dbdbdb;} +i.favourite.favourited {color: #FEAE00;} +ul.discussions li:hover i.favourite {color: #feae0054;} +ul.discussions li:hover i.favourite.favourited {color: #FEAE00;} +.discussions .side-content h3 {margin-top: 15px;} +div.location {width: 100px; height: 100px; display: inline-block; margin: 5px;} +div.location img {position: absolute; width: 100px; height: 100px; border-radius: 100%;} +div.location.unchecked img {-webkit-filter: grayscale(100%); filter: grayscale(100%); opacity: 0.7;} +div.location input {position: absolute; margin-top: 77px; font-size: 200%;} +div.location input:not(:checked)::before {display: none;} +div.location i {position: absolute; margin: 73px; padding: 0; font-size: 23px; border-radius: 100%; border: 1px solid transparent; cursor: pointer; color: #AC3E27;} +div.location i:hover {color: #f5310a;} +div.categories input[type="checkbox"] {font-size: 30px; color: #185B3D;} + + +/* Deadlines */ +ul.deadlines {padding: 0; margin: 15px 0;} +ul.deadlines li {display: flex; flex-direction: row; flex-wrap: wrap; border-radius: 25px; cursor: pointer; margin: 5px 0; padding: 10px 0;} +ul.deadlines li:hover {background: #F6F6F6;} +ul.deadlines .date {flex: 2; color: #AC3E27; text-align: center; align-self: center;} +ul.deadlines .date h3, ul.deadlines .date p {display: inline; margin: 0; color: #AC3E27;} +ul.deadlines .date h3 {font-size: 22px;} +ul.deadlines .date p.time {display: block;} +ul.deadlines .content {flex: 5;} +ul.deadlines .content h2 {color: black; font-size: 18px;} +ul.deadlines .content p {margin: 0;} +ul.deadlines .actions {flex: 1; align-self: center; text-align: center;} +ul.deadlines .actions i {padding: 0;} + + +/* Discussion */ +.discussion .content-wrapper {margin-bottom: 40px;} +.discussion i.favourite {padding: 5px;} +.discussion img.minimap {border-radius: 25px; width: 100%; border: 1px solid transparent; cursor: pointer; transition: 0.5s;} +.discussion img.minimap:hover {transform: scale(1.02); box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +ul.thread {padding: 0;} +ul.thread li {display: flex; flex-direction: row; flex-wrap: wrap; border-radius: 25px; margin: 5px 0; padding: 10px 0;} +ul.thread li .poster-avatar {flex: 1;} +ul.thread li .content {flex: 15;} +ul.thread li .content, ul.thread li .poster-avatar {padding: 2px 10px;} +ul.thread li .content h3 {margin: 0; padding: 0; font-size: 14px; width: fit-content; display: inline-block;} +ul.thread li .content a.timestamp {font-style: italic; text-decoration: none; font-weight: 300; font-size: 12px; display: inline-block; padding-left: 10px; color: black;} +ul.thread li .content a.timestamp:hover {text-decoration: underline;} +ul.thread li .content .post {font-size: 14px; font-weight: 400;} +ul.thread li .content .post ul {list-style-type: circle; font-size: 14px;} +ul.thread li .content .post ul li {margin: 2.5px 0; padding: 0; display: list-item;} +ul.thread li .post-actions {align-self: flex-end; margin: 5px 0 0 auto; text-align: end;} +ul.thread li .post-actions button {border: none; outline: none; background-color: #eeeeee; border: 1px solid transparent; color: #588734; border-radius: 25px; opacity: .85;} +ul.thread li .post-actions button:hover {background-color: white; border-color: #eeeeee; opacity: 1;} +ul.thread li .post-actions button.liked {background-color: #588734; color: white;} +ul.thread li.reply .content {border: 0.5px solid #dbdada; border-radius: 25px; padding: 5px 0 0 0; overflow: hidden;} +ul.thread li.reply:hover {background: none;} +ul.thread li.reply .reply-footer {background-color: #f6f6f6; border-top-left-radius: 25px; border-top-right-radius: 25px; padding: 5px 10px 10px;} +ul.thread li.reply ul.attachments {list-style: none; padding: 0;} +ul.thread li.reply ul.attachments li {border: 0.5px solid #185B3D; border-radius: 25px; display: inline-block; background-color: white; color: #185B3D; padding: 2.5px 10px; margin-right: 5px; cursor: pointer;} +ul.thread li.reply ul.attachments li:not(:last-child):after {padding-left: 5px; font-family: "Font Awesome 5 Pro"; font-weight: 400; content: "\f057";} +ul.thread li.reply ul.attachments li:hover {background: #f0eeee;} +ul.thread li.load-more {display: block; margin: 10px auto; width: 150px; background-color: #EEEEEE; color: #226244; border-radius: 25px; box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75); text-align: center; cursor: pointer;} +ul.thread li.load-more:hover {background-color: #FFFFFF;} +ul.thread li.load-more p {margin: 0; padding: 0; font-size: 13px;} +ul.thread a.add-content {display: inline-block; background-color: white; color: #185B3D; text-decoration: none;} +ul.thread a.add-content i {padding: 0 2.5px;} +ul.thread a.add-content:hover {background: #f0eeee;} +ul.thread .post-wrapper {text-align: right;} +ul.thread #post {display: inline-block; border: 0.5px solid #dbdada; background-color: white; color: #B2412B; outline: none; padding: 6.5px 10px; margin: 5px 0 0; border-radius: 25px; text-decoration: none;} +ul.thread #post:hover {background: #f0eeee;} +.widget .show-more {color: #555555; text-align: center; font-size: 14px; cursor: pointer;} + + +/* tinymce overrides */ +.tox.tox-tinymce {border: none !important;} + + +/* New discussion */ +.new-discussion .main-content form {display: grid; grid-template-columns: 150px 1fr; grid-gap: 17px;} +.new-discussion .main-content input, .new-discussion .main-content textarea {margin: 0;} +.new-discussion .main-content form>input>button {grid-column: 2 / 3;} +.new-discussion .main-content .minimap {height: 150px; width: 150px; border-radius: 25px; text-align: end; border: 1px solid transparent; cursor: pointer;} +.new-discussion .main-content .minimap:hover {box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +.new-discussion div.radio {padding: 5px 20px;} +.new-discussion div.category div.widget {margin: 0;} +.new-discussion div.category.tags {background-color: #f8f6f6; border-radius: 25px; padding: 10px;} +.new-discussion div.category.tags p {font-size: 12px; margin-left: 15px;} +.new-discussion div.category.tags input[type="search"] {margin-left: 10px;} +.locationModal img.map {width: 100%;} +.locationModal div.controls {position: absolute; top: 0; right: 0; padding: 20px; width: 300px; border-radius: 25px; background-color: rgba(255, 255, 255, 0.671); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); margin: 5px;} + + +/* Browse issues */ +.browse-issues .map-controls {width: 250px;} +.browse-issues div.controls ul.map-buttons li {padding: 10px 0 10px 0; text-align: center;} +.browse-issues ul.issues {list-style-type: none; margin: 0; padding: 0;} +.browse-issues ul.issues li {display: inline-block; border-radius: 25px; cursor: pointer; margin: 5px 0; max-width: 45%; transition: .2s; min-width: 300px;} +.browse-issues ul.issues li:hover {background: #F6F6F6; } +.browse-issues ul.issues li a {display: flex; cursor: pointer; text-align: left; text-decoration: none;} +.browse-issues ul.issues li a div.minimap {flex: 1; padding: 20px 10px;} +.browse-issues ul.issues li a div.issue-content {flex: 5; padding: 10px; align-self: center;} +.browse-issues ul.issues li a div.minimap img {border-radius: 25px; width: 100px; height: 100px;} +.browse-issues ul.issues li a h2 {border: 1px solid #185B3D; border-radius: 25px; padding: 5px 10px;} +.browse-issues ul.issues li a p {color: black;} +.browse-issues a.embed {color: rgb(105, 105, 105); position: absolute; bottom: 0; right: 0; margin-right: 60px; padding: 5px; background-color: #eeeeeee5; -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); border-radius: 25px;} + + +/* Issue */ +.issue .section-title h1 {color: #185B3D; border: 1px solid #185B3D; border-radius: 25px; padding: 5px 10px 10px; font-size: 30px;} +.issue .title-wrapper textarea {border: none; border-radius: 10px; padding: 2.5px 10px; width: 100%;} +.issue .main-content {max-width: 600px;} +.issue .side-content {width: 250px; max-width: unset;} +.issue .side-content img {border-radius: 25px; height: 100%;} +.issue .side-content button {position: fixed; align-self: center; display: block; margin: auto; bottom: 50px;} + + +/* New idea */ +.new-idea #map {height: -webkit-fill-available; border-radius: 25px; z-index: 1;} +.new-idea .map-controls {display: none; width: 400px; max-height: calc(100vh - 235px); overflow: scroll; z-index: 2;} +.new-idea form input, .new-idea form textarea {background-color: rgba(255, 255, 255, 0.671); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px);} +.new-idea form input {width: -webkit-fill-available;} +.new-idea form textarea {width: 100%;} +.new-idea form .light {font-size: 12px;} +.new-idea form {overflow: scroll;} +.new-idea .main-content.full-screen.full-map {height: calc(100vh - 230px);} +.modal-content .modal-body button.done {position: relative; display: block; margin: 30px 10px 0;} +.new-idea .geocoder {position: absolute; right: 30px; top: 233px; z-index: 3;} +@media (min-width: 1570px) { + .new-idea .geocoder {right: unset; left: 1470px;} +} + +/* Library */ +ul.library {list-style-type: unstyled; padding-left: 0;} +ul.library a {text-decoration: none;} +ul.library li {display: inline-block; border-radius: 25px; width: 280px; height: 405px; overflow: hidden; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); transition: .1s; margin: 5px 10px; cursor: pointer;} +ul.library li:hover {box-shadow: 2px 6px 12px -7px rgba(0,0,0,0.75);} +ul.library li img {height: 230px; width: 280px;} +ul.library li img.map {height: 100px;} +ul.library li h2 {margin: 10px 5px; padding: 0 5px; color: black; height: 55px;} +.library input.filter {border: 1px solid #eeeeee; font-size: 20px; padding: 10px 20px; border-radius: 25px; margin: 10px 10px 20px; width: 100%;} +.library div.controls ul.map-buttons li {padding: 10px 0 10px 0; text-align: center;} +.library-item img.minimap {border-radius: 25px; width: 100%;} + + +/* Profile */ +.profile .title-wrapper .section-title {flex: unset;} +.profile .website-link {margin: 10px;} +.profile .website-link i {margin-right: 5px;} +.profile img.avatar {width: 100px;} +.profile .widget.standalone:not(:first-of-type) {margin-left: 0;} + + +/* Create account */ +.create-account .main-content {border: 1px solid #eeeeee; border-radius: 25px; max-width: 1000px; margin: 50px auto;} +.create-account ul.wizard {width: auto; margin: 0 auto 50px; display: block;} +.create-account div.social-sign-in img {width: 400px; display: block; margin: 20px auto;} +.create-account h3 {color: #AC3E27; font-size: 30px;} +.create-account .form-floating {display: inline-block;} +.create-account form {text-align: center;} +.create-account input {width: 300px; display: inline-block; margin: 10px;} +.create-account button.next {text-align: center; margin: 15px auto; display: block;} +.create-account .ui-autocomplete {width: 200px !important;} +.signin .main-content a {color: #AC3E27; display: block; margin: 0 auto; text-align: center;} +.signin h3 {font-size: 20px;} + + +/* Planning applications */ +.planning-applications form .radio, form .category {background-color: transparent;} +.planning-applications form .map-controls {max-width: 310px; height: calc(100vh - 255px); overflow: scroll;} +.planning-applications form .category {flex-wrap: wrap;} +.planning-applications form .category .label {padding-right: 30px;} +.planning-applications .widget {margin: 20px 0;} + +ul.planning-applications {list-style-type: unstyled; margin: 0; padding: 0;} +ul.planning-applications li {display: flex; border-radius: 25px; overflow: hidden; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04); transition: .1s; margin: 10px 0; cursor: pointer;} +ul.planning-applications li:hover {box-shadow: 2px 6px 12px -7px rgba(0, 0, 0, 0.075);} +ul.planning-applications div.issue-content {padding: 5px 10px;} +ul.planning-applications div.minimap {height: 160px;} +ul.planning-applications li img {height: 250px; width: 300px;} +ul.planning-applications li img.map {height: 100px;} +ul.planning-applications li h2 {margin: 10px 5px; padding: 0; color: black; font-size: 15px;} +ul.planning-applications li p {font-size: 13px; margin: 10px 5px 15px;} +ul.planning-applications li p.uid {font-style: italic;} +ul.planning-applications li a {margin: 5px;} +ul.planning-applications li a.convert {background-color: #185B3D; color: white; padding: 5px 10px; border-radius: 25px; text-decoration: none; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +ul.planning-applications li a.convert:hover {background-color: #39956c;} +ul.planning-applications li a.hide {background-color: #dfdfdf; color: black; padding: 5px 10px; border-radius: 25px; text-decoration: none; box-shadow: 0 3px 8px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.04);} +ul.planning-applications li a.hide:hover {background-color: #c7c7c7;} +ul.application-types {list-style-type: none; padding: 0; margin: 0;} +ul.application-types li {display: inline-block; padding: 2.5px 15px 2.5px 5px; margin: 2.5px; color: white; border-radius: 25px;} +ul.application-types li label {color: white;} +.planning-applications input.filter {border: 1px solid #eeeeee; font-size: 20px; padding: 10px 20px; border-radius: 25px; margin: 20px; width: 100%;} +.planning-applications .main-content>input.filter {width: 80%; margin-top: 0;} + + +/* Dark mode */ +@media (prefers-color-scheme: dark) { + #top-menu {background-color: #AC3E27;} + #top-menu h1 {color: white;} + + h1, h2 {color: #ce5740;} + h3, h4, h5, h6, body, select, textarea, label {color: white;} + .drop-cap:first-child:first-letter {color: #ce5740;} + + #shade.white {background-color:rgba(0, 0, 0, 0.558);} + + body {background-color: #2D303E;} + nav {background-color: #3B3F50;} + nav i {color: #eeeeee;} + nav li {color: #eeeeee;} + nav li.active {background-color: #63646d; box-shadow: 0 3px 8px 0 rgba(170, 170, 170, 0.12), 0 3px 1px 0 rgba(145, 145, 145, 0.04);} + nav li:hover {background-color: #c0c0c0a6; color: white;} + + div.search {background-color: #63646D; color: white;} + div.search.expanded i {color: #963E2C;} + div.search:hover {background-color: rgb(167, 167, 167);} + div.search li {color: #963E2C;} + + button.primary {background-color: #ce5740; color: white;} + button.primary:hover {background-color: #e66d54;} + + form input[type="submit"] {background-color: #ce5740; color: white;} + form input[type="submit"]:hover {background-color: #e66d54;} + + .widget h2 {background-color: #1D8B5A; color: white;} + .widget .show-more {color: #FFFFFF;} + + .map-controls {color: white;} + .map-controls {background-color: rgba(29, 3, 3, 0.671)} + div.controls ul.map-buttons li.active {background-color: #ffffff4d;} + div.controls ul.map-buttons li:hover {background-color: #ffffff73;} + + ul.tags li.tag {background-color: #1d8b5a; color: white; opacity: 0.8;} + ul.tags li.tag:hover {opacity: 1; background: #22b170;} + ul.tags li.large-tag label {color: white;} + + ul.avatars li a {color: white;} + + .ios-segmented-control {background: #3B3F50;} + .ios-segmented-control .option label {color: white;} + .ios-segmented-control .selection {background: #63646D;} + + ul.discussions li {background-color: #3B3F50;} + ul.discussions li div.content p {color: white;} + ul.discussions li a:hover, ul.deadlines li a:hover {background-color: #5f6169;} + ul.discussions li div.minimap .unread p {background-color: #ce5740; color: white;} + ul.deadlines li:hover {background-color: #3a3e50;} + + ul.thread li.reply .content {border: none;} + ul.thread li .content a.timestamp {color: white;} + ul.thread li.reply .reply-footer {background-color: #2D303E;} + ul.thread li.reply ul.attachments li {background-color: #527B36; color: white;} + ul.thread li.reply ul.attachments li:hover {background-color: #5e8a41;} + ul.thread a.add-content {background-color: #527B36; color: white;} + ul.thread a.add-content:hover {background-color: #5e8a41;} + + ul.add-content li {color: white;} + ul.add-content li:hover {border-color: white;} + + .new-discussion div.category.tags {background-color: #3e4253; color: white;} + + .issue .title-wrapper textarea {background-color: #3e4253; color: white; margin-top: 10px;} + + .widget .title {color: #eeeeee; background-color: #1d8b5a;} + + a.action {background-color: #3B3F50;} + a.action:hover {background-color: #53586d;} + a.action p.description, a.action i {color: white;} + + ul.deadlines .content h2 {color: white;} + ul.deadlines .date h3 {color: #ce5740;} + + ul.thread li .content h3 {color: white;} + + ul.library li h2 {color: white;} + ul.library li {background-color: #3B3F50;} + ul.library li:hover {background-color: #6a6e80;} + .library input.filter {background-color: #3e4253; color: white;} + + div.location i {background-color: #3b3f5046;} + div.location i:hover {background-color: #787c8fa8;} + + .new-idea form input, .new-idea form textarea {background-color: #3e4253; color: white;} + + ul.planning-applications li h2 {color: white;} + ul.planning-applications li:hover {background-color: #3B3F50;} + + .browse-issues ul.issues li {text-align: center;} + .browse-issues ul.issues li:hover {background-color: #5f6169;} + .browse-issues ul.issues li h2 {background-color: #1d8b5a; color: white;} + .browse-issues ul.issues li a p {color: white;} + + .index div.tags {background-color: #2d303e54;} + .index ul.tags li {background-color: #1d8b5a; color: white; opacity: 0.8;} + .index ul.tags li:hover {opacity: 1; background: #22b170;} + + .locationModal div.controls {background-color: rgba(54, 54, 54, 0.671);} + + form .radio, form .category {background-color: rgba(54, 54, 54, 0.671);} + form input, form textarea {background-color: #3e4253; color: white;} + .new-discussion .main-content form>label {color: #1d8b5a;} + + + /* Override Bootstrap */ + .modal-content, .popover {background-color: #262834; color: white;} + .popover-header {background-color: #2D303E; color: white;} + .table {color: white;} + .modal-header .btn-close {color: white !important;} + ul.popover-group li {color: white;} + +} + +@media (max-width: 1255px) { + .browse-issues ul.issues li {max-width: 100%;} +} + +/* Responsive */ +@media (max-width: 1200px) { + ul.discussions>h2, ul.deadlines>h2 {display: block;} +} + + +@media (min-width: 1001px) and (max-width: 1169px) { + ul.discussions li i.favourite {display: none;} +} + + +/* Responsive */ +@media (max-width: 1000px) { + nav {display: none;} + div.search {z-index: 98;} + button#hamburger {display: inline-block;} + #content {margin-left: 0; margin-top: 60px;} + #top-menu {display: flex;} + + div.location {margin: 5px 2.5px;} + + .index img.flow {display: none;} +} + +@media (max-width: 992px) { + .locationModal img.map {height: 100%; border-radius: 0;} + .locationModal div.controls {padding: 10px; bottom: 0; width: calc(100% - 10px); margin: 5px; top: unset;} + .locationModal h3.icon.text-centered {display: none;} +} + +@media (max-width: 876px) { + ul.discussions li i.favourite {display: none;} +} + + +@media (max-width: 768px) { + body {padding: 5px;} + #shade {width: calc(100vw + 5px); height: calc(100vh + 5px);} + .content-wrapper {display: block;} + .side-content {display: none; position: absolute; top: 0; left: 10%; margin: auto;} + .show-side-content, .show-map-controls {display: block;} + .map-controls.absolute {top: 0;} + .title-wrapper .section-title {margin-right: 0; flex: unset; width: 100%;} + button.primary i {padding-left: 3px; padding-right: 14px;} + + /* Make sure Leaflet controls don't show through our popups */ + .leaflet-bottom.leaflet-right {z-index: 10 !important;} + + #top-menu {height: 65px; width: calc(100vw + 5px);} + #top-menu h1 {font-size: 20px;} + + div.search {margin-top: 0;} + div.search.expanded input {margin-top: 0;} + + .avatar {width: 35px;} + + a.action {width: unset;} + + .widget.standalone {margin: 20px 10px;} + + .ios-segmented-control {margin: 10px 5px;} + .ios-segmented-control .option label {font-size: 16px;} + + .full-map {width: auto;} + .map-controls {display: none; position: absolute; top: 0; left: 0; margin: auto; margin-top: 40px; z-index: 98; width: calc(100vw - 50px); height: auto;} + .planning-applications form .map-controls {max-width: unset;} + + #content {padding: 0;} + #content hr {margin: 5px 0;} + + .index div.action {width: auto;} + .index input {padding-left: 10px;} + .index .jumbotron {padding: 15px;} + .index .title-wrapper .section-title {display: inline-flex; margin-right: 15px; width: 100%;} + + .groups hr {display: none;} + .groups .main-content {margin-top: 120px;} + + h3.drop-cap:first-child:first-letter {font-size: 37px; line-height: 31px;} + .drop-cap:first-child:first-letter {padding-right: 3px;} + + .main-content {margin-right: 0; padding: 0 10px;} + + ul.thread li {display: block; margin: 5px 0; padding: 10px 0;} + ul.thread li .content, ul.thread li .poster-avatar {padding: 0 4px;} + ul.thread li.reply {display: block;} + ul.thread li.reply .content {max-width: calc(100vw - 5px);} + + ul.discussions li div.content {flex: 1.5; padding: 8px 0 8px 8px;} + ul.discussions li i.favourite {padding: 5px; display: block;} + ul.discussions li h3 {font-size: 16px;} + ul.discussions li div.minimap {padding: 10px 0;} + ul.discussions li div.minimap img {width: 90px; height: 90px;} + ul.discussions li div.minimap .unread {padding-left: 30px;} + + .discussion .content-wrapper {padding: 5px; width: calc(100vw - 10px);} + .discussion p.drop-cap:first-child:first-letter {font-size: 50px;} + .discussion .drop-cap:first-child:first-letter {line-height: 41px;} + + ul.deadlines .content {padding-left: 10px;} + + .new-discussion .title-wrapper {width: calc(100vw - 20px);} + .new-discussion .main-content {margin-bottom: 20px;} + .new-discussion .main-content form {grid-template-columns: unset;} + .new-discussion .main-content input, .new-discussion .main-content textarea {width: calc(100vw - 40px);} + .new-discussion .content-wrapper {padding: 5px; width: calc(100vw - 10px);} + form .radio, form .category {display: block;} + .new-discussion div.radio, .new-discussion div.category.tags {width: calc(100vw - 40px);} + .new-discussion div.category.tags input {width: calc(100vw - 80px);} + .new-discussion div.radio input {width: auto;} + + .new-idea .geocoder {top: 216px; right: 12px;} + + .browse-issues ul.issues {margin-top: 0;} + .browse-issues ul.issues li {display: block; max-width: unset;} + .browse-issues .map-controls {width: unset;} + .browse-issues .main-content {margin: 0;} + + ul.planning-applications li a.convert, ul.planning-applications li a.hide {display: block; text-align: center;} + + .new-idea .map-controls {width: 100vw; max-height: unset;} + .new-idea .title-wrapper .section-title {flex: 1;} + .new-idea .show-side-panel {display: none;} + + ul.library {text-align: center;} + .library input.filter {width: calc(100% - 20px);} + + ul.planning-applications li {display: inline-block; margin: 5px 10px 20px;} + ul.planning-applications li p {padding: 5px 10px;} + ul.planning-applications div.minimap {height: auto;} + ul.planning-applications li img {width: 100%;} + .planning-applications form .map-controls {height: 100%; width: 100vw;} + + .row {display: block;} + + ul.wizard li p {display: none;} + ul.wizard hr {width: 30px;} + .wizard-content {padding: 0 10px;} + + .create-account ul.wizard {margin: 10px 0 15px;} + .create-account .main-content {width: calc(100vw - 10px); margin: 20px auto;} + .create-account div.social-sign-in img {width: 345px;} + .signin .main-content {margin: 0 auto;} + + .profile .content-wrapper {padding: 10px; width: calc(100vw - 20px);} +} + +@media (max-height: 666px) { + nav hr {margin: 5px 0 5px -10px;} + nav li {font-size: 15px; padding: 7.5px 5px;} + div.search input {font-size: 19px; line-height: 30px;} + button.primary i {padding-left: 8px; padding-right: 18px;} + nav {overflow-y: scroll;} +} + +@media (max-width: 414px) { + div.geocoder input {width: 270px;} + ul.discussions div.minimap {display: none;} + .side-content {width: 100vw;} + + .index .section-title img {width: 30px;} + .index .section-title h4 {font-size: 25px;} + .index .section-title h1 {font-size: 29px;} + .index p.description {font-size: 16px;} +} + +@media (max-width: 375px) { + .index + button.primary {font-size: 12px; font-size: 14px; padding: 5px 8px 5px 12px;} + nav li {padding: 8px 2.5px;} +} + +@media (max-width: 330px) { + .side-content {left: 10px;} + .widget.standalone {width: 270px;} + .new-idea .geocoder {top: 239px;} + +} + diff --git a/app/controllers/new_ui/base_controller.rb b/app/controllers/new_ui/base_controller.rb new file mode 100644 index 000000000..dc95ed2b2 --- /dev/null +++ b/app/controllers/new_ui/base_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module NewUi + class ApplicationController < ::ActionController::Base + layout "application_new_ui" + end +end diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb new file mode 100644 index 000000000..7e249b6e4 --- /dev/null +++ b/app/views/layouts/_header.html.erb @@ -0,0 +1,62 @@ +
+ +
+ + + + + diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 0c0f92390..4439a386e 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -3,7 +3,7 @@ %head %title= page_title = favicon_link_tag 'favicon.ico', type: "image/x-icon" - = stylesheet_link_tag "application", media: "all" + = stylesheet_link_tag "application" media: "all" /[if lt IE 9] %script(src="//html5shiv.googlecode.com/svn/trunk/html5.js") /[if lt IE 8] diff --git a/app/views/layouts/application_new_ui.html.erb b/app/views/layouts/application_new_ui.html.erb new file mode 100644 index 000000000..3d284e622 --- /dev/null +++ b/app/views/layouts/application_new_ui.html.erb @@ -0,0 +1,32 @@ + + + + + <%= page_title %> + + + + <%= favicon_link_tag 'favicon.ico', type: "image/x-icon" %> + + <%= stylesheet_link_tag "application_new_ui", media: "all" %> + <%= javascript_include_tag "application_new_ui" %> + <%= csrf_meta_tags %> + <% if page_image %> + + <% end %> + <% if page_description %> + + + <% end %> + <% if page_title %> + " property="og:title"/> + <% end %> + + + + + + + + + diff --git a/package-lock.json b/package-lock.json index d8639ed35..44cad2325 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,12 +7,15 @@ "name": "cyclescape", "license": "MIT", "dependencies": { + "@benmajor/jquery-touch-events": "^2.0.3", "autosize": "^1.18.13", "browserify": "^14.5.0", "browserify-incremental": "^3.1.0", "coffeeify": "~0.6", "cropperjs": "^1.5.11", "intersection-observer": "^0.11.0", + "jquery-migrate": "^3.3.2", + "jquery-touch-events": "^1.0.7", "jquery-ui-timepicker-addon": "1.5.5", "js-cookie": "^2.2.1", "jsdom": "^9.0.0", @@ -36,6 +39,11 @@ "node": ">= 0.10" } }, + "node_modules/@benmajor/jquery-touch-events": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@benmajor/jquery-touch-events/-/jquery-touch-events-2.0.3.tgz", + "integrity": "sha512-yhhk/jzScpbuMf8zF7UTcaRFAgqM+8Elzsog9cSJywQBXKe7hJg+eJ9w/kmfqiLjZefT9p8pqwtqslmUvRA3kw==" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -2353,6 +2361,19 @@ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" }, + "node_modules/jquery-migrate": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.3.2.tgz", + "integrity": "sha512-L3gYhr7yEtLUSAeqXSicVa0vRD4aGwjw/bWY8YzrO2o/qDY1BaMyP3oB3bZf5Auy3Hu9ynliio0CTyDWCBPVDw==", + "peerDependencies": { + "jquery": ">=3 <4" + } + }, + "node_modules/jquery-touch-events": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/jquery-touch-events/-/jquery-touch-events-1.0.7.tgz", + "integrity": "sha1-RATo3e1gPnYumYle9QPsu/QC1m0=" + }, "node_modules/jquery-ui-timepicker-addon": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/jquery-ui-timepicker-addon/-/jquery-ui-timepicker-addon-1.5.5.tgz", @@ -4139,6 +4160,11 @@ } }, "dependencies": { + "@benmajor/jquery-touch-events": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@benmajor/jquery-touch-events/-/jquery-touch-events-2.0.3.tgz", + "integrity": "sha512-yhhk/jzScpbuMf8zF7UTcaRFAgqM+8Elzsog9cSJywQBXKe7hJg+eJ9w/kmfqiLjZefT9p8pqwtqslmUvRA3kw==" + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -6055,6 +6081,17 @@ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" }, + "jquery-migrate": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.3.2.tgz", + "integrity": "sha512-L3gYhr7yEtLUSAeqXSicVa0vRD4aGwjw/bWY8YzrO2o/qDY1BaMyP3oB3bZf5Auy3Hu9ynliio0CTyDWCBPVDw==", + "requires": {} + }, + "jquery-touch-events": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/jquery-touch-events/-/jquery-touch-events-1.0.7.tgz", + "integrity": "sha1-RATo3e1gPnYumYle9QPsu/QC1m0=" + }, "jquery-ui-timepicker-addon": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/jquery-ui-timepicker-addon/-/jquery-ui-timepicker-addon-1.5.5.tgz", diff --git a/package.json b/package.json index 7187b6c44..4429213d9 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,15 @@ { "name": "cyclescape", "dependencies": { + "@benmajor/jquery-touch-events": "^2.0.3", "autosize": "^1.18.13", "browserify": "^14.5.0", "browserify-incremental": "^3.1.0", "coffeeify": "~0.6", "cropperjs": "^1.5.11", "intersection-observer": "^0.11.0", + "jquery-migrate": "^3.3.2", + "jquery-touch-events": "^1.0.7", "jquery-ui-timepicker-addon": "1.5.5", "js-cookie": "^2.2.1", "jsdom": "^9.0.0",