Skip to content

Commit

Permalink
Set active class on current forecast tab
Browse files Browse the repository at this point in the history
We define a JS TagController which is instantated 3
times, once for each tag.

There's some magic (or convention) being used here:

TARGET

`static targets = [ "day" ]` identifies the DOM element
to which we wish to bind: `"data-tab-target" = "day"`

We then refer to this element with `this.dayTarget`

CLASS HELPER

`static classes = [ "active" ]`

similar to the `dayTarget` we can now reference our active
class as `this.activeClass`

As we've now got 4 data attributes I've used the Rails
[`tag()` method][] so that we can group our data attributes
under the `data` key which I think helps readability:

```
<%= tag.div class: "tab py-4 ...",
data: {
  date: forecast.date.to_s,
  controller: "tab",
  "tab-active-class": "active",
  "tab-target": "day"
} do
%>
```

[`tag()` method][]:
https://apidock.com/rails/ActionView/Helpers/TagHelper/tag
  • Loading branch information
edavey committed Oct 24, 2024
1 parent 0e1fec2 commit b71ff51
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 41 deletions.
8 changes: 0 additions & 8 deletions app/javascript/controllers/forecasts_controller.js

This file was deleted.

5 changes: 2 additions & 3 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@

import { application } from "./application"

import ForecastsController from "./forecasts_controller"
application.register("forecasts", ForecastsController)

import TabController from "./tab_controller"
application.register("tab", TabController)
21 changes: 21 additions & 0 deletions app/javascript/controllers/tab_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="tab"
export default class extends Controller {
static classes = [ "active" ]
static targets = [ "day" ]

connect() {
}

switch_tab() {
this.makeAllTabsInactive()
this.dayTarget.classList.toggle(this.activeClass)
}

makeAllTabsInactive() {
document.querySelectorAll('.tabs .tab').forEach(
(el) => el.classList.remove(this.activeClass)
)
}
}
50 changes: 31 additions & 19 deletions app/views/styled_forecasts/_day_tab.html.erb
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
<div class="tab py-4 flex-1 <%= day %> mx-2 px-1 text-center daqi-low border-b-0 border-l-2 border-r-2 border-t-2 border-gray-300" data-date="<%= forecast.date %>" >
<%= link_to update_styled_forecast_path(day: day), data: { turbo_frame: "day_predictions" } do %>
<div class="day">
<%= forecast.date == Date.today ? 'Today' : forecast.date.strftime('%A') %>
</div>
<div class="date">
<%= forecast.date.strftime("%d %B") %>
</div>
<div class="daqi-marker text-4xl py-2 text-green-600">
</div>
<div class="daqi-label text-base">
<%= forecast.air_pollution.label.capitalize %>
</div>
<div class="daqi-value font-normal">
Index <%= forecast.air_pollution.value %>/10
</div>
<% end %>
</div>
<%= tag.div class: "tab py-4 flex-1 #{day} mx-2 px-1 text-center daqi-low border-b-0 border-l-2 border-r-2 border-t-2 border-gray-300 #{day == :today ? "active" : ''}",
data: {
date: forecast.date.to_s,
controller: "tab",
"tab-active-class": "active",
"tab-target": "day"
} do
%>
<%=
link_to update_styled_forecast_path(day: day),
data: {
turbo_frame: "day_predictions",
action: "click->tab#switch_tab"
} do %>
<div class="day">
<%= forecast.date == Date.today ? 'Today' : forecast.date.strftime('%A') %>
</div>
<div class="date">
<%= forecast.date.strftime("%d %B") %>
</div>
<div class="daqi-marker text-4xl py-2 text-green-600">
</div>
<div class="daqi-label text-base">
<%= forecast.air_pollution.label.capitalize %>
</div>
<div class="daqi-value font-normal">
Index <%= forecast.air_pollution.value %>/10
</div>
<% end %>
<% end %>
5 changes: 4 additions & 1 deletion app/views/styled_forecasts/_forecast_tabs.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<header class="text-xl px-4 font-bold">
Air pollution
</header>
<div class="tabs flex flex-row items-stretch mt-4 m-1 text-xs font-bold" data-turbo-prefetch="false">
<div
class="tabs flex flex-row items-stretch mt-4 m-1 text-xs font-bold"
data-turbo-prefetch="false"
>
<%= render "day_tab", forecast: @forecasts.first, day: :today %>
<%= render "day_tab", forecast: @forecasts.second, day: :tomorrow %>
<%= render "day_tab", forecast: @forecasts.third, day: :day_after_tomorrow %>
Expand Down
14 changes: 6 additions & 8 deletions app/views/styled_forecasts/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<div data-controller="forecasts">
<%= render partial: "styled_forecasts/location" %>
<%= render partial: "styled_forecasts/forecast_tabs", forecasts: @forecasts %>
<%= render partial: "styled_forecasts/predictions", locals: { forecast: @forecasts.first } %>
<%= render partial: "sharing" %>
<%= render partial: "learning" %>
<%= render partial: "subscribe" %>
</div>
<%= render partial: "styled_forecasts/location" %>
<%= render partial: "styled_forecasts/forecast_tabs", forecasts: @forecasts %>
<%= render partial: "styled_forecasts/predictions", locals: { forecast: @forecasts.first } %>
<%= render partial: "sharing" %>
<%= render partial: "learning" %>
<%= render partial: "subscribe" %>
21 changes: 21 additions & 0 deletions spec/feature_steps/forecast_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,27 @@ def and_i_see_predicted_uv_level_v2
expect_prediction_v2(category: "ultraviolet-rays-uv", value: "Low")
end

def then_i_see_that_the_tomorrow_tab_is_active
expect(page).to have_css(".tab.tomorrow.active")

expect(page).not_to have_css(".tab.today.active")
expect(page).not_to have_css(".tab.day_after_tomorrow.active")
end

def and_i_see_that_the_today_tab_is_active
expect(page).to have_css(".tab.today.active")

expect(page).not_to have_css(".tab.tomorrow.active")
expect(page).not_to have_css(".tab.day_after_tomorrow.active")
end

def then_i_see_that_the_day_after_tomorrow_tab_is_active
expect(page).to have_css(".tab.day_after_tomorrow.active")

expect(page).not_to have_css(".tab.today.active")
expect(page).not_to have_css(".tab.tomorrow.active")
end

def and_i_see_predicted_uv_level_for_tomorrow
expect_styled_prediction(category: :"ultraviolet-rays-uv", level: :moderate)
end
Expand Down
6 changes: 4 additions & 2 deletions spec/features/visitors/view_styled_forecasts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
visit root_path
when_i_select_view_forecasts_v2
then_i_see_the_forecasts_page_v2

and_i_see_that_the_today_tab_is_active
and_i_see_predicted_air_pollution_status_for_each_day_v2
and_i_see_predicted_uv_level_v2
and_i_see_predicted_pollen_level_v2
Expand All @@ -40,7 +42,7 @@
when_i_select_view_forecasts_v2
and_i_switch_to_the_tab_for_tomorrow

# then I see that the _tomorrow_ tab is active
then_i_see_that_the_tomorrow_tab_is_active
and_i_see_predicted_uv_level_for_tomorrow
and_i_see_predicted_pollen_level_for_tomorrow
and_i_see_predicted_temperature_level_for_tomorrow
Expand All @@ -56,7 +58,7 @@
when_i_select_view_forecasts_v2
and_i_switch_to_the_tab_for_day_after_tomorrow

# then I see that the _day_after_tomorrow_ tab is active
then_i_see_that_the_day_after_tomorrow_tab_is_active
and_i_see_predicted_uv_level_for_day_after_tomorrow
and_i_see_predicted_pollen_level_for_day_after_tomorrow
and_i_see_predicted_temperature_level_for_day_after_tomorrow
Expand Down

0 comments on commit b71ff51

Please sign in to comment.