Compare commits

..

No commits in common. "c37a93bcdf4a079c1e9591025037ee2dd1ab3a73" and "7612dd6bd9300b4cc845899012a18bcd73edb9b9" have entirely different histories.

17 changed files with 130 additions and 345 deletions

View File

@ -36,17 +36,18 @@ ActiveAdmin.register City do
filter :name filter :name
filter :active filter :active
filter :country, as: :select
form do |f| form do |f|
f.inputs do f.inputs do
f.input :active f.input :active
f.input :name f.input :name
f.input :country
f.input :latitude f.input :latitude
f.input :longitude f.input :longitude
f.input :priority f.input :priority
f.input :timezone f.input :timezone
f.input :region
f.input :last_weather_fetch
f.input :last_image_generation
end end
f.actions f.actions
end end

View File

@ -1,9 +1,4 @@
ActiveAdmin.register Country do ActiveAdmin.register Country do
controller do
def find_resource
scoped_collection.friendly.find(params[:id])
end
end
# See permitted parameters documentation: # See permitted parameters documentation:
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters # https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
# #

View File

@ -1,51 +1,2 @@
module WeatherArtsHelper module WeatherArtsHelper
def weather_description_icon(description)
case description&.downcase
when /rain/
'<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>'.html_safe
when /cloud/
'<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" />
</svg>'.html_safe
when /sun|clear/
'<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>'.html_safe
else
'<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>'.html_safe
end
end
def weather_stat_icon(type)
case type
when "temperature"
'<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="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>'.html_safe
when "wind"
'<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="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>'.html_safe
when "humidity"
'<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="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
</svg>'.html_safe
when "visibility"
'<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="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>'.html_safe
when "pressure"
'<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="M16 8v8m-4-5v5m-4-2v2m-2 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>'.html_safe
when "cloud"
'<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 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" />
</svg>'.html_safe
end
end
end end

View File

@ -1,6 +0,0 @@
import './add_jquery'
import "jquery/dist/jquery"
import "jquery-ui/dist/jquery-ui"
import "jquery-ujs"
import "@activeadmin/activeadmin"

View File

@ -1,4 +0,0 @@
import jquery from 'jquery'
import $ from 'jquery'
window.jQuery = jquery
window.$ = $

View File

@ -6,4 +6,3 @@ import "@fontsource/raleway/400.css";
import "@fontsource/raleway/600.css"; import "@fontsource/raleway/600.css";
import "./controllers" import "./controllers"
import "./active_admin"

View File

@ -45,7 +45,7 @@ class City < ApplicationRecord
end end
def self.ransackable_attributes(auth_object = nil) def self.ransackable_attributes(auth_object = nil)
[ "active", "country_id", "created_at", "id", "id_value", "last_image_generation", "last_weather_fetch", "latitude", "longitude", "name", "priority", "region", "slug", "timezone", "updated_at" ] [ "active", "country", "created_at", "id", "id_value", "last_image_generation", "last_weather_fetch", "latitude", "longitude", "name", "priority", "region", "slug", "timezone", "updated_at" ]
end end
def last_weather_fetch def last_weather_fetch

View File

@ -1,53 +1,37 @@
<div class="min-h-screen bg-base-200"> <div class="min-h-screen">
<!-- 城市头部信息 --> <!-- 城市头部信息 -->
<section class="relative h-[50vh] overflow-hidden"> <section class="relative h-[40vh] overflow-hidden">
<% if @city.latest_weather_art&.image&.attached? %> <% if @city.latest_weather_art&.image&.attached? %>
<%= image_tag @city.latest_weather_art.image, <%= image_tag @city.latest_weather_art.image,
class: "w-full h-full object-cover" %> class: "w-full h-full object-cover" %>
<div class="absolute inset-0 bg-gradient-to-t from-base-100 via-base-100/60 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-t from-base-100 via-base-100/50 to-transparent"></div>
<% end %> <% end %>
<div class="absolute inset-0 flex items-center"> <div class="absolute inset-0 flex items-center">
<div class="container mx-auto px-4"> <div class="container mx-auto px-4">
<div class="max-w-4xl"> <div class="max-w-4xl">
<div class="flex items-center space-x-4 mb-6"> <div class="flex items-center space-x-4 mb-4">
<%= link_to cities_path, <%= link_to cities_path,
class: "btn btn-ghost btn-circle bg-base-100/50 backdrop-blur-sm hover:bg-base-100/70" do %> class: "btn btn-ghost btn-circle" do %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg> </svg>
<% end %> <% end %>
<div> <h1 class="text-4xl md:text-5xl font-display font-bold"><%= @city.localized_name %></h1>
<h1 class="text-4xl md:text-5xl font-display font-bold mb-2"><%= @city.localized_name %></h1>
<p class="text-lg opacity-80">
<%= @city.country.name %>, <%= @city.region %>
<span class="mx-2">•</span>
<%= Time.current.in_time_zone(@city.timezone).strftime("%Y-%m-%d %H:%M") %>
</p>
</div>
</div> </div>
<div class="stats bg-base-100/80 backdrop-blur-sm shadow-lg rounded-box"> <div class="stats bg-base-100/80 backdrop-blur-sm shadow">
<div class="stat"> <div class="stat">
<div class="stat-title">Latest Weather</div> <div class="stat-title">Latitude</div>
<div class="stat-value text-2xl"> <div class="stat-value text-2xl"><%= @city.latitude %></div>
<%= @city.latest_weather_art&.temperature %>°C
</div>
<div class="stat-desc">
<%= @city.latest_weather_art&.description %>
</div>
</div> </div>
<div class="stat"> <div class="stat">
<div class="stat-title">Coordinates</div> <div class="stat-title">Longitude</div>
<div class="stat-value text-xl"> <div class="stat-value text-2xl"><%= @city.longitude %></div>
<%= @city.latitude %>°N, <%= @city.longitude %>°E
</div>
<div class="stat-desc">Geographical Location</div>
</div> </div>
<div class="stat"> <div class="stat">
<div class="stat-title">Weather Records</div> <div class="stat-title">Weather Arts</div>
<div class="stat-value text-2xl"><%= @city.weather_arts.count %></div> <div class="stat-value text-2xl"><%= @city.weather_arts.count %></div>
<div class="stat-desc">Total Entries</div>
</div> </div>
</div> </div>
</div> </div>
@ -58,39 +42,20 @@
<!-- 天气艺术历史记录 --> <!-- 天气艺术历史记录 -->
<section class="container mx-auto px-4 py-16"> <section class="container mx-auto px-4 py-16">
<div class="space-y-8"> <div class="space-y-8">
<div class="flex justify-between items-center">
<h2 class="text-3xl font-display font-bold">Weather Art History</h2> <h2 class="text-3xl font-display font-bold">Weather Art History</h2>
<div class="stats shadow inline-flex">
<div class="stat">
<div class="stat-title">Last Updated</div>
<div class="stat-value text-primary text-lg">
<%= time_ago_in_words(@city.last_weather_fetch) if @city.last_weather_fetch %>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<% @city.weather_arts.order(weather_date: :desc).each do |art| %> <% @city.weather_arts.order(weather_date: :desc).each do |art| %>
<div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300"> <div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300">
<figure class="relative aspect-video overflow-hidden"> <figure class="relative aspect-[4/3] overflow-hidden">
<% if art.image.attached? %> <% if art.image.attached? %>
<%= image_tag art.image, <%= image_tag art.image,
class: "w-full h-full object-cover transform hover:scale-105 transition-transform duration-500" %> class: "w-full h-full object-cover transform hover:scale-105 transition-transform duration-500" %>
<% end %> <% end %>
<div class="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent"> <div class="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/60 to-transparent">
<div class="text-white"> <div class="text-white">
<div class="flex items-center justify-between"> <div class="text-2xl font-bold"><%= art.temperature %>°C</div>
<div class="text-3xl font-bold"><%= art.temperature %>°C</div> <div class="text-sm opacity-90"><%= art.weather_date.strftime("%B %d, %Y") %></div>
<div class="text-right">
<div class="text-sm font-semibold">
<%= art.weather_date.strftime("%H:%M") %>
</div>
<div class="text-xs opacity-80">
<%= art.weather_date.strftime("%B %d, %Y") %>
</div>
</div>
</div>
</div> </div>
</div> </div>
</figure> </figure>
@ -101,7 +66,7 @@
<div class="grid grid-cols-2 gap-4 my-4 text-sm"> <div class="grid grid-cols-2 gap-4 my-4 text-sm">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 opacity-70" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 opacity-70" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.5 14.7a3 3 0 11-6 0 3 3 0 016 0z" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" />
</svg> </svg>
<span>Humidity: <%= art.humidity %>%</span> <span>Humidity: <%= art.humidity %>%</span>
</div> </div>
@ -113,13 +78,10 @@
</div> </div>
</div> </div>
<%= link_to city_weather_art_path(@city, art), <div class="card-actions justify-end">
class: "btn btn-primary btn-block" do %> <%= link_to "View Details", city_weather_art_path(@city, art),
View Details class: "btn btn-primary btn-outline" %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> </div>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<% end %>
</div> </div>
</div> </div>
<% end %> <% end %>

View File

@ -45,9 +45,6 @@
gtag('config', 'G-PX1C92V5L7'); gtag('config', 'G-PX1C92V5L7');
</script> </script>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7296634171837358"
crossorigin="anonymous"></script>
</head> </head>
<body class="min-h-screen bg-base-100 font-sans"> <body class="min-h-screen bg-base-100 font-sans">
@ -56,7 +53,7 @@
<div class="container mx-auto"> <div class="container mx-auto">
<div class="flex-1"> <div class="flex-1">
<%= link_to root_path, class: "text-2xl font-display font-bold hover:text-primary transition-colors" do %> <%= link_to root_path, class: "text-2xl font-display font-bold hover:text-primary transition-colors" do %>
Today AI Weather AI Weather Art
<% end %> <% end %>
</div> </div>
<div class="flex-none"> <div class="flex-none">

View File

@ -1,11 +0,0 @@
<!-- app/views/weather_arts/_weather_stat.html.erb -->
<div class="stat bg-base-200/50 backdrop-blur-sm rounded-box hover:bg-base-300/50 transition-all duration-300">
<div class="flex items-center gap-2 mb-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="<%= icon %>" />
</svg>
<div class="stat-title font-medium"><%= title %></div>
</div>
<div class="stat-value text-2xl"><%= value %></div>
<div class="stat-desc mt-1"><%= desc %></div>
</div>

View File

@ -4,22 +4,11 @@
</script> </script>
<% end %> <% end %>
<div class="relative min-h-screen bg-base-200"> <div class="min-h-screen">
<!-- 背景图片 -->
<% if @weather_art.image.attached? %>
<div class="fixed inset-0 -z-10">
<%= image_tag @weather_art.image,
class: "absolute w-full h-full object-cover scale-110 filter blur-2xl opacity-25" %>
<div class="absolute inset-0 bg-gradient-to-b from-base-200/90 to-base-200/70 backdrop-blur-md"></div>
</div>
<% end %>
<!-- 主要内容 -->
<div class="relative z-10">
<!-- 返回导航 --> <!-- 返回导航 -->
<div class="container mx-auto px-4 py-6"> <div class="container mx-auto px-4 py-8">
<%= link_to city_path(@weather_art.city), <%= link_to city_path(@weather_art.city),
class: "btn btn-ghost btn-lg gap-2 bg-base-100/50 backdrop-blur-sm hover:bg-base-100/70 transition-all duration-300" do %> class: "btn btn-ghost gap-2" do %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <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="M15 19l-7-7 7-7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg> </svg>
@ -27,129 +16,72 @@
<% end %> <% end %>
</div> </div>
<!-- 主要内容 -->
<div class="container mx-auto px-4 pb-16"> <div class="container mx-auto px-4 pb-16">
<div class="max-w-6xl mx-auto"> <div class="max-w-6xl mx-auto">
<!-- 头部信息 --> <!-- 头部信息 -->
<div class="text-center space-y-4 mb-12"> <div class="text-center space-y-4 mb-12">
<div class="inline-flex items-center gap-2 text-sm font-medium px-4 py-2 rounded-full bg-base-100/50 backdrop-blur-sm"> <h1 class="text-4xl md:text-5xl font-display font-bold">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <%= @weather_art.city.name %>
<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" />
</svg>
<%= @weather_art.city.full_name %>
</div>
<h1 class="text-4xl md:text-6xl font-display font-bold">
<span class="bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
Weather Art
</span>
</h1> </h1>
<p class="text-xl text-base-content/70">
<div class="flex flex-wrap justify-center items-center gap-3">
<div class="badge badge-lg badge-primary gap-2">
<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="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<%= @weather_art.weather_date.strftime("%B %d, %Y") %> <%= @weather_art.weather_date.strftime("%B %d, %Y") %>
</div> </p>
<div class="badge badge-lg badge-secondary gap-2">
<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>
<%= @weather_art.weather_date.strftime("%H:%M") %>
</div>
</div>
</div> </div>
<!-- 主要卡片 --> <!-- 主要卡片 -->
<div class="card lg:card-side bg-base-100/80 backdrop-blur-md shadow-2xl"> <div class="card lg:card-side bg-base-100 shadow-2xl">
<figure class="lg:w-1/2 relative aspect-square lg:aspect-auto group"> <figure class="lg:w-1/2 relative aspect-square lg:aspect-auto">
<% if @weather_art.image.attached? %> <% if @weather_art.image.attached? %>
<%= image_tag @weather_art.image, <%= image_tag @weather_art.image,
class: "w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" %> class: "w-full h-full object-cover" %>
<div class="absolute inset-0 bg-gradient-to-t from-base-100/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<% end %> <% end %>
</figure> </figure>
<div class="card-body lg:w-1/2"> <div class="card-body lg:w-1/2">
<div class="prose max-w-none mb-8"> <h2 class="card-title font-display text-2xl mb-6">
<h2 class="card-title font-display text-3xl mb-4 flex items-center gap-3">
<%= weather_description_icon(@weather_art.description) %>
<%= @weather_art.description %> <%= @weather_art.description %>
</h2> </h2>
<div class="divider"></div>
</div>
<!-- 天气数据网格 --> <!-- 天气数据网格 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div class="grid grid-cols-2 gap-6">
<div class="stat bg-base-200/50 backdrop-blur-sm rounded-box hover:bg-base-300/50 transition-all duration-300"> <div class="stat bg-base-200 rounded-box">
<div class="flex items-center gap-2 mb-2"> <div class="stat-title">Temperature</div>
<%= weather_stat_icon("temperature") %> <div class="stat-value"><%= @weather_art.temperature %>°C</div>
<div class="stat-title font-medium">Temperature</div> <div class="stat-desc">Feels like <%= @weather_art.feeling_temp %>°C</div>
</div>
<div class="stat-value text-2xl"><%= @weather_art.temperature %>°C</div>
<div class="stat-desc mt-1">Feels like <%= @weather_art.feeling_temp %>°C</div>
</div> </div>
<div class="stat bg-base-200/50 backdrop-blur-sm rounded-box hover:bg-base-300/50 transition-all duration-300"> <div class="stat bg-base-200 rounded-box">
<div class="flex items-center gap-2 mb-2"> <div class="stat-title">Wind</div>
<%= weather_stat_icon("wind") %> <div class="stat-value"><%= @weather_art.wind_scale %></div>
<div class="stat-title font-medium">Wind</div> <div class="stat-desc"><%= @weather_art.wind_speed %> km/h</div>
</div>
<div class="stat-value text-2xl"><%= @weather_art.wind_scale %></div>
<div class="stat-desc mt-1"><%= @weather_art.wind_speed %> km/h</div>
</div> </div>
<div class="stat bg-base-200/50 backdrop-blur-sm rounded-box hover:bg-base-300/50 transition-all duration-300"> <div class="stat bg-base-200 rounded-box">
<div class="flex items-center gap-2 mb-2"> <div class="stat-title">Humidity</div>
<%= weather_stat_icon("humidity") %> <div class="stat-value"><%= @weather_art.humidity %>%</div>
<div class="stat-title font-medium">Humidity</div>
</div>
<div class="stat-value text-2xl"><%= @weather_art.humidity %>%</div>
<div class="stat-desc mt-1">Relative humidity</div>
</div> </div>
<div class="stat bg-base-200/50 backdrop-blur-sm rounded-box hover:bg-base-300/50 transition-all duration-300"> <div class="stat bg-base-200 rounded-box">
<div class="flex items-center gap-2 mb-2"> <div class="stat-title">Visibility</div>
<%= weather_stat_icon("visibility") %> <div class="stat-value"><%= @weather_art.visibility %> km</div>
<div class="stat-title font-medium">Visibility</div>
</div>
<div class="stat-value text-2xl"><%= @weather_art.visibility %> km</div>
<div class="stat-desc mt-1">Clear view distance</div>
</div> </div>
<div class="stat bg-base-200/50 backdrop-blur-sm rounded-box hover:bg-base-300/50 transition-all duration-300"> <div class="stat bg-base-200 rounded-box">
<div class="flex items-center gap-2 mb-2"> <div class="stat-title">Pressure</div>
<%= weather_stat_icon("pressure") %> <div class="stat-value"><%= @weather_art.pressure %> hPa</div>
<div class="stat-title font-medium">Pressure</div>
</div>
<div class="stat-value text-2xl"><%= @weather_art.pressure %> hPa</div>
<div class="stat-desc mt-1">Atmospheric pressure</div>
</div> </div>
<div class="stat bg-base-200/50 backdrop-blur-sm rounded-box hover:bg-base-300/50 transition-all duration-300"> <div class="stat bg-base-200 rounded-box">
<div class="flex items-center gap-2 mb-2"> <div class="stat-title">Cloud Cover</div>
<%= weather_stat_icon("cloud") %> <div class="stat-value"><%= @weather_art.cloud %>%</div>
<div class="stat-title font-medium">Cloud Cover</div>
</div>
<div class="stat-value text-2xl"><%= @weather_art.cloud %>%</div>
<div class="stat-desc mt-1">Sky coverage</div>
</div> </div>
</div> </div>
<!-- AI Prompt --> <!-- AI Prompt -->
<div class="mt-8"> <div class="mt-8 bg-base-200 p-6 rounded-box">
<div class="bg-base-200/50 backdrop-blur-sm p-6 rounded-box border border-base-300"> <h3 class="font-display font-bold text-lg mb-3">AI Prompt</h3>
<div class="flex items-center gap-3 mb-4"> <p class="text-base-content/70"><%= @weather_art.prompt %></p>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
<h3 class="font-display font-bold text-lg">AI Prompt</h3>
</div>
<p class="text-base-content/70 leading-relaxed">
<%= @weather_art.prompt %>
</p>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,9 +1,9 @@
class BatchGenerateWeatherArtsWorker class BatchGenerateWeatherArtsWorker
include Sidekiq::Worker include Sidekiq::Worker
GENERATION_INTERVAL = 24.hours GENERATION_INTERVAL = 6.hours
MAX_DURATION = 50.minutes MAX_DURATION = 50.minutes
SLEEP_DURATION = 120.seconds SLEEP_DURATION = 3.seconds
def perform(*args) def perform(*args)
start_time = Time.current start_time = Time.current

View File

@ -1,21 +0,0 @@
# config/initializers/schedule_tasks.rb
Rails.application.config.after_initialize do
if Rails.env.production? && !ENV["RAILS_BUILD"]
begin
redis_key = "startup_task_running"
unless Sidekiq.redis { |conn| conn.get(redis_key) }
Sidekiq.redis do |conn|
conn.setex(redis_key, 1.hour.to_i, "1")
end
RefreshSitemapWorker.perform_async
Rails.logger.info "Startup task (RefreshSitemapWorker) scheduled successfully"
end
rescue => e
Rails.logger.error "Error scheduling startup task: #{e.message}"
ensure
Sidekiq.redis { |conn| conn.del(redis_key) }
end
end
end

View File

@ -80,7 +80,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: "Xi'an", name: "Xi'an",
@ -89,7 +89,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Hangzhou', name: 'Hangzhou',
@ -98,7 +98,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Foshan', name: 'Foshan',
@ -107,7 +107,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Nanjing', name: 'Nanjing',
@ -116,7 +116,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Hong Kong', name: 'Hong Kong',
@ -125,7 +125,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Hong_Kong', timezone: 'Asia/Hong_Kong',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Shenyang', name: 'Shenyang',
@ -134,7 +134,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Zhengzhou', name: 'Zhengzhou',
@ -143,7 +143,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Qingdao', name: 'Qingdao',
@ -152,7 +152,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Suzhou', name: 'Suzhou',
@ -161,7 +161,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Changsha', name: 'Changsha',
@ -170,7 +170,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Jinan', name: 'Jinan',
@ -179,7 +179,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Kunming', name: 'Kunming',
@ -188,7 +188,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Harbin', name: 'Harbin',
@ -197,7 +197,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Shijiazhuang', name: 'Shijiazhuang',
@ -206,7 +206,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Hefei', name: 'Hefei',
@ -215,7 +215,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Dalian', name: 'Dalian',
@ -224,7 +224,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Xiamen', name: 'Xiamen',
@ -233,7 +233,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Nanning', name: 'Nanning',
@ -242,7 +242,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Changchun', name: 'Changchun',
@ -251,7 +251,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Taiyuan', name: 'Taiyuan',
@ -260,7 +260,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'New Taipei City', name: 'New Taipei City',
@ -269,7 +269,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Taipei', timezone: 'Asia/Taipei',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Guiyang', name: 'Guiyang',
@ -278,7 +278,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Wuxi', name: 'Wuxi',
@ -287,7 +287,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Shantou', name: 'Shantou',
@ -296,7 +296,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Ürümqi', name: 'Ürümqi',
@ -305,7 +305,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Zhongshan', name: 'Zhongshan',
@ -314,7 +314,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Ningbo', name: 'Ningbo',
@ -323,7 +323,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Fuzhou', name: 'Fuzhou',
@ -332,7 +332,7 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
}, },
{ {
name: 'Nanchang', name: 'Nanchang',
@ -341,6 +341,6 @@ City.create!([
country: china, country: china,
timezone: 'Asia/Shanghai', timezone: 'Asia/Shanghai',
active: true, active: true,
priority: 100 priority: 100,
} }
]) ])

View File

@ -16,8 +16,6 @@
"@hotwired/stimulus": "^3.2.2", "@hotwired/stimulus": "^3.2.2",
"@hotwired/turbo-rails": "^8.0.12", "@hotwired/turbo-rails": "^8.0.12",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"jquery": "^3.7.1",
"jquery-ui": "^1.14.1",
"postcss": "^8.5.1", "postcss": "^8.5.1",
"sass": "^1.83.4", "sass": "^1.83.4",
"tailwindcss": "^3.4.17" "tailwindcss": "^3.4.17"

View File

@ -1 +0,0 @@
google.com, pub-7296634171837358, DIRECT, f08c47fec0942fa0

View File

@ -729,19 +729,12 @@ jquery-ui@^1.13.3:
dependencies: dependencies:
jquery ">=1.12.0 <5.0.0" jquery ">=1.12.0 <5.0.0"
jquery-ui@^1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.14.1.tgz#ba342ea3ffff662b787595391f607d923313e040"
integrity sha512-DhzsYH8VeIvOaxwi+B/2BCsFFT5EGjShdzOcm5DssWjtcpGWIMsn66rJciDA6jBruzNiLf1q0KvwMoX1uGNvnQ==
dependencies:
jquery ">=1.12.0 <5.0.0"
jquery-ujs@^1.2.2: jquery-ujs@^1.2.2:
version "1.2.3" version "1.2.3"
resolved "https://registry.npmjs.org/jquery-ujs/-/jquery-ujs-1.2.3.tgz" resolved "https://registry.npmjs.org/jquery-ujs/-/jquery-ujs-1.2.3.tgz"
integrity sha512-59wvfx5vcCTHMeQT1/OwFiAj+UffLIwjRIoXdpO7Z7BCFGepzq9T9oLVeoItjTqjoXfUrHJvV7QU6pUR+UzOoA== integrity sha512-59wvfx5vcCTHMeQT1/OwFiAj+UffLIwjRIoXdpO7Z7BCFGepzq9T9oLVeoItjTqjoXfUrHJvV7QU6pUR+UzOoA==
"jquery@>=1.12.0 <5.0.0", jquery@^3.4.1, jquery@^3.7.1: "jquery@>=1.12.0 <5.0.0", jquery@^3.4.1:
version "3.7.1" version "3.7.1"
resolved "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz" resolved "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz"
integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==