feat(ui): add floating menu for video selection

Implement floating button that toggles a menu with video options
Add styling for floating elements and handle click interactions
Update video switching logic to prevent unintended transitions
This commit is contained in:
2025-07-16 23:22:53 +08:00
parent d51262ff03
commit 9563730a6f
3 changed files with 133 additions and 0 deletions
+12
View File
@@ -43,6 +43,18 @@
<p id="transcript"></p>
</div>
<!-- 悬浮球 -->
<div id="floating-button">
<i class="fas fa-bars"></i>
</div>
<!-- 悬浮菜单 -->
<div id="menu-container" class="hidden">
<button class="menu-item" data-video="视频资源/jimeng-2025-07-16-4437-比耶,然后微笑着优雅的左右摇晃.mp4">Pose</button>
<button class="menu-item" data-video="视频资源/生成加油视频.mp4">Cheer</button>
<button class="menu-item" data-video="视频资源/生成跳舞视频.mp4">Dance</button>
</div>
<!-- 底部麦克风和链接 -->
<footer class="bottom-bar">
<button class="mic-button" id="mic-button" aria-label="Start Listening">
+49
View File
@@ -15,6 +15,9 @@ document.addEventListener('DOMContentLoaded', function() {
let video2 = document.getElementById('video2');
const micButton = document.getElementById('mic-button');
const favorabilityBar = document.getElementById('favorability-bar');
const floatingButton = document.getElementById('floating-button');
const menuContainer = document.getElementById('menu-container');
const menuItems = document.querySelectorAll('.menu-item');
let activeVideo = video1;
let inactiveVideo = video2;
@@ -134,6 +137,51 @@ document.addEventListener('DOMContentLoaded', function() {
});
// --- 悬浮按钮交互 ---
floatingButton.addEventListener('click', (event) => {
event.stopPropagation(); // 防止事件冒泡到 document
menuContainer.classList.toggle('hidden');
});
menuItems.forEach(item => {
item.addEventListener('click', function() {
const videoSrc = this.getAttribute('data-video');
playSpecificVideo(videoSrc);
menuContainer.classList.add('hidden');
});
});
// 点击菜单外部区域关闭菜单
document.addEventListener('click', () => {
if (!menuContainer.classList.contains('hidden')) {
menuContainer.classList.add('hidden');
}
});
// 阻止菜单自身的点击事件冒泡
menuContainer.addEventListener('click', (event) => {
event.stopPropagation();
});
function playSpecificVideo(videoSrc) {
const currentVideoSrc = activeVideo.querySelector('source').getAttribute('src');
if (videoSrc === currentVideoSrc) return;
inactiveVideo.querySelector('source').setAttribute('src', videoSrc);
inactiveVideo.load();
inactiveVideo.addEventListener('canplaythrough', function onCanPlayThrough() {
inactiveVideo.removeEventListener('canplaythrough', onCanPlayThrough);
activeVideo.pause(); // 暂停当前视频,防止其 'ended' 事件触发切换
inactiveVideo.play().catch(error => console.error("Video play failed:", error));
activeVideo.classList.remove('active');
inactiveVideo.classList.add('active');
[activeVideo, inactiveVideo] = [inactiveVideo, activeVideo];
activeVideo.addEventListener('ended', switchVideo, { once: true });
}, { once: true });
}
// --- 情感分析与反应 ---
const positiveWords = ['开心', '高兴', '喜欢', '太棒了', '你好', '漂亮'];
const negativeWords = ['难过', '生气', '讨厌', '伤心'];
@@ -179,6 +227,7 @@ document.addEventListener('DOMContentLoaded', function() {
inactiveVideo.addEventListener('canplaythrough', function onCanPlayThrough() {
inactiveVideo.removeEventListener('canplaythrough', onCanPlayThrough);
activeVideo.pause(); // 暂停当前视频,防止其 'ended' 事件触发切换
inactiveVideo.play().catch(error => console.error("Video play failed:", error));
activeVideo.classList.remove('active');
inactiveVideo.classList.add('active');
+72
View File
@@ -152,6 +152,78 @@ html, body {
text-shadow: 1px 1px 2px rgba(0,0,0,0.7);
}
/* --- 悬浮按钮和菜单 --- */
#floating-button {
position: fixed;
bottom: 120px; /* 调整位置,使其在麦克风按钮上方 */
right: 30px;
width: 60px;
height: 60px;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
transition: transform 0.2s ease, box-shadow 0.2s ease;
z-index: 10;
}
#floating-button:hover {
transform: scale(1.1);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
#floating-button i {
font-size: 24px;
color: white;
}
#menu-container {
position: fixed;
bottom: 200px; /* 调整位置,使其在悬浮按钮上方 */
right: 30px;
width: 150px;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 10px;
padding: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
z-index: 9;
transition: opacity 0.3s ease, transform 0.3s ease;
transform-origin: bottom right;
}
#menu-container.hidden {
opacity: 0;
transform: scale(0.95);
pointer-events: none;
}
.menu-item {
display: block;
width: 100%;
padding: 12px;
background: none;
border: none;
color: white;
font-size: 1rem;
text-align: left;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.2s ease;
}
.menu-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
/* --- 底部内容 --- */
.bottom-bar {
width: 100%;