Skip to content

Commit 5828b4e

Browse files
Merge pull request #1131 from cloudinary/feature/crop-and-gravity-ui
Prepare the new UI of the Crop and Gravity Feature
2 parents fa1fed9 + c6e520b commit 5828b4e

8 files changed

Lines changed: 331 additions & 123 deletions

File tree

css/cloudinary.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

css/images/undo.svg

Lines changed: 3 additions & 0 deletions
Loading

js/cloudinary.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

php/ui/component/class-crops.php

Lines changed: 122 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class Crops extends Select {
2424
* @var string
2525
*/
2626
protected $demo_files = array(
27-
'leather_bag.jpg',
28-
'lady.jpg',
29-
'horses.jpg',
27+
'docs/addons/objectdetection/dirt-road-1851258_1280.jpg',
28+
'docs/model-993911_640.jpg',
29+
'docs/shoppable_bag.png',
3030
);
3131

3232
/**
@@ -96,7 +96,6 @@ protected function info_box( $struct ) {
9696
* @return array
9797
*/
9898
protected function input( $struct ) {
99-
10099
$mode = $this->setting->get_param( 'mode', 'demos' );
101100
$wrapper = $this->get_part( 'div' );
102101
$wrapper['attributes']['class'][] = 'cld-size-items';
@@ -112,89 +111,130 @@ protected function input( $struct ) {
112111
}
113112
$sizes = Utils::get_registered_sizes();
114113

115-
$selector = $this->make_selector();
116-
$wrapper['children']['control-selector'] = $selector;
114+
// Create size selector (tabs).
115+
$size_selector = $this->make_size_selector( $sizes );
116+
$wrapper['children']['size-selector'] = $size_selector;
117+
118+
// Get demo files.
119+
$mode = $this->setting->get_param( 'mode', 'demos' );
120+
121+
/**
122+
* Filter the demo files.
123+
*
124+
* @hook cloudinary_registered_sizes
125+
* @since 3.1.3
126+
*
127+
* @param $demo_files {array} array of demo files.
128+
*
129+
* @return {array}
130+
*/
131+
$examples = apply_filters( 'cloudinary_demo_crop_files', $this->demo_files );
132+
133+
if ( 'full' === $mode ) {
134+
$public_id = $this->setting->get_root_setting()->get_param( 'preview_id' );
135+
if ( ! empty( $public_id ) ) {
136+
$examples = array( $public_id );
137+
}
138+
}
139+
140+
// Create content area for each size.
117141
foreach ( $sizes as $size => $details ) {
118142
if ( empty( $details['crop'] ) ) {
119143
continue;
120144
}
121-
$row = $this->get_part( 'div' );
122-
$row['attributes']['class'][] = 'cld-size-items-item';
123-
$row['attributes']['class'][] = 'crop-preview';
124-
$row['content'] = $size;
125-
126-
$image = $this->get_part( 'img' );
127-
$image['content'] = $size;
128-
$size_array = array();
145+
146+
$size_content = $this->get_part( 'div' );
147+
$size_content['attributes']['class'][] = 'cld-size-content';
148+
$size_content['attributes']['data-size'] = $size;
149+
$size_content['render'] = true;
150+
151+
$size_array = array();
129152
if ( ! empty( $details['width'] ) ) {
130-
$size_array[] = 'w_' . $details['width'];
131-
$image['attributes']['width'] = $details['width'];
153+
$size_array[] = 'w_' . $details['width'];
132154
}
133155
if ( ! empty( $details['height'] ) ) {
134-
$size_array[] = 'h_' . $details['height'];
135-
$image['attributes']['height'] = $details['height'];
156+
$size_array[] = 'h_' . $details['height'];
157+
}
158+
$size_dimensions = implode( ',', $size_array );
159+
160+
// Create image previews container.
161+
$images_container = $this->get_part( 'div' );
162+
$images_container['attributes']['class'][] = 'cld-size-images';
163+
$images_container['render'] = true;
164+
165+
foreach ( $examples as $index => $file ) {
166+
$image_wrapper = $this->get_part( 'div' );
167+
$image_wrapper['attributes']['class'][] = 'cld-size-image-wrapper';
168+
$image_wrapper['render'] = true;
169+
170+
$image = $this->get_part( 'img' );
171+
$image['attributes']['data-size'] = $size_dimensions;
172+
$image['attributes']['data-file'] = $file;
173+
$image['render'] = true;
174+
if ( ! empty( $details['width'] ) ) {
175+
$image['attributes']['width'] = $details['width'];
176+
}
177+
if ( ! empty( $details['height'] ) ) {
178+
$image['attributes']['height'] = $details['height'];
179+
}
180+
181+
$image_wrapper['children']['image'] = $image;
182+
$images_container['children'][ 'image-' . $index ] = $image_wrapper;
136183
}
137-
$image['attributes']['data-size'] = implode( ',', $size_array );
138-
$size_key = $details['width'] . 'x' . $details['height'];
184+
185+
// Create single input field with disable checkbox.
186+
$size_key = $details['width'] . 'x' . $details['height'];
139187
if ( empty( $value[ $size_key ] ) ) {
140188
$value[ $size_key ] = '';
141189
}
142-
$row['children']['size'] = $image;
143-
$row['children']['input'] = $this->make_input( $this->get_name() . '[' . $size_key . ']', $value[ $size_key ] );
190+
191+
$input_wrapper = $this->make_input( $this->get_name() . '[' . $size_key . ']', $value[ $size_key ] );
192+
144193
// Set the placeholder.
145194
$placeholder = 'c_fill,g_auto';
146-
147195
if ( 'thumbnail' === $size ) {
148196
$placeholder = 'c_thumb,g_auto';
149197
}
150-
$row['children']['input']['children']['input']['attributes']['placeholder'] = $placeholder;
198+
$input_wrapper['children']['input']['attributes']['placeholder'] = $placeholder;
151199

152-
$wrapper['children'][ $size ] = $row;
200+
$size_content['children']['input'] = $input_wrapper;
201+
$size_content['children']['images'] = $images_container;
153202

203+
$wrapper['children'][ 'content-' . $size ] = $size_content;
154204
}
155205

156206
return $wrapper;
157207
}
158208

159209
/**
160-
* Make an image selector.
210+
* Make a size selector (tabs).
211+
*
212+
* @param array $sizes The registered sizes.
213+
* @return array
161214
*/
162-
protected function make_selector() {
215+
protected function make_size_selector( $sizes ) {
163216
$selector = $this->get_part( 'div' );
164-
$selector['attributes']['class'][] = 'cld-image-selector';
165-
$mode = $this->setting->get_param( 'mode', 'demos' );
217+
$selector['attributes']['class'][] = 'cld-size-selector';
218+
$selector['render'] = true;
166219

167-
/**
168-
* Filter the demo files.
169-
*
170-
* @hook cloudinary_registered_sizes
171-
* @since 3.1.3
172-
*
173-
* @param $demo_files {array} array of demo files.
174-
*
175-
* @return {array}
176-
*/
177-
$examples = apply_filters( 'cloudinary_demo_crop_files', $this->demo_files );
178-
if ( 'full' === $mode ) {
179-
$public_id = $this->setting->get_root_setting()->get_param( 'preview_id' );
180-
if ( ! empty( $public_id ) ) {
181-
$examples = array(
182-
$public_id,
183-
);
220+
$index = 0;
221+
foreach ( $sizes as $size => $details ) {
222+
if ( empty( $details['crop'] ) ) {
223+
continue;
184224
}
185-
}
186-
foreach ( $examples as $index => $file ) {
187-
$name = pathinfo( $file, PATHINFO_FILENAME );
188-
$item = $this->get_part( 'span' );
189-
$item['attributes']['data-image'] = $file;
225+
226+
$item = $this->get_part( 'span' );
227+
$item['attributes']['data-size'] = $size;
228+
$item['attributes']['class'][] = 'cld-size-selector-item';
229+
$item['render'] = true;
230+
190231
if ( 0 === $index ) {
191232
$item['attributes']['data-selected'] = true;
192-
193233
}
194-
$item['attributes']['class'][] = 'cld-image-selector-item';
195234

196-
$item['content'] = $name;
197-
$selector['children'][ 'image-' . $index ] = $item;
235+
$item['content'] = $size;
236+
$selector['children'][ 'size-' . $size ] = $item;
237+
++$index;
198238
}
199239

200240
return $selector;
@@ -215,9 +255,11 @@ protected function make_input( $name, $value ) {
215255
'crop-size-inputs',
216256
);
217257

218-
$label = $this->get_part( 'label' );
219-
$label['attributes']['for'] = $name;
220-
$label['content'] = __( 'Disable', 'cloudinary' );
258+
// Disable toggle control.
259+
$control = $this->get_part( 'label' );
260+
$control['attributes']['class'][] = 'cld-input-on-off-control';
261+
$control['attributes']['class'][] = 'medium';
262+
$control['attributes']['for'] = $name;
221263

222264
$check = $this->get_part( 'input' );
223265
$check['attributes']['type'] = 'checkbox';
@@ -230,15 +272,34 @@ protected function make_input( $name, $value ) {
230272
$check['attributes']['checked'] = 'checked';
231273
}
232274

275+
$slider = $this->get_part( 'span' );
276+
$slider['attributes']['class'][] = 'cld-input-on-off-control-slider';
277+
$slider['render'] = true;
278+
279+
$control['children']['input'] = $check;
280+
$control['children']['slider'] = $slider;
281+
282+
$label = $this->get_part( 'span' );
283+
$label['attributes']['class'] = 'cld-input-on-off-control-label';
284+
$label['content'] = __( 'Disable', 'cloudinary' );
285+
233286
$input = $this->get_part( 'input' );
234287
$input['attributes']['type'] = 'text';
235288
$input['attributes']['name'] = $name;
236289
$input['attributes']['value'] = '--' !== $value ? $value : '';
237290
$input['attributes']['class'][] = 'regular-text';
238291

239-
$wrapper['children']['input'] = $input;
240-
$wrapper['children']['label'] = $label;
241-
$wrapper['children']['check'] = $check;
292+
$clear_button = $this->get_part( 'button' );
293+
$clear_button['attributes']['type'] = 'button';
294+
$clear_button['attributes']['class'][] = 'button';
295+
$clear_button['attributes']['class'][] = 'clear-crop-input';
296+
$clear_button['attributes']['title'] = __( 'Reset input', 'cloudinary' );
297+
$clear_button['content'] = Utils::get_inline_svg( 'css/images/undo.svg', false ) . '<span>' . __( 'Reset', 'cloudinary' ) . '</span>';
298+
299+
$wrapper['children']['input'] = $input;
300+
$wrapper['children']['button'] = $clear_button;
301+
$wrapper['children']['control'] = $control;
302+
$wrapper['children']['label'] = $label;
242303

243304
return $wrapper;
244305
}

src/css/_variables.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ $color-transformations-cyan: #54c8db;
2424
$color-transformations-background: #262c35;
2525
$color-transformations-asset: #333B4C;
2626

27+
2728
/** Sizes */
2829
$content-width: 870px;
2930
$size-small: 783px;

src/css/components/ui/_sizes-preview.scss

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,30 +73,118 @@
7373
}
7474
}
7575

76-
.crop-size-inputs{
76+
.crop-size-inputs {
7777
display: flex;
7878
align-items: center;
7979
gap: 10px;
80+
margin-bottom: 16px;
81+
max-width: 400px;
82+
flex-wrap: wrap;
83+
}
84+
85+
.cld-ui-input.regular-text {
86+
max-width: 260px;
8087
}
8188

8289
.cld-ui-input.regular-text[disabled]{
8390
background-color: $color-light-grey;
8491
opacity: 0.5;
8592
}
8693

94+
.disable-toggle {
95+
margin: 0;
96+
}
97+
98+
// Medium size toggle (between mini and standard)
99+
.cld-input-on-off-control.medium {
100+
width: 25px;
101+
height: 13px;
102+
margin-right: 0;
103+
104+
.cld-input-on-off-control-slider::before {
105+
height: 9px;
106+
width: 9px;
107+
left: 2px;
108+
bottom: 2px;
109+
}
110+
111+
input:checked + .cld-input-on-off-control-slider::before {
112+
transform: translateX(12px);
113+
}
114+
}
115+
116+
.cld-input-on-off-control-label {
117+
font-size: 12px;
118+
}
119+
120+
.button.clear-crop-input {
121+
display: inline-flex;
122+
align-items: center;
123+
gap: 6px;
124+
background: transparent;
125+
border: none;
126+
color: $color-cld-blue;
127+
padding: 0;
128+
cursor: pointer;
129+
box-shadow: none;
130+
font-size: 14px;
131+
font-weight: 600;
132+
margin-right: 40px;
133+
134+
svg {
135+
width: 16px;
136+
height: 16px;
137+
fill: currentColor;
138+
}
139+
140+
&:hover {
141+
background: transparent;
142+
opacity: 0.8;
143+
}
144+
145+
&:focus {
146+
box-shadow: none;
147+
outline: none;
148+
}
149+
}
150+
87151
}
88152

89-
&-image-selector {
153+
&-size-selector {
90154
display: flex;
155+
flex-wrap: nowrap;
156+
overflow-x: scroll;
157+
scrollbar-width: thin;
158+
border: 1px solid $color-light-grey;
159+
border-radius: 4px;
160+
width: fit-content;
161+
max-width: 100%;
162+
163+
margin-bottom: 42px;
164+
padding: 4px;
91165

92166
&-item {
93-
border: 1px solid $color-light-grey;
94-
padding: 3px 6px;
167+
flex-shrink: 0;
168+
white-space: nowrap;
169+
padding: 8px;
95170
margin: 0 3px -1px 0;
96171
cursor: pointer;
172+
color: $color-transformations-asset;
173+
background-color: transparent;
174+
175+
font-weight: 600;
97176

98177
&[data-selected] {
99-
background-color: $color-light-grey;
178+
color: $color-cld-blue;
179+
background-color: rgba(52, 72, 197, 0.06);
100180
}
101181
}
102182
}
183+
184+
&-size-images {
185+
display: flex;
186+
flex-wrap: wrap;
187+
gap: 10px;
188+
189+
margin-bottom: 42px;
190+
}

0 commit comments

Comments
 (0)