- Wrap image_tag calls in begin-rescue blocks to catch loading errors - Log any exceptions to Rails logger for better debugging - Provide user feedback with a placeholder when images fail to load These changes improve the robustness of the application by ensuring that errors do not cause disruptions in the user interface.
163 lines
8.0 KiB
Plaintext
163 lines
8.0 KiB
Plaintext
<!-- app/views/cities/index.html.erb -->
|
|
<div class="min-h-screen">
|
|
<!-- 页面标题和背景 -->
|
|
<% featured_art = @latest_arts.first %>
|
|
<div class="relative bg-base-100">
|
|
<!-- 背景图像和渐变 -->
|
|
<% if featured_art&.image&.attached? %>
|
|
<% begin %>
|
|
<div class="absolute inset-0 h-[60vh] overflow-hidden">
|
|
<%= image_tag featured_art.webp_image.processed,
|
|
class: "w-full h-full object-cover object-center" %>
|
|
<% rescue StandardError => e %>
|
|
<% Rails.logger.error("image load error: #{e.message}") if defined?(Rails) %>
|
|
<% end %>
|
|
<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">
|
|
<%= t("cities.title") %>
|
|
</h1>
|
|
<p class="text-xl md:text-2xl text-base-content/70 font-light max-w-2xl mx-auto">
|
|
<%= t("arts.subtitle") %>
|
|
</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">
|
|
<%= t("text.latest_from") %>
|
|
<span class="font-semibold"><%= featured_art.city.name %></span>,
|
|
<%= featured_art.city.country.localized_name %>
|
|
<span class="mx-2">•</span>
|
|
<%= featured_art.formatted_time(:date) %>
|
|
</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">
|
|
<!-- 大洲/地区 (Region) SVG - 使用地球仪图标 -->
|
|
<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&.localized_name || t("text.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 %>
|
|
<%= t("text.all_regions") %>
|
|
<% end %>
|
|
</li>
|
|
<div class="divider my-1"></div>
|
|
<% @regions.each do |region| %>
|
|
<li>
|
|
<%= link_to region.localized_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">
|
|
<!-- 国家 (Country) SVG - 现代旗帜图标 -->
|
|
<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="M4 5a1 1 0 011-1h14a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h14a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6z"/>
|
|
</svg>
|
|
<%= @current_country&.localized_name || t("text.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 "#{t("text.all_in")} #{@current_region.localized_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&.emoji + " " || ""}#{country.localized_name}",
|
|
cities_path(region: @current_region.slug, country: country.slug),
|
|
class: "#{@current_country == country ? 'active' : ''}" %>
|
|
</li>
|
|
<% end %>
|
|
</ul>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% if @current_country %>
|
|
<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="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"/>
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"/>
|
|
</svg>
|
|
<%= @current_state&.name || t("text.all_states") %>
|
|
<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 "#{t("text.all_in")} #{@current_country.localized_name}",
|
|
cities_path(region: @current_region, country: @current_country.slug),
|
|
class: "#{@current_state ? '' : 'active'}" %>
|
|
</li>
|
|
<div class="divider my-1"></div>
|
|
<% @current_country.states.order(:name).each do |state| %>
|
|
<li>
|
|
<%= link_to "#{state.name}",
|
|
cities_path(region: @current_region.slug, country: @current_country.slug, state: state.slug),
|
|
class: "#{@current_state == state ? '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.localized_name %>
|
|
<% elsif @current_region %>
|
|
in <%= @current_region.localized_name %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<%= turbo_frame_tag "cities_results",data: { turbo_action: "advance" } do %>
|
|
<%= render "cities/results", cities: @cities %>
|
|
<% end %>
|
|
|
|
</div> |