feat: implement social sharing functionality

- Added `share_controller.js` to handle sharing logic.
- Created `_share_social.html.erb` partial for social sharing buttons.
- Integrated share buttons into city and weather art show pages.
- Added sharer.js dependency.

This feature allows users to share city and weather art pages on
various social media platforms such as Facebook, Twitter, LinkedIn,
Pinterest, Telegram, and WhatsApp, increasing content visibility.
This commit is contained in:
songtianlun 2025-02-16 11:58:25 +08:00
parent d4deddbb8c
commit 3f8b0dd231
8 changed files with 152 additions and 13 deletions

View File

@ -9,6 +9,7 @@ import FlashMessageController from "./flash_controller"
import SearchController from "./search_controller"
import PageLoadTimeController from "./page_load_time_controller"
import MapController from "./map_controller"
import ShareController from "./share_controller"
application.register("hello", HelloController)
application.register("photo-swipe-lightbox", PhotoSwipeLightBoxController)
@ -16,4 +17,5 @@ application.register("flash", FlashMessageController)
application.register("search", SearchController)
application.register("page-load-time", PageLoadTimeController)
application.register("map", MapController)
application.register("share", ShareController)

View File

@ -0,0 +1,12 @@
// app/javascript/controllers/share_controller.js
import { Controller } from "@hotwired/stimulus"
import Sharer from "sharer.js"
export default class extends Controller {
static targets = ["button"]
connect() {
// 初始化 sharer.js
window.Sharer.init()
}
}

View File

@ -77,23 +77,23 @@ class WeatherArt < ApplicationRecord
# 设置时区对象
time_zone = ActiveSupport::TimeZone[timezone_info["zoneName"]] ||
ActiveSupport::TimeZone["UTC"]
time = self.updated_at
date_string = self.weather_date&.strftime("%B %d, %Y")
time_string =
use_local_timezone ?
"#{time.in_time_zone(time_zone).strftime('%H:%M')} #{timezone_info['gmtOffsetName']}" :
"#{time.utc.strftime('%H:%M')} UTC"
case type
when :date
# 格式化日期
self&.weather_date&.strftime("%B %d, %Y")
date_string
when :time
# 获取时间
time = updated_at
if use_local_timezone
# 使用本地时区
local_time = time.in_time_zone(time_zone)
"#{local_time.strftime('%H:%M')} #{timezone_info['gmtOffsetName']}"
else
# 使用 UTC
"#{time.utc.strftime('%H:%M')} UTC"
end
time_string
when :all
"#{date_string} #{time_string}"
else
"#{date_string} #{time_string}"
end
end

View File

@ -70,6 +70,27 @@
</div>
<%= render 'cities/admin_panel' %>
<div class="card bg-base-100 backdrop-blur-md shadow-lg border border-primary/20 overflow-hidden">
<%
# 构建更吸引人的分享标题
share_title =
"🎨 #{@city.full_name}'s Weather Transformed into Art"
# 构建更有描述性的分享描述
share_description = [
"Discover this stunning AI-generated weather art!",
"in #{@city.full_name}.",
"Visit TodayAIWeather to see more amazing weather art."
].join(" ")
%>
<%= render "shared/share_social",
title: share_title,
description: share_description,
tags: "AIWeather,Art,AIart,Weather,#{@city&.name},#{@city&.country&.name}",
image: url_for(@city&.latest_weather_art&.webp_image&.processed)
%>
</div>
</div>
</div>
</div>
@ -99,4 +120,5 @@
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,74 @@
<!-- app/views/shared/_share_social.html.erb -->
<div class="card bg-base-100 p-4 rounded-2xl shadow-xl overflow-hidden"
data-controller="share">
<h3 class="font-display text-base font-medium center mb-4">Share This Page</h3>
<div class="flex flex-wrap gap-4 justify-center">
<!-- Facebook -->
<button class="btn btn-primary"
data-sharer="facebook"
data-title="<%= title %>"
data-url="<%= request.original_url %>">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"/>
</svg>
Facebook
</button>
<!-- Twitter/X -->
<button class="btn btn-info"
data-sharer="twitter"
data-title="<%= title %>"
data-hashtags=<%= tags %>
data-url="<%= request.original_url %>">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
Twitter
</button>
<!-- LinkedIn -->
<button class="btn btn-secondary"
data-sharer="linkedin"
data-url="<%= request.original_url %>">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
</svg>
LinkedIn
</button>
<!-- Pinterest -->
<button class="btn btn-accent"
data-sharer="pinterest"
data-url="<%= request.original_url %>"
data-image="<%= image %>"
data-description="<%= description %>">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0c-6.627 0-12 5.372-12 12 0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738.098.119.112.224.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146 1.124.347 2.317.535 3.554.535 6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z"/>
</svg>
Pinterest
</button>
<!-- WhatsApp -->
<button class="btn btn-success"
data-sharer="whatsapp"
data-title="<%= title %>"
data-url="<%= request.original_url %>">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/>
</svg>
WhatsApp
</button>
<!-- Telegram -->
<button class="btn btn-info"
data-sharer="telegram"
data-title="<%= title %>"
data-url="<%= request.original_url %>">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/>
</svg>
Telegram
</button>
</div>
</div>

View File

@ -94,6 +94,29 @@
</p>
</div>
<%
# 构建更吸引人的分享标题
share_title = [
"🎨 Amazing AI Weather Art: #{@weather_art.city.full_name}",
"#{@weather_art.description} at #{@weather_art.temperature}°C",
"#{@weather_art.formatted_time(:all, true)}"
].join("\n")
# 构建更有描述性的分享描述
share_description = [
"Discover this stunning AI-generated weather art!",
"#{@weather_art.description} in #{@weather_art.city.full_name}.",
"Created at #{@weather_art.formatted_time(:time, true)}",
"Visit TodayAIWeather to see more amazing weather art."
].join(" ")
%>
<%= render "shared/share_social",
title: share_title,
description: share_description,
tags: "AIWeather,Art,AIart,Weather,#{@weather_art.city&.name},#{@weather_art&.city&.country&.name}",
image: url_for(@weather_art.webp_image.processed)
%>
</div>
</div>

View File

@ -23,6 +23,7 @@
"photoswipe": "^5.4.4",
"postcss": "^8.5.1",
"sass": "^1.83.4",
"sharer.js": "^0.5.2",
"tailwindcss": "^3.4.17"
}
}

View File

@ -1265,6 +1265,11 @@ serialize-to-js@^3.1.2:
resolved "https://registry.yarnpkg.com/serialize-to-js/-/serialize-to-js-3.1.2.tgz#844b8a1c2d72412f68ea30da55090b3fc8e95790"
integrity sha512-owllqNuDDEimQat7EPG0tH7JjO090xKNzUtYz6X+Sk2BXDnOCilDdNLwjWeFywG9xkJul1ULvtUQa9O4pUaY0w==
sharer.js@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/sharer.js/-/sharer.js-0.5.2.tgz#68926277a4186384f98c8328d4cbd424d7d42aaa"
integrity sha512-HdwWYNSP+dJjCV5ogUOhKO7SormXamWC/00ThEcZMDBVuhsQ2/P0lBv/HYQ8jf5NxwxN/wad4YWEMPsfqlGecA==
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"