commit 98985aebfdf5f33de226c9d219e92eb764fc176e
parent a52a220c5f60cfb008ffa15df4fb1c5fc6f221ae
Author: Sunny <122193933+Sunny-JP@users.noreply.github.com>
Date: Thu, 20 Mar 2025 22:12:36 +0900
adjust player style (#18)
Diffstat:
3 files changed, 283 insertions(+), 346 deletions(-)
diff --git a/src/components/Player.vue b/src/components/Player.vue
@@ -1,9 +1,9 @@
<script setup lang="ts">
import { YoutubeIframe } from '@vue-youtube/component';
-import { ref, computed, onUnmounted, nextTick, watch } from 'vue';
+import { ref, computed, onUnmounted, watch } from 'vue';
import queue from '../queue';
import SvgIcon from '@jamescoyle/vue-icon';
-import { mdiRepeatOnce, mdiRepeatOff } from '@mdi/js';
+import { mdiRepeatOnce, mdiRepeatOff, mdiStarCheck, mdiStarPlusOutline } from '@mdi/js';
// YouTube player instance
const player = ref<any>(null);
@@ -21,15 +21,6 @@ const titleName = ref();
// Album info
let albumTitle = queue.get_albumTitle();
-// Title scrolling
-const titleElement = ref<HTMLElement | null>(null);
-const needsScroll = ref(false);
-const parentWidth = ref(0);
-const textWidth = ref(0);
-const isAnimating = ref(false);
-const SCROLL_SPEED = 40; // px/s
-const WAIT_TIME = 2000; // ms
-
// Fullscreen mode
const isFullscreen = ref(false);
const animationClass = ref("");
@@ -61,49 +52,27 @@ const onReady = (event: { target: any }) => {
endTime.value = Math.floor(event.target.getDuration());
title.value = event.target.getVideoData();
titleName.value = title.value['title'];
-
- nextTick(() => {
- if (titleElement.value) {
- parentWidth.value = titleElement.value.parentElement?.offsetWidth || 0;
- textWidth.value = titleElement.value.scrollWidth;
- needsScroll.value = textWidth.value > parentWidth.value;
-
- if (needsScroll.value) {
- startScrolling();
- }
- }
- });
-};
-
-// Compute animation duration
-const animationDuration = computed(() => {
- return needsScroll.value ? textWidth.value / SCROLL_SPEED : 0;
-});
-
-// Start scrolling if needed
-const startScrolling = async () => {
- if (!needsScroll.value) return;
- await new Promise(resolve => setTimeout(resolve, WAIT_TIME));
- isAnimating.value = true;
};
// Handle video state changes
const onStateChange = (event: { target: any; data: number }) => {
+ if (intervalId.value !== null) {
+ clearInterval(intervalId.value);
+ intervalId.value = null;
+ }
+
if (event.data === 1) { // Playing
isPlaying.value = true;
intervalId.value = window.setInterval(() => {
nowTime.value = Math.floor(event.target.getCurrentTime());
- }, 250);
+ }, 200);
} else if (event.data === 0) { // End
isPlaying.value = false;
queue.get_next();
} else if (event.data === 2) { // Paused
isPlaying.value = false;
- if (intervalId.value !== null) {
- clearInterval(intervalId.value);
- intervalId.value = null;
- }
}
+
albumTitle = queue.get_albumTitle();
};
@@ -154,19 +123,7 @@ const renderKey = queue.get_playerRenderKey();
<div class="info_box">
<!-- Video title -->
<div class="title" @click="toggleFullscreen">
- <div
- ref="titleElement"
- class="scroll-container"
- :class="{ scrolling: isAnimating }"
- :style="isAnimating ? `--animation-duration: ${animationDuration}s;` : ''"
- >
- <span v-if="needsScroll" class="scroll-text">
- {{ titleName }} {{ titleName }}
- </span>
- <span v-else class="single-text">
- {{ titleName }}
- </span>
- </div>
+ {{ titleName }}
</div>
<!-- Time and album info -->
@@ -181,6 +138,9 @@ const renderKey = queue.get_playerRenderKey();
<div class="fs_loop" @click="queue.onLoopButton()">
<SvgIcon type="mdi" :path="queue.isLoop.value ? mdiRepeatOnce : mdiRepeatOff" />
</div>
+ <div class="fs_fav" @click="queue.onLoopButton()">
+ <SvgIcon type="mdi" :path="queue.isLoop.value ? mdiStarCheck : mdiStarPlusOutline" />
+ </div>
</div>
<div class="fs_time_container">
@@ -197,299 +157,13 @@ const renderKey = queue.get_playerRenderKey();
</div>
</button>
</div>
-</template>
+ <!-- song list
+ <div class="song_list">
+ </div>
+ -->
+</template>
<style scoped>
-/* 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;
-}
-
-.fscontainer {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 30px;
- background: #000000;
-}
-
-.slide-down {
- animation: slideDown 0.25s ease forwards;
-}
-
-.slide-up {
- 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: 10px;
- margin: 5px;
- width: 100%;
- max-width: 500px;
-}
-
-.title {
- cursor: pointer;
- 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;
-}
-
-.fs_loop {
- cursor: pointer;
-}
-
-.container .album {
- font-family: "Poppins", "Noto Sans JP", "Helvetica Neue", "Helvetica", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Meiryo", sans-serif;
- font-size: clamp(1.5px, calc(3vw - 1px), 15px);
- margin-left: 10px;
- cursor: pointer;
- white-space: nowrap;
- overflow-x: scroll;
- -ms-overflow-style: none; /* Scrollbar hidden (IE・Edge) */
- scrollbar-width: none; /* Scrollbar hidden (Firefox) */
-}
-
-.container .album::-webkit-scrollbar{ /* Scrollbar hidden (Chrome・Safari) */
- display: none;
-}
-
-.container .fs_album {
- font-size: 0;
-}
-
-.fscontainer .album {
- font-size: 0;
-}
-
-.container .fs_album_container {
- font-size: 0;
- display: none;
-}
-
-.fscontainer .fs_album_container {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- font-size: clamp(2px, calc(4vw - 1.3px), 20px);
-}
-
-.fscontainer .fs_album {
- margin-right: 40px;
- cursor: pointer;
- white-space: nowrap;
- overflow-x: scroll;
- -ms-overflow-style: none; /* Scrollbar hidden (IE・Edge) */
- scrollbar-width: none; /* Scrollbar hidden (Firefox) */
-}
-
-.container .fs_album::-webkit-scrollbar{ /* Scrollbar hidden (Chrome・Safari) */
- display: none;
-}
-
-.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.75px, calc(3.5vw - 1.15px), 17.5px);
-}
-
-.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(2px, calc(4vw - 1.3px), 20px);
-}
-
-.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;
-}
-
-.container .play-pause-button{
- font-size: clamp(1.5px, 3vw, 15px);
- padding-left: clamp(1px, 1vw, 5px);
- padding-right: clamp(1px, 1vw, 5px);
-}
-
-.fscontainer .play-pause-button {
- position: relative;
- top: 35px;
-}
-
-.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;
-}
+@import '../player-style.css';
</style>
diff --git a/src/player-style.css b/src/player-style.css
@@ -0,0 +1,260 @@
+/* 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;
+}
+
+.fscontainer {
+ height: auto;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 30px;
+ background: #000000;
+}
+
+
+/* info_box */
+.container .info_box {
+ margin-left: 10px;
+ padding: 0px 10px 0px 0px;
+ width: 70vw;
+ max-width: 300px;
+}
+
+.fscontainer .info_box {
+ position: relative;
+ top: 10px;
+ margin: 5px;
+ width: 100%;
+ max-width: 500px;
+}
+
+
+/* title */
+.title {
+ position: relative;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+
+.container .title {
+ font-size: clamp(2px, calc(4vw - 1.3px), 20px);
+}
+
+.fscontainer .title {
+ font-size: clamp(3px, calc(6vw - 2px), 30px);
+}
+
+
+/* time */
+.container .time_container {
+ font-family: "Lekton", monospace;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ font-size: clamp(1.75px, calc(3.5vw - 1.15px), 17.5px);
+}
+
+.fscontainer .fs_time_container {
+ font-family: "Lekton", monospace;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin-top: 1em;
+ margin-bottom: 2em;
+ font-size: clamp(2px, calc(4vw - 1.3px), 20px);
+}
+
+.container .fs_time_container,
+.fscontainer .time_container {
+ font-size: 0;
+}
+
+.container .nowtime,
+.container .endtime {
+ padding-top: min(0.15vw, 2px);
+}
+
+.container .endtime {
+ margin-left: 5px;
+ text-align: right;
+}
+
+.container .endtime::before {
+ content: "-";
+ padding-right: 5px;
+}
+
+.fscontainer .endtime {
+ margin-left: auto;
+ text-align: right;
+}
+
+
+/* album */
+.container .album {
+ font-family: "Poppins", "Noto Sans JP", "Helvetica Neue", "Helvetica", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Meiryo", sans-serif;
+ font-size: clamp(1.5px, calc(3vw - 1px), 15px);
+ margin-left: 10px;
+ cursor: pointer;
+}
+
+.fscontainer .fs_album_container {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ font-size: clamp(2px, calc(4vw - 1.3px), 20px);
+}
+
+.fscontainer .fs_album {
+ margin-right: clamp(2px, calc(2vw), 12px);
+ cursor: pointer;
+}
+
+.container .fs_album_container,
+.fscontainer .album {
+ font-size: 0;
+ display: none;
+}
+
+.fs_loop,
+.fs_fav {
+ cursor: pointer;
+ padding-left: clamp(2px, calc(2vw), 12px);
+ margin-top: 4px;
+}
+
+svg {
+ width: clamp(2px, calc(6vw), 30px);
+ height: clamp(2px, calc(6vw), 30px);
+}
+
+
+/* control button */
+.play-pause-button {
+ background: none;
+ border: none;
+ padding: 0;
+ cursor: pointer;
+}
+
+.container .play-pause-button {
+ font-size: clamp(1.5px, 3vw, 15px);
+ padding-left: clamp(1px, 1vw, 5px);
+ padding-right: clamp(1px, 1vw, 5px);
+}
+
+.fscontainer .play-pause-button {
+ font-size: clamp(2px, 4vw, 20px);
+ position: relative;
+ top: 35px;
+ padding-bottom: 30px;
+}
+
+.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;
+}
+
+
+/* slide animation */
+.slide-down {
+ animation: slideDown 0.25s ease forwards;
+}
+
+.slide-up {
+ 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;
+ }
+}
+
+
+/* scrollbar hidden */
+.title,
+.album,
+.fs_album {
+ white-space: nowrap;
+ overflow-x: scroll;
+ /* Scrollbar hidden (IE・Edge) */
+ -ms-overflow-style: none;
+ /* Scrollbar hidden (Firefox) */
+ scrollbar-width: none;
+}
+
+.title::-webkit-scrollbar,
+.album::-webkit-scrollbar,
+.fs_album::-webkit-scrollbar {
+ /* Scrollbar hidden (Chrome・Safari) */
+ display: none;
+}+
\ No newline at end of file
diff --git a/src/style.css b/src/style.css
@@ -12,6 +12,8 @@ body {
background: #000000;
-webkit-text-size-adjust: none;
user-select: none;
+ -webkit-user-select: none;
+ -webkit-tap-highlight-color: transparent;
}
@@ -111,7 +113,7 @@ body {
font-weight: 500;
transform: translateX(100%);
transition: transform 0.4s ease;
- z-index: -10;
+ z-index: -20;
}
.menu.open {