diff options
| author | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
|---|---|---|
| committer | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
| commit | bce557cc2dc767628bed6aac87301a1be7c5431b (patch) | |
| tree | b51a051228d01fe3306cd7626d4a96768aadb944 /src/components/jet/item/TitledParagraphItem.svelte | |
init commit
Diffstat (limited to 'src/components/jet/item/TitledParagraphItem.svelte')
| -rw-r--r-- | src/components/jet/item/TitledParagraphItem.svelte | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/components/jet/item/TitledParagraphItem.svelte b/src/components/jet/item/TitledParagraphItem.svelte new file mode 100644 index 0000000..ad8e4bc --- /dev/null +++ b/src/components/jet/item/TitledParagraphItem.svelte @@ -0,0 +1,175 @@ +<script lang="ts" context="module"> + import type { + ShelfModel, + TitledParagraph, + } from '@jet-app/app-store/api/models'; + + export function isTitledParagraphItem( + item: ShelfModel | string, + ): item is TitledParagraph { + return typeof item !== 'string' && 'text' in item; + } +</script> + +<script lang="ts"> + import { sanitizeHtml } from '@amp/web-app-components/src/utils/sanitize-html'; + import LineClamp from '@amp/web-app-components/src/components/LineClamp/LineClamp.svelte'; + import { getNumericDateFromDateString } from '@amp/web-app-components/src/utils/date'; + import { getJet } from '~/jet/svelte'; + import { getI18n } from '~/stores/i18n'; + + export let item: TitledParagraph; + + const i18n = getI18n(); + const jet = getJet(); + const isDetailView = item.style === 'detail'; + const dateForDisplay = jet.localization.timeAgo( + new Date(item.secondarySubtitle), + ); + const dateForAttribute = getNumericDateFromDateString( + item.secondarySubtitle, + ); + + let isTruncated = true; +</script> + +<article class:detail={isDetailView} class:overview={!isDetailView}> + <div class="container"> + <p> + {#if item.text} + {#if !isTruncated || isDetailView} + {item.text} + {:else} + <LineClamp + clamp={5} + observe + on:resize={({ detail }) => + (isTruncated = detail.truncated)} + > + {@html sanitizeHtml(item.text)} + </LineClamp> + + {#if isTruncated} + <button on:click={() => (isTruncated = false)}> + {$i18n.t('ASE.Web.AppStore.More')} + </button> + {/if} + {/if} + {/if} + </p> + + <div class="metadata"> + <h4>{item.primarySubtitle}</h4> + <time datetime={dateForAttribute}>{dateForDisplay}</time> + </div> + </div> +</article> + +<style lang="scss"> + @use '@amp/web-shared-styles/sasskit-stylekit/ac-sasskit-config'; + @use 'ac-sasskit/core/locale' as *; + + article { + display: flex; + flex-direction: column-reverse; + font: var(--body-tall); + color: var(--systemPrimary); + margin: 0 var(--bodyGutter); + + @media (--range-small-up) { + flex-direction: row; + } + } + + .container { + display: flex; + width: 100%; + } + + p { + position: relative; + display: flex; + flex-direction: column; + white-space: break-spaces; + font: var(--body-tall); + } + + .metadata { + display: flex; + flex-direction: column; + justify-content: flex-start; + margin: 0 0 8px 8px; + text-align: end; + color: var(--systemSecondary); + } + + h4 { + font: var(--body-tall); + } + + button { + --gradient-direction: 270deg; + position: absolute; + bottom: 0; + display: flex; + justify-content: end; + color: var(--keyColor); + inset-inline-end: 0; + padding-inline-start: 20px; + background: linear-gradient( + var(--gradient-direction), + var(--pageBg) 72%, + transparent 100% + ); + + @include rtl { + --gradient-direction: 90deg; + } + } + + time { + color: var(--systemSecondary); + white-space: nowrap; + } + + .detail { + flex-direction: column-reverse; + margin: 0; + padding: 16px 0 0; + border-top: 1px solid var(--systemGray4); + } + + .detail .metadata { + gap: 2px; + } + + .detail h4 { + font: var(--body-emphasized-tall); + color: var(--systemPrimary); + } + + .overview .container { + @media (--range-medium-up) { + width: 66%; + } + } + + .overview .metadata { + flex-grow: 1; + gap: 4px; + } + + .overview p { + @media (--range-small-up) { + width: 66%; + } + + @media (--range-large-up) { + width: 50%; + } + } + + .detail .container { + justify-content: space-between; + } +</style> |
