refactor: move quality/skip/speed controls to bottom bar, sync visibility with top bar
This commit is contained in:
18
src/App.vue
18
src/App.vue
@@ -17,6 +17,9 @@ import { useGameEngine } from '@/composables/useGameEngine'
|
|||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useFullscreen } from '@/composables/useFullscreen'
|
import { useFullscreen } from '@/composables/useFullscreen'
|
||||||
import { useI18n, initStoryLocales } from '@/composables/useI18n'
|
import { useI18n, initStoryLocales } from '@/composables/useI18n'
|
||||||
|
import { getVideoMode } from '@engine/core/VideoManager'
|
||||||
|
|
||||||
|
const isLocalMode = getVideoMode() === 'local'
|
||||||
|
|
||||||
const store = useGameStore()
|
const store = useGameStore()
|
||||||
const { t, currentLang } = useI18n()
|
const { t, currentLang } = useI18n()
|
||||||
@@ -333,16 +336,19 @@ init()
|
|||||||
<div v-if="showPromptToast" class="prompt-toast">{{ promptToast }}</div>
|
<div v-if="showPromptToast" class="prompt-toast">{{ promptToast }}</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
<div v-if="started && !store.gameEnded" class="top-bar" :class="{ hidden: !showTopBar }">
|
<div v-if="started && !store.gameEnded" class="top-bar" :class="{ hidden: !showTopBar }">
|
||||||
<PlaybackBar
|
|
||||||
:can-skip="canSkip"
|
|
||||||
:current-speed="currentSpeed"
|
|
||||||
@skip="handleSkip"
|
|
||||||
@speed-change="handleSpeedChange"
|
|
||||||
/>
|
|
||||||
<button class="top-btn" @click="toggleFullscreen" :title="t('ui.fullscreen')">⛶</button>
|
<button class="top-btn" @click="toggleFullscreen" :title="t('ui.fullscreen')">⛶</button>
|
||||||
<button class="top-btn" @click="showPauseMenu = true" :title="t('ui.menu')">≡</button>
|
<button class="top-btn" @click="showPauseMenu = true" :title="t('ui.menu')">≡</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<PlaybackBar
|
||||||
|
v-if="started && !store.gameEnded"
|
||||||
|
:can-skip="canSkip"
|
||||||
|
:current-speed="currentSpeed"
|
||||||
|
:visible="showTopBar"
|
||||||
|
:show-quality="!isLocalMode"
|
||||||
|
@skip="handleSkip"
|
||||||
|
@speed-change="handleSpeedChange"
|
||||||
|
/>
|
||||||
<MainMenu
|
<MainMenu
|
||||||
v-if="!started || store.gameEnded"
|
v-if="!started || store.gameEnded"
|
||||||
:show-resume="!store.gameEnded && hasAutoSave"
|
:show-resume="!store.gameEnded && hasAutoSave"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useI18n } from '@/composables/useI18n'
|
import { useI18n } from '@/composables/useI18n'
|
||||||
import { getVideoMode } from '@engine/core/VideoManager'
|
|
||||||
|
|
||||||
const store = useGameStore()
|
const store = useGameStore()
|
||||||
const { t, currentLang, setLang } = useI18n()
|
const { t, currentLang, setLang } = useI18n()
|
||||||
@@ -13,15 +12,6 @@ const emit = defineEmits<{
|
|||||||
const fontSizeOptions = [20, 24, 28, 32]
|
const fontSizeOptions = [20, 24, 28, 32]
|
||||||
const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]
|
const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]
|
||||||
|
|
||||||
const qualityOptions = [
|
|
||||||
{ key: '', label: '自动' },
|
|
||||||
{ key: '超清 (1080P)', label: '超清 (1080P)', speed: '需要 2.5 Mbps' },
|
|
||||||
{ key: '高清 (720P)', label: '高清 (720P)', speed: '需要 2 Mbps' },
|
|
||||||
{ key: '标清 (480P)', label: '标清 (480P)', speed: '需要 0.8 Mbps' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const isWeb = getVideoMode() !== 'local'
|
|
||||||
|
|
||||||
const langLabels: Record<string, string> = {
|
const langLabels: Record<string, string> = {
|
||||||
zh: '中文',
|
zh: '中文',
|
||||||
en: 'English',
|
en: 'English',
|
||||||
@@ -49,15 +39,6 @@ const langLabels: Record<string, string> = {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-row" v-if="isWeb">
|
|
||||||
<span class="setting-label">画质</span>
|
|
||||||
<select :value="store.preferredQuality" @change="store.setPreferredQuality(($event.target as HTMLSelectElement).value)">
|
|
||||||
<option v-for="q in qualityOptions" :key="q.key" :value="q.key">
|
|
||||||
{{ q.label }}{{ q.speed ? '(' + q.speed + ')' : '' }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<span class="setting-label">{{ t('ui.subtitleSize') }}</span>
|
<span class="setting-label">{{ t('ui.subtitleSize') }}</span>
|
||||||
<select :value="store.subFontSize" @change="store.setSubFontSize(+($event.target as HTMLSelectElement).value)">
|
<select :value="store.subFontSize" @change="store.setSubFontSize(+($event.target as HTMLSelectElement).value)">
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch, onMounted } from 'vue'
|
import { ref, watch, onMounted } from 'vue'
|
||||||
import { useI18n } from '@/composables/useI18n'
|
import { useI18n } from '@/composables/useI18n'
|
||||||
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const store = useGameStore()
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
canSkip: boolean
|
canSkip: boolean
|
||||||
currentSpeed: number
|
currentSpeed: number
|
||||||
|
visible: boolean
|
||||||
|
showQuality: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -31,19 +35,45 @@ onMounted(() => updateLabel(props.currentSpeed))
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="playback-bar">
|
<div class="bottom-bar left" :class="{ hidden: !visible }">
|
||||||
<button v-if="canSkip" class="pb-btn skip-btn" @click="emit('skip')">{{ t('ui.skip') }}</button>
|
<button v-if="canSkip" class="bb-btn skip-btn" @click="emit('skip')">{{ t('ui.skip') }}</button>
|
||||||
<button class="pb-btn speed-btn" @click="toggleSpeed">{{ speedLabel }}</button>
|
<button class="bb-btn" @click="toggleSpeed">{{ speedLabel }}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="showQuality" class="bottom-bar right" :class="{ hidden: !visible }">
|
||||||
|
<select class="bb-select" :value="store.preferredQuality" @change="store.setPreferredQuality(($event.target as HTMLSelectElement).value)">
|
||||||
|
<option value="">自动</option>
|
||||||
|
<option value="超清 (1080P)">超清 (1080P)</option>
|
||||||
|
<option value="高清 (720P)">高清 (720P)</option>
|
||||||
|
<option value="标清 (480P)">标清 (480P)</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.playback-bar {
|
.bottom-bar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
z-index: 20;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pb-btn {
|
.bottom-bar.left {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-bar.right {
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-bar.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bb-btn {
|
||||||
padding: 6px 14px;
|
padding: 6px 14px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
@@ -54,7 +84,7 @@ onMounted(() => updateLabel(props.currentSpeed))
|
|||||||
transition: background 0.15s, color 0.15s;
|
transition: background 0.15s, color 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pb-btn:hover {
|
.bb-btn:hover {
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
@@ -67,4 +97,15 @@ onMounted(() => updateLabel(props.currentSpeed))
|
|||||||
.skip-btn:hover {
|
.skip-btn:hover {
|
||||||
background: rgba(255, 152, 0, 0.15);
|
background: rgba(255, 152, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bb-select {
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ccc;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user