@immich/ui 0.36.0 → 0.37.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.
- package/dist/components/AnnouncementBanner/AnnouncementBanner.svelte +44 -21
- package/dist/components/AnnouncementBanner/AnnouncementBanner.svelte.d.ts +4 -1
- package/dist/components/CommandPalette/CommandPalette.svelte +4 -4
- package/dist/components/NumberInput/NumberInput.svelte +17 -0
- package/dist/components/NumberInput/NumberInput.svelte.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +8 -8
- package/dist/utilities/common.d.ts +1 -1
- package/dist/utilities/common.js +0 -1
- package/package.json +5 -1
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
import type { IconLike, Size, TextColor } from '../../types.js';
|
|
6
6
|
import { cleanClass, resolveIcon } from '../../utilities/internal.js';
|
|
7
7
|
import { mdiAlertCircleOutline, mdiAlertOutline, mdiCheckAll, mdiInformationOutline, mdiPartyPopper } from '@mdi/js';
|
|
8
|
-
import
|
|
8
|
+
import { DateTime } from 'luxon';
|
|
9
|
+
import { onDestroy, onMount, type Snippet } from 'svelte';
|
|
9
10
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
10
11
|
import { tv } from 'tailwind-variants';
|
|
11
12
|
|
|
@@ -13,6 +14,8 @@
|
|
|
13
14
|
color?: TextColor;
|
|
14
15
|
size?: Size;
|
|
15
16
|
icon?: IconLike | false;
|
|
17
|
+
since?: DateTime;
|
|
18
|
+
until?: DateTime;
|
|
16
19
|
center?: boolean;
|
|
17
20
|
children?: Snippet;
|
|
18
21
|
content?: Snippet;
|
|
@@ -26,13 +29,13 @@
|
|
|
26
29
|
false: '',
|
|
27
30
|
},
|
|
28
31
|
color: {
|
|
29
|
-
primary: 'bg-primary/
|
|
30
|
-
secondary: 'bg-dark/
|
|
32
|
+
primary: 'bg-primary/20 text-primary dark:bg-primary/25',
|
|
33
|
+
secondary: 'bg-dark/20 text-dark dark:bg-dark/25',
|
|
31
34
|
muted: 'bg-subtle text-subtle dark:bg-subtle',
|
|
32
|
-
info: 'bg-info/
|
|
33
|
-
warning: 'bg-warning/
|
|
34
|
-
danger: 'bg-danger/
|
|
35
|
-
success: 'bg-success/
|
|
35
|
+
info: 'bg-info/20 text-info dark:bg-info/25',
|
|
36
|
+
warning: 'bg-warning/20 text-warning dark:bg-warning/25',
|
|
37
|
+
danger: 'bg-danger/20 text-danger dark:bg-danger/25',
|
|
38
|
+
success: 'bg-success/20 text-success dark:bg-success/25',
|
|
36
39
|
},
|
|
37
40
|
},
|
|
38
41
|
});
|
|
@@ -43,6 +46,8 @@
|
|
|
43
46
|
class: className,
|
|
44
47
|
center = false,
|
|
45
48
|
icon: iconOverride,
|
|
49
|
+
since,
|
|
50
|
+
until,
|
|
46
51
|
content,
|
|
47
52
|
children,
|
|
48
53
|
...restProps
|
|
@@ -75,19 +80,37 @@
|
|
|
75
80
|
},
|
|
76
81
|
},
|
|
77
82
|
});
|
|
83
|
+
|
|
84
|
+
let now = $state(DateTime.now());
|
|
85
|
+
let isStarted = $derived(since ? now >= since : true);
|
|
86
|
+
let isFinished = $derived(until ? now <= until : true);
|
|
87
|
+
let isVisible = $derived(isStarted && isFinished);
|
|
88
|
+
let timer: ReturnType<typeof setInterval>;
|
|
89
|
+
|
|
90
|
+
onMount(() => {
|
|
91
|
+
timer = setInterval(() => (now = DateTime.now()), 1000);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
onDestroy(() => {
|
|
95
|
+
if (timer) {
|
|
96
|
+
clearInterval(timer);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
78
99
|
</script>
|
|
79
100
|
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
{
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
{#if isVisible}
|
|
102
|
+
<div class={cleanClass(styles({ color, center }), className)} {...restProps}>
|
|
103
|
+
{#if content}
|
|
104
|
+
{@render content()}
|
|
105
|
+
{:else}
|
|
106
|
+
<div class="flex items-center gap-2">
|
|
107
|
+
{#if icon}
|
|
108
|
+
<Icon {icon} class={iconStyles({ color, size })} />
|
|
109
|
+
{/if}
|
|
110
|
+
<Text color="secondary" {size}>
|
|
111
|
+
{@render children?.()}
|
|
112
|
+
</Text>
|
|
113
|
+
</div>
|
|
114
|
+
{/if}
|
|
115
|
+
</div>
|
|
116
|
+
{/if}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { IconLike, Size, TextColor } from '../../types.js';
|
|
2
|
-
import
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
3
|
+
import { type Snippet } from 'svelte';
|
|
3
4
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
5
|
type Props = {
|
|
5
6
|
color?: TextColor;
|
|
6
7
|
size?: Size;
|
|
7
8
|
icon?: IconLike | false;
|
|
9
|
+
since?: DateTime;
|
|
10
|
+
until?: DateTime;
|
|
8
11
|
center?: boolean;
|
|
9
12
|
children?: Snippet;
|
|
10
13
|
content?: Snippet;
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
|
|
59
59
|
<svelte:window
|
|
60
60
|
use:shortcuts={[
|
|
61
|
-
{ shortcut: { key: 'k', meta: true },
|
|
62
|
-
{ shortcut: { key: 'k', ctrl: true },
|
|
61
|
+
{ shortcut: { key: 'k', meta: true }, onShortcut: handleOpen },
|
|
62
|
+
{ shortcut: { key: 'k', ctrl: true }, onShortcut: handleOpen },
|
|
63
63
|
{ shortcut: { key: '/' }, preventDefault: true, onShortcut: handleOpen },
|
|
64
|
-
{ shortcut: { key: 'ArrowUp' }, ignoreInputFields: false, onShortcut: handleUp },
|
|
65
|
-
{ shortcut: { key: 'ArrowDown' }, ignoreInputFields: false, onShortcut: handleDown },
|
|
64
|
+
{ shortcut: { key: 'ArrowUp' }, preventDefault: false, ignoreInputFields: false, onShortcut: handleUp },
|
|
65
|
+
{ shortcut: { key: 'ArrowDown' }, preventDefault: false, ignoreInputFields: false, onShortcut: handleDown },
|
|
66
66
|
{ shortcut: { key: 'k', ctrl: true }, ignoreInputFields: false, onShortcut: handleUp },
|
|
67
67
|
{ shortcut: { key: 'k', meta: true }, ignoreInputFields: false, onShortcut: handleUp },
|
|
68
68
|
{ shortcut: { key: 'j', ctrl: true }, ignoreInputFields: false, onShortcut: handleDown },
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Input from '../Input/Input.svelte';
|
|
3
|
+
import type { NumberInputProps } from '../../types.js';
|
|
4
|
+
|
|
5
|
+
let { value = $bindable<number>(), color = 'secondary', size, ...props }: NumberInputProps = $props();
|
|
6
|
+
|
|
7
|
+
const getValue = () => String(value ?? 0);
|
|
8
|
+
const setValue = (newValue: string) => {
|
|
9
|
+
const parsed = parseFloat(newValue);
|
|
10
|
+
if (isNaN(parsed)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
value = parsed;
|
|
14
|
+
};
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<Input bind:value={getValue, setValue} {size} type="number" {color} {...props} />
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export { default as ModalHeader } from './components/Modal/ModalHeader.svelte';
|
|
|
49
49
|
export { default as MultiSelect } from './components/MultiSelect/MultiSelect.svelte';
|
|
50
50
|
export { default as NavbarGroup } from './components/Navbar/NavbarGroup.svelte';
|
|
51
51
|
export { default as NavbarItem } from './components/Navbar/NavbarItem.svelte';
|
|
52
|
+
export { default as NumberInput } from './components/NumberInput/NumberInput.svelte';
|
|
52
53
|
export { default as PasswordInput } from './components/PasswordInput/PasswordInput.svelte';
|
|
53
54
|
export { default as Scrollable } from './components/Scrollable/Scrollable.svelte';
|
|
54
55
|
export { default as Select } from './components/Select/Select.svelte';
|
package/dist/index.js
CHANGED
|
@@ -51,6 +51,7 @@ export { default as ModalHeader } from './components/Modal/ModalHeader.svelte';
|
|
|
51
51
|
export { default as MultiSelect } from './components/MultiSelect/MultiSelect.svelte';
|
|
52
52
|
export { default as NavbarGroup } from './components/Navbar/NavbarGroup.svelte';
|
|
53
53
|
export { default as NavbarItem } from './components/Navbar/NavbarItem.svelte';
|
|
54
|
+
export { default as NumberInput } from './components/NumberInput/NumberInput.svelte';
|
|
54
55
|
export { default as PasswordInput } from './components/PasswordInput/PasswordInput.svelte';
|
|
55
56
|
export { default as Scrollable } from './components/Scrollable/Scrollable.svelte';
|
|
56
57
|
export { default as Select } from './components/Select/Select.svelte';
|
package/dist/types.d.ts
CHANGED
|
@@ -102,23 +102,23 @@ export type FieldContext = {
|
|
|
102
102
|
required?: boolean;
|
|
103
103
|
readOnly?: boolean;
|
|
104
104
|
} & LabelProps;
|
|
105
|
-
type BaseInputProps = {
|
|
105
|
+
type BaseInputProps<T> = {
|
|
106
106
|
ref?: HTMLInputElement | null;
|
|
107
107
|
class?: string;
|
|
108
|
-
value?: string;
|
|
109
108
|
size?: Size;
|
|
109
|
+
value?: T;
|
|
110
110
|
shape?: Shape;
|
|
111
111
|
inputSize?: HTMLInputAttributes['size'];
|
|
112
|
-
} & Omit<HTMLInputAttributes, 'size' | 'type'>;
|
|
113
|
-
export type InputProps = BaseInputProps & {
|
|
114
|
-
containerRef?: HTMLElement | null;
|
|
115
|
-
type?: HTMLInputAttributes['type'];
|
|
116
112
|
leadingIcon?: IconLike | Snippet;
|
|
117
113
|
trailingIcon?: IconLike | Snippet;
|
|
118
114
|
trailingText?: string;
|
|
115
|
+
containerRef?: HTMLElement | null;
|
|
116
|
+
} & Omit<HTMLInputAttributes, 'size' | 'type' | 'value'>;
|
|
117
|
+
export type InputProps = BaseInputProps<string> & {
|
|
118
|
+
type?: HTMLInputAttributes['type'];
|
|
119
119
|
};
|
|
120
|
-
export type
|
|
121
|
-
|
|
120
|
+
export type NumberInputProps = BaseInputProps<number>;
|
|
121
|
+
export type PasswordInputProps = BaseInputProps<string> & {
|
|
122
122
|
translations?: TranslationProps<'show_password' | 'hide_password'>;
|
|
123
123
|
isVisible?: boolean;
|
|
124
124
|
};
|
package/dist/utilities/common.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@immich/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"license": "GNU Affero General Public License version 3",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/immich-app/ui.git"
|
|
8
|
+
},
|
|
5
9
|
"scripts": {
|
|
6
10
|
"create": "node scripts/create.js",
|
|
7
11
|
"start": "npm run start:dev",
|