@abi-software/gallery 0.3.0 → 0.3.2-beta

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.
@@ -1,272 +1,324 @@
1
- <template>
2
- <el-card :shadow="shadow" :body-style="bodyStyle" :style="{ padding: '0px', maxWidth: width + 'rem' }" class="card">
3
- <div v-loading="!isReady">
4
- <div :style="imageContainerStyle">
5
- <img v-if="useDefaultImg" src="../assets/logo-sparc-wave-primary.svg" svg-inline :style="imageStyle" />
6
- <img v-else :src="thumbnail" alt="thumbnail loading ..." :style="imageStyle" />
7
- </div>
8
- <div v-if="false" class="image-overlay">
9
- <div
10
- class="triangle-right-corner"
11
- :style="`border-left-width: ${triangleHeight * 1.2}rem; border-top-width: ${triangleHeight}rem;`"
12
- @click="openLinkInNewTab"
13
- />
14
- <el-tooltip class="item" :content="`View ${data.type}`" placement="left">
15
- <img
16
- class="triangle-icon"
17
- :style="`height: ${triangleHeight * 0.25}rem;top: ${triangleHeight * 0.15}rem;right: ${triangleHeight * 0.15}rem`"
18
- :src="typeIcon"
19
- @click="openLinkInNewTab"
20
- />
21
- </el-tooltip>
22
- </div>
23
- <div v-if="showCardDetails" class="details">
24
- <p v-if="!data.hideType">
25
- <b>{{ data.type }}</b>
26
- </p>
27
- <el-popover ref="galleryPopover" :content="data.title" placement="top" trigger="hover" popper-class="gallery-popper" />
28
- <p v-if="!data.hideTitle" class="title" v-popover:galleryPopover>
29
- {{ data.title }}
30
- </p>
31
- <el-button class="button" @click.prevent="cardClicked"> View {{ data.type }}</el-button>
32
- </div>
33
- </div>
34
- </el-card>
35
- </template>
36
-
37
- <script>
38
- // import { SvgIcon } from '@abi-software/svg-sprite'
39
- import Vue from 'vue'
40
- import { Button, Card, Popover } from 'element-ui'
41
- import GalleryHelper from '../mixins/GalleryHelpers'
42
- Vue.use(Button)
43
- Vue.use(Card)
44
- Vue.use(Popover)
45
-
46
- function isValidHttpUrl(string) {
47
- let url = undefined
48
-
49
- try {
50
- url = new URL(string)
51
- } catch (_) {
52
- return false
53
- }
54
- return url.protocol === 'http:' || url.protocol === 'https:'
55
- }
56
-
57
- export default {
58
- name: 'GalleryCard',
59
- mixins: [GalleryHelper],
60
- props: {
61
- data: {
62
- type: Object,
63
- required: true,
64
- },
65
- width: {
66
- type: Number,
67
- default: 3,
68
- },
69
- height: {
70
- type: Number,
71
- default: 3,
72
- },
73
- showCardDetails: {
74
- type: Boolean,
75
- },
76
- bodyStyle: {
77
- type: Object,
78
- default: () => {
79
- return { padding: '20px', background: '#ffffff' }
80
- },
81
- },
82
- imageStyle: {
83
- type: Object,
84
- default: () => {
85
- return {}
86
- },
87
- },
88
- imageContainerStyle: {
89
- type: Object,
90
- default: () => {
91
- return {}
92
- },
93
- },
94
- shadow: {
95
- type: String,
96
- default: 'always',
97
- },
98
- },
99
- data() {
100
- return {
101
- ro: null,
102
- triangleSize: 4,
103
- thumbnail: undefined,
104
- useDefaultImg: false,
105
- }
106
- },
107
- computed: {
108
- isReady() {
109
- return this.data.title && (this.thumbnail || this.useDefaultImg) && (this.data.link || this.data.userData)
110
- },
111
- imageHeight() {
112
- return this.showCardDetails ? this.height * 0.525 : this.height
113
- },
114
- imageWidth() {
115
- return this.width - 2 * this.marginDetails
116
- },
117
- triangleHeight() {
118
- return this.height * 0.237
119
- },
120
- marginDetails() {
121
- return this.height * 0.076
122
- },
123
- typeIcon() {
124
- return undefined
125
- },
126
- },
127
- watch: {
128
- data: {
129
- deep: true,
130
- immediate: true,
131
- handler: function () {
132
- this.thumbnail = undefined
133
- this.useDefaultImg = false
134
- if (this.data.thumbnail) {
135
- if (isValidHttpUrl(this.data.thumbnail) && this.data.mimetype) {
136
- this.downloadThumbnail(this.data.thumbnail, { fetchAttempts: 0 })
137
- } else {
138
- this.thumbnail = this.data.thumbnail
139
- }
140
- } else {
141
- this.useDefaultImg = true
142
- }
143
- },
144
- },
145
- },
146
- methods: {
147
- /**
148
- * Open a new link if link is provide.
149
- * Fire an event if userData is provide.
150
- */
151
- cardClicked: function () {
152
- if (this.data.link) {
153
- const link = document.createElement('a')
154
- link.href = this.data.link
155
- link.target = '_blank'
156
- document.body.appendChild(link)
157
- link.click()
158
- link.remove()
159
- }
160
- if (this.data.userData) {
161
- this.$emit('card-clicked', this.data.userData)
162
- }
163
- },
164
- /**
165
- * handle thumbnail downloading,, it will use a default svg image if fails
166
- */
167
- downloadThumbnail: function (url, info) {
168
- this.getRequest(url, {}, 11000).then(
169
- (response) => {
170
- let data = response.data
171
- if (data.startsWith('data:')) {
172
- this.thumbnail = response.data
173
- } else {
174
- if (this.data.mimetype) {
175
- this.thumbnail = `data:${this.data.mimetype};base64,${response.data}`
176
- } else {
177
- this.thumbnail = response.data
178
- }
179
- }
180
- },
181
- (reason) => {
182
- if (reason.message.includes('timeout') && reason.message.includes('exceeded') && info.fetchAttempts < 3) {
183
- info.fetchAttempts += 1
184
- this.downloadThumbnail(url, info)
185
- } else {
186
- this.useDefaultImg = true
187
- }
188
- }
189
- )
190
- },
191
- },
192
- }
193
- </script>
194
-
195
- <style scoped>
196
- .button,
197
- .button:hover,
198
- .button:focus {
199
- z-index: 10;
200
- font-family: Asap;
201
- font-size: 14px;
202
- font-weight: normal;
203
- font-stretch: normal;
204
- font-style: normal;
205
- line-height: normal;
206
- letter-spacing: normal;
207
- background-color: #8300bf;
208
- border: #8300bf;
209
- color: white;
210
- cursor: pointer;
211
- margin-top: 8px;
212
- }
213
-
214
- .button:hover {
215
- background: #8300bf;
216
- box-shadow: -3px 2px 4px 0 rgba(0, 0, 0, 0.25);
217
- color: #fff;
218
- }
219
-
220
- .card {
221
- position: relative;
222
- }
223
- .details {
224
- text-align: left;
225
- }
226
-
227
- .title {
228
- overflow-x: hidden;
229
- text-overflow: ellipsis;
230
- white-space: nowrap;
231
- }
232
-
233
- p.bold {
234
- font-weight: bold;
235
- }
236
-
237
- .image-overlay {
238
- position: absolute;
239
- top: 0;
240
- right: 0;
241
- }
242
-
243
- .triangle-icon {
244
- position: absolute;
245
- }
246
-
247
- .triangle-right-corner {
248
- width: 0;
249
- height: 0;
250
- border-left: solid transparent;
251
- border-top: solid #8300bf;
252
- }
253
- </style>
254
-
255
- <style>
256
- .gallery-popper {
257
- background: #f3ecf6 !important;
258
- border: 1px solid #8300bf;
259
- border-radius: 4px;
260
- color: #303133 !important;
261
- font-size: 12px;
262
- line-height: 1rem;
263
- height: 1rem;
264
- padding: 10px;
265
- }
266
- .gallery-popper.el-popper[x-placement^='top'] .popper__arrow {
267
- border-top-color: #8300bf !important;
268
- }
269
- .gallery-popper.el-popper[x-placement^='top'] .popper__arrow:after {
270
- border-top-color: #f3ecf6 !important;
271
- }
272
- </style>
1
+ <template>
2
+ <el-card :shadow="shadow" :body-style="bodyStyle" :style="{ padding: '0px', maxWidth: width + 'rem' }" class="card">
3
+ <div v-loading="!isReady">
4
+ <div :style="imageContainerStyle">
5
+ <img v-if="useDefaultImg" src="../assets/logo-sparc-wave-primary.svg" svg-inline :style="imageStyle" />
6
+ <img v-else :src="thumbnail" alt="thumbnail loading ..." :style="imageStyle" />
7
+ </div>
8
+ <div v-if="false" class="image-overlay">
9
+ <div
10
+ class="triangle-right-corner"
11
+ :style="`border-left-width: ${triangleHeight * 1.2}rem; border-top-width: ${triangleHeight}rem;`"
12
+ @click="openLinkInNewTab"
13
+ />
14
+ <el-tooltip class="item" :content="`View ${data.type}`" placement="left">
15
+ <img
16
+ class="triangle-icon"
17
+ :style="`height: ${triangleHeight * 0.25}rem;top: ${triangleHeight * 0.15}rem;right: ${triangleHeight * 0.15}rem`"
18
+ :src="typeIcon"
19
+ @click="openLinkInNewTab"
20
+ />
21
+ </el-tooltip>
22
+ </div>
23
+ <div v-if="showCardDetails" class="details">
24
+ <p v-if="!data.hideType">
25
+ <b>{{ data.type }}</b>
26
+ </p>
27
+ <el-popover
28
+ ref="galleryPopover"
29
+ :disabled="disableTooltip"
30
+ :content="data.title"
31
+ placement="top"
32
+ trigger="hover"
33
+ popper-class="gallery-popper"
34
+ />
35
+ <!--use v-show here to make sure el popover always have a starting location -->
36
+ <p v-show="!data.hideTitle" ref="titleText" v-popover:galleryPopover class="title">
37
+ {{ data.title }}
38
+ </p>
39
+ <p v-show="data.hideTitle" class="title text-placeholder" />
40
+ <el-button class="button" @click.prevent="cardClicked"> View {{ data.type }}</el-button>
41
+ </div>
42
+ </div>
43
+ </el-card>
44
+ </template>
45
+
46
+ <script>
47
+ // import { SvgIcon } from '@abi-software/svg-sprite'
48
+ import Vue from 'vue'
49
+ import { Button, Card, Popover } from 'element-ui'
50
+ import GalleryHelper from '../mixins/GalleryHelpers'
51
+ Vue.use(Button)
52
+ Vue.use(Card)
53
+ Vue.use(Popover)
54
+
55
+ function isValidHttpUrl(string) {
56
+ let url = undefined
57
+
58
+ try {
59
+ url = new URL(string)
60
+ } catch (_) {
61
+ return false
62
+ }
63
+ return url.protocol === 'http:' || url.protocol === 'https:'
64
+ }
65
+
66
+ export default {
67
+ name: 'GalleryCard',
68
+ mixins: [GalleryHelper],
69
+ props: {
70
+ data: {
71
+ type: Object,
72
+ required: true,
73
+ },
74
+ width: {
75
+ type: Number,
76
+ default: 3,
77
+ },
78
+ height: {
79
+ type: Number,
80
+ default: 3,
81
+ },
82
+ showCardDetails: {
83
+ type: Boolean,
84
+ },
85
+ bodyStyle: {
86
+ type: Object,
87
+ default: () => {
88
+ return { padding: '20px', background: '#ffffff' }
89
+ },
90
+ },
91
+ imageStyle: {
92
+ type: Object,
93
+ default: () => {
94
+ return {}
95
+ },
96
+ },
97
+ imageContainerStyle: {
98
+ type: Object,
99
+ default: () => {
100
+ return {}
101
+ },
102
+ },
103
+ shadow: {
104
+ type: String,
105
+ default: 'always',
106
+ },
107
+ },
108
+ data() {
109
+ return {
110
+ ro: null,
111
+ triangleSize: 4,
112
+ thumbnail: undefined,
113
+ useDefaultImg: false,
114
+ disableTooltip: false,
115
+ tooltipCalculated: false,
116
+ }
117
+ },
118
+ computed: {
119
+ isReady() {
120
+ return this.data.title && (this.thumbnail || this.useDefaultImg) && (this.data.link || this.data.userData)
121
+ },
122
+ imageHeight() {
123
+ return this.showCardDetails ? this.height * 0.525 : this.height
124
+ },
125
+ imageWidth() {
126
+ return this.width - 2 * this.marginDetails
127
+ },
128
+ triangleHeight() {
129
+ return this.height * 0.237
130
+ },
131
+ marginDetails() {
132
+ return this.height * 0.076
133
+ },
134
+ typeIcon() {
135
+ return undefined
136
+ },
137
+ },
138
+ watch: {
139
+ data: {
140
+ deep: true,
141
+ immediate: true,
142
+ handler: function () {
143
+ this.thumbnail = undefined
144
+ this.useDefaultImg = false
145
+ this.tooltipCalculated = false
146
+ this.disableTooltip = false
147
+ if (this.data.thumbnail) {
148
+ if (isValidHttpUrl(this.data.thumbnail) && this.data.mimetype) {
149
+ this.downloadThumbnail(this.data.thumbnail, { fetchAttempts: 0 })
150
+ } else {
151
+ this.thumbnail = this.data.thumbnail
152
+ }
153
+ } else {
154
+ this.useDefaultImg = true
155
+ }
156
+ //Dynamically check title length to determine if popover should be shown
157
+ this.$nextTick(() => {
158
+ this.calculateShowTooltip()
159
+ })
160
+ },
161
+ },
162
+ },
163
+ updated: function () {
164
+ if (!this.tooltipCalculated) {
165
+ this.$nextTick(() => {
166
+ this.calculateShowTooltip()
167
+ })
168
+ }
169
+ },
170
+ methods: {
171
+ /**
172
+ * Open a new link if link is provide.
173
+ * Fire an event if userData is provide.
174
+ */
175
+ cardClicked: function () {
176
+ if (this.data.link) {
177
+ const link = document.createElement('a')
178
+ link.href = this.data.link
179
+ link.target = '_blank'
180
+ document.body.appendChild(link)
181
+ link.click()
182
+ link.remove()
183
+ }
184
+ if (this.data.userData) {
185
+ this.$emit('card-clicked', this.data.userData)
186
+ }
187
+ },
188
+ /**
189
+ * handle thumbnail downloading,, it will use a default svg image if fails
190
+ */
191
+ downloadThumbnail: function (url, info) {
192
+ this.getRequest(url, {}, 11000)
193
+ .then(
194
+ (response) => {
195
+ let data = response.data
196
+ if (data.startsWith('data:')) {
197
+ this.thumbnail = response.data
198
+ } else {
199
+ if (this.data.mimetype) {
200
+ this.thumbnail = `data:${this.data.mimetype};base64,${response.data}`
201
+ } else {
202
+ this.thumbnail = response.data
203
+ }
204
+ }
205
+ },
206
+ (reason) => {
207
+ if (reason.message.includes('timeout') && reason.message.includes('exceeded') && info.fetchAttempts < 3) {
208
+ info.fetchAttempts += 1
209
+ this.downloadThumbnail(url, info)
210
+ } else {
211
+ this.useDefaultImg = true
212
+ }
213
+ }
214
+ )
215
+ .catch((error) => {
216
+ console.error(error)
217
+ this.useDefaultImg = true
218
+ })
219
+ },
220
+ //dynamically calculate if tooltip is required
221
+ calculateShowTooltip: function () {
222
+ if (this.data.hideTitle) {
223
+ this.disableTooltip = true
224
+ this.tooltipCalculated = true
225
+ } else {
226
+ const ele = this.$refs.titleText
227
+ //Check if title text is rendered yet
228
+ if (ele && ele.offsetParent) {
229
+ this.tooltipCalculated = true
230
+ if (ele.offsetWidth >= ele.scrollWidth) this.disableTooltip = true
231
+ else this.disableTooltip = false
232
+ } else {
233
+ //text not rendered yet
234
+ if (this.data.title.length > 20) this.disableTooltip = false
235
+ else this.disableTooltip = true
236
+ }
237
+ }
238
+ },
239
+ },
240
+ }
241
+ </script>
242
+
243
+ <style scoped>
244
+ .button,
245
+ .button:hover,
246
+ .button:focus {
247
+ z-index: 10;
248
+ font-family: Asap;
249
+ font-size: 14px;
250
+ font-weight: normal;
251
+ font-stretch: normal;
252
+ font-style: normal;
253
+ line-height: normal;
254
+ letter-spacing: normal;
255
+ background-color: #8300bf;
256
+ border: #8300bf;
257
+ color: white;
258
+ cursor: pointer;
259
+ margin-top: 8px;
260
+ }
261
+
262
+ .button:hover {
263
+ background: #8300bf;
264
+ box-shadow: -3px 2px 4px 0 rgba(0, 0, 0, 0.25);
265
+ color: #fff;
266
+ }
267
+
268
+ .card {
269
+ position: relative;
270
+ }
271
+ .details {
272
+ text-align: left;
273
+ }
274
+
275
+ .text-placeholder {
276
+ height: 1rem;
277
+ }
278
+
279
+ .title {
280
+ overflow-x: hidden;
281
+ text-overflow: ellipsis;
282
+ white-space: nowrap;
283
+ }
284
+
285
+ p.bold {
286
+ font-weight: bold;
287
+ }
288
+
289
+ .image-overlay {
290
+ position: absolute;
291
+ top: 0;
292
+ right: 0;
293
+ }
294
+
295
+ .triangle-icon {
296
+ position: absolute;
297
+ }
298
+
299
+ .triangle-right-corner {
300
+ width: 0;
301
+ height: 0;
302
+ border-left: solid transparent;
303
+ border-top: solid #8300bf;
304
+ }
305
+ </style>
306
+
307
+ <style>
308
+ .gallery-popper {
309
+ background: #f3ecf6 !important;
310
+ border: 1px solid #8300bf;
311
+ border-radius: 4px;
312
+ color: #303133 !important;
313
+ font-size: 12px;
314
+ line-height: 1rem;
315
+ height: 1rem;
316
+ padding: 10px;
317
+ }
318
+ .gallery-popper.el-popper[x-placement^='top'] .popper__arrow {
319
+ border-top-color: #8300bf !important;
320
+ }
321
+ .gallery-popper.el-popper[x-placement^='top'] .popper__arrow:after {
322
+ border-top-color: #f3ecf6 !important;
323
+ }
324
+ </style>