@abi-software/gallery 0.2.2 → 0.3.0-beta.2

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,208 +1,286 @@
1
- <template>
2
- <div ref="myButton" class="gallery">
3
- <div class="gallery-strip">
4
- <a href="#" :class="['oval', 'prev', { disabled: !isPrevPossible }]" @click.prevent="goPrev">
5
- <span class="progress-button">&lsaquo;</span>
6
- </a>
7
- <div class="filler" />
8
- <div class="card-line">
9
- <span v-for="(item, index) in windowedItems" :key="'span_' + index" :class="['key-image-span', { active: isActive(index) }]">
10
- <card v-if="item !== undefined" :key="'card_' + index" :entry="item" :width="cardWidth" :height="cardHeight" :show-card-details="showCardDetails" />
11
- </span>
12
- </div>
13
- <div class="filler" />
14
- <a href="#" :class="['oval', 'next', { disabled: !isNextPossible }]" @click.prevent="goNext">
15
- <span class="progress-button">&rsaquo;</span>
16
- </a>
17
- </div>
18
- <div v-if="canShowIndicatorBar" class="bottom-spacer" />
19
- <index-indicator v-if="canShowIndicatorBar" :count="itemCount" :current="currentIndex" @clicked="indicatorClicked" />
20
- </div>
21
- </template>
22
-
23
- <script>
24
- import IndexIndicator from './IndexIndicator'
25
- import Card from './Card'
26
-
27
- function convertRemToPixels(rem) {
28
- if (typeof window !== 'undefined') {
29
- return rem * parseFloat(window.getComputedStyle(document.documentElement).fontSize)
30
- }
31
- return rem * 16
32
- }
33
-
34
- export default {
35
- name: 'Gallery',
36
- components: { IndexIndicator, Card },
37
- props: {
38
- items: {
39
- type: Array,
40
- default: () => {
41
- return []
42
- },
43
- },
44
- maxWidth: {
45
- type: Number,
46
- default: 3
47
- },
48
- cardWidth: {
49
- type: Number,
50
- default: 13.8,
51
- },
52
- showIndicatorBar: {
53
- type: Boolean,
54
- default: true,
55
- },
56
- highlightActive: {
57
- type: Boolean,
58
- default: true,
59
- },
60
- showCardDetails: {
61
- type: Boolean,
62
- default: true,
63
- },
64
- metaData: {
65
- type: Object,
66
- default: () => {
67
- return {
68
- datasetVersion: -1,
69
- datasetId: -1,
70
- }
71
- },
72
- },
73
- description: {
74
- type: String,
75
- default: '',
76
- },
77
- },
78
- data() {
79
- return {
80
- count: 0,
81
- currentIndex: 0,
82
- controlHeight: 2,
83
- controlWidth: 2,
84
- }
85
- },
86
- computed: {
87
- itemCount() {
88
- return this.items.length
89
- },
90
- isPrevPossible() {
91
- return this.currentIndex > 0
92
- },
93
- isNextPossible() {
94
- return this.currentIndex < this.itemCount - 1
95
- },
96
- cardHeight() {
97
- return 0.78 * this.cardWidth
98
- },
99
- cardLineWidth() {
100
- const cardSpacing = 0.25
101
- return this.itemCount * (this.cardWidth + cardSpacing) - cardSpacing
102
- },
103
- numberOfItemsVisible() {
104
- // The maximum width we are allowed minus two buttons for next and previous
105
- // divided by the width of a card.
106
- // const n = this.itemCount - 1
107
- const cardSpacingPx = convertRemToPixels(0.5)
108
- const buttonPx = convertRemToPixels(2)
109
- const cardWidthPx = convertRemToPixels(this.cardWidth)
110
- const cardItems = (this.maxWidth - 2 * buttonPx - 2 * cardSpacingPx) / (1.1 * cardWidthPx)
111
- return Math.floor(cardItems)
112
- },
113
- canShowIndicatorBar() {
114
- const indicatorWidth = convertRemToPixels(1)
115
- const indicatorAllowance = this.maxWidth / (indicatorWidth * this.itemCount)
116
- return this.showIndicatorBar && indicatorAllowance > 0.1
117
- },
118
- valueAdjustment() {
119
- const halfWindow = Math.floor(this.numberOfItemsVisible / 2)
120
- let valueAdjust = this.currentIndex - halfWindow
121
- if (valueAdjust < 0) {
122
- valueAdjust = 0
123
- } else if (valueAdjust + this.numberOfItemsVisible > this.itemCount) {
124
- valueAdjust = this.itemCount - this.numberOfItemsVisible
125
- }
126
-
127
- return valueAdjust
128
- },
129
- windowedItems() {
130
- let myArray = []
131
- for (let i = 0; i < this.numberOfItemsVisible; i++) {
132
- myArray.push(this.items[i + this.valueAdjustment])
133
- }
134
- return myArray
135
- },
136
- },
137
- methods: {
138
- isActive(index) {
139
- return this.currentIndex - this.valueAdjustment === index && this.highlightActive
140
- },
141
- goNext() {
142
- this.currentIndex += 1
143
- },
144
- goPrev() {
145
- this.currentIndex -= 1
146
- },
147
- indicatorClicked(index) {
148
- if (this.currentIndex !== index) {
149
- this.currentIndex = index
150
- }
151
- },
152
- },
153
- }
154
- </script>
155
-
156
- <style scoped>
157
- .oval {
158
- width: 2rem;
159
- height: 2rem;
160
- line-height: 2rem;
161
- box-shadow: 0 0.125rem 0.25rem 0 rgba(0, 0, 0, 0.25);
162
- border: solid 1px var(--pale-grey);
163
- background-color: #ffffff;
164
- border-radius: 1rem;
165
- display: flex;
166
- justify-content: center;
167
- user-select: none;
168
- }
169
-
170
- .gallery-strip,
171
- .card-line {
172
- display: flex;
173
- flex-wrap: nowrap;
174
- justify-content: space-around;
175
- align-items: center;
176
- }
177
-
178
- .card-line {
179
- flex-grow: 2;
180
- }
181
-
182
- .progress-button {
183
- font-size: 1.5rem;
184
- font-weight: bold;
185
- }
186
-
187
- .bottom-spacer {
188
- min-height: 4rem;
189
- }
190
-
191
- .filler {
192
- flex-grow: 1;
193
- }
194
-
195
- .key-image-span.active {
196
- transform: scale(1.1);
197
- }
198
-
199
- a.prev:not(.underline),
200
- a.next:not(.underline) {
201
- text-decoration: none;
202
- }
203
-
204
- .disabled {
205
- opacity: 0.5;
206
- pointer-events: none;
207
- }
208
- </style>
1
+ <template>
2
+ <div ref="myButton" class="gallery">
3
+ <div class="gallery-strip">
4
+ <a v-if="items.length > 1" href="#" :class="['oval', 'prev', { disabled: !isPrevPossible }]" @click.prevent="goPrev">
5
+ <span class="progress-button">&lsaquo;</span>
6
+ </a>
7
+ <div v-else style="width: 2rem" />
8
+ <div class="filler" />
9
+ <div class="card-line">
10
+ <span v-for="(item, index) in windowedItems" :key="'card_' + index" :class="['key-image-span', { active: isActive(index) }]">
11
+ <card
12
+ :data="item"
13
+ :body-style="bodyStyle"
14
+ :image-container-style="imageContainerStyle"
15
+ :image-style="imageStyle"
16
+ :width="cardWidth"
17
+ :height="cardHeight"
18
+ :shadow="shadow"
19
+ :show-card-details="showCardDetails"
20
+ @card-clicked="cardClicked"
21
+ />
22
+ </span>
23
+ </div>
24
+ <div class="filler" />
25
+ <a v-if="items.length > 1" href="#" :class="['oval', 'next', { disabled: !isNextPossible }]" @click.prevent="goNext">
26
+ <span class="progress-button">&rsaquo;</span>
27
+ </a>
28
+ <div v-else style="width: 2rem" />
29
+ </div>
30
+ <div v-if="canShowIndicatorBar" :style="bottomSpacer" />
31
+ <index-indicator v-if="canShowIndicatorBar" :count="itemCount" :current="currentIndex" @clicked="indicatorClicked" />
32
+ </div>
33
+ </template>
34
+
35
+ <script>
36
+ import IndexIndicator from './IndexIndicator'
37
+ import Card from './Card'
38
+
39
+ function convertRemToPixels(rem) {
40
+ if (typeof window !== 'undefined') {
41
+ return rem * parseFloat(window.getComputedStyle(document.documentElement).fontSize)
42
+ }
43
+ return rem * 16
44
+ }
45
+
46
+ export default {
47
+ name: 'Gallery',
48
+ components: { IndexIndicator, Card },
49
+ props: {
50
+ items: {
51
+ type: Array,
52
+ default: () => {
53
+ return []
54
+ },
55
+ },
56
+ maxWidth: {
57
+ type: Number,
58
+ required: true,
59
+ },
60
+ cardWidth: {
61
+ type: Number,
62
+ default: 13.8,
63
+ },
64
+ showIndicatorBar: {
65
+ type: Boolean,
66
+ default: true,
67
+ },
68
+ highlightActive: {
69
+ type: Boolean,
70
+ default: true,
71
+ },
72
+ showCardDetails: {
73
+ type: Boolean,
74
+ default: true,
75
+ },
76
+ bodyStyle: {
77
+ type: Object,
78
+ default: () => {
79
+ return { padding: '20px', background: '#ffffff' }
80
+ },
81
+ },
82
+ bottomSpacer: {
83
+ type: Object,
84
+ default: () => {
85
+ return { minHeight: '4rem' }
86
+ },
87
+ },
88
+ imageContainerStyle: {
89
+ type: Object,
90
+ default: () => {
91
+ return {}
92
+ },
93
+ },
94
+ imageStyle: {
95
+ type: Object,
96
+ default: () => {
97
+ return {}
98
+ },
99
+ },
100
+ metaData: {
101
+ type: Object,
102
+ default: () => {
103
+ return {
104
+ datasetVersion: -1,
105
+ datasetId: -1,
106
+ }
107
+ },
108
+ },
109
+ description: {
110
+ type: String,
111
+ default: '',
112
+ },
113
+ shadow: {
114
+ type: String,
115
+ default: 'always',
116
+ },
117
+ },
118
+ data() {
119
+ return {
120
+ count: 0,
121
+ currentIndex: 0,
122
+ controlHeight: 2,
123
+ controlWidth: 2,
124
+ visibleIndecies: [],
125
+ }
126
+ },
127
+ computed: {
128
+ itemCount() {
129
+ return this.items.length
130
+ },
131
+ isPrevPossible() {
132
+ return this.currentIndex > 0
133
+ },
134
+ isNextPossible() {
135
+ return this.currentIndex < this.itemCount - 1
136
+ },
137
+ cardHeight() {
138
+ return 0.78 * this.cardWidth
139
+ },
140
+ cardLineWidth() {
141
+ const cardSpacing = 0.25
142
+ return this.itemCount * (this.cardWidth + cardSpacing) - cardSpacing
143
+ },
144
+ numberOfItemsVisible() {
145
+ // The maximum width we are allowed minus two buttons for next and previous
146
+ // divided by the width of a card.
147
+ // const n = this.itemCount - 1
148
+ const cardSpacingPx = convertRemToPixels(0.5)
149
+ const buttonPx = convertRemToPixels(2)
150
+ const cardWidthPx = convertRemToPixels(this.cardWidth)
151
+ const cardItems = (this.maxWidth - 2 * buttonPx - 2 * cardSpacingPx) / (1.1 * cardWidthPx)
152
+ return Math.max(1, Math.floor(cardItems))
153
+ },
154
+ canShowIndicatorBar() {
155
+ const indicatorWidth = convertRemToPixels(1)
156
+ const indicatorAllowance = this.maxWidth / (indicatorWidth * this.itemCount)
157
+ return this.showIndicatorBar && indicatorAllowance > 0.1 && this.itemCount > 1
158
+ },
159
+ valueAdjustment() {
160
+ const halfWindow = Math.floor(this.numberOfItemsVisible / 2)
161
+ let valueAdjust = this.currentIndex - halfWindow
162
+ if (valueAdjust < 0) {
163
+ valueAdjust = 0
164
+ } else if (valueAdjust + this.numberOfItemsVisible > this.itemCount) {
165
+ valueAdjust = this.itemCount - this.numberOfItemsVisible
166
+ }
167
+
168
+ return valueAdjust
169
+ },
170
+ windowedItems() {
171
+ let myArray = []
172
+ for (let i = 0; i < this.numberOfItemsVisible; i++) {
173
+ myArray.push(this.items[i + this.valueAdjustment])
174
+ }
175
+ return myArray
176
+ },
177
+ },
178
+ methods: {
179
+ cardClicked(payload) {
180
+ this.$emit('card-clicked', payload)
181
+ },
182
+ isActive(index) {
183
+ return this.currentIndex - this.valueAdjustment === index && this.highlightActive
184
+ },
185
+ isVisible(index) {
186
+ return this.visibleIndecies.includes(index)
187
+ },
188
+ goNext() {
189
+ this.currentIndex += 1
190
+ },
191
+ goPrev() {
192
+ this.currentIndex -= 1
193
+ },
194
+ indicatorClicked(index) {
195
+ if (this.currentIndex !== index) {
196
+ this.currentIndex = index
197
+ }
198
+ },
199
+ },
200
+ created() {
201
+ this._visibleIndecies = []
202
+ },
203
+ watch: {
204
+ currentIndex: {
205
+ handler: function () {
206
+ const oddImagesVisible = this.numberOfItemsVisible % 2 === 1
207
+ let halfVisible = this.numberOfItemsVisible / 2
208
+ if (oddImagesVisible) {
209
+ halfVisible = (this.numberOfItemsVisible - 1) / 2
210
+ }
211
+ let rawIndicies = [this.currentIndex]
212
+ for (let i = 1; i <= halfVisible; i++) {
213
+ rawIndicies.push(this.currentIndex + i)
214
+ rawIndicies.push(this.currentIndex - i)
215
+ }
216
+
217
+ if (!oddImagesVisible) {
218
+ rawIndicies.pop()
219
+ }
220
+ this.visibleIndecies = []
221
+ for (let v of rawIndicies) {
222
+ if (v < 0) {
223
+ this.visibleIndecies.push(v + this.numberOfItemsVisible)
224
+ } else if (v >= this.itemCount) {
225
+ this.visibleIndecies.push(v - this.numberOfItemsVisible)
226
+ } else {
227
+ this.visibleIndecies.push(v)
228
+ }
229
+ }
230
+ },
231
+ immediate: true,
232
+ },
233
+ },
234
+ }
235
+ </script>
236
+
237
+ <style scoped>
238
+ .oval {
239
+ width: 2rem;
240
+ height: 2rem;
241
+ line-height: 2rem;
242
+ box-shadow: 0 0.125rem 0.25rem 0 rgba(0, 0, 0, 0.25);
243
+ border: solid 1px var(--pale-grey);
244
+ background-color: #ffffff;
245
+ border-radius: 1rem;
246
+ display: flex;
247
+ justify-content: center;
248
+ user-select: none;
249
+ }
250
+
251
+ .gallery-strip,
252
+ .card-line {
253
+ display: flex;
254
+ flex-wrap: nowrap;
255
+ justify-content: space-around;
256
+ align-items: center;
257
+ }
258
+
259
+ .card-line {
260
+ flex-grow: 2;
261
+ }
262
+
263
+ .progress-button {
264
+ font-size: 1.5rem;
265
+ font-weight: bold;
266
+ color: #8300bf;
267
+ }
268
+
269
+ .filler {
270
+ flex-grow: 1;
271
+ }
272
+
273
+ .key-image-span.active {
274
+ transform: scale(1.1);
275
+ }
276
+
277
+ a.prev:not(.underline),
278
+ a.next:not(.underline) {
279
+ text-decoration: none;
280
+ }
281
+
282
+ .disabled {
283
+ opacity: 0.5;
284
+ pointer-events: none;
285
+ }
286
+ </style>
@@ -1,45 +1,45 @@
1
- <template>
2
- <div class="indicator-container">
3
- <div
4
- v-for="(number, index) in count"
5
- :key="'indicator_' + number"
6
- :class="['indicator', { active: current === index }]"
7
- @click="$emit('clicked', index)"
8
- />
9
- </div>
10
- </template>
11
-
12
- <script>
13
- export default {
14
- name: 'IndexIndicator',
15
- props: {
16
- count: {
17
- type: Number,
18
- default: 0,
19
- },
20
- current: {
21
- type: Number,
22
- default: 0,
23
- },
24
- },
25
- }
26
- </script>
27
-
28
- <style scoped>
29
- .indicator-container {
30
- display: flex;
31
- justify-content: center;
32
- }
33
- .indicator {
34
- width: 1rem;
35
- height: 1rem;
36
- border-radius: 50%;
37
- background-color: #e4e7ed;
38
- margin-left: 0.25rem;
39
- margin-right: 0.25rem;
40
- }
41
-
42
- .indicator.active {
43
- background-color: #8300bf;
44
- }
45
- </style>
1
+ <template>
2
+ <div class="indicator-container">
3
+ <div
4
+ v-for="(number, index) in count"
5
+ :key="'indicator_' + number"
6
+ :class="['indicator', { active: current === index }]"
7
+ @click="$emit('clicked', index)"
8
+ />
9
+ </div>
10
+ </template>
11
+
12
+ <script>
13
+ export default {
14
+ name: 'IndexIndicator',
15
+ props: {
16
+ count: {
17
+ type: Number,
18
+ default: 0,
19
+ },
20
+ current: {
21
+ type: Number,
22
+ default: 0,
23
+ },
24
+ },
25
+ }
26
+ </script>
27
+
28
+ <style scoped>
29
+ .indicator-container {
30
+ display: flex;
31
+ justify-content: center;
32
+ }
33
+ .indicator {
34
+ width: 1rem;
35
+ height: 1rem;
36
+ border-radius: 50%;
37
+ background-color: #e4e7ed;
38
+ margin-left: 0.25rem;
39
+ margin-right: 0.25rem;
40
+ }
41
+
42
+ .indicator.active {
43
+ background-color: #8300bf;
44
+ }
45
+ </style>
package/src/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import Gallery from './components/Gallery.vue'
2
- export default Gallery
1
+ import Gallery from './components/Gallery.vue'
2
+ export default Gallery
package/src/main.js CHANGED
@@ -1,8 +1,2 @@
1
- import Vue from 'vue'
2
- import App from './App.vue'
3
-
4
- Vue.config.productionTip = false
5
-
6
- new Vue({
7
- render: h => h(App),
8
- }).$mount('#app')
1
+ import Gallery from './components/Gallery.vue'
2
+ export default Gallery