PluginProbe
Extendify / 3.0.4
Extendify v3.0.4
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / workflows / theme / components / SelectAnimation.jsx

SelectAnimation.jsx in Extendify 3.0.4, at src/Agent/workflows/theme/components/SelectAnimation.jsx

209 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { getOption } from '@agent/lib/wp';
2 import {
3 __experimentalToggleGroupControl as ToggleGroupControl,
4 __experimentalToggleGroupControlOption as ToggleGroupControlOption,
5 } from '@wordpress/components';
6 import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
7 import { __, _x } from '@wordpress/i18n';
8 import {
9 flipVertical,
10 Icon,
11 notAllowed,
12 shadow,
13 square,
14 } from '@wordpress/icons';
15 import classNames from 'classnames';
16
17 const animations = [
18 {
19 // translators: Animation style where the element gradually appears by transitioning from transparent to visible. Translate as a simple, non-technical description of the visual effect (e.g., 'appear', 'show up') suitable for non-technical users.
20 name: _x('Fade In', 'animation type', 'extendify-local'),
21 slug: 'fade',
22 icon: shadow,
23 },
24 {
25 // translators: Animation style where the element appears while moving upward. Translate as a simple, non-technical description of the motion (e.g., 'appear from below', 'rise into view') suitable for non-technical users.
26 name: _x('Fade Up', 'animation type', 'extendify-local'),
27 slug: 'fade-up',
28 icon: flipVertical,
29 },
30 {
31 // translators: Animation style where the element appears by scaling from small to its full size. Translate as a simple, non-technical description of the effect (e.g., 'zoom in', 'get closer') suitable for non-technical users. If the target language commonly uses the English term 'zoom', it's acceptable to keep it.
32 name: _x('Zoom In', 'animation type', 'extendify-local'),
33 slug: 'zoom-in',
34 icon: square,
35 },
36 {
37 // translators: None refers to 'no animation'. Apply the correct grammatical gender/form that agrees with the word for 'animation' in the target language.
38 name: _x('None', 'animation type', 'extendify-local'),
39 slug: 'none',
40 icon: notAllowed,
41 },
42 ];
43
44 const speeds = [
45 {
46 // translators: "Slow" refers to a slower speed at which the animation effect occurs. This is an option in a list of animation speeds.
47 name: _x('Slow', 'animation speed', 'extendify-local'),
48 slug: 'slow',
49 },
50 {
51 // translators: "Medium" refers to a moderate speed at which the animation effect occurs. This is an option in a list of animation speeds.
52 name: _x('Medium', 'animation speed', 'extendify-local'),
53 slug: 'medium',
54 },
55 {
56 // translators: "Fast" refers to a quicker speed at which the animation effect occurs. This is an option in a list of animation speeds.
57 name: _x('Fast', 'animation speed', 'extendify-local'),
58 slug: 'fast',
59 },
60 ];
61
62 export const SelectAnimation = ({ onConfirm, onCancel, onLoad }) => {
63 const initialSettings = useRef({});
64 const [animation, setAnimation] = useState(null);
65 const [touched, setTouched] = useState(0);
66 const [speed, setSpeed] = useState(null);
67 const [loading, setLoading] = useState(true);
68 const undoAnimation = useCallback(() => {
69 if (!touched) return;
70 window.ExtendableAnimations?.setType(initialSettings.current.type);
71 window.ExtendableAnimations?.setSpeed(initialSettings.current.speed);
72 }, [touched]);
73
74 const confirmed = useRef(false);
75 // Ref keeps the latest undo function, so clean-up always sees the current `touched` state.
76 const undoRef = useRef(undoAnimation);
77 undoRef.current = undoAnimation;
78 useEffect(() => {
79 return () => {
80 if (!confirmed.current) undoRef.current();
81 };
82 }, []);
83
84 const handleConfirm = () => {
85 if (!animation || !speed || loading) return;
86 confirmed.current = true;
87 onConfirm({ data: { type: animation, speed } });
88 };
89
90 useEffect(() => {
91 if (!touched) return;
92 window.ExtendableAnimations.setType(animation);
93 window.ExtendableAnimations.setSpeed(speed);
94 }, [speed, animation, touched]);
95
96 useEffect(() => {
97 if (loading) return;
98 onLoad();
99 }, [loading, onLoad]);
100
101 useEffect(() => {
102 if (!loading) return;
103 getOption('extendify_animation_settings').then((settings = {}) => {
104 const defaults = { type: 'none', speed: 'medium' };
105 initialSettings.current = { ...defaults, ...(settings || {}) };
106 setAnimation(initialSettings.current.type);
107 setSpeed(initialSettings.current.speed);
108 setLoading(false);
109 });
110 }, []);
111
112 if (loading) {
113 return (
114 <div className="min-h-24 p-2 text-center text-sm">
115 {
116 // translators: This is a status message. 'Loading' is a verb — the app is currently loading the animation options. It is not referring to 'loading animation' as a compound noun.
117 __('Loading animation options...', 'extendify-local')
118 }
119 </div>
120 );
121 }
122
123 return (
124 <div className="mb-4 ml-10 mr-2 flex flex-col rounded-lg border border-gray-300 bg-gray-50 rtl:ml-2 rtl:mr-10">
125 <div className="rounded-lg p-3 border-b border-gray-300 bg-white">
126 <div className="text-xs uppercase mb-3 text-gray-700 font-medium">
127 {/* translators: "Type" refers to the category of animation effects available. e.g. The type could be 'Zoom In', 'Fade', etc. */}
128 {_x('Type', 'animation type', 'extendify-local')}
129 </div>
130 <div className="grid gap-2 mb-6 grid-cols-2 auto-rows-fr">
131 {animations.map(({ name, slug, icon }) => (
132 <Button
133 key={slug}
134 name={name}
135 icon={icon}
136 selected={animation === slug}
137 onClick={() => {
138 setTouched((v) => v + 1);
139 setAnimation(slug);
140 }}
141 />
142 ))}
143 </div>
144 {/* mb-1 because the toggle group has margins even if undefined */}
145 <div className="text-xs uppercase mb-1 text-gray-700 font-medium">
146 {/* translators: "Speed" refers to the speed at which the animation effect occurs. This is a heading label shown above the toggle group for selecting animation speed. */}
147 {_x('Speed', 'animation speed', 'extendify-local')}
148 </div>
149 <ToggleGroupControl
150 className="border-gray-300 rounded-sm m-0 before:rounded-sm focus-within:border-gray-900"
151 __next40pxDefaultSize
152 __nextHasNoMarginBottom
153 isBlock
154 value={speed}
155 onChange={(speed) => {
156 setTouched((v) => v + 1);
157 setSpeed(speed);
158 }}
159 >
160 {speeds.map(({ name, slug }) => (
161 <ToggleGroupControlOption key={slug} label={name} value={slug} />
162 ))}
163 </ToggleGroupControl>
164 </div>
165 <div className="flex justify-start gap-2 p-3">
166 <button
167 type="button"
168 className="w-full rounded-sm border border-gray-500 bg-white p-2 text-sm text-gray-900"
169 onClick={onCancel}
170 >
171 {__('Cancel', 'extendify-local')}
172 </button>
173 <button
174 type="button"
175 className="w-full rounded-sm border border-design-main bg-design-main p-2 text-sm text-white"
176 disabled={!animation || !speed || loading}
177 onClick={handleConfirm}
178 >
179 {__('Save', 'extendify-local')}
180 </button>
181 </div>
182 </div>
183 );
184 };
185
186 const Button = ({ name, selected, icon, onClick }) => {
187 return (
188 <button
189 type="button"
190 className={classNames(
191 'relative h-full w-full rounded-lg border p-2 text-sm text-left flex flex-col gap-4 font-medium hover:bg-gray-100',
192 {
193 'border-gray-900 bg-gray-100': selected,
194 'border-gray-300 bg-gray-50': !selected,
195 },
196 )}
197 onClick={onClick}
198 >
199 <Icon icon={icon} className="h-6 w-6" />
200 {name}
201 {selected && (
202 <div className="absolute top-1 right-1 h-3.5 w-3.5 flex items-center justify-center rounded-full bg-design-main text-center text-xss text-white leading-none">
203 <span></span>
204 </div>
205 )}
206 </button>
207 );
208 };
209