ahoy_captain 0.10.1 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +23 -2
  3. data/app/assets/javascript/ahoy_captain/controllers/application_controller.js +12 -0
  4. data/app/assets/javascript/ahoy_captain/controllers/combobox_controller.js +50 -20
  5. data/app/assets/javascript/ahoy_captain/controllers/frame_link_controller.js +20 -0
  6. data/app/assets/javascript/ahoy_captain/controllers/line_chart_controller.js +67 -4
  7. data/app/assets/javascript/ahoy_captain/controllers/map_controller.js +47 -0
  8. data/app/assets/javascript/ahoy_captain/controllers/predicate_select_controller.js +1 -0
  9. data/app/assets/javascript/ahoy_captain/controllers/tile_controller.js +25 -1
  10. data/app/assets/javascript/ahoy_captain/helpers/countries.js +2261 -0
  11. data/app/components/ahoy_captain/combobox_component.html.erb +2 -2
  12. data/app/components/ahoy_captain/combobox_component.rb +1 -1
  13. data/app/components/ahoy_captain/comparison_link_component.html.erb +17 -0
  14. data/app/components/ahoy_captain/comparison_link_component.rb +10 -6
  15. data/app/components/ahoy_captain/dropdown_link_component.html.erb +2 -4
  16. data/app/components/ahoy_captain/dropdown_link_component.rb +4 -0
  17. data/app/components/ahoy_captain/previous_next_component.html.erb +8 -0
  18. data/app/components/ahoy_captain/previous_next_component.rb +11 -0
  19. data/app/components/ahoy_captain/stats/comparable_container_component.html.erb +1 -1
  20. data/app/components/ahoy_captain/stats/container_component.html.erb +1 -1
  21. data/app/components/ahoy_captain/sticky_nav_component.html.erb +26 -22
  22. data/app/components/ahoy_captain/sticky_nav_component.rb +8 -0
  23. data/app/components/ahoy_captain/tile_component.rb +7 -0
  24. data/app/controllers/ahoy_captain/locations/cities_controller.rb +22 -0
  25. data/app/controllers/ahoy_captain/locations/countries_controller.rb +22 -0
  26. data/app/controllers/ahoy_captain/locations/maps_controller.rb +24 -0
  27. data/app/controllers/ahoy_captain/locations/regions_controller.rb +22 -0
  28. data/app/helpers/ahoy_captain/application_helper.rb +0 -2
  29. data/app/models/ahoy_captain/range_from_params.rb +4 -1
  30. data/app/views/ahoy_captain/layouts/shared/_tile_loader.html.erb +12 -0
  31. data/app/views/ahoy_captain/locations/maps/show.html.erb +3 -0
  32. data/app/views/ahoy_captain/properties/_form.html.erb +1 -1
  33. data/app/views/ahoy_captain/roots/show.html.erb +89 -57
  34. data/app/views/ahoy_captain/stats/base/index.html.erb +1 -0
  35. data/app/views/ahoy_captain/stats/show.html.erb +13 -8
  36. data/config/routes.rb +7 -3
  37. data/lib/ahoy_captain/filters_configuration.rb +5 -5
  38. data/lib/ahoy_captain/version.rb +1 -1
  39. data/lib/ahoy_captain.rb +1 -0
  40. metadata +104 -12
  41. data/app/assets/javascript/ahoy_captain/controllers/active_links_controller.js +0 -30
  42. data/app/controllers/ahoy_captain/cities_controller.rb +0 -20
  43. data/app/controllers/ahoy_captain/countries_controller.rb +0 -20
  44. data/app/controllers/ahoy_captain/regions_controller.rb +0 -20
  45. /data/app/views/ahoy_captain/{cities → locations/cities}/index.html+details.erb +0 -0
  46. /data/app/views/ahoy_captain/{cities → locations/cities}/index.html.erb +0 -0
  47. /data/app/views/ahoy_captain/{countries → locations/countries}/index.html+details.erb +0 -0
  48. /data/app/views/ahoy_captain/{countries → locations/countries}/index.html.erb +0 -0
  49. /data/app/views/ahoy_captain/{regions → locations/regions}/index.html+details.erb +0 -0
  50. /data/app/views/ahoy_captain/{regions → locations/regions}/index.html.erb +0 -0
@@ -10,7 +10,7 @@
10
10
  >
11
11
  <div data-action="click->combobox#toggleOpen" data-combobox-target="box"
12
12
  class="
13
- bg-gray-900 ring-0 focus-within:ring-0 focus-within:ring-0 focus:ring-0 focus:outline-none w-full rounded-md px-4 py-2 text-sm
13
+ bg-gray-900 ring-0 focus-within:ring-0 focus-within:ring-0 focus:ring-0 focus:outline-none w-full rounded-md py-2 text-sm
14
14
  w-full"
15
15
  data-combobox-box-open-class="border-secondary-500 ring-1 ring-secondary-500">
16
16
  <select data-combobox-target="select" style="display:none;"
@@ -19,7 +19,7 @@
19
19
  id="<%= @select_html[:id] || "filter_#{@name}" %>"
20
20
  <% @select_html.each do |k,v| %><%=k %>="<%=v %>"<% end %>
21
21
  ><% @value.each do |value| %><option value="<%= value %>" selected><%= value %></option><% end %></select>
22
- <div data-combobox-target="selected" class="" style="display:none;"></div>
22
+ <div data-combobox-target="selected" class="px-2" style="display:none;"></div>
23
23
  <input data-combobox-target="input"
24
24
  data-action="input->combobox#onInput"
25
25
  class="input input-sm input-ghost w-full inline-block rounded-md focus:outline-none focus:ring-0 focus:bg-gray-900"
@@ -5,7 +5,7 @@ module AhoyCaptain
5
5
  @multiple = multiple
6
6
  @column = column
7
7
  @url = url
8
- @value = value
8
+ @value = Array(value)
9
9
  @select_html = select_html
10
10
  @disabled = disabled
11
11
  end
@@ -0,0 +1,17 @@
1
+ <div class="dropdown dropdown-end" data-controller='dropdown-label'>
2
+ <label
3
+ tabindex="0"
4
+ class="cursor-pointer flex <%= classes %>"
5
+ data-action='click->dropdown-label#removeHidden'
6
+ >
7
+ <span data-dropdown-label-target="label"><%= title %></span>
8
+
9
+ </label>
10
+ <ul class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52" data-dropdown-label-target="close">
11
+ <% links.each do |link| %>
12
+ <li data-action="click->dropdown-label#setLabel">
13
+ <%= link %>
14
+ <li>
15
+ <% end %>
16
+ </ul>
17
+ </div>
@@ -1,17 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AhoyCaptain::ComparisonLinkComponent < AhoyCaptain::DropdownLinkComponent
3
+ class AhoyCaptain::ComparisonLinkComponent < ViewComponent::Base
4
4
  include ::AhoyCaptain::CompareMode
5
5
  include ::AhoyCaptain::RangeOptions
6
6
  include ::AhoyCaptain::Rangeable
7
7
 
8
+ renders_many :links
9
+ renders_one :header
10
+
11
+ attr_reader :title, :classes
8
12
  def initialize(title: "", classes: "btn btn-sm btn-base-100 no-underline hover:bg-base-100")
9
13
  @classes = classes
10
14
  end
11
15
 
12
16
  # cheating
13
17
  def title
14
- self.with_option_content(options_for_option)
18
+ self.with_link_content(options_for_option)
15
19
 
16
20
  comparison_mode.label
17
21
  end
@@ -22,12 +26,12 @@ class AhoyCaptain::ComparisonLinkComponent < AhoyCaptain::DropdownLinkComponent
22
26
 
23
27
  def options_for_option
24
28
  [
25
- (link_to "Disable Comparison", AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: false))),
26
- (link_to "Previous period", AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: :previous)), class: selected(:previous, :true)),
27
- (link_to "Year-over-year", AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: :year)), class: selected(:year)),
28
29
  (link_to "Custom period", "javascript:customComparisonModal.showModal()", class: selected(:custom)),
30
+ (link_to "Year-over-year", AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: :year)), class: selected(:year)),
31
+ (link_to "Previous period", AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: :previous)), class: selected(:previous, :true)),
32
+ (link_to "Disable Comparison", AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: false))),
29
33
 
30
- ].join.html_safe
34
+ ].reverse.join.html_safe
31
35
  end
32
36
 
33
37
  private
@@ -1,13 +1,11 @@
1
- <div class="dropdown dropdown-end " data-controller='dropdown-label'>
1
+ <div class="dropdown dropdown-end" data-controller='dropdown-label'>
2
2
  <label
3
3
  tabindex="0"
4
4
  class="cursor-pointer flex <%= classes %>"
5
5
  data-action='click->dropdown-label#removeHidden'
6
6
  >
7
7
  <span data-dropdown-label-target="label"><%= title %></span>
8
- <svg class="h-8 w-8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
9
- <path fill="currentColor" d="M16.53 8.97a.75.75 0 0 1 0 1.06l-4 4a.75.75 0 0 1-1.06 0l-4-4a.75.75 0 1 1 1.06-1.06L12 12.44l3.47-3.47a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" />
10
- </svg>
8
+
11
9
  </label>
12
10
  <ul class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52" data-dropdown-label-target="close">
13
11
  <% options.each do |option| %>
@@ -9,6 +9,10 @@ class AhoyCaptain::DropdownLinkComponent < ViewComponent::Base
9
9
  @classes = classes
10
10
  end
11
11
 
12
+ def link_to(name, url, **options)
13
+ self.with_option_content view_context.link_to name, url, options
14
+ end
15
+
12
16
  private
13
17
 
14
18
  attr_reader :title, :classes
@@ -0,0 +1,8 @@
1
+ <div class="rounded shadow bg-white cursor-pointer dark:bg-gray-800 flex h-8">
2
+ <button class="flex items-center px-1 sm:px-2 border-r border-gray-300 rounded-l dark:border-gray-500 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-900" type="button">
3
+ <svg class="feather h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
4
+ </button>
5
+ <button class="flex items-center px-1 sm:px-2 rounded-r dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-900" type="button">
6
+ <svg class="feather h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
7
+ </button>
8
+ </div>
@@ -0,0 +1,11 @@
1
+ module AhoyCaptain
2
+ class PreviousNextComponent < ViewComponent::Base
3
+ def initialize(range)
4
+ @range = range
5
+ end
6
+
7
+ def render?
8
+ false
9
+ end
10
+ end
11
+ end
@@ -1,4 +1,4 @@
1
- <a href="<%= @url %>" class="relative px-4 md:px-6 w-1/2 my-4 w-auto group cursor-pointer" data-turbo-frame="chart">
1
+ <a href="<%= @url %>" class="relative px-4 md:px-6 w-1/2 my-4 w-auto group cursor-pointer" data-controller="frame-link" data-turbo-frame="chart">
2
2
  <div>
3
3
  <h5 class="text-sm font-bold uppercase whitespace-nowrap flex w-content border-transparent tooltip tooltip-bottom "
4
4
  data-active-links-target="link" data-tip="<%= tooltip %>">
@@ -1,4 +1,4 @@
1
- <a href="<%= @url %>" class="relative px-4 md:px-6 w-1/2 my-4 lg:w-auto group cursor-pointer" data-turbo-frame="chart">
1
+ <a href="<%= @url %>" class="relative px-4 md:px-6 w-1/2 my-4 lg:w-auto group cursor-pointer" data-controller="frame-link" data-turbo-frame="chart">
2
2
  <div>
3
3
  <h5 class="text-sm font-bold uppercase whitespace-nowrap flex w-content border-transparent tooltip tooltip-bottom "
4
4
  data-active-links-target="link">
@@ -1,28 +1,32 @@
1
- <div class="max-w-6xl flex justify-between sticky top-0 min-h-sm z-[99999] py-4 bg-base-100">
2
- <div class="flex items-center">
3
- <a href="/">
4
- <img src="<%= image_path "ahoy_captain/logo.png" %>" alt="AhoyCaptainLogo" class='max-h-20 md:h-16 rounded-full'>
5
- </a>
6
- <% if tag_list_hidden? %>
7
- <%= render AhoyCaptain::Filter::TagContainerComponent.new %>
8
- <% else %>
9
- <%= realtime_update %>
10
- <% end %>
11
- </div>
12
- <div class="flex flex-row-reverse col-span-2 items-center gap-3">
13
- <%= render AhoyCaptain::ComparisonLinkComponent.new %>
1
+ <div class=" sticky top-0 min-h-sm z-[99999] py-4 bg-base-100 pb-4">
2
+ <div class="max-w-6xl mx-auto max-w-6xl flex justify-between ">
3
+ <div class="flex items-center">
4
+ <a href="/">
5
+ <img src="<%= image_path "ahoy_captain/logo.png" %>" alt="AhoyCaptainLogo" class='max-h-20 md:h-16 rounded-full'>
6
+ </a>
7
+ <% if tag_list_hidden? %>
8
+ <%= render AhoyCaptain::Filter::TagContainerComponent.new %>
9
+ <% else %>
10
+ <%= realtime_update %>
11
+ <% end %>
12
+ </div>
13
+ <div class="flex flex-row-reverse col-span-2 items-center gap-3">
14
+ <%= render AhoyCaptain::ComparisonLinkComponent.new %>
15
+ <%= render AhoyCaptain::PreviousNextComponent.new(range) %>
14
16
 
15
- <%= render AhoyCaptain::DropdownLinkComponent.new(title: params[:start_date] ? "Custom Range" : (AhoyCaptain.config.ranges.find(params[:period] || AhoyCaptain.config.ranges.default).try(:label) || "Period"), classes: 'btn btn-sm btn-base-100 no-underline hover:bg-base-100') do |dropdown| %>
16
- <% dropdown.with_option do %>
17
- <% AhoyCaptain.config.ranges.each do |param, range| %>
18
- <a class='link no-underline' href="<%= request.path %>?<%= request.query_parameters.except("start_date", "end_date", "date", "compare_to_start_date", "compare_to_end_date").merge("period" => param).to_query %>"><%= range.label %></a>
19
- <% end %>
17
+ <%= render AhoyCaptain::DropdownLinkComponent.new(title: params[:start_date] ? custom_range_label : (AhoyCaptain.config.ranges.find(params[:period] || AhoyCaptain.config.ranges.default).try(:label) || "Period"), classes: 'btn btn-sm btn-base-100 no-underline hover:bg-base-100') do |dropdown| %>
18
+ <% dropdown.with_option do %>
19
+ <% AhoyCaptain.config.ranges.each do |param, range| %>
20
+ <a class='link no-underline' href="<%= request.path %>?<%= request.query_parameters.except("start_date", "end_date", "date", "compare_to_start_date", "compare_to_end_date").merge("period" => param).to_query %>"><%= range.label %></a>
21
+ <% end %>
20
22
 
21
- <a class='link no-underline ' href='#' onclick="event.preventDefault(); customRangeModal.showModal()">Custom range</a>
22
- <a class='link no-underline ' href='<%= AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: !compare_mode?)) %>'><%= compare_mode? ? "Disable Comparison" : "Compare" %></a>
23
+ <a class='link no-underline ' href='#' onclick="event.preventDefault(); customRangeModal.showModal()">Custom Range</a>
24
+ <a class='link no-underline ' href='<%= AhoyCaptain::Engine.routes.url_helpers.root_path(**helpers.search_params.merge(comparison: !compare_mode?)) %>'><%= compare_mode? ? "Disable Comparison" : "Compare" %></a>
25
+ <% end %>
23
26
  <% end %>
24
- <% end %>
25
27
 
26
- <%= render AhoyCaptain::Filter::DropdownComponent.new(filters: filters) %>
28
+ <%= render AhoyCaptain::Filter::DropdownComponent.new(filters: filters) %>
29
+ </div>
27
30
  </div>
31
+
28
32
  </div>
@@ -10,6 +10,14 @@ class AhoyCaptain::StickyNavComponent < ViewComponent::Base
10
10
  @filters ||= ::AhoyCaptain::FilterParser.parse(request)
11
11
  end
12
12
 
13
+ def custom_range_label
14
+ if range.custom?
15
+ [range.starts_at, range.ends_at].map { |date| date.strftime('%b %d, %Y') }.join("-")
16
+ else
17
+ "Custom Range"
18
+ end
19
+ end
20
+
13
21
  def tag_list_hidden?
14
22
  filters.values.map(&:values).flatten.size < ::AhoyCaptain::FilterParser::FILTER_MENU_MAX_SIZE
15
23
  end
@@ -11,6 +11,13 @@ class AhoyCaptain::TileComponent < ViewComponent::Base
11
11
  @wide = wide
12
12
  end
13
13
 
14
+ def link_to(name, url, **options)
15
+ options[:class] = "inline-block h-5 font-semibold"
16
+ options[:data] ||= {}
17
+ options[:data].merge!(controller: "frame-link")
18
+ view_context.link_to name, url, **options
19
+ end
20
+
14
21
  private
15
22
 
16
23
  attr_reader :title, :wide
@@ -0,0 +1,22 @@
1
+ module AhoyCaptain
2
+ module Locations
3
+ class CitiesController < ApplicationController
4
+ include AhoyCaptain::Limitable
5
+
6
+ before_action do
7
+ if Widget.disabled?(:locations, :cities)
8
+ raise Widget::WidgetDisabled.new("Widget disabled", :geography)
9
+ end
10
+ end
11
+
12
+ def index
13
+ results = cached(:cities) do
14
+ CityQuery.call(params)
15
+ .limit(limit)
16
+ end
17
+
18
+ @cities = paginate(results).map { |city| CityDecorator.new(city, self) }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module AhoyCaptain
2
+ module Locations
3
+ class CountriesController < ApplicationController
4
+ include Limitable
5
+
6
+ before_action do
7
+ if Widget.disabled?(:locations, :countries)
8
+ raise Widget::WidgetDisabled.new("Widget disabled", :geography)
9
+ end
10
+ end
11
+
12
+ def index
13
+ results = cached(:countries) do
14
+ CountryQuery.call(params)
15
+ .limit(limit)
16
+ end
17
+
18
+ @countries = paginate(results).map { |country| CountryDecorator.new(country, self) }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ module AhoyCaptain
2
+ module Locations
3
+ class MapsController < ApplicationController
4
+ include Limitable
5
+
6
+ before_action do
7
+ if Widget.disabled?(:locations, :map)
8
+ raise Widget::WidgetDisabled.new("Widget disabled", :geography)
9
+ end
10
+ end
11
+
12
+ def show
13
+ if request.variant.include?(:details)
14
+ results = CountryQuery.call(params)
15
+ results = results.limit(limit)
16
+ @countries = paginate(results).map { |country| CountryDecorator.new(country, self) }
17
+ render template: 'ahoy_captain/locations/countries/index'
18
+ else
19
+ @countries = visit_query.group("country").count
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ module AhoyCaptain
2
+ module Locations
3
+ class RegionsController < ApplicationController
4
+ include Limitable
5
+
6
+ before_action do
7
+ if Widget.disabled?(:locations, :regions)
8
+ raise Widget::WidgetDisabled.new("Widget disabled", :geography)
9
+ end
10
+ end
11
+
12
+ def index
13
+ results = cached(:regions) do
14
+ RegionQuery.call(params)
15
+ .limit(limit)
16
+ end
17
+
18
+ @regions = paginate(results).map { |region| RegionDecorator.new(region, self) }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -56,8 +56,6 @@ module AhoyCaptain
56
56
  :period,
57
57
  :interval,
58
58
  :comparison,
59
- :compare_to_start_date,
60
- :compare_to_end_date
61
59
  ]
62
60
 
63
61
  # properties stuff falls into current_property_filter
@@ -1,7 +1,6 @@
1
1
  module AhoyCaptain
2
2
  class RangeFromParams
3
3
  def self.from_params(params)
4
-
5
4
  compare = ComparisonMode.new(params)
6
5
  new(period: params[:period], start_date: params[:start_date], end_date: params[:end_date], date: params[:date], comparison: compare.enabled?(false), raw: params).tap { |instance| instance.build }
7
6
  end
@@ -53,6 +52,10 @@ module AhoyCaptain
53
52
  @range.end.nil?
54
53
  end
55
54
 
55
+ def custom?
56
+ @raw[:start_date].present? && @raw[:end_date].present?
57
+ end
58
+
56
59
  def [](value)
57
60
  if value == 0
58
61
  starts_at
@@ -0,0 +1,12 @@
1
+ <div class="mt-5" >
2
+ <div role="status" class="animate-pulse">
3
+ <div class="flex justify-between w-full mb-2">
4
+ <div class="h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-32"></div>
5
+ <div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24"></div>
6
+ </div>
7
+ <% 10.times do |i| %>
8
+ <div class="h-6 bg-gray-200 dark:bg-gray-700 max-w-[<%= 100 - (i * 10) %>%] mb-2.5"></div>
9
+ <% end %>
10
+ <span class="sr-only">Loading...</span>
11
+ </div>
12
+ </div>
@@ -0,0 +1,3 @@
1
+ <%= turbo_frame_tag :geography do %>
2
+ <canvas style="position: relative; width: 500px; height: 300px;" data-controller="map" data-map-data-value="<%= @countries.to_json %>"></canvas>
3
+ <% end %>
@@ -1,4 +1,4 @@
1
- <select class="select text-accent-content bg-accent" data-controller="properties" data-action="change->properties#handleChange">
1
+ <select class="select text-accent select-sm w-full max-w-sm" data-controller="properties" data-action="change->properties#handleChange">
2
2
  <option></option>
3
3
  <% @options.each do |key, value| %>
4
4
  <option value="<%= property_path(id: key) %>" <%= 'selected' if local_assigns[:selected] == value %>><%= value %></option>
@@ -1,40 +1,66 @@
1
- <main class='min-h-screen pb-4 max-w-6xl mx-auto' data-controller="application" data-action="combobox:init@window->application#comboboxInit">
1
+ <main class='w-screen overflow-hidden' data-action="combobox:init@window->application#comboboxInit">
2
+ <script id="tile-loader-template" type="template/html">
3
+ <%= render '/ahoy_captain/layouts/shared/tile_loader' %>
4
+ </script>
2
5
  <%= render AhoyCaptain::StickyNavComponent.new do |nav| %>
3
6
  <% nav.with_realtime_update do %>
4
7
  <%= turbo_frame_tag :realtime, src: realtime_path, data: { controller: "realtime", "realtime-interval-value" => AhoyCaptain.config.realtime_interval.to_i }, loading: :lazy %>
5
8
  <% end %>
6
9
  <% end %>
7
10
 
8
- <div class="grid grid-cols-1 lg:grid-cols-2 grid-flow-row gap-4">
11
+ <div class="grid grid-cols-1 lg:grid-cols-2 grid-flow-row gap-4 min-h-screen pb-4 max-w-6xl mx-auto">
9
12
  <%= render AhoyCaptain::TileComponent.new(wide: true, classes: "p-4 m-2") do |component| %>
10
13
  <% component.with_statistic_display do %>
11
- <%= turbo_frame_tag :stats, src: stats_path(search_params), loading: :lazy %>
12
-
14
+ <%= turbo_frame_tag :stats, src: stats_path(search_params), loading: :lazy, skeleton: false do %>
15
+ <div class="grid grid-cols-1 divide-y divide-base-200 overflow-hidden rounded-lg grid-cols-2 md:grid-cols-6 md:divide-y-0">
16
+ <% 6.times do %>
17
+ <div class="relative px-4 md:px-6 w-1/2 my-4 w-auto group cursor-pointer" >
18
+ <div role="status" class="max-w-sm animate-pulse">
19
+ <div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[120px] mb-2.5"></div>
20
+ <div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5 max-w-[60px]"></div>
21
+ <span class="sr-only">Loading...</span>
22
+ </div>
23
+ </div>
24
+ <% end %>
25
+ </div>
26
+ <% end %>
13
27
  <%= turbo_frame_tag :chart, src: stats_unique_visitors_path(search_params) do %>
28
+ <div role="status" class="p-4 animate-pulse md:p-6">
29
+ <div class="flex items-baseline mt-4 space-x-6">
30
+ <div class="w-full bg-gray-200 rounded-t-lg h-72 dark:bg-gray-700"></div>
31
+ <div class="w-full h-56 bg-gray-200 rounded-t-lg dark:bg-gray-700"></div>
32
+ <div class="w-full bg-gray-200 rounded-t-lg h-72 dark:bg-gray-700"></div>
33
+ <div class="w-full h-64 bg-gray-200 rounded-t-lg dark:bg-gray-700"></div>
34
+ <div class="w-full bg-gray-200 rounded-t-lg h-80 dark:bg-gray-700"></div>
35
+ <div class="w-full bg-gray-200 rounded-t-lg h-72 dark:bg-gray-700"></div>
36
+ <div class="w-full bg-gray-200 rounded-t-lg h-80 dark:bg-gray-700"></div>
37
+ </div>
38
+ <span class="sr-only">Loading...</span>
39
+ </div>
14
40
  <% end %>
15
41
  <% end %>
16
42
 
17
43
  <% end %>
18
44
 
19
45
  <%= render AhoyCaptain::TileComponent.new(title: 'Top Sources') do |component| %>
20
- <% component.with_display_links do %>
21
- <div data-controller="active-links">
22
- <a href="<%= sources_path(search_params) %>" data-turbo-frame="sources" class="" data-active-links-target="link">All</a>
23
- <%= render AhoyCaptain::DropdownLinkComponent.new(title: "Campaign") do |dropdown| %>
24
- <% %w{utm_source utm_medium utm_term utm_content utm_campaign}.each do |source| %>
25
- <% dropdown.with_option do %>
26
- <a href="<%= public_send("campaign_#{source}_path".to_sym, **search_params) %>" class=""
27
- data-turbo-frame="sources"
28
- data-active-links-target="link">
29
- <%= source.titleize.gsub("Utm", "UTM") %>
30
- </a>
46
+ <% component.with_display_links do %>
47
+ <div class="flex text-xs font-medium text-gray-400 space-x-2">
48
+ <div class="relative inline-block text-left">
49
+ <%= component.link_to "All", sources_path(search_params), data: { turbo_frame: "sources" } %>
50
+ <%= render AhoyCaptain::DropdownLinkComponent.new(title: "Campaign") do |dropdown| %>
51
+ <% %w{utm_source utm_medium utm_term utm_content utm_campaign}.each do |source| %>
52
+ <%= dropdown.link_to source.titleize.gsub("Utm", "UTM"), public_send("campaign_#{source}_path".to_sym, **search_params), data: { turbo_frame: "sources" } %>
31
53
  <% end %>
32
54
  <% end %>
33
- <% end %>
55
+ </div>
34
56
  </div>
57
+
58
+
35
59
  <% end %>
36
60
  <% component.with_statistic_display do %>
37
- <%= turbo_frame_tag :sources, src: sources_path(search_params), loading: :lazy %>
61
+ <%= turbo_frame_tag :sources, src: sources_path(search_params), loading: :lazy do %>
62
+ <%= render '/ahoy_captain/layouts/shared/tile_loader' %>
63
+ <% end %>
38
64
  <% end %>
39
65
  <% component.with_details_cta do %>
40
66
  <button data-action="click->details-modal#openModal" data-controller="details-modal" data-details-modal-target-value="#sources" class="link no-underline ">Details</button>
@@ -44,59 +70,62 @@
44
70
  <%= render AhoyCaptain::TileComponent.new(title: 'Top Pages') do |component| %>
45
71
  <% component.with_display_links do %>
46
72
  <div class="flex text-xs font-medium text-gray-400 space-x-2">
47
- <div class="relative inline-block text-left" data-controller="active-links"><div>
48
- <a href="<%= top_pages_path(search_params) %>"
49
- data-turbo-frame="pages"
50
- class="inline-block h-5 font-semibold"
51
- data-active-links-target="link"
52
- data-action="click->tile#setTitle">Top Pages</a>
53
- <a href="<%= entry_pages_path(search_params) %>" data-turbo-frame="pages" class="inline-block h-5 font-semibold" data-active-links-target="link" data-action="click->tile#setTitle">Entry Pages</a>
54
- <a href="<%= exit_pages_path(search_params) %>" data-turbo-frame="pages" class="inline-block h-5 font-semibold" data-active-links-target="link" data-action="click->tile#setTitle">Exit Pages</a>
73
+ <div class="relative inline-block text-left"><div>
74
+ <%= component.link_to "Top Pages", top_pages_path(search_params), data: { action: "click->tile#setTitle", turbo_frame: "pages" } %>
75
+ <%= component.link_to "Entry Pages", entry_pages_path(search_params), data: { action: "click->tile#setTitle", turbo_frame: "pages" } %>
76
+ <%= component.link_to "Exit Pages", exit_pages_path(search_params), data: { action: "click->tile#setTitle", turbo_frame: "pages" } %>
55
77
  </div>
56
78
  </div>
57
79
  </div>
58
80
 
59
81
  <% end %>
60
82
  <% component.with_statistic_display do %>
61
- <%= turbo_frame_tag :pages, src: top_pages_path(search_params), loading: :lazy %>
83
+ <%= turbo_frame_tag :pages, src: top_pages_path(search_params), loading: :lazy do %>
84
+ <%= render '/ahoy_captain/layouts/shared/tile_loader' %>
85
+ <% end %>
62
86
  <% end %>
63
87
  <% component.with_details_cta do %>
64
88
  <button data-action="click->details-modal#openModal" data-controller="details-modal" data-details-modal-target-value="#pages" class="link no-underline ">Details</button>
65
89
  <% end %>
66
90
  <% end %>
67
91
 
68
- <%= render AhoyCaptain::TileComponent.new(title: 'Countries') do |component| %>
92
+ <%= render AhoyCaptain::TileComponent.new(title: 'Map') do |component| %>
69
93
  <% component.with_display_links do %>
70
94
  <div class="flex text-xs font-medium text-gray-400 space-x-2">
71
- <div class="relative inline-block text-left" data-controller="active-links">
72
-
73
- <a href="<%= countries_path(search_params) %>" data-turbo-frame="geography" class="inline-block h-5 font-semibold" data-active-links-target="link" data-action="click->tile#setTitle">Countries</a>
74
- <a href="<%= regions_path(search_params) %>" data-turbo-frame="geography" class="inline-block h-5 font-semibold" data-active-links-target="link" data-action="click->tile#setTitle">Regions</a>
75
- <a href="<%= cities_path(search_params) %>" data-turbo-frame="geography" class="inline-block h-5 font-semibold" data-active-links-target="link" data-action="click->tile#setTitle">Cities</a>
95
+ <div class="relative inline-block text-left">
96
+ <%= component.link_to "Map", locations_map_path(search_params), data: { action: "click->tile#setTitle", turbo_frame: "geography" } %>
97
+ <%= component.link_to "Countries", locations_countries_path(search_params), data: { action: "click->tile#setTitle", turbo_frame: "geography" } %>
98
+ <%= component.link_to "Regions", locations_regions_path(search_params), data: { action: "click->tile#setTitle", turbo_frame: "geography" } %>
99
+ <%= component.link_to "Cities", locations_cities_path(search_params), data: { action: "click->tile#setTitle", turbo_frame: "geography" } %>
76
100
  </div>
77
101
  </div>
78
102
  <% end %>
79
103
  <% component.with_statistic_display do %>
80
- <%= turbo_frame_tag :geography, src: countries_path(search_params), loading: :lazy %>
104
+ <%= turbo_frame_tag :geography, src: locations_map_path(search_params), loading: :lazy do %>
105
+ <%= render '/ahoy_captain/layouts/shared/tile_loader' %>
106
+
107
+ <% end %>
81
108
  <% end %>
82
109
  <% component.with_details_cta do %>
83
- <button data-action="click->details-modal#openModal" data-controller="details-modal" data-details-modal-target-value="#geography" class="link no-underline ">Details</button>
110
+ <button data-action="click->details-modal#openModal" data-controller="details-modal" data-details-modal-target-value="#geography" class="link no-underline ">Details</button>
84
111
  <% end %>
85
112
  <% end %>
86
113
 
87
114
  <%= render AhoyCaptain::TileComponent.new(title: 'Devices') do |component| %>
88
115
  <% component.with_display_links do %>
89
116
  <div class="flex text-xs font-medium text-gray-400 space-x-2">
90
- <div class="relative inline-block text-left" data-controller="active-links">
91
-
92
- <a href="<%= devices_browsers_path(search_params) %>" data-turbo-frame="devices" class=" inline-block h-5 font-semibold" data-active-links-target="link">Browser</a>
93
- <a href="<%= devices_operating_systems_path(search_params) %>" data-turbo-frame="devices" class="inline-block h-5 font-semibold" data-active-links-target="link">OS</a>
94
- <a href="<%= devices_device_types_path(search_params) %>" data-turbo-frame="devices" class="inline-block h-5 font-semibold" data-active-links-target="link">Size</a>
117
+ <div class="relative inline-block text-left">
118
+ <%= component.link_to "Browser", devices_browsers_path(search_params), data: { turbo_frame: "devices" } %>
119
+ <%= component.link_to "OS", devices_operating_systems_path(search_params), data: { turbo_frame: "devices" } %>
120
+ <%= component.link_to "Size", devices_device_types_path(search_params), data: { turbo_frame: "devices" } %>
95
121
  </div>
96
122
  </div>
97
123
  <% end %>
98
124
  <% component.with_statistic_display do %>
99
- <%= turbo_frame_tag :devices, src: devices_browsers_path(search_params), loading: :lazy %>
125
+ <%= turbo_frame_tag :devices, src: devices_browsers_path(search_params), loading: :lazy do %>
126
+ <%= render '/ahoy_captain/layouts/shared/tile_loader' %>
127
+
128
+ <% end %>
100
129
  <% end %>
101
130
  <% component.with_details_cta do %>
102
131
  <button data-action="click->details-modal#openModal" data-controller="details-modal" data-details-modal-target-value="#devices" class="link no-underline ">Details</button>
@@ -105,29 +134,32 @@
105
134
  <%= render AhoyCaptain::TileComponent.new(title: "Goals and Funnels", wide: true, classes: "p-4 m-2") do |component| %>
106
135
  <% component.with_display_links do %>
107
136
  <div>
108
- <div data-controller="active-links">
109
-
110
- <a href="<%= goals_path(search_params) %>" data-turbo-frame="goals" class="link ">
111
- Goals
112
- </a>
113
- <a href="<%= properties_path(search_params) %>" data-turbo-frame="goals" class="link ">
114
- Properties
115
- </a>
116
- <%= render AhoyCaptain::DropdownLinkComponent.new(title: "Funnels") do |dropdown| %>
117
- <% AhoyCaptain.config.funnels.each do |id, funnel| %>
118
- <% dropdown.with_option do %>
119
- <a href="<%= funnel_path(id, search_params) %>" data-turbo-frame="goals" class="link ">
120
- <%= funnel.title %>
121
- </a>
137
+ <div >
138
+ <div class="flex text-xs font-medium text-gray-400 space-x-2">
139
+ <div class="relative inline-block text-left">
140
+ <a href="<%= goals_path(search_params) %>" data-turbo-frame="goals" class="inline-block h-5 font-semibold" data-controller="frame-link" data-action="click->tile#setTitle">Goals</a>
141
+ <a href="<%= properties_path(search_params) %>" data-turbo-frame="goals" class="inline-block h-5 font-semibold" data-controller="frame-link" data-action="click->tile#setTitle">Properties</a>
142
+ <%= render AhoyCaptain::DropdownLinkComponent.new(title: "Funnels") do |dropdown| %>
143
+ <% AhoyCaptain.config.funnels.each do |id, funnel| %>
144
+ <% dropdown.with_option do %>
145
+ <a href="<%= funnel_path(id, search_params) %>" data-turbo-frame="goals" class="link " data-action="click->tile#setTitle" title="<%= funnel.title %> Funnel">
146
+ <%= funnel.title %>
147
+ </a>
148
+ <% end %>
149
+ <% end %>
122
150
  <% end %>
123
- <% end %>
124
- <% end %>
151
+ </div>
152
+ </div>
153
+
125
154
  </div>
126
155
  </div>
127
156
  <% end %>
128
157
  <% component.with_statistic_display do %>
129
158
  <div class="p-4">
130
- <%= turbo_frame_tag :goals, src: goals_path(search_params), loading: :lazy %>
159
+ <%= turbo_frame_tag :goals, src: goals_path(search_params), loading: :lazy do %>
160
+ <%= render '/ahoy_captain/layouts/shared/tile_loader' %>
161
+ <% end %>
162
+
131
163
  </div>
132
164
  <% end %>
133
165
  <% end %>