diff --git a/Gemfile b/Gemfile index afbf61d3..dd0c1c45 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,7 @@ source "https://rubygems.org" git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby "3.3.6" +gem "active_link_to", "~> 1.0" # Active links with CSS classes gem "bootsnap", ">= 1.1.0", require: false gem "high_voltage" gem "jbuilder", "~> 2.11" diff --git a/Gemfile.lock b/Gemfile.lock index cca5ab7f..01e2c0e7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -45,6 +45,9 @@ GEM erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) + active_link_to (1.0.5) + actionpack + addressable activejob (7.2.2) activesupport (= 7.2.2) globalid (>= 0.3.6) @@ -452,6 +455,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + active_link_to (~> 1.0) better_errors binding_of_caller bootsnap (>= 1.1.0) diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 7f38e824..3db39c93 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,7 +1,5 @@ //= link_tree ../images -// include our initial GOV.UK based stylesheets for now whilst -// migrating to ESBuild bundled assets... -//= link_directory ../stylesheets .css +//= link_directory ../builds .css //= link_tree ../builds diff --git a/app/assets/stylesheets/application.tailwind.css.scss b/app/assets/stylesheets/application.tailwind.css.scss index fefb1167..a7a77f07 100644 --- a/app/assets/stylesheets/application.tailwind.css.scss +++ b/app/assets/stylesheets/application.tailwind.css.scss @@ -5,6 +5,8 @@ @import "leaflet.scss"; /* stylelint-disable-line scss/load-partial-extension */ @import "daqi-levels.scss"; /* stylelint-disable-line scss/load-partial-extension */ @import "share.scss"; /* stylelint-disable-line scss/load-partial-extension */ +@import "header.scss"; /* stylelint-disable-line scss/load-partial-extension */ +@import "footer.scss"; /* stylelint-disable-line scss/load-partial-extension */ @tailwind base; @tailwind components; @@ -15,62 +17,28 @@ --main-colour-light: #dae7f7; } -header.site-header { - background-color: var(--main-colour); - - @apply flex flex-row p-4; - - .site-title { - @apply text-white flex-auto; - - .site-name { - @apply text-2xl font-bold block; - } - - .site-strapline { - @apply text-sm block; - } - } - - nav { - @apply text-white flex-auto text-right; - - button { - @apply text-5xl; - } - - ul { - @apply text-sm; - } - } -} - -main { - padding: 1rem; -} - .tabs { - @apply flex flex-row items-stretch border-b-[2px] border-black; + @apply flex flex-row items-stretch border-b-[1px] border-zinc-500 mx-4; border-radius: 10px 10px 0 0; gap: 0.5rem; } .tab { - @apply flex-1 px-1 py-4 text-xs text-center font-bold border-[2px]; + @apply flex-1 px-1 py-4 text-xs text-center font-bold border-[1px] cursor-pointer; border-radius: 10px 10px 0 0; &.active { - @apply border-black border-solid border-b-0 -mb-[2px] bg-white; + @apply border-zinc-500 border-solid border-b-0 -mb-[1px]; } &.inactive { - @apply border-gray-400 border-dashed border-b-0 text-gray-400; + @apply border-gray-400 border-dashed border-b-0 text-gray-400 bg-white; } .daqi-indicator { - @apply size-9 rounded-full mx-auto my-1 flex justify-center items-center; + @apply size-7 rounded-full mx-auto my-1 flex justify-center items-center p-[3px]; } .daqi-label { @@ -83,9 +51,8 @@ main { } .tab-contents { - padding: 0.5rem; - border: 2px solid black; - border-top: 0; + @apply p-4 mx-4 border-[1px] border-t-0 border-zinc-500; + border-radius: 0 0 10px 10px; } @@ -117,23 +84,23 @@ main { } } +.forecast-timestamp { + @apply text-xs text-gray-500 text-center mt-2 block italic; +} + .sharing { button { - @apply flex mx-auto mt-6 px-8 py-2 rounded-md text-white justify-center; + @apply flex mx-auto mt-2 px-8 py-2 rounded-md text-white justify-center; background-color: var(--main-colour); } } -.forecast-timestamp { - @apply text-sm text-center text-gray-500 mt-2 block; -} - .learning, .subscribe { background-color: var(--main-colour-light); - @apply p-8 mt-2 text-center; + @apply p-8 mt-4 text-center; header { @apply font-bold; @@ -146,15 +113,9 @@ main { } } -select { - @apply inline-flex flex-row w-full gap-x-1.5 rounded-md bg-white px-3 py-2 text-base font-semibold text-gray-500 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50; -} - -.home-page-link { - color: revert; -} - .text-block { + @apply p-4; + h1 { @apply text-2xl font-bold mt-5 mb-3; } @@ -198,4 +159,49 @@ select { @apply px-2 py-1 border border-gray-400; } } + + details { + summary { + cursor: pointer; + + &::marker { + content: none; /* Hide the default marker */ + } + + h3 { + margin: 0; + + &::after { + content: "\002B"; /* Unicode character for plus sign */ + display: flex; + width: 1.5rem; + aspect-ratio: 1; + float: right; + align-items: center; + justify-content: center; + padding-bottom: 3px; + font-size: 1.3rem; + line-height: 0; + font-weight: normal; + color: black; + border: 1px solid black; + border-radius: 100%; + } + } + } + + &[open] summary h3 { + margin-bottom: 1rem; + + &::after { + content: "\2212"; /* Unicode character for minus sign */ + } + } + } +} + +.how-forecasts-are-made { + @apply py-8 px-4; + + background-color: #eee; } diff --git a/app/assets/stylesheets/footer.scss b/app/assets/stylesheets/footer.scss new file mode 100644 index 00000000..846e3a20 --- /dev/null +++ b/app/assets/stylesheets/footer.scss @@ -0,0 +1,33 @@ +.site-footer { + @apply text-white py-8 px-6; + + background-color: var(--main-colour); + + nav { + li { + @apply py-2; + + a.active { + @apply font-bold underline; + } + } + } + + .terms-and-conditions { + @apply mt-6; + + font-size: 0; /* Remove whitespace between inline-block elements */ + + li { + @apply text-xs inline-block border-r-white border-r px-2; + + &:first-child { + @apply pl-0; + } + + &:last-child { + @apply border-0; + } + } + } +} diff --git a/app/assets/stylesheets/header.scss b/app/assets/stylesheets/header.scss new file mode 100644 index 00000000..cf873a82 --- /dev/null +++ b/app/assets/stylesheets/header.scss @@ -0,0 +1,55 @@ +.site-header { + background-color: var(--main-colour); + + @apply flex flex-row flex-wrap p-4; + + .site-title { + @apply text-white text-center; + + .site-name { + @apply text-4xl font-bold block; + } + + .site-strapline { + @apply text-xs block; + } + } + + button { + @apply text-5xl flex-auto text-white text-right; + + line-height: 0; + + &::before { + content: "☰"; + font-size: 4rem; + bottom: 0.25rem; + position: relative; + } + + &.menu-open { + &::before { + content: "✕"; + font-size: 3.25rem; + bottom: 0; + right: 8px; + } + } + } + + nav { + @apply text-white w-full; + + ul { + @apply text-xl my-4; + + li { + @apply pt-4; + + a.active { + @apply font-bold underline; + } + } + } + } +} diff --git a/app/assets/stylesheets/leaflet.scss b/app/assets/stylesheets/leaflet.scss index fa8b5815..c7da1b25 100644 --- a/app/assets/stylesheets/leaflet.scss +++ b/app/assets/stylesheets/leaflet.scss @@ -20,3 +20,41 @@ /* From node_modules/leaflet.fullscreen/icon-fullscreen.svg */ background-image: url('data:image/svg+xml;charset=UTF-8,'); } + +.leaflet-pane { + .maplibregl-ctrl-attrib { + display: none; /* Hide duplicate attributions */ + } +} + +.leaflet-container { + a { + left: 2px !important; + + img { + width: 50px; /* Make the Maptiler logo smaller to fit on mobile */ + } + } +} + +.leaflet-control:not(.leaflet-control-attribution) { + border: 2px solid rgb(0 0 0 / 20%); + box-shadow: none; + border-radius: 4px; +} + +.leaflet-top:has(.leaflet-ctrl-geocoder) { + max-width: calc(100% - 60px); + + .leaflet-ctrl-geocoder { + max-width: 100%; + + form { + max-width: 100%; + + input { + height: 30px; + } + } + } +} diff --git a/app/components/day_tab_component.html.erb b/app/components/day_tab_component.html.erb index b9bf28e2..d05d7878 100644 --- a/app/components/day_tab_component.html.erb +++ b/app/components/day_tab_component.html.erb @@ -1,4 +1,4 @@ -<%= tag.div class: "tab #{@day} #{@active ? 'active' : 'inactive'}", +<%= tag.div class: "tab #{@day} #{@active ? 'active' : 'inactive'} #{@forecast.air_pollution.label == 'LOW' ? 'bg-white' : daqi_indicator_colour_class}", data: { date: @forecast.date.to_s, day: @day, diff --git a/app/components/day_tab_component.rb b/app/components/day_tab_component.rb index 24b84f4f..05f7d13f 100644 --- a/app/components/day_tab_component.rb +++ b/app/components/day_tab_component.rb @@ -10,6 +10,6 @@ def daqi_indicator_colour_class end def icon_stroke_colour_class - (@forecast.air_pollution.label == "HIGH") ? "stroke-white" : "stroke-black" + ["High", "Very high"].include?(@forecast.air_pollution.daqi_label) ? "stroke-white" : "stroke-black" end end diff --git a/app/controllers/forecasts_controller.rb b/app/controllers/forecasts_controller.rb index 32f808e6..57b90e64 100644 --- a/app/controllers/forecasts_controller.rb +++ b/app/controllers/forecasts_controller.rb @@ -16,8 +16,10 @@ def show respond_to do |format| format.turbo_stream do render turbo_stream: [ - turbo_stream.replace("forecasts-frame-top", partial: "forecasts/top"), - turbo_stream.replace("forecasts-frame-bottom", partial: "forecasts/bottom") + turbo_stream.replace("forecast-tabs-frame", partial: "forecasts/forecast_tabs"), + turbo_stream.replace("alert-guidance-frame", partial: "forecasts/alert_guidance"), + turbo_stream.replace("predictions-frame", partial: "forecasts/predictions"), + turbo_stream.replace("sharing-frame", partial: "forecasts/sharing") ] end format.html diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index ac362643..05461f9d 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -59,7 +59,7 @@ export default class MapController extends Controller { zoomControl: false, fullscreenControl: true, fullscreenControlOptions: { - position: "topright", + position: "bottomright", }, }); @@ -165,7 +165,7 @@ export default class MapController extends Controller { addGeolocationControl() { new LocateControl({ - position: "bottomright", + position: "topright", }).addTo(this.map); } diff --git a/app/javascript/controllers/navigation_controller.js b/app/javascript/controllers/navigation_controller.js index 42b5b541..161757a4 100644 --- a/app/javascript/controllers/navigation_controller.js +++ b/app/javascript/controllers/navigation_controller.js @@ -1,9 +1,10 @@ import { Controller } from "@hotwired/stimulus"; export default class NavigationController extends Controller { - static targets = ["menuList"]; + static targets = ["menuButton", "menuList"]; toggleMenu() { this.menuListTarget.classList.toggle("hidden"); + this.menuButtonTarget.classList.toggle("menu-open"); } } diff --git a/app/models/concerns/daqi_properties.rb b/app/models/concerns/daqi_properties.rb index 0134f5de..33b75865 100644 --- a/app/models/concerns/daqi_properties.rb +++ b/app/models/concerns/daqi_properties.rb @@ -12,6 +12,8 @@ def daqi_label def daqi_level case @value + when -999 + :low when 1..3 :low when 4..6 diff --git a/app/models/pollen_prediction.rb b/app/models/pollen_prediction.rb index 48358c22..6b92c1de 100644 --- a/app/models/pollen_prediction.rb +++ b/app/models/pollen_prediction.rb @@ -15,10 +15,6 @@ def guidance I18n.t("prediction.guidance.pollen.#{daqi_level}") end - def valid? - value != -999 - end - # :nocov: def inspect "#<#{self.class.name} @value=#{value}>" diff --git a/app/models/temperature_prediction.rb b/app/models/temperature_prediction.rb index cc6a2ac9..fb589cf3 100644 --- a/app/models/temperature_prediction.rb +++ b/app/models/temperature_prediction.rb @@ -1,18 +1,24 @@ class TemperaturePrediction - attr_reader :min, :max + attr_reader :min_c, :max_c, :min_f, :max_f def initialize(min:, max:) - @min = min - @max = max + @min_c = min + @max_c = max + @min_f = farenheit(min) + @max_f = farenheit(max) end def name "Temperature" end + def farenheit(celsius) + (celsius * 9 / 5) + 32 + end + # :nocov: def inspect - "#<#{self.class.name} @min=#{min} @max=#{max}>" + "#<#{self.class.name} @min=#{min_c} @max=#{max_c}>" end # :nocov: end diff --git a/app/views/forecasts/_alert_guidance.html.erb b/app/views/forecasts/_alert_guidance.html.erb index 1a27995a..b97c132e 100644 --- a/app/views/forecasts/_alert_guidance.html.erb +++ b/app/views/forecasts/_alert_guidance.html.erb @@ -1,3 +1,4 @@ + <% if @day_forecast.air_quality_alert %>

@@ -8,3 +9,4 @@

<% end %> +
diff --git a/app/views/forecasts/_bottom.html.erb b/app/views/forecasts/_bottom.html.erb deleted file mode 100644 index ace953be..00000000 --- a/app/views/forecasts/_bottom.html.erb +++ /dev/null @@ -1,6 +0,0 @@ - - <%= render "alert_guidance" %> - <%= render "predictions" %> - <%= render "sharing" %> - Forecast updated at <%= @day_forecast.air_pollution.forecasted_at.strftime("%H:%M on %A %d %B %Y") %> - \ No newline at end of file diff --git a/app/views/forecasts/_forecast_tabs.html.erb b/app/views/forecasts/_forecast_tabs.html.erb index 47646e71..bb6cadf3 100644 --- a/app/views/forecasts/_forecast_tabs.html.erb +++ b/app/views/forecasts/_forecast_tabs.html.erb @@ -1,6 +1,8 @@ -

Air pollution for <%= @zone.name %>

-
- <%= render(DayTabComponent.new(forecast: @forecasts.first, day: 'today', active: @day == 'today')) %> - <%= render(DayTabComponent.new(forecast: @forecasts.second, day: 'tomorrow', active: @day == 'tomorrow')) %> - <%= render(DayTabComponent.new(forecast: @forecasts.third, day: 'day_after_tomorrow', active: @day == 'day_after_tomorrow')) %> -
+ +

Air pollution for <%= @zone.name %>

+
+ <%= render(DayTabComponent.new(forecast: @forecasts.first, day: 'today', active: @day == 'today')) %> + <%= render(DayTabComponent.new(forecast: @forecasts.second, day: 'tomorrow', active: @day == 'tomorrow')) %> + <%= render(DayTabComponent.new(forecast: @forecasts.third, day: 'day_after_tomorrow', active: @day == 'day_after_tomorrow')) %> +
+
\ No newline at end of file diff --git a/app/views/forecasts/_how_forecasts_made.html.erb b/app/views/forecasts/_how_forecasts_made.html.erb new file mode 100644 index 00000000..c94dca3a --- /dev/null +++ b/app/views/forecasts/_how_forecasts_made.html.erb @@ -0,0 +1,11 @@ +
+
+ +

Learn how the forecasts are produced

+
+

The air quality forecasts are produced using <%= link_to("CERC's air pollution forecasting system", 'https://www.cerc.co.uk/forecast', target: '_blank') %>. Information from weather forecasts, forecasts of pollution across Europe from the <%= link_to('CAMS', 'https://atmosphere.copernicus.eu/', target: '_blank') %> Regional Ensemble and very detailed data on about 30,000 pollution sources across London are fed into the world-leading <%= link_to('ADMS-Urban', 'https://www.cerc.co.uk/environmental-software/ADMS-Urban-model.html', target: '_blank') %> air quality model to produce forecasts of air quality at a high degree of spatial resolution (10m). These forecasts are issued twice a day at about 7am and 7pm. The forecasts are updated throughout the day using real-time monitoring data from LondonAir. We compare the forecasts with observed pollution levels to assess the accuracy of the forecasts. These performance statistics are available <%= link_to('here', './pdfs/airTEXT 2023 performance.pdf', target: '_blank') %>.

+

The hourly concentrations of four pollutants are calculated: nitrogen dioxide (NO2), particulates (PM10 and PM2.5) and ozone (O3). From the hourly concentrations the daily air quality index (<%= link_to('DAQI', 'https://uk-air.defra.gov.uk/air-pollution/daqi', target: '_blank') %>) of each pollutant is derived. The overall air quality index is determined by the highest index for any of these pollutants.

+

airTEXT issues an alert for a local authority or region if at least 10% of the geographical area is predicted to reach MODERATE or above.

+

Forecast values of UV and temperature are supplied by <%= link_to('DTN', 'https://www.dtn.com/weather/', target: '_blank') %>. The pollen forecast is supplied by the <%= link_to('Met Office', 'https://www.metoffice.gov.uk/weather/warnings-and-advice/seasonal-advice/pollen-forecast', target: '_blank') %>.

+
+
diff --git a/app/views/forecasts/_predictions.html.erb b/app/views/forecasts/_predictions.html.erb index 7bf94f13..a1ea4b06 100644 --- a/app/views/forecasts/_predictions.html.erb +++ b/app/views/forecasts/_predictions.html.erb @@ -1,6 +1,9 @@ -
-

Other environmental forecasts

- <%= render(PredictionComponent.new(prediction: @day_forecast.uv)) %> - <%= render(PredictionComponent.new(prediction: @day_forecast.pollen)) if @day_forecast.pollen.valid? %> - <%= render "temperature_prediction", prediction: @day_forecast.temperature %> -
+ +
+

Other environmental forecasts

+ <%= render(PredictionComponent.new(prediction: @day_forecast.uv)) %> + <%= render(PredictionComponent.new(prediction: @day_forecast.pollen)) %> + <%= render "temperature_prediction", prediction: @day_forecast.temperature %> +
+ Forecast updated at <%= @day_forecast.air_pollution.forecasted_at.strftime("%H:%M on %A %d %B %Y") %> +
diff --git a/app/views/forecasts/_sharing.html.erb b/app/views/forecasts/_sharing.html.erb index 8b96538e..9b997241 100644 --- a/app/views/forecasts/_sharing.html.erb +++ b/app/views/forecasts/_sharing.html.erb @@ -1,37 +1,39 @@ -
- - - + diff --git a/app/views/forecasts/_temperature_prediction.html.erb b/app/views/forecasts/_temperature_prediction.html.erb index d5049746..8dfc85ae 100644 --- a/app/views/forecasts/_temperature_prediction.html.erb +++ b/app/views/forecasts/_temperature_prediction.html.erb @@ -1,7 +1,7 @@
<%= prediction.name %>
-
<%= "#{prediction.min.round}°C - #{prediction.max.round}" %>°C
+
<%= prediction.min_c.round %> to <%= prediction.max_c.round %>°C / <%= prediction.min_f.round %> to <%= prediction.max_f.round %>°F
diff --git a/app/views/forecasts/_top.html.erb b/app/views/forecasts/_top.html.erb deleted file mode 100644 index 2c64ccd5..00000000 --- a/app/views/forecasts/_top.html.erb +++ /dev/null @@ -1,4 +0,0 @@ - - <%= render "location_selector" %> - <%= render "forecast_tabs" %> - \ No newline at end of file diff --git a/app/views/forecasts/show.html.erb b/app/views/forecasts/show.html.erb index 9b2da83c..327d2fee 100644 --- a/app/views/forecasts/show.html.erb +++ b/app/views/forecasts/show.html.erb @@ -2,18 +2,23 @@ <% end %> -

Air quality forecast

-

The air quality forecast displays levels of air pollution, ultraviolet rays, pollen, and temperature over the next three days for your area of interest.

+
+

Air quality forecast

+

The air quality forecast displays levels of air pollution, ultraviolet rays, pollen, and temperature over the next three days for your area of interest.

+
- <%= render "top" %> + <%= render "location_selector" %> + <%= render "forecast_tabs" %>
+ <%= render "alert_guidance" %> <%= render "map" %> - - <%= render "bottom" %> + <%= render "predictions" %> + <%= render "sharing" %>
<%= render "subscribe" %> <%= render "learning" %> +<%= render "how_forecasts_made" %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 79db6639..a638a9bc 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -18,10 +18,7 @@ <%= render "layouts/messages" %> <%= yield %> - + <%= render "shared/footer" %>
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %> diff --git a/app/views/pages/about.html.erb b/app/views/pages/about.html.erb index d4eca35c..862046b7 100644 --- a/app/views/pages/about.html.erb +++ b/app/views/pages/about.html.erb @@ -9,7 +9,7 @@

Member local authorities pay a small annual subscription to be part of the service. The maintenance and development of the core airTEXT service is funded jointly by CERC and research projects in which CERC is involved. Grants from national and local government have contributed to airTEXT service developments in the past. airTEXT works in partnership with the GLA from time to time, for example on the Mayor of London's <%= link_to('public notifications', 'https://www.london.gov.uk/press-releases/mayoral/air-quality-alerts-warn-londoners-about-pollution', target: '_blank') %> during high pollution episodes.

How are the forecasts made?

-

The air quality forecasts are produced using <%= link_to("CERC's air pollution forecasting system", 'https://www.cerc.co.uk/forecast', target: '_blank') %>. Information from weather forecasts, forecasts of pollution across Europe from the <%= link_to('CAMS', 'https://atmosphere.copernicus.eu/', target: '_blank') %> Regional Ensemble and very detailed data on about 30,000 pollution sources across London are fed into the world-leading <%= link_to('ADMS-Urban', 'https://www.cerc.co.uk/environmental-software/ADMS-Urban-model.html', target: '_blank') %> air quality model to produce forecasts of air quality at a high degree of spatial resolution (10m). These forecasts are issued twice a day at about 7am and 7pm. The forecasts are updated throughout the day using real-time monitoring data from LondonAir. We compare the forecasts with observed pollution levels to assess the accuracy of the forecasts. These performance statistics are available <%= link_to('here', './pdfs/airTEXT 2023 performance.pdf', target: '_blank') %>.

p> +

The air quality forecasts are produced using <%= link_to("CERC's air pollution forecasting system", 'https://www.cerc.co.uk/forecast', target: '_blank') %>. Information from weather forecasts, forecasts of pollution across Europe from the <%= link_to('CAMS', 'https://atmosphere.copernicus.eu/', target: '_blank') %> Regional Ensemble and very detailed data on about 30,000 pollution sources across London are fed into the world-leading <%= link_to('ADMS-Urban', 'https://www.cerc.co.uk/environmental-software/ADMS-Urban-model.html', target: '_blank') %> air quality model to produce forecasts of air quality at a high degree of spatial resolution (10m). These forecasts are issued twice a day at about 7am and 7pm. The forecasts are updated throughout the day using real-time monitoring data from LondonAir. We compare the forecasts with observed pollution levels to assess the accuracy of the forecasts. These performance statistics are available <%= link_to('here', './pdfs/airTEXT 2023 performance.pdf', target: '_blank') %>.

The hourly concentrations of four pollutants are calculated: nitrogen dioxide (NO2), particulates (PM10 and PM2.5) and ozone (O3). From the hourly concentrations the daily air quality index (<%= link_to('DAQI', 'https://uk-air.defra.gov.uk/air-pollution/daqi', target: '_blank') %>) of each pollutant is derived. The overall air quality index is determined by the highest index for any of these pollutants.

airTEXT issues an alert for a local authority or region if at least 10% of the geographical area is predicted to reach MODERATE or above.

Forecast values of UV and temperature are supplied by <%= link_to('DTN', 'https://www.dtn.com/weather/', target: '_blank') %>. The pollen forecast is supplied by the <%= link_to('Met Office', 'https://www.metoffice.gov.uk/weather/warnings-and-advice/seasonal-advice/pollen-forecast', target: '_blank') %>.

diff --git a/app/views/pages/health_advice.html.erb b/app/views/pages/health_advice.html.erb index 22da4b7e..5a6a12bf 100644 --- a/app/views/pages/health_advice.html.erb +++ b/app/views/pages/health_advice.html.erb @@ -4,7 +4,7 @@

Health advice

Air pollution index

-

The index used to describe air quality is the <%= link_to('daily air quality index (DAQI)', 'http://uk-air.defra.gov.uk/air-pollution/daqi') %>% for the UK.

+

The index used to describe air quality is the <%= link_to('daily air quality index (DAQI)', 'http://uk-air.defra.gov.uk/air-pollution/daqi') %> for the UK.

The index represents air pollution using a 1 to 10 scale divided into four bands:

diff --git a/app/views/shared/_footer.html.erb b/app/views/shared/_footer.html.erb new file mode 100644 index 00000000..76817d8d --- /dev/null +++ b/app/views/shared/_footer.html.erb @@ -0,0 +1,18 @@ + diff --git a/app/views/shared/_footer_navigation.html.erb b/app/views/shared/_footer_navigation.html.erb deleted file mode 100644 index 999af3c1..00000000 --- a/app/views/shared/_footer_navigation.html.erb +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/app/views/shared/_header.html.erb b/app/views/shared/_header.html.erb index 981c2725..79e5ff5d 100644 --- a/app/views/shared/_header.html.erb +++ b/app/views/shared/_header.html.erb @@ -1,18 +1,17 @@ -