PluginProbe ʕ •ᴥ•ʔ
Presto Player / trunk
Presto Player vtrunk
4.3.0 4.2.4 4.2.3 4.2.2 4.2.0 4.2.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.12.0 1.13.0 1.14.0 1.14.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.13 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3-beta1 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.0-beta1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4
presto-player / src / admin / dashboard / pages / learn / ChapterCard.js
presto-player / src / admin / dashboard / pages / learn Last commit date
ChapterCard.js 1 month ago LearnPage.js 1 month ago LearnPageSkeleton.js 1 month ago ProgressPill.js 1 month ago ScreenshotDialog.js 1 month ago SetupCompleteCard.js 1 month ago StepItem.js 1 month ago useLearnProgress.js 1 month ago
ChapterCard.js
91 lines
1 import { useState } from '@wordpress/element';
2 import { ChevronDown, ChevronUp, ArrowUpRight } from 'lucide-react';
3 import StepItem from './StepItem';
4 import ProgressPill from './ProgressPill';
5
6 const { __ } = wp.i18n;
7
8 const ChapterCard = ( { chapter, defaultOpen = false, onStepToggle } ) => {
9 const [ open, setOpen ] = useState( defaultOpen );
10
11 const totalSteps = chapter.steps?.length || 0;
12 const completedSteps =
13 chapter.steps?.filter( ( step ) => step.completed ).length || 0;
14
15 const handleDocsClick = ( e ) => {
16 e.stopPropagation();
17 if ( chapter.docsUrl ) {
18 window.open( chapter.docsUrl, '_blank', 'noopener,noreferrer' );
19 }
20 };
21
22 return (
23 <div className="rounded-lg border border-solid border-border-subtle bg-background-primary overflow-hidden">
24 { /* Header */ }
25 <button
26 type="button"
27 onClick={ () => setOpen( ( v ) => ! v ) }
28 aria-expanded={ open }
29 className="w-full flex items-start justify-between gap-4 px-5 py-4 bg-transparent border-0 cursor-pointer text-left hover:bg-background-secondary/40 transition-colors"
30 >
31 <div className="flex-1 min-w-0">
32 <h3 className="m-0 text-base font-semibold text-text-primary">
33 { chapter.title }
34 </h3>
35 { chapter.description && (
36 <p className="m-0 mt-1 text-sm text-text-secondary leading-relaxed">
37 { chapter.description }
38 </p>
39 ) }
40 </div>
41
42 <div className="shrink-0 flex items-center gap-3 pt-1">
43 { chapter.docsUrl && (
44 <span
45 role="button"
46 tabIndex={ 0 }
47 onClick={ handleDocsClick }
48 onKeyDown={ ( e ) => {
49 if ( e.key === 'Enter' || e.key === ' ' ) {
50 handleDocsClick( e );
51 }
52 } }
53 className="inline-flex items-center gap-1 text-xs font-medium text-brand-primary-600 hover:text-brand-hover-700 cursor-pointer"
54 >
55 { __( 'Learn how', 'presto-player' ) }
56 <ArrowUpRight className="w-3.5 h-3.5" />
57 </span>
58 ) }
59
60 <ProgressPill
61 completed={ completedSteps }
62 total={ totalSteps }
63 />
64
65 { open ? (
66 <ChevronUp className="w-5 h-5 text-text-secondary" />
67 ) : (
68 <ChevronDown className="w-5 h-5 text-text-secondary" />
69 ) }
70 </div>
71 </button>
72
73 { /* Steps */ }
74 { open && (
75 <div className="border-0 border-t border-solid border-border-subtle p-4 flex flex-col gap-3 bg-background-secondary/20">
76 { chapter.steps?.map( ( step ) => (
77 <StepItem
78 key={ step.id }
79 chapterId={ chapter.id }
80 step={ step }
81 onToggle={ onStepToggle }
82 />
83 ) ) }
84 </div>
85 ) }
86 </div>
87 );
88 };
89
90 export default ChapterCard;
91