feat(frontend): 实现新手引导功能
- 添加 Guide 组件和引导步骤配置 - 实现 useOnboardingTour 和 useTourStepDescription composables - 添加 onboarding store 管理引导状态 - 更新多个视图和组件以支持引导功能 - 添加国际化支持(中英文) - 删除旧的实现指南文档
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
export { useAuthStore } from './auth'
|
||||
export { useAppStore } from './app'
|
||||
export { useSubscriptionStore } from './subscriptions'
|
||||
export { useOnboardingStore } from './onboarding'
|
||||
|
||||
// Re-export types for convenience
|
||||
export type { User, LoginRequest, RegisterRequest, AuthResponse } from '@/types'
|
||||
|
||||
88
frontend/src/stores/onboarding.ts
Normal file
88
frontend/src/stores/onboarding.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Onboarding Store
|
||||
* Manages onboarding tour state and control methods
|
||||
*/
|
||||
|
||||
import { defineStore } from 'pinia'
|
||||
import { markRaw, ref, shallowRef } from 'vue'
|
||||
import type { Driver } from 'driver.js'
|
||||
|
||||
type VoidCallback = () => void
|
||||
type NextStepCallback = (delay?: number) => Promise<void>
|
||||
type IsCurrentStepCallback = (selector: string) => boolean
|
||||
|
||||
export const useOnboardingStore = defineStore('onboarding', () => {
|
||||
const replayCallback = ref<VoidCallback | null>(null)
|
||||
const nextStepCallback = ref<NextStepCallback | null>(null)
|
||||
const isCurrentStepCallback = ref<IsCurrentStepCallback | null>(null)
|
||||
|
||||
// 全局 driver 实例,跨组件保持
|
||||
const driverInstance = shallowRef<Driver | null>(null)
|
||||
|
||||
function setReplayCallback(callback: VoidCallback | null): void {
|
||||
replayCallback.value = callback
|
||||
}
|
||||
|
||||
function setControlMethods(methods: {
|
||||
nextStep: NextStepCallback,
|
||||
isCurrentStep: IsCurrentStepCallback
|
||||
}): void {
|
||||
nextStepCallback.value = methods.nextStep
|
||||
isCurrentStepCallback.value = methods.isCurrentStep
|
||||
}
|
||||
|
||||
function clearControlMethods(): void {
|
||||
nextStepCallback.value = null
|
||||
isCurrentStepCallback.value = null
|
||||
}
|
||||
|
||||
function setDriverInstance(driver: Driver | null): void {
|
||||
driverInstance.value = driver ? markRaw(driver) : null
|
||||
}
|
||||
|
||||
function getDriverInstance(): Driver | null {
|
||||
return driverInstance.value
|
||||
}
|
||||
|
||||
function isDriverActive(): boolean {
|
||||
return driverInstance.value?.isActive?.() ?? false
|
||||
}
|
||||
|
||||
function replay(): void {
|
||||
if (replayCallback.value) {
|
||||
replayCallback.value()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually advance to the next step
|
||||
* @param delay Optional delay in ms (useful for waiting for animations)
|
||||
*/
|
||||
async function nextStep(delay = 0): Promise<void> {
|
||||
if (nextStepCallback.value) {
|
||||
await nextStepCallback.value(delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the tour is currently highlighting a specific element
|
||||
*/
|
||||
function isCurrentStep(selector: string): boolean {
|
||||
if (isCurrentStepCallback.value) {
|
||||
return isCurrentStepCallback.value(selector)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return {
|
||||
setReplayCallback,
|
||||
setControlMethods,
|
||||
clearControlMethods,
|
||||
setDriverInstance,
|
||||
getDriverInstance,
|
||||
isDriverActive,
|
||||
replay,
|
||||
nextStep,
|
||||
isCurrentStep
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user