Skip to content

Commit a46a6fb

Browse files
committed
Craft.ui.icon()
1 parent 6b99686 commit a46a6fb

25 files changed

+195
-64
lines changed

CHANGELOG-WIP.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@
5858
- Added `craft\services\Elements::getBulkOpKeys()`.
5959
- Added `craft\services\Search::indexElementIfQueued()`.
6060
- Added `craft\services\Search::queueIndexElement()`.
61+
- Added `craft\web\View::registerIcon()`.
6162
- Added `craft\web\assets\codemirror\CodeMirrorAsset`.
6263
- Added `Craft.ui.createIconPicker()`.
6364
- Added `Craft.ui.createIconPickerField()`.
65+
- Added `Craft.ui.icon()`.
6466
- `craft\base\Element::fieldLayoutFields()` now has an `$editableOnly` argument.
6567

6668
### System

src/controllers/AppController.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,22 @@ public function actionResourceJs(string $url): Response
131131
return $this->asRaw($response->getBody());
132132
}
133133

134+
/**
135+
* Returns the HTML for a control panel icon.
136+
*
137+
* @return Response
138+
* @since 5.7.0
139+
*/
140+
public function actionIconSvg(): Response
141+
{
142+
$this->requireCpRequest();
143+
$this->requireAcceptsJson();
144+
145+
return $this->asJson([
146+
'iconSvg' => Cp::iconSvg($this->request->getRequiredParam('icon')),
147+
]);
148+
}
149+
134150
/**
135151
* Returns the latest Craftnet API headers.
136152
*

src/web/View.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,6 @@ class View extends \yii\web\View
309309
*/
310310
private array $_assetBundleBuffers = [];
311311

312-
313312
/**
314313
* @var array
315314
* @see startJsImportBuffer()
@@ -335,6 +334,12 @@ class View extends \yii\web\View
335334
*/
336335
private array $_jsImports = [];
337336

337+
/**
338+
* @var string[] The icons that should be registered to the page.
339+
* @see registerIcons()
340+
*/
341+
private array $_icons = [];
342+
338343
/**
339344
* @var callable[][]
340345
*/
@@ -1609,6 +1614,20 @@ public function registerTranslations(string $category, array $messages): void
16091614
$this->registerJs($js, self::POS_BEGIN);
16101615
}
16111616

1617+
/**
1618+
* Registers icons for `Craft.ui.icon()`.
1619+
*
1620+
* @param string[] $icons The icons to be registered
1621+
* @since 5.7.0
1622+
*/
1623+
public function registerIcons(array $icons): void
1624+
{
1625+
$this->_icons = [
1626+
...$this->_icons,
1627+
...array_flip($icons),
1628+
];
1629+
}
1630+
16121631
/**
16131632
* Returns the active namespace.
16141633
*
@@ -2256,6 +2275,18 @@ protected function renderBodyEndHtml($ajaxMode): string
22562275
$lines[] = implode("\n", $this->_html[self::POS_END]);
22572276
}
22582277

2278+
if (!empty($this->_icons)) {
2279+
$icons = [];
2280+
foreach (array_keys($this->_icons) as $icon) {
2281+
$icons[$icon] = Cp::iconSvg($icon);
2282+
}
2283+
$iconsJs = Json::encode($icons);
2284+
$this->js[self::POS_END][] = <<<JS
2285+
Craft.icons = $iconsJs;
2286+
JS;
2287+
$this->_icons = [];
2288+
}
2289+
22592290
$html = parent::renderBodyEndHtml($ajaxMode);
22602291

22612292
return empty($lines) ? $html : implode("\n", $lines) . $html;

src/web/assets/cp/CpAsset.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,27 @@ private function _registerTranslations(View $view): void
449449
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.',
450450
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.',
451451
]);
452+
453+
$view->registerIcons([
454+
'arrow-down',
455+
'arrow-left',
456+
'arrow-right',
457+
'arrow-up',
458+
'arrows-rotate',
459+
'asterisk',
460+
'asterisk-slash',
461+
'clipboard',
462+
'edit',
463+
'gear',
464+
'image',
465+
'image-slash',
466+
'pencil',
467+
'plus',
468+
'remove',
469+
'share',
470+
'trash',
471+
'xmark',
472+
]);
452473
}
453474

454475
private function _craftData(): array

src/web/assets/cp/dist/cp.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.

src/web/assets/cp/dist/cp.js.map

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

src/web/assets/cp/src/js/BaseElementSelectInput.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -427,12 +427,14 @@ Craft.BaseElementSelectInput = Garnish.Base.extend(
427427
if (this.settings.sortable) {
428428
const axis = this.getElementSortAxis();
429429
actions.push({
430-
icon:
431-
axis === 'y'
432-
? 'arrow-up'
433-
: Craft.orientation === 'ltr'
434-
? 'arrow-left'
435-
: 'arrow-right',
430+
icon: async () =>
431+
await Craft.ui.icon(
432+
axis === 'y'
433+
? 'arrow-up'
434+
: Craft.orientation === 'ltr'
435+
? 'arrow-left'
436+
: 'arrow-right'
437+
),
436438
label:
437439
axis === 'y'
438440
? Craft.t('app', 'Move up')
@@ -445,12 +447,14 @@ Craft.BaseElementSelectInput = Garnish.Base.extend(
445447
},
446448
});
447449
actions.push({
448-
icon:
449-
axis === 'y'
450-
? 'arrow-down'
451-
: Craft.orientation === 'ltr'
452-
? 'arrow-right'
453-
: 'arrow-left',
450+
icon: async () =>
451+
await Craft.ui.icon(
452+
axis === 'y'
453+
? 'arrow-down'
454+
: Craft.orientation === 'ltr'
455+
? 'arrow-right'
456+
: 'arrow-left'
457+
),
454458
label:
455459
axis === 'y'
456460
? Craft.t('app', 'Move down')
@@ -467,7 +471,7 @@ Craft.BaseElementSelectInput = Garnish.Base.extend(
467471
if (this.settings.allowRemove) {
468472
if (this.settings.elementType) {
469473
actions.push({
470-
icon: 'arrows-rotate',
474+
icon: async () => await Craft.ui.icon('arrows-rotate'),
471475
label: Craft.t('app', 'Replace'),
472476
callback: () => {
473477
this._$replaceElement = $element;
@@ -477,7 +481,7 @@ Craft.BaseElementSelectInput = Garnish.Base.extend(
477481
}
478482

479483
actions.push({
480-
icon: 'remove',
484+
icon: async () => await Craft.ui.icon('remove'),
481485
label: Craft.t('app', 'Remove'),
482486
callback: () => {
483487
// If the element is selected, remove *all* the selected elements

src/web/assets/cp/src/js/ComponentSelectInput.js

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -310,12 +310,14 @@ Craft.ComponentSelectInput = Garnish.Base.extend(
310310
if (this.settings.sortable) {
311311
const axis = this.getComponentSortAxis();
312312
actions.push({
313-
icon:
314-
axis === 'y'
315-
? 'arrow-up'
316-
: Craft.orientation === 'ltr'
317-
? 'arrow-left'
318-
: 'arrow-right',
313+
icon: async () =>
314+
await Craft.ui.icon(
315+
axis === 'y'
316+
? 'arrow-up'
317+
: Craft.orientation === 'ltr'
318+
? 'arrow-left'
319+
: 'arrow-right'
320+
),
319321
label:
320322
axis === 'y'
321323
? Craft.t('app', 'Move up')
@@ -328,12 +330,14 @@ Craft.ComponentSelectInput = Garnish.Base.extend(
328330
},
329331
});
330332
actions.push({
331-
icon:
332-
axis === 'y'
333-
? 'arrow-down'
334-
: Craft.orientation === 'ltr'
335-
? 'arrow-right'
336-
: 'arrow-left',
333+
icon: async () =>
334+
await Craft.ui.icon(
335+
axis === 'y'
336+
? 'arrow-down'
337+
: Craft.orientation === 'ltr'
338+
? 'arrow-right'
339+
: 'arrow-left'
340+
),
337341
label:
338342
axis === 'y'
339343
? Craft.t('app', 'Move down')
@@ -348,7 +352,7 @@ Craft.ComponentSelectInput = Garnish.Base.extend(
348352
}
349353

350354
actions.push({
351-
icon: 'remove',
355+
icon: async () => await Craft.ui.icon('remove'),
352356
label: Craft.t('app', 'Remove'),
353357
callback: () => {
354358
this.removeComponent($component);

src/web/assets/cp/src/js/EditableTable.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,12 +652,12 @@ Craft.EditableTable = Garnish.Base.extend(
652652

653653
menu.addItems([
654654
{
655-
icon: 'arrow-up',
655+
icon: async () => await Craft.ui.icon('arrow-up'),
656656
label: Craft.t('app', 'Move up'),
657657
attributes: {'data-action': 'moveUp'},
658658
},
659659
{
660-
icon: 'arrow-down',
660+
icon: async () => await Craft.ui.icon('arrow-down'),
661661
label: Craft.t('app', 'Move down'),
662662
attributes: {'data-action': 'moveDown'},
663663
},

src/web/assets/cp/src/js/ElementEditor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ Craft.ElementEditor = Garnish.Base.extend(
953953
const button = menu.addItem(
954954
{
955955
type: 'button',
956-
icon: 'edit',
956+
icon: async () => await Craft.ui.icon('edit'),
957957
label: Craft.t('app', 'Edit draft settings'),
958958
},
959959
group

src/web/assets/cp/src/js/EntryTypeSelectInput.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Craft.EntryTypeSelectInput = Craft.ComponentSelectInput.extend(
2929
$component,
3030
[
3131
{
32-
icon: 'gear',
32+
icon: async () => await Craft.ui.icon('gear'),
3333
label: Craft.t('app', 'Settings'),
3434
callback: () => {
3535
this.createSettings($component);

src/web/assets/cp/src/js/FieldLayoutDesigner.js

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ Craft.FieldLayoutDesigner.Tab = Garnish.Base.extend({
522522
disclosureMenu.addItem(
523523
{
524524
label: Craft.t('app', 'Settings'),
525-
icon: 'gear',
525+
icon: async () => await Craft.ui.icon('gear'),
526526
onActivate: () => {
527527
this.createSettings();
528528
},
@@ -537,7 +537,10 @@ Craft.FieldLayoutDesigner.Tab = Garnish.Base.extend({
537537
Craft.orientation === 'ltr'
538538
? Craft.t('app', 'Move to the left')
539539
: Craft.t('app', 'Move to the right'),
540-
icon: Craft.orientation === 'ltr' ? 'arrow-left' : 'arrow-right',
540+
icon: async () =>
541+
await Craft.ui.icon(
542+
Craft.orientation === 'ltr' ? 'arrow-left' : 'arrow-right'
543+
),
541544
onActivate: () => {
542545
this.moveLeft();
543546
},
@@ -551,7 +554,10 @@ Craft.FieldLayoutDesigner.Tab = Garnish.Base.extend({
551554
Craft.orientation === 'ltr'
552555
? Craft.t('app', 'Move to the right')
553556
: Craft.t('app', 'Move to the left'),
554-
icon: Craft.orientation === 'ltr' ? 'arrow-right' : 'arrow-left',
557+
icon: async () =>
558+
await Craft.ui.icon(
559+
Craft.orientation === 'ltr' ? 'arrow-right' : 'arrow-left'
560+
),
555561
onActivate: () => {
556562
this.moveRight();
557563
},
@@ -562,7 +568,7 @@ Craft.FieldLayoutDesigner.Tab = Garnish.Base.extend({
562568
disclosureMenu.addItem(
563569
{
564570
label: Craft.t('app', 'Remove'),
565-
icon: 'xmark',
571+
icon: async () => await Craft.ui.icon('xmark'),
566572
destructive: true,
567573
onActivate: () => {
568574
this.destroy();
@@ -915,7 +921,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
915921
if (this.hasSettings && !this.tab.designer.settings.readOnly) {
916922
disclosureMenu.addItem({
917923
label: Craft.t('app', 'Settings'),
918-
icon: 'gear',
924+
icon: async () => await Craft.ui.icon('gear'),
919925
onActivate: () => {
920926
this.createSettings();
921927
},
@@ -933,7 +939,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
933939
makeRequiredBtn = disclosureMenu.addItem(
934940
{
935941
label: Craft.t('app', 'Make required'),
936-
icon: 'asterisk',
942+
icon: async () => await Craft.ui.icon('asterisk'),
937943
iconColor: 'rose',
938944
onActivate: () => {
939945
this.makeRequired();
@@ -945,7 +951,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
945951
dropRequiredBtn = disclosureMenu.addItem(
946952
{
947953
label: Craft.t('app', 'Make optional'),
948-
icon: 'asterisk-slash',
954+
icon: async () => await Craft.ui.icon('asterisk-slash'),
949955
iconColor: 'gray',
950956
onActivate: () => {
951957
this.dropRequired();
@@ -959,7 +965,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
959965
makeThumbnailBtn = disclosureMenu.addItem(
960966
{
961967
label: Craft.t('app', 'Use for element thumbnails'),
962-
icon: 'image',
968+
icon: async () => await Craft.ui.icon('image'),
963969
iconColor: 'violet',
964970
onActivate: () => {
965971
this.makeThumbnail();
@@ -970,7 +976,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
970976
dropThumbnailBtn = disclosureMenu.addItem(
971977
{
972978
label: Craft.t('app', 'Don’t use for element thumbnails'),
973-
icon: 'image-slash',
979+
icon: async () => await Craft.ui.icon('image-slash'),
974980
iconColor: 'gray',
975981
onActivate: () => {
976982
this.dropThumbnail();
@@ -985,7 +991,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
985991
const moveUpBtn = disclosureMenu.addItem(
986992
{
987993
label: Craft.t('app', 'Move up'),
988-
icon: 'arrow-up',
994+
icon: async () => await Craft.ui.icon('arrow-up'),
989995
onActivate: () => {
990996
this.moveUp();
991997
},
@@ -995,7 +1001,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
9951001
const moveDownBtn = disclosureMenu.addItem(
9961002
{
9971003
label: Craft.t('app', 'Move down'),
998-
icon: 'arrow-down',
1004+
icon: async () => await Craft.ui.icon('arrow-down'),
9991005
onActivate: () => {
10001006
this.moveDown();
10011007
},
@@ -1007,7 +1013,7 @@ Craft.FieldLayoutDesigner.Element = Garnish.Base.extend({
10071013
disclosureMenu.addItem(
10081014
{
10091015
label: Craft.t('app', 'Remove'),
1010-
icon: 'xmark',
1016+
icon: async () => await Craft.ui.icon('xmark'),
10111017
destructive: true,
10121018
onActivate: () => {
10131019
this.destroy();

0 commit comments

Comments
 (0)