@bytebrand/fe-ui-core-autobahn 1.0.56 → 1.0.57
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/locales/de/autobahn.json +4 -1
- package/locales/en/autobahn.json +4 -1
- package/package.json +1 -1
- package/theme/md3.css +256 -17
- package/vdp/VdpModules.tsx +32 -16
- package/vdp/VdpViewer.tsx +646 -56
package/locales/de/autobahn.json
CHANGED
|
@@ -188,7 +188,10 @@
|
|
|
188
188
|
"requestLabel": "Jetzt Anfragen",
|
|
189
189
|
"threeSixtyLabel": "360°-Ansicht",
|
|
190
190
|
"counterLabel": "Bild {{current}} von {{total}}",
|
|
191
|
-
"moreThumbsLabel": "{{count}} weitere Bilder"
|
|
191
|
+
"moreThumbsLabel": "{{count}} weitere Bilder",
|
|
192
|
+
"allPhotosTitle": "Alle {{count}} Fotos",
|
|
193
|
+
"allPhotosSubtitle": "Tippe auf ein Foto, um es zu öffnen.",
|
|
194
|
+
"allPhotosFooter": "{{count}} Fotos insgesamt"
|
|
192
195
|
},
|
|
193
196
|
"chrome": {
|
|
194
197
|
"menu": "Menü",
|
package/locales/en/autobahn.json
CHANGED
|
@@ -188,7 +188,10 @@
|
|
|
188
188
|
"requestLabel": "Enquire now",
|
|
189
189
|
"threeSixtyLabel": "360° view",
|
|
190
190
|
"counterLabel": "Image {{current}} of {{total}}",
|
|
191
|
-
"moreThumbsLabel": "{{count}} more images"
|
|
191
|
+
"moreThumbsLabel": "{{count}} more images",
|
|
192
|
+
"allPhotosTitle": "All {{count}} photos",
|
|
193
|
+
"allPhotosSubtitle": "Tap a photo to open it.",
|
|
194
|
+
"allPhotosFooter": "{{count}} photos total"
|
|
192
195
|
},
|
|
193
196
|
"chrome": {
|
|
194
197
|
"menu": "Menu",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytebrand/fe-ui-core-autobahn",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.57",
|
|
4
4
|
"description": "auto.de md3 (Autobahn) design system — UI primitives, cards, chrome, VDP modules, theme CSS and locales. Ships raw TypeScript source (like fe-ui-core before it); each consumer's bundler compiles it.",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"license": "UNLICENSED",
|
package/theme/md3.css
CHANGED
|
@@ -465,7 +465,7 @@ line-height: 31px;
|
|
|
465
465
|
height: 34px;
|
|
466
466
|
padding: 0 13px;
|
|
467
467
|
flex: none;
|
|
468
|
-
background:
|
|
468
|
+
background-color: hsla(0, 0%, 100%, .75);
|
|
469
469
|
border: 1px solid #d4dde7;
|
|
470
470
|
border-radius: 16px;
|
|
471
471
|
}
|
|
@@ -3258,6 +3258,16 @@ line-height: 31px;
|
|
|
3258
3258
|
opacity: 0.92;
|
|
3259
3259
|
}
|
|
3260
3260
|
}
|
|
3261
|
+
/* VDP gallery arrows only — .car-arrow is shared with the SRP card carousels (CarCard/CarRow),
|
|
3262
|
+
so this is scoped to .vdp-gallerybox rather than the base rule. */
|
|
3263
|
+
.md3 .vdp-gallerybox .car-arrow {
|
|
3264
|
+
width: 36px;
|
|
3265
|
+
height: 36px;
|
|
3266
|
+
border-radius: 18px;
|
|
3267
|
+
background-color: hsla(0, 0%, 100%, .75);
|
|
3268
|
+
border: 1px solid #D4DDE7;
|
|
3269
|
+
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.08);
|
|
3270
|
+
}
|
|
3261
3271
|
|
|
3262
3272
|
/* ==========================================================================
|
|
3263
3273
|
RESPONSIVE LAYOUT LAYER
|
|
@@ -4728,6 +4738,16 @@ line-height: 31px;
|
|
|
4728
4738
|
.md3 .enquiry-form {
|
|
4729
4739
|
padding: 24px;
|
|
4730
4740
|
}
|
|
4741
|
+
/* Vorname/Nachname/E-Mail carry their border/background as inline style (enquiryInput) —
|
|
4742
|
+
!important is required here to win over the inline style on focus. */
|
|
4743
|
+
.md3 .enquiry-name-row input:focus,
|
|
4744
|
+
.md3 .enquiry-email-wrap input:focus {
|
|
4745
|
+
background: #FFFFFF !important;
|
|
4746
|
+
border: 1px solid #005CFF !important;
|
|
4747
|
+
border-radius: 10px !important;
|
|
4748
|
+
outline: 0;
|
|
4749
|
+
box-shadow: none;
|
|
4750
|
+
}
|
|
4731
4751
|
/* outlined float-label fields (Figma phone/message row): label sits ON the top border */
|
|
4732
4752
|
.md3 .enq-float {
|
|
4733
4753
|
position: relative;
|
|
@@ -4754,12 +4774,25 @@ line-height: 31px;
|
|
|
4754
4774
|
border: 0;
|
|
4755
4775
|
background: none;
|
|
4756
4776
|
outline: 0;
|
|
4777
|
+
box-shadow: none;
|
|
4757
4778
|
color: var(--md-on-surface);
|
|
4758
4779
|
font: inherit;
|
|
4759
4780
|
font-size: 14px;
|
|
4760
4781
|
height: 46px;
|
|
4761
4782
|
padding: 0 12px;
|
|
4762
4783
|
}
|
|
4784
|
+
/* focus state (Figma): the .enq-float wrapper carries the border/background — the
|
|
4785
|
+
input/textarea/mselect-btn inside stay borderless (see above) so only one outline shows. */
|
|
4786
|
+
.md3 .enq-float:focus-within {
|
|
4787
|
+
background: #FFFFFF;
|
|
4788
|
+
border: 1px solid #005CFF;
|
|
4789
|
+
border-radius: 10px;
|
|
4790
|
+
box-shadow: none;
|
|
4791
|
+
}
|
|
4792
|
+
.md3 .enq-float:focus-within .enq-float-label {
|
|
4793
|
+
background: #FFFFFF;
|
|
4794
|
+
color: #005CFF;
|
|
4795
|
+
}
|
|
4763
4796
|
.md3 .enq-float textarea {
|
|
4764
4797
|
height: 96px;
|
|
4765
4798
|
padding: 12px;
|
|
@@ -4770,15 +4803,26 @@ line-height: 31px;
|
|
|
4770
4803
|
grid-template-columns: 82px 96px 1fr;
|
|
4771
4804
|
gap: 10px;
|
|
4772
4805
|
}
|
|
4773
|
-
.
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
gap: 4px;
|
|
4806
|
+
/* "Land" is a real Dropdown (.mselect) now, nested inside the .enq-float outline — strip
|
|
4807
|
+
its own trigger chrome (border/background/box-shadow ring) so the outer .enq-float border
|
|
4808
|
+
stays the only visible outline, and match the 46px height of the sibling inputs. */
|
|
4809
|
+
.md3 .enq-float .mselect-btn {
|
|
4778
4810
|
height: 46px;
|
|
4779
4811
|
padding: 0 10px 0 12px;
|
|
4780
|
-
|
|
4781
|
-
|
|
4812
|
+
gap: 4px;
|
|
4813
|
+
border: 0;
|
|
4814
|
+
background: none;
|
|
4815
|
+
outline: 0;
|
|
4816
|
+
box-shadow: none;
|
|
4817
|
+
}
|
|
4818
|
+
.md3 .enq-float .mselect-btn:hover,
|
|
4819
|
+
.md3 .enq-float .mselect-btn[aria-expanded="true"] {
|
|
4820
|
+
box-shadow: none;
|
|
4821
|
+
}
|
|
4822
|
+
.md3 .enq-float .mselect-btn .lucide {
|
|
4823
|
+
width: 14px;
|
|
4824
|
+
height: 14px;
|
|
4825
|
+
color: var(--md-on-surface-variant);
|
|
4782
4826
|
}
|
|
4783
4827
|
/* revocable-consent checkbox + microtext (Figma round 9) */
|
|
4784
4828
|
.md3 .enq-consent {
|
|
@@ -5188,9 +5232,10 @@ line-height: 31px;
|
|
|
5188
5232
|
}
|
|
5189
5233
|
.md3 .hiw-section {
|
|
5190
5234
|
background: var(--md-sc-lowest);
|
|
5191
|
-
border: 1px solid
|
|
5235
|
+
border: 1px solid #D4DDE7;
|
|
5192
5236
|
border-radius: 18px;
|
|
5193
5237
|
padding: 30px 24px;
|
|
5238
|
+
box-shadow: none;
|
|
5194
5239
|
}
|
|
5195
5240
|
.md3 .hiw-heading {
|
|
5196
5241
|
text-align: left;
|
|
@@ -5777,10 +5822,10 @@ line-height: 31px;
|
|
|
5777
5822
|
grid-template-columns: 1fr 1fr;
|
|
5778
5823
|
gap: 10px;
|
|
5779
5824
|
background: var(--md-sc-lowest);
|
|
5780
|
-
border: 1px solid
|
|
5825
|
+
border: 1px solid #D4DDE7;
|
|
5781
5826
|
border-radius: 18px;
|
|
5782
5827
|
padding: 18px 16px;
|
|
5783
|
-
box-shadow:
|
|
5828
|
+
box-shadow: none;
|
|
5784
5829
|
}
|
|
5785
5830
|
.md3 .trust-strip > div {
|
|
5786
5831
|
display: flex;
|
|
@@ -5944,6 +5989,7 @@ line-height: 31px;
|
|
|
5944
5989
|
}
|
|
5945
5990
|
.md3 .vdp-push-badges {
|
|
5946
5991
|
gap: 6px;
|
|
5992
|
+
margin-bottom: 13px;
|
|
5947
5993
|
}
|
|
5948
5994
|
}
|
|
5949
5995
|
|
|
@@ -6067,21 +6113,37 @@ color: #005CFF;
|
|
|
6067
6113
|
}
|
|
6068
6114
|
|
|
6069
6115
|
@media (max-width: 600px) {
|
|
6070
|
-
/* full-bleed gallery: edge-to-edge, app-like.
|
|
6071
|
-
the
|
|
6116
|
+
/* full-bleed gallery: edge-to-edge, app-like. Extra height (vs. the plain photo height)
|
|
6117
|
+
reserves room at the bottom for the controls row, now overlaid on the image itself
|
|
6118
|
+
(round 15 — supersedes the earlier "no overlay" layout). */
|
|
6072
6119
|
.md3 .vdp-gallerybox {
|
|
6073
6120
|
margin: 0 -24px;
|
|
6074
6121
|
border-radius: 0;
|
|
6075
6122
|
border: 0;
|
|
6076
6123
|
box-shadow: none;
|
|
6077
|
-
height:
|
|
6124
|
+
height: 230px;
|
|
6078
6125
|
aspect-ratio: auto;
|
|
6079
6126
|
}
|
|
6080
|
-
/*
|
|
6127
|
+
/* .vdp-gallery is the positioning context: .gallery-controls-row is its own sibling of
|
|
6128
|
+
.vdp-gallerybox in the DOM, so it needs a relative ancestor to overlay against. */
|
|
6129
|
+
.md3 .vdp-gallery {
|
|
6130
|
+
position: relative;
|
|
6131
|
+
}
|
|
6132
|
+
/* controls row now sits ON the image as an overlay, bottom-aligned (round 15) */
|
|
6081
6133
|
.md3 .gallery-controls-row {
|
|
6082
|
-
|
|
6134
|
+
position: absolute;
|
|
6135
|
+
left: 14px;
|
|
6136
|
+
right: 14px;
|
|
6137
|
+
bottom: 12px;
|
|
6138
|
+
z-index: 3;
|
|
6139
|
+
padding: 0;
|
|
6083
6140
|
}
|
|
6084
|
-
/*
|
|
6141
|
+
/* share/save icon buttons: scoped to THIS row (not the base .icon-btn--filled, which is
|
|
6142
|
+
also the opaque vdp-back + desktop overlay buttons) — translucent so photo shows through. */
|
|
6143
|
+
.md3 .gallery-controls-row .icon-btn--filled {
|
|
6144
|
+
background-color: hsla(0, 0%, 100%, .75);
|
|
6145
|
+
}
|
|
6146
|
+
/* the carousel's own overlay dots move into the on-image controls row (page-rendered;
|
|
6085
6147
|
the dots div carries an inline display:flex — hence !important) */
|
|
6086
6148
|
.md3 .vdp-gallerybox .cardcar-dots {
|
|
6087
6149
|
display: none !important;
|
|
@@ -6451,11 +6513,19 @@ color: #005CFF;
|
|
|
6451
6513
|
.md3 .vdp-similar {
|
|
6452
6514
|
margin-top: 14px !important;
|
|
6453
6515
|
}
|
|
6516
|
+
.md3 #vdp-kontakt {
|
|
6517
|
+
border: 1px solid #D4DDE7;
|
|
6518
|
+
box-shadow: none;
|
|
6519
|
+
}
|
|
6454
6520
|
.md3 #vdp-bewertungen {
|
|
6455
6521
|
padding: 28px 24px !important;
|
|
6522
|
+
border: 1px solid #D4DDE7;
|
|
6523
|
+
box-shadow: none;
|
|
6456
6524
|
}
|
|
6457
6525
|
.md3 #vdp-preis {
|
|
6458
6526
|
padding: 0 !important;
|
|
6527
|
+
border: 1px solid #D4DDE7;
|
|
6528
|
+
box-shadow: none;
|
|
6459
6529
|
}
|
|
6460
6530
|
.md3 #vdp-preis h2 {
|
|
6461
6531
|
padding: 22px 22px 0 !important;
|
|
@@ -6694,6 +6764,8 @@ color: #005CFF;
|
|
|
6694
6764
|
margin-bottom: 20px !important;
|
|
6695
6765
|
padding: 18px !important;
|
|
6696
6766
|
box-sizing: border-box;
|
|
6767
|
+
border: 1px solid #D4DDE7;
|
|
6768
|
+
box-shadow: none;
|
|
6697
6769
|
display: flex;
|
|
6698
6770
|
flex-direction: column;
|
|
6699
6771
|
}
|
|
@@ -6823,6 +6895,10 @@ color: #005CFF;
|
|
|
6823
6895
|
text-align: center;
|
|
6824
6896
|
color: #ffffff;
|
|
6825
6897
|
}
|
|
6898
|
+
.md3 #vdp-eco {
|
|
6899
|
+
border: 1px solid #D4DDE7;
|
|
6900
|
+
box-shadow: none;
|
|
6901
|
+
}
|
|
6826
6902
|
.md3 #vdp-eco .md-label-sm {
|
|
6827
6903
|
font-family: Arial, Helvetica, sans-serif;
|
|
6828
6904
|
font-style: normal;
|
|
@@ -6833,6 +6909,8 @@ color: #005CFF;
|
|
|
6833
6909
|
}
|
|
6834
6910
|
.md3 #vdp-daten {
|
|
6835
6911
|
padding: 26px 24px 34px 24px;
|
|
6912
|
+
border: 1px solid #D4DDE7;
|
|
6913
|
+
box-shadow: none;
|
|
6836
6914
|
}
|
|
6837
6915
|
.md3 #vdp-daten .mbtn--text {
|
|
6838
6916
|
font-family: Arial, Helvetica, sans-serif;
|
|
@@ -6855,6 +6933,8 @@ color: #005CFF;
|
|
|
6855
6933
|
}
|
|
6856
6934
|
.md3 #vdp-ausstattung {
|
|
6857
6935
|
padding: 28px 24px 19px 24px;
|
|
6936
|
+
border: 1px solid #D4DDE7;
|
|
6937
|
+
box-shadow: none;
|
|
6858
6938
|
}
|
|
6859
6939
|
.md3 #vdp-ausstattung h2 {
|
|
6860
6940
|
margin: 0 0 30px;
|
|
@@ -7018,6 +7098,8 @@ color: #005CFF;
|
|
|
7018
7098
|
}
|
|
7019
7099
|
.md3 .enq-country {
|
|
7020
7100
|
width: 70px;
|
|
7101
|
+
}
|
|
7102
|
+
.md3 .enq-country .mselect-label {
|
|
7021
7103
|
font-family: Arial, Helvetica, sans-serif;
|
|
7022
7104
|
font-style: normal;
|
|
7023
7105
|
font-weight: 400;
|
|
@@ -8931,3 +9013,160 @@ color: #005CFF;
|
|
|
8931
9013
|
background: var(--md-sc-lowest);
|
|
8932
9014
|
box-shadow: none;
|
|
8933
9015
|
}
|
|
9016
|
+
|
|
9017
|
+
/* ==========================================================================
|
|
9018
|
+
VdpViewer "all photos" bottom sheet (libs/packages/fe-ui-core-autobahn/vdp/VdpViewer.tsx)
|
|
9019
|
+
--------------------------------------------------------------------------
|
|
9020
|
+
New selectors only, own `.vdp-photosheet*` prefix — nothing above this block
|
|
9021
|
+
is touched. Static values live here; only per-state dynamics (slide
|
|
9022
|
+
transform/transition while open/dragging, backdrop opacity/pointer-events)
|
|
9023
|
+
stay inline in the component. 3 grid columns is the default (portrait,
|
|
9024
|
+
<=693px); the 693-860px media query below is the ONLY landscape-specific
|
|
9025
|
+
override, matching the one visual difference the spec calls for.
|
|
9026
|
+
========================================================================== */
|
|
9027
|
+
.md3 .vdp-photosheet-backdrop {
|
|
9028
|
+
position: absolute;
|
|
9029
|
+
inset: 0;
|
|
9030
|
+
background: rgba(0, 0, 0, 0.5);
|
|
9031
|
+
z-index: 210;
|
|
9032
|
+
}
|
|
9033
|
+
.md3 .vdp-photosheet {
|
|
9034
|
+
position: absolute;
|
|
9035
|
+
left: 0;
|
|
9036
|
+
right: 0;
|
|
9037
|
+
bottom: 0;
|
|
9038
|
+
height: 100vh;
|
|
9039
|
+
z-index: 211;
|
|
9040
|
+
display: flex;
|
|
9041
|
+
flex-direction: column;
|
|
9042
|
+
/* same dark color as the viewer's own header bar (rgba(6,11,18,0.8)), but fully opaque: the
|
|
9043
|
+
header uses 0.8 alpha OVER a photo, whereas this panel sits over the dimmed backdrop + viewer
|
|
9044
|
+
behind it — at 0.8 alpha, high-contrast content back there (e.g. the blue CTA button) bled
|
|
9045
|
+
through visibly during testing, so opacity is dropped without changing the hue itself. */
|
|
9046
|
+
background: rgb(6, 11, 18);
|
|
9047
|
+
border-radius: 16px 16px 0 0;
|
|
9048
|
+
overflow: hidden;
|
|
9049
|
+
}
|
|
9050
|
+
.md3 .vdp-photosheet__header {
|
|
9051
|
+
position: relative;
|
|
9052
|
+
flex: none;
|
|
9053
|
+
display: flex;
|
|
9054
|
+
align-items: center;
|
|
9055
|
+
justify-content: center;
|
|
9056
|
+
min-height: 88px;
|
|
9057
|
+
padding-top: 10px;
|
|
9058
|
+
touch-action: none;
|
|
9059
|
+
}
|
|
9060
|
+
.md3 .vdp-photosheet__handle {
|
|
9061
|
+
position: absolute;
|
|
9062
|
+
top: 8px;
|
|
9063
|
+
left: 50%;
|
|
9064
|
+
transform: translateX(-50%);
|
|
9065
|
+
width: 36px;
|
|
9066
|
+
height: 4px;
|
|
9067
|
+
border-radius: 2px;
|
|
9068
|
+
background: rgba(255, 255, 255, 0.28);
|
|
9069
|
+
}
|
|
9070
|
+
.md3 .vdp-photosheet__close {
|
|
9071
|
+
position: absolute;
|
|
9072
|
+
left: 12px;
|
|
9073
|
+
top: 50%;
|
|
9074
|
+
transform: translateY(-50%);
|
|
9075
|
+
}
|
|
9076
|
+
.md3 .vdp-photosheet__logo {
|
|
9077
|
+
display: flex;
|
|
9078
|
+
align-items: center;
|
|
9079
|
+
justify-content: center;
|
|
9080
|
+
}
|
|
9081
|
+
.md3 .vdp-photosheet__logo--portrait {
|
|
9082
|
+
transform: scale(0.75);
|
|
9083
|
+
}
|
|
9084
|
+
.md3 .vdp-photosheet__titles {
|
|
9085
|
+
flex: none;
|
|
9086
|
+
padding: 0 16px 12px;
|
|
9087
|
+
text-align: left;
|
|
9088
|
+
}
|
|
9089
|
+
.md3 .vdp-photosheet__title {
|
|
9090
|
+
margin: 0;
|
|
9091
|
+
font-family: 'Inter', var(--md-font);
|
|
9092
|
+
font-size: 18px;
|
|
9093
|
+
font-weight: 700;
|
|
9094
|
+
line-height: 24px;
|
|
9095
|
+
color: #ffffff;
|
|
9096
|
+
}
|
|
9097
|
+
.md3 .vdp-photosheet__subtitle {
|
|
9098
|
+
margin: 4px 0 0;
|
|
9099
|
+
font-family: 'Inter', var(--md-font);
|
|
9100
|
+
font-size: 13px;
|
|
9101
|
+
font-weight: 400;
|
|
9102
|
+
line-height: 18px;
|
|
9103
|
+
color: rgba(255, 255, 255, 0.56);
|
|
9104
|
+
}
|
|
9105
|
+
.md3 .vdp-photosheet__scroll {
|
|
9106
|
+
flex: 1;
|
|
9107
|
+
min-height: 0;
|
|
9108
|
+
overflow-y: auto;
|
|
9109
|
+
padding: 0 12px 12px;
|
|
9110
|
+
}
|
|
9111
|
+
.md3 .vdp-photosheet__grid {
|
|
9112
|
+
display: grid;
|
|
9113
|
+
grid-template-columns: repeat(3, 1fr);
|
|
9114
|
+
gap: 8px;
|
|
9115
|
+
}
|
|
9116
|
+
.md3 .vdp-photosheet__tile {
|
|
9117
|
+
position: relative;
|
|
9118
|
+
aspect-ratio: 4 / 3;
|
|
9119
|
+
box-sizing: border-box;
|
|
9120
|
+
border-radius: 10px;
|
|
9121
|
+
overflow: hidden;
|
|
9122
|
+
border: 1px solid rgba(255, 255, 255, 0.16);
|
|
9123
|
+
padding: 0;
|
|
9124
|
+
cursor: pointer;
|
|
9125
|
+
background: rgba(255, 255, 255, 0.06);
|
|
9126
|
+
}
|
|
9127
|
+
.md3 .vdp-photosheet__tile img {
|
|
9128
|
+
width: 100%;
|
|
9129
|
+
height: 100%;
|
|
9130
|
+
object-fit: cover;
|
|
9131
|
+
display: block;
|
|
9132
|
+
}
|
|
9133
|
+
.md3 .vdp-photosheet__tile--active {
|
|
9134
|
+
border: 3px solid #0b63f6;
|
|
9135
|
+
}
|
|
9136
|
+
.md3 .vdp-photosheet__badge {
|
|
9137
|
+
position: absolute;
|
|
9138
|
+
top: 6px;
|
|
9139
|
+
right: 6px;
|
|
9140
|
+
width: 20px;
|
|
9141
|
+
height: 20px;
|
|
9142
|
+
border-radius: 50%;
|
|
9143
|
+
background: #0b63f6;
|
|
9144
|
+
display: flex;
|
|
9145
|
+
align-items: center;
|
|
9146
|
+
justify-content: center;
|
|
9147
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
|
9148
|
+
}
|
|
9149
|
+
.md3 .vdp-photosheet__footer {
|
|
9150
|
+
flex: none;
|
|
9151
|
+
display: flex;
|
|
9152
|
+
align-items: center;
|
|
9153
|
+
justify-content: flex-start;
|
|
9154
|
+
gap: 6px;
|
|
9155
|
+
height: 44px;
|
|
9156
|
+
padding: 0 16px;
|
|
9157
|
+
/* rgba(0,0,0,0.5) was invisible here — it darkens whatever's behind it, and the sheet's own
|
|
9158
|
+
panel (rgb(6,11,18)) is already almost black, so a 50%-black overlay on top of near-black
|
|
9159
|
+
reads as no change at all. #1c222c is lighter/bluer and already used elsewhere in this same
|
|
9160
|
+
file (landscape's "Anrufen" CTA background), so it's a real, visible band without a new tone. */
|
|
9161
|
+
background: #1c222c;
|
|
9162
|
+
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
|
9163
|
+
color: rgba(255, 255, 255, 0.72);
|
|
9164
|
+
font-family: 'Inter', var(--md-font);
|
|
9165
|
+
font-size: 13px;
|
|
9166
|
+
font-weight: 500;
|
|
9167
|
+
}
|
|
9168
|
+
@media (min-width: 693px) and (max-width: 860px) {
|
|
9169
|
+
.md3 .vdp-photosheet__grid {
|
|
9170
|
+
grid-template-columns: repeat(4, 1fr);
|
|
9171
|
+
}
|
|
9172
|
+
}
|
package/vdp/VdpModules.tsx
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
import React, { useState } from 'react';
|
|
25
25
|
import { TranslationFunction } from '../types';
|
|
26
26
|
|
|
27
|
-
import { Button, Icon, Spec, StatChip, Stars, Switch } from '../ui';
|
|
27
|
+
import { Button, Dropdown, DropdownOption, Icon, Spec, StatChip, Stars, Switch } from '../ui';
|
|
28
28
|
import { CO2_CLASSES, CO2_COLORS, TIER_LABELS, TIER_KEYS, TIER_COLORS, TIER_BACKGROUNDS } from '../constants';
|
|
29
29
|
import { defaultVdpSpecs, EquipmentGroups, PriceRatingBands, VehicleDetail, VdpSpec, VdpReview } from './types';
|
|
30
30
|
import { CalcRow, DocCheckIcon, EvalBar, expanderBtnStyle, FinanceMode, Slider, TermChips } from './FinanceCalculator';
|
|
@@ -2495,6 +2495,7 @@ export const ReviewsTeaser: React.FunctionComponent<ReviewsTeaserProps> = ({ cou
|
|
|
2495
2495
|
alignItems: 'center',
|
|
2496
2496
|
justifyContent: 'space-between',
|
|
2497
2497
|
gap: 12,
|
|
2498
|
+
border: '1px solid #D4DDE7',
|
|
2498
2499
|
// sits between the finance card (order:3) and the highlights card (order:4) in the
|
|
2499
2500
|
// mobile .vdp-grid flex flow — tie-broken to AFTER the aside by JSX/DOM source order.
|
|
2500
2501
|
order: 3,
|
|
@@ -2682,6 +2683,12 @@ const FloatField: React.FunctionComponent<{
|
|
|
2682
2683
|
</label>
|
|
2683
2684
|
);
|
|
2684
2685
|
|
|
2686
|
+
/** phone country-code options for the "Land" dropdown (Figma: DE/AT/CH pinned first, then A–Z). */
|
|
2687
|
+
const ENQUIRY_COUNTRY_CODES: DropdownOption[] = [
|
|
2688
|
+
'+49', '+43', '+41', '+7', '+31', '+32', '+33', '+34', '+36', '+39', '+40', '+44', '+45', '+46',
|
|
2689
|
+
'+47', '+48', '+352', '+358', '+359', '+380', '+385', '+386', '+420', '+421', '+423',
|
|
2690
|
+
].map((code) => ({ value: code, label: code }));
|
|
2691
|
+
|
|
2685
2692
|
/** [icon, i18n label key] — resolved against the drilled t in the component. */
|
|
2686
2693
|
const ENQUIRY_BENEFITS: ReadonlyArray<[string, string]> = [
|
|
2687
2694
|
['clock', 'autobahn:enquiry.benefits.fastResponse'],
|
|
@@ -2704,6 +2711,7 @@ export const VdpEnquiry: React.FunctionComponent<VdpEnquiryProps> = ({
|
|
|
2704
2711
|
const [firstName, setFirstName] = useState('');
|
|
2705
2712
|
const [lastName, setLastName] = useState('');
|
|
2706
2713
|
const [email, setEmail] = useState('');
|
|
2714
|
+
const [countryCode, setCountryCode] = useState('+49');
|
|
2707
2715
|
const [areaCode, setAreaCode] = useState('');
|
|
2708
2716
|
const [phoneNum, setPhoneNum] = useState('');
|
|
2709
2717
|
const [consent, setConsent] = useState(false);
|
|
@@ -2719,15 +2727,18 @@ export const VdpEnquiry: React.FunctionComponent<VdpEnquiryProps> = ({
|
|
|
2719
2727
|
|
|
2720
2728
|
const emailOk = /.+@.+\..+/.test(email);
|
|
2721
2729
|
const phoneDigits = (areaCode + phoneNum).replace(/\D/g, '');
|
|
2722
|
-
|
|
2723
|
-
//
|
|
2724
|
-
|
|
2730
|
+
// backend (contact-form-users) caps the concatenated phoneMain (countryCode + areaCode +
|
|
2731
|
+
// phoneNum) at 22 chars total — mirrored here so an over-length number is caught before submit.
|
|
2732
|
+
const phoneOk = phoneDigits.length >= 6 && countryCode.length + areaCode.trim().length + phoneNum.trim().length <= 22;
|
|
2733
|
+
// Round 14: which channel is required follows the E-Mail/Telefon toggle — the * moves
|
|
2734
|
+
// between the e-mail field and the country-code field accordingly; the other channel
|
|
2735
|
+
// stays optional (validated only when filled); names + consent always required.
|
|
2725
2736
|
const valid =
|
|
2726
2737
|
firstName.trim().length > 0 &&
|
|
2727
2738
|
lastName.trim().length > 0 &&
|
|
2728
2739
|
consent &&
|
|
2729
|
-
phoneOk &&
|
|
2730
|
-
(email.trim().length === 0 || emailOk);
|
|
2740
|
+
(pref === 'email' ? emailOk : phoneOk) &&
|
|
2741
|
+
(pref === 'email' ? phoneDigits.length === 0 || phoneOk : email.trim().length === 0 || emailOk);
|
|
2731
2742
|
|
|
2732
2743
|
const submit = async (): Promise<void> => {
|
|
2733
2744
|
if (!valid || sending) return;
|
|
@@ -2736,7 +2747,7 @@ export const VdpEnquiry: React.FunctionComponent<VdpEnquiryProps> = ({
|
|
|
2736
2747
|
const note = t('autobahn:enquiry.preferredContact', {
|
|
2737
2748
|
channel: pref === 'email' ? t('autobahn:enquiry.contactMethod.email') : t('autobahn:enquiry.contactMethod.phone'),
|
|
2738
2749
|
});
|
|
2739
|
-
const phone = phoneDigits ?
|
|
2750
|
+
const phone = phoneDigits ? `${countryCode}${areaCode.trim()}${phoneNum.trim()}`.replace(/\s+/g, '') : '';
|
|
2740
2751
|
try {
|
|
2741
2752
|
await onSubmit({
|
|
2742
2753
|
name: `${firstName.trim()} ${lastName.trim()}`,
|
|
@@ -2843,26 +2854,30 @@ export const VdpEnquiry: React.FunctionComponent<VdpEnquiryProps> = ({
|
|
|
2843
2854
|
<input
|
|
2844
2855
|
style={enquiryInput}
|
|
2845
2856
|
type="email"
|
|
2846
|
-
// e-mail is
|
|
2847
|
-
placeholder={t('autobahn:enquiry.form.emailPlaceholder').replace(/\*$/, '')}
|
|
2857
|
+
// asterisk shows only while e-mail is the selected contact channel (round 14)
|
|
2858
|
+
placeholder={pref === 'email' ? t('autobahn:enquiry.form.emailPlaceholder') : t('autobahn:enquiry.form.emailPlaceholder').replace(/\*$/, '')}
|
|
2848
2859
|
value={email}
|
|
2849
2860
|
onChange={(e) => setEmail(e.target.value)}
|
|
2850
2861
|
aria-label={t('autobahn:enquiry.contactMethod.email')}
|
|
2851
2862
|
/>
|
|
2852
2863
|
</div>
|
|
2853
|
-
{/* Land (
|
|
2864
|
+
{/* Land (country-code dropdown) · Vorwahl · Telefonnummer — outlined float-label row (Figma) */}
|
|
2854
2865
|
<div className="enq-phone-row" style={{ marginTop: 16 }}>
|
|
2855
|
-
{/*
|
|
2856
|
-
<FloatField label={t('autobahn:enquiry.form.countryLabel') + '*'}>
|
|
2857
|
-
<
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2866
|
+
{/* * sits on the country-code field only while Telefon is the selected channel (round 14) */}
|
|
2867
|
+
<FloatField label={t('autobahn:enquiry.form.countryLabel') + (pref === 'phone' ? '*' : '')}>
|
|
2868
|
+
<Dropdown
|
|
2869
|
+
value={countryCode}
|
|
2870
|
+
options={ENQUIRY_COUNTRY_CODES}
|
|
2871
|
+
onChange={setCountryCode}
|
|
2872
|
+
ariaLabel={t('autobahn:enquiry.form.countryLabel')}
|
|
2873
|
+
className="enq-country"
|
|
2874
|
+
/>
|
|
2861
2875
|
</FloatField>
|
|
2862
2876
|
<FloatField label={t('autobahn:enquiry.form.areaCodeLabel')}>
|
|
2863
2877
|
<input
|
|
2864
2878
|
type="tel"
|
|
2865
2879
|
placeholder="1638"
|
|
2880
|
+
maxLength={5}
|
|
2866
2881
|
value={areaCode}
|
|
2867
2882
|
onChange={(e) => setAreaCode(e.target.value)}
|
|
2868
2883
|
aria-label={t('autobahn:enquiry.form.areaCodeLabel')}
|
|
@@ -2872,6 +2887,7 @@ export const VdpEnquiry: React.FunctionComponent<VdpEnquiryProps> = ({
|
|
|
2872
2887
|
<input
|
|
2873
2888
|
type="tel"
|
|
2874
2889
|
placeholder="5857458"
|
|
2890
|
+
maxLength={13}
|
|
2875
2891
|
value={phoneNum}
|
|
2876
2892
|
onChange={(e) => setPhoneNum(e.target.value)}
|
|
2877
2893
|
aria-label={t('autobahn:enquiry.form.phoneNumberLabel')}
|