@immich/ui 0.45.1 → 0.46.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.
@@ -28,27 +28,32 @@
28
28
  variants: {
29
29
  shape: styleVariants.shape,
30
30
  color: {
31
- primary: 'bg-primary-200 text-primary-950 dark:text-primary-50 dark:bg-primary-800',
32
- secondary: 'bg-neutral-200 text-neutral-950 dark:bg-neutral-800 dark:text-neutral-50',
33
- success: 'bg-success-200 text-success-950 dark:text-success-50 dark:bg-success-800',
34
- danger: 'bg-danger-200 text-danger-950 dark:text-danger-50 dark:bg-danger-800',
35
- warning: 'bg-warning-200 text-warning-950 dark:text-warning-50 dark:bg-warning-800',
36
- info: 'bg-info-200 text-info-950 dark:text-info-50 dark:bg-info-800',
31
+ primary:
32
+ 'bg-primary-100 border-primary-100 text-primary-950 dark:text-primary-50 dark:bg-primary-800 dark:border-primary-800',
33
+ secondary:
34
+ 'border-neutral-20 bg-neutral-100 text-neutral-950 dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-50',
35
+ success:
36
+ 'border-success-100 bg-success-100 text-success-950 dark:text-success-50 dark:bg-success-800 dark:border-success-800',
37
+ info: 'border-info-100 bg-info-200 text-info-950 dark:text-info-50 dark:bg-info-800 dark:border-info-800',
38
+ warning:
39
+ 'border-warning-100 bg-warning-200 text-warning-950 dark:text-warning-50 dark:bg-warning-800 dark:border-warning-800',
40
+ danger:
41
+ 'border-danger-100 bg-danger-200 text-danger-950 dark:text-danger-50 dark:bg-danger-900 dark:border-danger-800',
37
42
  },
38
43
  textSize: styleVariants.textSize,
39
44
  paddingSize: {
40
- tiny: 'px-1 py-0.5',
41
- small: 'px-2 py-0.5',
42
- medium: 'px-2 py-0.5',
43
- large: 'px-2 py-1.5',
44
- giant: 'px-3 py-1',
45
+ tiny: 'px-1.5 py-px',
46
+ small: 'px-1.75 py-0.5',
47
+ medium: 'px-2.5 py-0.75',
48
+ large: 'px-2.75 py-1',
49
+ giant: 'px-3 py-1.25',
45
50
  },
46
51
  roundedSize: {
47
- tiny: 'rounded-sm',
48
- small: 'rounded-sm',
49
- medium: 'rounded-sm',
50
- large: 'rounded-md',
51
- giant: 'rounded-md',
52
+ tiny: 'rounded-md',
53
+ small: 'rounded-md',
54
+ medium: 'rounded-md',
55
+ large: 'rounded-lg',
56
+ giant: 'rounded-lg',
52
57
  },
53
58
  },
54
59
  });
@@ -6,6 +6,8 @@
6
6
  import type { Color } from '../../types.js';
7
7
  import { cleanClass } from '../../utilities/internal.js';
8
8
  import { mdiChevronDown } from '@mdi/js';
9
+ import { slide } from 'svelte/transition';
10
+ import { cubicOut } from 'svelte/easing';
9
11
  import { type Snippet } from 'svelte';
10
12
  import type { HTMLAttributes } from 'svelte/elements';
11
13
  import { twMerge } from 'tailwind-merge';
@@ -49,12 +51,12 @@
49
51
  base: 'flex w-full grow flex-col',
50
52
  variants: {
51
53
  color: {
52
- primary: 'bg-primary-100 dark:bg-primary-900',
53
- secondary: 'text-dark bg-gray-100 dark:bg-neutral-900 dark:text-white',
54
- success: 'bg-success-100 dark:bg-success-900',
55
- danger: 'bg-danger-100 dark:bg-danger-900',
56
- warning: 'bg-warning-100 dark:bg-warning-900',
57
- info: 'bg-info-100 dark:bg-info-900',
54
+ primary: 'bg-primary-50 dark:bg-primary-900',
55
+ secondary: 'text-dark bg-neutral-50 dark:bg-neutral-900 dark:text-white',
56
+ success: 'bg-success-50 dark:bg-success-900',
57
+ danger: 'bg-danger-50 dark:bg-danger-900',
58
+ warning: 'bg-warning-50 dark:bg-warning-900',
59
+ info: 'bg-info-50 dark:bg-info-900',
58
60
  },
59
61
  },
60
62
  });
@@ -134,9 +136,11 @@
134
136
  {/if}
135
137
 
136
138
  {#if bodyChild && expanded}
137
- <Scrollable class={twMerge(cleanClass('p-4', bodyChild?.class))}>
138
- {@render bodyChild?.snippet()}
139
- </Scrollable>
139
+ <div transition:slide={{ duration: expandable ? 200 : 0, easing: cubicOut }}>
140
+ <Scrollable class={twMerge(cleanClass('p-4', bodyChild?.class))}>
141
+ {@render bodyChild?.snippet()}
142
+ </Scrollable>
143
+ </div>
140
144
  {/if}
141
145
 
142
146
  {#if footerChild}
@@ -11,7 +11,7 @@
11
11
 
12
12
  $effect(() => {
13
13
  // prevent reactivity loop
14
- const addCommands = (commands: CommandItem[], global?: boolean) =>
14
+ const addCommands = (commands: CommandItem[], global: boolean = false) =>
15
15
  untrack(() => commandPaletteManager.addCommands(commands, { global }));
16
16
 
17
17
  return addCommands(commands, global);
@@ -5,11 +5,12 @@
5
5
  import IconButton from '../IconButton/IconButton.svelte';
6
6
  import Kbd from '../Kbd/Kbd.svelte';
7
7
  import Text from '../Text/Text.svelte';
8
- import type { CommandItem } from '../../services/command-palette-manager.svelte';
8
+ import type { CommandItemResponse } from '../../services/command-palette-manager.svelte';
9
9
  import { mdiClose } from '@mdi/js';
10
+ import Badge from '../Badge/Badge.svelte';
10
11
 
11
12
  type Props = {
12
- item: CommandItem;
13
+ item: CommandItemResponse;
13
14
  selected: boolean;
14
15
  onSelect: () => void;
15
16
  onRemove?: () => void;
@@ -41,46 +42,48 @@
41
42
  fullWidth
42
43
  variant={selected ? 'outline' : 'ghost'}
43
44
  color="secondary"
44
- class="overflow-hidden border"
45
+ class="flex justify-between gap-3 border text-start {selected ? 'border-neutral-500!' : ''}"
45
46
  >
46
- <div class="flex w-full place-items-center justify-between gap-2">
47
- <div class="flex min-w-0 place-items-center gap-2">
48
- <Icon icon={item.icon} size="2rem" class={item.iconClass} />
49
- <div class="flex min-w-0 flex-col">
50
- <div class="flex place-items-center gap-1">
51
- <Text fontWeight="bold">{item.title}</Text>
52
- </div>
53
- {#if item.description}
54
- <Text
55
- size="small"
56
- class="overflow-hidden text-ellipsis whitespace-nowrap"
57
- color={selected ? undefined : 'muted'}>{item.description}</Text
58
- >
59
- {/if}
60
- </div>
47
+ <div class="flex flex-col">
48
+ <div class="flex items-center gap-1">
49
+ <Text fontWeight="bold">{item.title}</Text>
50
+ <Icon icon={item.icon} size="1.25rem" class={item.iconClass} />
61
51
  </div>
62
- <div class="flex flex-col items-end gap-1">
63
- {#if onRemove}
64
- <IconButton
65
- size="small"
66
- onclick={handleRemove}
67
- icon={mdiClose}
68
- shape="round"
69
- variant="ghost"
70
- color="secondary"
71
- aria-label="Remove"
72
- />
73
- {:else}
74
- <span class="shrink-0">[{item.type}]</span>
75
- {/if}
76
- {#if renderedShortcuts.length > 0}
77
- <div class="flex justify-end gap-1">
78
- {#each renderedShortcuts[0] as key (key)}
79
- <Kbd size="small">{key}</Kbd>
80
- {/each}
81
- </div>
52
+ {#if item.description}
53
+ <Text
54
+ size="small"
55
+ class="mt-0.5 line-clamp-4 w-full overflow-hidden text-ellipsis md:line-clamp-2"
56
+ color="muted">{item.description}</Text
57
+ >
58
+ {/if}
59
+ <div class="mt-2">
60
+ <Badge size="small" color="primary" shape="rectangle">{item.type}</Badge>
61
+ {#if item.isGlobal}
62
+ <Badge size="small" shape="rectangle" color="warning">Global</Badge>
82
63
  {/if}
83
64
  </div>
84
65
  </div>
66
+ {#if onRemove}
67
+ <IconButton
68
+ size="small"
69
+ onclick={handleRemove}
70
+ class="shrink-0"
71
+ icon={mdiClose}
72
+ shape="round"
73
+ variant="ghost"
74
+ color="secondary"
75
+ aria-label="Remove"
76
+ />
77
+ {:else if renderedShortcuts.length > 0}
78
+ <div class="flex shrink-0 flex-col justify-end gap-1">
79
+ {#each renderedShortcuts as shortcut (shortcut.join('-'))}
80
+ <div class="flex justify-end">
81
+ <Kbd size="tiny" class={selected ? '' : 'border-neutral-200 dark:border-neutral-700'}
82
+ >{shortcut.join(' ')}</Kbd
83
+ >
84
+ </div>
85
+ {/each}
86
+ </div>
87
+ {/if}
85
88
  </Button>
86
89
  </div>
@@ -1,6 +1,6 @@
1
- import type { CommandItem } from '../../services/command-palette-manager.svelte';
1
+ import type { CommandItemResponse } from '../../services/command-palette-manager.svelte';
2
2
  type Props = {
3
- item: CommandItem;
3
+ item: CommandItemResponse;
4
4
  selected: boolean;
5
5
  onSelect: () => void;
6
6
  onRemove?: () => void;
@@ -25,14 +25,14 @@
25
25
  };
26
26
 
27
27
  const itemStyles = tv({
28
- base: 'hover:bg-subtle flex w-full items-center gap-1 rounded-md px-1 py-0.5 text-start',
28
+ base: 'dark:hover:bg-primary-800 hover:bg-primary-100 flex w-full items-center gap-1 rounded-lg p-1 text-start hover:cursor-pointer',
29
29
  variants: {
30
30
  color: styleVariants.textColor,
31
31
  },
32
32
  });
33
33
 
34
34
  const wrapperStyles = tv({
35
- base: 'bg-light flex flex-col gap-1 overflow-hidden rounded-lg border py-1',
35
+ base: 'flex flex-col gap-1 overflow-hidden rounded-xl border bg-neutral-100 py-1 shadow-sm dark:border-neutral-700 dark:bg-neutral-900',
36
36
  variants: {
37
37
  size: {
38
38
  tiny: 'w-32',
@@ -102,7 +102,7 @@
102
102
  <div {...props} {...restProps} class={cleanClass(wrapperStyles({ size }), className)} transition:fly>
103
103
  {#each filteredItems as item, i (isDivider(item) ? i : item.title)}
104
104
  {#if isDivider(item)}
105
- <DropdownMenu.Separator class="my-0.5 border-t" />
105
+ <DropdownMenu.Separator class="my-0.5 border-t dark:border-neutral-700" />
106
106
  {:else}
107
107
  <DropdownMenu.Item
108
108
  textValue={item.title}
@@ -112,14 +112,14 @@
112
112
  >
113
113
  <div class={itemStyles({ color: item.color })}>
114
114
  <Icon icon={item.icon} class="m-2 shrink-0" />
115
- <Text class="grow text-start">{item.title}</Text>
115
+ <Text class="grow text-start font-medium select-none" size="medium">{item.title}</Text>
116
116
  </div>
117
117
  </DropdownMenu.Item>
118
118
  {/if}
119
119
  {/each}
120
120
 
121
121
  {#if filteredBottomItems}
122
- <DropdownMenu.Separator class="my-0.5 border-t" />
122
+ <DropdownMenu.Separator class="my-0.5 border-t dark:border-neutral-700" />
123
123
  <div class="flex gap-1 px-1">
124
124
  {#each filteredBottomItems as item (item.title)}
125
125
  <DropdownMenu.Item
@@ -50,7 +50,7 @@
50
50
  });
51
51
 
52
52
  const inputStyles = tv({
53
- base: cleanClass(styleVariants.inputCommon, 'flex-1 py-2'),
53
+ base: cleanClass(styleVariants.inputCommon, 'flex-1 py-2.5'),
54
54
  variants: {
55
55
  textSize: styleVariants.textSize,
56
56
  leadingPadding: {
@@ -88,18 +88,11 @@
88
88
 
89
89
  <div class="flex w-full flex-col gap-1" bind:this={containerRef}>
90
90
  {#if label}
91
- <Label
92
- id={labelId}
93
- for={inputId}
94
- {label}
95
- requiredIndicator={required === 'indicator'}
96
- {...labelProps}
97
- class="font-medium"
98
- />
91
+ <Label id={labelId} for={inputId} {label} requiredIndicator={required === 'indicator'} {...labelProps} />
99
92
  {/if}
100
93
 
101
94
  {#if description}
102
- <Text color="muted" size="small" id={descriptionId} class="mb-1">{description}</Text>
95
+ <Text color="muted" size="small" id={descriptionId} class="mb-2">{description}</Text>
103
96
  {/if}
104
97
 
105
98
  <div
@@ -7,7 +7,7 @@
7
7
  const { label, size, color, class: className, children, requiredIndicator, ...restProps }: LabelProps = $props();
8
8
 
9
9
  const styles = tv({
10
- base: '',
10
+ base: 'font-medium',
11
11
  variants: {
12
12
  size: styleVariants.textSize,
13
13
  color: styleVariants.textColor,
@@ -99,7 +99,7 @@
99
99
  {interactOutsideBehavior}
100
100
  class={cleanClass(modalContentStyles({ size }))}
101
101
  >
102
- <div class={cleanClass('flex grow flex-col justify-center')}>
102
+ <div class={cleanClass('flex w-full grow flex-col justify-center')}>
103
103
  <Card bind:ref={cardRef} class={cleanClass(modalStyles({ size }), className)}>
104
104
  <CardHeader class="border-b border-gray-200 px-5 py-3 dark:border-white/10">
105
105
  {#if headerChildren}
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import Logo from '../Logo/Logo.svelte';
3
3
  import Text from '../Text/Text.svelte';
4
+ import { t } from '../../services/translation.svelte.js';
4
5
  import type { Size } from '../../types.js';
5
6
  import { cleanClass } from '../../utilities/internal.js';
6
7
  import type { Snippet } from 'svelte';
@@ -13,7 +14,7 @@
13
14
  children?: Snippet;
14
15
  };
15
16
 
16
- const { effect = 'hover', text = 'Supporter', size = 'medium', children }: Props = $props();
17
+ const { effect = 'hover', text = t('supporter'), size = 'medium', children }: Props = $props();
17
18
 
18
19
  const iconSize: Record<Size, Size> = {
19
20
  tiny: 'tiny',
@@ -42,12 +42,12 @@
42
42
  variants: {
43
43
  fillColor: {
44
44
  default: 'border-gray-400 bg-gray-200 dark:border-gray-500 dark:bg-gray-800',
45
- primary: 'bg-primary-200 dark:bg-primary-800 border-transparent',
46
- secondary: 'border-transparent bg-neutral-300 dark:bg-neutral-700',
47
- success: 'bg-success-200 dark:bg-success-800 border-transparent',
48
- danger: 'bg-danger-200 dark:bg-danger-800 border-transparent',
49
- warning: 'bg-warning-200 dark:bg-warning-800 border-transparent',
50
- info: 'bg-info-200 dark:bg-info-800 border-transparent',
45
+ primary: 'bg-primary-100 dark:bg-primary-800 border-transparent',
46
+ secondary: 'border-transparent bg-neutral-200 dark:bg-neutral-700',
47
+ success: 'bg-success-100 dark:bg-success-800 border-transparent',
48
+ danger: 'bg-danger-100 dark:bg-danger-800 border-transparent',
49
+ warning: 'bg-warning-100 dark:bg-warning-800 border-transparent',
50
+ info: 'bg-info-100 dark:bg-info-800 border-transparent',
51
51
  },
52
52
  },
53
53
  });
@@ -95,7 +95,7 @@
95
95
  <div class="text-start">
96
96
  <Label id={labelId} for={inputId} {label} requiredIndicator={required === 'indicator'} {...labelProps} />
97
97
  {#if description}
98
- <Text color="secondary" size="small" id={descriptionId}>{description}</Text>
98
+ <Text color="muted" size="small" id={descriptionId}>{description}</Text>
99
99
  {/if}
100
100
  </div>
101
101
  {/if}
@@ -15,16 +15,15 @@
15
15
  }: ToastContainerProps = $props();
16
16
 
17
17
  const containerStyles = tv({
18
- base: 'bg-light text-dark overflow-hidden py-1.5 shadow-xs transition-all',
18
+ base: 'bg-light text-dark overflow-hidden border py-1.5 shadow-xs transition-all',
19
19
  variants: {
20
20
  color: {
21
- primary: 'bg-primary-100 dark:bg-primary-900',
22
- secondary: 'bg-neutral-100 dark:bg-neutral-900',
23
- muted: 'bg-subtle dark:bg-subtle',
24
- info: 'bg-info-100 dark:bg-info-900',
25
- warning: 'bg-warning-100 dark:bg-warning-900',
26
- danger: 'bg-danger-100 dark:bg-danger-900',
27
- success: 'bg-success-100 dark:bg-success-900',
21
+ primary: 'border-primary-100 bg-primary-50 dark:bg-primary-900 dark:border-primary-800',
22
+ secondary: 'border-neutral-200 bg-neutral-50 dark:border-neutral-700 dark:bg-neutral-800',
23
+ success: 'border-success-100 bg-success-50 dark:bg-success-900 dark:border-success-800',
24
+ info: 'border-info-100 bg-info-50 dark:bg-info-900 dark:border-info-800',
25
+ warning: 'border-warning-100 bg-warning-50 dark:bg-warning-900 dark:border-warning-800',
26
+ danger: 'border-danger-100 bg-danger-50 dark:bg-danger-900 dark:border-danger-800',
28
27
  },
29
28
  shape: styleVariants.shape,
30
29
  size: {
@@ -27,7 +27,20 @@
27
27
  );
28
28
 
29
29
  const iconStyles = tv({
30
- base: 'h-10 w-10 shrink-0 py-2',
30
+ base: 'h-8 w-8 shrink-0 rounded-xl py-1.75',
31
+ variants: {
32
+ color: {
33
+ primary: 'bg-primary-100 dark:bg-primary-800 text-primary',
34
+ secondary: 'bg-neutral-200 dark:bg-neutral-700',
35
+ success: 'bg-success-100 dark:bg-success-800 text-success',
36
+ info: 'bg-info-200 dark:bg-info-800 text-info',
37
+ warning: 'bg-warning-200 dark:bg-warning-700 text-warning',
38
+ danger: 'bg-danger-200 dark:bg-danger-800 text-danger',
39
+ },
40
+ },
41
+ });
42
+
43
+ const titleStyles = tv({
31
44
  variants: {
32
45
  color: styleVariants.textColor,
33
46
  },
@@ -38,16 +51,16 @@
38
51
  {#if typeof text === 'string'}{text}{:else}{@render text()}{/if}
39
52
  {/snippet}
40
53
 
41
- <div class="flex items-center px-2">
54
+ <div class="flex items-center px-3">
42
55
  <div class="flex items-center">
43
56
  {#if icon}
44
- <Icon {icon} class={iconStyles({ color })} />
57
+ <Icon {icon} class={iconStyles({ color })} size="18" />
45
58
  {/if}
46
59
  </div>
47
- <div class="flex grow justify-between">
60
+ <div class="ms-1 flex grow justify-between">
48
61
  <div class="flex flex-col p-2">
49
62
  {#if title}
50
- <Text fontWeight="bold">{@render resolve(title)}</Text>
63
+ <Text fontWeight="semi-bold" class={titleStyles({ color })}>{@render resolve(title)}</Text>
51
64
  {/if}
52
65
  {#if description}
53
66
  <Text size="small">{@render resolve(description)}</Text>
@@ -51,7 +51,7 @@
51
51
  });
52
52
 
53
53
  const buttonStyles = tv({
54
- base: 'flex h-8 w-8 items-center justify-center rounded-lg transition-colors hover:bg-neutral-200 hover:dark:bg-neutral-700',
54
+ base: 'flex h-10 w-10 items-center justify-center rounded-lg hover:cursor-pointer hover:bg-neutral-200 hover:dark:bg-neutral-700',
55
55
  });
56
56
 
57
57
  const segmentStyles = tv({
@@ -85,7 +85,7 @@
85
85
  })}
86
86
  >
87
87
  {#snippet children({ segments })}
88
- <div class={cleanClass(styleVariants.inputCommon, 'w-full px-4 py-2')}>
88
+ <div class={cleanClass(styleVariants.inputCommon, 'w-full px-3 py-2 font-medium')}>
89
89
  {#each segments as { part, value }, i (`segment-${i}`)}
90
90
  <DatePicker.Segment {part} class={segmentStyles({ textSize: size })}>
91
91
  {value}
@@ -140,7 +140,7 @@
140
140
  {#each weekDates as date (`date-${date.toString()}`)}
141
141
  <DatePicker.Cell {date} month={month.value} class="flex-1">
142
142
  <DatePicker.Day
143
- class="{buttonStyles()} data-selected:bg-primary data-selected:text-light data-today:border-primary border border-transparent data-disabled:cursor-not-allowed data-disabled:opacity-40 data-outside-month:text-gray-400 data-unavailable:cursor-not-allowed data-unavailable:text-gray-300 data-unavailable:line-through"
143
+ class="{buttonStyles()} data-selected:bg-primary data-selected:hover:bg-primary-300 data-selected:text-light data-today:border-primary-200 data-today:dark:border-primary-600 data-today:dark:bg-primary-800 data-today:bg-primary-50 border border-transparent text-sm data-disabled:cursor-not-allowed data-disabled:opacity-40 data-outside-month:text-gray-400 data-unavailable:cursor-not-allowed data-unavailable:text-gray-300 data-unavailable:line-through"
144
144
  >
145
145
  {date.day}
146
146
  </DatePicker.Day>
@@ -84,7 +84,7 @@
84
84
  <Select.Root type={multiple ? 'multiple' : 'single'} bind:value={internalValue as never} {onValueChange}>
85
85
  <Select.Trigger
86
86
  {disabled}
87
- class="w-full items-center gap-1 rounded-lg focus-visible:outline-none"
87
+ class="w-full items-center gap-1 rounded-lg py-0 focus-visible:outline-none"
88
88
  aria-label={placeholder}
89
89
  >
90
90
  <Field {readOnly} {required} {disabled} {invalid}>
@@ -104,6 +104,7 @@
104
104
  variant="ghost"
105
105
  shape="round"
106
106
  color="secondary"
107
+ size="tiny"
107
108
  class="m-1"
108
109
  icon={mdiUnfoldMoreHorizontal}
109
110
  {disabled}
@@ -12,28 +12,25 @@ export type CommandItem = {
12
12
  ignoreInputFields?: boolean;
13
13
  preventDefault?: boolean;
14
14
  };
15
+ id?: string;
15
16
  } & IfLike & ({
16
17
  href: string;
17
18
  } | {
18
- action: (command: CommandItem) => void;
19
+ action: (command: CommandItemResponse) => void;
19
20
  });
20
- export type CommandPaletteTranslations = TranslationProps<'search_placeholder' | 'search_no_results' | 'search_recently_used' | 'command_palette_prompt_default' | 'command_palette_to_select' | 'command_palette_to_close' | 'command_palette_to_navigate' | 'command_palette_to_show_all'>;
21
+ export type CommandItemResponse = CommandItem & {
22
+ id: string;
23
+ isGlobal: boolean;
24
+ };
25
+ export type CommandPaletteTranslations = TranslationProps<'search_placeholder' | 'search_no_results' | 'search_recently_used' | 'command_palette_prompt_default' | 'command_palette_to_select' | 'command_palette_to_close' | 'command_palette_to_navigate' | 'command_palette_to_show_all' | 'global'>;
21
26
  export declare const asText: (...items: unknown[]) => string;
22
27
  declare class CommandPaletteManager {
23
28
  #private;
24
29
  selectedIndex: number;
25
- items: (CommandItem & {
26
- id: string;
27
- })[];
28
- filteredItems: (CommandItem & {
29
- id: string;
30
- })[];
31
- recentItems: (CommandItem & {
32
- id: string;
33
- })[];
34
- results: (CommandItem & {
35
- id: string;
36
- })[];
30
+ items: CommandItemResponse[];
31
+ filteredItems: CommandItemResponse[];
32
+ recentItems: CommandItemResponse[];
33
+ results: CommandItemResponse[];
37
34
  get isEnabled(): boolean;
38
35
  enable(): void;
39
36
  get query(): string;
@@ -50,10 +47,8 @@ declare class CommandPaletteManager {
50
47
  up(): void;
51
48
  down(): void;
52
49
  reset(): void;
53
- addCommands(itemOrItems: MaybeArray<CommandItem & {
54
- id?: string;
55
- }>, options?: {
56
- global?: boolean;
50
+ addCommands(itemOrItems: MaybeArray<CommandItem>, options?: {
51
+ global: boolean;
57
52
  }): () => void;
58
53
  removeCommands(itemOrItems: MaybeArray<{
59
54
  id: string;
@@ -178,9 +178,13 @@ class CommandPaletteManager {
178
178
  this.#globalLayer = { items: [], recentItems: [] };
179
179
  this.#query = '';
180
180
  }
181
- addCommands(itemOrItems, options = {}) {
181
+ addCommands(itemOrItems, options = { global: false }) {
182
182
  const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
183
- const itemsWithId = items.map((item) => ({ ...item, id: item.id ?? generateId() }));
183
+ const itemsWithId = items.map((item) => ({
184
+ ...item,
185
+ id: item.id ?? generateId(),
186
+ isGlobal: options.global,
187
+ }));
184
188
  if (options.global) {
185
189
  this.#globalLayer.items.push(...itemsWithId);
186
190
  }
@@ -9,8 +9,6 @@ type ExtendsEmptyObject<T> = keyof T extends never ? never : T;
9
9
  type StripParamIfOptional<T> = T extends void ? [] : [T];
10
10
  type OptionalParamIfEmpty<T> = ExtendsEmptyObject<T> extends never ? [] | [Record<string, never> | undefined] : [T];
11
11
  declare class ModalManager {
12
- #private;
13
- get openCount(): number;
14
12
  show<T extends object>(Component: Component<T>, ...props: OptionalParamIfEmpty<Omit<T, 'onClose'>>): Promise<OnCloseData<T>>;
15
13
  open<T extends object, K = OnCloseData<T>>(Component: Component<T>, ...props: OptionalParamIfEmpty<Omit<T, 'onClose'>>): {
16
14
  onClose: Promise<K>;
@@ -1,10 +1,6 @@
1
1
  import { mount, unmount } from 'svelte';
2
2
  import ConfirmModal from '../components/ConfirmModal/ConfirmModal.svelte';
3
3
  class ModalManager {
4
- #openCount = $state(0);
5
- get openCount() {
6
- return this.#openCount;
7
- }
8
4
  show(Component, ...props) {
9
5
  return this.open(Component, ...props).onClose;
10
6
  }
@@ -14,7 +10,6 @@ class ModalManager {
14
10
  const deferred = new Promise((resolve) => {
15
11
  onClose = async (...args) => {
16
12
  await unmount(modal);
17
- this.#openCount--;
18
13
  // make sure bits-ui clean up finishes before resolving
19
14
  setTimeout(() => resolve(args[0]), 10);
20
15
  };
@@ -25,7 +20,6 @@ class ModalManager {
25
20
  onClose,
26
21
  },
27
22
  });
28
- this.#openCount++;
29
23
  });
30
24
  return {
31
25
  onClose: deferred,
@@ -22,6 +22,8 @@ declare const defaultTranslations: {
22
22
  toast_warning_title: string;
23
23
  toast_danger_title: string;
24
24
  save: string;
25
+ supporter: string;
26
+ global: string;
25
27
  };
26
28
  export type Translations = typeof defaultTranslations;
27
29
  export declare const translate: <T extends keyof Translations>(key: T, overrides?: TranslationProps<T>) => string;
@@ -28,6 +28,8 @@ const defaultTranslations = {
28
28
  toast_warning_title: 'Warning',
29
29
  toast_danger_title: 'Error',
30
30
  save: 'Save',
31
+ supporter: 'Supporter',
32
+ global: 'Global',
31
33
  };
32
34
  let translations = $state(defaultTranslations);
33
35
  export const translate = (key, overrides) => overrides?.[key] ?? translations[key];
package/dist/styles.js CHANGED
@@ -13,7 +13,7 @@ export const styleVariants = {
13
13
  muted: 'text-gray-600 dark:text-gray-400',
14
14
  },
15
15
  inputCommon: 'disabled:bg-gray-300 disabled:text-dark dark:disabled:bg-gray-900 dark:disabled:text-gray-200 bg-transparent transition outline-none disabled:cursor-not-allowed ',
16
- inputContainerCommon: 'bg-gray-100 ring-1 ring-gray-200 focus-within:ring-primary dark:focus-within:ring-primary transition outline-none focus-within:ring-1 disabled:cursor-not-allowed dark:bg-gray-600 dark:ring-black',
16
+ inputContainerCommon: 'bg-gray-100 ring-1 ring-gray-200 focus-within:ring-primary dark:focus-within:ring-primary transition outline-none focus-within:ring-1 disabled:cursor-not-allowed dark:bg-gray-800 dark:ring-black',
17
17
  shape: {
18
18
  rectangle: 'rounded-none',
19
19
  'semi-round': '',
@@ -83,66 +83,66 @@
83
83
  :root,
84
84
  .light {
85
85
  /* light */
86
- --immich-ui-primary-50: oklch(0.949 0.016 282.34);
86
+ --immich-ui-primary-50: oklch(0.9616 0.0166 271.24);
87
87
  --immich-ui-primary-100: oklch(0.897 0.033 281.96);
88
88
  --immich-ui-primary-200: oklch(0.787 0.07 281.03);
89
89
  --immich-ui-primary-300: oklch(0.686 0.106 278.96);
90
90
  --immich-ui-primary-400: oklch(0.577 0.142 275.93);
91
- --immich-ui-primary-500: oklch(0.473 0.151 272.94);
91
+ --immich-ui-primary-500: #4250af;
92
92
  --immich-ui-primary-600: oklch(0.404 0.129 273.18);
93
93
  --immich-ui-primary-700: oklch(0.343 0.109 272.56);
94
94
  --immich-ui-primary-800: oklch(0.272 0.088 272.94);
95
95
  --immich-ui-primary-900: oklch(0.211 0.068 273.01);
96
96
  --immich-ui-primary-950: oklch(0.15 0.05 273.01);
97
97
 
98
- --immich-ui-success-50: oklch(0.969 0.048 153.5);
99
- --immich-ui-success-100: oklch(0.926 0.124 152.83);
100
- --immich-ui-success-200: oklch(0.864 0.223 152.18);
101
- --immich-ui-success-300: oklch(0.804 0.206 152.33);
102
- --immich-ui-success-400: oklch(0.755 0.194 152.36);
103
- --immich-ui-success-500: oklch(0.698 0.179 152.3);
104
- --immich-ui-success-600: oklch(0.588 0.151 152.25);
105
- --immich-ui-success-700: oklch(0.469 0.12 152.39);
106
- --immich-ui-success-800: oklch(0.359 0.093 152.23);
107
- --immich-ui-success-900: oklch(0.243 0.063 151.99);
108
- --immich-ui-success-950: oklch(0.169 0.042 151.99);
109
-
110
- --immich-ui-danger-50: oklch(0.976 0.008 17.52);
111
- --immich-ui-danger-100: oklch(0.951 0.015 17.54);
112
- --immich-ui-danger-200: oklch(0.867 0.046 18.1);
113
- --immich-ui-danger-300: oklch(0.778 0.085 19.18);
114
- --immich-ui-danger-400: oklch(0.696 0.129 20.93);
115
- --immich-ui-danger-500: oklch(0.608 0.179 24.17);
116
- --immich-ui-danger-600: oklch(0.518 0.153 24.17);
117
- --immich-ui-danger-700: oklch(0.422 0.124 24.12);
118
- --immich-ui-danger-800: oklch(0.331 0.098 24.2);
119
- --immich-ui-danger-900: oklch(0.231 0.069 24.25);
120
- --immich-ui-danger-950: oklch(0.184 0.055 24.33);
121
-
122
- --immich-ui-warning: oklch(0.689 0.133 67.56);
123
- --immich-ui-warning-50: oklch(0.974 0.013 67.56);
124
- --immich-ui-warning-100: oklch(0.947 0.029 67.56);
125
- --immich-ui-warning-200: oklch(0.892 0.061 67.56);
126
- --immich-ui-warning-300: oklch(0.825 0.097 67.56);
127
- --immich-ui-warning-400: oklch(0.757 0.115 67.56);
128
- --immich-ui-warning-500: oklch(0.689 0.133 67.56);
129
- --immich-ui-warning-600: oklch(0.604 0.117 67.56);
130
- --immich-ui-warning-700: oklch(0.509 0.099 67.56);
131
- --immich-ui-warning-800: oklch(0.418 0.081 67.56);
132
- --immich-ui-warning-900: oklch(0.341 0.066 67.56);
133
- --immich-ui-warning-950: oklch(0.273 0.053 67.56);
134
-
135
- --immich-ui-info-50: oklch(0.967 0.018 254.53);
136
- --immich-ui-info-100: oklch(0.933 0.037 254.53);
137
- --immich-ui-info-200: oklch(0.862 0.078 254.53);
138
- --immich-ui-info-300: oklch(0.768 0.126 254.53);
139
- --immich-ui-info-400: oklch(0.667 0.152 254.53);
140
- --immich-ui-info-500: oklch(0.567 0.177 254.53);
141
- --immich-ui-info-600: oklch(0.492 0.155 254.53);
142
- --immich-ui-info-700: oklch(0.419 0.132 254.53);
143
- --immich-ui-info-800: oklch(0.347 0.109 254.53);
144
- --immich-ui-info-900: oklch(0.285 0.089 254.53);
145
- --immich-ui-info-950: oklch(0.232 0.073 254.53);
98
+ --immich-ui-success-50: oklch(0.969 0.051 148.59);
99
+ --immich-ui-success-100: oklch(0.937 0.109 148.66);
100
+ --immich-ui-success-200: oklch(0.863 0.249 147.5);
101
+ --immich-ui-success-300: oklch(0.813 0.234 147.54);
102
+ --immich-ui-success-400: oklch(0.762 0.219 147.59);
103
+ --immich-ui-success-500: oklch(0.708 0.204 147.56);
104
+ --immich-ui-success-600: oklch(0.594 0.171 147.56);
105
+ --immich-ui-success-700: oklch(0.476 0.136 147.69);
106
+ --immich-ui-success-800: oklch(0.36 0.104 147.58);
107
+ --immich-ui-success-900: oklch(0.252 0.073 147.47);
108
+ --immich-ui-success-950: oklch(0.194 0.056 147.87);
109
+
110
+ --immich-ui-danger-50: oklch(0.96 0.018 17.57);
111
+ --immich-ui-danger-100: oklch(0.926 0.034 17.84);
112
+ --immich-ui-danger-200: oklch(0.853 0.074 19.77);
113
+ --immich-ui-danger-300: oklch(0.774 0.125 21.53);
114
+ --immich-ui-danger-400: oklch(0.701 0.178 23.61);
115
+ --immich-ui-danger-500: oklch(0.633 0.24 28.79);
116
+ --immich-ui-danger-600: oklch(0.533 0.204 28.97);
117
+ --immich-ui-danger-700: oklch(0.433 0.166 28.91);
118
+ --immich-ui-danger-800: oklch(0.342 0.131 28.79);
119
+ --immich-ui-danger-900: oklch(0.245 0.094 29.51);
120
+ --immich-ui-danger-950: oklch(0.186 0.07 29.56);
121
+
122
+ --immich-ui-warning: oklch(0.812 0.17 76.3);
123
+ --immich-ui-warning-50: oklch(0.983 0.01 58.27);
124
+ --immich-ui-warning-100: oklch(0.959 0.027 63.96);
125
+ --immich-ui-warning-200: oklch(0.925 0.051 64.24);
126
+ --immich-ui-warning-300: oklch(0.882 0.086 67.45);
127
+ --immich-ui-warning-400: oklch(0.85 0.12 70.92);
128
+ --immich-ui-warning-500: oklch(0.812 0.17 76.3);
129
+ --immich-ui-warning-600: oklch(0.679 0.142 76.48);
130
+ --immich-ui-warning-700: oklch(0.539 0.113 76.63);
131
+ --immich-ui-warning-800: oklch(0.408 0.086 75.75);
132
+ --immich-ui-warning-900: oklch(0.27 0.057 76.33);
133
+ --immich-ui-warning-950: oklch(0.209 0.044 77.51);
134
+
135
+ --immich-ui-info-50: oklch(0.958 0.02 267.31);
136
+ --immich-ui-info-100: oklch(0.922 0.036 268.3);
137
+ --immich-ui-info-200: oklch(0.845 0.073 265.19);
138
+ --immich-ui-info-300: oklch(0.769 0.114 261.53);
139
+ --immich-ui-info-400: oklch(0.691 0.159 256.82);
140
+ --immich-ui-info-500: oklch(0.611 0.177 252.85);
141
+ --immich-ui-info-600: oklch(0.519 0.149 252.81);
142
+ --immich-ui-info-700: oklch(0.422 0.123 252.93);
143
+ --immich-ui-info-800: oklch(0.328 0.096 253.05);
144
+ --immich-ui-info-900: oklch(0.234 0.067 252.62);
145
+ --immich-ui-info-950: oklch(0.178 0.052 253.61);
146
146
 
147
147
  --immich-ui-light: 255 255 255;
148
148
  --immich-ui-dark: rgb(63, 60, 60);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immich/ui",
3
- "version": "0.45.1",
3
+ "version": "0.46.0",
4
4
  "license": "GNU Affero General Public License version 3",
5
5
  "repository": {
6
6
  "type": "git",