@bytebrand/fe-ui-core-autobahn 1.0.21 → 1.0.23
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 +46 -17
- package/ui/CardCarousel.tsx +1 -0
- package/vdp/FinanceCalculator.tsx +53 -26
- package/vdp/VdpModules.tsx +4 -2
package/locales/de/autobahn.json
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"leaseTerms": "{{mileage}} km/Jahr · {{months}} Monate",
|
|
15
15
|
"purchasePrice": "Kaufpreis",
|
|
16
16
|
"priceDropAmount": "−{{amount}} €",
|
|
17
|
+
"priceDropSave": "{{amount}} € sparen",
|
|
17
18
|
"savedAmount": "{{amount}} € gespart",
|
|
18
19
|
"zeroDownCompact": "0 € Anz.",
|
|
19
20
|
"zeroDown": "0 € Anzahlung",
|
|
@@ -414,7 +415,9 @@
|
|
|
414
415
|
"back": "zurück",
|
|
415
416
|
"share": "teilen",
|
|
416
417
|
"photos": "Alle {{count}} Fotos",
|
|
417
|
-
"photos_plural": "Alle {{count}} Fotos"
|
|
418
|
+
"photos_plural": "Alle {{count}} Fotos",
|
|
419
|
+
"photosCount": "{{count}} Fotos",
|
|
420
|
+
"photosCount_plural": "{{count}} Fotos"
|
|
418
421
|
},
|
|
419
422
|
"favorite": {
|
|
420
423
|
"label": "merken"
|
package/locales/en/autobahn.json
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"leaseTerms": "{{mileage}} km/year · {{months}} months",
|
|
15
15
|
"purchasePrice": "Purchase price",
|
|
16
16
|
"priceDropAmount": "−{{amount}} €",
|
|
17
|
+
"priceDropSave": "Save {{amount}} €",
|
|
17
18
|
"savedAmount": "€{{amount}} saved",
|
|
18
19
|
"zeroDownCompact": "€0 down",
|
|
19
20
|
"zeroDown": "€0 down payment",
|
|
@@ -414,7 +415,9 @@
|
|
|
414
415
|
"back": "Back",
|
|
415
416
|
"share": "Share",
|
|
416
417
|
"photos": "All {{count}} photos",
|
|
417
|
-
"photos_plural": "All {{count}} photos"
|
|
418
|
+
"photos_plural": "All {{count}} photos",
|
|
419
|
+
"photosCount": "{{count}} photos",
|
|
420
|
+
"photosCount_plural": "{{count}} photos"
|
|
418
421
|
},
|
|
419
422
|
"favorite": {
|
|
420
423
|
"label": "Save"
|
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.23",
|
|
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
|
@@ -155,12 +155,12 @@
|
|
|
155
155
|
NOT the 38px tappable filter-chip the base .chip is. */
|
|
156
156
|
.md3 .listcard-chips .chip { height: 24px; padding: 0 10px; font-size: 11.5px; border-radius: 8px; cursor: default; }
|
|
157
157
|
.md3 .listcard-chips .chip:hover { background: var(--md-surface); border-color: var(--md-outline-variant); }
|
|
158
|
-
/* VDP trust row (Sofort verfügbar/views/favorites/Geprüft) —
|
|
159
|
-
|
|
160
|
-
.md3 .vdp-trust-chip { display: inline-flex; align-items: center; gap: 6px; height:
|
|
161
|
-
border-radius:
|
|
162
|
-
background:
|
|
163
|
-
.md3 .vdp-trust-chip .lucide { width:
|
|
158
|
+
/* VDP trust row (Sofort verfügbar/views/favorites/Geprüft) — mobile-only, so the figma
|
|
159
|
+
push-chip palette is used literally (light blue-gray fill, dark bold label). */
|
|
160
|
+
.md3 .vdp-trust-chip { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 11px;
|
|
161
|
+
border-radius: 11px; font-size: 11px; font-weight: 700; line-height: 1; cursor: default; white-space: nowrap;
|
|
162
|
+
background: #F5F7FA; color: #1D2A38; border: 1px solid #E5EAF0; }
|
|
163
|
+
.md3 .vdp-trust-chip .lucide { width: 16px; height: 16px; flex: none; }
|
|
164
164
|
|
|
165
165
|
/* status / rating chip (no CTA) */
|
|
166
166
|
.md3 .statchip { display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 10px;
|
|
@@ -174,12 +174,17 @@
|
|
|
174
174
|
border-radius: var(--md-r-full); background: rgba(0,0,0,.55); color: #fff; font-size: 12px; font-weight: 500; backdrop-filter: blur(2px); }
|
|
175
175
|
.md3 .imglabel .lucide { width: 14px; height: 14px; }
|
|
176
176
|
|
|
177
|
-
/* mobile-only row under the gallery image:
|
|
178
|
-
|
|
179
|
-
.md3 .gallery-controls-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 2px 0; }
|
|
180
|
-
.md3 .gallery-photos-btn { display: inline-flex; align-items: center; gap:
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
/* mobile-only row under the gallery image (mockup): bordered "X Fotos" pill · slider dots ·
|
|
178
|
+
share/favorite — all in ONE row in normal flow, nothing overlaid on the image. */
|
|
179
|
+
.md3 .gallery-controls-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 2px 0; }
|
|
180
|
+
.md3 .gallery-photos-btn { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font: inherit;
|
|
181
|
+
font-size: 12px; font-weight: 700; color: var(--md-on-surface); height: 34px; padding: 0 13px; flex: none;
|
|
182
|
+
background: #fff; border: 1px solid #D4DDE7; border-radius: 16px; }
|
|
183
|
+
.md3 .gallery-photos-btn .lucide { width: 17px; height: 17px; }
|
|
184
|
+
/* page-driven slider dots (the carousel's own overlay dots are hidden on the phone VDP) */
|
|
185
|
+
.md3 .gallery-dots { display: flex; align-items: center; gap: 6px; min-width: 0; overflow: hidden; }
|
|
186
|
+
.md3 .gallery-dots .gdot { width: 6px; height: 6px; border-radius: 3px; background: #D4DDE7; flex: none; }
|
|
187
|
+
.md3 .gallery-dots .gdot--on { width: 30px; height: 5px; background: var(--md-on-surface); }
|
|
183
188
|
|
|
184
189
|
/* ---------- cards ---------- */
|
|
185
190
|
.md3 .mcard { background: var(--md-sc-lowest); border-radius: var(--md-r-md); border: 1px solid var(--md-outline-variant);
|
|
@@ -1160,8 +1165,10 @@
|
|
|
1160
1165
|
margin-bottom: -1px; transition: color .15s, border-color .15s; text-align: center; }
|
|
1161
1166
|
.md3 .fin-tab.on { color: var(--md-primary); border-bottom-color: var(--md-primary); }
|
|
1162
1167
|
.md3 .fin-tab:hover:not(.on) { color: var(--md-on-surface); }
|
|
1163
|
-
/* 2-col grid: left grows, right fixed 148px — pill (row 1) and bar (row 2) share a column edge, never wrap
|
|
1164
|
-
|
|
1168
|
+
/* 2-col grid: left grows, right fixed 148px — pill (row 1) and bar (row 2) share a column edge, never wrap.
|
|
1169
|
+
minmax(0,1fr) lets the rate column SHRINK below its content (plain 1fr's min is auto, which let the
|
|
1170
|
+
52px phone rate blow the whole card past the viewport). */
|
|
1171
|
+
.md3 .fin-price-grid { display: grid; grid-template-columns: minmax(0, 1fr) 148px; gap: 6px 16px; align-items: center; margin-top: 8px; }
|
|
1165
1172
|
.md3 .fin-rate-main { min-width: 0; }
|
|
1166
1173
|
/* rating pill — light tier-tinted bg, tier-colored text + icon (bg/color set inline per tier) */
|
|
1167
1174
|
.md3 .fin-eval-pill { display: inline-flex; align-items: center; gap: 5px; padding: 6px 13px;
|
|
@@ -1463,13 +1470,35 @@
|
|
|
1463
1470
|
display: flex; align-items: center; justify-content: center; rotate: 45deg; box-shadow: var(--md-e2); }
|
|
1464
1471
|
.md3 .dealer-pin .lucide { rotate: -45deg; }
|
|
1465
1472
|
|
|
1466
|
-
/* VDP: floating back button over the gallery —
|
|
1473
|
+
/* VDP: floating back button over the gallery — hidden everywhere now (the phone mockup
|
|
1474
|
+
shows a clean image with only the nav arrows; desktop has the breadcrumb). */
|
|
1467
1475
|
.md3 .vdp-back { display: none; position: absolute; top: 12px; left: 14px; z-index: 3; }
|
|
1468
1476
|
|
|
1477
|
+
/* mobile push-badges row ABOVE the gallery (mockup): flat tinted pills in normal flow —
|
|
1478
|
+
replaces the white overlay chips (DropChip & co) that sat on the image. Figma palette
|
|
1479
|
+
used literally; one non-wrapping swipeable line. */
|
|
1480
|
+
.md3 .vdp-push-badges { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; overflow-x: auto;
|
|
1481
|
+
scrollbar-width: none; margin-bottom: 10px; }
|
|
1482
|
+
.md3 .vdp-push-badges::-webkit-scrollbar { display: none; }
|
|
1483
|
+
.md3 .push-badge { display: inline-flex; align-items: center; justify-content: center; height: 28px; padding: 0 13px;
|
|
1484
|
+
border-radius: 11px; font-size: 13.5px; font-weight: 700; line-height: 1; white-space: nowrap; flex: none; }
|
|
1485
|
+
.md3 .push-badge--save { background: #E6F7EE; color: #168A45; border: 1px solid rgba(22,138,69,.07); }
|
|
1486
|
+
.md3 .push-badge--discount { background: #E60000; color: #fff; }
|
|
1487
|
+
.md3 .push-badge--down { background: #EAF2FF; color: #005CFF; border: 1px solid rgba(0,92,255,.05); }
|
|
1488
|
+
|
|
1469
1489
|
@media (max-width: 600px) {
|
|
1470
1490
|
/* full-bleed gallery: edge-to-edge, app-like (production pattern) */
|
|
1471
|
-
.md3 .vdp-
|
|
1472
|
-
|
|
1491
|
+
.md3 .vdp-gallerybox { margin: 0 -24px; border-radius: 0; border: 0; box-shadow: none; }
|
|
1492
|
+
/* the carousel's own overlay dots move into the below-image controls row (page-rendered;
|
|
1493
|
+
the dots div carries an inline display:flex — hence !important) */
|
|
1494
|
+
.md3 .vdp-gallerybox .cardcar-dots { display: none !important; }
|
|
1495
|
+
/* mockup hero rate is a notch bigger on phone (inline style says 48 — hence !important) */
|
|
1496
|
+
.md3 .fin-rate-main .num { font-size: 52px !important; letter-spacing: -1.5px !important; }
|
|
1497
|
+
/* narrower rating column (figma bar is 115px) frees room for the bigger rate; let the
|
|
1498
|
+
€ /mtl. suffix wrap under the number instead of pushing the grid wide on 4-digit rates */
|
|
1499
|
+
.md3 .fin-price-grid { grid-template-columns: minmax(0, 1fr) 112px; }
|
|
1500
|
+
.md3 .fin-rate-main > div { flex-wrap: wrap; }
|
|
1501
|
+
.md3 .fin-rate-main .md-body-sm { font-size: 15px !important; font-weight: 700 !important; color: var(--md-on-surface-variant) !important; }
|
|
1473
1502
|
}
|
|
1474
1503
|
|
|
1475
1504
|
/* ---------- save-search bar ---------- */
|
package/ui/CardCarousel.tsx
CHANGED
|
@@ -312,7 +312,17 @@ const FinanceCalculator: React.FunctionComponent<FinanceCalculatorProps> = ({
|
|
|
312
312
|
className={'fin-tab' + (mode === k ? ' on' : '')}
|
|
313
313
|
onClick={() => onModeChange(k)}
|
|
314
314
|
>
|
|
315
|
-
{
|
|
315
|
+
{k === 'cash' ? (
|
|
316
|
+
<>
|
|
317
|
+
{/* mockup names the cash tab "Kaufen" on phone; desktop keeps "Barzahlung" */}
|
|
318
|
+
<span className="hide-mobile">{t(labelKey)}</span>
|
|
319
|
+
<span className="show-mobile" style={{ justifyContent: 'center' }}>
|
|
320
|
+
{t('autobahn:card.price.buy')}
|
|
321
|
+
</span>
|
|
322
|
+
</>
|
|
323
|
+
) : (
|
|
324
|
+
t(labelKey)
|
|
325
|
+
)}
|
|
316
326
|
</button>
|
|
317
327
|
))}
|
|
318
328
|
</div>
|
|
@@ -469,34 +479,30 @@ const FinanceCalculator: React.FunctionComponent<FinanceCalculatorProps> = ({
|
|
|
469
479
|
|
|
470
480
|
{/* ============================== MOBILE (≤600px) — new layout ============================== */}
|
|
471
481
|
<div className="show-mobile" style={{ flexDirection: 'column' }}>
|
|
472
|
-
{/* side-by-side CTAs
|
|
473
|
-
|
|
474
|
-
|
|
482
|
+
{/* side-by-side CTAs — mockup ratio ~2:1, with the tiny auto.de-ID sitting
|
|
483
|
+
directly under the Anrufen button (not in its own full-width row). */}
|
|
484
|
+
<div style={{ display: 'flex', gap: 10, marginTop: 14, alignItems: 'flex-start' }}>
|
|
485
|
+
<Button variant="filled" size="lg" icon="shield-check" style={{ flex: 2 }} onClick={onSecure}>
|
|
475
486
|
{t('autobahn:finance.secureOffer')}
|
|
476
487
|
</Button>
|
|
477
|
-
<
|
|
478
|
-
{
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
{!isCash && onShowDetails && (
|
|
489
|
-
<DetailsLink
|
|
490
|
-
label={mode === 'leasing' ? t('autobahn:finance.leasingDetails') : t('autobahn:finance.financingDetails')}
|
|
491
|
-
onClick={onShowDetails}
|
|
492
|
-
/>
|
|
488
|
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0 }}>
|
|
489
|
+
<Button variant="outlined" size="lg" icon="phone" block onClick={onCall}>
|
|
490
|
+
{t('autobahn:finance.callCta')}
|
|
491
|
+
</Button>
|
|
492
|
+
{autoDeId && (
|
|
493
|
+
<span
|
|
494
|
+
className="num"
|
|
495
|
+
style={{ fontSize: 10, fontWeight: 700, color: 'var(--md-primary)', textAlign: 'center', whiteSpace: 'nowrap' }}
|
|
496
|
+
>
|
|
497
|
+
auto.de ID: {autoDeId}
|
|
498
|
+
</span>
|
|
493
499
|
)}
|
|
494
500
|
</div>
|
|
495
|
-
|
|
501
|
+
</div>
|
|
496
502
|
|
|
497
|
-
{/* Persönliche Beratung (left) · Finanzierungs-/Leasingdetails or hint (right) */}
|
|
503
|
+
{/* Persönliche Beratung (left) · divider · Finanzierungs-/Leasingdetails or hint (right) */}
|
|
498
504
|
<div className="fin-info">
|
|
499
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
|
|
505
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flex: 1 }}>
|
|
500
506
|
<Icon name="user" size={18} color="var(--md-on-surface-variant)" style={{ flex: 'none' }} />
|
|
501
507
|
<div style={{ minWidth: 0 }}>
|
|
502
508
|
<div className="md-label-sm" style={{ fontWeight: 700, color: 'var(--md-on-surface)' }}>
|
|
@@ -505,9 +511,30 @@ const FinanceCalculator: React.FunctionComponent<FinanceCalculatorProps> = ({
|
|
|
505
511
|
<div className="md-label-sm">{t('autobahn:finance.personalConsultationSub')}</div>
|
|
506
512
|
</div>
|
|
507
513
|
</div>
|
|
508
|
-
{
|
|
509
|
-
|
|
510
|
-
|
|
514
|
+
<span style={{ width: 1, alignSelf: 'stretch', background: 'var(--md-outline-variant)', flex: 'none' }} />
|
|
515
|
+
{!isCash && onShowDetails ? (
|
|
516
|
+
<button
|
|
517
|
+
type="button"
|
|
518
|
+
onClick={onShowDetails}
|
|
519
|
+
style={{
|
|
520
|
+
display: 'flex',
|
|
521
|
+
alignItems: 'center',
|
|
522
|
+
gap: 8,
|
|
523
|
+
background: 'none',
|
|
524
|
+
border: 0,
|
|
525
|
+
padding: 0,
|
|
526
|
+
cursor: 'pointer',
|
|
527
|
+
font: 'inherit',
|
|
528
|
+
color: 'var(--md-on-surface)',
|
|
529
|
+
textAlign: 'left',
|
|
530
|
+
}}
|
|
531
|
+
>
|
|
532
|
+
<Icon name="info" size={18} color="var(--md-on-surface-variant)" style={{ flex: 'none' }} />
|
|
533
|
+
<span className="md-label-sm" style={{ maxWidth: 82, lineHeight: 1.5 }}>
|
|
534
|
+
{mode === 'leasing' ? t('autobahn:finance.leasingDetails') : t('autobahn:finance.financingDetails')}
|
|
535
|
+
</span>
|
|
536
|
+
</button>
|
|
537
|
+
) : (
|
|
511
538
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6, color: 'var(--md-on-surface-variant)' }}>
|
|
512
539
|
<Icon name="info" size={15} />
|
|
513
540
|
<span className="md-label-sm">{t('autobahn:finance.financingLeasingPossible')}</span>
|
package/vdp/VdpModules.tsx
CHANGED
|
@@ -175,7 +175,8 @@ export interface VdpTrustRowProps {
|
|
|
175
175
|
* availability · view count · favorite count · "Geprüft" (every auto.de listing is
|
|
176
176
|
* 130-point inspected, so this one is always shown, not conditional real data). */
|
|
177
177
|
export const VdpTrustRow: React.FunctionComponent<VdpTrustRowProps> = ({ available, viewCount, favCount, t }) => (
|
|
178
|
-
|
|
178
|
+
// one swipeable line (mockup), never a ragged second row
|
|
179
|
+
<div style={{ display: 'flex', flexWrap: 'nowrap', overflowX: 'auto', scrollbarWidth: 'none', alignItems: 'center', gap: 6, marginTop: 10 }}>
|
|
179
180
|
{available && (
|
|
180
181
|
<span className="vdp-trust-chip">
|
|
181
182
|
<Icon name="check" size={13} stroke={2.4} color="var(--md-good)" />
|
|
@@ -1278,7 +1279,8 @@ export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalPro
|
|
|
1278
1279
|
[
|
|
1279
1280
|
['fin', 'autobahn:finance.mode.financing'],
|
|
1280
1281
|
['leasing', 'autobahn:finance.mode.leasing'],
|
|
1281
|
-
|
|
1282
|
+
// this sheet is mobile-only, so the cash tab is "Kaufen" here (desktop card says "Barzahlung")
|
|
1283
|
+
['cash', 'autobahn:card.price.buy'],
|
|
1282
1284
|
] as Array<[FinanceMode, string]>
|
|
1283
1285
|
).map(([k, labelKey]) => (
|
|
1284
1286
|
<button
|