@eturnity/eturnity_reusable_components 8.19.2 → 8.19.4

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 (35) hide show
  1. package/package.json +1 -1
  2. package/src/assets/svgIcons/download.svg +3 -3
  3. package/src/assets/svgIcons/filter.svg +3 -0
  4. package/src/assets/svgIcons/kanban_view.svg +6 -0
  5. package/src/assets/svgIcons/plus_button.svg +3 -3
  6. package/src/assets/svgIcons/table_view.svg +3 -0
  7. package/src/assets/theme.js +53 -5
  8. package/src/components/banner/banner/Banner.stories.js +99 -43
  9. package/src/components/banner/infoBanner/InfoBanner.stories.js +72 -30
  10. package/src/components/buttons/buttonIcon/ButtonIcon.stories.js +167 -0
  11. package/src/components/buttons/buttonIcon/index.vue +40 -6
  12. package/src/components/buttons/mainButton/MainButton.stories.js +115 -34
  13. package/src/components/draggableCard/draggableCard.stories.js +110 -54
  14. package/src/components/filter/filterSettings.vue +1 -1
  15. package/src/components/filterComponent/viewFilter.vue +605 -0
  16. package/src/components/filterComponent/viewSettings.vue +281 -0
  17. package/src/components/filterComponent/viewSort.vue +330 -0
  18. package/src/components/icon/Icon.stories.js +220 -0
  19. package/src/components/icon/index.vue +8 -1
  20. package/src/components/infoCard/index.vue +7 -3
  21. package/src/components/inputs/searchInput/index.vue +1 -1
  22. package/src/components/inputs/select/index.vue +6 -5
  23. package/src/components/inputs/select/option/index.vue +5 -0
  24. package/src/components/projectMarker/ProjectMarker.stories.js +130 -0
  25. package/src/components/selectedOptions/index.vue +13 -2
  26. package/src/components/selectedOptions/selectedOptions.stories.js +135 -37
  27. package/src/components/spinner/Spinner.stories.js +70 -18
  28. package/src/components/spinnerGif/SpinnerGif.stories.js +86 -0
  29. package/src/components/tableDropdown/TableDropdown.stories.js +192 -0
  30. package/src/components/tables/mainTable/MainTable.stories.js +151 -0
  31. package/src/components/tabsHeader/TabsHeader.stories.js +142 -0
  32. package/src/components/tabsHeader/index.vue +33 -9
  33. package/src/components/videoThumbnail/videoThumbnail.stories.js +90 -17
  34. package/src/helpers/translateLang.js +95 -24
  35. package/src/components/icon/Icons.stories.js +0 -31
@@ -0,0 +1,281 @@
1
+ <template>
2
+ <PageContainer>
3
+ <ButtonIcon
4
+ class="button-icon"
5
+ icon-name="settings"
6
+ :text="$gettext('view_settings')"
7
+ type="filter"
8
+ @click="toggleOptions"
9
+ />
10
+ <ButtonWrapper v-if="isOptionsVisible">
11
+ <BoxContainer class="box-container">
12
+ <BoxTitle>{{ $gettext('view_settings') }}</BoxTitle>
13
+ <SectionTitleContainer>
14
+ <SectionTitle>{{ $gettext('select_columns') }}</SectionTitle>
15
+ <MainButton
16
+ :text="$gettext('select_all')"
17
+ type="ghost"
18
+ @click="handleSelectAll"
19
+ />
20
+ </SectionTitleContainer>
21
+ <SelectOptionsContainer>
22
+ <SelectOption
23
+ v-for="column in columnsData"
24
+ :key="column.id"
25
+ :is-last-selected="column.selected && getSelectedCount() <= 1"
26
+ :is-selected="column.selected"
27
+ @click="handleSelectColumn(column)"
28
+ >
29
+ {{ $gettext(column.text) }}
30
+ </SelectOption>
31
+ </SelectOptionsContainer>
32
+ <LineSeparator v-if="detailedToggleOptions.length > 0" />
33
+ <SectionTitleContainer>
34
+ <SectionTitle>{{ $gettext('show_details') }}</SectionTitle>
35
+ </SectionTitleContainer>
36
+ <ToggleContainer>
37
+ <RCToggle
38
+ v-for="option in detailedToggleOptions"
39
+ :key="option.label"
40
+ :is-checked="option.value"
41
+ :label="$gettext(option.label)"
42
+ @on-toggle-change="$emit(option.onToggle, $event)"
43
+ />
44
+ </ToggleContainer>
45
+ <LineSeparator />
46
+ <SelectedContainer>
47
+ <SectionTitle>{{ $gettext('Shown') }}</SectionTitle>
48
+ <SelectComponent
49
+ ref="selectSortDropdown"
50
+ align-items="vertical"
51
+ class="sort-dropdown"
52
+ :dropdown-auto-close="true"
53
+ select-height="40px"
54
+ @click.stop
55
+ @input-change="onPageSizeChange($event)"
56
+ >
57
+ <template #selector>
58
+ <SelectedText>{{
59
+ pageSize + ' ' + $gettext('projects')
60
+ }}</SelectedText>
61
+ </template>
62
+ <template #dropdown>
63
+ <RcOption
64
+ v-for="option in shownOptions"
65
+ :key="option.label"
66
+ :value="option.value"
67
+ >
68
+ {{ $gettext(option.label) }}
69
+ </RcOption>
70
+ </template>
71
+ </SelectComponent>
72
+ </SelectedContainer>
73
+ </BoxContainer>
74
+ </ButtonWrapper>
75
+ </PageContainer>
76
+ </template>
77
+
78
+ <script>
79
+ import styled from 'vue3-styled-components'
80
+ import ButtonIcon from '../buttons/buttonIcon/index.vue'
81
+ import MainButton from '../buttons/mainButton/index.vue'
82
+ import RCToggle from '../inputs/toggle/index.vue'
83
+ import SelectComponent from '../inputs/select/index.vue'
84
+ import RcOption from '../inputs/select/option/index.vue'
85
+
86
+ const PageContainer = styled.div``
87
+
88
+ const ButtonWrapper = styled.div`
89
+ position: relative;
90
+ `
91
+
92
+ const BoxContainer = styled.div`
93
+ position: absolute;
94
+ z-index: 99;
95
+ top: 8px;
96
+ right: 0;
97
+ width: max-content;
98
+ max-width: 500px;
99
+ background-color: ${(props) => props.theme.colors.white};
100
+ border: 1px solid ${(props) => props.theme.semanticColors.grey[300]};
101
+ border-radius: 4px;
102
+ padding: 24px;
103
+ `
104
+
105
+ const BoxTitle = styled.div`
106
+ font-size: 14px;
107
+ font-weight: 500;
108
+ color: ${(props) => props.theme.semanticColors.teal[800]};
109
+ margin-bottom: 16px;
110
+ `
111
+
112
+ const SectionTitleContainer = styled.div`
113
+ display: flex;
114
+ align-items: center;
115
+ justify-content: space-between;
116
+ margin-bottom: 16px;
117
+ white-space: nowrap;
118
+ gap: 16px;
119
+ `
120
+
121
+ const SectionTitle = styled.div`
122
+ font-size: 12px;
123
+ font-weight: 500;
124
+ color: ${(props) => props.theme.semanticColors.teal[800]};
125
+ `
126
+
127
+ const SelectOptionsContainer = styled.div`
128
+ display: flex;
129
+ flex-direction: row;
130
+ flex-wrap: wrap;
131
+ gap: 8px;
132
+ `
133
+
134
+ const SelectAttrs = {
135
+ isSelected: Boolean,
136
+ isLastSelected: Boolean,
137
+ }
138
+ const SelectOption = styled('div', SelectAttrs)`
139
+ background-color: ${(props) =>
140
+ props.isSelected
141
+ ? props.theme.semanticColors.green[400]
142
+ : props.theme.colors.white};
143
+ color: ${(props) => props.theme.semanticColors.teal[800]};
144
+ border: 1px solid
145
+ ${(props) =>
146
+ props.isSelected
147
+ ? props.theme.semanticColors.green[400]
148
+ : props.theme.semanticColors.green[300]};
149
+ padding: 1px 10px;
150
+ font-size: 12px;
151
+ font-weight: 400;
152
+ border-radius: 4px;
153
+ cursor: ${(props) =>
154
+ props.isSelected && props.isLastSelected ? 'not-allowed' : 'pointer'};
155
+ user-select: none;
156
+ `
157
+
158
+ const LineSeparator = styled.div`
159
+ width: 100%;
160
+ height: 1px;
161
+ background-color: ${(props) => props.theme.semanticColors.grey[100]};
162
+ margin: 16px 0;
163
+ `
164
+
165
+ const ToggleContainer = styled.div`
166
+ display: flex;
167
+ flex-direction: column;
168
+ gap: 8px;
169
+ `
170
+
171
+ const SelectedText = styled.div`
172
+ font-size: 14px;
173
+ font-weight: 400;
174
+ color: ${(props) => props.theme.semanticColors.grey[800]};
175
+ `
176
+
177
+ const SelectedContainer = styled.div`
178
+ display: inline-flex;
179
+ gap: 8px;
180
+ flex-direction: column;
181
+ `
182
+
183
+ export default {
184
+ name: 'ViewSettings',
185
+ components: {
186
+ PageContainer,
187
+ ButtonIcon,
188
+ ButtonWrapper,
189
+ BoxContainer,
190
+ BoxTitle,
191
+ SectionTitleContainer,
192
+ SectionTitle,
193
+ MainButton,
194
+ SelectOptionsContainer,
195
+ SelectOption,
196
+ LineSeparator,
197
+ RCToggle,
198
+ ToggleContainer,
199
+ SelectComponent,
200
+ RcOption,
201
+ SelectedText,
202
+ SelectedContainer,
203
+ },
204
+ props: {
205
+ columnsData: {
206
+ type: Array,
207
+ required: true,
208
+ },
209
+ detailedToggleOptions: {
210
+ type: Array,
211
+ required: false,
212
+ },
213
+ pageSize: {
214
+ type: Number,
215
+ required: false,
216
+ default: 20,
217
+ },
218
+ },
219
+ emits: ['onSelectColumn', 'onSelectAllColumns'],
220
+ data() {
221
+ return {
222
+ isOptionsVisible: false,
223
+ }
224
+ },
225
+ computed: {
226
+ shownOptions() {
227
+ return [
228
+ { label: '20' + ' ' + this.$gettext('projects'), value: 20 },
229
+ { label: '50' + ' ' + this.$gettext('projects'), value: 50 },
230
+ { label: '100' + ' ' + this.$gettext('projects'), value: 100 },
231
+ ]
232
+ },
233
+ },
234
+ beforeUnmount() {
235
+ document.removeEventListener('click', this.handleClickOutside)
236
+ },
237
+ methods: {
238
+ getSelectedCount() {
239
+ return this.columnsData.filter((col) => col.selected).length
240
+ },
241
+ handleSelectAll() {
242
+ this.$emit('onSelectAllColumns')
243
+ },
244
+ handleSelectColumn(column) {
245
+ // Count currently selected columns
246
+ const selectedCount = this.getSelectedCount()
247
+
248
+ // Prevent deselecting if this is the last selected column
249
+ if (selectedCount <= 1 && column.selected) {
250
+ return
251
+ }
252
+
253
+ this.$emit('onSelectColumn', column)
254
+ },
255
+ toggleOptions() {
256
+ this.isOptionsVisible = !this.isOptionsVisible
257
+ if (this.isOptionsVisible) {
258
+ document.addEventListener('click', this.handleClickOutside)
259
+ } else {
260
+ document.removeEventListener('click', this.handleClickOutside)
261
+ }
262
+ },
263
+ handleClickOutside(event) {
264
+ const buttonIcon = this.$el.querySelector('.button-icon')
265
+ const boxContainer = this.$el.querySelector('.box-container')
266
+
267
+ if (
268
+ !buttonIcon.contains(event.target) &&
269
+ !boxContainer.contains(event.target)
270
+ ) {
271
+ this.isOptionsVisible = false
272
+ document.removeEventListener('click', this.handleClickOutside)
273
+ }
274
+ },
275
+ onPageSizeChange(value) {
276
+ console.log('value', value)
277
+ this.$emit('onPageSizeChange', value)
278
+ },
279
+ },
280
+ }
281
+ </script>
@@ -0,0 +1,330 @@
1
+ <template>
2
+ <PageContainer>
3
+ <ButtonIcon
4
+ class="button-icon"
5
+ icon-name="sorting"
6
+ :number-count="getNumberCount()"
7
+ :text="$gettext('sort')"
8
+ type="filter"
9
+ @click="toggleOptions"
10
+ />
11
+ <ButtonWrapper v-if="isOptionsVisible">
12
+ <BoxContainer class="box-container">
13
+ <BoxTitle>{{ $gettext('sort') }}</BoxTitle>
14
+ <SortOptionsContainer>
15
+ <template v-if="selectedSort.length > 0">
16
+ <SortDropdownContainer
17
+ v-for="(item, index) in selectedSort"
18
+ :key="index"
19
+ >
20
+ <SelectComponent
21
+ ref="selectSortDropdown"
22
+ align-items="vertical"
23
+ class="sort-dropdown"
24
+ :dropdown-auto-close="false"
25
+ select-height="40px"
26
+ @input-change="
27
+ onSelectSort({
28
+ type: 'column',
29
+ value: $event,
30
+ index: index,
31
+ })
32
+ "
33
+ >
34
+ <template #selector>
35
+ <SelectedText>{{
36
+ getSelectedLabel({ type: 'column', value: item.column }) ||
37
+ $gettext('category')
38
+ }}</SelectedText>
39
+ </template>
40
+ <template #dropdown>
41
+ <SelectOption
42
+ v-for="(item, index) in sortOptions"
43
+ :key="item.value"
44
+ :value="item.value"
45
+ >
46
+ {{ item.label }}
47
+ </SelectOption>
48
+ </template>
49
+ </SelectComponent>
50
+ <SelectComponent
51
+ ref="selectSortDropdown"
52
+ align-items="vertical"
53
+ class="sort-dropdown"
54
+ :dropdown-auto-close="false"
55
+ select-height="40px"
56
+ @input-change="
57
+ onSelectSort({
58
+ type: 'direction',
59
+ value: $event,
60
+ index: index,
61
+ })
62
+ "
63
+ >
64
+ <template #selector>
65
+ <SelectedText>{{
66
+ getSelectedLabel({
67
+ type: 'direction',
68
+ value: item.direction,
69
+ }) || $gettext('constraint')
70
+ }}</SelectedText>
71
+ </template>
72
+ <template #dropdown>
73
+ <SelectOption
74
+ v-for="(item, index) in directionOptions"
75
+ :key="item.value"
76
+ :value="item.value"
77
+ >
78
+ {{ item.label }}
79
+ </SelectOption>
80
+ </template>
81
+ </SelectComponent>
82
+ <IconContainer>
83
+ <RCIcon
84
+ :color="theme.semanticColors.teal[800]"
85
+ cursor="pointer"
86
+ name="close"
87
+ size="14px"
88
+ @click.stop="removeItem(index)"
89
+ />
90
+ </IconContainer>
91
+ </SortDropdownContainer>
92
+ </template>
93
+ <template v-else>
94
+ <SortDropdownContainer>
95
+ <SelectComponent
96
+ ref="selectSortDropdown"
97
+ align-items="vertical"
98
+ class="sort-dropdown"
99
+ :dropdown-auto-close="false"
100
+ select-height="40px"
101
+ @input-change="
102
+ onSelectSort({
103
+ type: 'column',
104
+ value: $event,
105
+ index: 0,
106
+ })
107
+ "
108
+ >
109
+ <template #selector>
110
+ <SelectedText>{{ $gettext('category') }}</SelectedText>
111
+ </template>
112
+ <template #dropdown>
113
+ <SelectOption
114
+ v-for="(item, index) in sortOptions"
115
+ :key="item.value"
116
+ :value="item.value"
117
+ >
118
+ {{ item.label }}
119
+ </SelectOption>
120
+ </template>
121
+ </SelectComponent>
122
+ <SelectComponent
123
+ ref="selectSortDropdown"
124
+ align-items="vertical"
125
+ class="sort-dropdown"
126
+ :dropdown-auto-close="false"
127
+ select-height="40px"
128
+ @input-change="
129
+ onSelectSort({
130
+ type: 'direction',
131
+ value: $event,
132
+ index: 0,
133
+ })
134
+ "
135
+ >
136
+ <template #selector>
137
+ <SelectedText>{{ $gettext('constraint') }}</SelectedText>
138
+ </template>
139
+ <template #dropdown>
140
+ <SelectOption
141
+ v-for="(item, index) in directionOptions"
142
+ :key="item.value"
143
+ :value="item.value"
144
+ >
145
+ {{ item.label }}
146
+ </SelectOption>
147
+ </template>
148
+ </SelectComponent>
149
+ </SortDropdownContainer>
150
+ </template>
151
+ </SortOptionsContainer>
152
+ </BoxContainer>
153
+ </ButtonWrapper>
154
+ </PageContainer>
155
+ </template>
156
+
157
+ <script>
158
+ import styled from 'vue3-styled-components'
159
+ import ButtonIcon from '../buttons/buttonIcon/index.vue'
160
+ import SelectComponent from '../inputs/select/index.vue'
161
+ import SelectOption from '../inputs/select/option/index.vue'
162
+ import RCIcon from '../icon'
163
+ import theme from '../../assets/theme'
164
+
165
+ const PageContainer = styled.div``
166
+
167
+ const ButtonWrapper = styled.div`
168
+ position: relative;
169
+ `
170
+
171
+ const BoxContainer = styled.div`
172
+ position: absolute;
173
+ z-index: 99;
174
+ top: 8px;
175
+ right: 0;
176
+ width: max-content;
177
+ max-width: 500px;
178
+ background-color: ${(props) => props.theme.colors.white};
179
+ border: 1px solid ${(props) => props.theme.semanticColors.grey[300]};
180
+ border-radius: 4px;
181
+ padding: 24px;
182
+ `
183
+
184
+ const BoxTitle = styled.div`
185
+ font-size: 14px;
186
+ font-weight: 500;
187
+ color: ${(props) => props.theme.semanticColors.teal[800]};
188
+ margin-bottom: 16px;
189
+ `
190
+
191
+ const SortOptionsContainer = styled.div`
192
+ display: flex;
193
+ flex-direction: column;
194
+ gap: 16px;
195
+ white-space: nowrap;
196
+ `
197
+
198
+ const SortDropdownContainer = styled.div`
199
+ display: flex;
200
+ flex-direction: row;
201
+ gap: 8px;
202
+ align-items: center;
203
+ `
204
+
205
+ const SelectedText = styled.div`
206
+ font-size: 14px;
207
+ font-weight: 400;
208
+ color: ${(props) => props.theme.semanticColors.grey[800]};
209
+ `
210
+
211
+ const IconContainer = styled.div`
212
+ margin-left: 12px;
213
+ `
214
+
215
+ export default {
216
+ name: 'ViewSettings',
217
+ components: {
218
+ PageContainer,
219
+ ButtonIcon,
220
+ ButtonWrapper,
221
+ BoxContainer,
222
+ BoxTitle,
223
+ SortOptionsContainer,
224
+ SortDropdownContainer,
225
+ SelectComponent,
226
+ SelectOption,
227
+ SelectedText,
228
+ RCIcon,
229
+ IconContainer,
230
+ },
231
+ props: {
232
+ sortOptions: {
233
+ type: Array,
234
+ required: true,
235
+ },
236
+ selectedSort: {
237
+ type: Array,
238
+ required: true,
239
+ },
240
+ },
241
+ data() {
242
+ return {
243
+ isOptionsVisible: false,
244
+ }
245
+ },
246
+ computed: {
247
+ directionOptions() {
248
+ return [
249
+ {
250
+ value: 'ascending',
251
+ label: this.$gettext('ascending'),
252
+ },
253
+ {
254
+ value: 'descending',
255
+ label: this.$gettext('descending'),
256
+ },
257
+ ]
258
+ },
259
+ theme() {
260
+ return theme
261
+ },
262
+ },
263
+ mounted() {},
264
+ beforeUnmount() {
265
+ document.removeEventListener('click', this.handleClickOutside)
266
+ },
267
+ methods: {
268
+ handleClickOutside(event) {
269
+ const buttonIcon = this.$el.querySelector('.button-icon')
270
+ const boxContainer = this.$el.querySelector('.box-container')
271
+ const isClickInSelect =
272
+ event.target.closest('.sort-dropdown') ||
273
+ event.target.closest('.rc-select-dropdown') ||
274
+ event.target.closest('.select-button') ||
275
+ event.target.closest('.caret_dropdown') ||
276
+ event.target.closest('.rc-select') ||
277
+ event.target.closest('.select-option') ||
278
+ event.target.closest('.icon') ||
279
+ event.target.closest('svg')
280
+
281
+ if (
282
+ !buttonIcon.contains(event.target) &&
283
+ !boxContainer.contains(event.target) &&
284
+ !isClickInSelect
285
+ ) {
286
+ this.isOptionsVisible = false
287
+ document.removeEventListener('click', this.handleClickOutside)
288
+ }
289
+ },
290
+ getNumberCount() {
291
+ return this.selectedSort.filter((item) => {
292
+ const hasColumn = !!item.column
293
+ const hasDirection = !!item.direction
294
+ return hasColumn && hasDirection
295
+ }).length
296
+ },
297
+ toggleOptions() {
298
+ this.isOptionsVisible = !this.isOptionsVisible
299
+ if (this.isOptionsVisible) {
300
+ document.addEventListener('click', this.handleClickOutside)
301
+ } else {
302
+ document.removeEventListener('click', this.handleClickOutside)
303
+ }
304
+ },
305
+ getSelectedLabel({ type, value }) {
306
+ if (!value) return
307
+ if (type === 'column') {
308
+ return this.sortOptions.find((option) => option.value === value).label
309
+ } else if (type === 'direction') {
310
+ return this.directionOptions.find((option) => option.value === value)
311
+ .label
312
+ }
313
+ },
314
+ onSelectSort({ type, value, index }) {
315
+ this.$emit('on-sort-change', {
316
+ type,
317
+ value,
318
+ index,
319
+ })
320
+ this.isOptionsVisible = true
321
+ },
322
+ removeItem(index) {
323
+ this.$emit('on-sort-change', {
324
+ type: 'remove',
325
+ index,
326
+ })
327
+ },
328
+ },
329
+ }
330
+ </script>