@weni/unnnic-system 2.13.0 → 2.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +56 -19
  3. package/dist/style.css +1 -1
  4. package/dist/unnnic.mjs +4546 -4471
  5. package/dist/unnnic.umd.js +19 -19
  6. package/package.json +1 -1
  7. package/src/components/Alert/Alert.vue +2 -0
  8. package/src/components/Alert/AlertBanner.vue +2 -0
  9. package/src/components/Alert/Version1dot1.vue +1 -0
  10. package/src/components/Alert/__tests__/Alert.spec.js +84 -0
  11. package/src/components/Alert/__tests__/AlertBanner.spec.js +89 -0
  12. package/src/components/Alert/__tests__/AlertCaller.spec.js +98 -0
  13. package/src/components/Alert/__tests__/Version1dot1.spec.js +124 -0
  14. package/src/components/AudioRecorder/AudioRecorder.vue +30 -1
  15. package/src/components/AvatarIcon/__tests__/AvatarIcon.spec.js +84 -0
  16. package/src/components/AvatarIcon/__tests__/__snapshots__/AvatarIcon.spec.js.snap +7 -0
  17. package/src/components/Breadcrumb/Breadcrumb.vue +4 -0
  18. package/src/components/Breadcrumb/__tests__/Breadcrumb.spec.js +68 -0
  19. package/src/components/FormElement/FormElement.vue +101 -28
  20. package/src/components/Input/BaseInput.vue +30 -38
  21. package/src/components/Input/Input.scss +43 -0
  22. package/src/components/Input/TextInput.vue +24 -25
  23. package/src/components/Input/__test__/TextInput.spec.js +2 -2
  24. package/src/components/Input/__test__/__snapshots__/Input.spec.js.snap +1 -1
  25. package/src/components/Input/__test__/__snapshots__/TextInput.spec.js.snap +1 -1
  26. package/src/components/Pagination/Pagination.vue +23 -4
  27. package/src/components/Pagination/__tests__/Pagination.spec.js +208 -0
  28. package/src/components/SelectSmart/SelectSmart.vue +16 -44
  29. package/src/components/SelectSmart/SelectSmartMultipleHeader.vue +5 -13
  30. package/src/components/SelectSmart/SelectSmartOption.vue +13 -9
  31. package/src/components/SkeletonLoading/SkeletonLoading.vue +17 -11
  32. package/src/components/SkeletonLoading/__tests__/SkeletonLoading.spec.js +125 -0
  33. package/src/components/TextArea/TextArea.vue +45 -128
  34. package/src/components/TextArea/__test__/TextArea.spec.js +26 -24
  35. package/src/components/TextArea/__test__/__snapshots__/TextArea.spec.js.snap +4 -4
  36. package/src/stories/Input.mdx +76 -0
  37. package/src/stories/Input.stories.js +82 -8
  38. package/src/stories/SelectSmart.mdx +15 -17
  39. package/src/stories/SelectSmart.stories.js +72 -6
  40. package/src/stories/TextArea.mdx +68 -0
  41. package/src/stories/TextArea.stories.js +68 -6
@@ -0,0 +1,208 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { beforeEach, describe, expect, it } from 'vitest';
3
+ import Pagination from '../Pagination.vue';
4
+
5
+ function setup(props) {
6
+ return mount(Pagination, { props });
7
+ }
8
+
9
+ describe('Pagination', () => {
10
+ describe('when pagination is not disabled', () => {
11
+ let wrapper;
12
+
13
+ describe('when the user is on the first page', () => {
14
+ beforeEach(() => {
15
+ wrapper = setup({
16
+ modelValue: 1,
17
+ max: 10,
18
+ disabled: false,
19
+ });
20
+ });
21
+
22
+ it('should show 1, 2, 3, ..., 10 page buttons', () => {
23
+ const texts = wrapper
24
+ .findAll('[data-test="page-button"]')
25
+ .map((element) => element.text());
26
+
27
+ ['1', '2', '3', '...', '10'].forEach((value, index) => {
28
+ expect(texts[index]).contains(value);
29
+ });
30
+ });
31
+
32
+ it('the previous button should be disabled', () => {
33
+ expect(
34
+ wrapper.find('[data-test="previous-button"]').isDisabled(),
35
+ ).toBeTruthy();
36
+ });
37
+
38
+ describe('when the user clicks on the next button', () => {
39
+ beforeEach(() => {
40
+ wrapper.find('[data-test="next-button"]').trigger('click');
41
+ });
42
+
43
+ it('emits @update:model-value with page number 2', () => {
44
+ expect(wrapper.emitted('update:model-value')).toHaveLength(1);
45
+ expect(wrapper.emitted('update:model-value')).toContainEqual([2]);
46
+ });
47
+ });
48
+
49
+ describe('when the user clicks on the right ellipsis button', () => {
50
+ beforeEach(() => {
51
+ wrapper.findAll('[data-test="page-button"]').at(-2).trigger('click');
52
+ });
53
+
54
+ it('emits @update:model-value with page number 4', () => {
55
+ expect(wrapper.emitted('update:model-value')).toHaveLength(1);
56
+ expect(wrapper.emitted('update:model-value')).toContainEqual([4]);
57
+ });
58
+ });
59
+ });
60
+
61
+ describe('when the user is on the second page', () => {
62
+ beforeEach(() => {
63
+ wrapper = setup({
64
+ modelValue: 2,
65
+ max: 10,
66
+ disabled: false,
67
+ });
68
+ });
69
+
70
+ it('should show 1, 2, 3, ..., 10 page buttons', () => {
71
+ const texts = wrapper
72
+ .findAll('[data-test="page-button"]')
73
+ .map((element) => element.text());
74
+
75
+ ['1', '2', '3', '...', '10'].forEach((value, index) => {
76
+ expect(texts[index]).contains(value);
77
+ });
78
+ });
79
+
80
+ describe('when the user clicks on the previous button', () => {
81
+ beforeEach(() => {
82
+ wrapper.find('[data-test="previous-button"]').trigger('click');
83
+ });
84
+
85
+ it('emits @update:model-value with page number 1', () => {
86
+ expect(wrapper.emitted('update:model-value')).toHaveLength(1);
87
+ expect(wrapper.emitted('update:model-value')).toContainEqual([1]);
88
+ });
89
+ });
90
+ });
91
+
92
+ describe('when the user is on the last page', () => {
93
+ beforeEach(() => {
94
+ wrapper = setup({
95
+ modelValue: 11,
96
+ max: 10,
97
+ disabled: false,
98
+ });
99
+ });
100
+
101
+ it('the next button should be disabled', () => {
102
+ expect(
103
+ wrapper.find('[data-test="next-button"]').isDisabled(),
104
+ ).toBeTruthy();
105
+ });
106
+ });
107
+
108
+ describe('when the user is on the 9th page', () => {
109
+ beforeEach(() => {
110
+ wrapper = setup({
111
+ modelValue: 9,
112
+ max: 10,
113
+ disabled: false,
114
+ });
115
+ });
116
+
117
+ it('should show 1, ..., 8, 9, 10 page buttons', () => {
118
+ const texts = wrapper
119
+ .findAll('[data-test="page-button"]')
120
+ .map((element) => element.text());
121
+
122
+ ['1', '...', '8', '9', '10'].forEach((value, index) => {
123
+ expect(texts[index]).contains(value);
124
+ });
125
+ });
126
+
127
+ describe('when the user clicks on the left ellipsis button', () => {
128
+ beforeEach(() => {
129
+ wrapper.findAll('[data-test="page-button"]').at(1).trigger('click');
130
+ });
131
+
132
+ it('emits @update:model-value with page number 7', () => {
133
+ expect(wrapper.emitted('update:model-value')).toHaveLength(1);
134
+ expect(wrapper.emitted('update:model-value')).toContainEqual([7]);
135
+ });
136
+ });
137
+ });
138
+
139
+ describe('when the user is on the 4rd page', () => {
140
+ beforeEach(() => {
141
+ wrapper = setup({
142
+ modelValue: 4,
143
+ max: 10,
144
+ disabled: false,
145
+ });
146
+ });
147
+
148
+ it('should show 1, ..., 4 ..., 10 page buttons', () => {
149
+ const texts = wrapper
150
+ .findAll('[data-test="page-button"]')
151
+ .map((element) => element.text());
152
+
153
+ ['1', '...', '4', '...', '10'].forEach((value, index) => {
154
+ expect(texts[index]).contains(value);
155
+ });
156
+ });
157
+
158
+ describe('when the user clicks on the right ellipsis button', () => {
159
+ beforeEach(() => {
160
+ wrapper.findAll('[data-test="page-button"]').at(-2).trigger('click');
161
+ });
162
+
163
+ it('emits @update:model-value with page number 5', () => {
164
+ expect(wrapper.emitted('update:model-value')).toHaveLength(1);
165
+ expect(wrapper.emitted('update:model-value')).toContainEqual([5]);
166
+ });
167
+ });
168
+ });
169
+
170
+ describe('when the user is on the 3rd page', () => {
171
+ beforeEach(() => {
172
+ wrapper = setup({
173
+ modelValue: 3,
174
+ max: 10,
175
+ disabled: false,
176
+ });
177
+ });
178
+
179
+ describe('when the user wants clicks on the next page button', () => {
180
+ it('emits @update:model-value with page number 4', () => {
181
+ wrapper.find('[data-test="next-button"]').trigger('click');
182
+
183
+ expect(wrapper.emitted('update:model-value')).toHaveLength(1);
184
+ expect(wrapper.emitted('update:model-value')).toContainEqual([4]);
185
+ });
186
+ });
187
+ });
188
+
189
+ describe('when the user is on the 7th page', () => {
190
+ beforeEach(() => {
191
+ wrapper = setup({
192
+ modelValue: 9,
193
+ max: 10,
194
+ disabled: false,
195
+ });
196
+ });
197
+
198
+ describe('when the user wants clicks on the previous page button', () => {
199
+ it('emits @update:model-value with page number 8', () => {
200
+ wrapper.find('[data-test="previous-button"]').trigger('click');
201
+
202
+ expect(wrapper.emitted('update:model-value')).toHaveLength(1);
203
+ expect(wrapper.emitted('update:model-value')).toContainEqual([8]);
204
+ });
205
+ });
206
+ });
207
+ });
208
+ });
@@ -22,9 +22,8 @@
22
22
  :iconLeft="
23
23
  isAutocompleteAllowed && autocompleteIconLeft ? 'search-1' : ''
24
24
  "
25
- :iconRight="active ? 'arrow-button-up-1' : 'arrow-button-down-1'"
26
- :iconRightClickable="!disabled"
27
- @icon-right-click="handleClickInput"
25
+ :iconRight="active ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
26
+ iconRightSize="ant"
28
27
  @click.stop="handleClickInput"
29
28
  @update:model-value="searchValue = $event"
30
29
  />
@@ -46,7 +45,6 @@
46
45
  :withoutSelectsMessage="multipleWithoutSelectsMessage"
47
46
  :locale="locale"
48
47
  :translations="translations"
49
- @clear-selected-options="clearSelectedOptions"
50
48
  @unselect-option="unselectOption"
51
49
  />
52
50
  <div
@@ -56,6 +54,7 @@
56
54
  `size-${size}`,
57
55
  {
58
56
  'with-descriptions': hasDescriptionOptions,
57
+ 'with-checkboxes': !!multiple,
59
58
  },
60
59
  ]"
61
60
  >
@@ -329,10 +328,6 @@ export default {
329
328
  );
330
329
  },
331
330
 
332
- clearSelectedOptions() {
333
- this.$emit('update:modelValue', []);
334
- },
335
-
336
331
  handleSelect(option) {
337
332
  if (option) {
338
333
  if (this.multiple && this.optionIsSelected(option)) {
@@ -559,7 +554,7 @@ export default {
559
554
  left: 0;
560
555
  right: 0;
561
556
 
562
- margin-top: 2px;
557
+ margin-top: $unnnic-spacing-nano;
563
558
 
564
559
  border-radius: $unnnic-border-radius-sm;
565
560
 
@@ -578,7 +573,7 @@ export default {
578
573
  margin-right: $unnnic-inline-xs;
579
574
  padding-right: $unnnic-inline-xs;
580
575
 
581
- max-height: calc-max-height(8.5);
576
+ max-height: calc-max-height(9.25);
582
577
 
583
578
  overflow-y: auto;
584
579
 
@@ -597,14 +592,22 @@ export default {
597
592
  }
598
593
 
599
594
  &.with-descriptions {
600
- max-height: calc-max-height(13.5);
595
+ max-height: calc-max-height(14.25);
596
+ }
597
+
598
+ &.with-checkboxes {
599
+ max-height: calc-max-height(11.75);
601
600
  }
602
601
 
603
602
  &.size-sm {
604
- max-height: calc-max-height(8);
603
+ max-height: calc-max-height(8.75);
605
604
 
606
605
  &.with-descriptions {
607
- max-height: calc-max-height(12);
606
+ max-height: calc-max-height(13.75);
607
+ }
608
+
609
+ &.with-checkboxes {
610
+ max-height: calc-max-height(10.75);
608
611
  }
609
612
  }
610
613
  }
@@ -632,43 +635,12 @@ export default {
632
635
  .unnnic-select-smart__input input {
633
636
  // entire class name to have higher priority in styles
634
637
 
635
- color: $unnnic-color-neutral-dark;
636
-
637
638
  &:read-only {
638
639
  cursor: pointer;
639
-
640
- &::placeholder {
641
- color: $unnnic-color-neutral-cloudy;
642
- }
643
- }
644
-
645
- &:not(:read-only :focus) {
646
- &::placeholder {
647
- color: $unnnic-color-neutral-cloudy;
648
- }
649
- }
650
-
651
- &:not(:read-only) {
652
- &:focus {
653
- &::placeholder {
654
- color: $unnnic-color-neutral-cleanest;
655
- }
656
- }
657
640
  }
658
641
 
659
642
  &:disabled {
660
- box-shadow: inset 0 0 0 $unnnic-border-width-thinner
661
- $unnnic-color-neutral-cleanest;
662
-
663
643
  cursor: not-allowed;
664
-
665
- &::placeholder {
666
- color: $unnnic-color-neutral-cleanest;
667
- }
668
-
669
- + .icon-right {
670
- cursor: not-allowed;
671
- }
672
644
  }
673
645
  }
674
646
  }
@@ -20,13 +20,6 @@
20
20
  +{{ selectedOptions.length - multipleSelectedsTags }}
21
21
  </p>
22
22
  </div>
23
- <UnnnicIcon
24
- class="unnnic-select-smart__options__multiple__selecteds__clear"
25
- icon="close-1"
26
- size="xs"
27
- clickable
28
- @click="clearSelectedOptions"
29
- />
30
23
  </div>
31
24
  <p
32
25
  v-if="!selectedOptions[0]"
@@ -39,14 +32,12 @@
39
32
 
40
33
  <script>
41
34
  import Tag from '../Tag/Tag.vue';
42
- import UnnnicIcon from '../Icon.vue';
43
35
  import UnnnicI18n from '../../mixins/i18n';
44
36
 
45
37
  export default {
46
38
  name: 'UnnnicSelectSmartMultipleHeader',
47
39
  components: {
48
40
  Tag,
49
- UnnnicIcon,
50
41
  },
51
42
  mixins: [UnnnicI18n],
52
43
  props: {
@@ -85,9 +76,6 @@ export default {
85
76
  },
86
77
  },
87
78
  methods: {
88
- clearSelectedOptions() {
89
- this.$emit('clear-selected-options');
90
- },
91
79
  unselectOption(option) {
92
80
  this.$emit('unselect-option', option);
93
81
  },
@@ -117,6 +105,10 @@ export default {
117
105
  margin: $unnnic-spacing-xs;
118
106
  margin-right: 0;
119
107
 
108
+ &:first-child {
109
+ margin-left: $unnnic-spacing-sm;
110
+ }
111
+
120
112
  &.unnnic-tag {
121
113
  outline-color: $unnnic-color-neutral-light;
122
114
  background-color: $unnnic-color-neutral-light;
@@ -144,7 +136,7 @@ export default {
144
136
  line-height: $unnnic-font-size-body-md + $unnnic-line-height-medium;
145
137
  font-size: $unnnic-font-size-body-md;
146
138
 
147
- padding: $unnnic-spacing-ant;
139
+ padding: $unnnic-spacing-ant $unnnic-spacing-sm;
148
140
  }
149
141
  }
150
142
  </style>
@@ -74,6 +74,7 @@ export default {
74
74
  type: Boolean,
75
75
  default: false,
76
76
  },
77
+ isMultiple: Boolean,
77
78
  },
78
79
  };
79
80
  </script>
@@ -87,7 +88,7 @@ export default {
87
88
  max-width: 100%;
88
89
 
89
90
  font-family: $unnnic-font-family-secondary;
90
- color: $unnnic-color-neutral-dark;
91
+ color: $unnnic-color-neutral-darkest;
91
92
  font-weight: $unnnic-font-weight-regular;
92
93
 
93
94
  white-space: nowrap;
@@ -95,9 +96,12 @@ export default {
95
96
  overflow: hidden;
96
97
  -webkit-line-clamp: 1;
97
98
 
99
+ & + & {
100
+ margin-top: $unnnic-spacing-nano;
101
+ }
102
+
98
103
  &--selectable:hover,
99
- &--focused,
100
- &--active {
104
+ &--focused {
101
105
  border-radius: $unnnic-border-radius-sm;
102
106
 
103
107
  background-color: $unnnic-color-neutral-light;
@@ -109,6 +113,7 @@ export default {
109
113
  }
110
114
 
111
115
  &--with-checkbox {
116
+ padding: $unnnic-spacing-xs $unnnic-spacing-ant;
112
117
  display: flex;
113
118
  align-items: center;
114
119
  gap: $unnnic-spacing-xs;
@@ -119,13 +124,15 @@ export default {
119
124
  }
120
125
 
121
126
  &__label {
127
+ display: block;
128
+
122
129
  &--md {
123
130
  font-size: $unnnic-font-size-body-gt;
124
131
  line-height: $unnnic-font-size-body-gt + $unnnic-line-height-medium;
125
132
  }
126
133
  &--sm {
127
134
  font-size: $unnnic-font-size-body-md;
128
- line-height: $unnnic-font-size-body-md + $unnnic-line-height-small;
135
+ line-height: $unnnic-font-size-body-md + $unnnic-line-height-md;
129
136
  }
130
137
  }
131
138
 
@@ -135,14 +142,11 @@ export default {
135
142
  color: $unnnic-color-neutral-cloudy;
136
143
  font-weight: $unnnic-font-weight-regular;
137
144
 
138
- &--md {
145
+ &--md,
146
+ &--sm {
139
147
  font-size: $unnnic-font-size-body-md;
140
148
  line-height: $unnnic-font-size-body-md + $unnnic-line-height-medium;
141
149
  }
142
- &--sm {
143
- font-size: $unnnic-font-size-body-sm;
144
- line-height: $unnnic-font-size-body-md + $unnnic-line-height-small;
145
- }
146
150
  }
147
151
  }
148
152
  </style>
@@ -1,7 +1,14 @@
1
1
  <template>
2
2
  <component
3
3
  :is="tag"
4
- v-if="showLoading"
4
+ v-if="direct"
5
+ :class="classes"
6
+ :style="styles"
7
+ ></component>
8
+
9
+ <component
10
+ :is="tag"
11
+ v-else-if="showLoading"
5
12
  >
6
13
  <span
7
14
  v-for="(element, index) in elements"
@@ -47,6 +54,9 @@ export default {
47
54
  type: Boolean,
48
55
  default: undefined,
49
56
  },
57
+ direct: {
58
+ type: Boolean,
59
+ },
50
60
  },
51
61
  setup() {
52
62
  const themeStyle = inject('_themeStyle', ref(SkeletonStyle));
@@ -58,11 +68,6 @@ export default {
58
68
  };
59
69
  },
60
70
  computed: {
61
- isLoading() {
62
- return typeof this.theme.loading !== 'undefined'
63
- ? this.theme.loading
64
- : this.loading;
65
- },
66
71
  classes() {
67
72
  return [`${this.prefix}-skeleton`];
68
73
  },
@@ -86,21 +91,22 @@ export default {
86
91
  return elements;
87
92
  },
88
93
  showLoading() {
89
- return typeof this.isLoading !== 'undefined'
90
- ? this.isLoading
94
+ return typeof this.loading !== 'undefined'
95
+ ? this.loading
91
96
  : this.isEmptyVNode(this.$slots.default);
92
97
  },
93
98
  },
94
99
  methods: {
95
100
  isEmptyVNode(children) {
96
101
  if (!children) return true;
97
- const [firstNode] = children;
98
- let str = firstNode.text;
102
+ const [firstNode] = children();
103
+ let str = firstNode.children;
104
+
99
105
  if (str) {
100
106
  // remove all line-break and space character
101
107
  str = str.replace(/(\n|\r\n|\s)/g, '');
102
108
  }
103
- return typeof firstNode.tag === 'undefined' && !str;
109
+ return !str;
104
110
  },
105
111
  },
106
112
  };
@@ -0,0 +1,125 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { beforeEach, describe, expect, it } from 'vitest';
3
+ import SkeletonLoading from '../SkeletonLoading.vue';
4
+
5
+ function setup(options) {
6
+ return mount(SkeletonLoading, options);
7
+ }
8
+
9
+ describe('SkeletonLoading', () => {
10
+ let wrapper;
11
+
12
+ describe('when the skeleton loading is a circle', () => {
13
+ beforeEach(() => {
14
+ wrapper = setup({
15
+ props: {
16
+ count: 1,
17
+ duration: 1.5,
18
+ tag: 'span',
19
+ width: '100px',
20
+ height: '100px',
21
+ circle: true,
22
+ loading: undefined,
23
+ direct: false,
24
+ },
25
+ });
26
+ });
27
+
28
+ it('should have borderRadius', () => {
29
+ expect(wrapper.vm.styles.borderRadius).toBe('50%');
30
+ });
31
+ });
32
+
33
+ describe('when the skeleton loading has not a duration', () => {
34
+ beforeEach(() => {
35
+ wrapper = setup({
36
+ props: {
37
+ count: 1,
38
+ duration: 0,
39
+ tag: 'span',
40
+ width: '100px',
41
+ height: '100px',
42
+ circle: false,
43
+ loading: undefined,
44
+ direct: false,
45
+ },
46
+ });
47
+ });
48
+
49
+ it('should not have the gradient background', () => {
50
+ expect(wrapper.vm.styles.backgroundImage).toBe('');
51
+ });
52
+ });
53
+
54
+ describe('when the default slot is provided and loading is undefined', () => {
55
+ beforeEach(() => {
56
+ wrapper = setup({
57
+ props: {
58
+ count: 1,
59
+ duration: 0,
60
+ tag: 'span',
61
+ width: '100px',
62
+ height: '100px',
63
+ circle: false,
64
+ loading: undefined,
65
+ direct: false,
66
+ },
67
+ slots: { default: 'Default slot' },
68
+ });
69
+ });
70
+
71
+ it('should not show the skeleton loading', () => {
72
+ expect(wrapper.html()).toBe('<!--v-if-->');
73
+ });
74
+ });
75
+
76
+ describe('when the loading prop is provided', () => {
77
+ beforeEach(() => {
78
+ wrapper = setup({
79
+ props: {
80
+ count: 1,
81
+ duration: 0,
82
+ tag: 'span',
83
+ width: '100px',
84
+ height: '100px',
85
+ circle: false,
86
+ loading: true,
87
+ direct: false,
88
+ },
89
+ });
90
+ });
91
+
92
+ it('showLoading should be as same as the loading prop', async () => {
93
+ expect(wrapper.vm.showLoading).toBeTruthy();
94
+
95
+ await wrapper.setProps({
96
+ loading: false,
97
+ });
98
+
99
+ expect(wrapper.vm.showLoading).toBeFalsy();
100
+ });
101
+ });
102
+
103
+ describe('when the direct', () => {
104
+ beforeEach(() => {
105
+ wrapper = setup({
106
+ props: {
107
+ count: 1,
108
+ duration: 0,
109
+ tag: 'span',
110
+ width: '100px',
111
+ height: '100px',
112
+ circle: false,
113
+ loading: true,
114
+ direct: true,
115
+ },
116
+ });
117
+ });
118
+
119
+ it('renders the skeleton loading directly on the component', async () => {
120
+ expect(wrapper.html()).toBe(
121
+ '<span class="unnnic-skeleton" style="background-color: rgb(232, 244, 244); width: 100px; height: 100px;"></span>',
122
+ );
123
+ });
124
+ });
125
+ });