feat: add city card component and improve index view
- Create a new partial for city card display with weather image - Update index page to show featured weather art with gradient - Refactor city listing layout and navigation for improved clarity This commit introduces a new component for displaying city cards that includes weather artwork when available. The index page has been refactored for better visual presentation and usability. Users can now better navigate through cities and see relevant weather data.
This commit is contained in:
parent
9cb1467301
commit
da7fca139c
53
app/views/cities/_city.html.erb
Normal file
53
app/views/cities/_city.html.erb
Normal file
@ -0,0 +1,53 @@
|
||||
<div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 group overflow-hidden">
|
||||
<% if city.latest_weather_art&.image&.attached? %>
|
||||
<figure class="relative aspect-[16/9]">
|
||||
<%= image_tag city.latest_weather_art.image,
|
||||
class: "w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-500" %>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent"></div>
|
||||
<div class="absolute bottom-0 left-0 right-0 p-6">
|
||||
<h3 class="text-2xl font-display text-white mb-1">
|
||||
<%= city.name %>
|
||||
</h3>
|
||||
<p class="text-white/80 text-sm">
|
||||
<%= city.country.name %>, <%= city.region.name %>
|
||||
</p>
|
||||
</div>
|
||||
</figure>
|
||||
<% else %>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title font-display"><%= city.name %></h3>
|
||||
<p class="text-base-content/70">
|
||||
<%= city.country.name %>, <%= city.region.name %>
|
||||
</p>
|
||||
<div class="flex gap-2 text-sm text-base-content/60">
|
||||
<span>Lat: <%= city.latitude %></span>
|
||||
<span>Long: <%= city.longitude %></span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="card-body <%= 'pt-0' if city.latest_weather_art&.image&.attached? %>">
|
||||
<div class="flex gap-4 text-sm text-base-content/70">
|
||||
<div class="flex items-center gap-1">
|
||||
<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="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>
|
||||
<%= city.timezone %>
|
||||
</div>
|
||||
<% if city.latest_weather_art %>
|
||||
<div class="flex items-center gap-1">
|
||||
<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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<%= city.latest_weather_art.weather_date.strftime("%b %d, %Y") %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<%= link_to "View Details", city_path(city),
|
||||
class: "btn btn-primary btn-sm" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,36 +1,72 @@
|
||||
<!-- 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="bg-gradient-to-r from-primary/10 to-secondary/10 py-12">
|
||||
<!-- 标题内容 -->
|
||||
<div class="relative pt-24 pb-48">
|
||||
<div class="container mx-auto px-4">
|
||||
<h1 class="text-4xl md:text-5xl font-display font-bold text-center mb-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 text-center text-base-content/70 max-w-2xl mx-auto">
|
||||
<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 %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选导航 -->
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="flex flex-wrap gap-4 items-center justify-center mb-8">
|
||||
<%= link_to "All Regions",
|
||||
cities_path,
|
||||
class: "btn btn-outline #{'btn-primary' unless @current_region}" %>
|
||||
<div class="sticky top-16 z-10 bg-base-100 shadow-lg">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="py-4">
|
||||
<!-- 区域选择 -->
|
||||
<div class="flex flex-wrap gap-3 items-center justify-center mb-4">
|
||||
<%= link_to cities_path,
|
||||
class: "btn btn-sm #{'btn-primary' unless @current_region} btn-outline" do %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" 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>
|
||||
All Regions
|
||||
<% end %>
|
||||
|
||||
<% @regions.each do |region| %>
|
||||
<%= link_to region.name,
|
||||
cities_path(region: region.slug),
|
||||
class: "btn btn-outline #{'btn-primary' if @current_region == region}" %>
|
||||
class: "btn btn-sm #{'btn-primary' if @current_region == region} btn-outline" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- 国家选择 (如果选择了区域) -->
|
||||
<% if @current_region %>
|
||||
<div class="flex flex-wrap gap-4 items-center justify-center mb-8">
|
||||
<%= link_to "All Countries in #{@current_region.name}",
|
||||
cities_path(region: @current_region.slug),
|
||||
class: "btn btn-sm btn-ghost #{'btn-active' unless @current_country}" %>
|
||||
<div class="flex flex-wrap gap-2 items-center justify-center">
|
||||
<%= link_to cities_path(region: @current_region.slug),
|
||||
class: "btn btn-sm btn-ghost #{'btn-active' unless @current_country}" do %>
|
||||
All in <%= @current_region.name %>
|
||||
<% end %>
|
||||
|
||||
<% @current_region.countries.order(:name).each do |country| %>
|
||||
<%= link_to country.name,
|
||||
@ -40,11 +76,19 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<!-- 当前选择显示 -->
|
||||
<div class="text-center mb-8">
|
||||
<div class="breadcrumbs text-sm justify-center">
|
||||
<!-- 面包屑导航 -->
|
||||
<% if @current_region || @current_country %>
|
||||
<div class="flex justify-center mt-4">
|
||||
<div class="breadcrumbs text-sm">
|
||||
<ul>
|
||||
<li><%= link_to "All Regions", cities_path %></li>
|
||||
<li>
|
||||
<%= link_to cities_path do %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||
</svg>
|
||||
Home
|
||||
<% end %>
|
||||
</li>
|
||||
<% if @current_region %>
|
||||
<li><%= @current_region.name %></li>
|
||||
<% end %>
|
||||
@ -54,66 +98,26 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 城市网格 -->
|
||||
<div class="container mx-auto px-4 pb-16">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<!-- 结果统计 -->
|
||||
<div class="text-center text-base-content/70 mb-8">
|
||||
Showing <%= @cities.count %> <%= 'city'.pluralize(@cities.count) %>
|
||||
<% if @current_country %>
|
||||
in <%= @current_country.name %>
|
||||
<% elsif @current_region %>
|
||||
in <%= @current_region.name %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- 城市卡片网格 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
<% @cities.each do |city| %>
|
||||
<div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 group overflow-hidden">
|
||||
<% if city.latest_weather_art&.image&.attached? %>
|
||||
<figure class="relative aspect-[16/9]">
|
||||
<%= image_tag city.latest_weather_art.image,
|
||||
class: "w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-500" %>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent"></div>
|
||||
<div class="absolute bottom-0 left-0 right-0 p-6">
|
||||
<h3 class="text-2xl font-display text-white mb-1">
|
||||
<%= city.name %>
|
||||
</h3>
|
||||
<p class="text-white/80 text-sm">
|
||||
<%= city.country.name %>, <%= city.region.name %>
|
||||
</p>
|
||||
</div>
|
||||
</figure>
|
||||
<% else %>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title font-display"><%= city.name %></h3>
|
||||
<p class="text-base-content/70">
|
||||
<%= city.country.name %>, <%= city.region.name %>
|
||||
</p>
|
||||
<div class="flex gap-2 text-sm text-base-content/60">
|
||||
<span>Lat: <%= city.latitude %></span>
|
||||
<span>Long: <%= city.longitude %></span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="card-body <%= 'pt-0' if city.latest_weather_art&.image&.attached? %>">
|
||||
<div class="flex gap-4 text-sm text-base-content/70">
|
||||
<div class="flex items-center gap-1">
|
||||
<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="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>
|
||||
<%= city.timezone %>
|
||||
</div>
|
||||
<% if city.latest_weather_art %>
|
||||
<div class="flex items-center gap-1">
|
||||
<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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<%= city.latest_weather_art.weather_date.strftime("%b %d, %Y") %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<%= link_to "View Details", city_path(city),
|
||||
class: "btn btn-primary btn-sm" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render partial: 'city', collection: @cities %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user