@immich/ui 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@
5
5
  import Icon from '../Icon/Icon.svelte';
6
6
  import Text from '../Text/Text.svelte';
7
7
  import type { Color, Size } from '../../types.js';
8
- import { cleanClass } from '../../utilities/internal.js';
8
+ import { cleanClass, resolveIcon } from '../../utilities/internal.js';
9
9
  import {
10
10
  mdiAlertOutline,
11
11
  mdiCheckCircleOutline,
@@ -66,14 +66,17 @@
66
66
  setTimeout(handleClose, duration);
67
67
  }
68
68
 
69
- const icons: Partial<Record<Color, string>> = {
70
- success: mdiCheckCircleOutline,
71
- warning: mdiAlertOutline,
72
- danger: mdiCloseCircleOutline,
73
- };
74
-
75
69
  const icon = $derived(
76
- iconOverride === false ? undefined : iconOverride || (icons[color] ?? mdiInformationVariantCircleOutline),
70
+ resolveIcon({
71
+ icons: {
72
+ success: mdiCheckCircleOutline,
73
+ warning: mdiAlertOutline,
74
+ danger: mdiCloseCircleOutline,
75
+ },
76
+ color,
77
+ override: iconOverride,
78
+ fallback: mdiInformationVariantCircleOutline,
79
+ }),
77
80
  );
78
81
  </script>
79
82
 
@@ -0,0 +1,93 @@
1
+ <script lang="ts">
2
+ import Icon from '../Icon/Icon.svelte';
3
+ import Text from '../Text/Text.svelte';
4
+ import { styleVariants } from '../../styles.js';
5
+ import type { IconLike, Size, TextColor } from '../../types.js';
6
+ import { cleanClass, resolveIcon } from '../../utilities/internal.js';
7
+ import { mdiAlertCircleOutline, mdiAlertOutline, mdiCheckAll, mdiInformationOutline, mdiPartyPopper } from '@mdi/js';
8
+ import type { Snippet } from 'svelte';
9
+ import type { HTMLAttributes } from 'svelte/elements';
10
+ import { tv } from 'tailwind-variants';
11
+
12
+ type Props = {
13
+ color?: TextColor;
14
+ size?: Size;
15
+ icon?: IconLike | false;
16
+ center?: boolean;
17
+ children?: Snippet;
18
+ content?: Snippet;
19
+ } & HTMLAttributes<HTMLElement>;
20
+
21
+ const styles = tv({
22
+ base: 'px-4 py-2',
23
+ variants: {
24
+ center: {
25
+ true: 'flex items-center justify-around',
26
+ false: '',
27
+ },
28
+ color: {
29
+ primary: 'bg-primary/15 text-primary dark:bg-primary/10',
30
+ secondary: 'bg-dark/15 text-dark dark:bg-dark/10',
31
+ muted: 'bg-subtle text-subtle dark:bg-subtle',
32
+ info: 'bg-info/15 text-info dark:bg-info/10',
33
+ warning: 'bg-warning/15 text-warning dark:bg-warning/10',
34
+ danger: 'bg-danger/15 text-danger dark:bg-danger/10',
35
+ success: 'bg-success/15 text-success dark:bg-success/10',
36
+ },
37
+ },
38
+ });
39
+
40
+ let {
41
+ color = 'primary',
42
+ size = 'medium',
43
+ class: className,
44
+ center = false,
45
+ icon: iconOverride,
46
+ content,
47
+ children,
48
+ ...restProps
49
+ }: Props = $props();
50
+
51
+ const icon = $derived(
52
+ resolveIcon({
53
+ icons: {
54
+ danger: mdiAlertCircleOutline,
55
+ warning: mdiAlertOutline,
56
+ success: mdiCheckAll,
57
+ info: mdiInformationOutline,
58
+ },
59
+ color,
60
+ override: iconOverride,
61
+ fallback: mdiPartyPopper,
62
+ }),
63
+ );
64
+
65
+ const iconStyles = tv({
66
+ base: '',
67
+ variants: {
68
+ color: styleVariants.textColor,
69
+ size: {
70
+ tiny: 'text-xs',
71
+ small: 'text-sm',
72
+ medium: 'text-base',
73
+ large: 'text-lg',
74
+ giant: 'text-xl',
75
+ },
76
+ },
77
+ });
78
+ </script>
79
+
80
+ <div class={cleanClass(styles({ color, center }), className)} {...restProps}>
81
+ {#if content}
82
+ {@render content()}
83
+ {:else}
84
+ <div class="flex items-center gap-2">
85
+ {#if icon}
86
+ <Icon {icon} class={iconStyles({ color, size })} />
87
+ {/if}
88
+ <Text color="secondary" {size}>
89
+ {@render children?.()}
90
+ </Text>
91
+ </div>
92
+ {/if}
93
+ </div>
@@ -0,0 +1,14 @@
1
+ import type { IconLike, Size, TextColor } from '../../types.js';
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ type Props = {
5
+ color?: TextColor;
6
+ size?: Size;
7
+ icon?: IconLike | false;
8
+ center?: boolean;
9
+ children?: Snippet;
10
+ content?: Snippet;
11
+ } & HTMLAttributes<HTMLElement>;
12
+ declare const AnnouncementBanner: import("svelte").Component<Props, {}, "">;
13
+ type AnnouncementBanner = ReturnType<typeof AnnouncementBanner>;
14
+ export default AnnouncementBanner;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import Scrollable from '../Scrollable/Scrollable.svelte';
3
- import { ChildKey } from '../../constants.js';
3
+ import { ChildKey, zIndex } from '../../constants.js';
4
4
  import Child from '../../internal/Child.svelte';
5
5
  import { cleanClass } from '../../utilities/internal.js';
6
6
  import { type Snippet } from 'svelte';
@@ -18,7 +18,7 @@
18
18
  <Scrollable
19
19
  class={cleanClass(
20
20
  'bg-light text-dark absolute shrink-0 border-e shadow-lg transition-all duration-200 md:relative',
21
- open ? 'w-[min(100vw,16rem)]' : 'w-[0px]',
21
+ open ? `${zIndex.AppShellSidebar} w-[min(100vw,16rem)]` : 'w-[0px] border-e-0',
22
22
  className,
23
23
  )}
24
24
  >
@@ -1,12 +1,21 @@
1
1
  <script lang="ts">
2
- import { styles } from '../../styles.js';
2
+ import { styleVariants } from '../../styles.js';
3
3
  import type { LabelProps } from '../../types.js';
4
4
  import { cleanClass } from '../../utilities/internal.js';
5
+ import { tv } from 'tailwind-variants';
5
6
 
6
7
  const { label, size, color, class: className, children, ...restProps }: LabelProps = $props();
8
+
9
+ const styles = tv({
10
+ base: '',
11
+ variants: {
12
+ size: styleVariants.textSize,
13
+ color: styleVariants.textColor,
14
+ },
15
+ });
7
16
  </script>
8
17
 
9
- <label class={cleanClass(styles.label({ size, color }), className)} {...restProps}>
18
+ <label class={cleanClass(styles({ size, color }), className)} {...restProps}>
10
19
  {#if label}{label}{/if}
11
20
  {@render children?.()}
12
21
  </label>
@@ -8,7 +8,7 @@
8
8
  import CloseButton from '../CloseButton/CloseButton.svelte';
9
9
  import Icon from '../Icon/Icon.svelte';
10
10
  import Logo from '../Logo/Logo.svelte';
11
- import { ChildKey } from '../../constants.js';
11
+ import { ChildKey, zIndex } from '../../constants.js';
12
12
  import type { ModalSize } from '../../types.js';
13
13
  import { cleanClass } from '../../utilities/internal.js';
14
14
  import { Dialog } from 'bits-ui';
@@ -41,7 +41,7 @@
41
41
  }: Props = $props();
42
42
 
43
43
  const modalStyles = tv({
44
- base: 'bg-light dark:bg-subtle border-subtle shadow-primary/20 flex rounded-none border shadow-sm sm:rounded-2xl dark:border-white/10',
44
+ base: `bg-light dark:bg-subtle border-subtle shadow-primary/20 flex rounded-none border shadow-sm sm:rounded-2xl dark:border-white/10`,
45
45
  variants: {
46
46
  size: {
47
47
  tiny: 'h-full sm:h-min md:max-w-sm',
@@ -55,7 +55,7 @@
55
55
  });
56
56
 
57
57
  const modalContentStyles = tv({
58
- base: 'fixed inset-0 m-auto flex max-h-dvh grow sm:p-4',
58
+ base: `${zIndex.ModalContent} fixed inset-0 m-auto flex max-h-dvh grow sm:p-4`,
59
59
  variants: {
60
60
  size: {
61
61
  tiny: 'sm:h-min md:max-w-sm',
@@ -89,7 +89,7 @@
89
89
 
90
90
  <Dialog.Root open={true} onOpenChange={(isOpen: boolean) => !isOpen && handleClose()}>
91
91
  <Dialog.Portal>
92
- <Dialog.Overlay class="fixed start-0 top-0 flex h-dvh max-h-dvh w-screen bg-black/30" />
92
+ <Dialog.Overlay class="{zIndex.ModalBackdrop} fixed start-0 top-0 flex h-dvh max-h-dvh w-screen bg-black/30" />
93
93
  <Dialog.Content
94
94
  {onEscapeKeydown}
95
95
  {escapeKeydownBehavior}
@@ -13,3 +13,8 @@ export declare enum ChildKey {
13
13
  ModalBody = "modal-body",
14
14
  ModalFooter = "modal-footer"
15
15
  }
16
+ export declare const zIndex: {
17
+ AppShellSidebar: string;
18
+ ModalBackdrop: string;
19
+ ModalContent: string;
20
+ };
package/dist/constants.js CHANGED
@@ -14,3 +14,8 @@ export var ChildKey;
14
14
  ChildKey["ModalBody"] = "modal-body";
15
15
  ChildKey["ModalFooter"] = "modal-footer";
16
16
  })(ChildKey || (ChildKey = {}));
17
+ export const zIndex = {
18
+ AppShellSidebar: 'z-30',
19
+ ModalBackdrop: 'z-40',
20
+ ModalContent: 'z-50',
21
+ };
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export { default as immichLogo } from './assets/immich-logo.svg';
11
11
  export { default as obtainiumBadge } from './assets/obtainium-badge.png';
12
12
  export { default as playStoreBadge } from './assets/playstore-badge.png';
13
13
  export { default as Alert } from './components/Alert/Alert.svelte';
14
+ export { default as AnnouncementBanner } from './components/AnnouncementBanner/AnnouncementBanner.svelte';
14
15
  export { default as AppShell } from './components/AppShell/AppShell.svelte';
15
16
  export { default as AppShellHeader } from './components/AppShell/AppShellHeader.svelte';
16
17
  export { default as AppShellSidebar } from './components/AppShell/AppShellSidebar.svelte';
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ export { default as obtainiumBadge } from './assets/obtainium-badge.png';
13
13
  export { default as playStoreBadge } from './assets/playstore-badge.png';
14
14
  // components
15
15
  export { default as Alert } from './components/Alert/Alert.svelte';
16
+ export { default as AnnouncementBanner } from './components/AnnouncementBanner/AnnouncementBanner.svelte';
16
17
  export { default as AppShell } from './components/AppShell/AppShell.svelte';
17
18
  export { default as AppShellHeader } from './components/AppShell/AppShellHeader.svelte';
18
19
  export { default as AppShellSidebar } from './components/AppShell/AppShellSidebar.svelte';
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import Icon from '../components/Icon/Icon.svelte';
3
3
  import LoadingSpinner from '../components/LoadingSpinner/LoadingSpinner.svelte';
4
+ import { styleVariants } from '../styles.js';
4
5
  import type { ButtonProps, Size } from '../types.js';
5
6
  import { isExternalLink, resolveUrl } from '../utilities/common.js';
6
7
  import { cleanClass } from '../utilities/internal.js';
@@ -56,13 +57,7 @@
56
57
  large: 'px-8 py-2.5',
57
58
  giant: 'px-10 py-3',
58
59
  },
59
- textSize: {
60
- tiny: 'text-xs',
61
- small: 'text-sm',
62
- medium: 'text-base',
63
- large: 'text-lg',
64
- giant: 'text-xl',
65
- },
60
+ textSize: styleVariants.textSize,
66
61
  iconSize: {
67
62
  tiny: 'h-6 w-6',
68
63
  small: 'h-8 w-8',
@@ -1,70 +1,87 @@
1
1
  <script lang="ts">
2
2
  import Heading from '../components/Heading/Heading.svelte';
3
+ import IconButton from '../components/IconButton/IconButton.svelte';
4
+ import HStack from '../components/Stack/HStack.svelte';
3
5
  import Stack from '../components/Stack/Stack.svelte';
4
- import VStack from '../components/Stack/VStack.svelte';
5
- import Text from '../components/Text/Text.svelte';
6
- import ThemeSwitcher from '../components/ThemeSwitcher/ThemeSwitcher.svelte';
7
6
  import { Constants } from './constants.js';
8
7
  import SiteFooterLink from './SiteFooterLink.svelte';
9
- import {
10
- mdiBookshelf,
11
- mdiChartGantt,
12
- mdiCubeOutline,
13
- mdiHomeSearchOutline,
14
- mdiKey,
15
- mdiOfficeBuildingOutline,
16
- mdiScriptTextOutline,
17
- mdiServerOutline,
18
- mdiShieldAccountOutline,
19
- mdiShoppingOutline,
20
- } from '@mdi/js';
21
- import { siAndroid, siApple, siDiscord, siGithub, siReddit } from 'simple-icons';
8
+ import { siDiscord, siGithub, siReddit, siRss, siWeblate, siX, siYoutube } from 'simple-icons';
22
9
  </script>
23
10
 
24
- <div class="mt-16 rounded-t-3xl bg-gray-100 p-8 dark:bg-neutral-900">
25
- <div class="mx-auto max-w-(--breakpoint-lg) xl:py-8">
11
+ <div class="mt-16 rounded-t-md bg-gray-50 p-8 lg:p-4 lg:py-8 dark:bg-neutral-900">
12
+ <div class="mx-auto max-w-(--breakpoint-lg)">
26
13
  <Stack gap={8}>
27
- <div class="place-center grid grid-cols-2 gap-8 md:grid-cols-3 lg:grid-cols-5">
14
+ <div class="place-center grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-4">
28
15
  <Stack>
29
- <Heading size="tiny">Social</Heading>
30
- <SiteFooterLink href={Constants.Socials.Github} icon={siGithub} text="GitHub" />
31
- <SiteFooterLink href={Constants.Socials.Discord} icon={siDiscord} text="Discord" />
32
- <SiteFooterLink href={Constants.Socials.Reddit} icon={siReddit} text="Reddit" />
16
+ <Heading size="small" class="mb-2">Download</Heading>
17
+ <SiteFooterLink href={Constants.Get.Android} text="Android" />
18
+ <SiteFooterLink href={Constants.Get.iOS} text="iOS" />
19
+ <SiteFooterLink href={Constants.Get.Download} text="Server" />
33
20
  </Stack>
34
21
 
35
22
  <Stack>
36
- <Heading size="tiny">Download</Heading>
37
- <SiteFooterLink href={Constants.Get.Android} icon={siAndroid} text="Android" />
38
- <SiteFooterLink href={Constants.Get.iOS} icon={siApple} text="iOS" />
39
- <SiteFooterLink href={Constants.Get.Download} icon={mdiServerOutline} text="Server" />
23
+ <Heading size="small" class="mb-2">Company</Heading>
24
+ <SiteFooterLink href={Constants.Socials.Futo} text="FUTO" />
25
+ <SiteFooterLink href={Constants.Sites.Buy} text="Purchase" />
26
+ <SiteFooterLink href={Constants.Sites.Store} text="Merch" />
40
27
  </Stack>
41
28
 
42
29
  <Stack>
43
- <Heading size="tiny">Company</Heading>
44
- <SiteFooterLink href={Constants.Socials.Futo} icon={mdiOfficeBuildingOutline} text="FUTO" />
45
- <SiteFooterLink href={Constants.Sites.Buy} icon={mdiKey} text="Purchase" />
46
- <SiteFooterLink href={Constants.Sites.Store} icon={mdiShoppingOutline} text="Merch" />
30
+ <Heading size="small" class="mb-2">Sites</Heading>
31
+ <SiteFooterLink href={Constants.Sites.Docs} text="Documentation" />
32
+ <SiteFooterLink href={Constants.Sites.My} text="My Immich" />
33
+ <SiteFooterLink href={Constants.Sites.Api} text="Immich API" />
47
34
  </Stack>
48
35
 
49
36
  <Stack>
50
- <Heading size="tiny">Sites</Heading>
51
- <SiteFooterLink href={Constants.Sites.Docs} icon={mdiScriptTextOutline} text="Documentation" />
52
- <SiteFooterLink href={Constants.Sites.My} icon={mdiHomeSearchOutline} text="My Immich" />
53
- <SiteFooterLink href={Constants.Sites.Api} icon={mdiCubeOutline} text="Immich API" />
54
- </Stack>
55
-
56
- <Stack>
57
- <Heading size="tiny">Miscellaneous</Heading>
58
- <SiteFooterLink href={Constants.Pages.Roadmap} icon={mdiChartGantt} text="Roadmap" />
59
- <SiteFooterLink href={Constants.Pages.CursedKnowledge} icon={mdiBookshelf} text="Cursed Knowledge" />
60
- <SiteFooterLink href={Constants.Pages.PrivacyPolicy} icon={mdiShieldAccountOutline} text="Privacy Policy" />
37
+ <Heading size="small" class="mb-2">Miscellaneous</Heading>
38
+ <SiteFooterLink href={Constants.Pages.Roadmap} text="Roadmap" />
39
+ <SiteFooterLink href={Constants.Pages.CursedKnowledge} text="Cursed Knowledge" />
40
+ <SiteFooterLink href={Constants.Pages.PrivacyPolicy} text="Privacy Policy" />
61
41
  </Stack>
62
42
  </div>
63
- <VStack class="text-center">
64
- <Text size="large">This project is available under GNU AGPL v3 license.</Text>
65
- <Text color="muted" variant="italic">Privacy should not be a luxury</Text>
66
- <ThemeSwitcher color="secondary" />
67
- </VStack>
43
+
44
+ <hr />
45
+
46
+ <HStack>
47
+ <IconButton
48
+ href={Constants.Socials.Github}
49
+ icon={siGithub}
50
+ aria-label="GitHub"
51
+ variant="ghost"
52
+ color="secondary"
53
+ />
54
+ <IconButton
55
+ href={Constants.Socials.Discord}
56
+ icon={siDiscord}
57
+ aria-label="Discord"
58
+ variant="ghost"
59
+ color="secondary"
60
+ />
61
+ <IconButton
62
+ href={Constants.Socials.Reddit}
63
+ icon={siReddit}
64
+ aria-label="reddit"
65
+ variant="ghost"
66
+ color="secondary"
67
+ />
68
+ <IconButton href={Constants.Socials.X} icon={siX} aria-label="X" variant="ghost" color="secondary" />
69
+ <IconButton
70
+ href={Constants.Socials.YouTube}
71
+ icon={siYoutube}
72
+ aria-label="YouTube"
73
+ variant="ghost"
74
+ color="secondary"
75
+ />
76
+ <IconButton
77
+ href={Constants.Socials.Weblate}
78
+ icon={siWeblate}
79
+ aria-label="Weblate"
80
+ variant="ghost"
81
+ color="secondary"
82
+ />
83
+ <IconButton href={Constants.Socials.Rss} icon={siRss} aria-label="RSS" variant="ghost" color="secondary" />
84
+ </HStack>
68
85
  </Stack>
69
86
  </div>
70
87
  </div>
@@ -1,21 +1,15 @@
1
1
  <script lang="ts">
2
- import HStack from '../components/Stack/HStack.svelte';
3
- import Icon from '../components/Icon/Icon.svelte';
4
2
  import Link from '../components/Link/Link.svelte';
5
3
  import Text from '../components/Text/Text.svelte';
6
4
 
7
5
  type Props = {
8
6
  href: string;
9
- icon: string | { path: string };
10
7
  text: string;
11
8
  };
12
9
 
13
- let { href, icon, text }: Props = $props();
10
+ let { href, text }: Props = $props();
14
11
  </script>
15
12
 
16
- <Link {href}>
17
- <HStack>
18
- <Icon {icon} size="1.5em" />
19
- <Text>{text}</Text>
20
- </HStack>
13
+ <Link {href} underline={false} class="text-dark/90 hover:text-primary transition-colors">
14
+ <Text>{text}</Text>
21
15
  </Link>
@@ -1,8 +1,5 @@
1
1
  type Props = {
2
2
  href: string;
3
- icon: string | {
4
- path: string;
5
- };
6
3
  text: string;
7
4
  };
8
5
  declare const SiteFooterLink: import("svelte").Component<Props, {}, "">;
@@ -4,7 +4,10 @@ export declare const Constants: {
4
4
  Github: string;
5
5
  Discord: string;
6
6
  Reddit: string;
7
+ Rss: string;
7
8
  Weblate: string;
9
+ X: string;
10
+ YouTube: string;
8
11
  };
9
12
  Get: {
10
13
  iOS: string;
@@ -6,7 +6,10 @@ export const Constants = {
6
6
  Github: 'https://github.com/immich-app/immich',
7
7
  Discord: 'https://discord.immich.app/',
8
8
  Reddit: 'https://www.reddit.com/r/immich/',
9
+ Rss: 'https://immich.app/blog/feed.xml',
9
10
  Weblate: 'https://hosted.weblate.org/projects/immich/immich/',
11
+ X: 'https://x.com/immichapp',
12
+ YouTube: 'https://www.youtube.com/@immich-app',
10
13
  },
11
14
  Get: {
12
15
  iOS: 'https://get.immich.app/ios',
package/dist/styles.d.ts CHANGED
@@ -1,54 +1,26 @@
1
- export declare const styles: {
2
- label: import("tailwind-variants").TVReturnType<{
3
- size: {
4
- tiny: string;
5
- small: string;
6
- medium: string;
7
- large: string;
8
- giant: string;
9
- };
10
- color: {
11
- muted: string;
12
- primary: string;
13
- secondary: string;
14
- success: string;
15
- danger: string;
16
- warning: string;
17
- info: string;
18
- };
19
- }, undefined, "", {
20
- size: {
21
- tiny: string;
22
- small: string;
23
- medium: string;
24
- large: string;
25
- giant: string;
26
- };
27
- color: {
28
- muted: string;
29
- primary: string;
30
- secondary: string;
31
- success: string;
32
- danger: string;
33
- warning: string;
34
- info: string;
35
- };
36
- }, undefined, import("tailwind-variants").TVReturnType<{
37
- size: {
38
- tiny: string;
39
- small: string;
40
- medium: string;
41
- large: string;
42
- giant: string;
43
- };
44
- color: {
45
- muted: string;
46
- primary: string;
47
- secondary: string;
48
- success: string;
49
- danger: string;
50
- warning: string;
51
- info: string;
52
- };
53
- }, undefined, "", unknown, unknown, undefined>>;
1
+ export declare const styleVariants: {
2
+ color: {
3
+ primary: string;
4
+ secondary: string;
5
+ success: string;
6
+ danger: string;
7
+ warning: string;
8
+ info: string;
9
+ };
10
+ textColor: {
11
+ muted: string;
12
+ primary: string;
13
+ secondary: string;
14
+ success: string;
15
+ danger: string;
16
+ warning: string;
17
+ info: string;
18
+ };
19
+ textSize: {
20
+ tiny: string;
21
+ small: string;
22
+ medium: string;
23
+ large: string;
24
+ giant: string;
25
+ };
54
26
  };
package/dist/styles.js CHANGED
@@ -1,24 +1,22 @@
1
- import { tv } from 'tailwind-variants';
2
- export const styles = {
3
- label: tv({
4
- base: '',
5
- variants: {
6
- size: {
7
- tiny: 'text-xs',
8
- small: 'text-sm',
9
- medium: 'text-base',
10
- large: 'text-lg',
11
- giant: 'text-xl',
12
- },
13
- color: {
14
- muted: 'text-gray-600 dark:text-gray-400',
15
- primary: 'text-primary',
16
- secondary: 'text-dark',
17
- success: 'text-success',
18
- danger: 'text-danger',
19
- warning: 'text-warning',
20
- info: 'text-info',
21
- },
22
- },
23
- }),
1
+ const color = {
2
+ primary: 'text-primary',
3
+ secondary: 'text-dark',
4
+ success: 'text-success',
5
+ danger: 'text-danger',
6
+ warning: 'text-warning',
7
+ info: 'text-info',
8
+ };
9
+ export const styleVariants = {
10
+ color,
11
+ textColor: {
12
+ ...color,
13
+ muted: 'text-gray-600 dark:text-gray-400',
14
+ },
15
+ textSize: {
16
+ tiny: 'text-xs',
17
+ small: 'text-sm',
18
+ medium: 'text-base',
19
+ large: 'text-lg',
20
+ giant: 'text-xl',
21
+ },
24
22
  };
package/dist/types.d.ts CHANGED
@@ -64,7 +64,7 @@ export type CloseButtonProps = {
64
64
  translations?: TranslationProps<'close'>;
65
65
  } & ButtonOrAnchor;
66
66
  export type IconButtonProps = ButtonBase & {
67
- icon: string;
67
+ icon: IconLike;
68
68
  flipped?: boolean;
69
69
  flopped?: boolean;
70
70
  'aria-label': string;
@@ -1,5 +1,11 @@
1
- import type { IconLike } from '../types.js';
1
+ import type { Color, IconLike, TextColor } from '../types.js';
2
2
  export declare const cleanClass: (...classNames: unknown[]) => string;
3
3
  export declare const withPrefix: (key: string) => string;
4
4
  export declare const generateId: () => string;
5
5
  export declare const isIconLike: (icon: unknown) => icon is IconLike;
6
+ export declare const resolveIcon: ({ icons, color, override, fallback, }: {
7
+ color: Color | TextColor;
8
+ fallback: IconLike;
9
+ override?: IconLike | false;
10
+ icons: Partial<Record<Color | TextColor, string>>;
11
+ }) => IconLike | undefined;
@@ -15,3 +15,12 @@ export const generateId = () => `ui-id-${_count++}`;
15
15
  export const isIconLike = (icon) => {
16
16
  return typeof icon === 'string' || !!(icon && typeof icon === 'object' && 'path' in icon);
17
17
  };
18
+ export const resolveIcon = ({ icons, color, override, fallback, }) => {
19
+ if (override) {
20
+ return override;
21
+ }
22
+ if (override === false) {
23
+ return;
24
+ }
25
+ return icons[color] ?? fallback;
26
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immich/ui",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "license": "GNU Affero General Public License version 3",
5
5
  "scripts": {
6
6
  "create": "node scripts/create.js",