Story 3.3 : Textes narrateur contextuels et arc de révélation - Composable useNarrator.ts avec queue de messages prioritaires - Composable useIdleDetection.ts (détection inactivité 30s) - Plugin narrator-transitions.client.ts (déclencheurs de navigation) - Layout adventure.vue avec NarratorBubble intégré - Store progression: narratorStage devient un getter calculé (0-20-40-60-80%) - Pages projets, competences, temoignages, parcours utilisent layout adventure - Messages: intro, transitions, encouragements 25/50/75%, hints, contact_unlocked Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
45 lines
1011 B
TypeScript
45 lines
1011 B
TypeScript
export interface UseIdleDetectionOptions {
|
|
timeout?: number
|
|
onIdle?: () => void
|
|
}
|
|
|
|
export function useIdleDetection(options: UseIdleDetectionOptions = {}) {
|
|
const { timeout = 30000, onIdle } = options
|
|
|
|
const isIdle = ref(false)
|
|
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
|
|
function resetTimer() {
|
|
isIdle.value = false
|
|
if (timeoutId) {
|
|
clearTimeout(timeoutId)
|
|
}
|
|
timeoutId = setTimeout(() => {
|
|
isIdle.value = true
|
|
onIdle?.()
|
|
}, timeout)
|
|
}
|
|
|
|
const events = ['mousedown', 'mousemove', 'keydown', 'scroll', 'touchstart']
|
|
|
|
if (import.meta.client) {
|
|
onMounted(() => {
|
|
events.forEach((event) => {
|
|
window.addEventListener(event, resetTimer, { passive: true })
|
|
})
|
|
resetTimer()
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
events.forEach((event) => {
|
|
window.removeEventListener(event, resetTimer)
|
|
})
|
|
if (timeoutId) {
|
|
clearTimeout(timeoutId)
|
|
}
|
|
})
|
|
}
|
|
|
|
return { isIdle: readonly(isIdle) }
|
|
}
|