commit 378c865761b9b7bacfaed7d0837e9211d69b63da
parent 79c53357f3cc5b9b649920a6226e3d67287fc297
Author: Sunny <122193933+Sunny-JP@users.noreply.github.com>
Date: Tue, 18 Mar 2025 02:29:55 +0900
Dev 5 (#13)
* add small player
* monospaced time font
* removed not using songname
Diffstat:
10 files changed, 323 insertions(+), 207 deletions(-)
diff --git a/src/App.vue b/src/App.vue
@@ -23,7 +23,7 @@ onBeforeUnmount(() => {
<header>
<nav>
<div class="title_bar">
- <p>GS Player</p>
+ <p><router-link to="/">GS Player</router-link></p>
</div>
<div class="hamburger_btn" @click.stop="MenuButton = !MenuButton">
<span class="line line_01" :class="{ 'btn_line01': MenuButton }"></span>
diff --git a/src/assets/AlbumsList.json b/src/assets/AlbumsList.json
@@ -1,22 +1,37 @@
[
{
- "albumTitle": {"ja":"アルバム1", "en": "Album1"},
+ "albumTitle": {
+ "ja": "アルバム1",
+ "en": "Album1"
+ },
"songs": [
{
- "title": { "ja": "曲1", "en": "Song 1" },
+ "title": {
+ "ja": "曲1",
+ "en": "Song 1"
+ },
"videoId": "QcrxntJERRs"
},
{
- "title": { "ja": "曲2", "en": "Song 2" },
+ "title": {
+ "ja": "曲2",
+ "en": "Song 2"
+ },
"videoId": "BrpIRBW4g0A"
}
]
},
{
- "albumTitle": {"ja":"アルバム2", "en": "Album2"},
+ "albumTitle": {
+ "ja": "アルバム2",
+ "en": "Album2"
+ },
"songs": [
{
- "title": { "ja": "曲A", "en": "Song A" },
+ "title": {
+ "ja": "曲A",
+ "en": "Song A"
+ },
"videoId": "L_jWHffIx5E"
}
]
diff --git a/src/components/About.vue b/src/components/About.vue
@@ -1,5 +1,5 @@
<template>
- <div class="container">
- <h1>About</h1>
- </div>
+ <div class="page">
+ <h1>About</h1>
+ </div>
</template>
\ No newline at end of file
diff --git a/src/components/AlbumList.vue b/src/components/AlbumList.vue
@@ -13,9 +13,10 @@ function add_play_album(albumIndex: number) {
<template>
<div class="page">
<h1>Album List</h1>
+ 曲タイトルをクリックするとPlayer表示を切り替えられるよ
<div v-for="(AlbumList, index) in AlbumList">
<button
- v-on:click="add_play_album(index)">
+ v-on:click="add_play_album(index)" class="button_album">
AlbumTitle: {{ AlbumList.albumTitle.ja }}
</button>
</div>
@@ -23,4 +24,11 @@ function add_play_album(albumIndex: number) {
</template>
<style scoped>
+.button_album {
+ background: #4c4c4c;
+ color: #ffffff;
+ border: none;
+ padding: 5px;
+ cursor: pointer;
+}
</style>
\ No newline at end of file
diff --git a/src/components/Enquiries.vue b/src/components/Enquiries.vue
@@ -1,5 +1,5 @@
<template>
- <div class="container">
- <h1>お問い合わせ</h1>
- </div>
+ <div class="page">
+ <h1>お問い合わせ</h1>
+ </div>
</template>
\ No newline at end of file
diff --git a/src/components/Info.vue b/src/components/Info.vue
@@ -1,3 +1,5 @@
<template>
- <h1>運営者情報</h1>
+ <div class="page">
+ <h1>運営者情報</h1>
+ </div>
</template>
\ No newline at end of file
diff --git a/src/components/Player.vue b/src/components/Player.vue
@@ -3,7 +3,7 @@ import { YoutubeIframe } from '@vue-youtube/component';
import { ref, computed, onUnmounted, nextTick } from 'vue';
import queue from '../queue';
-//let videoId = ref('zxt-_P_WXtM'); // example of long titleName
+// let videoId = ref('zxt-_P_WXtM'); // example of long titleName
// let videoId = ref('XAwXaGQwoZ0'); // example of short titleName
const player = ref<any>(null);
const nowTime = ref(0);
@@ -22,15 +22,12 @@ const isAnimating = ref(false);
const SCROLL_SPEED = 40; // px/s
const WAIT_TIME = 2000; // ms
-
const isFullscreen = ref(false);
const toggleFullscreen = () => {
isFullscreen.value = !isFullscreen.value;
};
-
-
const togglePlay = async () => {
player.value?.togglePlay(); // Change play-pause
};
@@ -122,7 +119,7 @@ const renderKey = queue.get_playerRenderKey();
@ready="onReady"
@state-change="onStateChange" />
<div class="info_box">
- <div class="title">
+ <div class="title" @click="toggleFullscreen">
<div ref="titleElement"
class="scroll-container"
:class="{ scrolling: isAnimating }"
@@ -137,6 +134,16 @@ const renderKey = queue.get_playerRenderKey();
</div>
<div class="album">{{albumTitle}}</div>
<div class="time_container">
+ <div v-for="(, index) in queue.get_queueTitleList()">
+ #{{ index }}
+ </div>
+ <div class="nowtime">{{ formattedNowTime }}</div>
+ <div class="endtime">{{ formattedEndTime }}</div>
+ </div>
+ <div class="queue" v-for="(SongName, index) in queue.get_queueTitleList()">
+ #{{ index }} : {{ SongName }}
+ </div>
+ <div class="fs_time_container">
<div class="nowtime">{{ formattedNowTime }}</div>
<div class="endtime">{{ formattedEndTime }}</div>
</div>
@@ -147,23 +154,253 @@ const renderKey = queue.get_playerRenderKey();
<div class="bar bar-right"></div>
</div>
</button>
- <button @click="queue.onLoopButton()">
- LoopButton
- </button>
- Queue
- <div v-for="(SongName, index) in queue.get_queueTitleList()">
- {{ index }} : {{ SongName }}
- </div>
</div>
- <button @click="toggleFullscreen" class="toggle-btn">
- {{ isFullscreen ? '通常表示' : 'フルスクリーン' }}
- </button>
+ <button @click="queue.onLoopButton()" class="toggle-btn-loop">
+ Loop
+ </button>
</template>
<style scoped>
-.toggle-btn {
+/* overall frame */
+.container {
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ height: 10vw;
+ max-height: 60px;
+ background: #000000;
+ border-top: #404040 solid 2px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding-top: clamp(1px, 2vw, 10px);
+ padding-bottom: clamp(1px, 2vw, 10px);
+ flex-direction: row;
+ animation: slideDown 0.25s ease forwards;
+}
+
+.fscontainer {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 30px;
+ background: #000000;
+ animation: slideUp 0.25s ease forwards;
+}
+
+@keyframes slideDown {
+ 0% {
+ transform: translateY(-100px);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateY(0);
+ }
+ 40%,100% {
+ opacity: 1;
+ }
+}
+
+@keyframes slideUp {
+ 0% {
+ transform: translateY(100px);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateY(0);
+ }
+ 40%,100% {
+ opacity: 1;
+ }
+}
+
+/* title, album, time */
+.container .info_box {
+ margin-left: 10px;
+ padding: 0px 10px 0px 0px;
+ width: 70vw;
+ max-width: 300px;
+ color: white;
+}
+
+.fscontainer .info_box {
+ position: relative;
+ top: 55px;
+ margin: 5px;
+ width: 100%;
+ max-width: 500px;
+}
+
+.title {
+ overflow: hidden;
+ white-space: nowrap;
+ position: relative;
+ width: 100%;
+}
+
+.container .scroll-container {
+ display: flex;
+ align-items: center;
+ white-space: nowrap;
+ font-size: clamp(2px, calc(4vw - 1.3px), 20px);
+}
+
+.fscontainer .scroll-container {
+ display: flex;
+ align-items: center;
+ white-space: nowrap;
+ font-size: clamp(3px, calc(6vw - 2px), 30px);
+}
+
+.scrolling .scroll-text {
+ display: inline-block;
+ animation: scrollText var(--animation-duration) linear infinite;
+}
+
+@keyframes scrollText {
+ 0% {
+ transform: translateX(0);
+ }
+
+ 20% {
+ transform: translateX(0);
+ }
+
+ 97% {
+ opacity: 1;
+ }
+
+ 98% {
+ opacity: 0;
+ transform: translateX(calc(-50%));
+ }
+
+ 99% {
+ opacity: 0;
+ transform: translateX(0);
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
+
+.single-text {
+ display: inline-block;
+ opacity: 1;
+}
+
+.container .album {
+ font-size: 0;
+}
+
+.fscontainer .album {
+ font-size: clamp(2px, calc(4vw - 1.3px), 20px);
+}
+
+.container .queue {
+ font-size: 0;
+}
+
+.fscontainer .queue {
+ font-size: clamp(1.5px, calc(3vw - 1px), 15px);
+}
+
+.container .time_container {
+ font-family: "Lekton", monospace;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ font-size: clamp(1.5px, calc(3vw - 1px), 15px);
+}
+
+.container .fs_time_container {
+ font-size: 0;
+}
+
+.fscontainer .time_container {
+ font-size: 0;
+}
+
+.fscontainer .fs_time_container {
+ font-family: "Lekton", monospace;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin-top: 0.5em;
+ margin-bottom: 2em;
+ font-size: clamp(1.75px, calc(3.5vw - 1.15px), 17.5px);
+}
+
+.container .endtime {
+ margin-left: 5px;
+ text-align: right;
+}
+
+.container .endtime::before {
+ content: "-";
+ padding-right: 5px;
+}
+
+.fscontainer .endtime {
+ margin-left: auto;
+ text-align: right;
+}
+
+/* control button */
+.play-pause-button {
+ font-size: clamp(2px, 4vw, 20px);
+ background: none;
+ border: none;
+ padding: 0;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.fscontainer .play-pause-button {
+ position: relative;
+ top: 55px;
+}
+
+.play-pause-icon {
+ position: relative;
+ width: 8vw;
+ max-width: 2em;
+ height: 9vw;
+ max-height: 2.2em;
+}
+
+.bar {
+ position: absolute;
+ background: white;
+ width: 0.9em;
+ height: 2.2em;
+ transition: all 0.3s ease-in-out;
+}
+
+.bar-left {
+ left: 0.12em;
+ clip-path: polygon(0% 0%, 100% 26%, 100% 74%, 0% 100%);
+}
+
+.bar-right {
+ right: 0.12em;
+ clip-path: polygon(0% 25%, 100% 50%, 0% 75%);
+}
+
+.playing .bar-left,
+.playing .bar-right {
+ clip-path: inset(0 0 0 0);
+ width: 0.5em;
+}
+
+
+.toggle-btn-loop {
position: fixed;
bottom: 90px;
+ left: 60px;
background: #4c4c4c;
color: #ffffff;
border: none;
diff --git a/src/components/Policy.vue b/src/components/Policy.vue
@@ -1,3 +1,5 @@
<template>
- <h1>プライバシーポリシー</h1>
+ <div class="page">
+ <h1>プライバシーポリシー</h1>
+ </div>
</template>
\ No newline at end of file
diff --git a/src/components/Terms.vue b/src/components/Terms.vue
@@ -1,5 +1,5 @@
<template>
- <div class="container">
- <h1>利用規約</h1>
- </div>
+ <div class="page">
+ <h1>利用規約</h1>
+ </div>
</template>
\ No newline at end of file
diff --git a/src/style.css b/src/style.css
@@ -1,6 +1,7 @@
@import './reset-style.css';
-@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100..900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Lekton:wght@700&family=Noto+Sans+JP:wght@100..900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
+/* general */
body {
margin: 0px;
padding: 0px;
@@ -12,32 +13,19 @@ body {
-webkit-text-size-adjust: none;
}
-.page {
- height: 70px;
-}
-.container {
- position: fixed;
- bottom: 0;
- width: 100%;
- height: 5em;
- background: #333;
- display: flex;
- align-items: center;
- justify-content: center;
+/* pages */
+.page {
+ position: absolute;
+ top: 55px;
padding: 10px;
- flex-direction: row;
+ z-index: -100;
}
-.fscontainer {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 30px;
-}
/* title bar */
.title_bar {
+ position: fixed;
padding: 15px;
width: calc(100vw - 30px);
height: 25px;
@@ -53,6 +41,12 @@ body {
line-height: 1;
}
+.title_bar a {
+ text-decoration: none;
+ color: #ffffff;
+}
+
+
/* hamburger button */
.hamburger_btn {
position: fixed;
@@ -88,7 +82,7 @@ body {
top: 36px;
}
-/* hamburger button transform -> x */
+/* hamburger button -transform */
.btn_line01 {
transform: translateY(10px) rotate(-45deg)
}
@@ -101,6 +95,7 @@ body {
transform: translateY(-10px) rotate(45deg);
}
+
/* side menu */
.menu {
background-color: #1f1f1f;
@@ -149,165 +144,22 @@ body {
margin-bottom: 6px;
}
-/* player */
+
+/* iframe in player */
.container iframe {
- width: 5em;
- height: auto;
+ width: 10vw;
+ max-width: 60px;
+ height: 10vw;
+ max-height: 60px;
aspect-ratio: 1/1;
}
.fscontainer iframe {
+ position: relative;
+ top: 55px;
margin-bottom: 5px;
width: 100%;
- height: 100%;
max-width: 500px;
+ height: 100%;
aspect-ratio: 1/1;
-}
-
-/* アンダーバー時のinfo_box配置 */
-.container .info_box {
- margin-left: 10px;
- padding: 5px;
- width: 70%;
- max-width: 300px;
- color: white;
-}
-
-/* フルスクリーン時のinfo_box */
-.fscontainer .info_box {
- margin: 5px;
- width: 100%;
- max-width: 500px;
-}
-
-.title {
- overflow: hidden;
- white-space: nowrap;
- position: relative;
- width: 100%;
-}
-
-.container .scroll-container {
- display: flex;
- align-items: center;
- white-space: nowrap;
- font-size: clamp(2px, calc(4vw - 1.3px), 20px);
-}
-
-.fscontainer .scroll-container {
- display: flex;
- align-items: center;
- white-space: nowrap;
- font-size: clamp(3px, calc(6vw - 2px), 30px);
-}
-
-.scrolling .scroll-text {
- display: inline-block;
- animation: scrollText var(--animation-duration) linear infinite;
-}
-
-@keyframes scrollText {
- 0% {
- transform: translateX(0);
- }
-
- 20% {
- transform: translateX(0);
- }
-
- 97% {
- opacity: 1;
- }
-
- 98% {
- opacity: 0;
- transform: translateX(calc(-50%));
- }
-
- 99% {
- opacity: 0;
- transform: translateX(0);
- }
-
- 100% {
- opacity: 1;
- }
-}
-
-.single-text {
- display: inline-block;
- opacity: 1;
-}
-
-.container .album {
- font-size: 0;
-}
-
-.fscontainer .album {
- font-size: clamp(2px, calc(4vw - 1.3px), 20px);
-}
-
-.container .time_container {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin-top: 0.5em;
- font-size: clamp(1.5px, calc(3vw - 1px), 15px);
-}
-
-.fscontainer .time_container {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin-top: 0.5em;
- margin-bottom: 2em;
- font-size: clamp(1.5px, calc(3vw - 1px), 15px);
-}
-
-.endtime {
- margin-left: auto;
- text-align: right;
-}
-
-/* control button */
-/* play-pause button */
-.play-pause-button {
- font-size: clamp(2px, 4vw, 20px);
- background: none;
- border: none;
- padding: 0.5em 0.5em 0.5em 1em;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.play-pause-icon {
- position: relative;
- width: 2em;
- height: 2.2em;
-}
-
-.bar {
- position: absolute;
- background: white;
- width: 0.9em;
- height: 2.2em;
- transition: all 0.3s ease-in-out;
-}
-
-.bar-left {
- left: 0.12em;
- clip-path: polygon(0% 0%, 100% 26%, 100% 74%, 0% 100%);
-}
-
-.bar-right {
- right: 0.12em;
- clip-path: polygon(0% 25%, 100% 50%, 0% 75%);
-}
-
-.playing .bar-left,
-.playing .bar-right {
- clip-path: inset(0 0 0 0);
- width: 0.5em;
}
\ No newline at end of file