mirror of
https://github.com/immich-app/static-pages.git
synced 2026-09-30 13:23:05 +08:00
feat(ui): direction-aware icons (#804)
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
import basicExample from './BasicExample.svelte?raw';
|
||||
import ColorExample from './ColorExample.svelte';
|
||||
import colorExample from './ColorExample.svelte?raw';
|
||||
import DirectionalExample from './DirectionalExample.svelte';
|
||||
import directionalExample from './DirectionalExample.svelte?raw';
|
||||
import IndicatorExample from './IndicatorExample.svelte';
|
||||
import indicatorExample from './IndicatorExample.svelte?raw';
|
||||
import OtherExample from './OtherExample.svelte';
|
||||
@@ -20,6 +22,7 @@
|
||||
{ title: 'Sizes', code: sizeExample, component: SizeExample },
|
||||
{ title: 'Colors', code: colorExample, component: ColorExample },
|
||||
{ title: 'Indicator', code: indicatorExample, component: IndicatorExample },
|
||||
{ title: 'Directionality', code: directionalExample, component: DirectionalExample },
|
||||
{ title: 'Other', code: otherExample, component: OtherExample },
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { Heading, HStack, Icon, Stack, Text } from '@immich/ui';
|
||||
import { mdiArrowRight } from '@mdi/js';
|
||||
|
||||
const icon = mdiArrowRight;
|
||||
const size = '2em';
|
||||
</script>
|
||||
|
||||
<HStack gap={8}>
|
||||
<Stack>
|
||||
<Heading size="tiny">Auto</Heading>
|
||||
<div class="flex place-items-center gap-2">
|
||||
<Icon {icon} {size} directional />
|
||||
<Text>Normal</Text>
|
||||
</div>
|
||||
<div class="flex place-items-center gap-2">
|
||||
<Icon {icon} {size} directional flipped />
|
||||
<Text>Flipped</Text>
|
||||
</div>
|
||||
</Stack>
|
||||
<div dir="ltr">
|
||||
<Stack>
|
||||
<Heading size="tiny">Left-to-right</Heading>
|
||||
<div class="flex place-items-center gap-2">
|
||||
<Icon {icon} {size} directional />
|
||||
<Text>Normal</Text>
|
||||
</div>
|
||||
<div class="flex place-items-center gap-2">
|
||||
<Icon {icon} {size} directional flipped />
|
||||
<Text>Flipped</Text>
|
||||
</div>
|
||||
</Stack>
|
||||
</div>
|
||||
<div dir="rtl">
|
||||
<Stack>
|
||||
<Heading size="tiny">Right-to-left</Heading>
|
||||
<div class="flex place-items-center gap-2">
|
||||
<Icon {icon} {size} directional />
|
||||
<Text>Normal</Text>
|
||||
</div>
|
||||
<div class="flex place-items-center gap-2">
|
||||
<Icon {icon} {size} directional flipped />
|
||||
<Text>Flipped</Text>
|
||||
</div>
|
||||
</Stack>
|
||||
</div>
|
||||
</HStack>
|
||||
@@ -25,7 +25,7 @@
|
||||
{#if typeof separator === 'object' && 'text' in separator}
|
||||
<span class="mx-1">{separator.text}</span>
|
||||
{:else}
|
||||
<Icon icon={separator} size="1rem" />
|
||||
<Icon icon={separator} size="1rem" directional />
|
||||
{/if}
|
||||
{/if}
|
||||
{#if item.href}
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
{:else if onClose}
|
||||
<IconButton
|
||||
icon={closeIcon ?? mdiClose}
|
||||
directional
|
||||
shape="round"
|
||||
variant="ghost"
|
||||
color="secondary"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
viewBox = '0 0 24 24',
|
||||
class: className = '',
|
||||
indicator: indicatorColor,
|
||||
directional = false,
|
||||
flipped = false,
|
||||
flopped = false,
|
||||
spin = false,
|
||||
@@ -36,13 +37,25 @@
|
||||
color: styleVariants.textColor,
|
||||
},
|
||||
});
|
||||
|
||||
const flip = $derived.by(() => {
|
||||
if (directional && flipped) {
|
||||
return 'ltr:-scale-x-100 rtl:scale-x-100';
|
||||
}
|
||||
if (directional) {
|
||||
return 'rtl:-scale-x-100 ltr:scale-x-100';
|
||||
}
|
||||
if (flipped) {
|
||||
return '-scale-x-100';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
{viewBox}
|
||||
class={cleanClass(className, flipped && '-scale-x-100', flopped && 'rotate-180', spin && 'animate-spin')}
|
||||
class={cleanClass(className, flip, flopped && 'rotate-180', spin && 'animate-spin')}
|
||||
stroke={strokeColor}
|
||||
stroke-width={strokeWidth}
|
||||
{role}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
const {
|
||||
icon,
|
||||
directional,
|
||||
flipped,
|
||||
flopped,
|
||||
indicator,
|
||||
@@ -18,5 +19,5 @@
|
||||
</script>
|
||||
|
||||
<Button icon {color} {...buttonProps} title={buttonTitle} aria-label={ariaLabel}>
|
||||
<Icon {icon} {flipped} {flopped} {indicator} size="60%" aria-hidden />
|
||||
<Icon {icon} {directional} {flipped} {flopped} {indicator} size="60%" aria-hidden />
|
||||
</Button>
|
||||
|
||||
@@ -50,11 +50,12 @@
|
||||
onscroll={onScroll}
|
||||
>
|
||||
{#if canScrollLeft || canScrollRight}
|
||||
<div class="sticky start-0 {zIndex.CarouselImage}">
|
||||
<div class="sticky inset-s-0 light {zIndex.CarouselImage}">
|
||||
{#if canScrollLeft}
|
||||
<div class="light absolute start-4 top-27 -translate-y-1/2 max-md:top-19" transition:fade={{ duration: 200 }}>
|
||||
<div class="absolute inset-s-4 top-27 -translate-y-1/2 max-md:top-19" transition:fade={{ duration: 200 }}>
|
||||
<IconButton
|
||||
icon={mdiChevronLeft}
|
||||
directional
|
||||
shape="round"
|
||||
variant="outline"
|
||||
color="secondary"
|
||||
@@ -66,12 +67,10 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if canScrollRight}
|
||||
<div
|
||||
class="light absolute end-4 top-27 {zIndex.CarouselImage} -translate-y-1/2 max-md:top-19"
|
||||
transition:fade={{ duration: 200 }}
|
||||
>
|
||||
<div class="absolute inset-e-4 top-27 -translate-y-1/2 max-md:top-19" transition:fade={{ duration: 200 }}>
|
||||
<IconButton
|
||||
icon={mdiChevronRight}
|
||||
directional
|
||||
shape="round"
|
||||
variant="outline"
|
||||
color="secondary"
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
>
|
||||
<Icon
|
||||
icon={expanded ? mdiChevronDown : mdiChevronRight}
|
||||
directional
|
||||
size="1em"
|
||||
class="shrink-0 delay-100 duration-100 "
|
||||
aria-hidden
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
href={previous.href}
|
||||
class="hover:border-primary hover:text-primary flex items-center gap-2 rounded-xl border p-4 transition-colors"
|
||||
>
|
||||
<Icon icon={mdiChevronLeft} size="1.5rem" />
|
||||
<Icon icon={mdiChevronLeft} size="1.5rem" directional />
|
||||
<div class="min-w-0">
|
||||
<Text color="muted" size="tiny">{t('navigate_previous', translations)}</Text>
|
||||
<Text fontWeight="semi-bold" class="truncate">{previous.title}</Text>
|
||||
@@ -36,7 +36,7 @@
|
||||
<Text color="muted" size="tiny">{t('navigate_next', translations)}</Text>
|
||||
<Text fontWeight="semi-bold" class="truncate">{next.title}</Text>
|
||||
</div>
|
||||
<Icon icon={mdiChevronRight} size="1.5rem" />
|
||||
<Icon icon={mdiChevronRight} size="1.5rem" directional />
|
||||
</a>
|
||||
{/if}
|
||||
</nav>
|
||||
|
||||
@@ -69,6 +69,10 @@ export type IconProps = {
|
||||
size?: string;
|
||||
color?: Color | 'currentColor' | string;
|
||||
indicator?: Color;
|
||||
/**
|
||||
* Flip the icon in RTL layouts
|
||||
*/
|
||||
directional?: boolean;
|
||||
flipped?: boolean;
|
||||
flopped?: boolean;
|
||||
spin?: boolean;
|
||||
@@ -116,6 +120,10 @@ export type ContextMenuButtonProps = ButtonBase & {
|
||||
|
||||
export type IconButtonProps = ButtonBase & {
|
||||
icon: IconLike;
|
||||
/**
|
||||
* Flip the icon in RTL layouts
|
||||
*/
|
||||
directional?: boolean;
|
||||
flipped?: boolean;
|
||||
flopped?: boolean;
|
||||
indicator?: Color;
|
||||
|
||||
Reference in New Issue
Block a user