summaryrefslogtreecommitdiff
path: root/src/components/AppIcon.svelte
diff options
context:
space:
mode:
authorrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
committerrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
commitbce557cc2dc767628bed6aac87301a1be7c5431b (patch)
treeb51a051228d01fe3306cd7626d4a96768aadb944 /src/components/AppIcon.svelte
init commit
Diffstat (limited to 'src/components/AppIcon.svelte')
-rw-r--r--src/components/AppIcon.svelte131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/components/AppIcon.svelte b/src/components/AppIcon.svelte
new file mode 100644
index 0000000..4cb0262
--- /dev/null
+++ b/src/components/AppIcon.svelte
@@ -0,0 +1,131 @@
+<script lang="ts" context="module">
+ import type { Artwork as JetArtworkType } from '@jet-app/app-store/api/models';
+ import type { NamedProfile } from '~/config/components/artwork';
+
+ export type AppIconProfile = Extract<
+ NamedProfile,
+ | 'app-icon'
+ | 'app-icon-large'
+ | 'app-icon-medium'
+ | 'app-icon-small'
+ | 'app-icon-xlarge'
+ | 'app-icon-river'
+ | 'brick-app-icon'
+ >;
+
+ export function doesAppIconNeedBorder(icon: JetArtworkType): boolean {
+ const doesIconHaveTransparentBackground =
+ icon.backgroundColor &&
+ isNamedColor(icon.backgroundColor) &&
+ icon.backgroundColor.name === 'clear';
+ const isIconPrerendered =
+ icon.style === 'roundedRectPrerendered' ||
+ icon.style === 'roundPrerendered';
+ const isIconUnadorned = icon.style === 'unadorned';
+
+ return (
+ !doesIconHaveTransparentBackground &&
+ !isIconPrerendered &&
+ !isIconUnadorned
+ );
+ }
+</script>
+
+<script lang="ts">
+ import Artwork from '~/components/Artwork.svelte';
+ import { ArtworkConfig } from '@amp/web-app-components/config/components/artwork';
+ import { isNamedColor } from '~/utils/color';
+
+ export let icon: JetArtworkType;
+ export let profile: AppIconProfile = 'app-icon';
+ export let fixedWidth: boolean = true;
+ export let disableAutoCenter: boolean = false;
+ export let withBorder: boolean = false;
+
+ const profiles = ArtworkConfig.get().PROFILES;
+
+ $: computedProfile = (
+ icon.style === 'pill'
+ ? `${profile}-pill`
+ : icon.style === 'tvRect'
+ ? `${profile}-tv-rect`
+ : profile
+ ) as NamedProfile;
+ $: widthFromProfile = profiles?.get(computedProfile)?.[0] ?? 0;
+ $: hasTransparentBackground =
+ !!icon.backgroundColor &&
+ isNamedColor(icon.backgroundColor) &&
+ icon.backgroundColor.name === 'clear';
+ $: needsBorder = withBorder || doesAppIconNeedBorder(icon);
+
+ // These prerendered "Solarium" icons need to use higher than normal quality due to how their
+ // rendering pipeline downscales/transforms sources.
+ $: quality =
+ icon.style &&
+ ['roundedRectPrerendered', 'roundPrerendered'].includes(icon.style)
+ ? 75
+ : undefined;
+</script>
+
+<div
+ class="app-icon"
+ class:pill={icon.style === 'pill'}
+ class:round={icon.style === 'round'}
+ class:rounded-rect={icon.style === 'roundedRect'}
+ class:tv-rect={icon.style === 'tvRect'}
+ class:rounded-rect-prerendered={icon.style === 'roundedRectPrerendered'}
+ class:round-prerendered={icon.style === 'roundPrerendered'}
+ class:with-border={needsBorder}
+ style={fixedWidth ? `--profileWidth: ${widthFromProfile}px` : ''}
+>
+ <Artwork
+ {disableAutoCenter}
+ {hasTransparentBackground}
+ {quality}
+ artwork={icon}
+ profile={computedProfile}
+ noShelfChevronAnchor={true}
+ />
+</div>
+
+<style>
+ .app-icon {
+ aspect-ratio: 1 / 1;
+ min-width: var(--profileWidth, auto);
+ }
+
+ .app-icon.pill {
+ aspect-ratio: 4 / 3;
+
+ /*
+ Creates elliptical corners with horizontal radii at 50% of the width and vertical radii
+ at 65% of the height, for a rounded, squished, pill-like effect
+ */
+ border-radius: 50% 50% 50% 50% / 65% 65% 65% 65%;
+ }
+
+ .app-icon.round {
+ border-radius: 50%;
+ }
+
+ .app-icon.rounded-rect {
+ border-radius: 23%;
+ }
+
+ .app-icon.tv-rect {
+ aspect-ratio: 16/9;
+ border-radius: 9% / 16%;
+ }
+
+ .app-icon.rounded-rect-prerendered {
+ border-radius: 25%;
+ }
+
+ .app-icon.round-prerendered {
+ border-radius: 50%;
+ }
+
+ .app-icon.with-border {
+ box-shadow: 0 0 0 1px var(--systemQuaternary);
+ }
+</style>