@eturnity/eturnity_reusable_components 1.0.15 → 1.0.16

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
@@ -0,0 +1,3 @@
1
+ <svg width="8" height="4" viewBox="0 0 8 4" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M4 4L8 0H0L4 4Z" fill="#263238"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="8" height="4" viewBox="0 0 8 4" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M4 0L8 4H0L4 0Z" fill="#FF5656"/>
3
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
2
+ <defs>
3
+ <style>
4
+ .cls-1 {
5
+ fill: #ff5656;
6
+ fill-rule: evenodd;
7
+ }
8
+ </style>
9
+ </defs>
10
+ <path id="delete_icon" class="cls-1" d="M15.44,27.225a0.8,0.8,0,0,0,.8.771h7.512a0.8,0.8,0,0,0,.8-0.771L25.1,15.9H14.9ZM21.7,18.711a0.327,0.327,0,0,1,.327-0.327h0.523a0.327,0.327,0,0,1,.327.327v6.472a0.327,0.327,0,0,1-.327.327H22.026a0.327,0.327,0,0,1-.327-0.327V18.711Zm-2.288,0a0.327,0.327,0,0,1,.327-0.327h0.523a0.327,0.327,0,0,1,.327.327v6.472a0.327,0.327,0,0,1-.327.327H19.739a0.327,0.327,0,0,1-.327-0.327V18.711h0Zm-2.287,0a0.327,0.327,0,0,1,.327-0.327h0.523a0.327,0.327,0,0,1,.327.327v6.472a0.327,0.327,0,0,1-.327.327H17.451a0.327,0.327,0,0,1-.327-0.327V18.711Zm8.329-5.884H21.988V12.172A0.169,0.169,0,0,0,21.819,12H18.18a0.168,0.168,0,0,0-.168.168v0.656H14.546a0.505,0.505,0,0,0-.505.505v1.587H25.958V13.332A0.505,0.505,0,0,0,25.453,12.827Z"/>
11
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
2
+ <defs>
3
+ <style>
4
+ .cls-1 {
5
+ fill: #DEE2EB;
6
+ fill-rule: evenodd;
7
+ }
8
+ </style>
9
+ </defs>
10
+ <path id="delete_icon" class="cls-1" d="M15.44,27.225a0.8,0.8,0,0,0,.8.771h7.512a0.8,0.8,0,0,0,.8-0.771L25.1,15.9H14.9ZM21.7,18.711a0.327,0.327,0,0,1,.327-0.327h0.523a0.327,0.327,0,0,1,.327.327v6.472a0.327,0.327,0,0,1-.327.327H22.026a0.327,0.327,0,0,1-.327-0.327V18.711Zm-2.288,0a0.327,0.327,0,0,1,.327-0.327h0.523a0.327,0.327,0,0,1,.327.327v6.472a0.327,0.327,0,0,1-.327.327H19.739a0.327,0.327,0,0,1-.327-0.327V18.711h0Zm-2.287,0a0.327,0.327,0,0,1,.327-0.327h0.523a0.327,0.327,0,0,1,.327.327v6.472a0.327,0.327,0,0,1-.327.327H17.451a0.327,0.327,0,0,1-.327-0.327V18.711Zm8.329-5.884H21.988V12.172A0.169,0.169,0,0,0,21.819,12H18.18a0.168,0.168,0,0,0-.168.168v0.656H14.546a0.505,0.505,0,0,0-.505.505v1.587H25.958V13.332A0.505,0.505,0,0,0,25.453,12.827Z"/>
11
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="7" height="11" viewBox="0 0 7 11" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M1 0V10H7" stroke="#B2B9C5"/>
3
+ </svg>
@@ -13,6 +13,11 @@ const theme = {
13
13
  blue: "#48a2d0",
14
14
  red: "#ff7e7e",
15
15
  disabled: "#c4c4c4",
16
+ blue1: "#e4efff",
17
+ grey3: "#b2b9c5",
18
+ grey4: "#ebeef4",
19
+ grey5: "#fafafa",
20
+ green: "#99db0c",
16
21
  },
17
22
  screen: {
18
23
  mobileSmall: "345px",
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <wrapper>
3
+ <icon :color="color" />
4
+ </wrapper>
5
+ </template>
6
+
7
+ <script>
8
+ // To use:
9
+ // <delete-icon
10
+ // color="gray" // red is default
11
+ // />
12
+ import styled from "vue-styled-components"
13
+
14
+ const Wrapper = styled.div`
15
+ width: 100%;
16
+ height: 100%;
17
+ min-height: 40px;
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ `
22
+
23
+ const iconAttrs = { color: String }
24
+ const Icon = styled("span", iconAttrs)`
25
+ width: 30px;
26
+ height: 30px;
27
+ background-position: center;
28
+ cursor: pointer;
29
+ background-image: ${(props) =>
30
+ props.color === "red"
31
+ ? `url(${require("../../assets/images/delete_icon.svg")})`
32
+ : props.color === "gray"
33
+ ? `url(${require("../../assets/images/delete_icon_gray.svg")})`
34
+ : `url(${require("../../assets/images/delete_icon.svg")})`};
35
+
36
+ &:hover {
37
+ box-shadow: 0px 4px 9px 1px rgb(0 0 0 / 20%);
38
+ border-radius: 4px;
39
+ background-image: ${() =>
40
+ `url(${require("../../assets/images/delete_icon.svg")})`};
41
+ }
42
+ `
43
+
44
+ export default {
45
+ name: "delete-icon",
46
+ components: {
47
+ Icon,
48
+ Wrapper,
49
+ },
50
+ props: {
51
+ color: {
52
+ required: false,
53
+ default: "red", // red, gray
54
+ },
55
+ },
56
+ }
57
+ </script>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <spinner-container v-if="fullWidth">
3
+ <container>
4
+ <spinner-wrapper :src="require('../../assets/icons/black-spinner.svg')" />
5
+ </container>
6
+ </spinner-container>
7
+ <container v-else>
8
+ <spinner-wrapper :src="require('../../assets/icons/black-spinner.svg')" />
9
+ </container>
10
+ </template>
11
+
12
+ <script>
13
+ import styled from "vue-styled-components"
14
+
15
+ const SpinnerContainer = styled.div`
16
+ position: fixed;
17
+ top: 0;
18
+ left: 0;
19
+ width: 100%;
20
+ height: 100%;
21
+ background: rgba(255, 255, 255, 0.8);
22
+ display: grid;
23
+ align-items: center;
24
+ justify-items: center;
25
+ z-index: 100;
26
+ `
27
+
28
+ const Container = styled.div`
29
+ display: grid;
30
+ align-items: center;
31
+ justify-items: center;
32
+ `
33
+
34
+ const SpinnerWrapper = styled.img`
35
+ width: 60px;
36
+ `
37
+
38
+ export default {
39
+ name: "spinner",
40
+ components: {
41
+ Container,
42
+ SpinnerWrapper,
43
+ SpinnerContainer,
44
+ },
45
+ props: {
46
+ fullWidth: {
47
+ required: false,
48
+ default: false,
49
+ },
50
+ },
51
+ }
52
+ </script>
@@ -0,0 +1,328 @@
1
+ <!-- This is just an example how to use mainTable with collective positioning -->
2
+ <!-- <template>
3
+ <draggable-table>
4
+ <thead>
5
+ <tr>
6
+ <div />
7
+ <th v-for="item in headerItems" :key="item.value">
8
+ {{ item.value }}
9
+ </th>
10
+ <th />
11
+ <div />
12
+ </tr>
13
+ </thead>
14
+ <draggable-container
15
+ :items="tableList"
16
+ handle=".drag-container"
17
+ :options="{ disabled: false }"
18
+ >
19
+ <parent-container v-for="el in tableList" :key="el.sales">
20
+ <tr :class="{ 'no-border': isOpen({ id: el.id }), disabled: true }">
21
+ <div class="drag-container">
22
+ <div class="drag-icon" />
23
+ </div>
24
+ <td>
25
+ <div :class="{ 'collective-container': el.children }">
26
+ <input-text :value="el.description" />
27
+ <div
28
+ v-if="el.children"
29
+ @click="
30
+ toggleShowChildren({ id: el.id, length: el.children.length })
31
+ "
32
+ :class="{
33
+ 'collective-box': true,
34
+ open: isChildrenOpen({ id: el.id }),
35
+ }"
36
+ >
37
+ {{ el.children.length }}
38
+ </div>
39
+ </div>
40
+ </td>
41
+ <td>
42
+ <div v-if="el.children" />
43
+ <input-text v-else :value="el.cost_price" />
44
+ </td>
45
+ <td>
46
+ <div v-if="el.children" />
47
+ <input-text v-else :value="el.margin" />
48
+ </td>
49
+ <td>
50
+ <div v-if="el.children" />
51
+ <input-text v-else :value="el.installation" />
52
+ </td>
53
+ <td>
54
+ <input-text :value="el.sales" />
55
+ </td>
56
+ <div class="arrow-container" @click="toggleOpen({ id: el.id })">
57
+ <div v-if="isOpen({ id: el.id })" class="arrow-up" />
58
+ <div v-if="!isOpen({ id: el.id })" class="arrow-down" />
59
+ </div>
60
+ <div class="icons-container">
61
+ <three-dots :options="listOptions" />
62
+ <delete-icon color="gray" />
63
+ </div>
64
+ </tr>
65
+ <tr v-if="isOpen({ id: el.id })" class="container-row">
66
+ <div />
67
+ <td class="no-border" colspan="6" v-if="isOpen({ id: el.id })">
68
+ <div class="open-container">
69
+ <container-wrapper>
70
+ <div>hi you</div>
71
+ <div>Test test</div>
72
+ </container-wrapper>
73
+ </div>
74
+ </td>
75
+ </tr>
76
+ <children-wrapper
77
+ v-if="
78
+ el.children && el.children.length && isChildrenOpen({ id: el.id })
79
+ "
80
+ >
81
+ <draggable-container :items="el.children" handle=".drag-container">
82
+ <template v-for="item in el.children">
83
+ <tr
84
+ :key="item.sales"
85
+ :class="{
86
+ 'no-border': isOpen({ id: item.id }),
87
+ disabled: true,
88
+ }"
89
+ >
90
+ <div class="drag-container">
91
+ <div class="drag-icon" />
92
+ </div>
93
+ <td>
94
+ <div class="collective-container">
95
+ <span class="subposition-icon" />
96
+ <input-text :value="item.description" />
97
+ </div>
98
+ </td>
99
+ <td>
100
+ <input-text :value="item.cost_price" />
101
+ </td>
102
+ <td>
103
+ <input-text :value="item.margin" />
104
+ </td>
105
+ <td>
106
+ <input-text :value="item.installation" />
107
+ </td>
108
+ <td><input-text :value="item.sales" /></td>
109
+ <div
110
+ class="arrow-container"
111
+ @click="toggleOpen({ id: item.id })"
112
+ >
113
+ <div v-if="isOpen({ id: item.id })" class="arrow-up" />
114
+ <div v-if="!isOpen({ id: item.id })" class="arrow-down" />
115
+ </div>
116
+ <div class="icons-container">
117
+ <three-dots :options="listOptions" />
118
+ <delete-icon color="gray" />
119
+ </div>
120
+ </tr>
121
+ <tr
122
+ v-if="isOpen({ id: item.id })"
123
+ class="container-row"
124
+ :key="item.sales"
125
+ >
126
+ <div />
127
+ <td
128
+ class="no-border"
129
+ colspan="6"
130
+ v-if="isOpen({ id: item.id })"
131
+ >
132
+ <div class="open-container">
133
+ <container-wrapper>
134
+ <div>hi you</div>
135
+ <div>Test test</div>
136
+ </container-wrapper>
137
+ </div>
138
+ </td>
139
+ </tr>
140
+ </template>
141
+ </draggable-container>
142
+ </children-wrapper>
143
+ </parent-container>
144
+ </draggable-container>
145
+ <tr class="footer">
146
+ <div />
147
+ <td class="text bold">
148
+ Total PV system code
149
+ </td>
150
+ <td />
151
+ <td />
152
+ <td />
153
+ <td class="text bold">
154
+ 17.000 CHF
155
+ </td>
156
+ <td />
157
+ <div />
158
+ </tr>
159
+ </draggable-table>
160
+ </template>
161
+
162
+ <script>
163
+ import draggable from "vuedraggable"
164
+ import styled from "vue-styled-components"
165
+ import DraggableTable from "@/components/reusable-components/tables/DraggableTable"
166
+ import InputText from "@eturnity/eturnity_reusable_components/src/components/inputs/inputText"
167
+ import DeleteIcon from "@/components/reusable-components/DeleteIcon"
168
+ import ThreeDots from "@/components/reusable-components/ThreeDots"
169
+
170
+ const DraggableContainer = styled(draggable)`
171
+ display: contents;
172
+ `
173
+
174
+ const ParentContainer = styled.tbody`
175
+ /* display: contents; */
176
+ `
177
+
178
+ const ChildrenWrapper = styled.div`
179
+ display: contents;
180
+ `
181
+
182
+ const ContainerWrapper = styled.div`
183
+ display: grid;
184
+ padding: 12px;
185
+ grid-template-columns: 1fr 1fr;
186
+ `
187
+
188
+ export default {
189
+ name: "nested-table",
190
+ components: {
191
+ DraggableContainer,
192
+ ParentContainer,
193
+ DraggableTable,
194
+ InputText,
195
+ ChildrenWrapper,
196
+ DeleteIcon,
197
+ ThreeDots,
198
+ ContainerWrapper,
199
+ },
200
+ data() {
201
+ return {
202
+ tableList: [
203
+ {
204
+ description: "My Description 1",
205
+ cost_price: null,
206
+ margin: null,
207
+ installation: null,
208
+ sales: 1000,
209
+ id: 1,
210
+ children: [
211
+ {
212
+ description: "My Description 2",
213
+ cost_price: 20,
214
+ margin: 200,
215
+ installation: 2000,
216
+ sales: 20,
217
+ id: 2,
218
+ children: [],
219
+ },
220
+ {
221
+ description: "My Description 7",
222
+ cost_price: 70,
223
+ margin: 700,
224
+ installation: 7000,
225
+ sales: 70,
226
+ id: 3,
227
+ children: [],
228
+ },
229
+ ],
230
+ },
231
+ {
232
+ description: "My Description 3",
233
+ cost_price: 30,
234
+ margin: 300,
235
+ installation: 3000,
236
+ sales: 30,
237
+ id: 4,
238
+ },
239
+ {
240
+ description: "My Description 5",
241
+ cost_price: 50,
242
+ margin: 500,
243
+ installation: 5000,
244
+ sales: 50,
245
+ id: 5,
246
+ children: [
247
+ {
248
+ description: "My Description 6",
249
+ cost_price: 60,
250
+ margin: 600,
251
+ installation: 6000,
252
+ sales: 60,
253
+ id: 6,
254
+ children: [],
255
+ },
256
+ ],
257
+ },
258
+ ],
259
+ openItem: null,
260
+ showChildren: [],
261
+ listOptions: [
262
+ {
263
+ name: "Option 1",
264
+ value: "option_1",
265
+ },
266
+ {
267
+ name: "Option 2",
268
+ value: "option_2",
269
+ },
270
+ {
271
+ name: "Option 3",
272
+ value: "option_3",
273
+ },
274
+ {
275
+ name: "Option 4",
276
+ value: "option_4",
277
+ },
278
+ ],
279
+ }
280
+ },
281
+ computed: {
282
+ headerItems() {
283
+ const items = [
284
+ {
285
+ value: "Description",
286
+ },
287
+ {
288
+ value: "Cost price",
289
+ },
290
+ {
291
+ value: "Calculation surcharge",
292
+ },
293
+ {
294
+ value: "Installation costs",
295
+ },
296
+ {
297
+ value: "Sales price",
298
+ },
299
+ ]
300
+
301
+ return items
302
+ },
303
+ },
304
+ methods: {
305
+ toggleOpen({ id }) {
306
+ this.openItem = this.openItem === id ? null : id
307
+ },
308
+ isOpen({ id }) {
309
+ return this.openItem === id
310
+ },
311
+ toggleShowChildren({ id, length }) {
312
+ if (!length) {
313
+ return
314
+ }
315
+ if (this.isChildrenOpen({ id })) {
316
+ // if the item is already in the Array
317
+ this.showChildren = this.showChildren.filter((item) => item !== id)
318
+ } else {
319
+ this.showChildren.push(id)
320
+ }
321
+ },
322
+ isChildrenOpen({ id }) {
323
+ return this.showChildren.length ? this.showChildren.includes(id) : false
324
+ },
325
+ },
326
+ }
327
+ </script>
328
+ -->
@@ -0,0 +1,262 @@
1
+ <template>
2
+ <table-scroll>
3
+ <table-wrapper :fullWidth="fullWidth">
4
+ <spinner-wrapper v-if="isLoading">
5
+ <spinner />
6
+ </spinner-wrapper>
7
+ <table-container v-else>
8
+ <slot />
9
+ </table-container>
10
+ </table-wrapper>
11
+ </table-scroll>
12
+ </template>
13
+
14
+ <script>
15
+ import styled from "vue-styled-components"
16
+ import Spinner from "../../components/spinner"
17
+
18
+ const TableScroll = styled.div`
19
+ position: relative;
20
+ max-width: 100%;
21
+ `
22
+
23
+ const wrapperAttrs = { fullWidth: Boolean }
24
+ const TableWrapper = styled("div", wrapperAttrs)`
25
+ width: ${(props) => (props.fullWidth ? "100%" : "fit-content")};
26
+ max-width: 100%;
27
+ overflow: auto;
28
+
29
+ ::-webkit-scrollbar {
30
+ width: 10px; //width of the whole scrollbar area
31
+ }
32
+
33
+ track ::-webkit-scrollbar-track {
34
+ background: #fff;
35
+ }
36
+
37
+ ::-webkit-scrollbar-thumb {
38
+ border-bottom: 2px solid #b2b9c4; // width of the actual scrollbar
39
+ }
40
+ `
41
+
42
+ const SpinnerWrapper = styled.div`
43
+ height: 150px;
44
+ display: grid;
45
+ align-items: center;
46
+ justify-items: center;
47
+ `
48
+
49
+ const TableContainer = styled.table`
50
+ width: 100%;
51
+ border-collapse: collapse;
52
+ border: none;
53
+ font-size: 13px;
54
+
55
+ thead {
56
+ font-weight: bold;
57
+
58
+ tr {
59
+ border-bottom: none !important;
60
+ }
61
+ }
62
+
63
+ th {
64
+ padding: 12px 20px;
65
+ background-color: ${(props) => props.theme.colors.blue1};
66
+ }
67
+
68
+ td {
69
+ padding: 7px 10px;
70
+ border-bottom: 1px solid ${(props) => props.theme.colors.grey4};
71
+
72
+ &.no-border {
73
+ border-bottom: none;
74
+ }
75
+
76
+ .collective-container {
77
+ display: grid;
78
+ grid-template-columns: auto 1fr;
79
+ align-items: center;
80
+ grid-gap: 10px;
81
+ cursor: pointer;
82
+ }
83
+
84
+ .collective-box {
85
+ width: 22px;
86
+ height: 22px;
87
+ border-radius: 4px;
88
+ color: #fff;
89
+ background-color: ${(props) => props.theme.colors.grey3};
90
+ font-size: 13px;
91
+ font-weight: normal;
92
+ display: grid;
93
+ align-items: center;
94
+ justify-items: center;
95
+
96
+ &.open {
97
+ background-color: ${(props) => props.theme.colors.green};
98
+ }
99
+ }
100
+ }
101
+
102
+ td,
103
+ th {
104
+ white-space: nowrap;
105
+ text-align: left;
106
+
107
+ &.align {
108
+ &-left {
109
+ text-align: left;
110
+ }
111
+
112
+ &-center {
113
+ text-align: center;
114
+ }
115
+
116
+ &-right {
117
+ text-align: right;
118
+ }
119
+ }
120
+ }
121
+
122
+ tr {
123
+ &.disabled {
124
+ cursor: not-allowed;
125
+ }
126
+
127
+ &.footer {
128
+ td {
129
+ background-color: ${(props) => props.theme.colors.grey5};
130
+ border-top: 1px solid ${(props) => props.theme.colors.grey4};
131
+ }
132
+ }
133
+
134
+ .text {
135
+ padding: 12px 0 12px 18px;
136
+ color: ${(props) => props.theme.colors.black};
137
+ }
138
+
139
+ .bold {
140
+ font-weight: bold;
141
+ }
142
+
143
+ .icons-container {
144
+ width: 100%;
145
+ display: inline-flex;
146
+ flex-wrap: nowrap;
147
+ background-color: #fff;
148
+ vertical-align: middle;
149
+ }
150
+
151
+ .arrow-container {
152
+ display: table-cell;
153
+ vertical-align: middle;
154
+ text-align: center;
155
+ text-align: -webkit-center;
156
+ cursor: pointer;
157
+ border-bottom: 1px solid ${(props) => props.theme.colors.grey4};
158
+ }
159
+
160
+ &.container-row td {
161
+ padding: 0;
162
+ }
163
+
164
+ &.no-border {
165
+ td,
166
+ .arrow-container {
167
+ border-bottom: none;
168
+ }
169
+ }
170
+
171
+ &:hover {
172
+ input {
173
+ background-color: ${(props) => props.theme.colors.grey5};
174
+ }
175
+
176
+ .drag-icon {
177
+ visibility: visible;
178
+ }
179
+ }
180
+
181
+ .drag-container {
182
+ display: table-cell;
183
+ width: auto;
184
+ vertical-align: middle;
185
+ }
186
+
187
+ .drag-icon {
188
+ visibility: hidden;
189
+ width: 10px;
190
+ height: 16px;
191
+ cursor: grab;
192
+ background-position: center;
193
+ background-image: ${() =>
194
+ `url(${require("@/assets/images/drag_icon.svg")})`};
195
+
196
+ &:active {
197
+ cursor: grabbing;
198
+ }
199
+ }
200
+
201
+ .subposition-icon {
202
+ width: 14px;
203
+ height: 11px;
204
+ background: no-repeat;
205
+ margin-left: 10px;
206
+ background-image: ${() =>
207
+ `url(${require("@/assets/images/subposition_icon.svg")})`};
208
+ }
209
+
210
+ .arrow-down {
211
+ width: 14px;
212
+ height: 11px;
213
+ background: no-repeat;
214
+ background-position: center;
215
+ background-image: ${() =>
216
+ `url(${require("@/assets/images/arrow_down.svg")})`};
217
+ }
218
+
219
+ .arrow-up {
220
+ width: 14px;
221
+ height: 11px;
222
+ background: no-repeat;
223
+ background-position: center;
224
+ background-image: ${() =>
225
+ `url(${require("@/assets/images/arrow_up_red.svg")})`};
226
+ }
227
+ }
228
+
229
+ input {
230
+ border: none;
231
+ font-size: 13px;
232
+ padding: 5px 10px;
233
+ }
234
+
235
+ .open-container {
236
+ border: 1px solid ${(props) => props.theme.colors.grey4};
237
+ border-radius: 4px;
238
+ margin-bottom: 10px;
239
+ }
240
+ `
241
+
242
+ export default {
243
+ name: "main-table",
244
+ components: {
245
+ TableScroll,
246
+ TableWrapper,
247
+ SpinnerWrapper,
248
+ Spinner,
249
+ TableContainer,
250
+ },
251
+ props: {
252
+ fullWidth: {
253
+ required: false,
254
+ default: true,
255
+ },
256
+ isLoading: {
257
+ required: false,
258
+ default: false,
259
+ },
260
+ },
261
+ }
262
+ </script>
@@ -0,0 +1,195 @@
1
+ <template>
2
+ <page-wrapper>
3
+ <title-text>
4
+ {{ tableTitle }}
5
+ </title-text>
6
+ <table-scroll>
7
+ <table-wrapper :fullWidth="fullWidth">
8
+ <spinner-wrapper v-if="isLoading">
9
+ <spinner />
10
+ </spinner-wrapper>
11
+ <table-container v-else>
12
+ <thead>
13
+ <tr>
14
+ <table-header v-for="(item, index) in headerItems" :key="index">
15
+ {{ item.value }}
16
+ </table-header>
17
+ <div v-if="showIconsContainer && tableItems.length" />
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ <empty-td colspan="100" v-if="!tableItems.length && !isLoading">
22
+ <empty-container>
23
+ {{ emptyText }}
24
+ </empty-container>
25
+ </empty-td>
26
+ <table-row v-for="(row, index) in tableItems" :key="index" v-else>
27
+ <table-item v-for="(item, idx) in row" :key="idx">
28
+ {{ item.value }}
29
+ </table-item>
30
+ <icons-container v-if="showIconsContainer">
31
+ <delete-icon
32
+ @click.native="$emit('on-click-delete', index)"
33
+ color="gray"
34
+ />
35
+ </icons-container>
36
+ </table-row>
37
+ </tbody>
38
+ </table-container>
39
+ </table-wrapper>
40
+ </table-scroll>
41
+ </page-wrapper>
42
+ </template>
43
+
44
+ <script>
45
+ // This is a read only table. Pass it data, and it displays it
46
+ // ToDo: add this to storybook
47
+ // import ViewTable from "@eturnity/eturnity_reusable_components/src/components/tables/viewTable"
48
+ import styled from "vue-styled-components"
49
+ import DeleteIcon from "../../deleteIcon"
50
+ import Spinner from "../../spinner"
51
+
52
+ const TableScroll = styled.div`
53
+ position: relative;
54
+ max-width: 100%;
55
+ `
56
+
57
+ const wrapperAttrs = { fullWidth: Boolean }
58
+ const TableWrapper = styled("div", wrapperAttrs)`
59
+ width: ${(props) => (props.fullWidth ? "100%" : "fit-content")};
60
+ max-width: 100%;
61
+ overflow: auto;
62
+
63
+ ::-webkit-scrollbar {
64
+ width: 10px; //width of the whole scrollbar area
65
+ }
66
+
67
+ track ::-webkit-scrollbar-track {
68
+ background: #fff;
69
+ }
70
+
71
+ ::-webkit-scrollbar-thumb {
72
+ border-bottom: 2px solid ${(props) => props.theme.colors.grey3}; // width of the actual scrollbar
73
+ }
74
+ `
75
+
76
+ const TableContainer = styled.table`
77
+ width: 100%;
78
+ border-collapse: collapse;
79
+ border: none;
80
+ `
81
+
82
+ const TableItem = styled.td`
83
+ border: 1px solid ${(props) => props.theme.colors.grey3};
84
+ width: auto;
85
+ white-space: nowrap;
86
+ padding: 12px;
87
+ text-align: right;
88
+ `
89
+
90
+ const TableHeader = styled(TableItem)`
91
+ background-color: #e6e8ee;
92
+ font-family: "Lato-Bold", Arial;
93
+ text-align: left;
94
+ `
95
+
96
+ const TableRow = styled.tr`
97
+ &:hover {
98
+ background-color: #f5f7fa;
99
+ cursor: pointer;
100
+ }
101
+ `
102
+
103
+ const TitleText = styled.div`
104
+ font-family: "Lato-Bold", Arial;
105
+ margin-bottom: 6px;
106
+ `
107
+
108
+ const PageWrapper = styled.div`
109
+ margin: 16px 0;
110
+ font-size: 13px;
111
+ `
112
+
113
+ const IconsContainer = styled.div`
114
+ width: 100%;
115
+ display: inline-flex;
116
+ flex-wrap: nowrap;
117
+ background-color: #fff;
118
+
119
+ &:hover {
120
+ background-color: #fff;
121
+ }
122
+ `
123
+
124
+ const SpinnerWrapper = styled.div`
125
+ border: 1px solid ${(props) => props.theme.colors.grey3};
126
+ height: 150px;
127
+ display: grid;
128
+ align-items: center;
129
+ justify-items: center;
130
+ `
131
+
132
+ const EmptyContainer = styled.div`
133
+ display: grid;
134
+ align-items: center;
135
+ justify-items: center;
136
+ height: 100px;
137
+ `
138
+
139
+ const EmptyTd = styled.td`
140
+ border: 1px solid ${(props) => props.theme.colors.grey3};
141
+ `
142
+
143
+ export default {
144
+ name: "view-table",
145
+ components: {
146
+ TableScroll,
147
+ TableWrapper,
148
+ TableContainer,
149
+ TableHeader,
150
+ TableItem,
151
+ TableRow,
152
+ TitleText,
153
+ PageWrapper,
154
+ DeleteIcon,
155
+ IconsContainer,
156
+ Spinner,
157
+ SpinnerWrapper,
158
+ EmptyContainer,
159
+ EmptyTd,
160
+ },
161
+ props: {
162
+ headerItems: {
163
+ required: true,
164
+ },
165
+ tableItems: {
166
+ required: true,
167
+ },
168
+ fullWidth: {
169
+ required: false,
170
+ default: true,
171
+ },
172
+ tableTitle: {
173
+ required: false,
174
+ default: null,
175
+ },
176
+ showDeleteButton: {
177
+ required: false,
178
+ default: false,
179
+ },
180
+ isLoading: {
181
+ required: false,
182
+ default: false,
183
+ },
184
+ emptyText: {
185
+ required: false,
186
+ default: "There are no items",
187
+ },
188
+ },
189
+ computed: {
190
+ showIconsContainer() {
191
+ return this.showDeleteButton
192
+ },
193
+ },
194
+ }
195
+ </script>
@@ -0,0 +1,157 @@
1
+ <template>
2
+ <page-container>
3
+ <button-container @click="toggleButton()">
4
+ <dot-item />
5
+ <dot-item />
6
+ <dot-item />
7
+ </button-container>
8
+ <options-container v-if="isOpen">
9
+ <option-item
10
+ v-for="item in options"
11
+ :key="item.value"
12
+ tabindex="0"
13
+ @click="onSelect(item.value)"
14
+ @keyup.enter="onSelect(item.value)"
15
+ >
16
+ {{ item.name }}
17
+ </option-item>
18
+ </options-container>
19
+ </page-container>
20
+ </template>
21
+
22
+ <script>
23
+ // import ThreeDots from "@eturnity/eturnity_reusable_components/src/components/threeDots"
24
+ // To use:
25
+ // <three-dots
26
+ // :options="listOptions"
27
+ // @on-select="onSelect($event)"
28
+ // />
29
+ // options to pass:
30
+ // listOptions: [
31
+ // {
32
+ // name: "Option 1",
33
+ // value: "option_1",
34
+ // },
35
+ // {
36
+ // name: "Option 2",
37
+ // value: "option_2",
38
+ // },
39
+ // {
40
+ // name: "Option 3",
41
+ // value: "option_3",
42
+ // },
43
+ // {
44
+ // name: "Option 4",
45
+ // value: "option_4",
46
+ // }
47
+ // ],
48
+
49
+ import styled from "vue-styled-components"
50
+
51
+ const PageContainer = styled.div`
52
+ position: relative;
53
+ display: grid;
54
+ align-items: center;
55
+ `
56
+
57
+ const ButtonContainer = styled.div`
58
+ display: flex;
59
+ flex-direction: column;
60
+ padding: 5px;
61
+ cursor: pointer;
62
+
63
+ div {
64
+ // This is the dot color
65
+ background-color: #263238;
66
+ }
67
+
68
+ &:hover {
69
+ div {
70
+ // Dot color on hover
71
+ background-color: ${(props) => props.theme.colors.grey3};
72
+ }
73
+ }
74
+ `
75
+
76
+ const DotItem = styled.div`
77
+ width: 4px;
78
+ height: 4px;
79
+ margin: 1px;
80
+ border-radius: 50%;
81
+ `
82
+
83
+ const OptionsContainer = styled.div`
84
+ z-index: 99;
85
+ position: absolute;
86
+ right: 0;
87
+ border: 1px solid
88
+ ${(props) =>
89
+ props.buttonColor ? props.buttonColor : props.theme.colors.grey3};
90
+ display: grid;
91
+ grid-template-columns: 1fr;
92
+ min-width: 200px;
93
+ width: max-content;
94
+ border-radius: 4px;
95
+ background-color: #fff;
96
+ margin-top: 8px;
97
+ max-height: 220px;
98
+ overflow: auto;
99
+ `
100
+
101
+ const OptionItem = styled.div`
102
+ padding: 12px;
103
+ cursor: pointer;
104
+ font-size: 13px;
105
+
106
+ &:hover {
107
+ background-color: #ebeef4;
108
+ }
109
+
110
+ &:focus-visible {
111
+ outline: none;
112
+ background-color: #ebeef4;
113
+ }
114
+ `
115
+
116
+ export default {
117
+ name: "three-dots",
118
+ components: {
119
+ PageContainer,
120
+ ButtonContainer,
121
+ DotItem,
122
+ OptionsContainer,
123
+ OptionItem,
124
+ },
125
+ props: {
126
+ options: {
127
+ required: true,
128
+ },
129
+ },
130
+ data() {
131
+ return {
132
+ isOpen: false,
133
+ }
134
+ },
135
+ methods: {
136
+ toggleButton() {
137
+ this.isOpen = !this.isOpen
138
+
139
+ if (this.isOpen) {
140
+ document.addEventListener("click", this.clickOutside)
141
+ } else {
142
+ document.removeEventListener("click", this.clickOutside)
143
+ }
144
+ },
145
+ onSelect(value) {
146
+ this.$emit("on-select", value)
147
+ this.isOpen = false
148
+ },
149
+ clickOutside(event) {
150
+ if (this.$el.contains(event.target) || !this.isOpen) {
151
+ return
152
+ }
153
+ this.toggleButton()
154
+ },
155
+ },
156
+ }
157
+ </script>
Binary file