@citizenplane/pimp 18.10.2 → 18.11.0

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.
Files changed (94) hide show
  1. package/dist/components/CpSeatMap.vue.d.ts +29 -0
  2. package/dist/components/CpSeatMap.vue.d.ts.map +1 -0
  3. package/dist/components/CpSeatMapEmergencyExitDialog.vue.d.ts +21 -0
  4. package/dist/components/CpSeatMapEmergencyExitDialog.vue.d.ts.map +1 -0
  5. package/dist/components/CpSeatMapGrid.vue.d.ts +17 -0
  6. package/dist/components/CpSeatMapGrid.vue.d.ts.map +1 -0
  7. package/dist/components/CpSeatMapPlane.vue.d.ts +24 -0
  8. package/dist/components/CpSeatMapPlane.vue.d.ts.map +1 -0
  9. package/dist/components/CpSeatMapRow.vue.d.ts +22 -0
  10. package/dist/components/CpSeatMapRow.vue.d.ts.map +1 -0
  11. package/dist/components/CpSeatMapRowFacility.vue.d.ts +16 -0
  12. package/dist/components/CpSeatMapRowFacility.vue.d.ts.map +1 -0
  13. package/dist/components/CpSeatMapSeat.vue.d.ts +21 -0
  14. package/dist/components/CpSeatMapSeat.vue.d.ts.map +1 -0
  15. package/dist/components/CpSeatMapSeatWrapper.vue.d.ts +23 -0
  16. package/dist/components/CpSeatMapSeatWrapper.vue.d.ts.map +1 -0
  17. package/dist/components/CpSeatMapZone.vue.d.ts +16 -0
  18. package/dist/components/CpSeatMapZone.vue.d.ts.map +1 -0
  19. package/dist/components/CpTabs.vue.d.ts.map +1 -1
  20. package/dist/components/icons/IconPlaneNose.vue.d.ts +3 -0
  21. package/dist/components/icons/IconPlaneNose.vue.d.ts.map +1 -0
  22. package/dist/components/icons/IconPlaneWing.vue.d.ts +3 -0
  23. package/dist/components/icons/IconPlaneWing.vue.d.ts.map +1 -0
  24. package/dist/components/icons/IconSparkle.vue.d.ts +3 -0
  25. package/dist/components/icons/IconSparkle.vue.d.ts.map +1 -0
  26. package/dist/components/index.d.ts +14 -1
  27. package/dist/components/index.d.ts.map +1 -1
  28. package/dist/constants/seatMap/CpSeatMapConfig.d.ts +22 -0
  29. package/dist/constants/seatMap/CpSeatMapConfig.d.ts.map +1 -0
  30. package/dist/constants/seatMap/CpSeatMapSeatSelection.d.ts +12 -0
  31. package/dist/constants/seatMap/CpSeatMapSeatSelection.d.ts.map +1 -0
  32. package/dist/constants/seatMap/CpSeatMapTransitionDirections.d.ts +5 -0
  33. package/dist/constants/seatMap/CpSeatMapTransitionDirections.d.ts.map +1 -0
  34. package/dist/constants/seatMap/IataTravelerTypes.d.ts +7 -0
  35. package/dist/constants/seatMap/IataTravelerTypes.d.ts.map +1 -0
  36. package/dist/constants/seatMap/Seat.d.ts +18 -0
  37. package/dist/constants/seatMap/Seat.d.ts.map +1 -0
  38. package/dist/constants/seatMap/SeatAncillary.d.ts +9 -0
  39. package/dist/constants/seatMap/SeatAncillary.d.ts.map +1 -0
  40. package/dist/constants/seatMap/SeatCharacteristic.d.ts +7 -0
  41. package/dist/constants/seatMap/SeatCharacteristic.d.ts.map +1 -0
  42. package/dist/constants/seatMap/SeatCharacteristicCodes.d.ts +10 -0
  43. package/dist/constants/seatMap/SeatCharacteristicCodes.d.ts.map +1 -0
  44. package/dist/constants/seatMap/SeatMap.d.ts +10 -0
  45. package/dist/constants/seatMap/SeatMap.d.ts.map +1 -0
  46. package/dist/constants/seatMap/SeatMapZone.d.ts +6 -0
  47. package/dist/constants/seatMap/SeatMapZone.d.ts.map +1 -0
  48. package/dist/constants/seatMap/SeatRow.d.ts +15 -0
  49. package/dist/constants/seatMap/SeatRow.d.ts.map +1 -0
  50. package/dist/constants/seatMap/SeatRowFacilities.d.ts +10 -0
  51. package/dist/constants/seatMap/SeatRowFacilities.d.ts.map +1 -0
  52. package/dist/constants/seatMap/SeatRowFacilityFlags.d.ts +8 -0
  53. package/dist/constants/seatMap/SeatRowFacilityFlags.d.ts.map +1 -0
  54. package/dist/constants/seatMap/SeatStatuses.d.ts +8 -0
  55. package/dist/constants/seatMap/SeatStatuses.d.ts.map +1 -0
  56. package/dist/constants/seatMap/index.d.ts +16 -0
  57. package/dist/constants/seatMap/index.d.ts.map +1 -0
  58. package/dist/helpers/seatMap.d.ts +28 -0
  59. package/dist/helpers/seatMap.d.ts.map +1 -0
  60. package/dist/pimp.es.js +4633 -4130
  61. package/dist/pimp.umd.js +40 -40
  62. package/dist/style.css +1 -1
  63. package/package.json +1 -1
  64. package/src/components/CpSeatMap.vue +226 -0
  65. package/src/components/CpSeatMapEmergencyExitDialog.vue +87 -0
  66. package/src/components/CpSeatMapGrid.vue +41 -0
  67. package/src/components/CpSeatMapPlane.vue +221 -0
  68. package/src/components/CpSeatMapRow.vue +183 -0
  69. package/src/components/CpSeatMapRowFacility.vue +88 -0
  70. package/src/components/CpSeatMapSeat.vue +138 -0
  71. package/src/components/CpSeatMapSeatWrapper.vue +189 -0
  72. package/src/components/CpSeatMapZone.vue +60 -0
  73. package/src/components/CpTabs.vue +25 -15
  74. package/src/components/icons/IconPlaneNose.vue +39 -0
  75. package/src/components/icons/IconPlaneWing.vue +11 -0
  76. package/src/components/icons/IconSparkle.vue +8 -0
  77. package/src/components/index.ts +51 -0
  78. package/src/constants/seatMap/CpSeatMapConfig.ts +47 -0
  79. package/src/constants/seatMap/CpSeatMapSeatSelection.ts +12 -0
  80. package/src/constants/seatMap/CpSeatMapTransitionDirections.ts +4 -0
  81. package/src/constants/seatMap/IataTravelerTypes.ts +6 -0
  82. package/src/constants/seatMap/Seat.ts +18 -0
  83. package/src/constants/seatMap/SeatAncillary.ts +8 -0
  84. package/src/constants/seatMap/SeatCharacteristic.ts +7 -0
  85. package/src/constants/seatMap/SeatCharacteristicCodes.ts +9 -0
  86. package/src/constants/seatMap/SeatMap.ts +10 -0
  87. package/src/constants/seatMap/SeatMapZone.ts +5 -0
  88. package/src/constants/seatMap/SeatRow.ts +15 -0
  89. package/src/constants/seatMap/SeatRowFacilities.ts +10 -0
  90. package/src/constants/seatMap/SeatRowFacilityFlags.ts +7 -0
  91. package/src/constants/seatMap/SeatStatuses.ts +7 -0
  92. package/src/constants/seatMap/index.ts +16 -0
  93. package/src/helpers/seatMap.ts +76 -0
  94. package/src/stories/CpSeatMap.stories.ts +357 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@citizenplane/pimp",
3
- "version": "18.10.2",
3
+ "version": "18.11.0",
4
4
  "scripts": {
5
5
  "dev": "storybook dev -p 8081",
6
6
  "build-storybook": "storybook build --output-dir ./docs",
@@ -0,0 +1,226 @@
1
+ <template>
2
+ <div class="cpSeatMap" :style="seatMapDynamicStyle" :class="seatMapClasses">
3
+ <cp-seat-map-plane
4
+ :key="seatMap.aircraft"
5
+ class="cpSeatMap__plane"
6
+ :is-large="isLargePlane"
7
+ :map-key="seatMap.ref_id_segment"
8
+ :transition-direction="transitionDirection"
9
+ >
10
+ <cp-seat-map-zone v-for="zone in zones" :key="zone.id" class="cpSeatMap__zone" :title="zone.title">
11
+ <cp-seat-map-grid class="cpSeatMap__grid" :layout="zone.layout" :style="getGridDynamicStyle(zone.layout)">
12
+ <cp-seat-map-row
13
+ v-for="row in getZoneRows(seatMap, zone.id)"
14
+ :key="row.number"
15
+ class="cpSeatMap__row"
16
+ :config="config"
17
+ :row="row"
18
+ :seat-block-size="getSeatBlockSize(zone.layout)"
19
+ >
20
+ <cp-seat-map-seat-wrapper
21
+ v-for="seat in row.seats"
22
+ :key="seat.id"
23
+ :config="config"
24
+ :is-highlighted="highlightedSeatId === seat.id"
25
+ :is-selection-enabled="isSelectionEnabled"
26
+ :row-number="row.number"
27
+ :seat="seat"
28
+ :selection="getSeatSelection(row.number, seat.column)"
29
+ :style="getSeatDynamicStyle(seat)"
30
+ @select="handleSelectSeat"
31
+ />
32
+ <template v-if="hasHallway(zone.layout)">
33
+ <span
34
+ v-for="hallway in getHallways(zone.layout)"
35
+ :key="hallway.index"
36
+ class="cpSeatMap__hallway"
37
+ :style="getHallwayDynamicStyle(hallway.index)"
38
+ >
39
+ {{ row.number }}
40
+ </span>
41
+ </template>
42
+ </cp-seat-map-row>
43
+ </cp-seat-map-grid>
44
+ </cp-seat-map-zone>
45
+ </cp-seat-map-plane>
46
+
47
+ <cp-seat-map-emergency-exit-dialog
48
+ v-model:is-visible="isEmergencyExitDialogVisible"
49
+ :config="config"
50
+ @close="handleCloseEmergencyExitDialog"
51
+ @confirm="handleConfirmEmergencyExit"
52
+ />
53
+ </div>
54
+ </template>
55
+
56
+ <script setup lang="ts">
57
+ import { computed, ref } from 'vue'
58
+
59
+ import type { CpSeatMapConfig } from '@/constants/seatMap/CpSeatMapConfig'
60
+ import type { CpSeatMapSeatSelection } from '@/constants/seatMap/CpSeatMapSeatSelection'
61
+ import type { Seat } from '@/constants/seatMap/Seat'
62
+ import type { SeatMap } from '@/constants/seatMap/SeatMap'
63
+
64
+ import { DEFAULT_CP_SEAT_MAP_CONFIG } from '@/constants/seatMap/CpSeatMapConfig'
65
+ import { CpSeatMapTransitionDirections } from '@/constants/seatMap/CpSeatMapTransitionDirections'
66
+ import {
67
+ displaySeat,
68
+ getGridTemplateAreas,
69
+ getGridTemplateColumns,
70
+ getHallways,
71
+ getSeatBlockSize,
72
+ getSeatMapZones,
73
+ getZoneRows,
74
+ hasHallway,
75
+ isLargeSeatMap,
76
+ type SeatMapLayout,
77
+ } from '@/helpers/seatMap'
78
+ import CpSeatMapEmergencyExitDialog from './CpSeatMapEmergencyExitDialog.vue'
79
+ import CpSeatMapGrid from './CpSeatMapGrid.vue'
80
+ import CpSeatMapPlane from './CpSeatMapPlane.vue'
81
+ import CpSeatMapRow from './CpSeatMapRow.vue'
82
+ import CpSeatMapSeatWrapper from './CpSeatMapSeatWrapper.vue'
83
+ import CpSeatMapZone from './CpSeatMapZone.vue'
84
+
85
+ interface Props {
86
+ config?: CpSeatMapConfig
87
+ /** Seat id to pulse — the consumer bumps it to draw the eye to a seat. */
88
+ highlightedSeatId?: number | null
89
+ /** Seats are inert until the consumer has something to seat. */
90
+ isSelectionEnabled?: boolean
91
+ seatMap: SeatMap
92
+ /** Seats the consumer has assigned, keyed as `12A` (see `displaySeat`). */
93
+ selections?: Record<string, CpSeatMapSeatSelection>
94
+ transitionDirection?: CpSeatMapTransitionDirections
95
+ }
96
+
97
+ const props = withDefaults(defineProps<Props>(), {
98
+ config: () => DEFAULT_CP_SEAT_MAP_CONFIG,
99
+ highlightedSeatId: null,
100
+ isSelectionEnabled: true,
101
+ selections: () => ({}),
102
+ transitionDirection: CpSeatMapTransitionDirections.FORWARD,
103
+ })
104
+
105
+ const emit = defineEmits<{ select: [seat: Seat, rowNumber: number] }>()
106
+
107
+ const isEmergencyExitDialogVisible = ref(false)
108
+ const pendingExitRowSeat = ref<{ rowNumber: number; seat: Seat } | null>(null)
109
+
110
+ const zones = computed(() => getSeatMapZones(props.seatMap))
111
+
112
+ const isLargePlane = computed(() => isLargeSeatMap(zones.value))
113
+
114
+ const seatMapClasses = computed(() => {
115
+ return { 'cpSeatMap--isLarge': isLargePlane.value }
116
+ })
117
+
118
+ const seatMapDynamicStyle = computed(() => {
119
+ return {
120
+ '--seat-mobile-width': isLargePlane.value ? '32px' : '40px',
121
+ '--hallway-mobile-width': isLargePlane.value ? '16px' : '32px',
122
+ }
123
+ })
124
+
125
+ const getGridDynamicStyle = (layout: SeatMapLayout) => {
126
+ return {
127
+ '--columns-count': layout.length,
128
+ '--grid-template-areas': `"${getGridTemplateAreas(layout)}"`,
129
+ '--grid-template-columns': getGridTemplateColumns(layout),
130
+ }
131
+ }
132
+
133
+ const getSeatSelection = (rowNumber: number, column: string) => {
134
+ return props.selections[displaySeat({ row: rowNumber, column })] ?? null
135
+ }
136
+
137
+ const getSeatDynamicStyle = (seat: Seat) => {
138
+ return {
139
+ gridColumn: seat.column,
140
+ }
141
+ }
142
+
143
+ const getHallwayDynamicStyle = (hallwayIndex: number) => {
144
+ return {
145
+ gridArea: `HALLWAY-${hallwayIndex}`,
146
+ }
147
+ }
148
+
149
+ // Exit rows need an acknowledgement before the seat leaves this component; every
150
+ // other seat is emitted straight away. No selection state is held here.
151
+ const handleSelectSeat = (seat: Seat, rowNumber: number) => {
152
+ if (seat.is_exit_row) {
153
+ pendingExitRowSeat.value = { rowNumber, seat }
154
+ isEmergencyExitDialogVisible.value = true
155
+ return
156
+ }
157
+
158
+ emit('select', seat, rowNumber)
159
+ }
160
+
161
+ const handleCloseEmergencyExitDialog = () => {
162
+ isEmergencyExitDialogVisible.value = false
163
+ pendingExitRowSeat.value = null
164
+ }
165
+
166
+ const handleConfirmEmergencyExit = () => {
167
+ if (pendingExitRowSeat.value) {
168
+ const { seat, rowNumber } = pendingExitRowSeat.value
169
+ emit('select', seat, rowNumber)
170
+ }
171
+
172
+ handleCloseEmergencyExitDialog()
173
+ }
174
+ </script>
175
+
176
+ <style lang="scss">
177
+ .cpSeatMap {
178
+ --hallway-width: 32px;
179
+ --seat-width: 32px;
180
+
181
+ position: relative;
182
+ min-height: 75vh;
183
+
184
+ &__grid > div {
185
+ grid-template-areas: var(--grid-template-areas);
186
+ grid-template-columns: var(--grid-template-columns);
187
+ }
188
+
189
+ &__hallway {
190
+ font-size: fn.px-to-em(12);
191
+ font-weight: 700;
192
+ letter-spacing: fn.px-to-rem(2);
193
+ line-height: fn.px-to-rem(24);
194
+ text-transform: uppercase;
195
+ }
196
+
197
+ &__row:has(.cpSeatMapRowFacility--isTop) .cpSeatMap__hallway {
198
+ grid-row: 2 !important;
199
+ place-self: end center;
200
+ }
201
+
202
+ &__zone {
203
+ position: relative;
204
+ z-index: 1;
205
+ }
206
+ }
207
+
208
+ @include mx.media-query-max(551px) {
209
+ .cpSeatMap {
210
+ --seat-width: var(--seat-mobile-width);
211
+ --hallway-width: var(--hallway-mobile-width);
212
+
213
+ &:not(&--isLarge) &__grid > div {
214
+ gap: var(--cp-spacing-md);
215
+ }
216
+
217
+ &__plane .cpSeatMapPlane__plane {
218
+ display: none;
219
+ }
220
+
221
+ &__hallway {
222
+ font-size: fn.px-to-em(10);
223
+ }
224
+ }
225
+ }
226
+ </style>
@@ -0,0 +1,87 @@
1
+ <template>
2
+ <cp-dynamic-dialog
3
+ v-model:is-visible="isVisible"
4
+ class="cpSeatMapEmergencyExitDialog"
5
+ :max-width="450"
6
+ :title="config.emergencyExit.title"
7
+ @close="emit('close')"
8
+ >
9
+ <div class="cpSeatMapEmergencyExitDialog__content">
10
+ <p class="cpSeatMapEmergencyExitDialog__description">{{ config.emergencyExit.subtitle }}</p>
11
+ <cp-alert color="warning" :title="config.emergencyExit.disclaimerTitle">
12
+ <p>{{ config.emergencyExit.disclaimerContent }}</p>
13
+ </cp-alert>
14
+ </div>
15
+
16
+ <template #footer>
17
+ <div class="cpSeatMapEmergencyExitDialog__footer">
18
+ <cp-button appearance="secondary" class="cpSeatMapEmergencyExitDialog__close" @click="emit('close')">
19
+ {{ config.emergencyExit.close }}
20
+ </cp-button>
21
+ <cp-button color="success" @click="emit('confirm')">
22
+ {{ config.emergencyExit.confirm }}
23
+ </cp-button>
24
+ </div>
25
+ </template>
26
+ </cp-dynamic-dialog>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import type { CpSeatMapConfig } from '@/constants/seatMap/CpSeatMapConfig'
31
+
32
+ import { DEFAULT_CP_SEAT_MAP_CONFIG } from '@/constants/seatMap/CpSeatMapConfig'
33
+ import CpAlert from './CpAlert.vue'
34
+ import CpButton from './CpButton.vue'
35
+ import CpDynamicDialog from './CpDynamicDialog.vue'
36
+
37
+ interface Props {
38
+ config?: CpSeatMapConfig
39
+ }
40
+
41
+ withDefaults(defineProps<Props>(), {
42
+ config: () => DEFAULT_CP_SEAT_MAP_CONFIG,
43
+ })
44
+
45
+ const emit = defineEmits<{
46
+ close: []
47
+ confirm: []
48
+ }>()
49
+
50
+ const isVisible = defineModel<boolean>('isVisible', { default: false })
51
+ </script>
52
+
53
+ <style lang="scss">
54
+ html:has([data-vsbs-backdrop], .cpSeatMapEmergencyExitDialog) [data-vsbs-backdrop] {
55
+ z-index: 1;
56
+ }
57
+
58
+ [data-vsbs-sheet]:has(.cpSeatMapEmergencyExitDialog) {
59
+ z-index: 2;
60
+ }
61
+
62
+ .cpSeatMapEmergencyExitDialog {
63
+ &__content {
64
+ display: flex;
65
+ flex-direction: column;
66
+ gap: var(--cp-spacing-lg);
67
+ }
68
+
69
+ &__description {
70
+ color: var(--cp-text-secondary);
71
+ font-size: var(--cp-text-size-sm);
72
+ line-height: var(--cp-line-height-sm);
73
+ }
74
+
75
+ &__footer {
76
+ display: flex;
77
+ width: 100%;
78
+ align-items: center;
79
+ justify-content: space-between;
80
+ gap: var(--cp-spacing-xl);
81
+
82
+ > * {
83
+ flex: 1;
84
+ }
85
+ }
86
+ }
87
+ </style>
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <div class="cpSeatMapGrid">
3
+ <div class="cpSeatMapGrid__columns">
4
+ <span v-for="(column, index) in layout" :key="index" class="cpSeatMapGrid__column">
5
+ {{ column }}
6
+ </span>
7
+ </div>
8
+ <slot />
9
+ </div>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import type { SeatMapLayout } from '@/helpers/seatMap'
14
+
15
+ interface Props {
16
+ layout: SeatMapLayout
17
+ }
18
+
19
+ defineProps<Props>()
20
+ </script>
21
+
22
+ <style lang="scss">
23
+ .cpSeatMapGrid {
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ justify-content: center;
28
+ gap: var(--cp-spacing-md);
29
+
30
+ &__columns {
31
+ display: grid;
32
+ font-size: fn.px-to-em(12);
33
+ font-weight: 700;
34
+ gap: var(--cp-spacing-md);
35
+ letter-spacing: fn.px-to-rem(2);
36
+ line-height: fn.px-to-rem(24);
37
+ text-align: center;
38
+ text-transform: uppercase;
39
+ }
40
+ }
41
+ </style>
@@ -0,0 +1,221 @@
1
+ <template>
2
+ <div class="cpSeatMapPlane" :class="planeDynamicClass">
3
+ <div class="cpSeatMapPlane__plane">
4
+ <icon-plane-nose class="cpSeatMapPlane__nose" />
5
+ <icon-plane-wing class="cpSeatMapPlane__wing cpSeatMapPlane__wing--isLeft" />
6
+ <icon-plane-wing class="cpSeatMapPlane__wing cpSeatMapPlane__wing--isRight" />
7
+ </div>
8
+
9
+ <div class="cpSeatMapPlane__body">
10
+ <div class="cpSeatMapPlane__cabin">
11
+ <transition mode="out-in" :name="dynamicTransitionName">
12
+ <div :key="mapKey" class="cpSeatMapPlane__content">
13
+ <slot />
14
+ </div>
15
+ </transition>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { computed } from 'vue'
23
+
24
+ import { useIsBreakpoint } from '@/composables/useIsBreakpoint'
25
+
26
+ import { CpSeatMapTransitionDirections } from '@/constants/seatMap/CpSeatMapTransitionDirections'
27
+ import IconPlaneNose from './icons/IconPlaneNose.vue'
28
+ import IconPlaneWing from './icons/IconPlaneWing.vue'
29
+
30
+ interface Props {
31
+ isLarge?: boolean
32
+ /** Changing this replays the cabin transition — pass the current segment id. */
33
+ mapKey?: string
34
+ transitionDirection?: CpSeatMapTransitionDirections
35
+ }
36
+
37
+ const props = withDefaults(defineProps<Props>(), {
38
+ isLarge: false,
39
+ mapKey: '',
40
+ transitionDirection: CpSeatMapTransitionDirections.FORWARD,
41
+ })
42
+
43
+ const isMobile = useIsBreakpoint()
44
+
45
+ const planeDynamicClass = computed(() => {
46
+ return {
47
+ 'cpSeatMapPlane--isLarge': props.isLarge,
48
+ }
49
+ })
50
+
51
+ const dynamicTransitionName = computed(() => {
52
+ if (isMobile.value) return `cpSeatMapSlide-${props.transitionDirection}`
53
+ return 'cpSeatMapFade'
54
+ })
55
+ </script>
56
+
57
+ <style lang="scss">
58
+ .cpSeatMapFade-enter-active,
59
+ .cpSeatMapFade-leave-active {
60
+ transition: opacity 300ms ease;
61
+ }
62
+
63
+ .cpSeatMapFade-enter-from,
64
+ .cpSeatMapFade-leave-to {
65
+ opacity: 0;
66
+ }
67
+
68
+ .cpSeatMapSlide-backward,
69
+ .cpSeatMapSlide-forward {
70
+ &-enter-active,
71
+ &-leave-active {
72
+ transition:
73
+ transform 200ms ease,
74
+ opacity 200ms ease;
75
+ }
76
+
77
+ &-enter-from,
78
+ &-leave-to {
79
+ opacity: 0;
80
+ }
81
+
82
+ &-enter-to {
83
+ transform: translate3d(0, 0, 0);
84
+ }
85
+ }
86
+
87
+ .cpSeatMapSlide-forward {
88
+ &-enter-from {
89
+ transform: translate3d(3vw, 0, 0);
90
+ }
91
+
92
+ &-leave-to {
93
+ transform: translate3d(-3vw, 0, 0);
94
+ }
95
+ }
96
+
97
+ .cpSeatMapSlide-backward {
98
+ &-enter-from {
99
+ transform: translate3d(-3vw, 0, 0);
100
+ }
101
+
102
+ &-leave-to {
103
+ transform: translate3d(3vw, 0, 0);
104
+ }
105
+ }
106
+
107
+ .cpSeatMapPlane {
108
+ position: relative;
109
+ height: 100%;
110
+ animation: cp-seat-map-plane-reveal 1000ms ease forwards;
111
+
112
+ $plane-shadow:
113
+ inset 20px 0 20px -20px #eaecff,
114
+ inset -20px 0 20px -20px #eaecff;
115
+
116
+ @keyframes cp-seat-map-plane-reveal {
117
+ from {
118
+ opacity: 0;
119
+ transform: translateY(100%) scale(2);
120
+ }
121
+
122
+ to {
123
+ opacity: 1;
124
+ transform: translateY(0) scale(1);
125
+ }
126
+ }
127
+
128
+ @keyframes cp-seat-map-cabin-reveal {
129
+ to {
130
+ opacity: 1;
131
+ }
132
+ }
133
+
134
+ &__nose {
135
+ position: absolute;
136
+ z-index: 0;
137
+ top: 0;
138
+ width: 100%;
139
+ transform: translateY(calc(-100% + fn.px-to-rem(35)));
140
+
141
+ path {
142
+ box-shadow: $plane-shadow;
143
+ stroke-width: fn.px-to-rem(2);
144
+ }
145
+ }
146
+
147
+ &__plane {
148
+ position: absolute;
149
+ top: 0;
150
+ left: 0;
151
+ width: 100%;
152
+ height: 100%;
153
+ pointer-events: none;
154
+ }
155
+
156
+ &__wing {
157
+ position: absolute;
158
+ top: max(60%, fn.px-to-rem(500));
159
+ width: fn.px-to-rem(180);
160
+ height: max(30%, fn.px-to-rem(265));
161
+ transform: translateY(-60%);
162
+
163
+ &--isLeft {
164
+ left: fn.px-to-rem(-180);
165
+ }
166
+
167
+ &--isRight {
168
+ right: fn.px-to-rem(-180);
169
+ transform: translateY(-60%) scaleX(-1);
170
+ }
171
+ }
172
+
173
+ &__body {
174
+ position: relative;
175
+ z-index: 1;
176
+ min-height: 100%;
177
+ padding: fn.px-to-rem(40) var(--cp-spacing-2xl);
178
+ border-right: 1px solid var(--cp-border-soft);
179
+ border-left: 1px solid var(--cp-border-soft);
180
+ background-color: var(--cp-background-primary);
181
+ box-shadow: $plane-shadow;
182
+ }
183
+
184
+ &--isLarge .cpSeatMapPlane__body {
185
+ padding-inline: var(--cp-spacing-md);
186
+ }
187
+
188
+ &__cabin {
189
+ animation: cp-seat-map-cabin-reveal 1000ms ease forwards 1000ms;
190
+ opacity: 0;
191
+ }
192
+
193
+ &__content {
194
+ display: flex;
195
+ flex-direction: column;
196
+ gap: var(--cp-spacing-2xl);
197
+ transition-timing-function: ease-in-out;
198
+ }
199
+ }
200
+
201
+ @include mx.media-query-max(551px) {
202
+ .cpSeatMapPlane {
203
+ animation: none;
204
+
205
+ &__body {
206
+ padding: 0;
207
+ border: none;
208
+ background-color: transparent;
209
+ box-shadow: none;
210
+ }
211
+
212
+ &__cabin {
213
+ animation-delay: 200ms;
214
+ }
215
+
216
+ &__content {
217
+ gap: var(--cp-spacing-xl);
218
+ }
219
+ }
220
+ }
221
+ </style>