PluginProbe ʕ •ᴥ•ʔ
Presto Player / trunk
Presto Player vtrunk
4.3.1 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 / StepItem.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
StepItem.js
139 lines
1 import { useState } from '@wordpress/element';
2 import { Button } from '@bsf/force-ui';
3 import {
4 ArrowUpRight,
5 Check,
6 ChevronDown,
7 ChevronUp,
8 Circle,
9 Info,
10 } from 'lucide-react';
11 import ScreenshotDialog from './ScreenshotDialog';
12
13 const { __ } = wp.i18n;
14
15 const StepItem = ( { chapterId, step, onToggle } ) => {
16 const [ open, setOpen ] = useState( false );
17 const [ screenshotOpen, setScreenshotOpen ] = useState( false );
18 const completed = !! step.completed;
19
20 const toggleCompleted = ( e ) => {
21 e.stopPropagation();
22 onToggle( chapterId, step.id, ! completed );
23 };
24
25 return (
26 <div className="rounded-lg border border-solid border-border-subtle bg-background-primary">
27 { /* Header */ }
28 <button
29 type="button"
30 onClick={ () => setOpen( ( v ) => ! v ) }
31 aria-expanded={ open }
32 className="w-full flex items-center gap-3 px-4 py-3 bg-transparent border-0 cursor-pointer text-left hover:bg-background-secondary/40 transition-colors"
33 >
34 <span
35 role="button"
36 tabIndex={ 0 }
37 onClick={ toggleCompleted }
38 onKeyDown={ ( e ) => {
39 if ( e.key === 'Enter' || e.key === ' ' ) {
40 toggleCompleted( e );
41 }
42 } }
43 aria-label={
44 completed
45 ? __( 'Mark step incomplete', 'presto-player' )
46 : __( 'Mark step complete', 'presto-player' )
47 }
48 className={ `shrink-0 inline-flex items-center justify-center w-5 h-5 rounded-full border border-solid transition-colors cursor-pointer ${
49 completed
50 ? 'bg-brand-primary-600 border-brand-primary-600 text-white'
51 : 'bg-background-primary border-border-strong text-transparent hover:border-brand-400'
52 }` }
53 >
54 { completed ? (
55 <Check className="w-3 h-3" />
56 ) : (
57 <Circle className="w-0 h-0" />
58 ) }
59 </span>
60
61 <span className="flex-1 text-sm font-medium text-text-primary">
62 { step.title }
63 </span>
64
65 { step.isPro && (
66 <span className="inline-flex items-center px-2 py-0.5 rounded text-[10px] font-semibold uppercase tracking-wide bg-background-secondary text-text-secondary border border-solid border-border-subtle">
67 { __( 'Pro', 'presto-player' ) }
68 </span>
69 ) }
70
71 { open ? (
72 <ChevronUp className="w-5 h-5 text-text-secondary shrink-0" />
73 ) : (
74 <ChevronDown className="w-5 h-5 text-text-secondary shrink-0" />
75 ) }
76 </button>
77
78 { /* Body */ }
79 { open && (
80 <div className="border-0 border-t border-solid border-border-subtle px-4 py-4 flex items-start justify-between gap-4">
81 <div className="flex-1">
82 <p className="m-0 text-sm text-text-secondary leading-relaxed">
83 { step.description }
84 </p>
85
86 { step.docsUrl && (
87 <a
88 href={ step.docsUrl }
89 target="_blank"
90 rel="noopener noreferrer"
91 className="inline-flex items-center gap-1 mt-2 text-xs font-medium text-brand-primary-600 hover:text-brand-hover-700 no-underline"
92 >
93 { __( 'Read documentation', 'presto-player' ) }
94 <ArrowUpRight className="w-3.5 h-3.5" />
95 </a>
96 ) }
97 </div>
98
99 <div className="shrink-0 flex items-center gap-2">
100 <button
101 type="button"
102 onClick={ () => setScreenshotOpen( true ) }
103 aria-label={ __( 'View screenshot', 'presto-player' ) }
104 className="inline-flex items-center justify-center w-8 h-8 rounded-full border-0 bg-background-primary text-text-secondary hover:text-brand-primary-600 cursor-pointer transition-colors"
105 >
106 <Info className="w-4 h-4" />
107 </button>
108
109 { step.headerAction?.url && (
110 <Button
111 variant="primary"
112 size="sm"
113 onClick={ () => {
114 window.open(
115 step.headerAction.url,
116 '_blank',
117 'noopener,noreferrer'
118 );
119 } }
120 >
121 { step.headerAction.label }
122 </Button>
123 ) }
124 </div>
125 </div>
126 ) }
127
128 <ScreenshotDialog
129 open={ screenshotOpen }
130 onOpenChange={ setScreenshotOpen }
131 title={ step.title }
132 screenshot={ step.screenshot }
133 />
134 </div>
135 );
136 };
137
138 export default StepItem;
139