@eturnity/eturnity_reusable_components 1.0.14 → 1.0.18

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.14",
3
+ "version": "1.0.18",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
package/src/App.vue CHANGED
@@ -1,7 +1,24 @@
1
1
  <template>
2
2
  <ThemeProvider :theme="getTheme()" :style="{ height: '100%' }">
3
3
  <page-container>
4
- <page-subtitle text="My Page Title" />
4
+ <main-table>
5
+ <thead>
6
+ <tr>
7
+ <th>Column 1</th>
8
+ <th>Column 2</th>
9
+ <th>Column 3</th>
10
+ <th>Column 4</th>
11
+ </tr>
12
+ </thead>
13
+ <tbody>
14
+ <tr>
15
+ <td class="text">Body 1</td>
16
+ <td class="text">Body 2</td>
17
+ <td class="text">Body 3</td>
18
+ <td class="text">Body 4</td>
19
+ </tr>
20
+ </tbody>
21
+ </main-table>
5
22
  </page-container>
6
23
  </ThemeProvider>
7
24
  </template>
@@ -10,7 +27,7 @@
10
27
  import { ThemeProvider } from "vue-styled-components"
11
28
  import theme from "./assets/theme"
12
29
  import styled from "vue-styled-components"
13
- import PageSubtitle from "@/components/pageSubtitle"
30
+ import MainTable from "@/components/tables/mainTable"
14
31
 
15
32
  const PageContainer = styled.div`
16
33
  padding: 40px;
@@ -21,7 +38,7 @@ export default {
21
38
  components: {
22
39
  ThemeProvider,
23
40
  PageContainer,
24
- PageSubtitle,
41
+ MainTable,
25
42
  },
26
43
  data() {
27
44
  return {
@@ -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,8 @@
1
+ <svg width="10" height="16" viewBox="0 0 10 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M4 2C4 3.10457 3.10457 4 2 4C0.89543 4 0 3.10457 0 2C0 0.89543 0.89543 0 2 0C3.10457 0 4 0.89543 4 2Z" fill="#B2B9C5"/>
3
+ <path d="M10 2C10 3.10457 9.10457 4 8 4C6.89543 4 6 3.10457 6 2C6 0.89543 6.89543 0 8 0C9.10457 0 10 0.89543 10 2Z" fill="#B2B9C5"/>
4
+ <path d="M4 8C4 9.10457 3.10457 10 2 10C0.89543 10 0 9.10457 0 8C0 6.89543 0.89543 6 2 6C3.10457 6 4 6.89543 4 8Z" fill="#B2B9C5"/>
5
+ <path d="M10 8C10 9.10457 9.10457 10 8 10C6.89543 10 6 9.10457 6 8C6 6.89543 6.89543 6 8 6C9.10457 6 10 6.89543 10 8Z" fill="#B2B9C5"/>
6
+ <path d="M4 14C4 15.1046 3.10457 16 2 16C0.89543 16 0 15.1046 0 14C0 12.8954 0.89543 12 2 12C3.10457 12 4 12.8954 4 14Z" fill="#B2B9C5"/>
7
+ <path d="M10 14C10 15.1046 9.10457 16 8 16C6.89543 16 6 15.1046 6 14C6 12.8954 6.89543 12 8 12C9.10457 12 10 12.8954 10 14Z" fill="#B2B9C5"/>
8
+ </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>
@@ -11,7 +11,8 @@
11
11
  // />
12
12
  import styled from "vue-styled-components"
13
13
 
14
- const SubtitleText = styled.div`
14
+ const textAttrs = { color: String }
15
+ const SubtitleText = styled("div", textAttrs)`
15
16
  color: ${(props) => (props.color ? props.color : props.theme.colors.gray1)};
16
17
  font-size: 13px;
17
18
  margin-bottom: 30px;
@@ -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,264 @@
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
+ // ToDo: add this to storybook
16
+ // import MainTable from "@eturnity/eturnity_reusable_components/src/components/tables/mainTable"
17
+ import styled from "vue-styled-components"
18
+ import Spinner from "../../spinner"
19
+
20
+ const TableScroll = styled.div`
21
+ position: relative;
22
+ max-width: 100%;
23
+ `
24
+
25
+ const wrapperAttrs = { fullWidth: Boolean }
26
+ const TableWrapper = styled("div", wrapperAttrs)`
27
+ width: ${(props) => (props.fullWidth ? "100%" : "fit-content")};
28
+ max-width: 100%;
29
+ overflow: auto;
30
+
31
+ ::-webkit-scrollbar {
32
+ width: 10px; //width of the whole scrollbar area
33
+ }
34
+
35
+ track ::-webkit-scrollbar-track {
36
+ background: #fff;
37
+ }
38
+
39
+ ::-webkit-scrollbar-thumb {
40
+ border-bottom: 2px solid #b2b9c4; // width of the actual scrollbar
41
+ }
42
+ `
43
+
44
+ const SpinnerWrapper = styled.div`
45
+ height: 150px;
46
+ display: grid;
47
+ align-items: center;
48
+ justify-items: center;
49
+ `
50
+
51
+ const TableContainer = styled.table`
52
+ width: 100%;
53
+ border-collapse: collapse;
54
+ border: none;
55
+ font-size: 13px;
56
+
57
+ thead {
58
+ font-weight: bold;
59
+
60
+ tr {
61
+ border-bottom: none !important;
62
+ }
63
+ }
64
+
65
+ th {
66
+ padding: 12px 20px;
67
+ background-color: ${(props) => props.theme.colors.blue1};
68
+ }
69
+
70
+ td {
71
+ padding: 7px 10px;
72
+ border-bottom: 1px solid ${(props) => props.theme.colors.grey4};
73
+
74
+ &.no-border {
75
+ border-bottom: none;
76
+ }
77
+
78
+ .collective-container {
79
+ display: grid;
80
+ grid-template-columns: auto 1fr;
81
+ align-items: center;
82
+ grid-gap: 10px;
83
+ cursor: pointer;
84
+ }
85
+
86
+ .collective-box {
87
+ width: 22px;
88
+ height: 22px;
89
+ border-radius: 4px;
90
+ color: #fff;
91
+ background-color: ${(props) => props.theme.colors.grey3};
92
+ font-size: 13px;
93
+ font-weight: normal;
94
+ display: grid;
95
+ align-items: center;
96
+ justify-items: center;
97
+
98
+ &.open {
99
+ background-color: ${(props) => props.theme.colors.green};
100
+ }
101
+ }
102
+ }
103
+
104
+ td,
105
+ th {
106
+ white-space: nowrap;
107
+ text-align: left;
108
+
109
+ &.align {
110
+ &-left {
111
+ text-align: left;
112
+ }
113
+
114
+ &-center {
115
+ text-align: center;
116
+ }
117
+
118
+ &-right {
119
+ text-align: right;
120
+ }
121
+ }
122
+ }
123
+
124
+ tr {
125
+ &.disabled {
126
+ cursor: not-allowed;
127
+ }
128
+
129
+ &.footer {
130
+ td {
131
+ background-color: ${(props) => props.theme.colors.grey5};
132
+ border-top: 1px solid ${(props) => props.theme.colors.grey4};
133
+ }
134
+ }
135
+
136
+ .text {
137
+ padding: 12px 0 12px 18px;
138
+ color: ${(props) => props.theme.colors.black};
139
+ }
140
+
141
+ .bold {
142
+ font-weight: bold;
143
+ }
144
+
145
+ .icons-container {
146
+ width: 100%;
147
+ display: inline-flex;
148
+ flex-wrap: nowrap;
149
+ background-color: #fff;
150
+ vertical-align: middle;
151
+ }
152
+
153
+ .arrow-container {
154
+ display: table-cell;
155
+ vertical-align: middle;
156
+ text-align: center;
157
+ text-align: -webkit-center;
158
+ cursor: pointer;
159
+ border-bottom: 1px solid ${(props) => props.theme.colors.grey4};
160
+ }
161
+
162
+ &.container-row td {
163
+ padding: 0;
164
+ }
165
+
166
+ &.no-border {
167
+ td,
168
+ .arrow-container {
169
+ border-bottom: none;
170
+ }
171
+ }
172
+
173
+ &:hover {
174
+ input {
175
+ background-color: ${(props) => props.theme.colors.grey5};
176
+ }
177
+
178
+ .drag-icon {
179
+ visibility: visible;
180
+ }
181
+ }
182
+
183
+ .drag-container {
184
+ display: table-cell;
185
+ width: auto;
186
+ vertical-align: middle;
187
+ }
188
+
189
+ .drag-icon {
190
+ visibility: hidden;
191
+ width: 10px;
192
+ height: 16px;
193
+ cursor: grab;
194
+ background-position: center;
195
+ background-image: ${() =>
196
+ `url(${require("../../../assets/icons/drag_icon.svg")})`};
197
+
198
+ &:active {
199
+ cursor: grabbing;
200
+ }
201
+ }
202
+
203
+ .subposition-icon {
204
+ width: 14px;
205
+ height: 11px;
206
+ background: no-repeat;
207
+ margin-left: 10px;
208
+ background-image: ${() =>
209
+ `url(${require("../../../assets/icons/subposition_icon.svg")})`};
210
+ }
211
+
212
+ .arrow-down {
213
+ width: 14px;
214
+ height: 11px;
215
+ background: no-repeat;
216
+ background-position: center;
217
+ background-image: ${() =>
218
+ `url(${require("../../../assets/icons/arrow_down.svg")})`};
219
+ }
220
+
221
+ .arrow-up {
222
+ width: 14px;
223
+ height: 11px;
224
+ background: no-repeat;
225
+ background-position: center;
226
+ background-image: ${() =>
227
+ `url(${require("../../../assets/icons/arrow_up_red.svg")})`};
228
+ }
229
+ }
230
+
231
+ input {
232
+ border: none;
233
+ font-size: 13px;
234
+ padding: 5px 10px;
235
+ }
236
+
237
+ .open-container {
238
+ border: 1px solid ${(props) => props.theme.colors.grey4};
239
+ border-radius: 4px;
240
+ margin-bottom: 10px;
241
+ }
242
+ `
243
+
244
+ export default {
245
+ name: "main-table",
246
+ components: {
247
+ TableScroll,
248
+ TableWrapper,
249
+ SpinnerWrapper,
250
+ Spinner,
251
+ TableContainer,
252
+ },
253
+ props: {
254
+ fullWidth: {
255
+ required: false,
256
+ default: true,
257
+ },
258
+ isLoading: {
259
+ required: false,
260
+ default: false,
261
+ },
262
+ },
263
+ }
264
+ </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