summaryrefslogtreecommitdiff
path: root/src/components/jet/item/ProductMedia
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/jet/item/ProductMedia')
-rw-r--r--src/components/jet/item/ProductMedia/ProductMediaMacItem.svelte31
-rw-r--r--src/components/jet/item/ProductMedia/ProductMediaPadItem.svelte89
-rw-r--r--src/components/jet/item/ProductMedia/ProductMediaPhoneItem.svelte142
-rw-r--r--src/components/jet/item/ProductMedia/ProductMediaTVItem.svelte34
-rw-r--r--src/components/jet/item/ProductMedia/ProductMediaVisionItem.svelte38
-rw-r--r--src/components/jet/item/ProductMedia/ProductMediaWatchItem.svelte50
6 files changed, 384 insertions, 0 deletions
diff --git a/src/components/jet/item/ProductMedia/ProductMediaMacItem.svelte b/src/components/jet/item/ProductMedia/ProductMediaMacItem.svelte
new file mode 100644
index 0000000..516ed32
--- /dev/null
+++ b/src/components/jet/item/ProductMedia/ProductMediaMacItem.svelte
@@ -0,0 +1,31 @@
+<script lang="ts">
+ import type { ProductMediaItem } from '@jet-app/app-store/api/models';
+ import Artwork from '~/components/Artwork.svelte';
+ import Video from '~/components/jet/Video.svelte';
+
+ export let item: ProductMediaItem;
+</script>
+
+{#if item.screenshot}
+ <article>
+ <Artwork artwork={item.screenshot} profile="screenshot-mac" />
+ </article>
+{:else if item.video}
+ <article>
+ <Video autoplay video={item.video} profile="screenshot-mac" />
+ </article>
+{/if}
+
+<style>
+ article {
+ overflow: hidden;
+ }
+
+ article :global(.video) {
+ aspect-ratio: 16/10;
+ }
+
+ article :global(video) {
+ object-fit: cover;
+ }
+</style>
diff --git a/src/components/jet/item/ProductMedia/ProductMediaPadItem.svelte b/src/components/jet/item/ProductMedia/ProductMediaPadItem.svelte
new file mode 100644
index 0000000..6b9886c
--- /dev/null
+++ b/src/components/jet/item/ProductMedia/ProductMediaPadItem.svelte
@@ -0,0 +1,89 @@
+<script lang="ts">
+ import type {
+ ProductMediaItem,
+ MediaType,
+ } from '@jet-app/app-store/api/models';
+ import Artwork from '~/components/Artwork.svelte';
+ import Video from '~/components/jet/Video.svelte';
+
+ export let item: ProductMediaItem;
+ export let hasPortraitMedia: boolean;
+ export let mediaType: MediaType | undefined;
+</script>
+
+{#if item.screenshot || item.video}
+ <article>
+ <div
+ class="artwork-container"
+ class:ipad-pro-2018={mediaType === 'ipadPro_2018'}
+ class:ipad-11={mediaType === 'ipad_11'}
+ class:portrait={hasPortraitMedia}
+ >
+ {#if item.screenshot}
+ <Artwork
+ artwork={item.screenshot}
+ profile={hasPortraitMedia
+ ? 'screenshot-pad-portrait'
+ : 'screenshot-pad'}
+ />
+ {:else if item.video}
+ <Video
+ autoplay
+ video={item.video}
+ profile={hasPortraitMedia
+ ? 'screenshot-pad-portrait'
+ : 'screenshot-pad'}
+ />
+ {/if}
+ </div>
+ </article>
+{/if}
+
+<style>
+ .artwork-container,
+ .artwork-container :global(video) {
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ border-radius: 1.3% / 1.9%;
+ overflow: hidden;
+
+ /* This `transform` is required to make the `overflow: hidden` clip properly on Chrome */
+ transform: translateZ(0);
+ }
+
+ .artwork-container.portrait {
+ aspect-ratio: 3/4;
+ background: var(--systemQuaternary);
+ }
+
+ .artwork-container.portrait,
+ .artwork-container.portrait :global(video) {
+ border-radius: 1.9% / 1.3%;
+ }
+
+ .ipad-pro-2018,
+ .ipad-pro-2018 :global(video) {
+ mask-image: url('/assets/images/masks/ipad-pro-2018-mask-landscape.svg');
+ }
+
+ .ipad-pro-2018.portrait,
+ .ipad-pro-2018.portrait :global(video) {
+ mask-image: url('/assets/images/masks/ipad-pro-2018-mask.svg');
+ }
+
+ .ipad-11,
+ .ipad-11 :global(video) {
+ mask-image: url('/assets/images/masks/ipad-11-mask-landscape.svg');
+ }
+
+ .ipad-11.portrait,
+ .ipad-11.portrait :global(video) {
+ mask-image: url('/assets/images/masks/ipad-11-mask.svg');
+ }
+
+ .artwork-container :global(video):fullscreen {
+ mask-image: none;
+ border-radius: 0;
+ }
+</style>
diff --git a/src/components/jet/item/ProductMedia/ProductMediaPhoneItem.svelte b/src/components/jet/item/ProductMedia/ProductMediaPhoneItem.svelte
new file mode 100644
index 0000000..255b663
--- /dev/null
+++ b/src/components/jet/item/ProductMedia/ProductMediaPhoneItem.svelte
@@ -0,0 +1,142 @@
+<script lang="ts">
+ import type {
+ ProductMediaItem,
+ MediaType,
+ } from '@jet-app/app-store/api/models';
+ import { getAspectRatio } from '@amp/web-app-components/src/components/Artwork/utils/artProfile';
+ import Artwork from '~/components/Artwork.svelte';
+ import Video from '~/components/jet/Video.svelte';
+ import type { NamedProfile } from '~/config/components/artwork';
+
+ export let item: ProductMediaItem;
+ export let hasPortraitMedia: boolean;
+ export let mediaType: MediaType | undefined;
+
+ const getArtworkProfile = (
+ mediaType: MediaType | undefined,
+ hasPortraitMedia: boolean,
+ ): NamedProfile => {
+ const suffix = hasPortraitMedia ? '_portrait' : '';
+
+ // Map specific media types to their artwork profile names
+ const mediaTypeProfiles: Record<string, string> = {
+ iphone_6_5: 'screenshot-iphone_6_5',
+ iphone_5_8: 'screenshot-iphone_5_8',
+ iphone_d74: 'screenshot-iphone_d74',
+ };
+
+ const baseProfile =
+ mediaType && mediaTypeProfiles[mediaType]
+ ? mediaTypeProfiles[mediaType]
+ : 'screenshot-phone';
+
+ return `${baseProfile}${suffix}` as NamedProfile;
+ };
+
+ $: isLandscapeScreenshot =
+ item.screenshot && item.screenshot.width > item.screenshot.height;
+ $: profile = getArtworkProfile(mediaType, !isLandscapeScreenshot);
+ $: restOfShelfAspectRatio = getAspectRatio(
+ getArtworkProfile(mediaType, hasPortraitMedia),
+ );
+</script>
+
+{#if item.screenshot || item.video}
+ <article
+ class:with-rotated-artwork={isLandscapeScreenshot && hasPortraitMedia}
+ style:--aspect-ratio={`${restOfShelfAspectRatio}`}
+ >
+ <div
+ class="artwork-container"
+ class:iphone-6-5={mediaType === 'iphone_6_5'}
+ class:iphone-5-8={mediaType === 'iphone_5_8'}
+ class:iphone-d74={mediaType === 'iphone_d74'}
+ class:portrait={hasPortraitMedia}
+ >
+ {#if item.screenshot}
+ <Artwork
+ {profile}
+ artwork={item.screenshot}
+ disableAutoCenter={true}
+ withoutBorder={true}
+ />
+ {:else if item.video}
+ <Video autoplay video={item.video} {profile} />
+ {/if}
+ </div>
+ </article>
+{/if}
+
+<style>
+ article.with-rotated-artwork {
+ position: relative;
+ aspect-ratio: var(--aspect-ratio);
+ }
+
+ /*
+ * For iPhone screenshots that are landscape, but in a shelf/list with portrait screenshots,
+ * as denoted by `hasPortraitMedia`, we rotate the landscape screenshot to be in the portrait
+ * orientation, and scale it up so it fills the container.
+ */
+ article.with-rotated-artwork .artwork-container {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ height: auto;
+ width: calc((1 / var(--aspect-ratio)) * 100%);
+ transform: translate(-50%, -50%) rotate(-90deg);
+ transform-origin: center;
+ }
+
+ .artwork-container,
+ .artwork-container :global(video) {
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: 100%;
+ border-radius: 20px;
+ overflow: hidden;
+
+ /* This `transform` is required to make the `overflow: hidden` clip properly on Chrome */
+ transform: translateZ(0);
+ }
+
+ .iphone-5-8,
+ .iphone-5-8 :global(video) {
+ /* need to confirm with design for correct value */
+ border-radius: 23px;
+ mask-image: url('/assets/images/masks/iphone-5-8-mask-landscape.svg');
+ }
+
+ .iphone-5-8.portrait,
+ .iphone-5-8.portrait :global(video) {
+ mask-image: url('/assets/images/masks/iphone-5-8-mask.svg');
+ }
+
+ .iphone-6-5,
+ .iphone-6-5 :global(video) {
+ /* need to confirm with design for correct value */
+ border-radius: 21px;
+ mask-image: url('/assets/images/masks/iphone-6-5-mask-landscape.svg');
+ }
+
+ .iphone-6-5.portrait,
+ .iphone-6-5.portrait :global(video) {
+ mask-image: url('/assets/images/masks/iphone-6-5-mask.svg');
+ }
+
+ .iphone-d74,
+ .iphone-d74 :global(video) {
+ border-radius: 5.7% / 12.8%;
+ }
+
+ .iphone-d74.portrait,
+ .iphone-d74.portrait :global(video) {
+ border-radius: 12.8% / 5.7%;
+ }
+
+ .artwork-container :global(video):fullscreen {
+ mask-image: none;
+ border-radius: 0;
+ object-fit: contain;
+ }
+</style>
diff --git a/src/components/jet/item/ProductMedia/ProductMediaTVItem.svelte b/src/components/jet/item/ProductMedia/ProductMediaTVItem.svelte
new file mode 100644
index 0000000..7f7fd7a
--- /dev/null
+++ b/src/components/jet/item/ProductMedia/ProductMediaTVItem.svelte
@@ -0,0 +1,34 @@
+<script lang="ts">
+ import type { ProductMediaItem } from '@jet-app/app-store/api/models';
+ import Artwork from '~/components/Artwork.svelte';
+ import Video from '~/components/jet/Video.svelte';
+
+ export let item: ProductMediaItem;
+</script>
+
+{#if item.screenshot || item.video}
+ <article>
+ <div class="artwork-container">
+ {#if item.screenshot}
+ <Artwork artwork={item.screenshot} profile="screenshot-tv" />
+ {:else if item.video}
+ <Video autoplay video={item.video} profile="screenshot-tv" />
+ {/if}
+ </div>
+ </article>
+{/if}
+
+<style>
+ .artwork-container,
+ .artwork-container :global(video) {
+ border-radius: 1.3% / 1.9%;
+ overflow: hidden;
+
+ /* This `transform` is required to make the `overflow: hidden` clip properly on Chrome */
+ transform: translateZ(0);
+ }
+
+ .artwork-container :global(video):fullscreen {
+ border-radius: 0;
+ }
+</style>
diff --git a/src/components/jet/item/ProductMedia/ProductMediaVisionItem.svelte b/src/components/jet/item/ProductMedia/ProductMediaVisionItem.svelte
new file mode 100644
index 0000000..e893dd6
--- /dev/null
+++ b/src/components/jet/item/ProductMedia/ProductMediaVisionItem.svelte
@@ -0,0 +1,38 @@
+<script lang="ts">
+ import type { ProductMediaItem } from '@jet-app/app-store/api/models';
+ import Artwork from '~/components/Artwork.svelte';
+ import Video from '~/components/jet/Video.svelte';
+
+ export let item: ProductMediaItem;
+</script>
+
+{#if item.screenshot || item.video}
+ <article>
+ <div class="artwork-container">
+ {#if item.screenshot}
+ <Artwork
+ artwork={item.screenshot}
+ profile="screenshot-vision"
+ />
+ {:else if item.video}
+ <Video
+ autoplay
+ video={item.video}
+ profile="screenshot-vision"
+ />
+ {/if}
+ </div>
+ </article>
+{/if}
+
+<style>
+ .artwork-container,
+ .artwork-container :global(video) {
+ border-radius: 20px;
+ overflow: hidden;
+ }
+
+ .artwork-container :global(video):fullscreen {
+ border-radius: 0;
+ }
+</style>
diff --git a/src/components/jet/item/ProductMedia/ProductMediaWatchItem.svelte b/src/components/jet/item/ProductMedia/ProductMediaWatchItem.svelte
new file mode 100644
index 0000000..0a4b50e
--- /dev/null
+++ b/src/components/jet/item/ProductMedia/ProductMediaWatchItem.svelte
@@ -0,0 +1,50 @@
+<script lang="ts">
+ import type {
+ ProductMediaItem,
+ MediaType,
+ } from '@jet-app/app-store/api/models';
+ import Artwork from '~/components/Artwork.svelte';
+
+ export let item: ProductMediaItem;
+ export let mediaType: MediaType | undefined;
+</script>
+
+{#if item.screenshot}
+ <article>
+ <div
+ class="artwork-container"
+ class:apple-watch-2018={mediaType === 'appleWatch_2018'}
+ class:apple-watch-2021={mediaType === 'appleWatch_2021'}
+ class:apple-watch-2022={mediaType === 'appleWatch_2022'}
+ class:apple-watch-2024={mediaType === 'appleWatch_2024'}
+ >
+ <Artwork artwork={item.screenshot} profile="screenshot-watch" />
+ </div>
+ </article>
+{/if}
+
+<style>
+ .artwork-container {
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ border-radius: 12px;
+ overflow: hidden;
+ }
+
+ .apple-watch-2018 {
+ mask-image: url('/assets/images/masks/apple-watch-2018-mask.svg');
+ }
+
+ .apple-watch-2021 {
+ mask-image: url('/assets/images/masks/apple-watch-2021-mask.svg');
+ }
+
+ .apple-watch-2022 {
+ mask-image: url('/assets/images/masks/apple-watch-2022-mask.svg');
+ }
+
+ .apple-watch-2024 {
+ mask-image: url('/assets/images/masks/apple-watch-2024-mask.svg');
+ }
+</style>