@citizenplane/pimp 18.23.1 → 18.23.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.
- package/dist/components/CpAncillaryItem.vue.d.ts +4 -0
- package/dist/components/CpAncillaryItem.vue.d.ts.map +1 -1
- package/dist/pimp.es.js +1729 -1703
- package/dist/pimp.umd.js +40 -40
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/assets/images/ancillaries/airport-transfer.png +0 -0
- package/src/assets/images/ancillaries/bicycle.png +0 -0
- package/src/assets/images/ancillaries/cabin-bag.png +0 -0
- package/src/assets/images/ancillaries/checked-bag-size-1.png +0 -0
- package/src/assets/images/ancillaries/checked-bag-size-2.png +0 -0
- package/src/assets/images/ancillaries/checked-bag-size-3.png +0 -0
- package/src/assets/images/ancillaries/checked-bag.png +0 -0
- package/src/assets/images/ancillaries/connectivity.png +0 -0
- package/src/assets/images/ancillaries/diving-set.png +0 -0
- package/src/assets/images/ancillaries/extra-weight.png +0 -0
- package/src/assets/images/ancillaries/fast-track.png +0 -0
- package/src/assets/images/ancillaries/firearm.png +0 -0
- package/src/assets/images/ancillaries/fishing-rod.png +0 -0
- package/src/assets/images/ancillaries/golf.png +0 -0
- package/src/assets/images/ancillaries/hand-bag.png +0 -0
- package/src/assets/images/ancillaries/kite-surf.png +0 -0
- package/src/assets/images/ancillaries/lounge-access.png +0 -0
- package/src/assets/images/ancillaries/meet-and-greet.png +0 -0
- package/src/assets/images/ancillaries/music.png +0 -0
- package/src/assets/images/ancillaries/oversized.png +0 -0
- package/src/assets/images/ancillaries/pet-in-cabin.png +0 -0
- package/src/assets/images/ancillaries/pet-in-hold.png +0 -0
- package/src/assets/images/ancillaries/skis.png +0 -0
- package/src/assets/images/ancillaries/special-meal.png +0 -0
- package/src/assets/images/ancillaries/standard-meal.png +0 -0
- package/src/components/CpAncillaryItem.vue +165 -7
- package/src/stories/CpAncillaryItem.stories.ts +212 -6
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3,16 +3,31 @@
|
|
|
3
3
|
<div class="cpAncillaryItem__wrap">
|
|
4
4
|
<div class="cpAncillaryItem__visual">
|
|
5
5
|
<img v-if="ancillaryImage" alt="" class="cpAncillaryItem__image" :src="ancillaryImage" />
|
|
6
|
-
<cp-icon v-else class="cpAncillaryItem__fallbackIcon" size="
|
|
6
|
+
<cp-icon v-else class="cpAncillaryItem__fallbackIcon" :size="fallbackIconSize" type="shopping-bag" />
|
|
7
7
|
</div>
|
|
8
8
|
<div class="cpAncillaryItem__content">
|
|
9
9
|
<div class="cpAncillaryItem__name">
|
|
10
|
-
<
|
|
10
|
+
<div class="cpAncillaryItem__heading">
|
|
11
|
+
<p class="cpAncillaryItem__title">{{ title }}</p>
|
|
12
|
+
<p v-if="hasInlinePrice" class="cpAncillaryItem__bullet">•</p>
|
|
13
|
+
<p v-if="hasInlinePrice" class="cpAncillaryItem__inlinePrice">{{ formattedPrice }}</p>
|
|
14
|
+
</div>
|
|
11
15
|
<p class="cpAncillaryItem__description">{{ description }}</p>
|
|
12
16
|
<p v-if="subtitle" class="cpAncillaryItem__subtitle">{{ subtitle }}</p>
|
|
13
17
|
</div>
|
|
14
18
|
<div class="cpAncillaryItem__quantity">
|
|
19
|
+
<cp-button
|
|
20
|
+
v-if="isAddButtonVisible"
|
|
21
|
+
appearance="secondary"
|
|
22
|
+
class="cpAncillaryItem__addButton"
|
|
23
|
+
color="accent"
|
|
24
|
+
size="sm"
|
|
25
|
+
@click="selectFirstQuantity"
|
|
26
|
+
>
|
|
27
|
+
{{ addLabel }}
|
|
28
|
+
</cp-button>
|
|
15
29
|
<cp-quantity-counter
|
|
30
|
+
v-else
|
|
16
31
|
v-model="quantity"
|
|
17
32
|
class="cpAncillaryItem__counter"
|
|
18
33
|
:decrease-label="decreaseLabel"
|
|
@@ -20,9 +35,9 @@
|
|
|
20
35
|
:increase-label="increaseLabel"
|
|
21
36
|
:max="maxQuantity"
|
|
22
37
|
/>
|
|
23
|
-
<span v-if="
|
|
38
|
+
<span v-if="hasMaxQuantityCaption" class="cpAncillaryItem__maxQuantity">{{ maxQuantityLabel }}</span>
|
|
24
39
|
</div>
|
|
25
|
-
<p v-if="
|
|
40
|
+
<p v-if="hasStackedPrice" class="cpAncillaryItem__price">{{ formattedPrice }}</p>
|
|
26
41
|
</div>
|
|
27
42
|
</div>
|
|
28
43
|
</div>
|
|
@@ -31,6 +46,7 @@
|
|
|
31
46
|
<script setup lang="ts">
|
|
32
47
|
import { computed } from 'vue'
|
|
33
48
|
|
|
49
|
+
import CpButton from '@/components/CpButton.vue'
|
|
34
50
|
import CpIcon from '@/components/CpIcon.vue'
|
|
35
51
|
import CpQuantityCounter from '@/components/CpQuantityCounter.vue'
|
|
36
52
|
|
|
@@ -62,9 +78,11 @@ import StandardMealImage from '@/assets/images/ancillaries/standard-meal.png'
|
|
|
62
78
|
import { CpAncillaryItemTypes } from '@/constants/CpAncillaryItemTypes'
|
|
63
79
|
|
|
64
80
|
interface Props {
|
|
81
|
+
addLabel?: string
|
|
65
82
|
currency?: string
|
|
66
83
|
description: string
|
|
67
84
|
disableAnimation?: boolean
|
|
85
|
+
layout?: 'card' | 'list'
|
|
68
86
|
locale?: string
|
|
69
87
|
maxQuantity?: number | null
|
|
70
88
|
maxQuantityLabel?: string
|
|
@@ -76,6 +94,8 @@ interface Props {
|
|
|
76
94
|
}
|
|
77
95
|
|
|
78
96
|
const props = withDefaults(defineProps<Props>(), {
|
|
97
|
+
addLabel: 'Add',
|
|
98
|
+
layout: 'card',
|
|
79
99
|
locale: () => (typeof navigator === 'undefined' ? 'en' : navigator.language),
|
|
80
100
|
maxQuantity: null,
|
|
81
101
|
vertical: false,
|
|
@@ -116,16 +136,40 @@ const ancillaryImages: Partial<Record<CpAncillaryItemTypes, string>> = {
|
|
|
116
136
|
|
|
117
137
|
const ancillaryImage = computed(() => ancillaryImages[props.type] ?? null)
|
|
118
138
|
|
|
139
|
+
const isListLayout = computed(() => props.layout === 'list')
|
|
140
|
+
|
|
141
|
+
const fallbackIconSize = computed(() => {
|
|
142
|
+
if (isListLayout.value) return '28'
|
|
143
|
+
return '40'
|
|
144
|
+
})
|
|
145
|
+
|
|
119
146
|
const hasMaxQuantity = computed(() => props.maxQuantity !== null)
|
|
120
147
|
|
|
148
|
+
const hasMaxQuantityCaption = computed(() => hasMaxQuantity.value && !isListLayout.value)
|
|
149
|
+
|
|
150
|
+
const isAddButtonVisible = computed(() => quantity.value < 1)
|
|
151
|
+
|
|
152
|
+
const selectFirstQuantity = (): void => {
|
|
153
|
+
quantity.value = 1
|
|
154
|
+
}
|
|
155
|
+
|
|
121
156
|
const formattedPrice = computed(() => {
|
|
122
157
|
if (props.price === undefined || !props.currency) return null
|
|
123
158
|
return new Intl.NumberFormat(props.locale, { style: 'currency', currency: props.currency }).format(props.price / 100)
|
|
124
159
|
})
|
|
125
160
|
|
|
161
|
+
const hasPrice = computed(() => formattedPrice.value !== null)
|
|
162
|
+
|
|
163
|
+
const hasInlinePrice = computed(() => hasPrice.value && isListLayout.value)
|
|
164
|
+
|
|
165
|
+
const hasStackedPrice = computed(() => hasPrice.value && !isListLayout.value)
|
|
166
|
+
|
|
167
|
+
const isVerticalCard = computed(() => props.vertical && !isListLayout.value)
|
|
168
|
+
|
|
126
169
|
const isSelected = computed(() => quantity.value > 0)
|
|
127
170
|
const cpAncillaryItemDynamicClass = computed(() => ({
|
|
128
|
-
'cpAncillaryItem--
|
|
171
|
+
'cpAncillaryItem--isList': isListLayout.value,
|
|
172
|
+
'cpAncillaryItem--isVertical': isVerticalCard.value,
|
|
129
173
|
'cpAncillaryItem--isSelected': isSelected.value,
|
|
130
174
|
}))
|
|
131
175
|
</script>
|
|
@@ -256,7 +300,7 @@ const cpAncillaryItemDynamicClass = computed(() => ({
|
|
|
256
300
|
}
|
|
257
301
|
}
|
|
258
302
|
|
|
259
|
-
&--isSelected {
|
|
303
|
+
&--isSelected:not(#{&}--isList) {
|
|
260
304
|
border-color: var(--cp-border-accent-solid);
|
|
261
305
|
outline: fn.px-to-rem(1) solid var(--cp-border-accent-solid);
|
|
262
306
|
outline-offset: fn.px-to-rem(-2);
|
|
@@ -270,8 +314,122 @@ const cpAncillaryItemDynamicClass = computed(() => ({
|
|
|
270
314
|
}
|
|
271
315
|
}
|
|
272
316
|
|
|
317
|
+
&--isList {
|
|
318
|
+
padding: 0;
|
|
319
|
+
border: none;
|
|
320
|
+
border-radius: 0;
|
|
321
|
+
background: none;
|
|
322
|
+
container-type: inline-size;
|
|
323
|
+
|
|
324
|
+
.cpAncillaryItem__wrap {
|
|
325
|
+
align-items: center;
|
|
326
|
+
padding: var(--cp-spacing-lg) 0;
|
|
327
|
+
border-radius: 0;
|
|
328
|
+
border-bottom: fn.px-to-rem(1) solid var(--cp-border-soft);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.cpAncillaryItem__visual {
|
|
332
|
+
width: fn.px-to-rem(44);
|
|
333
|
+
height: fn.px-to-rem(44);
|
|
334
|
+
border-radius: 0;
|
|
335
|
+
background: none;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.cpAncillaryItem__image {
|
|
339
|
+
width: fn.px-to-rem(28);
|
|
340
|
+
height: fn.px-to-rem(28);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.cpAncillaryItem__content {
|
|
344
|
+
flex-direction: row;
|
|
345
|
+
align-items: center;
|
|
346
|
+
padding: 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.cpAncillaryItem__name {
|
|
350
|
+
flex: auto;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.cpAncillaryItem__heading {
|
|
354
|
+
display: flex;
|
|
355
|
+
flex-direction: column;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.cpAncillaryItem__title {
|
|
359
|
+
font-weight: 500;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.cpAncillaryItem__bullet,
|
|
363
|
+
.cpAncillaryItem__inlinePrice {
|
|
364
|
+
color: var(--cp-text-secondary);
|
|
365
|
+
font-size: var(--cp-text-size-md);
|
|
366
|
+
font-weight: 500;
|
|
367
|
+
line-height: var(--cp-text-md-line-height);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.cpAncillaryItem__bullet {
|
|
371
|
+
display: none;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.cpAncillaryItem__quantity {
|
|
375
|
+
flex: none;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
&:last-child .cpAncillaryItem__wrap {
|
|
379
|
+
border-bottom: none;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
@include mx.media-query-min(48rem) {
|
|
383
|
+
.cpAncillaryItem__heading {
|
|
384
|
+
flex-direction: row;
|
|
385
|
+
gap: var(--cp-spacing-sm);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.cpAncillaryItem__bullet {
|
|
389
|
+
display: block;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@container (width < 22rem) {
|
|
394
|
+
.cpAncillaryItem__wrap {
|
|
395
|
+
gap: var(--cp-spacing-sm);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.cpAncillaryItem__visual {
|
|
399
|
+
width: fn.px-to-rem(40);
|
|
400
|
+
height: fn.px-to-rem(40);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.cpAncillaryItem__image {
|
|
404
|
+
width: fn.px-to-rem(24);
|
|
405
|
+
height: fn.px-to-rem(24);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.cpAncillaryItem__content {
|
|
409
|
+
flex-wrap: wrap;
|
|
410
|
+
align-items: center;
|
|
411
|
+
gap: var(--cp-spacing-md);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.cpAncillaryItem__heading {
|
|
415
|
+
flex-direction: column;
|
|
416
|
+
gap: 0;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.cpAncillaryItem__bullet {
|
|
420
|
+
display: none;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.cpAncillaryItem__description,
|
|
424
|
+
.cpAncillaryItem__subtitle {
|
|
425
|
+
font-size: var(--cp-text-size-xs);
|
|
426
|
+
line-height: var(--cp-text-xs-line-height);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
273
431
|
@media (hover: hover) {
|
|
274
|
-
&:hover .cpAncillaryItem__image {
|
|
432
|
+
&:not(#{&}--isList):hover .cpAncillaryItem__image {
|
|
275
433
|
transform: scale3d(1.1, 1.1, 1);
|
|
276
434
|
}
|
|
277
435
|
}
|
|
@@ -8,10 +8,43 @@ import { docCellStyle, docLabelStyle, docRowWrapStyle } from '@/stories/document
|
|
|
8
8
|
|
|
9
9
|
const galleryCellStyle = `${docCellStyle} width: 260px;`
|
|
10
10
|
|
|
11
|
+
const listStackRows = [
|
|
12
|
+
{
|
|
13
|
+
title: 'Hand bag',
|
|
14
|
+
description: '5kg • 45 × 36 × 20 cm',
|
|
15
|
+
type: CpAncillaryItemTypes.HAND_BAG,
|
|
16
|
+
price: 990,
|
|
17
|
+
quantity: 0,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
title: 'Cabin bag',
|
|
21
|
+
description: '10kg • 55 × 36 × 25 cm',
|
|
22
|
+
type: CpAncillaryItemTypes.CABIN_BAG,
|
|
23
|
+
price: 1990,
|
|
24
|
+
quantity: 1,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
title: 'Checked bag',
|
|
28
|
+
description: '23kg • 158 cm total',
|
|
29
|
+
type: CpAncillaryItemTypes.CHECKED_BAG,
|
|
30
|
+
price: 2990,
|
|
31
|
+
quantity: 0,
|
|
32
|
+
},
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
const listCompactRows = listStackRows.slice(0, 2)
|
|
36
|
+
|
|
37
|
+
const listWrapStyle = 'padding: 20px 0; width: 358px;'
|
|
38
|
+
const listCompactWrapStyle = 'padding: 20px 0; width: 21rem;'
|
|
39
|
+
|
|
11
40
|
const meta = {
|
|
12
41
|
title: 'Business/CpAncillaryItem',
|
|
13
42
|
component: CpAncillaryItem,
|
|
14
43
|
argTypes: {
|
|
44
|
+
addLabel: {
|
|
45
|
+
control: 'text',
|
|
46
|
+
description: 'Label of the button shown while the quantity is 0',
|
|
47
|
+
},
|
|
15
48
|
currency: {
|
|
16
49
|
control: 'text',
|
|
17
50
|
description: 'ISO currency code used to format price',
|
|
@@ -20,6 +53,11 @@ const meta = {
|
|
|
20
53
|
control: 'text',
|
|
21
54
|
description: 'Description text for the ancillary',
|
|
22
55
|
},
|
|
56
|
+
layout: {
|
|
57
|
+
control: 'select',
|
|
58
|
+
options: ['card', 'list'],
|
|
59
|
+
description: 'Card renders the bordered tile, list renders a separated row',
|
|
60
|
+
},
|
|
23
61
|
locale: {
|
|
24
62
|
control: 'text',
|
|
25
63
|
description: 'Locale used to format price, defaults to the browser locale',
|
|
@@ -60,7 +98,8 @@ export default meta
|
|
|
60
98
|
type Story = StoryObj<typeof meta>
|
|
61
99
|
|
|
62
100
|
/**
|
|
63
|
-
* Default ancillary card.
|
|
101
|
+
* Default ancillary card. It starts on the Add button, which sets the quantity to 1
|
|
102
|
+
* and hands over to the counter. Use the controls to experiment with each prop in isolation.
|
|
64
103
|
*/
|
|
65
104
|
export const Default: Story = {
|
|
66
105
|
args: {
|
|
@@ -93,7 +132,8 @@ export const Default: Story = {
|
|
|
93
132
|
/* -------------------------------------------------------------------------- */
|
|
94
133
|
|
|
95
134
|
/**
|
|
96
|
-
* quantity > 0
|
|
135
|
+
* quantity > 0 replaces the Add button with the counter, adds the accent ring and
|
|
136
|
+
* swaps the counter background.
|
|
97
137
|
*/
|
|
98
138
|
export const Selected: Story = {
|
|
99
139
|
args: {
|
|
@@ -115,7 +155,7 @@ export const Selected: Story = {
|
|
|
115
155
|
}
|
|
116
156
|
|
|
117
157
|
/**
|
|
118
|
-
* No maxQuantity: the counter has no upper bound and the caption is hidden.
|
|
158
|
+
* No maxQuantity: once added, the counter has no upper bound and the caption is hidden.
|
|
119
159
|
*/
|
|
120
160
|
export const Uncapped: Story = {
|
|
121
161
|
args: {
|
|
@@ -227,6 +267,159 @@ export const VerticalOnMobile: Story = {
|
|
|
227
267
|
}),
|
|
228
268
|
}
|
|
229
269
|
|
|
270
|
+
/* -------------------------------------------------------------------------- */
|
|
271
|
+
/* List layout */
|
|
272
|
+
/* -------------------------------------------------------------------------- */
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* The list layout: no card frame, a 44px visual, title and price on one line and
|
|
276
|
+
* a soft bottom separator so stacked rows read as a list. maxQuantityLabel is not
|
|
277
|
+
* rendered here.
|
|
278
|
+
*/
|
|
279
|
+
export const List: Story = {
|
|
280
|
+
args: {
|
|
281
|
+
title: 'Hand bag',
|
|
282
|
+
description: '5kg • 45 × 36 × 20 cm',
|
|
283
|
+
type: CpAncillaryItemTypes.HAND_BAG,
|
|
284
|
+
quantity: 0,
|
|
285
|
+
maxQuantity: 10,
|
|
286
|
+
maxQuantityLabel: 'max. 10',
|
|
287
|
+
price: 990,
|
|
288
|
+
currency: 'EUR',
|
|
289
|
+
layout: 'list',
|
|
290
|
+
},
|
|
291
|
+
render: (args) => ({
|
|
292
|
+
components: { CpAncillaryItem },
|
|
293
|
+
setup() {
|
|
294
|
+
const quantity = ref(0)
|
|
295
|
+
return { args, quantity, listWrapStyle }
|
|
296
|
+
},
|
|
297
|
+
template: `
|
|
298
|
+
<div :style="listWrapStyle">
|
|
299
|
+
<CpAncillaryItem v-bind="args" v-model:quantity="quantity" />
|
|
300
|
+
</div>
|
|
301
|
+
`,
|
|
302
|
+
}),
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Selected list row: the counter replaces the Add button and the row keeps its
|
|
307
|
+
* plain background, without the accent ring the card gets.
|
|
308
|
+
*/
|
|
309
|
+
export const ListSelected: Story = {
|
|
310
|
+
args: {
|
|
311
|
+
...List.args,
|
|
312
|
+
quantity: 1,
|
|
313
|
+
},
|
|
314
|
+
render: (args) => ({
|
|
315
|
+
components: { CpAncillaryItem },
|
|
316
|
+
setup() {
|
|
317
|
+
const quantity = ref(1)
|
|
318
|
+
return { args, quantity, listWrapStyle }
|
|
319
|
+
},
|
|
320
|
+
template: `
|
|
321
|
+
<div :style="listWrapStyle">
|
|
322
|
+
<CpAncillaryItem v-bind="args" v-model:quantity="quantity" />
|
|
323
|
+
</div>
|
|
324
|
+
`,
|
|
325
|
+
}),
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Below the tablet breakpoint the title, the price and the description stack on
|
|
330
|
+
* three lines and the bullet disappears.
|
|
331
|
+
*/
|
|
332
|
+
export const ListOnMobile: Story = {
|
|
333
|
+
args: {
|
|
334
|
+
...List.args,
|
|
335
|
+
},
|
|
336
|
+
globals: {
|
|
337
|
+
viewport: { value: '390-844', isRotated: false },
|
|
338
|
+
},
|
|
339
|
+
render: (args) => ({
|
|
340
|
+
components: { CpAncillaryItem },
|
|
341
|
+
setup() {
|
|
342
|
+
const quantity = ref(0)
|
|
343
|
+
return { args, quantity, listWrapStyle }
|
|
344
|
+
},
|
|
345
|
+
template: `
|
|
346
|
+
<div :style="listWrapStyle">
|
|
347
|
+
<CpAncillaryItem v-bind="args" v-model:quantity="quantity" />
|
|
348
|
+
</div>
|
|
349
|
+
`,
|
|
350
|
+
}),
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Under 22rem of component width the row goes compact: a 4px gap to a 40px visual
|
|
355
|
+
* holding a 24px image, the details wrap with an 8px gap, and the description drops
|
|
356
|
+
* to 12px. Driven by the component's own width, so a 336px side panel switches while
|
|
357
|
+
* the wider list does not.
|
|
358
|
+
*/
|
|
359
|
+
export const ListCompact: Story = {
|
|
360
|
+
args: {
|
|
361
|
+
...List.args,
|
|
362
|
+
},
|
|
363
|
+
parameters: { controls: { disable: true } },
|
|
364
|
+
render: () => ({
|
|
365
|
+
components: { CpAncillaryItem },
|
|
366
|
+
setup() {
|
|
367
|
+
const rows = listCompactRows
|
|
368
|
+
const quantities = ref(Object.fromEntries(rows.map((row) => [row.type, row.quantity])))
|
|
369
|
+
return { rows, quantities, listCompactWrapStyle }
|
|
370
|
+
},
|
|
371
|
+
template: `
|
|
372
|
+
<div :style="listCompactWrapStyle">
|
|
373
|
+
<CpAncillaryItem
|
|
374
|
+
v-for="row in rows"
|
|
375
|
+
:key="row.type"
|
|
376
|
+
v-model:quantity="quantities[row.type]"
|
|
377
|
+
:title="row.title"
|
|
378
|
+
:description="row.description"
|
|
379
|
+
:type="row.type"
|
|
380
|
+
:price="row.price"
|
|
381
|
+
currency="EUR"
|
|
382
|
+
layout="list"
|
|
383
|
+
/>
|
|
384
|
+
</div>
|
|
385
|
+
`,
|
|
386
|
+
}),
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Several rows in a row, to show how the separators build a list. The last row drops
|
|
391
|
+
* its separator so the list does not end on a rule.
|
|
392
|
+
*/
|
|
393
|
+
export const ListStack: Story = {
|
|
394
|
+
args: {
|
|
395
|
+
...List.args,
|
|
396
|
+
},
|
|
397
|
+
parameters: { controls: { disable: true } },
|
|
398
|
+
render: () => ({
|
|
399
|
+
components: { CpAncillaryItem },
|
|
400
|
+
setup() {
|
|
401
|
+
const rows = listStackRows
|
|
402
|
+
const quantities = ref(Object.fromEntries(rows.map((row) => [row.type, row.quantity])))
|
|
403
|
+
return { rows, quantities, listWrapStyle }
|
|
404
|
+
},
|
|
405
|
+
template: `
|
|
406
|
+
<div :style="listWrapStyle">
|
|
407
|
+
<CpAncillaryItem
|
|
408
|
+
v-for="row in rows"
|
|
409
|
+
:key="row.type"
|
|
410
|
+
v-model:quantity="quantities[row.type]"
|
|
411
|
+
:title="row.title"
|
|
412
|
+
:description="row.description"
|
|
413
|
+
:type="row.type"
|
|
414
|
+
:price="row.price"
|
|
415
|
+
currency="EUR"
|
|
416
|
+
layout="list"
|
|
417
|
+
/>
|
|
418
|
+
</div>
|
|
419
|
+
`,
|
|
420
|
+
}),
|
|
421
|
+
}
|
|
422
|
+
|
|
230
423
|
/* -------------------------------------------------------------------------- */
|
|
231
424
|
/* Gallery */
|
|
232
425
|
/* -------------------------------------------------------------------------- */
|
|
@@ -244,15 +437,27 @@ export const Gallery: Story = {
|
|
|
244
437
|
components: { CpAncillaryItem },
|
|
245
438
|
setup() {
|
|
246
439
|
const types = Object.values(CpAncillaryItemTypes)
|
|
247
|
-
const
|
|
248
|
-
|
|
440
|
+
const cardQuantities = ref(Object.fromEntries(types.map((type) => [type, 0])))
|
|
441
|
+
const listQuantities = ref(Object.fromEntries(types.map((type) => [type, 0])))
|
|
442
|
+
return { types, cardQuantities, listQuantities, galleryCellStyle, docLabelStyle, docRowWrapStyle }
|
|
249
443
|
},
|
|
250
444
|
template: `
|
|
251
445
|
<div :style="docRowWrapStyle">
|
|
252
446
|
<div v-for="type in types" :key="type" :style="galleryCellStyle">
|
|
253
447
|
<span :style="docLabelStyle">{{ type }}</span>
|
|
254
448
|
<CpAncillaryItem
|
|
255
|
-
v-model:quantity="
|
|
449
|
+
v-model:quantity="cardQuantities[type]"
|
|
450
|
+
:title="type"
|
|
451
|
+
description="Sample description"
|
|
452
|
+
:type="type"
|
|
453
|
+
:max-quantity="5"
|
|
454
|
+
max-quantity-label="max. 5"
|
|
455
|
+
:price="1000"
|
|
456
|
+
currency="EUR"
|
|
457
|
+
/>
|
|
458
|
+
<span :style="docLabelStyle">{{ type }} — list</span>
|
|
459
|
+
<CpAncillaryItem
|
|
460
|
+
v-model:quantity="listQuantities[type]"
|
|
256
461
|
:title="type"
|
|
257
462
|
description="Sample description"
|
|
258
463
|
:type="type"
|
|
@@ -260,6 +465,7 @@ export const Gallery: Story = {
|
|
|
260
465
|
max-quantity-label="max. 5"
|
|
261
466
|
:price="1000"
|
|
262
467
|
currency="EUR"
|
|
468
|
+
layout="list"
|
|
263
469
|
/>
|
|
264
470
|
</div>
|
|
265
471
|
</div>
|