@streamscloud/embeddable 3.4.2 → 5.0.0

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.
Files changed (112) hide show
  1. package/dist/ads/ad-card/cmp.ad-card.svelte +220 -0
  2. package/dist/{short-videos/short-video-viewer/cmp.ad.svelte.d.ts → ads/ad-card/cmp.ad-card.svelte.d.ts} +3 -2
  3. package/dist/ads/ad-card/index.d.ts +3 -0
  4. package/dist/ads/ad-card/index.js +2 -0
  5. package/dist/ads/ad-card/mapper.d.ts +3 -0
  6. package/dist/ads/ad-card/mapper.js +14 -0
  7. package/dist/ads/ad-card/operations.generated.d.ts +24 -0
  8. package/dist/ads/ad-card/operations.generated.js +48 -0
  9. package/dist/ads/ad-card/operations.graphql +21 -0
  10. package/dist/ads/ad-card/types.d.ts +18 -0
  11. package/dist/ads/ad-card/types.js +1 -0
  12. package/dist/core/locale.d.ts +3 -0
  13. package/dist/products/price-helper.d.ts +18 -3
  14. package/dist/products/price-helper.js +9 -6
  15. package/dist/products/product-card/cmp.product-card.svelte +219 -0
  16. package/dist/products/product-card/cmp.product-card.svelte.d.ts +15 -0
  17. package/dist/products/product-card/index.d.ts +4 -0
  18. package/dist/products/product-card/index.js +2 -0
  19. package/dist/products/product-card/mapper.d.ts +3 -0
  20. package/dist/products/product-card/mapper.js +22 -0
  21. package/dist/products/product-card/operations.generated.d.ts +26 -0
  22. package/dist/products/product-card/operations.generated.js +59 -0
  23. package/dist/products/product-card/operations.graphql +23 -0
  24. package/dist/products/product-card/product-card-localization.d.ts +8 -0
  25. package/dist/{short-videos/short-video-viewer/short-video-product-localization.js → products/product-card/product-card-localization.js} +1 -1
  26. package/dist/products/product-card/types.d.ts +12 -0
  27. package/dist/products/product-card/types.js +1 -0
  28. package/dist/short-videos/short-video-viewer/cmp.attachments.svelte +12 -40
  29. package/dist/short-videos/short-video-viewer/cmp.attachments.svelte.d.ts +1 -1
  30. package/dist/short-videos/short-video-viewer/cmp.short-video-controls.svelte +145 -0
  31. package/dist/short-videos/short-video-viewer/cmp.short-video-controls.svelte.d.ts +19 -0
  32. package/dist/short-videos/short-video-viewer/cmp.short-video-viewer.svelte +46 -20
  33. package/dist/short-videos/short-video-viewer/cmp.short-video-viewer.svelte.d.ts +4 -2
  34. package/dist/short-videos/short-video-viewer/index.d.ts +3 -7
  35. package/dist/short-videos/short-video-viewer/index.js +2 -5
  36. package/dist/short-videos/short-video-viewer/mapper.d.ts +1 -1
  37. package/dist/short-videos/short-video-viewer/mapper.js +25 -22
  38. package/dist/short-videos/short-video-viewer/operations.generated.d.ts +6 -8
  39. package/dist/short-videos/short-video-viewer/operations.generated.js +10 -17
  40. package/dist/short-videos/short-video-viewer/operations.graphql +8 -10
  41. package/dist/short-videos/short-video-viewer/short-video-attachments-localization.d.ts +3 -7
  42. package/dist/short-videos/short-video-viewer/short-video-attachments-localization.js +0 -14
  43. package/dist/short-videos/short-video-viewer/short-video-viewer-localization.d.ts +3 -3
  44. package/dist/short-videos/short-video-viewer/types.d.ts +23 -13
  45. package/dist/short-videos/short-video-viewer/ui-manager.svelte.d.ts +5 -0
  46. package/dist/short-videos/short-video-viewer/ui-manager.svelte.js +15 -2
  47. package/dist/short-videos/short-videos-player/cmp.short-videos-player.svelte +25 -163
  48. package/dist/short-videos/short-videos-player/cmp.short-videos-player.svelte.d.ts +7 -2
  49. package/dist/short-videos/short-videos-player/controls.svelte +125 -125
  50. package/dist/short-videos/short-videos-player/controls.svelte.d.ts +4 -2
  51. package/dist/short-videos/short-videos-player/index.d.ts +2 -0
  52. package/dist/short-videos/short-videos-player/index.js +12 -3
  53. package/dist/short-videos/short-videos-player/operations.generated.d.ts +6 -8
  54. package/dist/short-videos/short-videos-player/operations.generated.js +10 -17
  55. package/dist/short-videos/short-videos-player/short-videos-player-localization.d.ts +1 -3
  56. package/dist/short-videos/short-videos-player/short-videos-player-localization.js +0 -2
  57. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte +211 -0
  58. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte.d.ts +18 -0
  59. package/dist/short-videos/short-videos-player/types.d.ts +10 -8
  60. package/dist/short-videos/short-videos-player/ui-manager.svelte.d.ts +4 -3
  61. package/dist/short-videos/short-videos-player/ui-manager.svelte.js +9 -8
  62. package/dist/streams/layout/element-views/price-element-view.svelte +5 -4
  63. package/dist/streams/layout/models/mapper.js +10 -18
  64. package/dist/streams/layout/models/stream-layout-short-video-model.d.ts +1 -0
  65. package/dist/streams/stream-player/cmp.stream-player.svelte +23 -8
  66. package/dist/streams/stream-player/cmp.stream-player.svelte.d.ts +3 -1
  67. package/dist/streams/stream-player/controls.svelte +87 -74
  68. package/dist/streams/stream-player/controls.svelte.d.ts +2 -0
  69. package/dist/streams/stream-player/index.d.ts +2 -0
  70. package/dist/streams/stream-player/index.js +4 -3
  71. package/dist/streams/stream-player/mapper.d.ts +1 -1
  72. package/dist/streams/stream-player/mapper.js +1 -1
  73. package/dist/streams/stream-player/stream-overview.svelte +12 -1
  74. package/dist/streams/stream-player/stream-overview.svelte.d.ts +1 -0
  75. package/dist/streams/stream-player/stream-player-localization.d.ts +1 -3
  76. package/dist/streams/stream-player/stream-player-localization.js +0 -2
  77. package/dist/streams/stream-player/ui-manager.svelte.d.ts +4 -2
  78. package/dist/streams/stream-player/ui-manager.svelte.js +10 -5
  79. package/dist/ui/button/resources/button-theme.svelte +1 -0
  80. package/dist/ui/line-clamp/cmp.line-clamp.svelte +35 -13
  81. package/dist/ui/player/cmp.player-slider.svelte +74 -9
  82. package/dist/ui/progress/cmp.progress.svelte +4 -1
  83. package/dist/ui/seek-bar/cmp.seek-bar.svelte +112 -28
  84. package/dist/ui/seek-bar/cmp.seek-bar.svelte.d.ts +3 -0
  85. package/dist/ui/shadow-dom/index.d.ts +2 -1
  86. package/dist/ui/shadow-dom/index.js +2 -1
  87. package/dist/ui/shadow-dom/{shadow-host.d.ts → modal-shadow-host.d.ts} +1 -1
  88. package/dist/ui/shadow-dom/modal-shadow-host.js +21 -0
  89. package/dist/ui/shadow-dom/shadow-root-service.d.ts +1 -0
  90. package/dist/ui/shadow-dom/shadow-root-service.js +23 -0
  91. package/dist/ui/video/cmp.video.svelte +46 -38
  92. package/dist/ui/video/cmp.video.svelte.d.ts +3 -0
  93. package/dist/ui/video/index.d.ts +1 -0
  94. package/dist/ui/video/index.js +1 -0
  95. package/dist/ui/video/types.d.ts +4 -0
  96. package/dist/ui/video/types.js +5 -0
  97. package/package.json +5 -1
  98. package/dist/short-videos/short-video-viewer/cmp.ad.svelte +0 -140
  99. package/dist/short-videos/short-video-viewer/cmp.product.svelte +0 -168
  100. package/dist/short-videos/short-video-viewer/cmp.product.svelte.d.ts +0 -14
  101. package/dist/short-videos/short-video-viewer/cmp.short-video-details.svelte +0 -125
  102. package/dist/short-videos/short-video-viewer/cmp.short-video-details.svelte.d.ts +0 -14
  103. package/dist/short-videos/short-video-viewer/cmp.social-interactions.svelte +0 -69
  104. package/dist/short-videos/short-video-viewer/cmp.social-interactions.svelte.d.ts +0 -10
  105. package/dist/short-videos/short-video-viewer/description.svelte +0 -53
  106. package/dist/short-videos/short-video-viewer/description.svelte.d.ts +0 -9
  107. package/dist/short-videos/short-video-viewer/short-video-details-localization.d.ts +0 -14
  108. package/dist/short-videos/short-video-viewer/short-video-details-localization.js +0 -17
  109. package/dist/short-videos/short-video-viewer/short-video-product-localization.d.ts +0 -8
  110. package/dist/short-videos/short-videos-player/action-button.svelte +0 -38
  111. package/dist/short-videos/short-videos-player/action-button.svelte.d.ts +0 -10
  112. package/dist/ui/shadow-dom/shadow-host.js +0 -32
@@ -0,0 +1,220 @@
1
+ <script lang="ts">import { toPriceRepresentation } from '../../products/price-helper';
2
+ import { Button, ButtonSize } from '../../ui/button';
3
+ import { Image } from '../../ui/image';
4
+ import { LineClamp } from '../../ui/line-clamp';
5
+ let { ad, inert = false } = $props();
6
+ </script>
7
+
8
+ <div class="ad-card" inert={inert}>
9
+ <div class="ad-card__image">
10
+ <Image src={ad.image} alt={ad.title} />
11
+ </div>
12
+ <div class="ad-card__info">
13
+ <div class="ad-card__content">
14
+ {#if ad.title}
15
+ <div class="ad-card__title">
16
+ <LineClamp value={ad.title} maxLines={2} />
17
+ </div>
18
+ {/if}
19
+ {#if ad.description}
20
+ <div class="ad-card__description">
21
+ <LineClamp value={ad.description} maxLines={2} />
22
+ </div>
23
+ {/if}
24
+ </div>
25
+ <div class="ad-card__price-container">
26
+ {#if ad.price && ad.currency}
27
+ <div class="ad-card__price">
28
+ {#if ad.priceInfoLabel}
29
+ <span class="ad-card__price-info-label">{ad.priceInfoLabel}</span>
30
+ {/if}
31
+ {toPriceRepresentation({ amount: ad.price, currency: ad.currency })}
32
+ </div>
33
+ {/if}
34
+ </div>
35
+ <div class="ad-card__button-container">
36
+ {#if ad.ctaButton}
37
+ <Button
38
+ size={ButtonSize.Standard}
39
+ on={{ click: () => ad.ctaButton && window.open(ad.ctaButton.url, '_blank') }}
40
+ --button--font--size="1em"
41
+ --button--font--color={ad.ctaButton.textColor}
42
+ --button--background={ad.ctaButton.background}
43
+ --button--min-width="100%">
44
+ <span class="ad-card__button-text">{ad.ctaButton.text}</span>
45
+ </Button>
46
+ {/if}
47
+ </div>
48
+ </div>
49
+ </div>
50
+
51
+ <style>@keyframes fadeIn {
52
+ 0% {
53
+ opacity: 1;
54
+ }
55
+ 50% {
56
+ opacity: 0.4;
57
+ }
58
+ 100% {
59
+ opacity: 1;
60
+ }
61
+ }
62
+ .ad-card {
63
+ width: 100%;
64
+ height: max-content;
65
+ display: flex;
66
+ flex-direction: column;
67
+ position: relative;
68
+ container-type: inline-size;
69
+ aspect-ratio: 10/16;
70
+ color: #000000;
71
+ background-color: rgba(255, 255, 255, 0.9);
72
+ border: 0.038125rem solid #f2f2f3;
73
+ border-radius: 0.5rem;
74
+ padding: 0.75rem 0.75rem 1.125rem;
75
+ justify-content: flex-start;
76
+ gap: 0.5rem;
77
+ /* Set 'container-type: inline-size;' to reference container*/
78
+ }
79
+ :global([data-theme="dark"]) .ad-card {
80
+ background-color: rgba(18, 18, 18, 0.9);
81
+ color: #ffffff;
82
+ border-color: #1e1e1e;
83
+ }
84
+ @container (width < 230px) {
85
+ .ad-card {
86
+ padding: 0.5rem 0.5rem 0.75rem;
87
+ }
88
+ }
89
+ .ad-card__image {
90
+ border-radius: 0.25rem;
91
+ overflow: hidden;
92
+ aspect-ratio: 1/1;
93
+ width: 100%;
94
+ --image--width: 100%;
95
+ --image--height: 100%;
96
+ --image--object-fit: cover;
97
+ }
98
+ .ad-card__info {
99
+ display: grid;
100
+ grid-template-rows: 0.7fr auto auto;
101
+ grid-template-areas: "content" "price" "button";
102
+ row-gap: 0rem;
103
+ flex: 1 1 auto;
104
+ min-height: 0;
105
+ /* Set 'container-type: inline-size;' to reference container*/
106
+ }
107
+ @container (width < 230px) {
108
+ .ad-card__info {
109
+ row-gap: 0rem;
110
+ }
111
+ }
112
+ .ad-card__content {
113
+ grid-area: content;
114
+ display: flex;
115
+ flex-direction: column;
116
+ gap: 0.1875rem;
117
+ align-self: start;
118
+ /* Set 'container-type: inline-size;' to reference container*/
119
+ }
120
+ @container (width < 230px) {
121
+ .ad-card__content {
122
+ gap: 0.09375rem;
123
+ }
124
+ }
125
+ .ad-card__price-container {
126
+ grid-area: price;
127
+ display: flex;
128
+ justify-content: flex-end;
129
+ align-items: center;
130
+ min-height: 3rem;
131
+ /* Set 'container-type: inline-size;' to reference container*/
132
+ }
133
+ @container (width < 230px) {
134
+ .ad-card__price-container {
135
+ min-height: 2rem;
136
+ }
137
+ }
138
+ .ad-card__button-container {
139
+ grid-area: button;
140
+ display: flex;
141
+ justify-content: center;
142
+ align-items: end;
143
+ min-height: 2.5rem;
144
+ margin-top: 0.125rem;
145
+ /* Set 'container-type: inline-size;' to reference container*/
146
+ }
147
+ @container (width < 230px) {
148
+ .ad-card__button-container {
149
+ min-height: 2rem;
150
+ margin-top: 0.09375rem;
151
+ }
152
+ }
153
+ .ad-card__button-text {
154
+ display: block;
155
+ text-overflow: ellipsis;
156
+ width: 100%;
157
+ white-space: nowrap;
158
+ overflow: hidden;
159
+ }
160
+ .ad-card__title {
161
+ font-weight: 700;
162
+ font-size: 1.125rem;
163
+ line-height: 1.375rem;
164
+ min-height: 1.375rem;
165
+ /* Set 'container-type: inline-size;' to reference container*/
166
+ }
167
+ @container (width < 230px) {
168
+ .ad-card__title {
169
+ font-size: 0.75rem;
170
+ line-height: 0.875rem;
171
+ min-height: 0.875rem;
172
+ }
173
+ }
174
+ .ad-card__description {
175
+ font-weight: 400;
176
+ color: #6b7280;
177
+ font-size: 0.9375rem;
178
+ line-height: 1.375rem;
179
+ min-height: 1.375rem;
180
+ /* Set 'container-type: inline-size;' to reference container*/
181
+ }
182
+ @container (width < 230px) {
183
+ .ad-card__description {
184
+ font-size: 0.625rem;
185
+ line-height: 0.875rem;
186
+ min-height: 0.875rem;
187
+ }
188
+ }
189
+ .ad-card__price {
190
+ font-size: 1.875rem;
191
+ font-weight: 700;
192
+ text-align: right;
193
+ display: flex;
194
+ align-items: end;
195
+ gap: 0.625rem;
196
+ /* Set 'container-type: inline-size;' to reference container*/
197
+ }
198
+ @container (width < 230px) {
199
+ .ad-card__price {
200
+ font-size: 1.25rem;
201
+ }
202
+ }
203
+ .ad-card__price-info-label {
204
+ font-family: "Inter", sans-serif;
205
+ font-weight: 400;
206
+ font-style: normal;
207
+ font-size: 0.75rem;
208
+ line-height: 1.125rem;
209
+ letter-spacing: 0;
210
+ text-align: right;
211
+ color: #6b7280;
212
+ white-space: nowrap;
213
+ /* Set 'container-type: inline-size;' to reference container*/
214
+ }
215
+ @container (width < 230px) {
216
+ .ad-card__price-info-label {
217
+ font-size: 0.625rem;
218
+ line-height: 0.875rem;
219
+ }
220
+ }</style>
@@ -1,6 +1,7 @@
1
- import type { ShortVideoViewerAdModel } from './types';
1
+ import type { AdCardModel } from './types';
2
2
  type Props = {
3
- ad: ShortVideoViewerAdModel;
3
+ ad: AdCardModel;
4
+ inert?: boolean;
4
5
  };
5
6
  declare const Cmp: import("svelte").Component<Props, {}, "">;
6
7
  type Cmp = ReturnType<typeof Cmp>;
@@ -0,0 +1,3 @@
1
+ export { default as AdCard } from './cmp.ad-card.svelte';
2
+ export type { AdCardModel } from './types';
3
+ export { mapToAdCardModel } from './mapper';
@@ -0,0 +1,2 @@
1
+ export { default as AdCard } from './cmp.ad-card.svelte';
2
+ export { mapToAdCardModel } from './mapper';
@@ -0,0 +1,3 @@
1
+ import type { AdCardPayloadFragment } from './operations.generated';
2
+ import type { AdCardModel } from './types';
3
+ export declare const mapToAdCardModel: (payload: AdCardPayloadFragment) => AdCardModel;
@@ -0,0 +1,14 @@
1
+ import { getMediaItemImageUrl } from '../../core/media';
2
+ export const mapToAdCardModel = (payload) => {
3
+ return {
4
+ id: payload.id,
5
+ type: payload.type,
6
+ image: getMediaItemImageUrl(payload.media[0]),
7
+ title: payload.title,
8
+ description: payload.description,
9
+ price: payload.price,
10
+ priceInfoLabel: payload.priceInfo,
11
+ currency: payload.currency,
12
+ ctaButton: payload.ctaButton
13
+ };
14
+ };
@@ -0,0 +1,24 @@
1
+ import type * as SchemaTypes from '../../../gql/types';
2
+ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
3
+ export type AdCardPayloadFragment = {
4
+ id: string;
5
+ title: string;
6
+ description: string | null;
7
+ price: number | null;
8
+ currency: SchemaTypes.Currency | null;
9
+ priceInfo: string | null;
10
+ type: SchemaTypes.AdType;
11
+ ctaButton: {
12
+ background: string;
13
+ textColor: string;
14
+ text: string;
15
+ url: string;
16
+ border: string;
17
+ } | null;
18
+ media: Array<{
19
+ url: string;
20
+ thumbnailUrl: string | null;
21
+ type: SchemaTypes.MediaType;
22
+ }>;
23
+ };
24
+ export declare const AdCardPayloadFragmentDoc: DocumentNode<AdCardPayloadFragment, unknown>;
@@ -0,0 +1,48 @@
1
+ export const AdCardPayloadFragmentDoc = {
2
+ kind: 'Document',
3
+ definitions: [
4
+ {
5
+ kind: 'FragmentDefinition',
6
+ name: { kind: 'Name', value: 'AdCardPayloadFragment' },
7
+ typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Ad' } },
8
+ selectionSet: {
9
+ kind: 'SelectionSet',
10
+ selections: [
11
+ { kind: 'Field', name: { kind: 'Name', value: 'id' } },
12
+ { kind: 'Field', name: { kind: 'Name', value: 'title' } },
13
+ { kind: 'Field', name: { kind: 'Name', value: 'description' } },
14
+ { kind: 'Field', name: { kind: 'Name', value: 'price' } },
15
+ { kind: 'Field', name: { kind: 'Name', value: 'currency' } },
16
+ { kind: 'Field', name: { kind: 'Name', value: 'priceInfo' } },
17
+ {
18
+ kind: 'Field',
19
+ name: { kind: 'Name', value: 'ctaButton' },
20
+ selectionSet: {
21
+ kind: 'SelectionSet',
22
+ selections: [
23
+ { kind: 'Field', name: { kind: 'Name', value: 'background' } },
24
+ { kind: 'Field', name: { kind: 'Name', value: 'textColor' } },
25
+ { kind: 'Field', name: { kind: 'Name', value: 'text' } },
26
+ { kind: 'Field', name: { kind: 'Name', value: 'url' } },
27
+ { kind: 'Field', name: { kind: 'Name', value: 'border' } }
28
+ ]
29
+ }
30
+ },
31
+ { kind: 'Field', name: { kind: 'Name', value: 'type' } },
32
+ {
33
+ kind: 'Field',
34
+ name: { kind: 'Name', value: 'media' },
35
+ selectionSet: {
36
+ kind: 'SelectionSet',
37
+ selections: [
38
+ { kind: 'Field', name: { kind: 'Name', value: 'url' } },
39
+ { kind: 'Field', name: { kind: 'Name', value: 'thumbnailUrl' } },
40
+ { kind: 'Field', name: { kind: 'Name', value: 'type' } }
41
+ ]
42
+ }
43
+ }
44
+ ]
45
+ }
46
+ }
47
+ ]
48
+ };
@@ -0,0 +1,21 @@
1
+ fragment AdCardPayloadFragment on Ad {
2
+ id
3
+ title
4
+ description
5
+ price
6
+ currency
7
+ priceInfo
8
+ ctaButton {
9
+ background
10
+ textColor
11
+ text
12
+ url
13
+ border
14
+ }
15
+ type
16
+ media {
17
+ url
18
+ thumbnailUrl
19
+ type
20
+ }
21
+ }
@@ -0,0 +1,18 @@
1
+ import { AdType, type Currency } from '../../core/enums';
2
+ export type AdCardModel = {
3
+ id: string;
4
+ type: AdType;
5
+ image: string | null;
6
+ title: string;
7
+ description: string | null;
8
+ price: number | null;
9
+ currency: Currency | null;
10
+ priceInfoLabel: string | null;
11
+ ctaButton: {
12
+ background: string;
13
+ textColor: string;
14
+ text: string;
15
+ url: string;
16
+ border: string;
17
+ } | null;
18
+ };
@@ -0,0 +1 @@
1
+ import { AdType } from '../../core/enums';
@@ -1,4 +1,7 @@
1
1
  export type Locale = 'en' | 'no';
2
+ export type LocalizationSchema = {
3
+ [key: string]: Record<Locale, unknown>;
4
+ };
2
5
  export declare const getLocale: <T>(input?: Locale | T) => Locale | T;
3
6
  export declare const isEn: <T>(input: Locale | T) => input is "en";
4
7
  export declare const isNo: <T>(input: Locale | T) => input is "no";
@@ -1,4 +1,19 @@
1
1
  import { Currency } from '../core/enums';
2
- export declare const toPriceRepresentation: (amount: number, currency: Currency, includeCurrency?: boolean) => string;
3
- export declare const shouldUseSalePrice: (price: number, salePrice: number | null, effectiveDateFrom: string | null, effectiveDateTo: string | null) => boolean;
4
- export declare const isSalePriceEffective: (salePrice: number | null, effectiveDateFrom: string | null, effectiveDateTo: string | null) => boolean;
2
+ export declare const toPriceRepresentation: (data: {
3
+ amount: number;
4
+ currency: Currency;
5
+ includeCurrency?: boolean;
6
+ }) => string;
7
+ export declare const shouldUseSalePrice: (data: {
8
+ price: number;
9
+ salePrice: number | null;
10
+ effectiveDateFrom: number | null;
11
+ effectiveDateTo: number | null;
12
+ referenceDate?: string | Date | null;
13
+ }) => boolean;
14
+ export declare const isSalePriceEffective: (data: {
15
+ salePrice: number | null;
16
+ effectiveDateFrom: number | null;
17
+ effectiveDateTo: number | null;
18
+ referenceDate?: string | Date | null;
19
+ }) => boolean;
@@ -1,6 +1,7 @@
1
1
  import { Currency } from '../core/enums';
2
2
  import { Utils } from '../core/utils';
3
- export const toPriceRepresentation = (amount, currency, includeCurrency = true) => {
3
+ export const toPriceRepresentation = (data) => {
4
+ const { amount, currency, includeCurrency = true } = data;
4
5
  const formatNumber = (value) => {
5
6
  const noDecimals = Number.isInteger(value);
6
7
  const options = {
@@ -27,21 +28,23 @@ export const toPriceRepresentation = (amount, currency, includeCurrency = true)
27
28
  }
28
29
  }
29
30
  };
30
- export const shouldUseSalePrice = (price, salePrice, effectiveDateFrom, effectiveDateTo) => {
31
- if (!isSalePriceEffective(salePrice, effectiveDateFrom, effectiveDateTo)) {
31
+ export const shouldUseSalePrice = (data) => {
32
+ const { price, salePrice, effectiveDateFrom, effectiveDateTo, referenceDate } = data;
33
+ if (!isSalePriceEffective({ salePrice, effectiveDateFrom, effectiveDateTo, referenceDate })) {
32
34
  return false;
33
35
  }
34
36
  return price !== salePrice;
35
37
  };
36
- export const isSalePriceEffective = (salePrice, effectiveDateFrom, effectiveDateTo) => {
38
+ export const isSalePriceEffective = (data) => {
39
+ const { salePrice, effectiveDateFrom, effectiveDateTo, referenceDate } = data;
37
40
  if (!salePrice) {
38
41
  return false;
39
42
  }
40
43
  if (!effectiveDateFrom && !effectiveDateTo) {
41
44
  return true;
42
45
  }
43
- const now = Date.now();
46
+ const reference = referenceDate ? (typeof referenceDate === 'string' ? new Date(referenceDate).getTime() : referenceDate.getTime()) : Date.now();
44
47
  const fromDate = effectiveDateFrom && new Date(effectiveDateFrom);
45
48
  const toDate = effectiveDateTo && new Date(effectiveDateTo);
46
- return (!fromDate || now >= fromDate.getTime()) && (!toDate || now < toDate.getTime());
49
+ return (!fromDate || reference >= fromDate.getTime()) && (!toDate || reference < toDate.getTime());
47
50
  };
@@ -0,0 +1,219 @@
1
+ <script lang="ts">import { toPriceRepresentation } from '../price-helper';
2
+ import { Image } from '../../ui/image';
3
+ import { LineClamp } from '../../ui/line-clamp';
4
+ import { ProportionalContainer } from '../../ui/proportional-container';
5
+ import { ProductCardLocalization } from './product-card-localization';
6
+ let { product, includeBeforeNowPrefix, inert = false, localization: localizationInit = 'en', on } = $props();
7
+ const localization = $derived(new ProductCardLocalization(localizationInit));
8
+ const showDescriptionPresented = $derived(product.shortDescription && product.shortDescription.length > 0);
9
+ const onProductClicked = (event) => {
10
+ if (!product.link) {
11
+ return;
12
+ }
13
+ event.preventDefault();
14
+ event.stopPropagation();
15
+ if (on === null || on === void 0 ? void 0 : on.productClick) {
16
+ on.productClick(product.id);
17
+ }
18
+ window.open(product.link, '_blank', 'noopener noreferrer');
19
+ };
20
+ </script>
21
+
22
+ <div class="product-card" inert={inert}>
23
+ <ProportionalContainer ratio={1}>
24
+ <Image src={product.image} />
25
+ </ProportionalContainer>
26
+
27
+ <div class="product-card__info">
28
+ <LineClamp maxLines={1}>
29
+ <div class="product-card__brand">{product.brandName}</div>
30
+ </LineClamp>
31
+ <LineClamp value={product.shortDescription} maxLines={showDescriptionPresented ? 1 : 2}>
32
+ <div class="product-card__title" class:two-lines={!showDescriptionPresented}>{product.title}</div>
33
+ </LineClamp>
34
+ <LineClamp value={product.shortDescription} maxLines={2}>
35
+ <div class="product-card__description" class:two-lines={showDescriptionPresented}>{product.shortDescription}</div>
36
+ </LineClamp>
37
+ <div class="product-price">
38
+ <div class="product-price__before-price">
39
+ {#if product.salePrice}
40
+ {#if includeBeforeNowPrefix}
41
+ {localization.beforeNowPrefix}
42
+ {/if}
43
+ {toPriceRepresentation({ amount: product.price, currency: product.currency })}
44
+ {/if}
45
+ </div>
46
+ <div class="product-price__price product-price__price--sale">
47
+ {toPriceRepresentation({ amount: product.salePrice ?? product.price, currency: product.currency })}
48
+ </div>
49
+ </div>
50
+ </div>
51
+
52
+ {#if product.link}
53
+ <a href={product.link} onclick={onProductClicked} target="_blank" rel="noopener noreferrer" class="product-card__link" aria-label="none">&nbsp;</a>
54
+ {/if}
55
+ </div>
56
+
57
+ <style>@keyframes fadeIn {
58
+ 0% {
59
+ opacity: 1;
60
+ }
61
+ 50% {
62
+ opacity: 0.4;
63
+ }
64
+ 100% {
65
+ opacity: 1;
66
+ }
67
+ }
68
+ .product-card {
69
+ --image--border-radius: 0.25rem;
70
+ --image--object-fit: fit;
71
+ --image--width: auto;
72
+ --image--height: auto;
73
+ width: 100%;
74
+ height: max-content;
75
+ display: flex;
76
+ flex-direction: column;
77
+ position: relative;
78
+ container-type: inline-size;
79
+ aspect-ratio: 10/16;
80
+ color: #000000;
81
+ background-color: rgba(255, 255, 255, 0.9);
82
+ border: 0.038125rem solid #f2f2f3;
83
+ border-radius: 0.5rem;
84
+ padding: 0.75rem 0.75rem 1.125rem;
85
+ justify-content: space-between;
86
+ /* Set 'container-type: inline-size;' to reference container*/
87
+ }
88
+ :global([data-theme="dark"]) .product-card {
89
+ background-color: rgba(18, 18, 18, 0.9);
90
+ color: #ffffff;
91
+ border-color: #1e1e1e;
92
+ }
93
+ @container (width < 230px) {
94
+ .product-card {
95
+ padding: 0.5rem 0.5rem 0.75rem;
96
+ }
97
+ }
98
+ .product-card__info {
99
+ display: flex;
100
+ flex-direction: column;
101
+ gap: 0.375rem;
102
+ margin-top: 0.1875rem;
103
+ /* Set 'container-type: inline-size;' to reference container*/
104
+ }
105
+ @container (width < 230px) {
106
+ .product-card__info {
107
+ gap: 0.25rem;
108
+ margin-top: 0.125rem;
109
+ }
110
+ }
111
+ .product-card__brand {
112
+ font-weight: 700;
113
+ font-size: 0.75rem;
114
+ line-height: 1.375rem;
115
+ min-height: 1.375rem;
116
+ /* Set 'container-type: inline-size;' to reference container*/
117
+ }
118
+ @container (width < 230px) {
119
+ .product-card__brand {
120
+ font-size: 0.5rem;
121
+ line-height: 0.875rem;
122
+ min-height: 0.875rem;
123
+ }
124
+ }
125
+ .product-card__title {
126
+ font-weight: 700;
127
+ font-size: 1.125rem;
128
+ line-height: 1.375rem;
129
+ min-height: 1.375rem;
130
+ /* Set 'container-type: inline-size;' to reference container*/
131
+ }
132
+ @container (width < 230px) {
133
+ .product-card__title {
134
+ font-size: 0.75rem;
135
+ line-height: 0.875rem;
136
+ min-height: 0.875rem;
137
+ }
138
+ }
139
+ .product-card__description {
140
+ font-weight: 400;
141
+ color: #6b7280;
142
+ font-size: 0.9375rem;
143
+ line-height: 1.375rem;
144
+ min-height: 1.375rem;
145
+ /* Set 'container-type: inline-size;' to reference container*/
146
+ }
147
+ @container (width < 230px) {
148
+ .product-card__description {
149
+ font-size: 0.625rem;
150
+ line-height: 0.875rem;
151
+ min-height: 0.875rem;
152
+ }
153
+ }
154
+ .product-card .two-lines {
155
+ height: 2.75rem;
156
+ /* Set 'container-type: inline-size;' to reference container*/
157
+ }
158
+ @container (width < 230px) {
159
+ .product-card .two-lines {
160
+ height: 1.75rem;
161
+ }
162
+ }
163
+ .product-card__link {
164
+ position: absolute;
165
+ top: 0;
166
+ left: 0;
167
+ width: 100%;
168
+ height: 100%;
169
+ }
170
+
171
+ .product-price {
172
+ --_product-price--align: right;
173
+ --_product-price--before--color: #6b7280;
174
+ --_product-price--before--font-size: 0.75em;
175
+ --_product-price--color: inherit;
176
+ --_product-price--font-size: 1.875em;
177
+ --_product-price--gap: 0.375em;
178
+ --_product-price--min-height: 2.40625rem;
179
+ width: 100%;
180
+ display: flex;
181
+ flex-direction: column;
182
+ justify-items: end;
183
+ gap: var(--_product-price--gap);
184
+ min-height: var(--_product-price--min-height);
185
+ /* Set 'container-type: inline-size;' to reference container*/
186
+ }
187
+ @container (width < 230px) {
188
+ .product-price {
189
+ --_product-price--before--font-size: 0.5rem;
190
+ --_product-price--font-size: 1.25rem;
191
+ --_product-price--gap: 0.25rem;
192
+ }
193
+ }
194
+ .product-price__before-price {
195
+ width: 100%;
196
+ color: var(--_product-price--before--color);
197
+ text-decoration: line-through;
198
+ font-size: var(--_product-price--before--font-size);
199
+ font-weight: 500;
200
+ text-align: var(--_product-price--align);
201
+ min-height: var(--_product-price--before--font-size);
202
+ text-overflow: ellipsis;
203
+ width: 100%;
204
+ white-space: nowrap;
205
+ overflow: hidden;
206
+ }
207
+ .product-price__price {
208
+ width: 100%;
209
+ color: var(--_product-price--color);
210
+ font-size: var(--_product-price--font-size);
211
+ font-weight: 800;
212
+ margin-top: auto;
213
+ text-align: var(--_product-price--align);
214
+ min-height: var(--_product-price--font-size);
215
+ text-overflow: ellipsis;
216
+ width: 100%;
217
+ white-space: nowrap;
218
+ overflow: hidden;
219
+ }</style>
@@ -0,0 +1,15 @@
1
+ import type { Locale } from '../../core/locale';
2
+ import { type IProductCardLocalization } from './product-card-localization';
3
+ import type { ProductCardModel } from './types';
4
+ type Props = {
5
+ product: ProductCardModel;
6
+ localization?: IProductCardLocalization | Locale;
7
+ includeBeforeNowPrefix?: boolean;
8
+ inert?: boolean;
9
+ on?: {
10
+ productClick?: (id: string) => void;
11
+ };
12
+ };
13
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
14
+ type Cmp = ReturnType<typeof Cmp>;
15
+ export default Cmp;
@@ -0,0 +1,4 @@
1
+ export { default as ProductCard } from './cmp.product-card.svelte';
2
+ export { mapToProductCard } from './mapper';
3
+ export type { ProductCardModel } from './types';
4
+ export type { ProductCardPayloadFragment } from './operations.generated';