feat: add navigation between weather arts

- Implement previous and next weather art navigation
- Update weather arts controller to fetch adjacent weather arts
- Modify show view to include navigation links

This update enhances the user experience by allowing users to
navigate through weather arts seamlessly. The previous and
next buttons improve accessibility, providing a smoother
browsing experience. The implementation also accounts for
situations where no adjacent weather arts exist, ensuring
clarity for users.
This commit is contained in:
songtianlun 2025-02-03 11:09:31 +08:00
parent 5d1846e0a0
commit 884e1dfc9f
6 changed files with 82 additions and 16 deletions

View File

@ -56,11 +56,13 @@ gem "ahoy_matey", "~> 5.2"
gem "ruby-openai", "~> 7.3" gem "ruby-openai", "~> 7.3"
gem "httparty", "~> 0.22.0" gem "httparty", "~> 0.22.0"
gem "down", "~> 5.4" gem "down", "~> 5.4"
gem "aws-sdk-s3", "~> 1.179" gem "aws-sdk-s3", "~> 1.177"
gem "sidekiq", "~> 7.3" gem "sidekiq", "~> 7.3"
gem "sidekiq-scheduler", "~> 5.0" gem "sidekiq-scheduler", "~> 5.0"
gem "image_processing", "~> 1.13" gem "image_processing", "~> 1.13"
gem "ruby-vips", "~> 2.2"
gem "mini_magick", "~> 4.13.2"
group :development, :test do group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem

View File

@ -84,8 +84,8 @@ GEM
uri (>= 0.13.1) uri (>= 0.13.1)
addressable (2.8.7) addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
ahoy_matey (5.2.1) ahoy_matey (5.3.0)
activesupport (>= 6.1) activesupport (>= 7)
device_detector (>= 1) device_detector (>= 1)
safely_block (>= 0.4) safely_block (>= 0.4)
arbre (1.7.0) arbre (1.7.0)
@ -93,8 +93,8 @@ GEM
ruby2_keywords (>= 0.0.2) ruby2_keywords (>= 0.0.2)
ast (2.4.2) ast (2.4.2)
aws-eventstream (1.3.0) aws-eventstream (1.3.0)
aws-partitions (1.1043.0) aws-partitions (1.1044.0)
aws-sdk-core (3.217.0) aws-sdk-core (3.217.1)
aws-eventstream (~> 1, >= 1.3.0) aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0) aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9) aws-sigv4 (~> 1.9)
@ -238,7 +238,7 @@ GEM
activerecord activerecord
kaminari-core (= 1.2.2) kaminari-core (= 1.2.2)
kaminari-core (1.2.2) kaminari-core (1.2.2)
language_server-protocol (3.17.0.3) language_server-protocol (3.17.0.4)
logger (1.6.5) logger (1.6.5)
loofah (2.24.0) loofah (2.24.0)
crass (~> 1.0.2) crass (~> 1.0.2)
@ -268,7 +268,7 @@ GEM
net-protocol net-protocol
net-protocol (0.2.2) net-protocol (0.2.2)
timeout timeout
net-scp (4.0.0) net-scp (4.1.0)
net-ssh (>= 2.6.5, < 8.0.0) net-ssh (>= 2.6.5, < 8.0.0)
net-sftp (4.0.0) net-sftp (4.0.0)
net-ssh (>= 5.0.0, < 8.0.0) net-ssh (>= 5.0.0, < 8.0.0)
@ -315,7 +315,7 @@ GEM
nio4r (~> 2.0) nio4r (~> 2.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.8.1) racc (1.8.1)
rack (3.1.8) rack (3.1.9)
rack-session (2.1.0) rack-session (2.1.0)
base64 (>= 0.1.0) base64 (>= 0.1.0)
rack (>= 3.0.0) rack (>= 3.0.0)
@ -369,17 +369,17 @@ GEM
actionpack (>= 5.2) actionpack (>= 5.2)
railties (>= 5.2) railties (>= 5.2)
rexml (3.4.0) rexml (3.4.0)
rubocop (1.70.0) rubocop (1.71.1)
json (~> 2.3) json (~> 2.3)
language_server-protocol (>= 3.17.0) language_server-protocol (>= 3.17.0)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 3.3.0.2) parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0) regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.36.2, < 2.0) rubocop-ast (>= 1.38.0, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0) unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.37.0) rubocop-ast (1.38.0)
parser (>= 3.3.1.0) parser (>= 3.3.1.0)
rubocop-minitest (0.36.0) rubocop-minitest (0.36.0)
rubocop (>= 1.61, < 2.0) rubocop (>= 1.61, < 2.0)
@ -387,7 +387,7 @@ GEM
rubocop-performance (1.23.1) rubocop-performance (1.23.1)
rubocop (>= 1.48.1, < 2.0) rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rails (2.29.0) rubocop-rails (2.29.1)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
rack (>= 1.1) rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0) rubocop (>= 1.52.0, < 2.0)
@ -511,7 +511,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
activeadmin (~> 3.2) activeadmin (~> 3.2)
ahoy_matey (~> 5.2) ahoy_matey (~> 5.2)
aws-sdk-s3 (~> 1.179) aws-sdk-s3 (~> 1.177)
bootsnap bootsnap
brakeman brakeman
capybara capybara
@ -527,12 +527,14 @@ DEPENDENCIES
kamal kamal
kaminari (~> 1.2) kaminari (~> 1.2)
meta-tags (~> 2.22) meta-tags (~> 2.22)
mini_magick (~> 4.13.2)
pg (~> 1.5) pg (~> 1.5)
propshaft propshaft
puma (>= 5.0) puma (>= 5.0)
rails (~> 8.0.1) rails (~> 8.0.1)
rubocop-rails-omakase rubocop-rails-omakase
ruby-openai (~> 7.3) ruby-openai (~> 7.3)
ruby-vips (~> 2.2)
selenium-webdriver selenium-webdriver
sidekiq (~> 7.3) sidekiq (~> 7.3)
sidekiq-scheduler (~> 5.0) sidekiq-scheduler (~> 5.0)

View File

@ -3,6 +3,16 @@ class WeatherArtsController < ApplicationController
@city = City.friendly.find(params[:city_id]) @city = City.friendly.find(params[:city_id])
@weather_art = @city.weather_arts.friendly.find(params[:slug]) @weather_art = @city.weather_arts.friendly.find(params[:slug])
@previous_weather_art = @city.weather_arts
.where("id < ?", @weather_art.id)
.order(weather_date: :desc)
.first
@next_weather_art = @city.weather_arts
.where("id > ?", @weather_art.id)
.order(weather_date: :asc)
.first
ahoy.track "View Weather Art", { ahoy.track "View Weather Art", {
weather_art_id: @weather_art.id, weather_art_id: @weather_art.id,
city_id: @weather_art.city_id, city_id: @weather_art.city_id,

View File

@ -86,6 +86,36 @@
<%= @weather_art.prompt %> <%= @weather_art.prompt %>
</p> </p>
</div> </div>
<!-- 上一个和下一个导航 -->
<div class="flex flex-col sm:flex-row justify-between items-center gap-4 mt-8">
<% if @previous_weather_art %>
<%= link_to city_weather_art_path(@city, @previous_weather_art),
class: "btn btn-outline btn-primary w-full sm:w-auto flex items-center justify-center 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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
Previous Weather Art
<% end %>
<% end %>
<% if @next_weather_art %>
<%= link_to city_weather_art_path(@city, @next_weather_art),
class: "btn btn-outline btn-primary w-full sm:w-auto flex items-center justify-center gap-2" do %>
Next Weather Art
<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="M9 5l7 7-7 7" />
</svg>
<% end %>
<% end %>
</div> </div>
<% if @previous_weather_art.nil? && @next_weather_art.nil? %>
<div class="text-center text-base-content/70 py-4">
No more Weather Arts available
</div>
<% end %>
</div>
</div> </div>
</div> </div>

View File

@ -1 +1 @@
0Upt112zhMfb3aADOgxSWUCTTUNgtTrpoivR9+KJFKcazTjqRauvQ9W+uicYrjJjv497gHMFhusWZysDl1/uwHHaoHvyp7auIjRHiOR1YKfRLgbMSYMgSOKlP4HbiZ66hjhT+4T50JjmwwLcPFtgPaZG3lasTAXejc9ejiSn+OsIGvJje5MXnPREId5pvC/SNW4uCYMe6OEsfhTlsj8hES7odHJzMsGQGGuVkcg1EimogOE9oWK6FS0bj45R+7HCiIYlbcmDkRNraGDMGJI+oaxx2mi+34ENoxqfbYEv4PhsWPYcOROK8FyrpXwvRG/a1J8LFxTLkVloKsBIInLojvd9u8zwpcTOtsaHOxsQV7gLzUt2GbUiT4EZUdzHpIDRboJEuVxm6ioBctcJ744xnkn5rxOoJH+JWRhxf+CVLYojcYMdkcyGEOHv0nXtpWtu/xsJT3fTqJBLuyGWNQUfTDsw3qQDUOrsgSNvXvhEu1iWptoByp4d0adaCDS0+TVt+BFg2xPzSnIU3IAXgSnhyLTVd87jxBMHtcngIj4HAj+nDIs65KT4dk4Y+ns3eWE345Z0CzUz1J6M8ikva0cQiBB6wxMl1yghysCcSfKX4z/KbuJv6StQJIqw4HkDZ9youXEbnmiXTxuEaC0Yg3SE0dFf5k9Rj5govLMdCf1Msj04RQHt0b08s3UdTgegriru+j7dC6yTaDbHkrNorREME3SENzdksI1D5k08D4Z+TYpO/+yyZE5qKELEse9TgJiFZ6g1H2sFs9zCxBDif67ovFSqrRaNgP7qBY8uEfFNVP6Y6eSnfccJlFBGlwflhwwA1osit+5rKlvhqQs37qsmFZRuj9BdrAJbdr/0ogEbLyeTEw3Zq+0m0/Vf4j5ueCv2eDpk/gSQdl869v+5anLTqMUWM4KV1wS1OrPkMC5XkZHLUo1/1+Dl6FKfZhWydRso1R9WL5B0Jk7UEWMPX0qoxxuixR1jwWzYmlehq0iNw7hQPdgwCbDtRxEMPr8MkUnG5Fd0YZUfnhHJ+EWVCZHKhUJclRSB9LnDKVPJr/oFuOHLmJg6Vll4WHCnIK9nCHdr7ed6O89vA5Z8DRlE/6yAXFlPKrCldWYbrL3BAgzQK8MxD5fzgzRkGiwVEtQwhbtbdDHUJ9rdAEmLJZj1UJXLIhX9jFspB9stHqyRxrcef/Y+h9dBvuFdvSIFEXA0TWHintx9YDgsJb591d6rjJn+JYEmZs9UONEEuiijPf9waqTb0oIrUQwnlUOX69bBipiU5ZQ2yQvepuRY3ooK3IGHvngxZPT0F8Mfh5Zcx9GGJd17LZb9DJOs7uOlrpXydToq/3Qm1q6TmgjbFYpC6iyrhDyE5XLL/XwVavh7m2QYqVbUXk2tGk2C0UR6CTE6tsV1+kDs1nylIEgAA5Nr43HQtRAXPmo0k8Txy5wMMIbLE1keqjl7XdGPnLsX9CJi6ue6KZxhigwcdakvW6Y=--H101ebDKrzdM39ll--a5R5klrhU6QgghGPjjWfAQ== zSnch4RlzPEpqZOE+TyBVBnHu+wyiNfNZoe1zi+cGNcgN/0BMw3xVQNIdu5ZgZzklukyimLlvkic7/G3PZE5aooqKIPeaGIgVKwdBvIGZYkTbrLTPtiA2Mx2iay4u6XI3eLDZZdy9g446GTngz9beQFR9s7dBbRBewOdIuCjA17seywsv722x97wHCv1xoGBeknK0DrEaYQcnECcy3G3esAsGeoKCQRMNHIf5/IbB6J+ZsoyOpnwtjOXdfEUnmtieLqvyw1xjgOxQTp2GMJk8zq+dGUBR3nIzplzccJbotppWfUbd9nxuT0stxWdFtKRPceynUfJ4awQNOmx+qGXi2/sYZH9lEB0nnyuKUpte6/bf1kcxcXyqTcsjaw0f9DXC3z9jx0pPbf2+O1MLZSFmo7Sr18mXjHVWjSCXnuYmWWkkuKESl4DwW5KScguWdnsf+/Y1eHds2MpE9dRLynlf5ONvFMY495iXuN4bR7UE5utAmU3imAg8vhErDqiro2L0GKMY5boMg+9NIObSlxwI6uAer8HaIKBVioiXGHFoFofR0LpmIKTbHiRF9ZZM3KCunsrQXAvRB4X7jL18JR08cDGGML2m03u9fcn9VuCYgcr+TLnsBozoG+ATP03kXc6lxkxjDvOc2z/AKqPmHUejCvsTLibFuEgw34E/NnVgcrC/Cggh/pp2Vmc6Yg2aQN7NcUmz0enGpzaTcnwiiB/8U8ig5WUovZP/iG3JH8S4KtBhDVz4hzz3FDOFBZCHd0rDrLtcyPtOcI3/WTZ0BgV5SXxA6L1gmM+aSYXtiyKZ2iUUOkMnNPvmHtimd+IWJZn2qXswX8RuE5QTqL5R5PRIdawdMSf9QrBSmDllNCo3czzClBRSNMYk2+ueWtiyvRuxP/xyNVl5e8nGOhAFWjCA+DVVA1xGWvS+R+3nxMSMtNaqTc2RPHQ3u4hY4k/0UH2TmnnzIJHS8vYScO4EzasTb/9FMeUEDnx369D7gvkXW6OapIKxwV0oQR8a/ZYUpOVyV6rSUIvEKrlpXCG8fh/6LwprYTPrnWe8iIwGqxKcuecrmtRSijAHgI2ZzMpSN91tomBBn9Qs+5svRbcXCO9KUKtjB9V82J7xqT+LwOyf1wa+v9zcO1aQxel2npRTsg7a4eIyIx1iyP7hHLAAuYIeEj1pBjiY/LiGZw+ScrXu1sIFTpt2SIKUOCVSN1y52/zXkwTRHc3qf4IdeHX6DqzWmWUiEHwm9Lva1fJ6poJ3vqWi7OLWJqyDtiN2FHJqybQ9mrgWPb0WBYi3umnfPy6ZYMQ6jQ8YarK8aFHsVdjUL0I4DKigAuer47p2rUcaFvySGCoMaSu5krSBw3VkDR6y1J8wIAm7nKZOSyoKwRjrgwXOl8yTN+zoemiaUMNJI1mTu1JQeg5rX2yUvwLEu5hu/5eOuRCkoSiwcG1+LmcnZbYRgSRvDzRcKYKZ/5hzQkPCLRkwAhh1Zp7mtc=--dyeF3fjnBpbK0tnw--nWdBu1crWT0VX9aHfnoKRw==

View File

@ -183,3 +183,25 @@ guangzhou_weather_art2.image.attach(
filename: "sample-guangzhou-weather-art-2.png", filename: "sample-guangzhou-weather-art-2.png",
content_type: "image/png" content_type: "image/png"
) )
guangzhou_weather_art3 = WeatherArt.create!(
city: guangzhou,
weather_date: 2.day.ago,
description: 'Sunny with some clouds',
temperature: 23.21,
feeling_temp: 22.11,
humidity: 65,
wind_scale: "0.7",
wind_speed: 15,
precipitation: 0,
pressure: 1014,
visibility: 10000,
cloud: 30,
prompt: "A clear day in Guangzhou, China. In the foreground, people are walking near the iconic Canton Tower, surrounded by vibrant greenery and modern buildings. The sky is blue with no clouds, and the sun is shining brightly. It's a perfect day, with a temperature of around 23 degrees Celsius. The scene captures the lively atmosphere of the city, showing locals enjoying their day out."
)
guangzhou_weather_art3.image.attach(
io: File.open("db/seeds/images/sample-guangzhou-weather-art-2.png"),
filename: "sample-guangzhou-weather-art-2.png",
content_type: "image/png"
)