From 77f0d3c3f400a3937248b64fd94c66b10b2a3c27 Mon Sep 17 00:00:00 2001 From: Mario Castigliano Date: Thu, 28 Nov 2024 16:48:55 +0100 Subject: [PATCH] fix: review part one --- .../pearl-chain-legacy.scss | 31 +-- .../pearl-chain-leg/pearl-chain-leg.scss | 59 +++-- .../pearl-chain-leg/pearl-chain-leg.ts | 31 +-- .../pearl-chain/pearl-chain/pearl-chain.scss | 41 +-- .../pearl-chain/pearl-chain.stories.ts | 21 +- .../pearl-chain/pearl-chain/pearl-chain.ts | 239 ++++++------------ .../pearl-chain/pearl-chain.visual.spec.ts | 4 +- src/storybook/pages/home/home-logged-in.ts | 22 +- 8 files changed, 169 insertions(+), 279 deletions(-) diff --git a/src/elements-experimental/pearl-chain-legacy/pearl-chain-legacy.scss b/src/elements-experimental/pearl-chain-legacy/pearl-chain-legacy.scss index b71aa0beb99..666e22a6c35 100644 --- a/src/elements-experimental/pearl-chain-legacy/pearl-chain-legacy.scss +++ b/src/elements-experimental/pearl-chain-legacy/pearl-chain-legacy.scss @@ -4,8 +4,9 @@ background-color: unset; background-image: linear-gradient(to right, currentcolor 0%, currentcolor 50%, Canvas 50%); background-repeat: repeat-x; - background-size: calc(2 * var(--sbb-pearl-chain-spacing-small)) var(--sbb-pearl-chain-height); - inset-inline-end: var(--sbb-pearl-chain-height); + background-size: calc(2 * var(--sbb-pearl-chain-leg-spacing-small)) + var(--sbb-pearl-chain-leg-height); + inset-inline-end: var(--sbb-pearl-chain-leg-height); @include sbb.if-forced-colors { background: unset; @@ -18,11 +19,11 @@ @include sbb.box-sizing; :host { - --sbb-pearl-chain-height: var(--sbb-border-width-2x); - --sbb-pearl-chain-spacing-small: #{sbb.px-to-rem-build(2)}; + --sbb-pearl-chain-leg-height: var(--sbb-border-width-2x); + --sbb-pearl-chain-leg-spacing-small: #{sbb.px-to-rem-build(2)}; --sbb-pearl-chain-color: var(--sbb-pearl-chain-bullet-color); - --sbb-pearl-chain-color-disruption: var(--sbb-pearl-chain-bullet-color-disruption); - --sbb-pearl-chain-color-past: var(--sbb-pearl-chain-bullet-color-past); + --sbb-pearl-chain-leg-color-disruption: var(--sbb-pearl-chain-bullet-color-disruption); + --sbb-pearl-chain-leg-color-past: var(--sbb-pearl-chain-bullet-color-past); --sbb-pearl-chain-leg-width: 100%; display: block; @@ -38,7 +39,7 @@ color: var(--sbb-pearl-chain-color); width: 100%; padding-block: calc( - (var(--sbb-pearl-chain-bullet-size-start-end) - var(--sbb-pearl-chain-height)) / 2 + (var(--sbb-pearl-chain-bullet-size-start-end) - var(--sbb-pearl-chain-leg-height)) / 2 ); padding-inline-end: var(--sbb-pearl-chain-bullet-size-start-end); } @@ -69,8 +70,8 @@ flex-shrink: 0; flex-grow: 0; position: relative; - height: var(--sbb-pearl-chain-height); - border-inline-end: var(--sbb-pearl-chain-spacing-small) solid Canvas; + height: var(--sbb-pearl-chain-leg-height); + border-inline-end: var(--sbb-pearl-chain-leg-spacing-small) solid Canvas; background-color: currentcolor; width: var(--sbb-pearl-chain-leg-width); display: flex; @@ -112,7 +113,7 @@ .sbb-pearl-chain__leg--progress .sbb-pearl-chain__stop, .sbb-pearl-chain--progress, .sbb-pearl-chain__bullet--past { - color: var(--sbb-pearl-chain-color-past); + color: var(--sbb-pearl-chain-leg-color-past); @include sbb.pearl-chain-bullet-past; @@ -131,7 +132,7 @@ .sbb-pearl-chain--arrival-disruption, .sbb-pearl-chain--departure-disruption, .sbb-pearl-chain__leg--disruption { - color: var(--sbb-pearl-chain-color-disruption); + color: var(--sbb-pearl-chain-leg-color-disruption); @include sbb.pearl-chain-bullet-disruption; @@ -154,7 +155,7 @@ } .sbb-pearl-chain__leg--skipped { - color: var(--sbb-pearl-chain-color-disruption); + color: var(--sbb-pearl-chain-leg-color-disruption); &::after { @include sbb-pearl-chain-dotted; @@ -179,7 +180,7 @@ inset-block: 0; inset-inline-start: 0; background-color: currentcolor; - border-radius: var(--sbb-pearl-chain-height); + border-radius: var(--sbb-pearl-chain-leg-height); z-index: 1; @include sbb.if-forced-colors { @@ -192,11 +193,11 @@ } .sbb-pearl-chain__leg:last-of-type::after { - inset-inline-end: calc(-1 * var(--sbb-pearl-chain-height)); + inset-inline-end: calc(-1 * var(--sbb-pearl-chain-leg-height)); } .sbb-pearl-chain__leg--progress::after { - background-color: var(--sbb-pearl-chain-color-past); + background-color: var(--sbb-pearl-chain-leg-color-past); // --sbb-pearl-chain-leg-status: defined in .ts file width: var(--sbb-pearl-chain-leg-status); diff --git a/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.scss b/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.scss index 9d944f9e5d7..e86dd1b0249 100644 --- a/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.scss +++ b/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.scss @@ -1,11 +1,12 @@ @use '../../core/styles' as sbb; -@mixin sbb-pearl-chain-dotted { +@mixin sbb-pearl-chain-leg-dotted { background-color: unset; background-image: linear-gradient(to right, currentcolor 0%, currentcolor 50%, Canvas 50%); background-repeat: repeat-x; - background-size: calc(2 * var(--sbb-pearl-chain-spacing-small)) var(--sbb-pearl-chain-height); - inset-inline-end: var(--sbb-pearl-chain-height); + background-size: calc(2 * var(--sbb-pearl-chain-leg-spacing-small)) + var(--sbb-pearl-chain-leg-height); + inset-inline-end: var(--sbb-pearl-chain-leg-height); @include sbb.if-forced-colors { background: unset; @@ -18,13 +19,11 @@ @include sbb.box-sizing; :host { - --sbb-pearl-chain-height: var(--sbb-border-width-2x); - --sbb-pearl-chain-spacing-small: #{sbb.px-to-rem-build(2)}; - --sbb-pearl-chain-color: var(--sbb-pearl-chain-bullet-color); - --sbb-pearl-chain-color-disruption: var(--sbb-pearl-chain-bullet-color-disruption); - --sbb-pearl-chain-color-past: var(--sbb-pearl-chain-bullet-color-past); + --sbb-pearl-chain-leg-height: var(--sbb-border-width-2x); + --sbb-pearl-chain-leg-spacing-small: #{sbb.px-to-rem-build(2)}; + --sbb-pearl-chain-leg-color-disruption: var(--sbb-pearl-chain-bullet-color-disruption); + --sbb-pearl-chain-leg-color-past: var(--sbb-pearl-chain-bullet-color-past); --sbb-pearl-chain-leg-width: 100%; - --sbb-pearl-chain-leg-animation: none; display: contents; @@ -34,8 +33,11 @@ .sbb-pearl-chain__leg { flex: var(--sbb-pearl-chain-leg-weight, 1) var(--sbb-pearl-chain-leg-weight, 1); position: relative; - height: var(--sbb-pearl-chain-height); - border-inline-end: var(--sbb-pearl-chain-last-leg-margin, var(--sbb-pearl-chain-spacing-small)) + height: var(--sbb-pearl-chain-leg-height); + border-inline-end: var( + --sbb-pearl-chain-last-leg-margin, + var(--sbb-pearl-chain-leg-spacing-small) + ) solid Canvas; background-color: currentcolor; width: var(--sbb-pearl-chain-leg-width); @@ -45,21 +47,17 @@ @include sbb.if-forced-colors { background-color: CanvasText; - :host([past='']) & { + :host([past]) & { background-color: GrayText; } } - :host([data-last-leg]) & { - --sbb-pearl-chain-last-leg-margin: none; - - &::after { - inset-inline-end: calc(-1 * var(--sbb-pearl-chain-height)); - } + &::after { + inset-inline-end: var(--sbb-pearl-chain-last-leg-inset-inline-end, 0); } :host([past]) & { - color: var(--sbb-pearl-chain-color-past); + color: var(--sbb-pearl-chain-leg-color-past); @include sbb.pearl-chain-bullet-past; @@ -69,7 +67,7 @@ } :host([disruption]) & { - color: var(--sbb-pearl-chain-color-disruption); + color: var(--sbb-pearl-chain-leg-color-disruption); @include sbb.pearl-chain-bullet-disruption; @@ -79,21 +77,25 @@ } &::after { - @include sbb-pearl-chain-dotted; + @include sbb-pearl-chain-leg-dotted; } } :host(:is([arrival-skipped], [departure-skipped])) & { - color: var(--sbb-pearl-chain-color-disruption); + color: var(--sbb-pearl-chain-leg-color-disruption); &::after { - @include sbb-pearl-chain-dotted; + @include sbb-pearl-chain-leg-dotted; } } :host([data-progress]:not([arrival-skipped], [departure-skipped], [disruption])) & { + --sbb-pearl-chain-status-position-normalized: calc( + (100% - var(--sbb-pearl-chain-bullet-size-start-end)) * var(--sbb-pearl-chain-status-position) + ); + &::before { - --sbb-pearl-chain-bullet-animation-name: var(--sbb-pearl-chain-leg-animation); + --sbb-pearl-chain-bullet-animation-name: var(--sbb-pearl-chain-leg-animation, none); @include sbb.pearl-chain-bullet-position; @@ -105,7 +107,7 @@ z-index: 4; // --sbb-pearl-chain-status-position: defined in .ts file - inset-inline-start: var(--sbb-pearl-chain-status-position); + inset-inline-start: var(--sbb-pearl-chain-status-position-normalized); } } @@ -115,10 +117,10 @@ } & { - background-color: var(--sbb-pearl-chain-color-past); + background-color: var(--sbb-pearl-chain-leg-color-past); // --sbb-pearl-chain-leg-status: defined in .ts file - width: var(--sbb-pearl-chain-status-position); + width: var(--sbb-pearl-chain-status-position-normalized); } } } @@ -131,7 +133,7 @@ inset-block: 0; inset-inline-start: 0; background-color: currentcolor; - border-radius: var(--sbb-pearl-chain-height); + border-radius: var(--sbb-pearl-chain-leg-height); z-index: 1; @include sbb.if-forced-colors { @@ -144,6 +146,7 @@ } .sbb-pearl-chain__stop { + display: var(--sbb-pearl-chain-leg-stop-display, unset); position: relative; z-index: 2; diff --git a/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.ts b/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.ts index f61954ce16d..b848760aba4 100644 --- a/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.ts +++ b/src/elements/pearl-chain/pearl-chain-leg/pearl-chain-leg.ts @@ -1,9 +1,8 @@ import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; -import { html, LitElement, nothing } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { forceType } from '../../core/decorators.js'; -import type { SbbDateLike } from '../../core/interfaces.js'; import style from './pearl-chain-leg.scss?lit&inline'; @@ -17,23 +16,23 @@ class SbbPearlChainLegElement extends LitElement { /** Departure time of the leg. */ @property() - public set departure(value: SbbDateLike | null) { + public set departure(value: Date | null) { this._departure = value; } - public get departure(): SbbDateLike | null { + public get departure(): Date | null { return this._departure; } - private _departure: SbbDateLike | null = null; + private _departure: Date | null = null; /** Arrival time of the leg. */ @property() - public set arrival(value: SbbDateLike | null) { + public set arrival(value: Date | null) { this._arrival = value; } - public get arrival(): SbbDateLike | null { + public get arrival(): Date | null { return this._arrival; } - private _arrival: SbbDateLike | null = null; + private _arrival: Date | null = null; /** Whether the leg is disrupted. */ @forceType() @@ -65,26 +64,22 @@ class SbbPearlChainLegElement extends LitElement { @property({ type: Number, attribute: 'arrival-delay' }) public accessor arrivalDelay: number = 0; - private _displayStop(): boolean { - return !this.hasAttribute('data-first-leg'); - } - - protected override willUpdate(_changedProperties: PropertyValues): void { - super.willUpdate(_changedProperties); + protected override willUpdate(changedProperties: PropertyValues): void { + super.willUpdate(changedProperties); - //We need to update parent pearl-chain so that following leg can be styled properly. - if (_changedProperties.has('arrivalSkipped')) { + // We need to update parent pearl-chain so that following leg can be styled properly. + if (changedProperties.has('arrivalSkipped')) { const parentPearlChain = this.closest?.('sbb-pearl-chain'); if (!parentPearlChain) { return; } - parentPearlChain.requestUpdate(); + parentPearlChain?.requestUpdate(); } } protected override render(): TemplateResult { return html`
- ${this._displayStop() ? html` ` : nothing} +
`; } } diff --git a/src/elements/pearl-chain/pearl-chain/pearl-chain.scss b/src/elements/pearl-chain/pearl-chain/pearl-chain.scss index 830c07aa675..be44aceeefb 100644 --- a/src/elements/pearl-chain/pearl-chain/pearl-chain.scss +++ b/src/elements/pearl-chain/pearl-chain/pearl-chain.scss @@ -4,11 +4,11 @@ @include sbb.box-sizing; :host { - --sbb-pearl-chain-height: var(--sbb-border-width-2x); - --sbb-pearl-chain-spacing-small: #{sbb.px-to-rem-build(2)}; + --sbb-pearl-chain-leg-height: var(--sbb-border-width-2x); + --sbb-pearl-chain-leg-spacing-small: #{sbb.px-to-rem-build(2)}; --sbb-pearl-chain-color: var(--sbb-pearl-chain-bullet-color); - --sbb-pearl-chain-color-disruption: var(--sbb-pearl-chain-bullet-color-disruption); - --sbb-pearl-chain-color-past: var(--sbb-pearl-chain-bullet-color-past); + --sbb-pearl-chain-leg-color-disruption: var(--sbb-pearl-chain-bullet-color-disruption); + --sbb-pearl-chain-leg-color-past: var(--sbb-pearl-chain-bullet-color-past); --sbb-pearl-chain-leg-width: 100%; display: block; @@ -16,6 +16,19 @@ @include sbb.pearl-chain-bullet-variables; } +:host([marker='pulsing']) { + --sbb-pearl-chain-leg-animation: pearl-chain-bullet-position-pulse; +} + +::slotted(sbb-pearl-chain-leg:first-of-type) { + --sbb-pearl-chain-leg-stop-display: none; +} + +::slotted(sbb-pearl-chain-leg:last-of-type) { + --sbb-pearl-chain-last-leg-margin: none; + --sbb-pearl-chain-last-leg-inset-inline-end: calc(-1 * var(--sbb-pearl-chain-leg-height)); +} + .sbb-pearl-chain__wrapper { display: flex; justify-content: space-between; @@ -33,12 +46,12 @@ color: var(--sbb-pearl-chain-color); width: 100%; padding-block: calc( - (var(--sbb-pearl-chain-bullet-size-start-end) - var(--sbb-pearl-chain-height)) / 2 + (var(--sbb-pearl-chain-bullet-size-start-end) - var(--sbb-pearl-chain-leg-height)) / 2 ); padding-inline-end: var(--sbb-pearl-chain-bullet-size-start-end); } -// first and last bullet +// First and last bullet .sbb-pearl-chain__bullet { @include sbb.pearl-chain-bullet-start-end; @include sbb.pearl-chain-bullet; @@ -60,8 +73,8 @@ } } -.sbb-pearl-chain__bullet-past { - color: var(--sbb-pearl-chain-color-past); +.sbb-pearl-chain__bullet[data-past] { + color: var(--sbb-pearl-chain-leg-color-past); @include sbb.pearl-chain-bullet-past; @@ -70,8 +83,8 @@ } } -.sbb-pearl-chain__bullet-disruption { - color: var(--sbb-pearl-chain-color-disruption); +.sbb-pearl-chain__bullet[data-disrupted] { + color: var(--sbb-pearl-chain-leg-color-disruption); @include sbb.if-forced-colors { color: Highlight; @@ -79,13 +92,7 @@ } } -.sbb-pearl-chain__bullet-skipped { +.sbb-pearl-chain__bullet[data-skipped] { @include sbb.pearl-chain-bullet-start-end; @include sbb.pearl-chain-bullet-skipped; } - -.sbb-pearl-chain__time { - @include sbb.text-s--bold; - - color: var(--sbb-color-charcoal); -} diff --git a/src/elements/pearl-chain/pearl-chain/pearl-chain.stories.ts b/src/elements/pearl-chain/pearl-chain/pearl-chain.stories.ts index 60407c2d499..c7ebbe03fbb 100644 --- a/src/elements/pearl-chain/pearl-chain/pearl-chain.stories.ts +++ b/src/elements/pearl-chain/pearl-chain/pearl-chain.stories.ts @@ -17,12 +17,6 @@ import { } from './pearl-chain.sample-data.js'; import readme from './readme.md?raw'; -const disableAnimation: InputType = { - control: { - type: 'boolean', - }, -}; - const now: InputType = { control: { type: 'date', @@ -44,13 +38,11 @@ const marker: InputType = { }; const defaultArgTypes: ArgTypes = { - 'disable-animation': disableAnimation, marker: marker, now, }; const defaultArgs: Args = { - 'disable-animation': false, marker: marker.options![0], now: new Date('2024-12-05T12:11:00').valueOf(), }; @@ -157,7 +149,7 @@ export const CancelledManyStops: StoryObj = { argTypes: defaultArgTypes, }; -export const withPosition: StoryObj = { +export const WithPosition: StoryObj = { render: TemplateWithPosition, argTypes: defaultArgTypes, args: { @@ -217,17 +209,6 @@ export const Mixed: StoryObj = { }, }; -export const MixedWithTime: StoryObj = { - render: TemplateAlteration, - argTypes: { ...defaultArgTypes, serviceAlteration }, - args: { - ...defaultArgs, - serviceAlteration: serviceAlteration.options![2], - departure: '2024-12-18T12:13:00', - arrival: '2024-11-30T12:13:00', - }, -}; - const meta: Meta = { decorators: [(story) => html`
${story()}
`], parameters: { diff --git a/src/elements/pearl-chain/pearl-chain/pearl-chain.ts b/src/elements/pearl-chain/pearl-chain/pearl-chain.ts index 6ac906e7996..932acf18662 100644 --- a/src/elements/pearl-chain/pearl-chain/pearl-chain.ts +++ b/src/elements/pearl-chain/pearl-chain/pearl-chain.ts @@ -1,21 +1,16 @@ -import { addMinutes, differenceInMinutes, format, isAfter, isBefore } from 'date-fns'; -import type { CSSResultGroup, TemplateResult } from 'lit'; -import { html, LitElement, nothing } from 'lit'; +import { addMinutes, differenceInMinutes, isAfter, isBefore } from 'date-fns'; +import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { classMap } from 'lit/directives/class-map.js'; -import { SbbLanguageController } from '../../core/controllers.js'; -import { defaultDateAdapter } from '../../core/datetime.js'; -import { i18nArrival, i18nDeparture } from '../../core/i18n.js'; +import { type DateAdapter, defaultDateAdapter } from '../../core/datetime.js'; import type { SbbDateLike } from '../../core/interfaces/types.js'; -import '../../screen-reader-only.js'; import '../pearl-chain-leg.js'; import type { SbbPearlChainLegElement } from '../pearl-chain-leg.js'; import style from './pearl-chain.scss?lit&inline'; type Status = 'progress' | 'future' | 'past'; -type Marker = 'static' | 'pulsing'; /** * It visually displays journey information. @@ -27,103 +22,49 @@ class SbbPearlChainElement extends LitElement { /** Whether the marker should be pulsing or static. */ @property() - public accessor marker: Marker = 'static'; - - /** Prop to render the departure time - will be formatted as "H:mm" */ - @property() - public set departure(value: SbbDateLike | null) { - this._departure = value; - } - public get departure(): SbbDateLike | null { - return this._departure; - } - private _departure: SbbDateLike | null = null; - - /** Prop to render the arrival time - will be formatted as "H:mm" */ - @property() - public set arrival(value: SbbDateLike | null) { - this._arrival = value; - } - public get arrival(): SbbDateLike | null { - return this._arrival; - } - private _arrival: SbbDateLike | null = null; + public accessor marker: 'static' | 'pulsing' = 'static'; /** A configured date which acts as the current date instead of the real current date. Recommended for testing purposes. */ @property() - public set now(value: SbbDateLike | undefined) { - this._now = defaultDateAdapter.getValidDateOrNull(defaultDateAdapter.deserialize(value)); + public set now(value: Date) { + this._now = + this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value)) ?? new Date(); } - public get now(): SbbDateLike | null { + + public get now(): Date { return this._now; } - private _now: Date | null = null; - private _language = new SbbLanguageController(this); + private _now: Date = new Date(); + + private _dateAdapter: DateAdapter = defaultDateAdapter; private _legs(): SbbPearlChainLegElement[] { return Array.from(this.querySelectorAll?.('sbb-pearl-chain-leg') ?? []); } - private _removeTimezone(time: SbbDateLike | null): Date | undefined { - const parsedDate = defaultDateAdapter.deserialize(time); - - if (!parsedDate || !defaultDateAdapter.isValid(parsedDate)) { - return undefined; - } - - const isoTime = parsedDate!.toISOString(); - - if (isoTime.includes('Z')) { - return new Date(isoTime.replace('Z', '')); - } - - if (isoTime.includes('T')) { - const dateTime = isoTime.split('T'); - - if (dateTime[1] && (dateTime[1].includes('+') || dateTime[1].includes('-'))) { - return new Date(`${dateTime[0]}T${dateTime[1].split(/[+-]/)[0]}`); - } - } - return new Date(isoTime); - } - - private _getAllDuration(legs: SbbPearlChainLegElement[]): number { + private _totalDuration(legs: SbbPearlChainLegElement[]): number { return legs?.reduce((sum: number, leg) => { - const arrivalNoTz = this._removeTimezone(leg.arrival); - const departureNoTz = this._removeTimezone(leg.departure); + const arrivalNoTz = this._dateAdapter.deserialize(leg.arrival); + const departureNoTz = this._dateAdapter.deserialize(leg.departure) as Date; if (arrivalNoTz && departureNoTz) { - return ( - sum + - differenceInMinutes( - this._removeTimezone(leg.arrival)!, - this._removeTimezone(leg.departure)!, - ) - ); + return sum + differenceInMinutes(arrivalNoTz, departureNoTz); } return sum; }, 0); } - private _isAllCancelled(legs: SbbPearlChainLegElement[]): boolean { - return legs?.every((leg) => leg?.disruption); - } - - private _getRelativeDuration( - legs: SbbPearlChainLegElement[], - leg: SbbPearlChainLegElement, - ): number { - const arrivalNoTz = this._removeTimezone(leg.arrival); - const departureNoTz = this._removeTimezone(leg.departure); + private _getRelativeDuration(totalDuration: number, leg: SbbPearlChainLegElement): number { + const arrivalNoTz = this._dateAdapter.deserialize(leg.arrival); + const departureNoTz = this._dateAdapter.deserialize(leg.departure); if (arrivalNoTz && departureNoTz) { const duration = differenceInMinutes(arrivalNoTz, departureNoTz); - const allDurations = this._getAllDuration(legs); - if (allDurations === 0) { + if (totalDuration === 0) { return 100; } - return (duration / allDurations) * 100; + return (duration / totalDuration) * 100; } return 0; } @@ -139,13 +80,14 @@ class SbbPearlChainElement extends LitElement { return total && (progress / total) * 100; } - private _addMinutes(d: SbbDateLike, amount: number): Date { - return addMinutes(defaultDateAdapter.deserialize(d)!, amount); + private _addMinutes(d: SbbDateLike | null, amount: number): Date { + const date: Date | null = this._dateAdapter.deserialize(d); + return date ? addMinutes(date, amount) : this._dateAdapter.invalid(); } private _getLegStatus(now: Date, leg: SbbPearlChainLegElement): Status { - const start = this._addMinutes(leg.departure!, leg.departureDelay); - const end = this._addMinutes(leg.arrival!, leg.arrivalDelay); + const start = this._addMinutes(leg.departure, leg.departureDelay); + const end = this._addMinutes(leg.arrival, leg.arrivalDelay); return this._getStatus(now, start, end); } @@ -158,120 +100,83 @@ class SbbPearlChainElement extends LitElement { return 'future'; } - private _renderContent(content: TemplateResult): TemplateResult { - return html` -
- ${this.departure && this.arrival - ? html`` - : nothing} - ${content} - ${this.arrival && this.departure - ? html`` - : nothing} -
- `; - } - private _renderPosition(now: Date, progressLeg: SbbPearlChainLegElement): void { const currentPosition = this._getProgress( now, - this._addMinutes(progressLeg.departure!, progressLeg.departureDelay), - this._addMinutes(progressLeg.arrival!, progressLeg.arrivalDelay), + this._addMinutes(progressLeg.departure, progressLeg.departureDelay), + this._addMinutes(progressLeg.arrival, progressLeg.arrivalDelay), ); if (currentPosition < 0 && currentPosition > 100) { return; } - progressLeg?.style.setProperty('--sbb-pearl-chain-status-position', `${currentPosition}%`); - if (this.marker === 'pulsing') { - progressLeg?.style.setProperty( - '--sbb-pearl-chain-leg-animation', - 'pearl-chain-bullet-position-pulse', - ); - } - if (currentPosition >= 50) { - progressLeg?.style.setProperty('transform', `translateX(-100%)`); - } + progressLeg?.style.setProperty('--sbb-pearl-chain-status-position', `${currentPosition / 100}`); } - protected override render(): TemplateResult { - const now = (this.now as Date) ?? new Date(); + private _getBullet(index: number): Element { + const a = Array.from(this.shadowRoot!.querySelectorAll('.sbb-pearl-chain__bullet')); + return a[index]; + } - const rideLegs: SbbPearlChainLegElement[] = this._legs(); + private _getFirstBullet(): Element { + return this._getBullet(0); + } - if (!rideLegs.length) { - return html``; - } + private _getLastBullet(): Element { + return this._getBullet(1); + } - const statusDeparture = this._getLegStatus(now, rideLegs[0]); + protected override updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); - const statusArrival = this._getLegStatus(now, rideLegs[rideLegs.length - 1]); + this._setUpComponent(); + } + + private _configureBullet(bullet: Element, leg: SbbPearlChainLegElement, first: boolean): void { + const status = this._getLegStatus(this.now, leg); + + bullet.toggleAttribute('data-disrupted', leg.disruption); + bullet.toggleAttribute('data-skipped', first ? leg.departureSkipped : leg.arrivalSkipped); + bullet.toggleAttribute('data-past', status === 'past' || (status === 'progress' && first)); + } + + private _setUpComponent(): void { + const legs: SbbPearlChainLegElement[] = this._legs(); - rideLegs[0]?.toggleAttribute('data-first-leg', true); - rideLegs[rideLegs.length - 1].toggleAttribute('data-last-leg', true); + this._configureBullet(this._getFirstBullet(), legs[0], true); + this._configureBullet(this._getLastBullet(), legs[legs.length - 1], false); - rideLegs.map((leg, index) => { - const status = this._getLegStatus(now, leg); + legs.map((leg, index) => { + const status = this._getLegStatus(this.now, leg); leg.style.setProperty( '--sbb-pearl-chain-leg-weight', - `${this._getRelativeDuration(rideLegs, leg) / 100}`, + `${this._getRelativeDuration(this._totalDuration(legs), leg) / 100}`, ); leg.past = status === 'past'; leg.toggleAttribute('data-progress', status === 'progress'); if (status === 'progress') { - this._renderPosition(now, leg); + this._renderPosition(this.now, leg); } - //If previous leg has arrival-skipped an attribute is set to style the stop - if (index > 0 && rideLegs[index - 1]) { - leg.toggleAttribute('data-skip-departure', !!rideLegs[index - 1].arrivalSkipped); + // If previous leg has arrival-skipped an attribute is set to style the stop + if (index > 0 && legs[index - 1]) { + leg.toggleAttribute('data-skip-departure', legs[index - 1].arrivalSkipped); } }); + } - if (this._isAllCancelled(rideLegs)) { - return this._renderContent(html` + protected override render(): TemplateResult { + return html` +
- - - + + +
- `); - } - - return this._renderContent(html` -
- - -
- `); + `; } } diff --git a/src/elements/pearl-chain/pearl-chain/pearl-chain.visual.spec.ts b/src/elements/pearl-chain/pearl-chain/pearl-chain.visual.spec.ts index f74ffc153c7..e9c2ed0540f 100644 --- a/src/elements/pearl-chain/pearl-chain/pearl-chain.visual.spec.ts +++ b/src/elements/pearl-chain/pearl-chain/pearl-chain.visual.spec.ts @@ -95,8 +95,8 @@ describe(`sbb-pearl-chain`, () => { now=${(c.now ?? new Date('2024-12-01T12:11:00').valueOf()) / 1000} marker="static" > - ${c.legs.map((l) => l)} + ${c.legs} + `); }), ); diff --git a/src/storybook/pages/home/home-logged-in.ts b/src/storybook/pages/home/home-logged-in.ts index 498f8b8ef2c..227e0f3dd6e 100644 --- a/src/storybook/pages/home/home-logged-in.ts +++ b/src/storybook/pages/home/home-logged-in.ts @@ -4,9 +4,9 @@ import { html } from 'lit'; import type { SbbDialogElement } from '../../../elements/dialog.js'; import { - futureLeg, - pastLeg, -} from '../../../elements-experimental/pearl-chain-legacy/pearl-chain-legacy.sample-data.js'; + futureLegTemplate, + pastLegTemplate, +} from '../../../elements/pearl-chain/pearl-chain/pearl-chain.sample-data.js'; import { bikeProduct, @@ -20,7 +20,7 @@ import { } from './home.common.js'; import '../../../elements/dialog.js'; import '../../../elements/journey-header.js'; -import '../../../elements-experimental/pearl-chain-legacy.js'; +import '../../../elements/pearl-chain.js'; import './home.scss'; export const homeLoggedInTemplate = (args: Args): TemplateResult => html` @@ -108,10 +108,9 @@ export const homeLoggedInTemplate = (args: Args): TemplateResult => html` 2nd class, valid until 30.11.2022 - + + ${pastLegTemplate} ${futureLegTemplate} Ticket @@ -155,10 +154,9 @@ export const homeLoggedInTemplate = (args: Args): TemplateResult => html` Saturday, 21.02.2021, 1 h 26 min - + + ${pastLegTemplate} ${futureLegTemplate} + Details