@immich/ui 0.30.1 → 0.31.1

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.
@@ -8,17 +8,25 @@
8
8
  type Props = {
9
9
  color?: TextColor;
10
10
  size?: Size;
11
- variant?: 'filled';
11
+ variant?: 'filled' | 'ghost' | 'outline';
12
12
  class?: string;
13
13
  children: Snippet;
14
14
  } & HTMLAttributes<HTMLElement>;
15
15
 
16
- const { class: className, size = 'medium', variant, color = 'secondary', children, ...restProps }: Props = $props();
16
+ const {
17
+ class: className,
18
+ size = 'medium',
19
+ variant = 'filled',
20
+ color = 'primary',
21
+ children,
22
+ ...restProps
23
+ }: Props = $props();
17
24
 
18
25
  const styles = tv({
19
- base: 'font-monospace',
26
+ base: 'font-monospace rounded-lg px-2 py-1',
20
27
  variants: {
21
- textColor: {
28
+ ghostTheme: {
29
+ false: '',
22
30
  muted: 'text-gray-600 dark:text-gray-400',
23
31
  primary: 'text-primary',
24
32
  secondary: 'text-dark',
@@ -28,20 +36,26 @@
28
36
  info: 'text-info',
29
37
  },
30
38
 
31
- filled: {
32
- true: 'rounded-lg p-3',
33
- false: '',
34
- },
35
-
36
- filledColor: {
39
+ filledTheme: {
37
40
  false: '',
38
- muted: 'text-light bg-gray-600 dark:bg-gray-800',
39
- primary: 'text-primary dark:bg-primary/20 bg-gray-200 dark:text-gray-200',
41
+ muted: 'text-dark bg-subtle',
42
+ primary: 'text-dark dark:bg-primary/20 bg-gray-200 dark:text-gray-200',
40
43
  secondary: 'text-light bg-gray-700 dark:bg-gray-200',
41
44
  success: 'bg-success text-light',
42
45
  danger: 'bg-danger text-light',
43
46
  warning: 'bg-warning text-light',
44
- info: 'bg-info text-dark',
47
+ info: 'bg-info text-light',
48
+ },
49
+
50
+ outlineTheme: {
51
+ false: '',
52
+ muted: 'border border-gray-600 text-gray-600 dark:border-gray-400 dark:text-gray-400',
53
+ primary: 'border-primary text-primary border',
54
+ secondary: 'border-dark text-dark border',
55
+ success: 'border-success text-success border',
56
+ danger: 'border-danger text-danger border',
57
+ warning: 'border-warning text-warning border',
58
+ info: 'border-info text-info border',
45
59
  },
46
60
 
47
61
  size: {
@@ -58,9 +72,9 @@
58
72
  <code
59
73
  class={cleanClass(
60
74
  styles({
61
- filled: variant === 'filled',
62
- filledColor: variant === 'filled' && color,
63
- textColor: color,
75
+ filledTheme: variant === 'filled' ? color : false,
76
+ outlineTheme: variant === 'outline' ? color : false,
77
+ ghostTheme: variant === 'ghost' ? color : false,
64
78
  size,
65
79
  }),
66
80
  className,
@@ -4,7 +4,7 @@ import type { HTMLAttributes } from 'svelte/elements';
4
4
  type Props = {
5
5
  color?: TextColor;
6
6
  size?: Size;
7
- variant?: 'filled';
7
+ variant?: 'filled' | 'ghost' | 'outline';
8
8
  class?: string;
9
9
  children: Snippet;
10
10
  } & HTMLAttributes<HTMLElement>;
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ import Card from '../Card/Card.svelte';
3
+ import IconButton from '../IconButton/IconButton.svelte';
4
+ import { theme } from '../../services/theme.svelte.js';
5
+ import { Theme, type TranslationProps } from '../../types.js';
6
+ import { t } from '../../services/translation.svelte.js';
7
+ import { mdiCheckCircle, mdiContentCopy } from '@mdi/js';
8
+ import { Highlight, LineNumbers } from 'svelte-highlight';
9
+ import { typescript, type LanguageType } from 'svelte-highlight/languages';
10
+ import vsLight from 'svelte-highlight/styles/vs';
11
+ import vsDark from 'svelte-highlight/styles/vs2015';
12
+
13
+ type Props = {
14
+ code: string;
15
+ language?: LanguageType<string>;
16
+ lineNumbers?: boolean;
17
+ lightTheme?: string;
18
+ darkTheme?: string;
19
+ copy?: boolean;
20
+ translations?: TranslationProps<'code_copy' | 'code_copied'>;
21
+ };
22
+
23
+ let {
24
+ code,
25
+ copy = true,
26
+ language = typescript,
27
+ lineNumbers,
28
+ lightTheme = vsLight,
29
+ darkTheme = vsDark,
30
+ translations,
31
+ }: Props = $props();
32
+
33
+ let copied = $state(false);
34
+ let canCopy = $derived<boolean>(copy && !!(navigator.clipboard && globalThis.ClipboardItem));
35
+
36
+ const handleCopy = async () => {
37
+ try {
38
+ await navigator.clipboard.writeText(code);
39
+ copied = true;
40
+ setTimeout(() => (copied = false), 3000);
41
+ } catch (error) {
42
+ console.error('Failed to copy code to clipboard', error);
43
+ }
44
+ };
45
+ </script>
46
+
47
+ <svelte:head>
48
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
49
+ {@html theme.value === Theme.Dark ? darkTheme : lightTheme}
50
+ </svelte:head>
51
+
52
+ <Card class="relative">
53
+ <div class="text-sm">
54
+ {#if canCopy}
55
+ <span class="absolute top-2 right-2 cursor-pointer">
56
+ <IconButton
57
+ icon={copied ? mdiCheckCircle : mdiContentCopy}
58
+ size="small"
59
+ aria-label={copied ? t('code_copied', translations) : t('code_copy', translations)}
60
+ variant="ghost"
61
+ color={copied ? 'success' : 'secondary'}
62
+ onclick={handleCopy}
63
+ />
64
+ </span>
65
+ {/if}
66
+ {#if lineNumbers}
67
+ <Highlight {language} {code} let:highlighted>
68
+ <LineNumbers {highlighted} hideBorder wrapLines />
69
+ </Highlight>
70
+ {:else}
71
+ <Highlight {language} {code} />
72
+ {/if}
73
+ </div>
74
+ </Card>
@@ -0,0 +1,14 @@
1
+ import { type TranslationProps } from '../../types.js';
2
+ import { type LanguageType } from 'svelte-highlight/languages';
3
+ type Props = {
4
+ code: string;
5
+ language?: LanguageType<string>;
6
+ lineNumbers?: boolean;
7
+ lightTheme?: string;
8
+ darkTheme?: string;
9
+ copy?: boolean;
10
+ translations?: TranslationProps<'code_copy' | 'code_copied'>;
11
+ };
12
+ declare const CodeBlock: import("svelte").Component<Props, {}, "">;
13
+ type CodeBlock = ReturnType<typeof CodeBlock>;
14
+ export default CodeBlock;
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export { default as CardTitle } from './components/Card/CardTitle.svelte';
25
25
  export { default as Checkbox } from './components/Checkbox/Checkbox.svelte';
26
26
  export { default as CloseButton } from './components/CloseButton/CloseButton.svelte';
27
27
  export { default as Code } from './components/Code/Code.svelte';
28
+ export { default as CodeBlock } from './components/CodeBlock/CodeBlock.svelte';
28
29
  export { default as CommandPalette } from './components/CommandPalette/CommandPalette.svelte';
29
30
  export { default as ConfirmModal } from './components/ConfirmModal/ConfirmModal.svelte';
30
31
  export { default as Container } from './components/Container/Container.svelte';
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ export { default as CardTitle } from './components/Card/CardTitle.svelte';
27
27
  export { default as Checkbox } from './components/Checkbox/Checkbox.svelte';
28
28
  export { default as CloseButton } from './components/CloseButton/CloseButton.svelte';
29
29
  export { default as Code } from './components/Code/Code.svelte';
30
+ export { default as CodeBlock } from './components/CodeBlock/CodeBlock.svelte';
30
31
  export { default as CommandPalette } from './components/CommandPalette/CommandPalette.svelte';
31
32
  export { default as ConfirmModal } from './components/ConfirmModal/ConfirmModal.svelte';
32
33
  export { default as Container } from './components/Container/Container.svelte';
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import type { FontWeight, HeadingColor, HeadingTag, TextVariant } from '../types.js';
2
+ import type { FontWeight, HeadingColor, HeadingTag, Size, TextVariant } from '../types.js';
3
3
  import { cleanClass } from '../utils.js';
4
4
  import type { Snippet } from 'svelte';
5
5
  import type { HTMLAttributes } from 'svelte/elements';
@@ -13,12 +13,13 @@
13
13
  fontWeight?: FontWeight;
14
14
  variant?: TextVariant;
15
15
  color?: HeadingColor;
16
+ size?: Size;
16
17
  class?: string;
17
18
 
18
19
  children: Snippet;
19
20
  } & HTMLAttributes<HTMLElement>;
20
21
 
21
- const { tag = 'p', color, fontWeight, variant, class: className, children, ...restProps }: Props = $props();
22
+ const { tag = 'p', color, fontWeight, variant, size, class: className, children, ...restProps }: Props = $props();
22
23
 
23
24
  const styles = tv({
24
25
  variants: {
@@ -38,13 +39,20 @@
38
39
  bold: 'font-bold',
39
40
  'extra-bold': 'font-extrabold',
40
41
  },
42
+ size: {
43
+ tiny: 'text-xs',
44
+ small: 'text-sm',
45
+ medium: 'text-base',
46
+ large: 'text-lg',
47
+ giant: 'text-xl',
48
+ },
41
49
  variant: {
42
50
  italic: 'italic',
43
51
  },
44
52
  },
45
53
  });
46
54
 
47
- const classList = $derived(cleanClass(styles({ color, fontWeight, variant }), className));
55
+ const classList = $derived(cleanClass(styles({ color, size, fontWeight, variant }), className));
48
56
  </script>
49
57
 
50
58
  <svelte:element this={tag} class={classList} {...restProps}>
@@ -1,4 +1,4 @@
1
- import type { FontWeight, HeadingColor, HeadingTag, TextVariant } from '../types.js';
1
+ import type { FontWeight, HeadingColor, HeadingTag, Size, TextVariant } from '../types.js';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
4
  type Props = {
@@ -9,6 +9,7 @@ type Props = {
9
9
  fontWeight?: FontWeight;
10
10
  variant?: TextVariant;
11
11
  color?: HeadingColor;
12
+ size?: Size;
12
13
  class?: string;
13
14
  children: Snippet;
14
15
  } & HTMLAttributes<HTMLElement>;
@@ -3,6 +3,8 @@ declare const defaultTranslations: {
3
3
  cancel: string;
4
4
  close: string;
5
5
  confirm: string;
6
+ code_copy: string;
7
+ code_copied: string;
6
8
  search_placeholder: string;
7
9
  search_no_results: string;
8
10
  search_recently_used: string;
@@ -3,6 +3,10 @@ const defaultTranslations = {
3
3
  cancel: 'Cancel',
4
4
  close: 'Close',
5
5
  confirm: 'Confirm',
6
+ // code
7
+ code_copy: 'Copy',
8
+ code_copied: 'Copied',
9
+ // search
6
10
  search_placeholder: 'Search...',
7
11
  search_no_results: 'No results',
8
12
  search_recently_used: 'Recently used',
@@ -15,12 +15,15 @@ export declare const Constants: {
15
15
  };
16
16
  Sites: {
17
17
  Api: string;
18
- Demo: string;
19
- My: string;
20
18
  Buy: string;
21
- Get: string;
19
+ Data: string;
20
+ Datasets: string;
21
+ Demo: string;
22
22
  Docs: string;
23
+ Get: string;
24
+ My: string;
23
25
  Store: string;
26
+ Ui: string;
24
27
  };
25
28
  Pages: {
26
29
  CursedKnowledge: string;
@@ -28,6 +31,7 @@ export declare const Constants: {
28
31
  };
29
32
  Npm: {
30
33
  Sdk: string;
34
+ Ui: string;
31
35
  };
32
36
  };
33
37
  export declare const siteCommands: {
@@ -17,12 +17,15 @@ export const Constants = {
17
17
  },
18
18
  Sites: {
19
19
  Api: 'https://api.immich.app/',
20
- Demo: 'https://demo.immich.app/',
21
- My: 'https://my.immich.app/',
22
20
  Buy: 'https://buy.immich.app/',
23
- Get: 'https://get.immich.app/',
21
+ Data: 'https://data.immich.app/',
22
+ Datasets: 'https://datasets.immich.app/',
23
+ Demo: 'https://demo.immich.app/',
24
24
  Docs: 'https://docs.immich.app/',
25
+ Get: 'https://get.immich.app/',
26
+ My: 'https://my.immich.app/',
25
27
  Store: 'https://immich.store/',
28
+ Ui: 'https://ui.immich.app/',
26
29
  },
27
30
  Pages: {
28
31
  CursedKnowledge: 'https://immich.app/cursed-knowledge',
@@ -30,6 +33,7 @@ export const Constants = {
30
33
  },
31
34
  Npm: {
32
35
  Sdk: 'https://www.npmjs.com/package/@immich/sdk',
36
+ Ui: 'https://www.npmjs.com/package/@immich/ui',
33
37
  },
34
38
  };
35
39
  export const siteCommands = [
@@ -73,6 +77,16 @@ export const siteCommands = [
73
77
  description: 'Support the project by purchasing Immich merchandise',
74
78
  href: Constants.Sites.Store,
75
79
  },
80
+ {
81
+ title: 'Immich Datasets',
82
+ description: 'Help improve Immich by contributing your own files',
83
+ href: Constants.Sites.Datasets,
84
+ },
85
+ {
86
+ title: 'Immich UI',
87
+ description: 'View our Svelte component library, @immich/ui',
88
+ href: Constants.Sites.Ui,
89
+ },
76
90
  {
77
91
  title: 'Cursed Knowledge',
78
92
  description: 'View our collection of cursed knowledge',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immich/ui",
3
- "version": "0.30.1",
3
+ "version": "0.31.1",
4
4
  "license": "GNU Affero General Public License version 3",
5
5
  "scripts": {
6
6
  "create": "node scripts/create.js",
@@ -59,7 +59,7 @@
59
59
  "publint": "^0.3.0",
60
60
  "svelte": "^5.37.0",
61
61
  "svelte-check": "^4.0.0",
62
- "svelte-highlight": "^7.8.0",
62
+ "svelte-highlight": "^7.8.4",
63
63
  "tailwindcss": "^4.1.7",
64
64
  "typescript": "^5.0.0",
65
65
  "typescript-eslint": "^8.34.1",