'use client' import type { StepByStepTourTaskId, StepByStepTourTaskView } from './types' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { useEffect, useRef } from 'react' export type FloatingChecklistProps = { className?: string title: string duration: string minimized: boolean progress: { ariaValueText: string completed: number total: number } completionPrompt?: { description: string dismissLabel: string label: string onDismiss: () => void title: string } tasks: StepByStepTourTaskView[] skipLabel: string minimizeLabel: string restoreLabel: string getTaskCompleteLabel: (taskTitle: string) => string getTaskIncompleteLabel: (taskTitle: string) => string onMinimize: () => void onRestore: () => void onSkip: () => void onCompleteTask: (taskId: StepByStepTourTaskId) => void onStartTask: (taskId: StepByStepTourTaskId) => void onUncompleteTask: (taskId: StepByStepTourTaskId) => void } export function FloatingChecklist({ className, title, duration, minimized, progress, completionPrompt, tasks, skipLabel, minimizeLabel, restoreLabel, getTaskCompleteLabel, getTaskIncompleteLabel, onMinimize, onRestore, onSkip, onCompleteTask, onStartTask, onUncompleteTask, }: FloatingChecklistProps) { if (minimized && !completionPrompt) { return ( ) } return ( {title} {duration} {!completionPrompt && ( <> {skipLabel} > )} {tasks.map((task) => ( ))} {completionPrompt && } ) } function TourCompletionPrompt({ description, dismissLabel, label, onDismiss, title, }: NonNullable) { const dismissRef = useRef(null) useEffect(() => { dismissRef.current?.focus({ preventScroll: true }) }, []) return ( {title} {description} {dismissLabel} ) } function MinimizedTourPill({ title, progress, restoreLabel, onRestore, className, }: { title: string progress: FloatingChecklistProps['progress'] restoreLabel: string onRestore: () => void className?: string }) { return ( {title} {`${progress.completed}/${progress.total}`} ) } function TourProgress({ ariaValueText, completed, total, }: { ariaValueText: string completed: number total: number }) { return ( <> {Array.from({ length: total }, (_, index) => { const active = index < completed return ( ) })} > ) } function TourTaskRow({ task, onCompleteTask, getTaskCompleteLabel, getTaskIncompleteLabel, onStartTask, onUncompleteTask, }: { task: StepByStepTourTaskView onCompleteTask: (taskId: StepByStepTourTaskId) => void getTaskCompleteLabel: (taskTitle: string) => string getTaskIncompleteLabel: (taskTitle: string) => string onStartTask: (taskId: StepByStepTourTaskId) => void onUncompleteTask: (taskId: StepByStepTourTaskId) => void }) { const completed = task.status === 'completed' const current = task.status === 'current' const disabled = task.status === 'disabled' const completionToggleDisabled = disabled || task.canToggleCompletion === false const statusIndicatorDisabled = completed ? disabled : completionToggleDisabled return ( {task.title} {!completed && ( <> {disabled && task.disabledReason ? task.disabledReason : task.description} onStartTask(task.id)} > {task.primaryActionLabel} {task.learnMoreHref && task.learnMoreLabel && ( {task.learnMoreLabel} )} > )} onCompleteTask(task.id)} onUncomplete={() => onUncompleteTask(task.id)} /> ) } function TaskStatusIndicator({ completed, disabled, completeLabel, incompleteLabel, onComplete, onUncomplete, }: { completed: boolean disabled: boolean completeLabel: string incompleteLabel: string onComplete: () => void onUncomplete: () => void }) { if (completed) { return ( ) } return ( ) }
{duration}
{description}
{disabled && task.disabledReason ? task.disabledReason : task.description}