PluginProbe
Code Snippets / 4.0.0-beta.2
Code Snippets v4.0.0-beta.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / components / ManageMenu / AiAgentDemo / DemoSidebar.tsx

DemoSidebar.tsx in Code Snippets 4.0.0-beta.2, at js/components/ManageMenu/AiAgentDemo/DemoSidebar.tsx

193 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, { useState } from 'react'
2 import { __, sprintf } from '@wordpress/i18n'
3 import classnames from 'classnames'
4 import { DEMO_EXAMPLES } from './demoScript'
5 import { hasReached } from './types'
6 import type { DemoStage } from './types'
7
8 type DemoSidebarTab = 'actions' | 'history'
9
10 interface DemoQuotaWindow {
11 label: string
12 used: number
13 limit: number
14 }
15
16 /** Sample usage, so the meters the real agent shows have something to draw. */
17 const DEMO_QUOTA: readonly DemoQuotaWindow[] = [
18 { label: __('Today', 'code-snippets'), used: 2, limit: 25 },
19 { label: __('This month', 'code-snippets'), used: 34, limit: 300 }
20 ]
21
22 const FULL_PERCENT = 100
23
24 /** Conversations the scripted library already holds when the demo opens. */
25 const PAST_CONVERSATIONS: readonly string[] = [
26 __('Hide the admin bar for subscribers', 'code-snippets'),
27 __('Custom login screen logo', 'code-snippets')
28 ]
29
30 interface DemoStatus {
31 label: string
32 modifier?: string
33 }
34
35 /**
36 * How the conversation the walkthrough is having would be labelled in the
37 * history rail at each point of the script.
38 */
39 const currentStatus = (stage: DemoStage): DemoStatus => {
40 if ('applying' === stage) {
41 return { label: __('Updating', 'code-snippets') }
42 }
43
44 if (hasReached(stage, 'result-ready')) {
45 return { label: __('Completed', 'code-snippets'), modifier: 'is-done' }
46 }
47
48 if (hasReached(stage, 'building')) {
49 return { label: __('Building', 'code-snippets') }
50 }
51
52 if (hasReached(stage, 'plan-ready')) {
53 return { label: __('Plan ready', 'code-snippets'), modifier: 'is-plan' }
54 }
55
56 return { label: __('Planning', 'code-snippets') }
57 }
58
59 const DemoQuota: React.FC = () =>
60 <div className="ai-agent-quota">
61 <h2 className="ai-agent-sidebar__heading">{__('AI usage', 'code-snippets')}</h2>
62
63 {DEMO_QUOTA.map(({ label, used, limit }) =>
64 <div key={label} className="ai-agent-quota__row">
65 <div className="ai-agent-quota__label">
66 <span>{label}</span>
67 <span>{sprintf(
68 /* translators: 1: used count, 2: limit count. */
69 __('%1$d / %2$d', 'code-snippets'),
70 used,
71 limit
72 )}</span>
73 </div>
74
75 <div className="ai-agent-quota__track is-ok">
76 <div
77 className="ai-agent-quota__fill"
78 style={{ inlineSize: `${FULL_PERCENT * used / limit}%` }}
79 />
80 </div>
81 </div>)}
82 </div>
83
84 const DemoHistory: React.FC<{ stage: DemoStage }> = ({ stage }) => {
85 const status = currentStatus(stage)
86
87 return (
88 <div className="ai-agent-history">
89 <ul className="ai-agent-history__list">
90 {hasReached(stage, 'prompt-sent') &&
91 <li className="ai-agent-history__item is-active">
92 <span className="ai-agent-history__open">
93 <span className="ai-agent-history__title">
94 {__('Dismissible welcome banner', 'code-snippets')}
95 </span>
96 <span className={classnames('ai-agent-history__status', status.modifier)}>
97 {status.label}
98 </span>
99 </span>
100 </li>}
101
102 {PAST_CONVERSATIONS.map(title =>
103 <li key={title} className="ai-agent-history__item">
104 <span className="ai-agent-history__open">
105 <span className="ai-agent-history__title">{title}</span>
106 <span className="ai-agent-history__status is-done">
107 {__('Completed', 'code-snippets')}
108 </span>
109 </span>
110 </li>)}
111 </ul>
112 </div>
113 )
114 }
115
116 interface DemoTabProps {
117 tab: DemoSidebarTab
118 current: DemoSidebarTab
119 label: string
120 onSelect: (tab: DemoSidebarTab) => void
121 }
122
123 const DemoTab: React.FC<DemoTabProps> = ({ tab, current, label, onSelect }) =>
124 <button
125 type="button"
126 role="tab"
127 id={`ai-agent-demo-tab-${tab}`}
128 aria-selected={tab === current}
129 aria-controls={`ai-agent-demo-panel-${tab}`}
130 className={classnames('ai-agent-sidebar__tab', { 'is-active': tab === current })}
131 onClick={() => onSelect(tab)}
132 >
133 {label}
134 </button>
135
136 /**
137 * The sidebar the real agent uses, rendered inert. Only the tabs respond: the
138 * prompt chips, usage meters and conversation list are here for the shape of
139 * the page, not to be operated.
140 */
141 export const DemoSidebar: React.FC<{ stage: DemoStage }> = ({ stage }) => {
142 const [tab, setTab] = useState<DemoSidebarTab>('actions')
143
144 return (
145 <aside className="ai-agent-sidebar" aria-label={__('AI Agent tools', 'code-snippets')}>
146 <div className="ai-agent-sidebar__tabs" role="tablist">
147 <DemoTab
148 tab="actions"
149 current={tab}
150 label={__('Prompt Actions', 'code-snippets')}
151 onSelect={setTab}
152 />
153
154 <DemoTab
155 tab="history"
156 current={tab}
157 label={__('Past Conversations', 'code-snippets')}
158 onSelect={setTab}
159 />
160 </div>
161
162 <div
163 className="ai-agent-sidebar__panel"
164 role="tabpanel"
165 id="ai-agent-demo-panel-actions"
166 aria-labelledby="ai-agent-demo-tab-actions"
167 hidden={'actions' !== tab}
168 >
169 <div className="ai-agent-examples">
170 <h2 className="ai-agent-sidebar__heading">{__('Prompt examples', 'code-snippets')}</h2>
171
172 {DEMO_EXAMPLES.map(example =>
173 <button key={example} type="button" className="ai-agent-examples__chip" disabled>
174 {example}
175 </button>)}
176 </div>
177
178 <DemoQuota />
179 </div>
180
181 <div
182 className="ai-agent-sidebar__panel"
183 role="tabpanel"
184 id="ai-agent-demo-panel-history"
185 aria-labelledby="ai-agent-demo-tab-history"
186 hidden={'history' !== tab}
187 >
188 <DemoHistory stage={stage} />
189 </div>
190 </aside>
191 )
192 }
193