Compare commits

...

16 Commits

Author SHA1 Message Date
d69a193e6d refactor: consolidate Docker build process
Some checks failed
CI / scan_ruby (push) Waiting to run
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
Docker / docker (push) Has been cancelled
- Removed unused Dockerfile.base and Dockerfile.build.
- Combined build steps into the main Dockerfile for improved clarity and maintenance.
- Updated base image references accordingly.

This change streamlines the Docker build process by reducing the number of Dockerfiles and improving the clarity of dependency management.
2025-02-02 00:44:36 +08:00
2c72e96977 feat: switch to using official ruby slim image
Update the Dockerfile to use the official ruby slim image, rather than a custom image. This reduces the Docker image size and improves build times.

- Update the base build and development images to use the official ruby slim image
- Remove redundant arguments in the build and development stages

Using the official ruby slim image simplifies the build process and reduces the image size, resulting in faster build times and a more maintainable Dockerfile.
2025-02-02 00:40:59 +08:00
378530cc1b feat: automate base image build for GitHub Actions
- Added new GitHub Actions to docker-main.yml to build and push base images
- Created a new Dockerfile.base with the base packages installation
- Modified the existing Dockerfile to use the new base image
- Created a new Dockerfile.build with the build stage to reduce the size of the final image
2025-02-02 00:38:11 +08:00
536b97a7da feat: update latest weather art display
- Change latest weather art limit from 6 to 20
- Shuffle the collection and display the last 10 items
- Update the section title to reflect the shuffling

This commit enhances the visibility of the latest weather art by
increasing the limit of displayed items. It randomizes the selection
of the latest art pieces for a more dynamic user experience, while the
UI title is updated to clarify this feature. This change improves user
engagement with the content.
2025-02-02 00:21:51 +08:00
f2951e2741 feat: optimize batch weather art generation
- Introduce BATCH_SIZE constant to limit processed cities
- Shuffle and limit eligible cities processing to enhance worker efficiency

This update improves the performance of the BatchGenerateWeatherArtsWorker
by ensuring that only a set number of cities are processed within the
allotted time, reducing the risk of timeouts and making the overall
system more responsive.
2025-02-01 15:01:36 +08:00
9417358625 refactor: adjust image loading in weather art view
- Update image link to use original blob instead of a resized variant
- Remove the resizing option for the image tag for better fidelity
- Modify CSS class for a smoother hover effect without scaling issues

This refactor improves the image loading behavior by allowing
full-resolution images to be loaded directly. The previous resizing
was limiting image quality, and this change enhances user experience
when viewing weather art.
2025-02-01 14:58:51 +08:00
dependabot[bot]
31bd6fd74e build(deps): bump solid_cable from 3.0.5 to 3.0.7
Bumps [solid_cable](https://github.com/rails/solid_cable) from 3.0.5 to 3.0.7.
- [Release notes](https://github.com/rails/solid_cable/releases)
- [Commits](https://github.com/rails/solid_cable/compare/v3.0.5...v3.0.7)

---
updated-dependencies:
- dependency-name: solid_cable
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 14:47:06 +08:00
dependabot[bot]
e36448e6d7 chore(deps): bump solid_queue from 1.1.2 to 1.1.3
Bumps [solid_queue](https://github.com/rails/solid_queue) from 1.1.2 to 1.1.3.
- [Release notes](https://github.com/rails/solid_queue/releases)
- [Commits](https://github.com/rails/solid_queue/compare/v1.1.2...v1.1.3)

---
updated-dependencies:
- dependency-name: solid_queue
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 14:46:56 +08:00
dependabot[bot]
11df3a31d1 chore(deps): bump puma from 6.5.0 to 6.6.0
Bumps [puma](https://github.com/puma/puma) from 6.5.0 to 6.6.0.
- [Release notes](https://github.com/puma/puma/releases)
- [Changelog](https://github.com/puma/puma/blob/master/History.md)
- [Commits](https://github.com/puma/puma/compare/v6.5.0...v6.6.0)

---
updated-dependencies:
- dependency-name: puma
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 14:46:42 +08:00
dependabot[bot]
2c3f8e1b8e chore(deps): bump aws-sdk-s3 from 1.177.0 to 1.179.0
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.177.0 to 1.179.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 14:46:33 +08:00
9a745dcee0 Merge branch 'dev' 2025-02-01 14:45:27 +08:00
09b3f06ad4 style: adjust pagination button sizes
- Change button classes from `btn` to `btn btn-xs` for all pagination buttons
- Ensure consistent styling across all pagination elements

These changes standardize the button sizes in the pagination component, improving the visual uniformity. The adjustment enhances user experience by making the pagination buttons more appropriately sized within the interface, without affecting functionality.
2025-02-01 14:45:17 +08:00
05449d1e7f chore: update PhotoSwipe import paths
- Change import for PhotoSwipeLightbox to 'photoswipe/lightbox'
- Change import for PhotoSwipe to 'photoswipe'

These updates reflect the new module structure of the PhotoSwipe library, ensuring that the controller utilizes the correct paths for improved functionality and maintainability.
2025-02-01 14:31:53 +08:00
905ec35fd8 feat: add photo swipe lightbox functionality
- Integrate PhotoSwipe library for enhanced image viewing
- Create PhotoSwipeLightBoxController to manage images
- Register lightbox controller in Stimulus framework
- Update views to include lightbox functionality
- Modify styles to accommodate new design elements

This commit introduces a new way for users to view images with
PhotoSwipe, improving the interactivity of the photo gallery. It
also includes adjustments to the layout and styles for better
presentation and user experience.
2025-02-01 14:19:19 +08:00
0352923c5b feat: update weather data report format
Some checks are pending
Docker / docker (push) Waiting to run
- Include actual update time in weather report
- Rename watermark worker file for clarity

This commit enhances the weather data report by
updating the format to include the actual update time
retrieved from the weather service API. Additionally,
the watermark worker file has been renamed to improve
readability and consistency in the naming convention.
2025-01-31 10:46:32 +08:00
bbf8dfc2e6 feat: add watermarking functionality to weather art
Some checks failed
Docker / docker (push) Has been cancelled
- Include the image_processing gem to handle image manipulation
- Create a background worker for adding watermarks to weather art images
- Update WeatherArt model to attach watermark images
- Add a new watermark image asset

This commit enhances the WeatherArt feature by allowing images to
have watermarks added asynchronously, improving the visual
presentation of the art. It ensures sufficient image dimensions
before processing and includes error handling for the worker.
2025-01-29 01:53:50 +08:00
21 changed files with 290 additions and 205 deletions

View File

@ -56,10 +56,12 @@ 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.177" gem "aws-sdk-s3", "~> 1.179"
gem "sidekiq", "~> 7.3" gem "sidekiq", "~> 7.3"
gem "sidekiq-scheduler", "~> 5.0" gem "sidekiq-scheduler", "~> 5.0"
gem "image_processing", "~> 1.13"
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
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"

View File

@ -93,17 +93,17 @@ 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.1035.0) aws-partitions (1.1043.0)
aws-sdk-core (3.215.0) aws-sdk-core (3.217.0)
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)
jmespath (~> 1, >= 1.6.1) jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.96.0) aws-sdk-kms (1.97.0)
aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5) aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.177.0) aws-sdk-s3 (1.179.0)
aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-core (~> 3, >= 3.216.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5) aws-sigv4 (~> 1.5)
aws-sigv4 (1.11.0) aws-sigv4 (1.11.0)
@ -164,6 +164,14 @@ GEM
multipart-post (~> 2.0) multipart-post (~> 2.0)
faraday-net_http (3.4.0) faraday-net_http (3.4.0)
net-http (>= 0.5.0) net-http (>= 0.5.0)
ffi (1.17.1-aarch64-linux-gnu)
ffi (1.17.1-aarch64-linux-musl)
ffi (1.17.1-arm-linux-gnu)
ffi (1.17.1-arm-linux-musl)
ffi (1.17.1-arm64-darwin)
ffi (1.17.1-x86_64-darwin)
ffi (1.17.1-x86_64-linux-gnu)
ffi (1.17.1-x86_64-linux-musl)
formtastic (5.0.0) formtastic (5.0.0)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
formtastic_i18n (0.7.0) formtastic_i18n (0.7.0)
@ -181,15 +189,19 @@ GEM
csv csv
mini_mime (>= 1.0.0) mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
i18n (1.14.6) i18n (1.14.7)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
image_processing (1.13.0)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
inherited_resources (1.14.0) inherited_resources (1.14.0)
actionpack (>= 6.0) actionpack (>= 6.0)
has_scope (>= 0.6) has_scope (>= 0.6)
railties (>= 6.0) railties (>= 6.0)
responders (>= 2) responders (>= 2)
io-console (0.8.0) io-console (0.8.0)
irb (1.14.3) irb (1.15.1)
pp (>= 0.6.0)
rdoc (>= 4.0.0) rdoc (>= 4.0.0)
reline (>= 0.4.2) reline (>= 0.4.2)
jbuilder (2.13.0) jbuilder (2.13.0)
@ -240,6 +252,7 @@ GEM
matrix (0.4.2) matrix (0.4.2)
meta-tags (2.22.1) meta-tags (2.22.1)
actionpack (>= 6.0.0, < 8.1) actionpack (>= 6.0.0, < 8.1)
mini_magick (4.13.2)
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.25.4) minitest (5.25.4)
msgpack (1.7.5) msgpack (1.7.5)
@ -263,21 +276,21 @@ GEM
net-protocol net-protocol
net-ssh (7.3.0) net-ssh (7.3.0)
nio4r (2.7.4) nio4r (2.7.4)
nokogiri (1.18.1-aarch64-linux-gnu) nokogiri (1.18.2-aarch64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.1-aarch64-linux-musl) nokogiri (1.18.2-aarch64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.1-arm-linux-gnu) nokogiri (1.18.2-arm-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.1-arm-linux-musl) nokogiri (1.18.2-arm-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.1-arm64-darwin) nokogiri (1.18.2-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.1-x86_64-darwin) nokogiri (1.18.2-x86_64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.1-x86_64-linux-gnu) nokogiri (1.18.2-x86_64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.1-x86_64-linux-musl) nokogiri (1.18.2-x86_64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ostruct (0.6.1) ostruct (0.6.1)
@ -286,6 +299,9 @@ GEM
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pg (1.5.9) pg (1.5.9)
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
propshaft (1.1.0) propshaft (1.1.0)
actionpack (>= 7.0.0) actionpack (>= 7.0.0)
activesupport (>= 7.0.0) activesupport (>= 7.0.0)
@ -295,7 +311,7 @@ GEM
date date
stringio stringio
public_suffix (6.0.1) public_suffix (6.0.1)
puma (6.5.0) puma (6.6.0)
nio4r (~> 2.0) nio4r (~> 2.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.8.1) racc (1.8.1)
@ -386,6 +402,9 @@ GEM
faraday (>= 1) faraday (>= 1)
faraday-multipart (>= 1) faraday-multipart (>= 1)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
ruby-vips (2.2.2)
ffi (~> 1.12)
logger
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rubyzip (2.4.1) rubyzip (2.4.1)
rufus-scheduler (3.9.2) rufus-scheduler (3.9.2)
@ -410,7 +429,7 @@ GEM
tilt (>= 1.4.0, < 3) tilt (>= 1.4.0, < 3)
sitemap_generator (6.3.0) sitemap_generator (6.3.0)
builder (~> 3.0) builder (~> 3.0)
solid_cable (3.0.5) solid_cable (3.0.7)
actioncable (>= 7.2) actioncable (>= 7.2)
activejob (>= 7.2) activejob (>= 7.2)
activerecord (>= 7.2) activerecord (>= 7.2)
@ -419,7 +438,7 @@ GEM
activejob (>= 7.2) activejob (>= 7.2)
activerecord (>= 7.2) activerecord (>= 7.2)
railties (>= 7.2) railties (>= 7.2)
solid_queue (1.1.2) solid_queue (1.1.3)
activejob (>= 7.1) activejob (>= 7.1)
activerecord (>= 7.1) activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1) concurrent-ruby (>= 1.3.1)
@ -492,7 +511,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
activeadmin (~> 3.2) activeadmin (~> 3.2)
ahoy_matey (~> 5.2) ahoy_matey (~> 5.2)
aws-sdk-s3 (~> 1.177) aws-sdk-s3 (~> 1.179)
bootsnap bootsnap
brakeman brakeman
capybara capybara
@ -502,6 +521,7 @@ DEPENDENCIES
down (~> 5.4) down (~> 5.4)
friendly_id (~> 5.5) friendly_id (~> 5.5)
httparty (~> 0.22.0) httparty (~> 0.22.0)
image_processing (~> 1.13)
jbuilder jbuilder
jsbundling-rails jsbundling-rails
kamal kamal

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -1,3 +1,4 @@
@import "photoswipe/dist/photoswipe.css";
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;

View File

@ -1,6 +1,6 @@
class HomeController < ApplicationController class HomeController < ApplicationController
def index def index
@latest_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(6) @latest_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(20).shuffle.last(10)
@featured_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(5) @featured_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(5)
set_meta_tags( set_meta_tags(
title: "AI-Generated Weather Art", title: "AI-Generated Weather Art",

View File

@ -1,5 +1,6 @@
// Entry point for the build script in your package.json // Entry point for the build script in your package.json
import "@hotwired/turbo-rails" import "@hotwired/turbo-rails"
import "@hotwired/stimulus"
import "@fontsource/playfair-display/400.css"; import "@fontsource/playfair-display/400.css";
import "@fontsource/playfair-display/700.css"; import "@fontsource/playfair-display/700.css";
import "@fontsource/raleway/400.css"; import "@fontsource/raleway/400.css";

View File

@ -6,3 +6,9 @@ import { application } from "./application"
import HelloController from "./hello_controller" import HelloController from "./hello_controller"
application.register("hello", HelloController) application.register("hello", HelloController)
import PhotoSwipeLightBoxController from "./photo_swipe_lightbox_controller"
console.log("ready to register photo-swipe")
application.register("photo-swipe-lightbox", PhotoSwipeLightBoxController)
console.log("successful to register photo-swipe")

View File

@ -0,0 +1,42 @@
import { Controller } from "@hotwired/stimulus"
import PhotoSwipeLightbox from 'photoswipe/lightbox'
import PhotoSwipe from 'photoswipe'
import 'photoswipe/dist/photoswipe.css'
export default class extends Controller {
static targets = ['image', 'gallery']
connect() {
this.initPhotoSwipeLightbox()
}
initPhotoSwipeLightbox() {
const lightbox = new PhotoSwipeLightbox({
gallery: this.galleryTarget,
children: 'a',
pswpModule: PhotoSwipe,
initialZoomInEndEvent: 'mousedown',
dataSource: (items) => {
return items.map((item) => ({
src: item.dataset.pswpSrc,
w: parseInt(item.dataset.pswpWidth, 10),
h: parseInt(item.dataset.pswpHeight, 10),
title: item.dataset.pswpCaption,
}))
},
padding: { top: 0, bottom: 0, left: 0, right: 0 }, // 自定义图片与页面边界的填充
closeOnScroll: false,
zoom: true, // 启用缩放功能
bgOpacity: 0.9, // 背景透明度
pswpUIOptions: {
arrowPrev: true,
arrowNext: true,
zoom: true, // 添加缩放按钮
fullscreen: true, // 添加全屏按钮
counter: true, // 显示当前图片编号
}
})
lightbox.init()
// console.log('PhotoSwipeLightbox instance:', lightbox);
}
}

View File

@ -4,6 +4,7 @@ class WeatherArt < ApplicationRecord
belongs_to :city belongs_to :city
has_one_attached :image has_one_attached :image
has_one_attached :image_with_watermark
has_many :visits, class_name: "Ahoy::Visit", foreign_key: :weather_art_id has_many :visits, class_name: "Ahoy::Visit", foreign_key: :weather_art_id
has_many :events, class_name: "Ahoy::Event", foreign_key: :weather_art_id has_many :events, class_name: "Ahoy::Event", foreign_key: :weather_art_id
@ -50,4 +51,8 @@ class WeatherArt < ApplicationRecord
Ahoy::Event.where("properties::jsonb->>'event_type' = 'weather_art_view' AND (properties::jsonb->>'weather_art_id')::integer = ?", self.id).count Ahoy::Event.where("properties::jsonb->>'event_type' = 'weather_art_view' AND (properties::jsonb->>'weather_art_id')::integer = ?", self.id).count
end end
end end
def image_url
image.attached? ? image.blob : nil
end
end end

View File

@ -50,7 +50,7 @@ class AiService
- Temperature: #{weather_data[:temperature]}°C - Temperature: #{weather_data[:temperature]}°C
- Weather: #{weather_data[:description]} - Weather: #{weather_data[:description]}
- Cloud cover: #{weather_data[:cloud]}% - Cloud cover: #{weather_data[:cloud]}%
- Time: Early morning - Time: #{weather_data[:time]}
Requirements: Requirements:
- Feature iconic landmarks or architecture from #{city.name} - Feature iconic landmarks or architecture from #{city.name}

View File

@ -31,7 +31,8 @@ class WeatherService
pressure: data["pressure"].to_f, pressure: data["pressure"].to_f,
visibility: data["vis"].to_f, visibility: data["vis"].to_f,
cloud: data["cloud"].to_f, cloud: data["cloud"].to_f,
description: data["text"] description: data["text"],
time: response["updateTime"]
} }
end end
end end

View File

@ -25,7 +25,7 @@
<!-- 最新天气艺术 --> <!-- 最新天气艺术 -->
<section class="container mx-auto px-4 py-16 space-y-12"> <section class="container mx-auto px-4 py-16 space-y-12">
<h2 class="text-3xl font-display font-bold text-center">Latest Weather Art</h2> <h2 class="text-3xl font-display font-bold text-center">Shuffle Latest Weather Art</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<% @latest_arts.each do |art| %> <% @latest_arts.each do |art| %>

View File

@ -33,22 +33,22 @@
<%# Includes all stylesheet files in app/assets/stylesheets %> <%# Includes all stylesheet files in app/assets/stylesheets %>
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %> <%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<script defer data-domain="todayaiweather.com" src="https://plausible.frytea.com/js/script.js"></script> <!-- <script defer data-domain="todayaiweather.com" src="https://plausible.frytea.com/js/script.js"></script>-->
<script defer src="https://busuanzi.frytea.com/js"></script> <!-- <script defer src="https://busuanzi.frytea.com/js"></script>-->
<!-- Google tag (gtag.js) --> <!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-PX1C92V5L7"></script> <!-- <script async src="https://www.googletagmanager.com/gtag/js?id=G-PX1C92V5L7"></script>-->
<script> <!-- <script>-->
window.dataLayer = window.dataLayer || []; <!-- window.dataLayer = window.dataLayer || [];-->
function gtag(){dataLayer.push(arguments);} <!-- function gtag(){dataLayer.push(arguments);}-->
gtag('js', new Date()); <!-- gtag('js', new Date());-->
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" <!-- <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7296634171837358"-->
crossorigin="anonymous"></script> <!-- crossorigin="anonymous"></script>-->
</head> </head>

View File

@ -12,7 +12,7 @@
<div class="join shadow-lg"> <div class="join shadow-lg">
<!-- 首页 --> <!-- 首页 -->
<%= link_to url_for(page: 1, region: params[:region], country: params[:country], sort: params[:sort]), <%= link_to url_for(page: 1, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.first_page? ? 'btn-disabled' : 'btn-ghost'}" do %> class: "join-item btn btn-xs #{collection.first_page? ? 'btn-disabled' : 'btn-ghost'}" 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="M11 19l-7-7 7-7m8 14l-7-7 7-7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
</svg> </svg>
@ -20,7 +20,7 @@
<!-- 上一页 --> <!-- 上一页 -->
<%= link_to url_for(page: collection.prev_page || 1, region: params[:region], country: params[:country], sort: params[:sort]), <%= link_to url_for(page: collection.prev_page || 1, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.first_page? ? 'btn-disabled' : 'btn-ghost'}" do %> class: "join-item btn btn-xs #{collection.first_page? ? 'btn-disabled' : 'btn-ghost'}" 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>
@ -33,35 +33,35 @@
<% if start_page > 1 %> <% if start_page > 1 %>
<%= link_to 1, url_for(page: 1, region: params[:region], country: params[:country], sort: params[:sort]), <%= link_to 1, url_for(page: 1, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn btn-ghost hover:bg-primary/5" %> class: "join-item btn btn-xs btn-ghost hover:bg-primary/5" %>
<% if start_page > 2 %> <% if start_page > 2 %>
<button class="join-item btn btn-ghost btn-disabled">...</button> <button class="join-item btn btn-xs btn-ghost btn-disabled">...</button>
<% end %> <% end %>
<% end %> <% end %>
<% (start_page..end_page).each do |page| %> <% (start_page..end_page).each do |page| %>
<% if page == collection.current_page %> <% if page == collection.current_page %>
<button class="join-item btn btn-ghost bg-primary/10 font-medium"> <button class="join-item btn btn-xs btn-ghost bg-primary/10 font-medium">
<%= page %> <%= page %>
</button> </button>
<% else %> <% else %>
<%= link_to page, url_for(page: page, region: params[:region], country: params[:country], sort: params[:sort]), <%= link_to page, url_for(page: page, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn btn-ghost hover:bg-primary/5" %> class: "join-item btn btn-xs btn-ghost hover:bg-primary/5" %>
<% end %> <% end %>
<% end %> <% end %>
<% if end_page < collection.total_pages %> <% if end_page < collection.total_pages %>
<% if end_page < collection.total_pages - 1 %> <% if end_page < collection.total_pages - 1 %>
<button class="join-item btn btn-ghost btn-disabled">...</button> <button class="join-item btn btn-xs btn-ghost btn-disabled">...</button>
<% end %> <% end %>
<%= link_to collection.total_pages, <%= link_to collection.total_pages,
url_for(page: collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]), url_for(page: collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn btn-ghost hover:bg-primary/5" %> class: "join-item btn btn-xs btn-ghost hover:bg-primary/5" %>
<% end %> <% end %>
<!-- 下一页 --> <!-- 下一页 -->
<%= link_to url_for(page: collection.next_page || collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]), <%= link_to url_for(page: collection.next_page || collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.last_page? ? 'btn-disabled' : 'btn-ghost'}" do %> class: "join-item btn btn-xs #{collection.last_page? ? 'btn-disabled' : 'btn-ghost'}" 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="M9 5l7 7-7 7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg> </svg>
@ -69,7 +69,7 @@
<!-- 末页 --> <!-- 末页 -->
<%= link_to url_for(page: collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]), <%= link_to url_for(page: collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.last_page? ? 'btn-disabled' : 'btn-ghost'}" do %> class: "join-item btn btn-xs #{collection.last_page? ? 'btn-disabled' : 'btn-ghost'}" 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="M13 5l7 7-7 7M5 5l7 7-7 7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
</svg> </svg>

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

@ -0,0 +1,37 @@
<%# Partial _weather_stats.html.erb %>
<div class="stat bg-gradient-to-br from-primary/10 to-primary/20 hover:from-primary hover:to-primary/30 p-4 rounded-lg">
<div class="stat-title font-medium text-base">Temperature</div>
<div class="stat-value text-3xl"><%= weather_art.temperature %>°C</div>
<div class="stat-desc">Feels like <%= weather_art.feeling_temp %>°C</div>
</div>
<div class="stat bg-gradient-to-br from-secondary/10 to-secondary/20 hover:from-secondary hover:to-secondary/30 p-4 rounded-lg">
<div class="stat-title font-medium text-base">Wind</div>
<div class="stat-value text-3xl"><%= weather_art.wind_scale %></div>
<div class="stat-desc"><%= weather_art.wind_speed %> km/h</div>
</div>
<div class="stat bg-base-300 hover:bg-base-400 p-4 rounded-lg">
<div class="stat-title font-medium text-base">Humidity</div>
<div class="stat-value text-3xl"><%= weather_art.humidity %>%</div>
<div class="stat-desc">Relative humidity</div>
</div>
<div class="stat bg-base-300 hover:bg-base-400 p-4 rounded-lg">
<div class="stat-title font-medium text-base">Visibility</div>
<div class="stat-value text-3xl"><%= weather_art.visibility %> km</div>
<div class="stat-desc">Clear view distance</div>
</div>
<div class="stat bg-accent/10 hover:bg-accent p-4 rounded-lg">
<div class="stat-title font-medium text-base">Pressure</div>
<div class="stat-value text-3xl"><%= weather_art.pressure %> hPa</div>
<div class="stat-desc">Atmospheric pressure</div>
</div>
<div class="stat bg-base-200 hover:bg-base-100 p-4 rounded-lg">
<div class="stat-title font-medium text-base">Cloud Cover</div>
<div class="stat-value text-3xl"><%= weather_art.cloud %>%</div>
<div class="stat-desc">Sky coverage</div>
</div>

View File

@ -4,155 +4,88 @@
</script> </script>
<% end %> <% end %>
<div class="relative min-h-screen bg-base-200"> <div class="relative min-h-screen bg-white"> <!-- 使用更明快的背景颜色 -->
<!-- 背景图片 --> <div class="container mx-auto px-4 pt-12 pb-16">
<% if @weather_art.image.attached? %> <div class="max-w-6xl mx-auto space-y-6">
<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="flex items-center">
<!-- 返回导航 --> <%= link_to city_path(@weather_art.city),
<div class="container mx-auto px-4 py-6"> class: "btn btn-ghost btn-md gap-2 bg-base-200 hover:bg-base-300 transition-all duration-300" do %>
<%= link_to city_path(@weather_art.city), <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
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 %> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> </svg>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" /> Back to <%= @weather_art.city.name %>
</svg> <% end %>
Back to <%= @weather_art.city.name %> </div>
<% end %>
</div>
<div class="container mx-auto px-4 pb-16"> <!-- 主要内容 -->
<div class="max-w-6xl mx-auto"> <div class="card bg-base-200/80 backdrop-blur-md shadow-lg overflow-hidden"> <!-- 调整透明度和阴影 -->
<!-- 头部信息 --> <div class="grid lg:grid-cols-2 gap-6 items-center">
<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">
<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" />
</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"> <% if @weather_art.image.attached? %>
Weather Art <figure class="relative lg:h-[30rem] h-auto overflow-hidden rounded-lg"> <!-- 添加圆角 -->
</span> <div class="gallery" data-controller="photo-swipe-lightbox">
</h1> <div data-photo-swipe-lightbox-target="gallery" class="h-full">
<% blob = @weather_art.image_blob %>
<%= link_to rails_blob_path(blob),
data: {
pswp_src: rails_blob_url(blob),
pswp_caption: 'Weather Art',
pswp_width: 1792,
pswp_height: 1024
} do %>
<%= image_tag @weather_art.image,
class: "object-cover w-full h-full transition-transform transform hover:scale-105 ease-in-out" %> <!-- 改变缩放效果 -->
<% end %>
</div>
</div>
</figure>
<% end %>
<div class="flex flex-wrap justify-center items-center gap-3"> <!-- 信息区域 -->
<div class="badge badge-lg badge-primary gap-2"> <div class="card-body p-8 lg:py-10 lg:px-12">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <div class="prose max-w-none">
<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" /> <h1 class="font-display text-4xl md:text-5xl font-bold text-gradient mb-6">
</svg> Weather Art
<%= @weather_art.weather_date.strftime("%B %d, %Y") %> </h1>
</div>
<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 class="flex flex-wrap gap-4 mb-6">
<div class="card lg:card-side bg-base-100/80 backdrop-blur-md shadow-2xl"> <div class="badge badge-lg badge-primary">
<figure class="lg:w-1/2 relative aspect-square lg:aspect-auto group"> <%= @weather_art.weather_date.strftime("%B %d, %Y") %>
<% if @weather_art.image.attached? %> </div>
<%= image_tag @weather_art.image, <div class="badge badge-lg badge-secondary">
class: "w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" %> <%= @weather_art.weather_date.strftime("%H:%M") %>
<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> </div>
<% end %> </div>
</figure>
<div class="card-body lg:w-1/2"> <h2 class="text-2xl font-semibold mb-4">
<div class="prose max-w-none mb-8">
<h2 class="card-title font-display text-3xl mb-4 flex items-center gap-3">
<%= weather_description_icon(@weather_art.description) %> <%= weather_description_icon(@weather_art.description) %>
<%= @weather_art.description %> <%= @weather_art.description %>
</h2> </h2>
<div class="divider"></div> <div class="divider"></div>
</div>
<!-- 天气数据网格 --> <div class="grid grid-cols-2 gap-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <%= render 'weather_stats', weather_art: @weather_art %> <!-- 使用局部渲染 -->
<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">
<%= weather_stat_icon("temperature") %>
<div class="stat-title font-medium">Temperature</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 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">
<%= weather_stat_icon("wind") %>
<div class="stat-title font-medium">Wind</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 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">
<%= weather_stat_icon("humidity") %>
<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 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">
<%= weather_stat_icon("visibility") %>
<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 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">
<%= weather_stat_icon("pressure") %>
<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 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">
<%= weather_stat_icon("cloud") %>
<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>
<!-- AI Prompt -->
<div class="mt-8">
<div class="bg-base-200/50 backdrop-blur-sm p-6 rounded-box border border-base-300">
<div class="flex items-center gap-3 mb-4">
<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>
</div> </div>
<!-- AI Prompt -->
<div class="bg-primary/10 backdrop-blur-md p-6 rounded-lg border border-primary/20">
<div class="flex items-center gap-3 mb-4">
<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/80 leading-relaxed">
<%= @weather_art.prompt %>
</p>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,53 @@
class AddWatermarkToWeatherArtWorker
include Sidekiq::Worker
def perform(weather_art_id)
@weather_art = WeatherArt.find_by(id: weather_art_id)
return unless @weather_art
add_watermark
rescue StandardError => e
Rails.logger.error "Error adding watermark to WeatherArt #{weather_art_id}: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
end
private
attr_reader :weather_art
def add_watermark
return if weather_art.image_with_watermark.attached?
watermark_path = Rails.root.join("app/assets/images/today_ai_weather_copyright_watermark1.png")
return unless File.exist?(watermark_path)
image_tempfile = nil
watermark_tempfile = nil
begin
image_tempfile = weather_art.image.download
return unless image_dimensions_are_sufficient?(image_tempfile.path)
image = ImageProcessing::Vips.source(image_tempfile.path)
watermark = ImageProcessing::Vips.source(watermark_path)
watermarked_image = image.composite(watermark, "overlay")
watermark_tempfile = Tempfile.new([ "watermarked_image", ".png" ])
watermarked_image.write_to_file(watermark_tempfile.path)
weather_art.image_with_watermark.attach(
io: File.open(watermark_tempfile.path),
filename: "#{generate_filename("watermarked")}",
content_type: "image/png"
)
ensure
watermark_tempfile.unlink if watermark_tempfile
end
end
def image_dimensions_are_sufficient?(image_path)
dimensions = ImageProcessing::Vips.source(image_path).sizes
dimensions.width >= 200 && dimensions.height >= 200
end
def generate_filename(prefix)
"#{prefix}_#{weather_art.image.filename.base}"
end
end

View File

@ -1,19 +1,16 @@
class BatchGenerateWeatherArtsWorker class BatchGenerateWeatherArtsWorker
include Sidekiq::Worker include Sidekiq::Worker
GENERATION_INTERVAL = 24.hours GENERATION_INTERVAL = 24.hours
MAX_DURATION = 50.minutes MAX_DURATION = 50.minutes
SLEEP_DURATION = 120.seconds SLEEP_DURATION = 120.seconds
BATCH_SIZE = 20
def perform(*args) def perform(*args)
start_time = Time.current start_time = Time.current
cities_to_process = get_eligible_cities.shuffle.take(BATCH_SIZE)
cities_to_process = get_eligible_cities
cities_to_process.each do |city| cities_to_process.each do |city|
break if Time.current - start_time > MAX_DURATION break if Time.current - start_time > MAX_DURATION
Rails.logger.info "Generating weather art for #{city.name}" Rails.logger.info "Generating weather art for #{city.name}"
GenerateWeatherArtWorker.perform_async(city.id) GenerateWeatherArtWorker.perform_async(city.id)
sleep SLEEP_DURATION sleep SLEEP_DURATION
end end
@ -23,7 +20,6 @@ class BatchGenerateWeatherArtsWorker
def get_eligible_cities def get_eligible_cities
cutoff_time = Time.current - GENERATION_INTERVAL cutoff_time = Time.current - GENERATION_INTERVAL
City.active City.active
.joins("LEFT JOIN ( .joins("LEFT JOIN (
SELECT city_id, MAX(created_at) as last_generation_time SELECT city_id, MAX(created_at) as last_generation_time

View File

@ -18,6 +18,7 @@
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"jquery": "^3.7.1", "jquery": "^3.7.1",
"jquery-ui": "^1.14.1", "jquery-ui": "^1.14.1",
"photoswipe": "^5.4.4",
"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

@ -153,7 +153,7 @@
"@hotwired/stimulus@^3.2.2": "@hotwired/stimulus@^3.2.2":
version "3.2.2" version "3.2.2"
resolved "https://registry.npmjs.org/@hotwired/stimulus/-/stimulus-3.2.2.tgz" resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608"
integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A== integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A==
"@hotwired/turbo-rails@^8.0.12": "@hotwired/turbo-rails@^8.0.12":
@ -722,20 +722,13 @@ jiti@^1.21.6:
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz" resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz"
integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A== integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==
jquery-ui@^1.13.3: jquery-ui@^1.13.3, jquery-ui@^1.14.1:
version "1.14.1" version "1.14.1"
resolved "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.14.1.tgz" resolved "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.14.1.tgz"
integrity sha512-DhzsYH8VeIvOaxwi+B/2BCsFFT5EGjShdzOcm5DssWjtcpGWIMsn66rJciDA6jBruzNiLf1q0KvwMoX1uGNvnQ== integrity sha512-DhzsYH8VeIvOaxwi+B/2BCsFFT5EGjShdzOcm5DssWjtcpGWIMsn66rJciDA6jBruzNiLf1q0KvwMoX1uGNvnQ==
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"
@ -853,6 +846,11 @@ path-scurry@^1.11.1:
lru-cache "^10.2.0" lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
photoswipe@^5.4.4:
version "5.4.4"
resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-5.4.4.tgz#e045dc036453493188d5c8665b0e8f1000ac4d6e"
integrity sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==
picocolors@^1, picocolors@^1.0.1, picocolors@^1.1.1: picocolors@^1, picocolors@^1.0.1, picocolors@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"