@autobusal/routes-order 1.9.0 → 1.9.1
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/CHANGELOG.md +673 -0
- package/Checkout/Checkout.tsx +519 -0
- package/Checkout/Sidebar/Sidebar.tsx +124 -0
- package/Checkout/Sidebar/styles.ts +52 -0
- package/Facts/Facts.tsx +271 -0
- package/Facts/questions.ts +250 -0
- package/Facts/service.ts +111 -0
- package/Facts/services.ts +19 -0
- package/Facts/styles.ts +112 -0
- package/Facts/types.ts +167 -0
- package/Faq/Faq.tsx +52 -0
- package/Faq/styles.ts +68 -0
- package/Found/Dates/Dates.tsx +59 -5
- package/Found/Dates/styles.ts +137 -7
- package/Found/Empty/Empty.tsx +136 -0
- package/Found/Empty/styles.ts +98 -0
- package/Found/Filters/Filters.tsx +10 -7
- package/Found/Filters/styles.ts +79 -8
- package/Found/Found.tsx +128 -29
- package/Found/Group/Group.tsx +3 -1
- package/Found/Header/styles.ts +20 -4
- package/Found/Orders/Orders.tsx +25 -4
- package/Found/Picks/Picks.tsx +10 -3
- package/Found/Picks/styles.ts +60 -9
- package/Found/Route/Route.tsx +189 -33
- package/Found/Route/styles.ts +488 -50
- package/Found/SameDay/SameDay.tsx +35 -0
- package/Found/SameDay/styles.ts +27 -0
- package/Found/Sort/styles.ts +52 -7
- package/Found/Summary/Summary.tsx +1 -1
- package/Found/Summary/styles.ts +12 -0
- package/Found/Watch/Watch.tsx +187 -0
- package/Found/Watch/styles.ts +118 -0
- package/Found/refine.ts +69 -0
- package/Links/Links.tsx +91 -0
- package/Links/styles.ts +75 -0
- package/RoutesOrder.tsx +239 -31
- package/Schedule/Schedule.tsx +123 -0
- package/Schedule/styles.ts +71 -0
- package/Sections/Schema.tsx +186 -0
- package/Sections/Sections.tsx +160 -0
- package/Sections/styles.ts +44 -0
- package/Step1/prepare.ts +21 -2
- package/Step2.tsx +34 -1
- package/Step4/Passenger/Passenger.tsx +253 -24
- package/Step4/Passenger/styles.ts +21 -1
- package/Step4/Passengers/Display.tsx +10 -2
- package/Step4/Passengers/Passengers.tsx +53 -4
- package/Step4/Saved/Choose.tsx +99 -0
- package/Step4/Saved/Remember.tsx +58 -0
- package/Step4/Saved/styles.ts +87 -0
- package/Step4/checkAge.ts +15 -4
- package/Step5/Addons/Addons.tsx +146 -4
- package/Step5/Addons/styles.ts +94 -0
- package/Step5/Billing/Billing.tsx +138 -70
- package/Step5/Coupons/Coupons.tsx +28 -18
- package/Step5/Coupons/styles.ts +41 -8
- package/Step5/Payments/Payments.tsx +36 -5
- package/Step5/Payments/styles.ts +16 -7
- package/Step5/Summary/About/About.tsx +99 -27
- package/Step5/Summary/About/styles.ts +118 -1
- package/Step5/Summary/styles.ts +12 -5
- package/Step5/utilities.ts +67 -12
- package/Steps/Steps.tsx +3 -1
- package/commerce.ts +24 -0
- package/package.json +1 -1
- package/services.ts +295 -12
- package/styles.ts +126 -0
- package/types.ts +78 -1
- package/Found/Booking/Booking.tsx +0 -61
- package/Found/Booking/styles.ts +0 -50
- package/Step4/Step4.tsx +0 -114
- package/Step5/Step5.tsx +0 -185
package/Found/Route/styles.ts
CHANGED
|
@@ -6,8 +6,20 @@ export const Container = styled.div<{ $type: 'favorite' | 'normal' }>`
|
|
|
6
6
|
position: relative;
|
|
7
7
|
display: flex;
|
|
8
8
|
flex-direction: column;
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
12
|
+
* Tighter on a phone. Every result carried 15px of padding and 15px
|
|
13
|
+
* between each of its bands, which is most of a thumb of screen spent on
|
|
14
|
+
* gaps before anything is read.
|
|
15
|
+
*/
|
|
16
|
+
gap: 8px;
|
|
17
|
+
padding: 10px;
|
|
18
|
+
|
|
19
|
+
@media (min-width: 640px) {
|
|
20
|
+
gap: 15px;
|
|
21
|
+
padding: 15px;
|
|
22
|
+
}
|
|
11
23
|
|
|
12
24
|
${ props => props.$type === 'favorite' && css`
|
|
13
25
|
border: 1px solid ${ props => props.theme.font.success };
|
|
@@ -45,92 +57,363 @@ export const FavoriteStop = styled.div`
|
|
|
45
57
|
border-bottom-right-radius: ${ props => props.theme.borderRadius };
|
|
46
58
|
`;
|
|
47
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
62
|
+
*
|
|
63
|
+
* VERTICAL on a phone, side by side from 640px up.
|
|
64
|
+
*
|
|
65
|
+
* Side by side was tried first and does not survive the content: each end
|
|
66
|
+
* gets about 96px at 375px, while "Thessaloniki (GRC) 16:30" measures 215px
|
|
67
|
+
* - it painted 50px outside the card, and the page never scrolled sideways
|
|
68
|
+
* so nothing looked broken until it was measured against the box it was
|
|
69
|
+
* supposed to be in. Stacked, each end has the full width, so nothing is
|
|
70
|
+
* truncated and nothing escapes.
|
|
71
|
+
*
|
|
72
|
+
* Compact is bought back a different way: tight gaps, a short arrow turned
|
|
73
|
+
* to point down the column, and the price on one row instead of a centred
|
|
74
|
+
* stack. Same information, roughly a third less height than before.
|
|
75
|
+
*/
|
|
48
76
|
export const Trip = styled.div`
|
|
49
77
|
display: flex;
|
|
50
78
|
flex-direction: column;
|
|
51
|
-
gap:
|
|
79
|
+
gap: 6px;
|
|
52
80
|
|
|
53
81
|
@media (min-width: 640px) {
|
|
54
82
|
flex-direction: row;
|
|
55
83
|
flex-wrap: wrap;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: 15px;
|
|
56
86
|
}
|
|
57
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
90
|
+
* A tighter gap once every cell shares one row: four gaps at 15px spent
|
|
91
|
+
* 60px of the widest layout on whitespace, while the arrival column was
|
|
92
|
+
* overflowing by 50px.
|
|
93
|
+
*/
|
|
58
94
|
@media (min-width: 1024px) {
|
|
59
95
|
flex-wrap: nowrap;
|
|
96
|
+
gap: 10px;
|
|
60
97
|
}
|
|
61
98
|
`;
|
|
62
99
|
|
|
63
100
|
export const Company = styled.div`
|
|
64
101
|
flex-basis: 100%;
|
|
65
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
105
|
+
* A column now, because the operator's rating sits under the logo. Left
|
|
106
|
+
* as a bare block it would have laid the stars out beside the logo and
|
|
107
|
+
* eaten the 185px this cell gets on desktop.
|
|
108
|
+
*/
|
|
109
|
+
display: flex;
|
|
110
|
+
flex-direction: column;
|
|
111
|
+
gap: 6px;
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
115
|
+
* Centred at EVERY width, not just on desktop. LinkCompany carries an
|
|
116
|
+
* auto horizontal margin, so the logo is centred in this cell whatever the
|
|
117
|
+
* screen - leaving the rating and the route code at flex-start put them
|
|
118
|
+
* under the left edge of a box whose logo sat in the middle of it. On a
|
|
119
|
+
* 768px card that was a 300px gap between the two.
|
|
120
|
+
*/
|
|
121
|
+
align-items: center;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
125
|
+
*
|
|
126
|
+
* 185px down to 120px. The logo is an identifier, not the product - it
|
|
127
|
+
* only has to be recognisable - and the 65px it gives back goes to the two
|
|
128
|
+
* location columns, which were the cells actually running out of room.
|
|
129
|
+
*
|
|
130
|
+
*/
|
|
66
131
|
@media (min-width: 1024px) {
|
|
67
|
-
flex
|
|
132
|
+
flex: 0 0 120px;
|
|
68
133
|
}
|
|
69
134
|
`;
|
|
70
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
138
|
+
*
|
|
139
|
+
* min-width: 0 is what makes `flex: 1` mean "an equal share". Without it
|
|
140
|
+
* the default min-width:auto stops a column shrinking below its content,
|
|
141
|
+
* so the arrival column (long city plus a long stop name) grew to 215px
|
|
142
|
+
* while the departure column got 155px - the two halves of the same row
|
|
143
|
+
* were different widths, and no fixed header could ever line up with
|
|
144
|
+
* both. It also stops one long stop name stealing width from the other
|
|
145
|
+
* side of the card.
|
|
146
|
+
*/
|
|
71
147
|
export const Location = styled.div`
|
|
72
148
|
flex: 1;
|
|
149
|
+
min-width: 0;
|
|
73
150
|
display: flex;
|
|
74
151
|
flex-direction: column;
|
|
75
|
-
align-items: center;
|
|
76
|
-
gap: 5px;
|
|
77
|
-
text-align: center;
|
|
78
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
155
|
+
* Left-aligned while the ends are stacked - centred text in a full-width
|
|
156
|
+
* column leaves the two times floating in the middle of the card with
|
|
157
|
+
* nothing to line them up against. Centred again from 640px, where the
|
|
158
|
+
* two ends sit either side of the arrow and the symmetry is the point.
|
|
159
|
+
*/
|
|
160
|
+
align-items: flex-start;
|
|
161
|
+
gap: 1px;
|
|
162
|
+
text-align: left;
|
|
163
|
+
|
|
164
|
+
@media (min-width: 640px) {
|
|
165
|
+
align-items: center;
|
|
166
|
+
gap: 3px;
|
|
167
|
+
text-align: center;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
172
|
+
*
|
|
173
|
+
* The heading has to be allowed to WRAP now that the two ends share a
|
|
174
|
+
* row. The min-width:0 above lets this column shrink, but the heading
|
|
175
|
+
* inside kept its intrinsic single-line width and simply painted outside
|
|
176
|
+
* the card - "Thessaloniki (GRC) 16:30" measured 215px inside a 96px
|
|
177
|
+
* column and ran 50px past the card's right edge. The page never scrolled
|
|
178
|
+
* sideways, so nothing looked broken until the text was measured against
|
|
179
|
+
* the box it was supposed to be in.
|
|
180
|
+
*
|
|
181
|
+
* A step down in size as well, because three columns of a 375px screen do
|
|
182
|
+
* not have room for a headline at body-copy scale.
|
|
183
|
+
*/
|
|
79
184
|
& > h2 {
|
|
80
185
|
margin-bottom: 0;
|
|
186
|
+
max-width: 100%;
|
|
187
|
+
line-height: 1.25;
|
|
188
|
+
overflow-wrap: anywhere;
|
|
81
189
|
}
|
|
82
190
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
193
|
+
* break-word, not normal. Real spaces now let the heading wrap between
|
|
194
|
+
* city, country and time, which covers almost every width - but at exactly
|
|
195
|
+
* 1024px, where the card first lays out in one row and the columns are at
|
|
196
|
+
* their narrowest, "Thessaloniki" on its own still exceeds its column and
|
|
197
|
+
* a heading that cannot break simply paints over the price.
|
|
198
|
+
*
|
|
199
|
+
* break-word only splits a word when it has a line to itself and still
|
|
200
|
+
* does not fit, so the ordinary case is untouched. The phone layout's
|
|
201
|
+
* anywhere would break words it did not have to.
|
|
202
|
+
*/
|
|
203
|
+
@media (min-width: 640px) {
|
|
204
|
+
& > h2 {
|
|
205
|
+
overflow-wrap: break-word;
|
|
206
|
+
}
|
|
86
207
|
}
|
|
87
208
|
`;
|
|
88
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
212
|
+
*
|
|
213
|
+
* The stop name is supporting detail, not a heading. At the same 16px as
|
|
214
|
+
* body copy it competed with the city above it; a step down lets the eye
|
|
215
|
+
* land on the city first and read the stop only when it needs to.
|
|
216
|
+
*/
|
|
217
|
+
/**
|
|
218
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
219
|
+
*
|
|
220
|
+
* Clamped to two lines on a phone. Now that the two ends of the journey
|
|
221
|
+
* share a row, each gets about 96px - and a name like "Terminali Lindor
|
|
222
|
+
* Interurban dhe Nderkombetar i Autobusave (TEG)" ran to five lines and
|
|
223
|
+
* stretched the whole row to match, so one terminal with a long name made
|
|
224
|
+
* every card taller than the screen. Two lines and an ellipsis, which is
|
|
225
|
+
* what the reference layouts do with the same problem.
|
|
226
|
+
*/
|
|
227
|
+
export const Stop = styled.span`
|
|
228
|
+
display: -webkit-box;
|
|
229
|
+
-webkit-line-clamp: 2;
|
|
230
|
+
-webkit-box-orient: vertical;
|
|
231
|
+
overflow: hidden;
|
|
232
|
+
font-size: ${ props => props.theme.size.xs };
|
|
233
|
+
font-weight: 700;
|
|
234
|
+
line-height: 1.3;
|
|
235
|
+
color: ${ props => props.theme.font.faded };
|
|
236
|
+
|
|
237
|
+
@media (min-width: 1024px) {
|
|
238
|
+
display: block;
|
|
239
|
+
overflow: visible;
|
|
240
|
+
}
|
|
241
|
+
`;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
245
|
+
*
|
|
246
|
+
* The country code comes out of the database lowercase ("alb", "grc").
|
|
247
|
+
* An ISO country code is by definition upper case, so it is cased here at
|
|
248
|
+
* render time rather than left to the data - every consumer would otherwise
|
|
249
|
+
* have to remember to do it. Set smaller and muted so it qualifies the city
|
|
250
|
+
* without competing with it.
|
|
251
|
+
*/
|
|
252
|
+
export const Iso = styled.span`
|
|
253
|
+
// JSX drops the literal spaces around this element, so the gap on either
|
|
254
|
+
// side of "(ALB)" is this margin's job, not whitespace's
|
|
255
|
+
margin: 0 5px;
|
|
256
|
+
font-size: ${ props => props.theme.size.xs };
|
|
257
|
+
font-weight: 700;
|
|
258
|
+
text-transform: uppercase;
|
|
259
|
+
letter-spacing: .5px;
|
|
260
|
+
color: ${ props => props.theme.font.faded };
|
|
261
|
+
`;
|
|
262
|
+
|
|
89
263
|
export const Time = styled.div`
|
|
90
264
|
display: flex;
|
|
91
|
-
flex-direction:
|
|
92
|
-
gap:
|
|
265
|
+
flex-direction: row;
|
|
266
|
+
gap: 6px;
|
|
93
267
|
align-items: center;
|
|
94
268
|
font-weight: 700;
|
|
95
269
|
|
|
270
|
+
@media (min-width: 640px) {
|
|
271
|
+
flex-direction: column;
|
|
272
|
+
gap: 8px;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
277
|
+
* The arrow sat between two stacked blocks at 1.5x the largest type in
|
|
278
|
+
* the theme. Now that the two ends of the journey share a row with it,
|
|
279
|
+
* that size would take the width the city names need - it is a
|
|
280
|
+
* separator, not a headline.
|
|
281
|
+
*/
|
|
282
|
+
/**
|
|
283
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
284
|
+
* Turned to point DOWN while the two ends are stacked - an arrow pointing
|
|
285
|
+
* right between two things sitting one above the other says the wrong
|
|
286
|
+
* thing about which way the journey goes.
|
|
287
|
+
*/
|
|
96
288
|
& > svg {
|
|
97
|
-
font-size:
|
|
289
|
+
font-size: ${ props => props.theme.size.l };
|
|
290
|
+
transform: rotate(90deg);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
@media (min-width: 640px) {
|
|
294
|
+
& > svg {
|
|
295
|
+
font-size: calc(1.5 * ${ props => props.theme.size.xxl });
|
|
296
|
+
transform: none;
|
|
297
|
+
}
|
|
98
298
|
}
|
|
99
299
|
|
|
100
300
|
& > span {
|
|
101
|
-
display:
|
|
102
|
-
|
|
103
|
-
|
|
301
|
+
display: flex;
|
|
302
|
+
align-items: center;
|
|
303
|
+
gap: 5px;
|
|
304
|
+
padding: 3px 12px;
|
|
305
|
+
white-space: nowrap;
|
|
306
|
+
font-size: ${ props => props.theme.size.m };
|
|
104
307
|
background: ${ props => props.theme.background.neutral };
|
|
105
308
|
border-radius: 100px;
|
|
106
309
|
}
|
|
107
310
|
|
|
311
|
+
// the hourglass is a hint, not a heading - the big arrow above already
|
|
312
|
+
// owns the visual weight in this column
|
|
313
|
+
& > span > svg {
|
|
314
|
+
flex-shrink: 0;
|
|
315
|
+
font-size: ${ props => props.theme.size.m };
|
|
316
|
+
opacity: .7;
|
|
317
|
+
}
|
|
318
|
+
|
|
108
319
|
@media (min-width: 640px) {
|
|
109
|
-
flex
|
|
320
|
+
flex: 0 0 120px;
|
|
110
321
|
}
|
|
111
322
|
`;
|
|
112
323
|
|
|
113
324
|
export const Price = styled.div`
|
|
114
325
|
flex-basis: 100%;
|
|
115
326
|
display: flex;
|
|
116
|
-
|
|
117
|
-
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
330
|
+
*
|
|
331
|
+
* On a phone: the fare and the button share one row, and the tax note sits
|
|
332
|
+
* under them.
|
|
333
|
+
*
|
|
334
|
+
* Reordered in CSS rather than in the markup, because the source order -
|
|
335
|
+
* fare, note, button - is the right one to read aloud and the right one
|
|
336
|
+
* for a crawler: the note explains the number it follows. Only the
|
|
337
|
+
* PAINTING needs to differ, and the order property says exactly that
|
|
338
|
+
* without moving the note away from the price it qualifies.
|
|
339
|
+
*/
|
|
340
|
+
flex-direction: row;
|
|
341
|
+
flex-wrap: wrap;
|
|
342
|
+
justify-content: space-between;
|
|
118
343
|
align-items: center;
|
|
344
|
+
gap: 4px 8px;
|
|
119
345
|
|
|
120
|
-
& >
|
|
121
|
-
|
|
122
|
-
|
|
346
|
+
& > *:nth-child(1) { order: 1; }
|
|
347
|
+
|
|
348
|
+
/* the note drops to its own line under both */
|
|
349
|
+
& > *:nth-child(2) { order: 3; flex-basis: 100%; }
|
|
350
|
+
|
|
351
|
+
& > *:nth-child(3) { order: 2; }
|
|
123
352
|
|
|
124
353
|
@media (min-width: 768px) {
|
|
125
|
-
flex
|
|
354
|
+
flex: 0 0 165px;
|
|
355
|
+
flex-direction: column;
|
|
356
|
+
justify-content: initial;
|
|
357
|
+
gap: 8px;
|
|
358
|
+
|
|
359
|
+
& > *:nth-child(1),
|
|
360
|
+
& > *:nth-child(2),
|
|
361
|
+
& > *:nth-child(3) {
|
|
362
|
+
order: initial;
|
|
363
|
+
flex-basis: auto;
|
|
364
|
+
}
|
|
126
365
|
}
|
|
127
366
|
`;
|
|
128
367
|
|
|
368
|
+
/**
|
|
369
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
370
|
+
*
|
|
371
|
+
* The decimals ride as superscript rather than at full size. On a fare
|
|
372
|
+
* board the cents are almost never what anyone is comparing, and at the
|
|
373
|
+
* headline size they were taking a third of the width of the widest thing
|
|
374
|
+
* on the card. The line-height is pinned to 1 so the shrunk decimals do
|
|
375
|
+
* not leave a gap under the row.
|
|
376
|
+
*/
|
|
377
|
+
export const Amount = styled.strong`
|
|
378
|
+
display: flex;
|
|
379
|
+
align-items: flex-start;
|
|
380
|
+
line-height: 1;
|
|
381
|
+
font-size: ${ props => props.theme.size.xxl };
|
|
382
|
+
`;
|
|
383
|
+
|
|
384
|
+
export const Decimals = styled.span`
|
|
385
|
+
margin-left: 1px;
|
|
386
|
+
font-size: ${ props => props.theme.size.s };
|
|
387
|
+
line-height: 1;
|
|
388
|
+
`;
|
|
389
|
+
|
|
390
|
+
export const Currency = styled.span`
|
|
391
|
+
margin-left: 4px;
|
|
392
|
+
align-self: center;
|
|
393
|
+
font-size: ${ props => props.theme.size.m };
|
|
394
|
+
`;
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
398
|
+
*
|
|
399
|
+
* Tucked up against the price it qualifies, which reads as one unit and
|
|
400
|
+
* frees the vertical space the Select button needs.
|
|
401
|
+
*/
|
|
129
402
|
export const PriceNotice = styled.span`
|
|
130
|
-
|
|
131
|
-
|
|
403
|
+
/**
|
|
404
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
405
|
+
* Left-aligned under the fare on a phone, where it is a full-width line
|
|
406
|
+
* beneath a price and a button rather than the middle of a centred stack.
|
|
407
|
+
*/
|
|
408
|
+
font-size: ${ props => props.theme.size.xxs };
|
|
409
|
+
line-height: 1.25;
|
|
132
410
|
color: ${ props => props.theme.font.faded };
|
|
133
|
-
text-align:
|
|
411
|
+
text-align: left;
|
|
412
|
+
|
|
413
|
+
@media (min-width: 768px) {
|
|
414
|
+
margin-top: -4px;
|
|
415
|
+
text-align: center;
|
|
416
|
+
}
|
|
134
417
|
`;
|
|
135
418
|
|
|
136
419
|
export const LinkCompany = styled(Link)`
|
|
@@ -143,26 +426,125 @@ export const LinkCompany = styled(Link)`
|
|
|
143
426
|
|
|
144
427
|
border-radius: 8px;
|
|
145
428
|
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
432
|
+
* Smaller from the width where the card lays out in one row, since that is
|
|
433
|
+
* the only place the space was contested.
|
|
434
|
+
*/
|
|
435
|
+
@media (min-width: 1024px) {
|
|
436
|
+
max-width: 120px;
|
|
437
|
+
|
|
438
|
+
& > img {
|
|
439
|
+
${ logoBox('100%', '44px') }
|
|
440
|
+
}
|
|
441
|
+
}
|
|
146
442
|
`;
|
|
147
443
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
444
|
+
/**
|
|
445
|
+
* The route code, under the logo.
|
|
446
|
+
*
|
|
447
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
448
|
+
* Moved out of the collapsed details and up beside the operator it belongs
|
|
449
|
+
* to. It is an identifier of the same kind as the logo, and putting it here
|
|
450
|
+
* frees a slot in the details row for things that genuinely need explaining.
|
|
451
|
+
*/
|
|
452
|
+
export const CodeCompany = styled(Link)`
|
|
453
|
+
display: inline-flex;
|
|
454
|
+
align-items: center;
|
|
455
|
+
gap: 4px;
|
|
456
|
+
max-width: 100%;
|
|
457
|
+
padding: 2px 8px;
|
|
458
|
+
border: 1px solid ${ props => props.theme.background.neutral };
|
|
459
|
+
border-radius: 100px;
|
|
460
|
+
background: ${ props => props.theme.background.neutral };
|
|
461
|
+
color: ${ props => props.theme.font.faded };
|
|
462
|
+
font-size: ${ props => props.theme.size.xxs };
|
|
463
|
+
font-weight: 700;
|
|
464
|
+
line-height: 1.4;
|
|
465
|
+
letter-spacing: .3px;
|
|
466
|
+
white-space: nowrap;
|
|
467
|
+
overflow: hidden;
|
|
468
|
+
text-overflow: ellipsis;
|
|
469
|
+
transition: all .3s ease;
|
|
470
|
+
|
|
471
|
+
/*
|
|
472
|
+
* A route symbol rather than a bus or a ticket. The code identifies which
|
|
473
|
+
* LINE this is - the same job a flight number does - and a bus icon would
|
|
474
|
+
* say the thing the whole card already says. Slightly larger than the text
|
|
475
|
+
* beside it, because at this size the glyph is what carries the meaning
|
|
476
|
+
* and the letters are only the value.
|
|
477
|
+
*/
|
|
478
|
+
& > svg {
|
|
479
|
+
flex-shrink: 0;
|
|
480
|
+
font-size: ${ props => props.theme.size.s };
|
|
481
|
+
opacity: .8;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
&:hover {
|
|
485
|
+
border-color: ${ props => props.theme.primary.normal };
|
|
486
|
+
color: ${ props => props.theme.primary.normal };
|
|
487
|
+
}
|
|
488
|
+
`;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
492
|
+
*
|
|
493
|
+
* Collapsible, and inline at every width including phones.
|
|
494
|
+
*
|
|
495
|
+
* Hidden with CSS rather than unmounted, deliberately. These cards are on a
|
|
496
|
+
* page the prerender crawl snapshots for every route pair in the sitemap, so
|
|
497
|
+
* amenities, the route code, transit countries and the policy link have to
|
|
498
|
+
* be IN the DOM whether or not a reader has opened them - unmounting would
|
|
499
|
+
* take real per-pair content out of exactly the pages Tier 3 exists to
|
|
500
|
+
* fatten.
|
|
501
|
+
*
|
|
502
|
+
* Wrapping instead of stacking on a phone turns four bands of vertical space
|
|
503
|
+
* into one or two, which is the space the results themselves wanted.
|
|
504
|
+
*/
|
|
505
|
+
export const Details = styled.div<{ $open: boolean }>`
|
|
506
|
+
display: ${ props => (props.$open ? 'flex' : 'none') };
|
|
507
|
+
flex-wrap: wrap;
|
|
508
|
+
gap: 6px;
|
|
152
509
|
|
|
153
510
|
@media (min-width: 640px) {
|
|
154
|
-
|
|
155
|
-
flex-wrap: wrap;
|
|
511
|
+
gap: 15px;
|
|
156
512
|
}
|
|
157
513
|
`;
|
|
158
514
|
|
|
159
|
-
|
|
160
|
-
|
|
515
|
+
/**
|
|
516
|
+
* The disclosure. Small and quiet - it is a way to get at supporting detail,
|
|
517
|
+
* not an action competing with "select".
|
|
518
|
+
*/
|
|
519
|
+
export const ButtonDetails = styled.button`
|
|
520
|
+
display: inline-flex;
|
|
521
|
+
align-items: center;
|
|
522
|
+
gap: 5px;
|
|
523
|
+
align-self: flex-start;
|
|
524
|
+
padding: 4px 0;
|
|
161
525
|
font-size: ${ props => props.theme.size.s };
|
|
526
|
+
color: ${ props => props.theme.font.faded };
|
|
527
|
+
|
|
528
|
+
&:hover {
|
|
529
|
+
color: ${ props => props.theme.font.normal };
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
svg {
|
|
533
|
+
transition: transform 0.2s ease;
|
|
534
|
+
}
|
|
535
|
+
`;
|
|
536
|
+
|
|
537
|
+
export const Detail = styled.div`
|
|
538
|
+
flex: 1 1 auto;
|
|
539
|
+
min-width: 0;
|
|
540
|
+
padding: 5px 8px;
|
|
541
|
+
font-size: calc(${ props => props.theme.size.s } - 1px);
|
|
162
542
|
background: ${ props => props.theme.background.neutral };
|
|
163
543
|
border-radius: ${ props => props.theme.borderRadius };
|
|
164
544
|
|
|
165
545
|
@media (min-width: 480px) {
|
|
546
|
+
padding: 8px 10px;
|
|
547
|
+
font-size: ${ props => props.theme.size.s };
|
|
166
548
|
flex-basis: calc(50% - 7.5px);
|
|
167
549
|
}
|
|
168
550
|
@media (min-width: 768px) {
|
|
@@ -178,10 +560,6 @@ export const TitleDetail = styled.h6`
|
|
|
178
560
|
font-size: ${ props => props.theme.size.xs };
|
|
179
561
|
`;
|
|
180
562
|
|
|
181
|
-
export const LinkRoute = styled(Link)`
|
|
182
|
-
font-weight: 700;
|
|
183
|
-
`;
|
|
184
|
-
|
|
185
563
|
export const ButtonPolicy = styled.button`
|
|
186
564
|
display: flex;
|
|
187
565
|
align-items: center;
|
|
@@ -195,20 +573,80 @@ export const ButtonPolicy = styled.button`
|
|
|
195
573
|
}
|
|
196
574
|
`;
|
|
197
575
|
|
|
198
|
-
|
|
576
|
+
/**
|
|
577
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
578
|
+
*
|
|
579
|
+
* Left-aligned now that this sits inside a Detail column alongside route,
|
|
580
|
+
* transit and policies, rather than centred in a full-width band of its
|
|
581
|
+
* own under the card.
|
|
582
|
+
*/
|
|
583
|
+
export const FeaturesItems = styled.div`
|
|
199
584
|
display: flex;
|
|
200
|
-
flex-
|
|
201
|
-
|
|
585
|
+
flex-wrap: wrap;
|
|
586
|
+
gap: 6px;
|
|
202
587
|
`;
|
|
203
588
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
589
|
+
/**
|
|
590
|
+
* "Leaves in 40 minutes", on today's departures only.
|
|
591
|
+
*
|
|
592
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
593
|
+
*
|
|
594
|
+
* Same-day seats are sellable now, and a time alone does not tell somebody
|
|
595
|
+
* whether they can make it - "14:00" reads very differently at nine in the
|
|
596
|
+
* morning and at half past one. Under an hour it turns urgent, because that
|
|
597
|
+
* is the point where the answer stops being "yes" and starts being "only if
|
|
598
|
+
* you leave now".
|
|
599
|
+
*/
|
|
600
|
+
export const Leaves = styled.div<{ $soon: boolean }>`
|
|
601
|
+
align-self: flex-start;
|
|
602
|
+
padding: 3px 10px;
|
|
603
|
+
border-radius: 100px;
|
|
604
|
+
font-size: ${ props => props.theme.size.xs };
|
|
605
|
+
font-weight: 700;
|
|
606
|
+
white-space: nowrap;
|
|
607
|
+
|
|
608
|
+
color: ${ props => (props.$soon ? '#FFF' : props.theme.font.normal) };
|
|
609
|
+
background: ${ props => (props.$soon ? props.theme.font.error : props.theme.primary.neutral) };
|
|
207
610
|
`;
|
|
208
611
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
612
|
+
/**
|
|
613
|
+
* The +1 on an overnight arrival.
|
|
614
|
+
*
|
|
615
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-05
|
|
616
|
+
*
|
|
617
|
+
* Sits INSIDE the h2, right against the clock time it qualifies, because
|
|
618
|
+
* that is the number it changes the meaning of. Raised and shrunk rather
|
|
619
|
+
* than boxed: it reads as an annotation on the time, the way a footnote
|
|
620
|
+
* marker does, and a second pill on a card that already carries an offer
|
|
621
|
+
* badge and a countdown would compete with both.
|
|
622
|
+
*
|
|
623
|
+
* The title attribute carries the sentence - "arrives the next day" - so
|
|
624
|
+
* the meaning is available to anyone for whom "+1" is not self-evident,
|
|
625
|
+
* which on a first visit is most people.
|
|
626
|
+
*/
|
|
627
|
+
export const NextDay = styled.sup`
|
|
628
|
+
margin-left: 4px;
|
|
629
|
+
padding: 1px 4px;
|
|
630
|
+
border-radius: 4px;
|
|
631
|
+
font-size: ${ props => props.theme.size.xs };
|
|
632
|
+
font-weight: 700;
|
|
633
|
+
white-space: nowrap;
|
|
634
|
+
vertical-align: super;
|
|
635
|
+
cursor: help;
|
|
636
|
+
color: ${ props => props.theme.font.normal };
|
|
637
|
+
background: ${ props => props.theme.primary.neutral };
|
|
638
|
+
`;
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* The calendar day under one end of an overnight trip.
|
|
642
|
+
*
|
|
643
|
+
* Rendered on BOTH ends or neither: a date shown only over the arrival
|
|
644
|
+
* leaves the reader working out what day the departure was, which is the
|
|
645
|
+
* question the whole thing exists to answer.
|
|
646
|
+
*/
|
|
647
|
+
export const Day = styled.span`
|
|
648
|
+
font-size: ${ props => props.theme.size.xs };
|
|
649
|
+
font-weight: 700;
|
|
650
|
+
white-space: nowrap;
|
|
651
|
+
color: ${ props => props.theme.primary.normal };
|
|
652
|
+
`;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import { HiOutlineExclamationCircle } from 'react-icons/hi';
|
|
3
|
+
import { Container } from './styles';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
t: TFunction<'common'>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The caution that comes with selling today's seats.
|
|
11
|
+
*
|
|
12
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
13
|
+
*
|
|
14
|
+
* Same-day departures are sellable now, and two things about them are worth
|
|
15
|
+
* saying plainly before somebody pays.
|
|
16
|
+
*
|
|
17
|
+
* A coach that has already left is filtered out server-side
|
|
18
|
+
* (Search\Departed), and since countries carry a timezone that filter is now
|
|
19
|
+
* judged against the DEPARTURE STOP's own clock rather than ours - so the
|
|
20
|
+
* warning is no longer about doubt on our side.
|
|
21
|
+
*
|
|
22
|
+
* What remains is the honest thing to say when the margin is minutes: every
|
|
23
|
+
* time on the page is local to its stop, the seat is real, the coach is
|
|
24
|
+
* about to go, and whether somebody can reach the terminal in time is not
|
|
25
|
+
* something we can know for them.
|
|
26
|
+
*/
|
|
27
|
+
const SameDay = ({ t }: Props): JSX.Element => (
|
|
28
|
+
<Container>
|
|
29
|
+
<HiOutlineExclamationCircle />
|
|
30
|
+
|
|
31
|
+
<span>{ t('routes_order.step2.same_day') }</span>
|
|
32
|
+
</Container>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export default SameDay;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
5
|
+
*
|
|
6
|
+
* Shown only on a same-day search. A caution, not an alarm - the whole point
|
|
7
|
+
* of selling today is that these seats are worth selling, and a red banner
|
|
8
|
+
* over every one of them would say the opposite.
|
|
9
|
+
*/
|
|
10
|
+
export const Container = styled.div`
|
|
11
|
+
display: flex;
|
|
12
|
+
gap: 8px;
|
|
13
|
+
align-items: flex-start;
|
|
14
|
+
margin-bottom: 15px;
|
|
15
|
+
padding: 10px 12px;
|
|
16
|
+
border-radius: ${ props => props.theme.borderRadius };
|
|
17
|
+
background: ${ props => props.theme.primary.neutral };
|
|
18
|
+
color: ${ props => props.theme.font.normal };
|
|
19
|
+
font-size: ${ props => props.theme.size.s };
|
|
20
|
+
line-height: 1.4;
|
|
21
|
+
|
|
22
|
+
& > svg {
|
|
23
|
+
flex: 0 0 auto;
|
|
24
|
+
margin-top: 2px;
|
|
25
|
+
font-size: ${ props => props.theme.size.l };
|
|
26
|
+
}
|
|
27
|
+
`;
|