@weni/unnnic-system 1.16.37 → 1.16.39-develop.0

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.
@@ -0,0 +1,122 @@
1
+ <template>
2
+ <span
3
+ class="user-avatar"
4
+ :class="{
5
+ active,
6
+ clickable,
7
+ disabled,
8
+ [`user-avatar--${size}`]: true,
9
+ }"
10
+ @click="$emit('click')"
11
+ @keypress.enter="$emit('click')"
12
+ >
13
+ <unnnic-icon
14
+ v-if="username === 'Agent'"
15
+ icon="single-neutral-actions-1"
16
+ size="sm"
17
+ :scheme="disabled ? 'neutral-snow' : ''"
18
+ />
19
+ <unnnic-icon
20
+ v-else-if="username === 'Bot'"
21
+ icon="science-fiction-robot-2"
22
+ size="sm"
23
+ :scheme="disabled ? 'neutral-snow' : ''"
24
+ />
25
+ <img v-else-if="!!photoUrl" :src="photoUrl" alt="" />
26
+ <span v-else>
27
+ {{ getUsernameFirstCharacter }}
28
+ </span>
29
+ </span>
30
+ </template>
31
+
32
+ <script>
33
+ import UnnnicIcon from '../Icon.vue';
34
+
35
+ export default {
36
+ name: 'UserAvatar',
37
+ components: {
38
+ UnnnicIcon,
39
+ },
40
+ props: {
41
+ active: {
42
+ type: Boolean,
43
+ default: false,
44
+ },
45
+ clickable: {
46
+ type: Boolean,
47
+ default: false,
48
+ },
49
+ disabled: {
50
+ type: Boolean,
51
+ default: false,
52
+ },
53
+ size: {
54
+ type: String,
55
+ default: 'xl',
56
+ validator: (value) => ['xs', 'sm', 'ant', 'md', 'lg', 'xl', '2xl'].indexOf(value) !== -1,
57
+ },
58
+ username: {
59
+ type: String,
60
+ required: true,
61
+ },
62
+ photoUrl: {
63
+ type: String,
64
+ default: '',
65
+ },
66
+ },
67
+
68
+ computed: {
69
+ getUsernameFirstCharacter() {
70
+ return this.username ? this.username.charAt(0).toUpperCase() : '';
71
+ },
72
+ },
73
+ };
74
+ </script>
75
+
76
+ <style lang="scss" scoped>
77
+ @import '../../assets/scss/unnnic.scss';
78
+
79
+ $avatar-sizes: '2xl' 3rem, 'xl' $unnnic-icon-size-xl, 'lg' $unnnic-icon-size-lg,
80
+ 'md' $unnnic-icon-size-md, 'ant' $unnnic-icon-size-ant, 'sm' $unnnic-icon-size-sm,
81
+ 'xs' $unnnic-icon-size-xs;
82
+
83
+ .user-avatar {
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ border-radius: $unnnic-border-radius-sm;
88
+
89
+ background: $unnnic-color-weni-50;
90
+ color: $unnnic-color-aux-purple-500;
91
+
92
+ &.active {
93
+ background: $unnnic-color-weni-100;
94
+ }
95
+
96
+ &.disabled {
97
+ background: $unnnic-color-neutral-cleanest;
98
+ color: $unnnic-color-neutral-snow;
99
+ }
100
+
101
+ &.clickable {
102
+ cursor: pointer;
103
+ }
104
+
105
+ @each $name, $size in $avatar-sizes {
106
+ &--#{$name} {
107
+ width: $size;
108
+ height: $size;
109
+
110
+ font-size: calc($size / 2);
111
+ font-family: $unnnic-font-family-secondary;
112
+
113
+ overflow: hidden;
114
+
115
+ img {
116
+ width: 100%;
117
+ height: auto;
118
+ }
119
+ }
120
+ }
121
+ }
122
+ </style>
@@ -35,6 +35,8 @@
35
35
  :withoutSelectsMessage="multipleWithoutSelectsMessage"
36
36
  @clear-selected-options="clearSelectedOptions"
37
37
  @unselect-option="unselectOption"
38
+ :locale="locale"
39
+ :translations="translations"
38
40
  />
39
41
  <div
40
42
  ref="selectSmartOptionsScrollArea"
@@ -62,7 +64,7 @@
62
64
  v-if="filterOptions(options).length === 0"
63
65
  class="unnnic-select-smart__options--no-results"
64
66
  >
65
- {{ $t('select_smart.without_results') }}
67
+ {{ i18n('without_results') }}
66
68
  </p>
67
69
  </div>
68
70
  </div>
@@ -78,9 +80,11 @@ import SelectSmartOption from './SelectSmartOption.vue';
78
80
  import SelectSmartMultipleHeader from './SelectSmartMultipleHeader.vue';
79
81
  import TextInput from '../Input/TextInput.vue';
80
82
  import DropdownSkeleton from '../Dropdown/DropdownSkeleton.vue';
83
+ import UnnnicI18n from '../../mixins/i18n';
81
84
 
82
85
  export default {
83
86
  name: 'UnnnicSelectSmart',
87
+ mixins: [UnnnicI18n],
84
88
  components: {
85
89
  TextInput,
86
90
  SelectSmartOption,
@@ -103,7 +107,8 @@ export default {
103
107
  ],
104
108
  },
105
109
  value: {
106
- type: null,
110
+ type: Array,
111
+ default: () => [],
107
112
  },
108
113
  size: {
109
114
  type: String,
@@ -157,6 +162,14 @@ export default {
157
162
 
158
163
  selectedOptions: [],
159
164
  multipleSelectedsTags: 2,
165
+
166
+ defaultTranslations: {
167
+ without_results: {
168
+ 'pt-br': 'Nenhum resultado encontrado',
169
+ en: 'No results found',
170
+ es: 'Ningún resultado encontrado',
171
+ },
172
+ },
160
173
  };
161
174
  },
162
175
 
@@ -168,7 +181,15 @@ export default {
168
181
  this.isAutocompleteAllowed = true;
169
182
  }
170
183
 
171
- if (this.options[0].value) {
184
+ if (this.value[0] && this.value[0].value) {
185
+ this.value.forEach((option) => this.selectOption(option));
186
+
187
+ if (this.isAutocompleteAllowed) {
188
+ this.$nextTick(() => {
189
+ this.searchValue = this.selectedLabel;
190
+ });
191
+ }
192
+ } else if (this.options[0].value) {
172
193
  this.selectOption(this.options[0]);
173
194
  }
174
195
  },
@@ -188,10 +209,10 @@ export default {
188
209
  });
189
210
  },
190
211
 
191
- searchValue() {
212
+ searchValue(newSearchValue, oldSearchValue) {
192
213
  this.focusedOption = null;
193
214
 
194
- if (!this.active) this.active = true;
215
+ if (!this.active && oldSearchValue) this.active = true;
195
216
  },
196
217
 
197
218
  selectedOptions(newSelectedOptions) {
@@ -222,7 +243,7 @@ export default {
222
243
  return isValueMatch && option.value !== '';
223
244
  }
224
245
 
225
- const isEmptyOption = option.value === '' && this.value == null;
246
+ const isEmptyOption = option.value === '' && this.value.length === 0;
226
247
  return isEmptyOption || isValueMatch;
227
248
  });
228
249
 
@@ -391,7 +412,7 @@ export default {
391
412
 
392
413
  unselectOption(option) {
393
414
  const indexToRemove = this.selectedOptions.findIndex(
394
- (selectedOption) => selectedOption === option,
415
+ (selectedOption) => selectedOption.value === option.value,
395
416
  );
396
417
 
397
418
  if (indexToRemove !== -1) {
@@ -29,7 +29,7 @@
29
29
  />
30
30
  </div>
31
31
  <p v-if="!selectedOptions[0]" class="unnnic-select-smart__options__multiple--without-multiples">
32
- {{ withoutSelectsMessage || $t('select_smart.without_multiple_selected') }}
32
+ {{ withoutSelectsMessage || i18n('without_multiple_selected') }}
33
33
  </p>
34
34
  </div>
35
35
  </template>
@@ -37,9 +37,11 @@
37
37
  <script>
38
38
  import Tag from '../Tag/Tag.vue';
39
39
  import IconSvg from '../Icon.vue';
40
+ import UnnnicI18n from '../../mixins/i18n';
40
41
 
41
42
  export default {
42
43
  name: 'UnnnicSelectSmartMultipleHeader',
44
+ mixins: [UnnnicI18n],
43
45
  components: {
44
46
  Tag,
45
47
  IconSvg,
@@ -57,6 +59,14 @@ export default {
57
59
  data() {
58
60
  return {
59
61
  multipleSelectedsTags: 2,
62
+
63
+ defaultTranslations: {
64
+ without_multiple_selected: {
65
+ 'pt-br': 'Nenhuma opção selecionada',
66
+ en: 'No option selected',
67
+ es: 'Ninguna opción seleccionada',
68
+ },
69
+ },
60
70
  };
61
71
  },
62
72
  computed: {
@@ -0,0 +1,119 @@
1
+ <template>
2
+ <transition-group class="ripples" name="grow" tag="div">
3
+ <div
4
+ class="ripple"
5
+ v-for="ripple in ripples"
6
+ :key="ripple.id"
7
+ :style="{
8
+ top: ripple.top,
9
+ left: ripple.left,
10
+ width: ripple.width,
11
+ height: ripple.height,
12
+ }"
13
+ :class="`ripples-color--${color}`"
14
+ ></div>
15
+ </transition-group>
16
+ </template>
17
+
18
+ <script>
19
+ export default {
20
+ props: {
21
+ color: {
22
+ type: String,
23
+ default: 'neutral-white',
24
+ },
25
+ },
26
+ data() {
27
+ return {
28
+ ripples: [],
29
+ rippleWidth: 0,
30
+ halfRippleWidth: 0,
31
+ };
32
+ },
33
+ mounted() {
34
+ const { transitionContainer } = this.$parent.$refs;
35
+
36
+ if (transitionContainer) {
37
+ this.$parent.$refs.transitionContainer.style.position = 'relative';
38
+ this.$parent.$refs.transitionContainer.style.overflow = 'hidden';
39
+ }
40
+
41
+ const width = transitionContainer.offsetWidth;
42
+ const height = transitionContainer.offsetHeight;
43
+ this.rippleWidth = width > height ? width : height;
44
+ this.halfRippleWidth = this.rippleWidth / 2;
45
+
46
+ window.addEventListener('mouseup', this.purgeRipples);
47
+ },
48
+ beforeDestroy() {
49
+ window.removeEventListener('mouseup', this.purgeRipples);
50
+ },
51
+ methods: {
52
+ addRipple(e) {
53
+ const { left, top } = this.$parent.$refs.transitionContainer.getBoundingClientRect();
54
+ const rippleId = Date.now();
55
+ this.ripples.push({
56
+ width: `${this.rippleWidth}px`,
57
+ height: `${this.rippleWidth}px`,
58
+ left: `${e.clientX - left - this.halfRippleWidth}px`,
59
+ top: `${e.clientY - top - this.halfRippleWidth}px`,
60
+ id: rippleId,
61
+ });
62
+ },
63
+ purgeRipples() {
64
+ this.ripples = [];
65
+ },
66
+ },
67
+ };
68
+ </script>
69
+
70
+ <style scoped lang="scss">
71
+ @import '../../assets/scss/unnnic.scss';
72
+
73
+ .ripples {
74
+ position: absolute;
75
+ width: 100%;
76
+ height: 100%;
77
+ z-index: 1;
78
+
79
+ @each $name, $color in $scheme-colors {
80
+ &-color--#{$name} {
81
+ background-color: $color;
82
+ }
83
+ }
84
+ }
85
+
86
+ .ripple {
87
+ position: absolute;
88
+ border-radius: 50%;
89
+ transform: scale(0);
90
+ opacity: 0.05;
91
+ animation: grow 1s ease-out;
92
+ }
93
+
94
+ .grow-enter-active, .grow-enter-to-active {
95
+ transition: all 1.5s ease-out;
96
+ }
97
+ .grow-leave-active, .grow-leave-to-active {
98
+ transition: all 1s ease-out;
99
+ }
100
+
101
+ .grow-enter {
102
+ transform: scale(0);
103
+ opacity: 0.1;
104
+ }
105
+
106
+ .grow-enter-to {
107
+ transform: scale(4);
108
+ opacity: 0.1;
109
+ }
110
+
111
+ .grow-leave {
112
+ transform: scale(4);
113
+ opacity: 0.1;
114
+ }
115
+ .grow-leave-to {
116
+ transform: scale(4);
117
+ opacity: 0;
118
+ }
119
+ </style>
@@ -11,9 +11,5 @@
11
11
  },
12
12
  "import_card": {
13
13
  "importing": "Importing"
14
- },
15
- "select_smart": {
16
- "without_results": "No results found",
17
- "without_multiple_selected": "No option selected"
18
14
  }
19
15
  }
@@ -11,9 +11,5 @@
11
11
  },
12
12
  "import_card": {
13
13
  "importing": "Importando"
14
- },
15
- "select_smart": {
16
- "without_results": "Ningún resultado encontrado",
17
- "without_multiple_selected": "Ninguna opción seleccionada"
18
14
  }
19
15
  }
@@ -11,9 +11,5 @@
11
11
  },
12
12
  "import_card": {
13
13
  "importing": "Importando"
14
- },
15
- "select_smart": {
16
- "without_results": "Nenhum resultado encontrado",
17
- "without_multiple_selected": "Nenhuma opção selecionada"
18
14
  }
19
15
  }
@@ -0,0 +1,51 @@
1
+ import { get } from 'lodash';
2
+
3
+ export default {
4
+ props: {
5
+ locale: {
6
+ type: String,
7
+ },
8
+ translations: {
9
+ type: Object,
10
+ },
11
+ },
12
+
13
+ methods: {
14
+ i18n(...args) {
15
+ const [key, defaults] = args;
16
+
17
+ const locale = (this.locale || get(this, '$i18n.locale'))?.toLowerCase();
18
+
19
+ let text = get(this.translations, `${key}.${locale}`, get(this.translations, key));
20
+
21
+ if (!text) {
22
+ text = get(get(this.defaultTranslations, key), locale, defaults);
23
+ }
24
+
25
+ if (text?.includes('|') && typeof args[1] === 'number') {
26
+ const count = args[1];
27
+ const pluralization = text.split('|');
28
+
29
+ if (pluralization.length === 3) {
30
+ text = pluralization[count] || pluralization[2];
31
+ } else if (pluralization.length === 2) {
32
+ text = count === 1 ? pluralization[0] : pluralization[1];
33
+ }
34
+ }
35
+
36
+ let vars = {};
37
+
38
+ Object.values(args).slice(1).forEach((argument) => {
39
+ if (!(argument instanceof Array) && argument instanceof Object) {
40
+ vars = argument;
41
+ }
42
+ });
43
+
44
+ Object.keys(vars).forEach((varName) => {
45
+ text = text?.replaceAll(new RegExp(`{ *${varName} *}`, 'g'), vars[varName]);
46
+ });
47
+
48
+ return text;
49
+ },
50
+ },
51
+ };
@@ -41,7 +41,32 @@ export default {
41
41
  const Template = (args, { argTypes }) => ({
42
42
  props: Object.keys(argTypes),
43
43
  components: { alertCaller, unnnicAlert },
44
- template: '<div><button @click="unnnicCallAlert"> Click for alert </button> <unnnic-alert v-bind="$props"></unnnic-alert> </div>',
44
+ template: `
45
+ <div>
46
+ <button @click="unnnicCallAlert">Click for alert</button>
47
+
48
+ <h3>Refactoring changes:</h3>
49
+
50
+ <ul>
51
+ <li>Removed props: title, icon, hide-close-text, close-text, position</li>
52
+ <li>Added props: link-text, link-href, link-target (default: '_blank'), type (default, success, error)</li>
53
+ <li>Avoid using scheme prop, instead use the 'type' prop to change the color variant</li>
54
+ <li>Avoid using on-close prop to listen to close event, instead use the '@close' event</li>
55
+ </ul>
56
+
57
+ <pre>
58
+ Recommended use:
59
+
60
+ &lt;unnnic-alert
61
+ type String default 'default' ('default', 'success', 'error')
62
+ text String required
63
+ @close Event
64
+ link-href String
65
+ ┠ link-text String default 'Learn more'
66
+ ┖ link-target String default '_blank'
67
+ /&gt;
68
+ </pre>
69
+ </div>`,
45
70
  methods: {
46
71
  unnnicCallAlert() {
47
72
  alert.callAlert({ props: this.$props, seconds: this.$props.seconds });
@@ -0,0 +1,69 @@
1
+ import unnnicChatsContact from '../components/ChatsContact/ChatsContact.vue';
2
+
3
+ export default {
4
+ title: 'Chats/Contact',
5
+ component: unnnicChatsContact,
6
+ };
7
+
8
+ const Template = (args, { argTypes }) => ({
9
+ props: Object.keys(argTypes),
10
+ components: { unnnicChatsContact },
11
+ template: '<unnnic-chats-contact v-bind="$props"/>',
12
+ });
13
+
14
+ const TemplateList = (args, { argTypes }) => ({
15
+ props: Object.keys(argTypes),
16
+ components: { unnnicChatsContact },
17
+ data() {
18
+ return {
19
+ selectedContact: 1,
20
+ };
21
+ },
22
+ template: `
23
+ <div style="display: grid; gap: 5px;">
24
+ <unnnic-chats-contact v-for="index in 5" v-bind="$props" @click="selectedContact = index" :selected="selectedContact === index"/>
25
+ </div>
26
+ `,
27
+ });
28
+
29
+ const defaultArgs = {
30
+ username: 'John Doe',
31
+ lastMessage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas vel.',
32
+ };
33
+ const unreadMessages = 5;
34
+ const waitingTime = 10;
35
+
36
+ export const Default = Template.bind({});
37
+ Default.args = {
38
+ ...defaultArgs,
39
+ unreadMessages,
40
+ };
41
+
42
+ export const Selected = Template.bind({});
43
+ Selected.args = {
44
+ ...defaultArgs,
45
+ selected: true,
46
+ };
47
+
48
+ export const Read = Template.bind({});
49
+ Read.args = {
50
+ ...defaultArgs,
51
+ };
52
+
53
+ export const Waiting = Template.bind({});
54
+ Waiting.args = {
55
+ ...defaultArgs,
56
+ waitingTime,
57
+ unreadMessages,
58
+ };
59
+
60
+ export const WaitingRead = Template.bind({});
61
+ WaitingRead.args = {
62
+ ...defaultArgs,
63
+ waitingTime,
64
+ };
65
+
66
+ export const ContactList = TemplateList.bind({});
67
+ ContactList.args = {
68
+ ...defaultArgs,
69
+ };
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable no-alert */
2
- import unnnicNavbarChats from '../components/NavbarChats/NavbarChats.vue';
2
+ import unnnicChatsNavbar from '../components/ChatsNavbar/ChatsNavbar.vue';
3
3
 
4
4
  export default {
5
- title: 'Example/NavbarChats',
6
- component: unnnicNavbarChats,
5
+ title: 'Chats/Navbar',
6
+ component: unnnicChatsNavbar,
7
7
  argTypes: {
8
8
  links: [
9
9
  {
@@ -16,8 +16,8 @@ export default {
16
16
 
17
17
  const Template = (args, { argTypes }) => ({
18
18
  props: Object.keys(argTypes),
19
- components: { unnnicNavbarChats },
20
- template: '<unnnic-navbar-chats v-bind="$props"/>',
19
+ components: { unnnicChatsNavbar },
20
+ template: '<unnnic-chats-navbar v-bind="$props"/>',
21
21
  });
22
22
 
23
23
  export const Default = Template.bind({});
@@ -0,0 +1,35 @@
1
+ import unnnicChatsUserAvatar from '../components/ChatsUserAvatar/ChatsUserAvatar.vue';
2
+
3
+ export default {
4
+ title: 'Chats/UserAvatar',
5
+ component: unnnicChatsUserAvatar,
6
+ argTypes: {
7
+ size: {
8
+ control: {
9
+ type: 'select',
10
+ options: ['xs', 'sm', 'ant', 'md', 'lg', 'xl', '2xl'],
11
+ },
12
+ },
13
+ },
14
+ };
15
+
16
+ const Template = (args, { argTypes }) => ({
17
+ props: Object.keys(argTypes),
18
+ components: { unnnicChatsUserAvatar },
19
+ template: '<unnnic-chats-user-avatar v-bind="$props"/>',
20
+ });
21
+
22
+ export const Default = Template.bind({});
23
+ Default.args = {
24
+ username: 'John Doe',
25
+ };
26
+
27
+ export const Agent = Template.bind({});
28
+ Agent.args = {
29
+ username: 'Agent',
30
+ };
31
+
32
+ export const Bot = Template.bind({});
33
+ Bot.args = {
34
+ username: 'Bot',
35
+ };