fix: hoist prompt toast to App.vue so it survives ChoicePanel unmount after selection

This commit is contained in:
2026-06-09 16:55:57 +08:00
parent bf4b85f727
commit bca137535b
2 changed files with 37 additions and 31 deletions

View File

@@ -26,6 +26,8 @@ const showChapterSelect = ref(false)
const hasAutoSave = ref(false)
const currentSpeed = ref(1)
const canSkip = ref(false)
const promptToast = ref('')
const showPromptToast = ref(false)
const { loadGame, start, resumeAutoSave, makeChoice, clickHotspot, startChapter,
skipScene, setSpeed, getSpeed, isSceneWatched,
@@ -57,6 +59,12 @@ function onChoose(index: number) {
makeChoice(index)
}
function onPrompt(text: string) {
promptToast.value = text
showPromptToast.value = true
setTimeout(() => { showPromptToast.value = false }, 2500)
}
function toggleMenu() {
showMenu.value = !showMenu.value
if (showMenu.value) {
@@ -167,7 +175,11 @@ init()
:timer-total="store.timerTotal"
:timer-remaining="store.timerRemaining"
@choose="onChoose"
@prompt="onPrompt"
/>
<Transition name="prompt-toast">
<div v-if="showPromptToast" class="prompt-toast">{{ promptToast }}</div>
</Transition>
<div v-if="started && !store.gameEnded" class="top-bar">
<LangSwitch />
<PlaybackBar
@@ -356,4 +368,27 @@ html, body {
.end-btn:hover {
background: rgba(255, 200, 100, 0.15);
}
.prompt-toast {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 16px 36px;
font-size: 20px;
color: #ffc107;
background: rgba(0, 0, 0, 0.85);
border: 1px solid rgba(255, 193, 7, 0.4);
border-radius: 6px;
letter-spacing: 3px;
text-align: center;
white-space: nowrap;
pointer-events: none;
z-index: 50;
}
.prompt-toast-enter-active { transition: opacity 0.3s ease; }
.prompt-toast-leave-active { transition: opacity 0.8s ease; }
.prompt-toast-enter-from,
.prompt-toast-leave-to { opacity: 0; }
</style>

View File

@@ -11,13 +11,12 @@ const props = defineProps<{
const emit = defineEmits<{
choose: [index: number]
prompt: [text: string]
}>()
const { t } = useI18n()
const focusIndex = ref(0)
const btnRefs = ref<(HTMLButtonElement | null)[]>([])
const toastText = ref('')
const toastVisible = ref(false)
function timerPercent(): number {
if (props.timerTotal <= 0) return 0
@@ -58,9 +57,7 @@ function onKeydown(e: KeyboardEvent, index: number) {
function handleChoose(index: number) {
const choice = props.choices[index]
if (choice?.prompt) {
toastText.value = choice.prompt
toastVisible.value = true
setTimeout(() => { toastVisible.value = false }, 2200)
emit('prompt', choice.prompt)
}
emit('choose', index)
}
@@ -90,10 +87,6 @@ function handleChoose(index: number) {
{{ t(choice.textKey || choice.text) }}
</button>
</div>
<Transition name="toast-fade">
<div class="prompt-toast" v-if="toastVisible">{{ toastText }}</div>
</Transition>
</div>
</template>
@@ -191,26 +184,4 @@ function handleChoose(index: number) {
border-color: rgba(255, 193, 7, 0.7);
box-shadow: 0 0 12px rgba(255, 193, 7, 0.3);
}
.prompt-toast {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 14px 32px;
font-size: 18px;
color: #ffc107;
background: rgba(0, 0, 0, 0.85);
border: 1px solid rgba(255, 193, 7, 0.4);
border-radius: 6px;
letter-spacing: 2px;
text-align: center;
white-space: nowrap;
pointer-events: none;
}
.toast-fade-enter-active { transition: opacity 0.3s ease; }
.toast-fade-leave-active { transition: opacity 0.6s ease; }
.toast-fade-enter-from,
.toast-fade-leave-to { opacity: 0; }
</style>