- Implement loading state in the search input with spinner. - Optimize the search request to handle pending requests and cancels. - Add dynamic response handling for Turbo frames to load search results. - Create a new partial for city search results. - Update the cities controller to support Turbo stream responses. These enhancements improve user experience during searches by showing a loading spinner and addressing potential issues with overlapping requests, ensuring that the application remains responsive and functional when fetching city search results.
122 lines
5.6 KiB
Plaintext
122 lines
5.6 KiB
Plaintext
<!-- app/views/cities/index.html.erb -->
|
|
<div class="min-h-screen">
|
|
<!-- 页面标题和背景 -->
|
|
<% featured_art = WeatherArt.includes(:city).joins(:image_attachment).order(created_at: :desc).first %>
|
|
<div class="relative bg-base-100">
|
|
<!-- 背景图像和渐变 -->
|
|
<% if featured_art&.image&.attached? %>
|
|
<div class="absolute inset-0 h-[60vh] overflow-hidden">
|
|
<%= image_tag featured_art.image,
|
|
class: "w-full h-full object-cover object-center" %>
|
|
<div class="absolute inset-0 bg-gradient-to-b from-base-100/40 via-base-100/80 to-base-100"></div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<div class="relative pt-24 pb-32">
|
|
<div class="container mx-auto px-4">
|
|
<div class="max-w-3xl mx-auto text-center space-y-6">
|
|
<h1 class="text-5xl md:text-6xl font-display font-bold leading-tight">
|
|
Explore Cities
|
|
</h1>
|
|
<p class="text-xl md:text-2xl text-base-content/70 font-light max-w-2xl mx-auto">
|
|
Discover AI-generated weather art from cities around the world
|
|
</p>
|
|
|
|
<!-- 特色图片信息 -->
|
|
<% if featured_art %>
|
|
<div class="inline-block mt-6 px-4 py-2 bg-base-100/80 backdrop-blur-sm rounded-full text-sm">
|
|
Latest from
|
|
<span class="font-semibold"><%= featured_art.city.name %></span>,
|
|
<%= featured_art.city.country.name %>
|
|
<span class="mx-2">•</span>
|
|
<%= featured_art.weather_date.strftime("%B %d, %Y") %>
|
|
</div>
|
|
<% end %>
|
|
<%= render 'cities/search_city' %>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="sticky top-16 z-20 bg-base-100/95 backdrop-blur-sm border-b border-base-200">
|
|
<div class="container mx-auto px-4">
|
|
<div class="py-3 flex items-center justify-between gap-4">
|
|
<div class="flex items-center gap-4">
|
|
<div class="dropdown">
|
|
<button class="btn btn-ghost gap-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<%= @current_region&.name || 'All Regions' %>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</button>
|
|
<ul class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-52 max-h-80 overflow-y-auto flex-nowrap">
|
|
<li>
|
|
<%= link_to cities_path,
|
|
class: "#{@current_region ? '' : 'active'}" do %>
|
|
All Regions
|
|
<% end %>
|
|
</li>
|
|
<div class="divider my-1"></div>
|
|
<% @regions.each do |region| %>
|
|
<li>
|
|
<%= link_to region.name,
|
|
cities_path(region: region.slug),
|
|
class: "#{@current_region == region ? 'active' : ''}" %>
|
|
</li>
|
|
<% end %>
|
|
</ul>
|
|
</div>
|
|
|
|
<% if @current_region %>
|
|
<div class="dropdown dropdown-bottom">
|
|
<button class="btn btn-ghost gap-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 21v-4m0 0V5a2 2 0 012-2h6.5l1 1H21l-3 6 3 6h-8.5l-1-1H5a2 2 0 00-2 2zm9-13.5V9" />
|
|
</svg>
|
|
<%= @current_country&.name || "All Countries" %>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</button>
|
|
<ul class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-52 max-h-80 overflow-y-auto flex-nowrap">
|
|
<li>
|
|
<%= link_to "All in #{@current_region.name}",
|
|
cities_path(region: @current_region.slug),
|
|
class: "#{@current_country ? '' : 'active'}" %>
|
|
</li>
|
|
<div class="divider my-1"></div>
|
|
<% @current_region.countries.order(:name).each do |country| %>
|
|
<li>
|
|
<%= link_to country.name,
|
|
cities_path(region: @current_region.slug, country: country.slug),
|
|
class: "#{@current_country == country ? 'active' : ''}" %>
|
|
</li>
|
|
<% end %>
|
|
</ul>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div class="text-sm text-base-content/70 hidden">
|
|
<%= @cities.count %> <%= 'city'.pluralize(@cities.count) %>
|
|
<% if @current_country %>
|
|
in <%= @current_country.name %>
|
|
<% elsif @current_region %>
|
|
in <%= @current_region.name %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<%= turbo_frame_tag "cities_results" do %>
|
|
<%= render "cities/results", cities: @cities %>
|
|
<% end %>
|
|
|
|
</div> |