init commit

This commit is contained in:
rxliuli
2025-11-04 05:03:50 +08:00
commit bce557cc2d
1396 changed files with 172991 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
<script lang="ts">
import {
isFlowAction,
type EditorialStoryCard,
type FlowAction,
} from '@jet-app/app-store/api/models';
import type { Opt } from '@jet/environment';
import LineClamp from '@amp/web-app-components/src/components/LineClamp/LineClamp.svelte';
import { sanitizeHtml } from '@amp/web-app-components/src/utils/sanitize-html';
import AppIcon from '~/components/AppIcon.svelte';
import Artwork from '~/components/Artwork.svelte';
import LinkWrapper from '~/components/LinkWrapper.svelte';
import { getI18n } from '~/stores/i18n';
import HoverWrapper from '~/components/HoverWrapper.svelte';
export let item: EditorialStoryCard;
let {
clickAction,
collectionIcons,
title,
lockup: { title: lockupTitle, subtitle, heading: lockupHeading } = {},
} = item;
const i18n = getI18n();
const hasMultipleCollectionIcons = (collectionIcons?.length ?? 0) > 1;
const destination: Opt<FlowAction> =
clickAction && isFlowAction(clickAction) ? clickAction : undefined;
</script>
<LinkWrapper action={destination}>
<article>
{#if item.artwork}
<div class="artwork-container">
<HoverWrapper element="div">
<Artwork
artwork={item.artwork}
profile="editorial-story-card"
/>
</HoverWrapper>
</div>
{/if}
<div class="details-container">
<div
class="title-container"
class:on-dark={item.isMediaDark}
class:on-light={!item.isMediaDark}
>
{#if item.badge}
<h4>{item.badge.title}</h4>
{/if}
{#if item.title}
<h3>{@html sanitizeHtml(item.title)}</h3>
{/if}
{#if item.description}
<p>{@html sanitizeHtml(item.description)}</p>
{/if}
</div>
{#if collectionIcons && !item.editorialDisplayOptions.suppressLockup}
<div class="lockup-container">
<ul class:with-multiple-icons={hasMultipleCollectionIcons}>
{#each collectionIcons as collectionIcon}
<li class="app-icon-container">
<AppIcon
icon={collectionIcon}
fixedWidth={false}
profile={hasMultipleCollectionIcons
? 'app-icon-medium'
: 'app-icon'}
/>
</li>
{/each}
</ul>
{#if !hasMultipleCollectionIcons}
<div class="metadata-container">
{#if lockupHeading}
<span class="lockup-eyebrow">
{lockupHeading}
</span>
{/if}
<!--
Some cards with the lockup UI don't have a `lockup` property,
so we use the title of the item as a fallback.
-->
{#if lockupTitle || title}
<LineClamp clamp={1}>
<h4 class="lockup-title">
{lockupTitle || title}
</h4>
</LineClamp>
{/if}
{#if subtitle}
<LineClamp clamp={1}>
<p class="lockup-subtitle">{subtitle}</p>
</LineClamp>
{/if}
</div>
{#if destination}
<div class="button-container">
<span class="get-button transparent">
{$i18n.t('ASE.Web.AppStore.View')}
</span>
</div>
{/if}
{/if}
</div>
{/if}
</div>
<div
class="blur-overlay"
style:--brightness={item.isMediaDark ? 0.75 : 1.25}
/>
</article>
</LinkWrapper>
<style lang="scss">
@use '@amp/web-shared-styles/sasskit-stylekit/ac-sasskit-config';
@use 'ac-sasskit/core/helpers' as *;
@use 'ac-sasskit/core/locale' as *;
article {
position: relative;
overflow: hidden;
border-radius: var(--global-border-radius-large);
box-shadow: var(--shadow-medium);
aspect-ratio: 3/4;
container-type: inline-size;
container-name: card;
}
.artwork-container {
position: absolute;
width: 100%;
height: 100%;
}
.details-container {
display: flex;
flex-direction: column;
justify-content: end;
height: 100%;
border-radius: var(--global-border-radius-large);
overflow: hidden;
z-index: 1;
}
.title-container {
padding: 20px;
z-index: 2;
}
.title-container h3 {
margin-bottom: 2px;
font: var(--title-1-emphasized);
text-wrap: pretty;
}
.title-container h4 {
font: var(--callout-emphasized);
}
.on-dark {
color: var(--systemPrimary-onDark);
}
.on-light {
color: var(--systemPrimary-onLight);
}
.title-container.on-dark h4 {
color: var(--systemSecondary-onDark);
mix-blend-mode: plus-lighter;
}
.title-container.on-light h4 {
color: var(--systemSecondary-onLight);
}
.title-container.on-dark p {
font: var(--body);
color: var(--systemSecondary-onDark);
}
.title-container.on-light p {
font: var(--body);
color: var(--systemSecondary-onLight);
}
.lockup-container {
display: flex;
align-items: center;
min-height: 80px;
padding: 10px 20px;
color: var(--systemPrimary-onDark);
background-image: linear-gradient(rgba(0, 0, 0, 0.2) 0 0);
z-index: 2;
}
.metadata-container {
flex-grow: 1;
margin-inline-end: 16px;
}
.lockup-title {
font: var(--title-3-emphasized);
}
.lockup-eyebrow {
color: var(--systemSecondary-onDark);
font: var(--subhead-emphasized);
text-transform: uppercase;
mix-blend-mode: plus-lighter;
}
.lockup-subtitle {
color: var(--systemSecondary-onDark);
font: var(--callout);
mix-blend-mode: plus-lighter;
}
.app-icon-container {
flex-shrink: 0;
width: 48px;
margin-inline-end: 16px;
}
article:hover .blur-overlay {
height: 52%;
backdrop-filter: blur(70px) saturate(1.5)
brightness(calc(var(--brightness) * 0.9));
}
.blur-overlay {
position: absolute;
z-index: 1;
top: unset;
bottom: 0;
width: 100%;
height: 50%;
border-radius: var(--global-border-radius-large);
mask-image: linear-gradient(
180deg,
rgba(255, 255, 255, 0) 5%,
rgba(0, 0, 0, 1) 50%
);
backdrop-filter: blur(50px) saturate(1.5)
brightness((var(--brightness)));
transition-property: height, backdrop-filter;
transition-duration: 210ms;
transition-timing-function: ease-out;
}
ul.with-multiple-icons {
width: 100%;
display: grid;
gap: 12px;
.app-icon-container {
width: 100%;
margin-inline-end: unset;
}
}
// In the following container queries, we are specifying column counts and hiding icons past
// that number to ensure a reasonable number of icons are shown for different size cards.
@container card (max-width: 300px) {
ul.with-multiple-icons {
// Think of "4" as the number of columns to show
grid-template-columns: repeat(4, 1fr);
}
// And "5" as the number of columns to hide past
.app-icon-container:nth-child(n + 5) {
display: none;
}
}
@container card (min-width: 300px) and (max-width: 400px) {
ul.with-multiple-icons {
grid-template-columns: repeat(5, 1fr);
}
.app-icon-container:nth-child(n + 6) {
display: none;
}
}
@container card (min-width: 400px) {
ul.with-multiple-icons {
grid-template-columns: repeat(6, 1fr);
}
.app-icon-container:nth-child(n + 7) {
display: none;
}
}
</style>