From c13bea950abf79c0a92cb4cfb2fd32c5f729394a Mon Sep 17 00:00:00 2001 From: Misei Date: Mon, 2 Feb 2026 09:24:25 +0900 Subject: [PATCH 1/3] feat: add developer info and donation modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add developer name (未完成成果物研究所) to version info - Implement donation modal that appears on first launch - Add donation dialog shown flag to app settings - Integrate Twitch subscription link (http://subs.twitch.tv/flowingspdg) - Use existing tauri-plugin-opener for external browser navigation --- src-tauri/Cargo.toml | 1 - src-tauri/capabilities/default.json | 24 ++--- src-tauri/src/commands.rs | 3 + src/App.tsx | 31 +++++- src/components/DonationModal.css | 156 ++++++++++++++++++++++++++++ src/components/DonationModal.tsx | 76 ++++++++++++++ src/components/VersionInfo.tsx | 2 +- src/hooks/useSettings.ts | 2 + 8 files changed, 280 insertions(+), 15 deletions(-) create mode 100644 src/components/DonationModal.css create mode 100644 src/components/DonationModal.tsx diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 008eb36..d8b3360 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -39,4 +39,3 @@ network-interface = "2.0.5" [target.'cfg(any(target_os = "macos", windows, target_os = "linux"))'.dependencies] tauri-plugin-updater = "2" tauri-plugin-process = "2" - diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index ef80212..6745c6f 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -1,12 +1,12 @@ -{ - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "Capability for the main window", - "windows": ["main"], - "permissions": [ - "core:default", - "opener:default", - "updater:default", - "process:default" - ] -} +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Capability for the main window", + "windows": ["main"], + "permissions": [ + "core:default", + "opener:default", + "updater:default", + "process:default" + ] +} diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 1a365c1..e7ae72b 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -33,6 +33,8 @@ pub struct AppSettings { pub obs: OBSSettings, pub master: MasterSettings, pub slave: SlaveSettings, + #[serde(default)] + pub donation_dialog_shown: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -69,6 +71,7 @@ impl Default for AppSettings { default_host: "192.168.1.100".to_string(), default_port: 8080, }, + donation_dialog_shown: false, } } } diff --git a/src/App.tsx b/src/App.tsx index d33ce9a..b2383db 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,10 +16,12 @@ import { AlertPanel } from "./components/AlertPanel"; import { OBSSourceList } from "./components/OBSSourceList"; import { SplashScreen } from "./components/SplashScreen"; import { VersionInfo } from "./components/VersionInfo"; +import { DonationModal } from "./components/DonationModal"; import { AppMode } from "./types/sync"; function App() { const [showSplash, setShowSplash] = useState(true); + const [showDonationModal, setShowDonationModal] = useState(false); const [appMode, setAppMode] = useState(null); const [obsHost, setObsHost] = useState("localhost"); const [obsPort, setObsPort] = useState(4455); @@ -128,11 +130,38 @@ function App() { } }; + const handleSplashComplete = () => { + setShowSplash(false); + // Show donation modal if it hasn't been shown before + if (settings && !settings.donationDialogShown) { + setShowDonationModal(true); + } + }; + + const handleCloseDonationModal = async () => { + setShowDonationModal(false); + // Mark donation dialog as shown + if (settings) { + try { + await saveSettings({ + ...settings, + donationDialogShown: true, + }); + } catch (error) { + console.error("Failed to save donation dialog status:", error); + } + } + }; + return (
{showSplash && ( - setShowSplash(false)} /> + )} + void; +} + +/** + * 寄付を呼びかけるモーダルダイアログ + */ +export function DonationModal({ isOpen, onClose }: DonationModalProps) { + const [isOpening, setIsOpening] = useState(false); + + if (!isOpen) { + return null; + } + + const handleDonate = async () => { + try { + setIsOpening(true); + await open("http://subs.twitch.tv/flowingspdg"); + // ブラウザを開いた後、少し待ってから閉じる + setTimeout(() => { + onClose(); + }, 500); + } catch (error) { + console.error("Failed to open donation URL:", error); + setIsOpening(false); + } + }; + + return ( +
+
e.stopPropagation()}> +
+

🎬 OBS Sync

+

by 未完成成果物研究所

+
+ +
+

+ OBS Syncをお使いいただきありがとうございます! +

+

+ このアプリケーションは無料でご利用いただけますが、 + 開発を継続するために、もしよろしければサポートをお願いいたします。 +

+
+ +
+ + +
+
+
+ ); +} diff --git a/src/components/VersionInfo.tsx b/src/components/VersionInfo.tsx index 00fcc2b..ad8c5d0 100644 --- a/src/components/VersionInfo.tsx +++ b/src/components/VersionInfo.tsx @@ -12,7 +12,7 @@ export function VersionInfo() { return ( - v{appVersion} ({gitCommit}) + v{appVersion} ({gitCommit}) | 未完成成果物研究所 ); } diff --git a/src/hooks/useSettings.ts b/src/hooks/useSettings.ts index 3c4a2a7..b29547d 100644 --- a/src/hooks/useSettings.ts +++ b/src/hooks/useSettings.ts @@ -20,6 +20,7 @@ export interface AppSettings { obs: OBSSettings; master: MasterSettings; slave: SlaveSettings; + donationDialogShown?: boolean; } export const useSettings = () => { @@ -48,6 +49,7 @@ export const useSettings = () => { defaultHost: "192.168.1.100", defaultPort: 8080, }, + donationDialogShown: false, }; setSettings(defaultSettings); return defaultSettings; From 2d14606aa0ee12df6de9c041686d9c876ee5a0f1 Mon Sep 17 00:00:00 2001 From: Misei Date: Mon, 2 Feb 2026 09:46:16 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E3=83=A2=E3=83=BC=E3=83=80=E3=83=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DonationModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/DonationModal.tsx b/src/components/DonationModal.tsx index fe9405e..fa41a58 100644 --- a/src/components/DonationModal.tsx +++ b/src/components/DonationModal.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { open } from "@tauri-apps/plugin-opener"; +import { openUrl } from "@tauri-apps/plugin-opener"; import "./DonationModal.css"; interface DonationModalProps { @@ -20,7 +20,7 @@ export function DonationModal({ isOpen, onClose }: DonationModalProps) { const handleDonate = async () => { try { setIsOpening(true); - await open("http://subs.twitch.tv/flowingspdg"); + await openUrl("http://subs.twitch.tv/flowingspdg"); // ブラウザを開いた後、少し待ってから閉じる setTimeout(() => { onClose(); From 5a6e45699f2904639f0025991a1966cc0e65f939 Mon Sep 17 00:00:00 2001 From: Misei Date: Mon, 2 Feb 2026 09:51:33 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E3=83=95=E3=83=83=E3=82=BF?= =?UTF-8?q?=E3=83=BC=E3=81=AB=E5=AF=84=E4=BB=98=E3=83=9C=E3=82=BF=E3=83=B3?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - フッターに寄付モーダルを開くボタンを追加 - 紫色のグラデーションデザインで既存UIに調和 - レスポンシブデザイン対応(モバイル表示時は縦並び) - ホバーエフェクトとアニメーション効果を実装 --- src/App.css | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/App.tsx | 13 ++++++++++-- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/App.css b/src/App.css index 99e3dae..977f8aa 100644 --- a/src/App.css +++ b/src/App.css @@ -685,6 +685,58 @@ button:not(:disabled):active { margin-top: auto; } +.footer-content { + display: flex; + justify-content: center; + align-items: center; + gap: 2rem; + margin-bottom: 1rem; + flex-wrap: wrap; +} + +.footer-copyright { + margin-top: 0.5rem; +} + +.btn-donation { + background: linear-gradient(135deg, #a855f7 0%, #7c3aed 100%); + color: white; + padding: 0.625rem 1.25rem; + border-radius: 9999px; + font-size: 0.875rem; + font-weight: 600; + box-shadow: 0 4px 12px rgba(168, 85, 247, 0.3); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + border: 1px solid rgba(255, 255, 255, 0.1); + position: relative; + overflow: hidden; +} + +.btn-donation::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transition: left 0.5s; +} + +.btn-donation:hover:not(:disabled)::before { + left: 100%; +} + +.btn-donation:hover:not(:disabled) { + transform: translateY(-2px) scale(1.05); + box-shadow: 0 8px 20px rgba(168, 85, 247, 0.5); + background: linear-gradient(135deg, #9333ea 0%, #6b21a8 100%); +} + +.btn-donation:active:not(:disabled) { + transform: translateY(0) scale(1.02); +} + /* Responsive */ @media (max-width: 768px) { .app-header { @@ -733,6 +785,11 @@ button:not(:disabled):active { .mode-badge { width: 100%; } + + .footer-content { + flex-direction: column; + gap: 1rem; + } } /* Toast Container Override */ diff --git a/src/App.tsx b/src/App.tsx index b2383db..15b7563 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -410,8 +410,17 @@ function App() {
);