From 350bcfb60e2202779912c059e27837aba61b5709 Mon Sep 17 00:00:00 2001 From: Sea10wood Date: Sun, 11 Aug 2024 14:04:39 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E3=83=96=E3=83=A9=E3=83=B3=E3=83=81?= =?UTF-8?q?=E3=82=92=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88=E3=82=8B=E5=89=8D?= =?UTF-8?q?=E3=81=AE=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/responsive/homeSP/index.tsx | 2 ++ src/components/ui/Rule/index.module.css | 12 ++++++++++++ src/components/ui/Rule/index.tsx | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/components/ui/Rule/index.module.css create mode 100644 src/components/ui/Rule/index.tsx diff --git a/src/components/responsive/homeSP/index.tsx b/src/components/responsive/homeSP/index.tsx index 92fdcbd..9b6c79e 100644 --- a/src/components/responsive/homeSP/index.tsx +++ b/src/components/responsive/homeSP/index.tsx @@ -3,6 +3,7 @@ import { useSocketRefStore } from "../../../store"; import { requestPermission } from "../../../utils/permission"; import { DefaultButton } from "../../ui/Button"; import styles from "./index.module.css"; +import Rule from "../../ui/Rule"; function HomeSP() { const navigate = useNavigate(); @@ -59,6 +60,7 @@ function HomeSP() { 射的へ向かう + ); diff --git a/src/components/ui/Rule/index.module.css b/src/components/ui/Rule/index.module.css new file mode 100644 index 0000000..778150b --- /dev/null +++ b/src/components/ui/Rule/index.module.css @@ -0,0 +1,12 @@ +.text{ + font-size: 16px; + color: #212121; + padding: 24px; + font-family: Yuji Syuku, sans-serif; + line-height: 1.5; + font-weight: 400; + font-style: normal; + position: absolute; + bottom: 10px; + text-align: left; +} \ No newline at end of file diff --git a/src/components/ui/Rule/index.tsx b/src/components/ui/Rule/index.tsx new file mode 100644 index 0000000..6368383 --- /dev/null +++ b/src/components/ui/Rule/index.tsx @@ -0,0 +1,18 @@ +import styles from './index.module.css' + +function Rule() { + return ( +
+

〜ルール〜

+

+ 1,画面にスマホを向け、ポインタの位置を確認(1回につき3発のコルク玉が渡されます) +
+ 2,狙いを目掛けてスマホのトリガーボタンを押すと当たればGetです +
+ 3,結果はぜひSNSでポストしてね +

+
+ ); +} + +export default Rule; From 9dea0bb45c8f2bae38990a86b2d23cd7227fd8e5 Mon Sep 17 00:00:00 2001 From: Sea10wood Date: Sun, 11 Aug 2024 15:43:46 +0900 Subject: [PATCH 2/3] Merge branch 'query_auto_making' of github.com:claustra01/virtual-natsumatsuri-frontend --- cspell.json | 2 +- src/components/QRCodeGenerator.tsx | 20 ++ .../responsive/homePC/index.module.css | 229 ++++++++++++------ src/components/responsive/homePC/index.tsx | 104 +++++--- .../responsive/homeSP/index.module.css | 13 + src/components/responsive/homeSP/index.tsx | 14 +- src/components/ui/Button/index.module.css | 7 +- src/components/ui/Rule/index.module.css | 12 - src/components/ui/Rule/index.tsx | 4 +- src/components/ui/TextButton/index.module.css | 16 ++ src/index.css | 9 +- src/store/index.ts | 1 + src/store/useRoomIdStore.ts | 15 ++ src/utils/copyClipBoard.ts | 10 + src/utils/queryParams.ts | 19 ++ 15 files changed, 330 insertions(+), 145 deletions(-) create mode 100644 src/components/QRCodeGenerator.tsx delete mode 100644 src/components/ui/Rule/index.module.css create mode 100644 src/store/useRoomIdStore.ts create mode 100644 src/utils/copyClipBoard.ts create mode 100644 src/utils/queryParams.ts diff --git a/cspell.json b/cspell.json index 3255c33..3da8c6e 100644 --- a/cspell.json +++ b/cspell.json @@ -2,5 +2,5 @@ "ignorePaths": ["node_modules/**", "*.svg"], "version": "0.2", "language": "en", - "words": ["NATSUMATSURI", "yatai", "Dela", "Yuji", "Syuku", "zustand", "wadaiko"] + "words": ["NATSUMATSURI", "yatai", "Dela", "Yuji", "Syuku", "zustand", "wadaiko", "qrcode"] } diff --git a/src/components/QRCodeGenerator.tsx b/src/components/QRCodeGenerator.tsx new file mode 100644 index 0000000..e98bd8b --- /dev/null +++ b/src/components/QRCodeGenerator.tsx @@ -0,0 +1,20 @@ +import QRCode from "qrcode.react"; + +type QRCodeGeneratorProps = { + size?: number; + url: string; + onUrlGenerated?: (url: string) => void; +}; + +const QRCodeGenerator: React.FC = ({ + size = 128, + url, +}) => { + return ( +
+ +
+ ); +}; + +export default QRCodeGenerator; diff --git a/src/components/responsive/homePC/index.module.css b/src/components/responsive/homePC/index.module.css index 6ef54f8..cd4c496 100644 --- a/src/components/responsive/homePC/index.module.css +++ b/src/components/responsive/homePC/index.module.css @@ -1,113 +1,184 @@ @keyframes infinity-scroll-left { - from { - transform: translateX(0); - } - to { - transform: translateX(-100%); - } + from { + transform: translateX(0); + } + to { + transform: translateX(-100%); + } +} + +.scroll-infinity { + position: absolute; + display: flex; + z-index: 100; + width: 100vw; + overflow: hidden; } .scroll-infinity__wrap { - display: flex; - overflow: hidden; - width: 100vw; + overflow: hidden; } .scroll-infinity__list { - display: flex; - list-style: none; - padding: 0; + display: flex; + list-style: none; + padding: 0; } .scroll-infinity__list--left { - animation: infinity-scroll-left 60s infinite linear 0.5s both; + animation: infinity-scroll-left 60s infinite linear 0.5s both; } .scroll-infinity__item { - width: 33.33vw; + width: 33.33vw; } .scroll-infinity__item > img { - width: 100%; + width: 100%; } .background-logo { - opacity: 0.2; - position: absolute; - top: 50%; - left: 24%; - transform: translate(-50%, -50%); - justify-content: center; - align-items: center; - max-width: 48%; + opacity: 0.1; + position: absolute; + top: 50%; + left: 24%; + transform: translate(-50%, -50%); + justify-content: center; + align-items: center; + max-width: 48%; +} +.background-logo img { + height: 90vh; + aspect-ratio: 1 / 1; } li { - font-size: 40px; - padding: 0 32px; + font-size: 40px; + padding: 0 32px; +} + +.red-lite { + opacity: 0.8; + position: absolute; + top: 2%; + width: 200px; + height: 200px; + right: 0; + z-index: -1; +} + +.pistol-img { + opacity: 0.2; + position: absolute; + top: 25%; + right: 12px; + transform: scale(-1, 1); +} + +.overlay-square { + position: absolute; + top: 20%; + right: 120px; + width: 520px; + height: 532px; + z-index: 1; +} + +.qr-scan { + position: absolute; + bottom: 10px; + right: 0; + z-index: 10; +} + +.link-copy { + margin: 50px; + z-index: 10; +} + +.content-wrapper { + width: 100vw; + height: 100vh; + display: flex; + flex-direction: row; + overflow: hidden; +} + +.left-container { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + width: 50%; + height: 100%; +} + +.right-container { + display: flex; + width: 50%; + height: 100%; } .go-game-pc { - position: absolute; - top: 80%; - left: 24%; - transform: translate(-50%, -50%); - justify-content: center; - align-items: center; - width: 40%; - text-align: center; - z-index: 10; + z-index: 10; } -.go-game-pc button { - width: 100%; - padding: 16px 0; - font-size: 24px; +.qr-wrapper { + display: flex; + position: relative; + justify-content: center; + align-items: center; + width: 68%; + aspect-ratio: 520 / 560; + background-color: rgba(255, 255, 255, 0.8); + z-index: 1; + margin-top: 80px; } -.red-lite{ - opacity: 0.8; - position: absolute; - top: 2%; - right: 0; +.qr-wrapper svg { + width: 80%; + position: absolute; + top: 55%; + left: 50%; + transform: translate(-50%, -50%); } -.pistol-img{ - opacity: 0.2; - position: absolute; - top: 25%; - right: 8%; - transform: scale(-1, 1); +.yatai-wrapper { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} +.id-room { + position: absolute; + top: 7%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 32px; + z-index: 10; } -.overlay-square { - position: absolute; - top: 20%; - right: 120px; - width: 520px; - height: 532px; - background-color: rgba(255, 255, 255, 0.8); - z-index: 1; -} - -.id-room{ - position: absolute; - top: 20%; - right: 300px; - font-size: 32px; - z-index: 10; -} - -.qr-scan{ - position: absolute; - top: 60%; - right: -10px; - z-index: 10; -} - -.link-copy{ - position: absolute; - top: 80%; - right: 300px; - z-index: 10; +.text{ + font-size: 24px; + color: #212121; + padding: 24px; + font-family: Yuji Syuku, sans-serif; + line-height: 1.5; + font-weight: 400; + font-style: normal; + position: absolute; + bottom: 10px; + text-align: left; +} + +.white-box{ + width: 50%; + height: 30%; + background-color: #fff; + opacity: 0.4; +} +.ready{ + font-size: 24px; } \ No newline at end of file diff --git a/src/components/responsive/homePC/index.tsx b/src/components/responsive/homePC/index.tsx index d921698..b12a375 100644 --- a/src/components/responsive/homePC/index.tsx +++ b/src/components/responsive/homePC/index.tsx @@ -1,18 +1,34 @@ +import { useState } from "react"; import { useNavigate } from "react-router-dom"; -import { useSocketRefStore } from "../../../store"; +import { useRoomIdStore, useSocketRefStore } from "../../../store"; +import { copyStringToClipboard } from "../../../utils/copyClipBoard"; import { requestPermission } from "../../../utils/permission"; +import QRCodeGenerator from "../../QRCodeGenerator"; import { DefaultButton } from "../../ui/Button"; import TextButton from "../../ui/TextButton"; import styles from "./index.module.css"; +import Rule from "../../ui/Rule"; function HomePC() { const navigate = useNavigate(); const setRef = useSocketRefStore((state) => state.setRef); + const roomId = useRoomIdStore((state) => state.uuid); + const url = `${window.location.href}?room_id=${roomId}`; + const [buttonText, setButtonText] = useState("共有リンクをコピー"); + + const handleCopyClick = () => { + copyStringToClipboard(url); + setButtonText("コピーしました"); + setTimeout(() => setButtonText("共有リンクをコピー"), 2000); + }; const handleClick = () => { requestPermission(); const socketRef = new WebSocket( - `wss://${import.meta.env.VITE_HOST_NAME || "virtual-natsumatsuri-3jpy6th4da-an.a.run.app"}/ws?room_id=2`, + `wss://${ + import.meta.env.VITE_HOST_NAME || + "virtual-natsumatsuri-3jpy6th4da-an.a.run.app" + }/ws?room_id=${roomId}`, ); setRef({ current: socketRef }); const audio = new Audio("/sound/wadaiko.mp3"); @@ -28,7 +44,7 @@ function HomePC() { }; return ( -
+
-
- 背景にばーちゃるなつまつりのロゴ -
-
- - 射的へ向かう - + +
+
+ 背景にばーちゃるなつまつりのロゴ +
+
+ + 射的へ向かう + +
+
+ +
-
-
-

屋台のID

+
+
+
+
+

屋台のID

+
+ +
+
+ qr-scan +
+
+ +
+
- 赤提灯 + 赤提灯
-
- qr-scan -
-
- -
); } diff --git a/src/components/responsive/homeSP/index.module.css b/src/components/responsive/homeSP/index.module.css index d206a1a..86e7af8 100644 --- a/src/components/responsive/homeSP/index.module.css +++ b/src/components/responsive/homeSP/index.module.css @@ -62,3 +62,16 @@ li { padding: 12px 0; font-size: 18px; } + +.text{ + font-size: 16px; + color: #212121; + padding: 24px; + font-family: Yuji Syuku, sans-serif; + line-height: 1.5; + font-weight: 400; + font-style: normal; + position: absolute; + bottom: 10px; + text-align: left; +} \ No newline at end of file diff --git a/src/components/responsive/homeSP/index.tsx b/src/components/responsive/homeSP/index.tsx index 9b6c79e..69cae8c 100644 --- a/src/components/responsive/homeSP/index.tsx +++ b/src/components/responsive/homeSP/index.tsx @@ -11,15 +11,19 @@ function HomeSP() { const handleClick = () => { requestPermission(); + const params = new URLSearchParams(location.search); + const roomId = params.get("room_id"); const socketRef = new WebSocket( - `wss://${import.meta.env.VITE_HOST_NAME || "virtual-natsumatsuri-3jpy6th4da-an.a.run.app"}/ws?room_id=2`, + `wss://${import.meta.env.VITE_HOST_NAME || + "virtual-natsumatsuri-3jpy6th4da-an.a.run.app" + }/ws?room_id=${roomId}`, ); setRef({ current: socketRef }); const audio = new Audio("/sound/wadaiko.mp3"); audio .play() .then(() => { - setTimeout(() => {}, 500); + setTimeout(() => { }, 500); }) .catch((error) => { console.error("オーディオの音が出なかった", error); @@ -55,12 +59,14 @@ function HomeSP() { height="380" />
+
+ +
- + 射的へ向かう
-
); diff --git a/src/components/ui/Button/index.module.css b/src/components/ui/Button/index.module.css index bee8aab..b26a508 100644 --- a/src/components/ui/Button/index.module.css +++ b/src/components/ui/Button/index.module.css @@ -15,11 +15,12 @@ } &[data-size="lg"] { - padding: 8px 48px; - font-size: 24px; - font-weight: bold; + padding: 4px 120px; + font-size: 40px; + font-weight: regular; border-radius: 4px; white-space: nowrap; + left: } &[data-variant="contained"] { diff --git a/src/components/ui/Rule/index.module.css b/src/components/ui/Rule/index.module.css deleted file mode 100644 index 778150b..0000000 --- a/src/components/ui/Rule/index.module.css +++ /dev/null @@ -1,12 +0,0 @@ -.text{ - font-size: 16px; - color: #212121; - padding: 24px; - font-family: Yuji Syuku, sans-serif; - line-height: 1.5; - font-weight: 400; - font-style: normal; - position: absolute; - bottom: 10px; - text-align: left; -} \ No newline at end of file diff --git a/src/components/ui/Rule/index.tsx b/src/components/ui/Rule/index.tsx index 6368383..df2ebf4 100644 --- a/src/components/ui/Rule/index.tsx +++ b/src/components/ui/Rule/index.tsx @@ -1,8 +1,6 @@ -import styles from './index.module.css' - function Rule() { return ( -
+

〜ルール〜

1,画面にスマホを向け、ポインタの位置を確認(1回につき3発のコルク玉が渡されます) diff --git a/src/components/ui/TextButton/index.module.css b/src/components/ui/TextButton/index.module.css index 70179ab..01f6615 100644 --- a/src/components/ui/TextButton/index.module.css +++ b/src/components/ui/TextButton/index.module.css @@ -7,7 +7,12 @@ text-decoration: none; outline: none; font-family: 'Yuji Syuku', serif; + transition: transform 0.2s; + outline: none; } +.textButton:focus { + outline: none; + } .textButton.sm { font-size: 12px; @@ -24,3 +29,14 @@ .underline { text-decoration: underline; } + +.textButton:active { + animation: bounce 0.3s; + } + + @keyframes bounce { + 0% { transform: scale(1); } + 50% { transform: scale(1.2); } + 100% { transform: scale(1); } + } + \ No newline at end of file diff --git a/src/index.css b/src/index.css index a29afbb..a19add4 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,13 @@ :root { - font-family: Dela Gothic One, Yuji Syuku, serif, sans-serif; + font-family: Dela Gothic One, Yuji Syuku, serif, sans-serif; line-height: 1.5; font-weight: 400; font-style: normal; --black: #212121; --white: #ffffff; - --red: #FF3131; - --yellow: #FFF501; + --red: #ff3131; + --yellow: #fff501; } a { @@ -24,7 +24,8 @@ body { display: flex; min-width: 320px; min-height: 100vh; - background-color: #FFF2F2; + background-color: #fff2f2; + overflow: hidden; } h1 { diff --git a/src/store/index.ts b/src/store/index.ts index d527464..725c6ae 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,2 +1,3 @@ export { useSocketRefStore } from "./useSocketRefStore"; export { useUUIDStore } from "./useUUIDStore"; +export { useRoomIdStore } from "./useRoomIdStore"; diff --git a/src/store/useRoomIdStore.ts b/src/store/useRoomIdStore.ts new file mode 100644 index 0000000..32eb412 --- /dev/null +++ b/src/store/useRoomIdStore.ts @@ -0,0 +1,15 @@ +import { create } from "zustand"; +import { generateUUID } from "../utils/uuid"; + +type State = { + uuid: string; +}; + +type Action = { + updateUUID: () => void; +}; + +export const useRoomIdStore = create()((set) => ({ + uuid: generateUUID(), + updateUUID: () => set(() => ({ uuid: generateUUID() })), +})); diff --git a/src/utils/copyClipBoard.ts b/src/utils/copyClipBoard.ts new file mode 100644 index 0000000..1652119 --- /dev/null +++ b/src/utils/copyClipBoard.ts @@ -0,0 +1,10 @@ +export const copyStringToClipboard = (text: string) => { + navigator.clipboard.writeText(text).then( + () => { + console.log("Async: Copying to clipboard was successful!"); + }, + (err) => { + console.error("Async: Could not copy text: ", err); + }, + ); +}; diff --git a/src/utils/queryParams.ts b/src/utils/queryParams.ts new file mode 100644 index 0000000..457c80c --- /dev/null +++ b/src/utils/queryParams.ts @@ -0,0 +1,19 @@ +export function generateQueryParams( + params: Record, +): string { + const searchParams = new URLSearchParams(); + // biome-ignore lint/complexity/noForEach: + Object.entries(params).forEach(([key, value]) => { + searchParams.append(key, String(value)); + }); + return searchParams.toString(); +} + +export function appendQueryParamsToUrl( + baseUrl: string, + params: Record, +): string { + const queryString = generateQueryParams(params); + const separator = baseUrl.includes("?") ? "&" : "?"; + return `${baseUrl}${separator}${queryString}`; +} From c8d1991d6abcc2c9db72b413a58115c850852286 Mon Sep 17 00:00:00 2001 From: Sea10wood Date: Sun, 11 Aug 2024 15:48:01 +0900 Subject: [PATCH 3/3] add: pnpm check --- src/components/responsive/homePC/index.tsx | 4 ++-- src/components/responsive/homeSP/index.tsx | 9 +++++---- src/components/ui/Rule/index.tsx | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/responsive/homePC/index.tsx b/src/components/responsive/homePC/index.tsx index b12a375..98456c2 100644 --- a/src/components/responsive/homePC/index.tsx +++ b/src/components/responsive/homePC/index.tsx @@ -5,9 +5,9 @@ import { copyStringToClipboard } from "../../../utils/copyClipBoard"; import { requestPermission } from "../../../utils/permission"; import QRCodeGenerator from "../../QRCodeGenerator"; import { DefaultButton } from "../../ui/Button"; +import Rule from "../../ui/Rule"; import TextButton from "../../ui/TextButton"; import styles from "./index.module.css"; -import Rule from "../../ui/Rule"; function HomePC() { const navigate = useNavigate(); @@ -62,7 +62,7 @@ function HomePC() {

- +
背景にばーちゃるなつまつりのロゴ diff --git a/src/components/responsive/homeSP/index.tsx b/src/components/responsive/homeSP/index.tsx index 69cae8c..78d8ba0 100644 --- a/src/components/responsive/homeSP/index.tsx +++ b/src/components/responsive/homeSP/index.tsx @@ -2,8 +2,8 @@ import { useNavigate } from "react-router-dom"; import { useSocketRefStore } from "../../../store"; import { requestPermission } from "../../../utils/permission"; import { DefaultButton } from "../../ui/Button"; -import styles from "./index.module.css"; import Rule from "../../ui/Rule"; +import styles from "./index.module.css"; function HomeSP() { const navigate = useNavigate(); @@ -14,8 +14,9 @@ function HomeSP() { const params = new URLSearchParams(location.search); const roomId = params.get("room_id"); const socketRef = new WebSocket( - `wss://${import.meta.env.VITE_HOST_NAME || - "virtual-natsumatsuri-3jpy6th4da-an.a.run.app" + `wss://${ + import.meta.env.VITE_HOST_NAME || + "virtual-natsumatsuri-3jpy6th4da-an.a.run.app" }/ws?room_id=${roomId}`, ); setRef({ current: socketRef }); @@ -23,7 +24,7 @@ function HomeSP() { audio .play() .then(() => { - setTimeout(() => { }, 500); + setTimeout(() => {}, 500); }) .catch((error) => { console.error("オーディオの音が出なかった", error); diff --git a/src/components/ui/Rule/index.tsx b/src/components/ui/Rule/index.tsx index df2ebf4..1f77951 100644 --- a/src/components/ui/Rule/index.tsx +++ b/src/components/ui/Rule/index.tsx @@ -1,6 +1,6 @@ function Rule() { return ( -
+

〜ルール〜

1,画面にスマホを向け、ポインタの位置を確認(1回につき3発のコルク玉が渡されます)