@immich/ui 0.59.0 → 0.60.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.
Files changed (32) hide show
  1. package/dist/common/use-child.svelte.d.ts +1 -1
  2. package/dist/common/use-child.svelte.js +2 -0
  3. package/dist/components/ActionBar/ActionBar.svelte +22 -0
  4. package/dist/components/ActionBar/ActionBar.svelte.d.ts +4 -0
  5. package/dist/components/ActionButton/ActionButton.svelte +33 -0
  6. package/dist/components/ActionButton/ActionButton.svelte.d.ts +15 -0
  7. package/dist/components/AppShell/AppShell.svelte +10 -5
  8. package/dist/components/AppShell/AppShellBar.svelte +16 -0
  9. package/dist/components/AppShell/AppShellBar.svelte.d.ts +8 -0
  10. package/dist/components/ContextMenu/ContextMenuButton.svelte +11 -9
  11. package/dist/components/ControlBar/ControlBar.svelte +92 -0
  12. package/dist/components/ControlBar/ControlBar.svelte.d.ts +4 -0
  13. package/dist/components/ControlBar/ControlBarContent.svelte +16 -0
  14. package/dist/components/ControlBar/ControlBarContent.svelte.d.ts +8 -0
  15. package/dist/components/ControlBar/ControlBarDescription.svelte +15 -0
  16. package/dist/components/ControlBar/ControlBarDescription.svelte.d.ts +8 -0
  17. package/dist/components/ControlBar/ControlBarHeader.svelte +16 -0
  18. package/dist/components/ControlBar/ControlBarHeader.svelte.d.ts +8 -0
  19. package/dist/components/ControlBar/ControlBarOverflow.svelte +16 -0
  20. package/dist/components/ControlBar/ControlBarOverflow.svelte.d.ts +8 -0
  21. package/dist/components/ControlBar/ControlBarTitle.svelte +23 -0
  22. package/dist/components/ControlBar/ControlBarTitle.svelte.d.ts +16 -0
  23. package/dist/components/ProgressBar/ProgressBar.svelte +31 -9
  24. package/dist/components/ProgressBar/ProgressBar.svelte.d.ts +1 -0
  25. package/dist/constants.d.ts +6 -0
  26. package/dist/constants.js +6 -0
  27. package/dist/index.d.ts +9 -0
  28. package/dist/index.js +9 -0
  29. package/dist/internal/Child.svelte +6 -5
  30. package/dist/theme/default.css +5 -0
  31. package/dist/types.d.ts +20 -0
  32. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import { ChildKey } from '../constants.js';
2
- import type { ChildData } from '../types.js';
2
+ import { type ChildData } from '../types.js';
3
3
  export declare const withChildrenSnippets: (key: ChildKey) => {
4
4
  getChildren: <T>(key: ChildKey) => ChildData<T> | undefined;
5
5
  };
@@ -1,4 +1,5 @@
1
1
  import { ChildKey } from '../constants.js';
2
+ import {} from '../types.js';
2
3
  import { withPrefix } from '../utilities/internal.js';
3
4
  import { setContext } from 'svelte';
4
5
  import { SvelteMap } from 'svelte/reactivity';
@@ -6,6 +7,7 @@ export const withChildrenSnippets = (key) => {
6
7
  const map = new SvelteMap();
7
8
  setContext(withPrefix(key), {
8
9
  register: (child, data) => map.set(child, data),
10
+ unregister: (child) => map.delete(child),
9
11
  });
10
12
  return {
11
13
  getChildren: (key) => map.get(key)?.(),
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import ActionButton from '../ActionButton/ActionButton.svelte';
3
+ import ContextMenuButton from '../ContextMenu/ContextMenuButton.svelte';
4
+ import ControlBar from '../ControlBar/ControlBar.svelte';
5
+ import ControlBarOverflow from '../ControlBar/ControlBarOverflow.svelte';
6
+ import type { ActionBarProps } from '../../types.js';
7
+ import { isEnabled } from '../../utilities/common.js';
8
+
9
+ const { actions, overflowActions = [], children, ...restProps }: ActionBarProps = $props();
10
+
11
+ const items = $derived(overflowActions.filter((action) => isEnabled(action)));
12
+ </script>
13
+
14
+ <ControlBar {...restProps}>
15
+ {@render children?.()}
16
+ <ControlBarOverflow>
17
+ {#each actions as action, i (i)}
18
+ <ActionButton {action} />
19
+ {/each}
20
+ <ContextMenuButton {items} />
21
+ </ControlBarOverflow>
22
+ </ControlBar>
@@ -0,0 +1,4 @@
1
+ import type { ActionBarProps } from '../../types.js';
2
+ declare const ActionBar: import("svelte").Component<ActionBarProps, {}, "">;
3
+ type ActionBar = ReturnType<typeof ActionBar>;
4
+ export default ActionBar;
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ import Button from '../Button/Button.svelte';
3
+ import IconButton from '../IconButton/IconButton.svelte';
4
+ import type { ActionItem, Color, Size, Variants } from '../../types.js';
5
+ import { isEnabled } from '../../utilities/common.js';
6
+ import { mdiPlus } from '@mdi/js';
7
+
8
+ type Props = {
9
+ action: ActionItem & { data?: { title?: string } };
10
+ color?: Color;
11
+ size?: Size;
12
+ variant?: Variants;
13
+ type?: 'icon' | 'button';
14
+ };
15
+
16
+ const { action, type = 'icon', size, color: colorOverride, variant: variantOverride }: Props = $props();
17
+ const { title, icon, onAction } = $derived(action);
18
+ const common = $derived({
19
+ variant: variantOverride ?? 'ghost',
20
+ color: colorOverride ?? action.color ?? 'secondary',
21
+ onclick: () => onAction(action),
22
+ });
23
+ </script>
24
+
25
+ {#if isEnabled(action)}
26
+ {#if type === 'icon'}
27
+ <IconButton {...common} {size} shape="round" icon={icon ?? mdiPlus} aria-label={title} />
28
+ {:else if type === 'button'}
29
+ <Button {...common} size={size ?? 'small'} leadingIcon={icon} title={action.data?.title}>
30
+ {title}
31
+ </Button>
32
+ {/if}
33
+ {/if}
@@ -0,0 +1,15 @@
1
+ import type { ActionItem, Color, Size, Variants } from '../../types.js';
2
+ type Props = {
3
+ action: ActionItem & {
4
+ data?: {
5
+ title?: string;
6
+ };
7
+ };
8
+ color?: Color;
9
+ size?: Size;
10
+ variant?: Variants;
11
+ type?: 'icon' | 'button';
12
+ };
13
+ declare const ActionButton: import("svelte").Component<Props, {}, "">;
14
+ type ActionButton = ReturnType<typeof ActionButton>;
15
+ export default ActionButton;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { withChildrenSnippets } from '../../common/use-child.svelte.js';
3
3
  import Scrollable from '../Scrollable/Scrollable.svelte';
4
- import { ChildKey } from '../../constants.js';
4
+ import { ChildKey, zIndex } from '../../constants.js';
5
5
  import { cleanClass } from '../../utilities/internal.js';
6
6
  import type { Snippet } from 'svelte';
7
7
 
@@ -13,19 +13,24 @@
13
13
  const { class: className, children }: Props = $props();
14
14
 
15
15
  const { getChildren: getChildSnippet } = withChildrenSnippets(ChildKey.AppShell);
16
+ const bar = $derived(getChildSnippet(ChildKey.AppShellBar));
16
17
  const header = $derived(getChildSnippet(ChildKey.AppShellHeader));
17
18
  const sidebar = $derived(getChildSnippet(ChildKey.AppShellSidebar));
18
19
  </script>
19
20
 
20
21
  <div class={cleanClass('flex h-dvh flex-col overflow-hidden', className)}>
21
- {#if header}
22
- <header class="border-b">
23
- {@render header?.snippet()}
22
+ {#if bar}
23
+ <div class={cleanClass('h-control-bar-container px-2 pt-2', zIndex.AppShellBar, bar.class)}>
24
+ {@render bar.snippet()}
25
+ </div>
26
+ {:else if header}
27
+ <header class={cleanClass('h-control-bar-container flex items-center gap-2 border-b', header.class)}>
28
+ {@render header.snippet()}
24
29
  </header>
25
30
  {/if}
26
31
  <div class="relative flex w-full grow overflow-y-auto">
27
32
  {#if sidebar}
28
- {@render sidebar?.snippet()}
33
+ {@render sidebar.snippet()}
29
34
  {/if}
30
35
  <Scrollable class="grow" resetOnNavigate>
31
36
  {@render children?.()}
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { ChildKey } from '../../constants.js';
3
+ import Child from '../../internal/Child.svelte';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ type Props = {
7
+ children: Snippet;
8
+ class?: string;
9
+ };
10
+
11
+ let { children, class: className }: Props = $props();
12
+ </script>
13
+
14
+ <Child for={ChildKey.AppShell} as={ChildKey.AppShellBar} class={className}>
15
+ {@render children?.()}
16
+ </Child>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ children: Snippet;
4
+ class?: string;
5
+ };
6
+ declare const AppShellBar: import("svelte").Component<Props, {}, "">;
7
+ type AppShellBar = ReturnType<typeof AppShellBar>;
8
+ export default AppShellBar;
@@ -23,12 +23,14 @@
23
23
  };
24
24
  </script>
25
25
 
26
- <IconButton
27
- {icon}
28
- {color}
29
- {shape}
30
- {variant}
31
- aria-label={ariaLabel ?? t('open_menu', translations)}
32
- {...rest}
33
- {onclick}
34
- />
26
+ {#if items.length > 0}
27
+ <IconButton
28
+ {icon}
29
+ {color}
30
+ {shape}
31
+ {variant}
32
+ aria-label={ariaLabel ?? t('open_menu', translations)}
33
+ {...rest}
34
+ {onclick}
35
+ />
36
+ {/if}
@@ -0,0 +1,92 @@
1
+ <script lang="ts">
2
+ import { shortcuts } from '../../actions/shortcut.js';
3
+ import { withChildrenSnippets } from '../../common/use-child.svelte.js';
4
+ import IconButton from '../IconButton/IconButton.svelte';
5
+ import { ChildKey } from '../../constants.js';
6
+ import { t } from '../../services/translation.svelte.js';
7
+ import type { ControlBarProps } from '../../types.js';
8
+ import { cleanClass } from '../../utilities/internal.js';
9
+ import { mdiClose } from '@mdi/js';
10
+ import { fly } from 'svelte/transition';
11
+ import { tv } from 'tailwind-variants';
12
+
13
+ let {
14
+ ref = $bindable(null),
15
+ closeIcon,
16
+ class: className,
17
+ shape = 'semi-round',
18
+ variant = 'ghost',
19
+ closeOnEsc = true,
20
+ static: isStatic = false,
21
+ translations,
22
+ onClose,
23
+ children,
24
+ ...restProps
25
+ }: ControlBarProps = $props();
26
+
27
+ const styles = tv({
28
+ base: `h-control-bar flex w-full items-center gap-2 px-2`,
29
+ variants: {
30
+ variant: {
31
+ filled: 'dark:bg-subtle bg-white shadow-lg',
32
+ outline: 'dark:border-light-200 border-light-200 border shadow-md',
33
+ ghost: '',
34
+ },
35
+ shape: {
36
+ 'semi-round': 'rounded-lg',
37
+ rectangle: 'rounded-none',
38
+ },
39
+ },
40
+ });
41
+
42
+ const onEscape = () => {
43
+ if (closeOnEsc) {
44
+ onClose?.();
45
+ }
46
+ };
47
+
48
+ const { getChildren: getChildSnippet } = withChildrenSnippets(ChildKey.ControlBar);
49
+ const headerChild = $derived(getChildSnippet(ChildKey.ControlBarHeader));
50
+ const contentChild = $derived(getChildSnippet(ChildKey.ControlBarContent));
51
+ const overflowChild = $derived(getChildSnippet(ChildKey.ControlBarOverflow));
52
+ </script>
53
+
54
+ <svelte:window use:shortcuts={[{ shortcut: { key: 'Escape' }, onShortcut: onEscape }]} />
55
+
56
+ <nav
57
+ bind:this={ref}
58
+ in:fly={{ y: 10, duration: isStatic ? 0 : 200 }}
59
+ class={cleanClass(styles({ shape, variant }), className)}
60
+ {...restProps}
61
+ >
62
+ <div class={cleanClass('flex shrink-0 items-center gap-2')}>
63
+ {#if typeof closeIcon === 'function'}
64
+ {@render closeIcon?.()}
65
+ {:else if onClose}
66
+ <IconButton
67
+ icon={closeIcon ?? mdiClose}
68
+ shape="round"
69
+ variant="ghost"
70
+ color="secondary"
71
+ aria-label={t('close', translations)}
72
+ onclick={() => onClose()}
73
+ />
74
+ {/if}
75
+
76
+ <div class={cleanClass('flex shrink-0 flex-col')}>
77
+ {@render headerChild?.snippet()}
78
+ </div>
79
+ </div>
80
+
81
+ <div class={cleanClass('flex grow items-center gap-2', contentChild?.class)}>
82
+ {@render contentChild?.snippet()}
83
+ </div>
84
+
85
+ {#if overflowChild}
86
+ <div class={cleanClass('flex shrink-0 items-center gap-2', overflowChild.class)}>
87
+ {@render overflowChild.snippet()}
88
+ </div>
89
+ {/if}
90
+
91
+ {@render children?.()}
92
+ </nav>
@@ -0,0 +1,4 @@
1
+ import type { ControlBarProps } from '../../types.js';
2
+ declare const ControlBar: import("svelte").Component<ControlBarProps, {}, "ref">;
3
+ type ControlBar = ReturnType<typeof ControlBar>;
4
+ export default ControlBar;
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { ChildKey } from '../../constants.js';
3
+ import Child from '../../internal/Child.svelte';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ type Props = {
7
+ class?: string;
8
+ children: Snippet;
9
+ };
10
+
11
+ let { class: className, children }: Props = $props();
12
+ </script>
13
+
14
+ <Child for={ChildKey.ControlBar} as={ChildKey.ControlBarContent} class={className}>
15
+ {@render children?.()}
16
+ </Child>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ class?: string;
4
+ children: Snippet;
5
+ };
6
+ declare const ControlBarContent: import("svelte").Component<Props, {}, "">;
7
+ type ControlBarContent = ReturnType<typeof ControlBarContent>;
8
+ export default ControlBarContent;
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import Text from '../Text/Text.svelte';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ type Props = {
6
+ class?: string;
7
+ children: Snippet;
8
+ };
9
+
10
+ let { children, class: className }: Props = $props();
11
+ </script>
12
+
13
+ <Text size="small" color="muted" class={className}>
14
+ {@render children?.()}
15
+ </Text>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ class?: string;
4
+ children: Snippet;
5
+ };
6
+ declare const ControlBarDescription: import("svelte").Component<Props, {}, "">;
7
+ type ControlBarDescription = ReturnType<typeof ControlBarDescription>;
8
+ export default ControlBarDescription;
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { ChildKey } from '../../constants.js';
3
+ import Child from '../../internal/Child.svelte';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ type Props = {
7
+ class?: string;
8
+ children: Snippet;
9
+ };
10
+
11
+ let { class: className, children }: Props = $props();
12
+ </script>
13
+
14
+ <Child for={ChildKey.ControlBar} as={ChildKey.ControlBarHeader} class={className}>
15
+ {@render children?.()}
16
+ </Child>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ class?: string;
4
+ children: Snippet;
5
+ };
6
+ declare const ControlBarHeader: import("svelte").Component<Props, {}, "">;
7
+ type ControlBarHeader = ReturnType<typeof ControlBarHeader>;
8
+ export default ControlBarHeader;
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { ChildKey } from '../../constants.js';
3
+ import Child from '../../internal/Child.svelte';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ type Props = {
7
+ class?: string;
8
+ children: Snippet;
9
+ };
10
+
11
+ let { class: className, children }: Props = $props();
12
+ </script>
13
+
14
+ <Child for={ChildKey.ControlBar} as={ChildKey.ControlBarOverflow} class={className}>
15
+ {@render children?.()}
16
+ </Child>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ class?: string;
4
+ children: Snippet;
5
+ };
6
+ declare const ControlBarOverflow: import("svelte").Component<Props, {}, "">;
7
+ type ControlBarOverflow = ReturnType<typeof ControlBarOverflow>;
8
+ export default ControlBarOverflow;
@@ -0,0 +1,23 @@
1
+ <script lang="ts">
2
+ import Heading from '../Heading/Heading.svelte';
3
+ import type { Color, FontWeight, HeadingSize, HeadingTag } from '../../types.js';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ type Props = {
7
+ /**
8
+ * The HTML element type.
9
+ */
10
+ tag?: HeadingTag;
11
+ class?: string;
12
+ size?: HeadingSize;
13
+ color?: Color;
14
+ fontWeight?: FontWeight;
15
+ children: Snippet;
16
+ };
17
+
18
+ const { size = 'small', fontWeight = 'medium', color = 'primary', tag, class: className, children }: Props = $props();
19
+ </script>
20
+
21
+ <Heading {tag} {size} {color} {fontWeight} class={className}>
22
+ {@render children?.()}
23
+ </Heading>
@@ -0,0 +1,16 @@
1
+ import type { Color, FontWeight, HeadingSize, HeadingTag } from '../../types.js';
2
+ import type { Snippet } from 'svelte';
3
+ type Props = {
4
+ /**
5
+ * The HTML element type.
6
+ */
7
+ tag?: HeadingTag;
8
+ class?: string;
9
+ size?: HeadingSize;
10
+ color?: Color;
11
+ fontWeight?: FontWeight;
12
+ children: Snippet;
13
+ };
14
+ declare const ControlBarTitle: import("svelte").Component<Props, {}, "">;
15
+ type ControlBarTitle = ReturnType<typeof ControlBarTitle>;
16
+ export default ControlBarTitle;
@@ -10,22 +10,31 @@
10
10
  size?: Size;
11
11
  shape?: Shape;
12
12
  color?: Color;
13
+ border?: boolean;
13
14
  class?: string;
14
15
  children?: Snippet;
15
16
  };
16
17
 
17
- let { progress, shape = 'round', size = 'medium', color = 'primary', class: className, children }: Props = $props();
18
+ let {
19
+ progress,
20
+ shape = 'round',
21
+ size = 'medium',
22
+ color = 'primary',
23
+ border = false,
24
+ class: className,
25
+ children,
26
+ }: Props = $props();
18
27
 
19
28
  const containerStyles = tv({
20
- base: 'bg-light-100 dark:bg-light-200 dark:border-light-300 relative w-full overflow-hidden border',
29
+ base: 'bg-light-100 dark:bg-light-200 relative w-full overflow-hidden',
21
30
  variants: {
22
31
  shape: styleVariants.shape,
23
32
  size: {
24
- tiny: 'h-3',
25
- small: 'h-4',
26
- medium: 'h-5',
27
- large: 'h-6',
28
- giant: 'h-12',
33
+ tiny: 'h-2',
34
+ small: 'h-3',
35
+ medium: 'h-4',
36
+ large: 'h-5',
37
+ giant: 'h-7',
29
38
  },
30
39
  roundedSize: {
31
40
  tiny: 'rounded-sm',
@@ -34,6 +43,9 @@
34
43
  large: 'rounded-lg',
35
44
  giant: 'rounded-xl',
36
45
  },
46
+ border: {
47
+ true: 'dark:border-light-300 border',
48
+ },
37
49
  },
38
50
  });
39
51
 
@@ -42,18 +54,28 @@
42
54
  variants: {
43
55
  color: styleVariants.filledColor,
44
56
  shape: styleVariants.shape,
57
+ size: {
58
+ tiny: 'min-w-2',
59
+ small: 'min-w-3',
60
+ medium: 'min-w-4',
61
+ large: 'min-w-5',
62
+ giant: 'min-w-7',
63
+ },
45
64
  },
46
65
  });
47
66
  </script>
48
67
 
49
68
  <div
50
69
  class={cleanClass(
51
- containerStyles({ size, shape, roundedSize: shape === 'semi-round' ? size : undefined }),
70
+ containerStyles({ size, shape, roundedSize: shape === 'semi-round' ? size : undefined, border }),
52
71
  className,
53
72
  )}
54
73
  >
55
74
  <div class="absolute flex h-full w-full items-center justify-center">
56
75
  {@render children?.()}
57
76
  </div>
58
- <div class={cleanClass(barStyles({ color, shape }))} style="width: {progress * 100}%"></div>
77
+ <div
78
+ class={cleanClass(barStyles({ size: progress > 0 ? size : undefined, color, shape }))}
79
+ style="width: {progress * 100}%"
80
+ ></div>
59
81
  </div>
@@ -5,6 +5,7 @@ type Props = {
5
5
  size?: Size;
6
6
  shape?: Shape;
7
7
  color?: Color;
8
+ border?: boolean;
8
9
  class?: string;
9
10
  children?: Snippet;
10
11
  };
@@ -3,11 +3,16 @@ export declare enum ChildKey {
3
3
  HelperText = "helped-text",
4
4
  AppShell = "app-shell",
5
5
  AppShellHeader = "app-shell-header",
6
+ AppShellBar = "app-shell-bar",
6
7
  AppShellSidebar = "app-shell-sidebar",
7
8
  Card = "card",
8
9
  CardHeader = "card-header",
9
10
  CardBody = "card-body",
10
11
  CardFooter = "card-footer",
12
+ ControlBar = "control-bar",
13
+ ControlBarHeader = "control-bar-header",
14
+ ControlBarContent = "control-bar-content",
15
+ ControlBarOverflow = "control-bar-overflow",
11
16
  Modal = "modal",
12
17
  ModalHeader = "modal-header",
13
18
  ModalBody = "modal-body",
@@ -20,6 +25,7 @@ export declare enum ChildKey {
20
25
  export declare const zIndex: {
21
26
  CarouselImage: string;
22
27
  AppShellSidebar: string;
28
+ AppShellBar: string;
23
29
  ModalBackdrop: string;
24
30
  ModalContent: string;
25
31
  SelectDropdown: string;
package/dist/constants.js CHANGED
@@ -4,11 +4,16 @@ export var ChildKey;
4
4
  ChildKey["HelperText"] = "helped-text";
5
5
  ChildKey["AppShell"] = "app-shell";
6
6
  ChildKey["AppShellHeader"] = "app-shell-header";
7
+ ChildKey["AppShellBar"] = "app-shell-bar";
7
8
  ChildKey["AppShellSidebar"] = "app-shell-sidebar";
8
9
  ChildKey["Card"] = "card";
9
10
  ChildKey["CardHeader"] = "card-header";
10
11
  ChildKey["CardBody"] = "card-body";
11
12
  ChildKey["CardFooter"] = "card-footer";
13
+ ChildKey["ControlBar"] = "control-bar";
14
+ ChildKey["ControlBarHeader"] = "control-bar-header";
15
+ ChildKey["ControlBarContent"] = "control-bar-content";
16
+ ChildKey["ControlBarOverflow"] = "control-bar-overflow";
12
17
  ChildKey["Modal"] = "modal";
13
18
  ChildKey["ModalHeader"] = "modal-header";
14
19
  ChildKey["ModalBody"] = "modal-body";
@@ -21,6 +26,7 @@ export var ChildKey;
21
26
  export const zIndex = {
22
27
  CarouselImage: 'z-1',
23
28
  AppShellSidebar: 'z-30',
29
+ AppShellBar: 'z-35',
24
30
  ModalBackdrop: 'z-40',
25
31
  ModalContent: 'z-50',
26
32
  SelectDropdown: 'z-55',
package/dist/index.d.ts CHANGED
@@ -10,9 +10,12 @@ export { default as immichLogoJson } from './assets/immich-logo.json';
10
10
  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
+ export { default as ActionBar } from './components/ActionBar/ActionBar.svelte';
14
+ export { default as ActionButton } from './components/ActionButton/ActionButton.svelte';
13
15
  export { default as Alert } from './components/Alert/Alert.svelte';
14
16
  export { default as AnnouncementBanner } from './components/AnnouncementBanner/AnnouncementBanner.svelte';
15
17
  export { default as AppShell } from './components/AppShell/AppShell.svelte';
18
+ export { default as AppShellBar } from './components/AppShell/AppShellBar.svelte';
16
19
  export { default as AppShellHeader } from './components/AppShell/AppShellHeader.svelte';
17
20
  export { default as AppShellSidebar } from './components/AppShell/AppShellSidebar.svelte';
18
21
  export { default as Avatar } from './components/Avatar/Avatar.svelte';
@@ -35,6 +38,12 @@ export { default as CommandPaletteProvider } from './components/CommandPalette/C
35
38
  export { default as ConfirmModal } from './components/ConfirmModal/ConfirmModal.svelte';
36
39
  export { default as Container } from './components/Container/Container.svelte';
37
40
  export { default as ContextMenuButton } from './components/ContextMenu/ContextMenuButton.svelte';
41
+ export { default as ControlBar } from './components/ControlBar/ControlBar.svelte';
42
+ export { default as ControlBarContent } from './components/ControlBar/ControlBarContent.svelte';
43
+ export { default as ControlBarDescription } from './components/ControlBar/ControlBarDescription.svelte';
44
+ export { default as ControlBarHeader } from './components/ControlBar/ControlBarHeader.svelte';
45
+ export { default as ControlBarOverflow } from './components/ControlBar/ControlBarOverflow.svelte';
46
+ export { default as ControlBarTitle } from './components/ControlBar/ControlBarTitle.svelte';
38
47
  export { default as DatePicker } from './components/DatePicker/DatePicker.svelte';
39
48
  export { default as Field } from './components/Field/Field.svelte';
40
49
  export { default as FormatBytes } from './components/FormatBytes/FormatBytes.svelte';
package/dist/index.js CHANGED
@@ -12,9 +12,12 @@ export { default as immichLogo } from './assets/immich-logo.svg';
12
12
  export { default as obtainiumBadge } from './assets/obtainium-badge.png';
13
13
  export { default as playStoreBadge } from './assets/playstore-badge.png';
14
14
  // components
15
+ export { default as ActionBar } from './components/ActionBar/ActionBar.svelte';
16
+ export { default as ActionButton } from './components/ActionButton/ActionButton.svelte';
15
17
  export { default as Alert } from './components/Alert/Alert.svelte';
16
18
  export { default as AnnouncementBanner } from './components/AnnouncementBanner/AnnouncementBanner.svelte';
17
19
  export { default as AppShell } from './components/AppShell/AppShell.svelte';
20
+ export { default as AppShellBar } from './components/AppShell/AppShellBar.svelte';
18
21
  export { default as AppShellHeader } from './components/AppShell/AppShellHeader.svelte';
19
22
  export { default as AppShellSidebar } from './components/AppShell/AppShellSidebar.svelte';
20
23
  export { default as Avatar } from './components/Avatar/Avatar.svelte';
@@ -37,6 +40,12 @@ export { default as CommandPaletteProvider } from './components/CommandPalette/C
37
40
  export { default as ConfirmModal } from './components/ConfirmModal/ConfirmModal.svelte';
38
41
  export { default as Container } from './components/Container/Container.svelte';
39
42
  export { default as ContextMenuButton } from './components/ContextMenu/ContextMenuButton.svelte';
43
+ export { default as ControlBar } from './components/ControlBar/ControlBar.svelte';
44
+ export { default as ControlBarContent } from './components/ControlBar/ControlBarContent.svelte';
45
+ export { default as ControlBarDescription } from './components/ControlBar/ControlBarDescription.svelte';
46
+ export { default as ControlBarHeader } from './components/ControlBar/ControlBarHeader.svelte';
47
+ export { default as ControlBarOverflow } from './components/ControlBar/ControlBarOverflow.svelte';
48
+ export { default as ControlBarTitle } from './components/ControlBar/ControlBarTitle.svelte';
40
49
  export { default as DatePicker } from './components/DatePicker/DatePicker.svelte';
41
50
  export { default as Field } from './components/Field/Field.svelte';
42
51
  export { default as FormatBytes } from './components/FormatBytes/FormatBytes.svelte';
@@ -1,12 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { ChildKey } from '../constants.js';
3
- import type { ChildData } from '../types.js';
3
+ import type { ContextType } from '../types.js';
4
4
  import { withPrefix } from '../utilities/internal.js';
5
- import { getContext, type Snippet } from 'svelte';
5
+ import { getContext, onDestroy, type Snippet } from 'svelte';
6
6
 
7
- type ContextType = {
8
- register: (key: ChildKey, data: () => ChildData) => void;
9
- };
10
7
  type Props = {
11
8
  for: ChildKey;
12
9
  as: ChildKey;
@@ -26,4 +23,8 @@
26
23
  } else {
27
24
  console.log('Unable to find context for key:', key);
28
25
  }
26
+
27
+ onDestroy(() => {
28
+ context?.unregister(as);
29
+ });
29
30
  </script>
@@ -5,6 +5,11 @@
5
5
 
6
6
  @import 'tailwindcss';
7
7
 
8
+ @theme {
9
+ --spacing-control-bar-container: --spacing(18);
10
+ --spacing-control-bar: --spacing(16);
11
+ }
12
+
8
13
  @theme inline {
9
14
  --color-primary-50: var(--immich-ui-primary-50);
10
15
  --color-primary-100: var(--immich-ui-primary-100);
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Shortcut } from './actions/shortcut.js';
2
+ import type { ChildKey } from './constants.js';
2
3
  import type { Translations } from './services/translation.svelte.js';
3
4
  import type { DateTime } from 'luxon';
4
5
  import type { Component, Snippet } from 'svelte';
@@ -304,4 +305,23 @@ export type CarouselImageItem = {
304
305
  alt?: string;
305
306
  id?: string;
306
307
  };
308
+ export type ControlBarProps = {
309
+ ref?: HTMLElement | null;
310
+ closeIcon?: IconLike | Snippet;
311
+ variant?: Variants;
312
+ shape?: 'semi-round' | 'rectangle';
313
+ translations?: TranslationProps<'close'>;
314
+ onClose?: () => void;
315
+ children?: Snippet;
316
+ closeOnEsc?: boolean;
317
+ static?: boolean;
318
+ } & HTMLAttributes<HTMLElement>;
319
+ export type ActionBarProps = ControlBarProps & {
320
+ actions: ActionItem[];
321
+ overflowActions?: ActionItem[];
322
+ };
323
+ export type ContextType = {
324
+ register: (key: ChildKey, data: () => ChildData) => void;
325
+ unregister: (key: ChildKey) => void;
326
+ };
307
327
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immich/ui",
3
- "version": "0.59.0",
3
+ "version": "0.60.0",
4
4
  "license": "GNU Affero General Public License version 3",
5
5
  "repository": {
6
6
  "type": "git",
@@ -58,7 +58,7 @@
58
58
  "@immich/svelte-markdown-preprocess": "^0.1.0"
59
59
  },
60
60
  "volta": {
61
- "node": "24.12.0"
61
+ "node": "24.13.0"
62
62
  },
63
63
  "scripts": {
64
64
  "create": "node scripts/create.js",