From bce557cc2dc767628bed6aac87301a1be7c5431b Mon Sep 17 00:00:00 2001
From: rxliuli <rxliuli@gmail.com>
Date: Tue, 4 Nov 2025 05:03:50 +0800
Subject: init commit

---
 .../jet/item/SmallStoryCardWithMediaRiver.svelte   | 118 +++++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 src/components/jet/item/SmallStoryCardWithMediaRiver.svelte

(limited to 'src/components/jet/item/SmallStoryCardWithMediaRiver.svelte')

diff --git a/src/components/jet/item/SmallStoryCardWithMediaRiver.svelte b/src/components/jet/item/SmallStoryCardWithMediaRiver.svelte
new file mode 100644
index 0000000..038f504
--- /dev/null
+++ b/src/components/jet/item/SmallStoryCardWithMediaRiver.svelte
@@ -0,0 +1,118 @@
+<script lang="ts" context="module">
+    import type {
+        TodayCard,
+        TodayCardMediaRiver,
+    } from '@jet-app/app-store/api/models';
+
+    export interface TodayCardWithMediaRiver extends TodayCard {
+        media: TodayCardMediaRiver;
+    }
+
+    export function isSmallStoryCardWithMediaRiver(
+        item: TodayCard,
+    ): item is TodayCardWithMediaRiver {
+        return !!item.media && item.media.kind === 'river';
+    }
+</script>
+
+<script lang="ts">
+    import type { Opt } from '@jet/environment/types/optional';
+    import HoverWrapper from '~/components/HoverWrapper.svelte';
+    import LinkWrapper from '~/components/LinkWrapper.svelte';
+    import AppIconRiver from '~/components/AppIconRiver.svelte';
+    import {
+        getBackgroundGradientCSSVarsFromArtworks,
+        getLuminanceForRGB,
+    } from '~/utils/color';
+
+    export let item: TodayCardWithMediaRiver;
+
+    $: icons = item.media.lockups.map((lockup) => lockup.icon);
+    $: backgroundGradientCssVars = getBackgroundGradientCSSVarsFromArtworks(
+        icons,
+        {
+            // sorts from darkest to lightest
+            sortFn: (a, b) => getLuminanceForRGB(a) - getLuminanceForRGB(b),
+        },
+    );
+
+    let title: Opt<string>;
+    let eyebrow: Opt<string>;
+    $: {
+        eyebrow = item.heading;
+        title = item.title;
+
+        if (item.inlineDescription) {
+            eyebrow = item.title;
+            title = item.inlineDescription;
+        }
+    }
+</script>
+
+<LinkWrapper action={item.clickAction}>
+    <HoverWrapper>
+        <div class="river-container" style={backgroundGradientCssVars}>
+            <AppIconRiver {icons} profile="app-icon" />
+        </div>
+    </HoverWrapper>
+
+    <div class="text-container">
+        {#if eyebrow}
+            <h4>{eyebrow}</h4>
+        {/if}
+
+        {#if title}
+            <h3>{title}</h3>
+        {/if}
+    </div>
+</LinkWrapper>
+
+<style>
+    .river-container {
+        --app-icon-river-icon-width: 48px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        aspect-ratio: 16 / 9;
+        width: 100%;
+        border-radius: 8px;
+        background: radial-gradient(
+                circle at 3% -50%,
+                var(--top-left, #000) 20%,
+                transparent 70%
+            ),
+            radial-gradient(
+                circle at -50% 120%,
+                var(--bottom-left, #000) 40%,
+                transparent 80%
+            ),
+            radial-gradient(
+                circle at 140% -50%,
+                var(--top-right, #000) 60%,
+                transparent 80%
+            ),
+            radial-gradient(
+                circle at 62% 100%,
+                var(--bottom-right, #000) 50%,
+                transparent 100%
+            );
+    }
+
+    .river-container :global(.app-icons:last-of-type) {
+        margin-bottom: 0;
+    }
+
+    .text-container {
+        margin-top: 8px;
+    }
+
+    h3 {
+        font: var(--title-3);
+    }
+
+    h4 {
+        margin-bottom: 2px;
+        font: var(--callout-emphasized);
+        color: var(--systemSecondary);
+    }
+</style>
-- 
cgit v1.2.3

