@bytebrand/fe-ui-core-autobahn 1.0.25 → 1.0.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebrand/fe-ui-core-autobahn",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
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
@@ -157,10 +157,11 @@
157
157
  .md3 .listcard-chips .chip:hover { background: var(--md-surface); border-color: var(--md-outline-variant); }
158
158
  /* VDP trust row (Sofort verfügbar/views/favorites/Geprüft) — mobile-only, so the figma
159
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; }
160
+ .md3 .vdp-trust-chip { display: inline-flex; align-items: center; justify-content: center; gap: 5px; height: 30px;
161
+ padding: 0 9px; border-radius: 11px; font-size: 11px; font-weight: 700; line-height: 1; cursor: default;
162
+ white-space: nowrap; background: #F5F7FA; color: #1D2A38; border: 1px solid #E5EAF0;
163
+ flex: 1 1 auto; /* the four chips stretch to fill the block width (mockup), min = natural width */ }
164
+ .md3 .vdp-trust-chip .lucide { width: 14px; height: 14px; flex: none; }
164
165
 
165
166
  /* status / rating chip (no CTA) */
166
167
  .md3 .statchip { display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 10px;
@@ -1316,7 +1317,7 @@
1316
1317
  /* mobile-only "first screen": identity + trust row BEFORE the finance card, highlights/
1317
1318
  condition tiles moved AFTER it (both split out of the desktop-only VdpHeaderCard,
1318
1319
  which stays bundled inside .vdp-gallery, hidden on mobile via hide-mobile). */
1319
- .md3 .vdp-header-summary { order: 2; padding: 0 4px; margin-bottom: 4px; }
1320
+ .md3 .vdp-header-summary { order: 2; padding: 0; margin-bottom: 4px; /* flush with the card edges so the trust chips span the same width */ }
1320
1321
  .md3 .vdp-aside { order: 3; }
1321
1322
  .md3 .vdp-header-extras { order: 4; margin-top: 16px; }
1322
1323
  .md3 .vdp-details { order: 5; }
@@ -1389,7 +1390,7 @@
1389
1390
  .md3 .vdp-header-summary .vdp-trim { display: none; }
1390
1391
  .md3 .vdp-header-summary .vdp-meta { display: flex; flex-wrap: wrap; grid-template-columns: none; margin-top: 6px;
1391
1392
  font-size: 13.5px; font-weight: 400; color: var(--md-on-surface-variant); }
1392
- .md3 .vdp-header-summary .vdp-meta > span + span::before { content: ''; }
1393
+ .md3 .vdp-header-summary .vdp-meta > span + span::before { content: ''; margin: 0 8px; }
1393
1394
  .md3 .vdp-header-summary .vdp-meta > span { overflow: visible; text-overflow: clip; }
1394
1395
  .md3 .vdp-header-summary .vdp-meta .lucide { display: none; }
1395
1396
  .md3 .vdp-header-summary .vdp-meta > span:nth-child(5) { display: none; }
@@ -1492,12 +1493,30 @@
1492
1493
  .md3 .push-badge--discount { background: #E60000; color: #fff; }
1493
1494
  .md3 .push-badge--down { background: #EAF2FF; color: #005CFF; border: 1px solid rgba(0,92,255,.05); }
1494
1495
 
1496
+ /* "Rate anpassen" sheet (mobile modal) — mockup slider rows: bordered current-value box
1497
+ above the slider; term chips as one flat row of plain numbers (no "Mon." suffix). */
1498
+ .md3 .fin-val-box { display: inline-block; border: 1px solid var(--md-outline-variant); border-radius: 7px;
1499
+ padding: 4px 9px; font-size: 12.5px; font-weight: 600; margin-bottom: 6px; background: var(--md-sc-lowest); }
1500
+ .md3 .fin-sheet-terms .term-chips { display: flex; flex-wrap: wrap; gap: 8px; }
1501
+ .md3 .fin-sheet-terms .term-chip { flex: 1 1 0; min-width: 46px; height: 40px; border-radius: 8px; padding: 0 2px; }
1502
+ .md3 .fin-sheet-terms .tc-unit { display: none; }
1503
+ /* mockup sliders show no min/max end labels — the boxed current value carries the figure */
1504
+ .md3 .fin-sheet-adjust .mslider + div { display: none; }
1505
+
1495
1506
  @media (max-width: 600px) {
1496
- /* full-bleed gallery: edge-to-edge, app-like (production pattern) */
1497
- .md3 .vdp-gallerybox { margin: 0 -24px; border-radius: 0; border: 0; box-shadow: none; }
1507
+ /* full-bleed gallery: edge-to-edge, app-like; mockup image band is short+wide (~390×222,
1508
+ not 4:3) so the whole finance card — incl. Rate anpassen — fits the first screen */
1509
+ .md3 .vdp-gallerybox { margin: 0 -24px; border-radius: 0; border: 0; box-shadow: none;
1510
+ height: 222px; aspect-ratio: auto; }
1511
+ /* controls row straddles the image's bottom edge (mockup), half-on half-off */
1512
+ .md3 .gallery-controls-row { margin-top: -17px; position: relative; z-index: 3; padding: 0 2px; }
1498
1513
  /* the carousel's own overlay dots move into the below-image controls row (page-rendered;
1499
1514
  the dots div carries an inline display:flex — hence !important) */
1500
1515
  .md3 .vdp-gallerybox .cardcar-dots { display: none !important; }
1516
+ /* tighter stacked rhythm so title→chips→finance card land above the fold */
1517
+ .md3 .vdp-grid { gap: 14px; }
1518
+ .md3 .fin-tabs { margin-bottom: 12px; }
1519
+ .md3 .fin-info { margin-top: 10px; padding-top: 10px; }
1501
1520
  /* mockup hero rate is a notch bigger on phone (inline style says 48 — hence !important) */
1502
1521
  .md3 .fin-rate-main .num { font-size: 52px !important; letter-spacing: -1.5px !important; }
1503
1522
  /* narrower rating column (figma bar is 115px) frees room for the bigger rate; let the
@@ -530,7 +530,9 @@ const FinanceCalculator: React.FunctionComponent<FinanceCalculatorProps> = ({
530
530
  }}
531
531
  >
532
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 }}>
533
+ {/* no max-width: "Finanzierungsdetails" is one unbreakable word — capping the
534
+ span clipped it mid-word instead of wrapping */}
535
+ <span className="md-label-sm" style={{ lineHeight: 1.5 }}>
534
536
  {mode === 'leasing' ? t('autobahn:finance.leasingDetails') : t('autobahn:finance.financingDetails')}
535
537
  </span>
536
538
  </button>
@@ -176,7 +176,7 @@ export interface VdpTrustRowProps {
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
+ <div style={{ display: 'flex', flexWrap: 'nowrap', overflowX: 'auto', scrollbarWidth: 'none', alignItems: 'center', gap: 5, marginTop: 10 }}>
180
180
  {available && (
181
181
  <span className="vdp-trust-chip">
182
182
  <Icon name="check" size={13} stroke={2.4} color="var(--md-good)" />
@@ -1011,7 +1011,10 @@ const ToggleRow: React.FunctionComponent<{
1011
1011
  onChange: (checked: boolean) => void;
1012
1012
  }> = ({ label, price, checked, disabled, onChange }) => (
1013
1013
  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
1014
- <span className="md-title-sm">{label}</span>
1014
+ <span className="md-title-sm" style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
1015
+ {label}
1016
+ <Icon name="info" size={13} color="var(--md-on-surface-variant)" />
1017
+ </span>
1015
1018
  <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
1016
1019
  {price && (
1017
1020
  <span className="num" style={{ fontWeight: 700, fontSize: 13.5 }}>
@@ -1028,6 +1031,8 @@ export interface FinanceDetailsModalProps {
1028
1031
  open: boolean;
1029
1032
  /** active payment mode — drives labels + which legal example shows. */
1030
1033
  mode: 'fin' | 'leasing' | 'cash';
1034
+ /** car make+model — mobile sheet subtitle under the title (mockup). */
1035
+ vehicleName?: string;
1031
1036
  price: number;
1032
1037
  monthly: number;
1033
1038
  apr: number;
@@ -1092,6 +1097,7 @@ export interface FinanceDetailsModalProps {
1092
1097
  export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalProps> = ({
1093
1098
  open,
1094
1099
  mode,
1100
+ vehicleName,
1095
1101
  price,
1096
1102
  monthly,
1097
1103
  apr,
@@ -1204,8 +1210,13 @@ export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalPro
1204
1210
  <h2 className="md-headline-sm hide-mobile" style={{ margin: 0 }}>
1205
1211
  {title}
1206
1212
  </h2>
1207
- <h2 className="md-headline-sm show-mobile" style={{ margin: 0 }}>
1213
+ <h2 className="md-headline-sm show-mobile" style={{ margin: 0, flexDirection: 'column', alignItems: 'flex-start', gap: 2 }}>
1208
1214
  {mobileTitle}
1215
+ {vehicleName && (
1216
+ <span className="md-label-sm" style={{ fontWeight: 400 }}>
1217
+ {vehicleName}
1218
+ </span>
1219
+ )}
1209
1220
  </h2>
1210
1221
  <button className="icon-btn" onClick={onClose} aria-label={t('autobahn:modal.close')}>
1211
1222
  <Icon name="x" size={20} />
@@ -1356,20 +1367,25 @@ export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalPro
1356
1367
  <Button variant="filled" size="lg" icon="shield-check" style={{ flex: 1 }} onClick={onSecure}>
1357
1368
  {t('autobahn:finance.secureOffer')}
1358
1369
  </Button>
1359
- <Button variant="outlined" size="lg" icon="phone" style={{ width: 52, flex: 'none' }} onClick={onCall} />
1370
+ {/* padding:0 — mbtn--lg's 30px side padding left no room for the icon at width 52 */}
1371
+ <Button variant="outlined" size="lg" icon="phone" style={{ width: 52, flex: 'none', padding: 0, borderRadius: 12 }} onClick={onCall} />
1360
1372
  </div>
1361
1373
  </>
1362
1374
  ) : (
1363
1375
  <>
1364
1376
  {adjustable && (
1365
- <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
1377
+ <div className="fin-sheet-adjust" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
1366
1378
  <div>
1367
- <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
1368
- <span className="md-title-sm">{t('autobahn:finance.downPaymentSliderLabel')}</span>
1369
- <span className="num" style={{ fontWeight: 700 }}>
1379
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
1380
+ <span className="md-title-sm" style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
1381
+ {t('autobahn:finance.downPaymentSliderLabel')}
1382
+ <Icon name="info" size={13} color="var(--md-on-surface-variant)" />
1383
+ </span>
1384
+ <span className="num" style={{ fontWeight: 700, color: 'var(--md-primary)' }}>
1370
1385
  {eur(down)} €
1371
1386
  </span>
1372
1387
  </div>
1388
+ <span className="fin-val-box num">{eur(down)} €</span>
1373
1389
  <Slider
1374
1390
  min={downMin as number}
1375
1391
  max={downMax as number}
@@ -1381,12 +1397,16 @@ export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalPro
1381
1397
  </div>
1382
1398
  {isLease && annualMileage != null && onAnnualMileageChange && (
1383
1399
  <div>
1384
- <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
1385
- <span className="md-title-sm">{t('autobahn:finance.annualMileageLabel')}</span>
1386
- <span className="num" style={{ fontWeight: 700 }}>
1400
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
1401
+ <span className="md-title-sm" style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
1402
+ {t('autobahn:finance.annualMileageLabel')}
1403
+ <Icon name="info" size={13} color="var(--md-on-surface-variant)" />
1404
+ </span>
1405
+ <span className="num" style={{ fontWeight: 700, color: 'var(--md-primary)' }}>
1387
1406
  {eur(annualMileage)} km
1388
1407
  </span>
1389
1408
  </div>
1409
+ <span className="fin-val-box num">{eur(annualMileage)} km</span>
1390
1410
  <Slider
1391
1411
  min={annualMileageMin}
1392
1412
  max={annualMileageMax}
@@ -1397,9 +1417,10 @@ export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalPro
1397
1417
  />
1398
1418
  </div>
1399
1419
  )}
1400
- <div>
1401
- <div className="md-title-sm" style={{ marginBottom: 8 }}>
1402
- {t('autobahn:finance.termSelection')}
1420
+ <div className="fin-sheet-terms">
1421
+ <div className="md-title-sm" style={{ display: 'flex', alignItems: 'center', gap: 5, marginBottom: 8 }}>
1422
+ {t('autobahn:finance.termSelectionMonths')}
1423
+ <Icon name="info" size={13} color="var(--md-on-surface-variant)" />
1403
1424
  </div>
1404
1425
  <TermChips options={termVals} value={term} onChange={onTermChange as (n: number) => void} t={t} />
1405
1426
  </div>
@@ -1427,15 +1448,16 @@ export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalPro
1427
1448
  <Button variant="filled" size="lg" icon="shield-check" style={{ flex: 1 }} onClick={onSecure}>
1428
1449
  {t('autobahn:finance.requestRate')}
1429
1450
  </Button>
1430
- <Button variant="outlined" size="lg" icon="phone" style={{ width: 52, flex: 'none' }} onClick={onCall} />
1451
+ {/* padding:0 — mbtn--lg's 30px side padding left no room for the icon at width 52 */}
1452
+ <Button variant="outlined" size="lg" icon="phone" style={{ width: 52, flex: 'none', padding: 0, borderRadius: 12 }} onClick={onCall} />
1431
1453
  </div>
1432
1454
 
1433
- <button type="button" onClick={() => setShowBreakdown((v) => !v)} style={expanderBtnStyle}>
1455
+ {/* centered ⓘ details toggle (mockup shows no chevron) */}
1456
+ <button type="button" onClick={() => setShowBreakdown((v) => !v)} style={{ ...expanderBtnStyle, justifyContent: 'center', padding: '2px 0' }}>
1434
1457
  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7 }}>
1435
1458
  <Icon name="info" size={16} color="var(--md-primary)" />
1436
1459
  {isLease ? t('autobahn:modal.leasingDetails') : t('autobahn:modal.financingDetails')}
1437
1460
  </span>
1438
- <Icon name={showBreakdown ? 'chevron-up' : 'chevron-down'} size={18} color="var(--md-primary)" />
1439
1461
  </button>
1440
1462
  {showBreakdown && (
1441
1463
  <div>