diff --git a/apps/desktop/src/components/ImageDiff.svelte b/apps/desktop/src/components/ImageDiff.svelte new file mode 100644 index 0000000000..fbc2244fc5 --- /dev/null +++ b/apps/desktop/src/components/ImageDiff.svelte @@ -0,0 +1,197 @@ + + +{#if loadError} +
+ + {#snippet caption()} + Can't preview this file type + {/snippet} + +
+{:else} + +{/if} + + diff --git a/apps/desktop/src/components/UnifiedDiffView.svelte b/apps/desktop/src/components/UnifiedDiffView.svelte index 452c3729d1..94b596b858 100644 --- a/apps/desktop/src/components/UnifiedDiffView.svelte +++ b/apps/desktop/src/components/UnifiedDiffView.svelte @@ -1,5 +1,6 @@ + +{#snippet imageDimensions(metadata: ImageMetadata | null)} + {#if metadata} + + {metadata.width}×{metadata.height} + {#if metadata.size} + · {formatFileSize(metadata.size)} + {/if} + + {/if} +{/snippet} + +{#snippet sizeDifference()} + {#if beforeImageMetadata?.size && afterImageMetadata?.size} + · + beforeImageMetadata.size} + > + {formatSizeDifference(beforeImageMetadata.size, afterImageMetadata.size)} + {#if afterImageMetadata.size < beforeImageMetadata.size} + + {:else if afterImageMetadata.size > beforeImageMetadata.size} + + {/if} + + {/if} +{/snippet} + +{#snippet comparisonFooter()} + +{/snippet} + +{#snippet imagePanel(props: { + url: string; + label: string; + isBefore?: boolean; + metadata: ImageMetadata | null; +})} +
+
+ {fileName} ({props.label}) +
+ + +
+{/snippet} + +{#snippet swipe(props: { controlValue: number; onValueChange: (value: number) => void })} +
+
+
+ {fileName} (After) +
+
+ {fileName} (Before) +
+
+
+
+
+
+ {@render comparisonFooter()} +
+{/snippet} + +{#snippet onionSkin(props: { controlValue: number; onValueChange: (value: number) => void })} +
+
+
+ {fileName} (After) +
+
+ {fileName} (Before) +
+
+
+ Before + + After +
+ {@render comparisonFooter()} +
+{/snippet} + +
+ {#if beforeImageUrl && afterImageUrl && !isLoading} +
+ (viewMode = id as ViewMode)}> + 2-up + Swipe + Onion Skin + +
+ {/if} + +
+ {#if isLoading} +
+ + +
+
+ + +
+ {:else if beforeImageUrl || afterImageUrl} + {#if viewMode === '2-up'} + {#if beforeImageUrl} + {@render imagePanel({ + url: beforeImageUrl, + label: afterImageUrl ? 'Before' : 'Removed', + isBefore: true, + metadata: beforeImageMetadata + })} + {/if} + + {#if afterImageUrl} + {@render imagePanel({ + url: afterImageUrl, + label: beforeImageUrl ? 'After' : 'Added', + metadata: afterImageMetadata + })} + {/if} + {:else if viewMode === 'swipe' && beforeImageUrl && afterImageUrl} + {@render swipe({ + controlValue: swipePosition, + onValueChange: (value) => (swipePosition = value) + })} + {:else if viewMode === 'onion-skin' && beforeImageUrl && afterImageUrl} + {@render onionSkin({ + controlValue: onionOpacity, + onValueChange: (value) => (onionOpacity = value) + })} + {/if} + {/if} +
+
+ + diff --git a/packages/ui/src/lib/components/RangeInput.svelte b/packages/ui/src/lib/components/RangeInput.svelte index 2eb6ca4458..a0c27a768b 100644 --- a/packages/ui/src/lib/components/RangeInput.svelte +++ b/packages/ui/src/lib/components/RangeInput.svelte @@ -40,8 +40,8 @@ onchange }: Props = $props(); - // Calculate the percentage for the fill effect - let percentage = $derived(((value - min) / (max - min)) * 100); + // Calculate the fill ratio (0-1) + let fillRatio = $derived((value - min) / (max - min));
{/if} -
-
-
-
-
-
- - { - oninput?.(parseFloat(e.currentTarget.value)); - }} - onchange={(e) => { - onchange?.(parseFloat(e.currentTarget.value)); - }} - /> -
+ { + oninput?.(parseFloat(e.currentTarget.value)); + }} + onchange={(e) => { + onchange?.(parseFloat(e.currentTarget.value)); + }} + /> {#if error}

{error}

@@ -99,11 +92,10 @@ diff --git a/packages/ui/src/lib/components/SkeletonBone.svelte b/packages/ui/src/lib/components/SkeletonBone.svelte index 2314a50055..26d24228cd 100644 --- a/packages/ui/src/lib/components/SkeletonBone.svelte +++ b/packages/ui/src/lib/components/SkeletonBone.svelte @@ -12,7 +12,7 @@ height = '1rem', radius = 'var(--radius-ml)', color = 'var(--clr-scale-ntrl-70)', - opacity = 0.35 + opacity = 0.34 }: Props = $props(); @@ -35,7 +35,7 @@ opacity: var(--opacity-value); } 100% { - opacity: calc(var(--opacity-value) + var(--opacity-value) * 0.5); + opacity: calc(var(--opacity-value) + var(--opacity-value) * 0.7); } } diff --git a/packages/ui/src/lib/index.ts b/packages/ui/src/lib/index.ts index c93213726a..167feb8f59 100644 --- a/packages/ui/src/lib/index.ts +++ b/packages/ui/src/lib/index.ts @@ -18,6 +18,7 @@ export { default as EditorLogo } from '$components/EditorLogo.svelte'; export { default as EmptyStatePlaceholder } from '$components/EmptyStatePlaceholder.svelte'; export { default as HunkDiff, type LineClickParams } from '$components/hunkDiff/HunkDiff.svelte'; export { default as Icon, type IconName } from '$components/Icon.svelte'; +export { default as ImageDiff } from '$components/ImageDiff.svelte'; export { default as InfoButton } from '$components/InfoButton.svelte'; export { default as InfoMessage, type MessageStyle } from '$components/InfoMessage.svelte'; export { diff --git a/packages/ui/src/stories/components/ImageDiff.stories.svelte b/packages/ui/src/stories/components/ImageDiff.stories.svelte new file mode 100644 index 0000000000..bf61a3bd7f --- /dev/null +++ b/packages/ui/src/stories/components/ImageDiff.stories.svelte @@ -0,0 +1,64 @@ + + + + {#snippet template(args)} + + {/snippet} + + + + {#snippet template(args)} + + {/snippet} + + + + {#snippet template(args)} + + {/snippet} + + + + {#snippet template(args)} + + {/snippet} +