mirror of
https://github.com/immich-app/static-pages.git
synced 2026-09-30 13:23:05 +08:00
feat: carousel card icons (#722)
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
import ComponentPage from '$lib/components/ComponentPage.svelte';
|
||||
import BasicExample from './BasicExample.svelte';
|
||||
import basicExample from './BasicExample.svelte?raw';
|
||||
import IconsExample from './IconsExample.svelte';
|
||||
import iconsExample from './IconsExample.svelte?raw';
|
||||
</script>
|
||||
|
||||
<ComponentPage
|
||||
@@ -10,5 +12,10 @@
|
||||
description="A horizontal scrolling carousel for displaying a list of images"
|
||||
size="large"
|
||||
>
|
||||
<ComponentExamples examples={[{ title: 'Basic', code: basicExample, component: BasicExample }]} />
|
||||
<ComponentExamples
|
||||
examples={[
|
||||
{ title: 'Basic', code: basicExample, component: BasicExample },
|
||||
{ title: 'Icons', code: iconsExample, component: IconsExample },
|
||||
]}
|
||||
/>
|
||||
</ComponentPage>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { carouselImageItems } from '$lib/constants.js';
|
||||
import { mdiHeart, mdiPlayCircleOutline, mdiStar } from '@mdi/js';
|
||||
import { ImageCarousel } from '@immich/ui';
|
||||
|
||||
const items = carouselImageItems.map((item, i) => ({
|
||||
...item,
|
||||
leftIcons: i % 2 === 0 ? [mdiStar] : [],
|
||||
rightIcons: i % 2 === 0 ? [mdiPlayCircleOutline] : [mdiHeart, mdiPlayCircleOutline],
|
||||
}));
|
||||
</script>
|
||||
|
||||
<ImageCarousel {items} />
|
||||
@@ -0,0 +1,55 @@
|
||||
<script lang="ts">
|
||||
import Icon from '$lib/components/Icon/Icon.svelte';
|
||||
import type { CarouselImageItem, IconLike } from '$lib/types.js';
|
||||
import { cleanClass } from '$lib/utilities/internal.js';
|
||||
|
||||
type Props = {
|
||||
item: CarouselImageItem;
|
||||
leftIcons?: IconLike[];
|
||||
rightIcons?: IconLike[];
|
||||
class?: string;
|
||||
};
|
||||
|
||||
const { item, leftIcons, rightIcons, class: className }: Props = $props();
|
||||
|
||||
let left = $derived(leftIcons ?? item.leftIcons ?? []);
|
||||
let right = $derived(rightIcons ?? item.rightIcons ?? []);
|
||||
</script>
|
||||
|
||||
<a
|
||||
class={cleanClass(
|
||||
'item-card relative me-2 inline-block aspect-3/4 h-54 rounded-xl last:me-0 max-md:h-37.5 md:me-4 md:aspect-4/3 xl:aspect-video',
|
||||
className,
|
||||
)}
|
||||
href={item.href}
|
||||
>
|
||||
<img class="h-full w-full rounded-xl object-cover" src={item.src} alt={item.alt ?? item.title} draggable="false" />
|
||||
{#if left.length > 0}
|
||||
<div class="absolute top-3 left-3 flex gap-2 text-white drop-shadow-md">
|
||||
{#each left as icon, i (i)}
|
||||
<Icon {icon} size="1.5rem" aria-hidden />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if right.length > 0}
|
||||
<div class="absolute top-3 right-3 flex gap-2 text-white drop-shadow-md">
|
||||
{#each right as icon, i (i)}
|
||||
<Icon {icon} size="1.5rem" aria-hidden />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
class="absolute inset-s-0 top-0 h-full w-full rounded-xl bg-linear-to-t from-black/40 via-transparent to-transparent transition-all hover:bg-black/20"
|
||||
></div>
|
||||
<p class="absolute inset-s-4 bottom-2 text-lg text-white max-md:text-sm">
|
||||
{item.title}
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
.item-card {
|
||||
box-shadow:
|
||||
rgba(60, 64, 67, 0.3) 0px 1px 2px 0px,
|
||||
rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import IconButton from '$lib/components/IconButton/IconButton.svelte';
|
||||
import ImageCard from '$lib/components/ImageCard/ImageCard.svelte';
|
||||
import { zIndex } from '$lib/constants.js';
|
||||
import { t } from '$lib/services/translation.svelte.js';
|
||||
import type { CarouselImageItem, TranslationProps } from '$lib/types.js';
|
||||
@@ -37,18 +38,7 @@
|
||||
</script>
|
||||
|
||||
{#snippet defaultChild(item: CarouselImageItem)}
|
||||
<a
|
||||
class="item-card relative me-2 inline-block aspect-3/4 h-54 rounded-xl last:me-0 max-md:h-37.5 md:me-4 md:aspect-4/3 xl:aspect-video"
|
||||
href={item.href}
|
||||
>
|
||||
<img class="h-full w-full rounded-xl object-cover" src={item.src} alt={item.alt ?? item.title} draggable="false" />
|
||||
<div
|
||||
class="absolute start-0 top-0 h-full w-full rounded-xl bg-linear-to-t from-black/40 via-transparent to-transparent transition-all hover:bg-black/20"
|
||||
></div>
|
||||
<p class="absolute start-4 bottom-2 text-lg text-white max-md:text-sm">
|
||||
{item.title}
|
||||
</p>
|
||||
</a>
|
||||
<ImageCard {item} />
|
||||
{/snippet}
|
||||
|
||||
{#if shouldRender}
|
||||
@@ -101,11 +91,3 @@
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.item-card {
|
||||
box-shadow:
|
||||
rgba(60, 64, 67, 0.3) 0px 1px 2px 0px,
|
||||
rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -57,6 +57,7 @@ export { default as Heading } from '$lib/components/Heading/Heading.svelte';
|
||||
export { default as HelperText } from '$lib/components/HelperText/HelperText.svelte';
|
||||
export { default as Icon } from '$lib/components/Icon/Icon.svelte';
|
||||
export { default as IconButton } from '$lib/components/IconButton/IconButton.svelte';
|
||||
export { default as ImageCard } from '$lib/components/ImageCard/ImageCard.svelte';
|
||||
export { default as ImageCarousel } from '$lib/components/ImageCarousel/ImageCarousel.svelte';
|
||||
export { default as Input } from '$lib/components/Input/Input.svelte';
|
||||
export { default as Kbd } from '$lib/components/Kbd/Kbd.svelte';
|
||||
|
||||
@@ -424,6 +424,8 @@ export type CarouselImageItem = {
|
||||
src: string;
|
||||
alt?: string;
|
||||
id?: string;
|
||||
leftIcons?: IconLike[];
|
||||
rightIcons?: IconLike[];
|
||||
};
|
||||
|
||||
export type ControlBarProps = {
|
||||
|
||||
Reference in New Issue
Block a user