Show copyable share links after batch upload completes.

Add share results panel gated by showShareLinks, build URLs from queue entry secrets, and align file name handling with the metadata inspector.
This commit is contained in:
2026-10-25 22:00:16 +01:00
parent f305ce7a39
commit f5be0a0de3
4 changed files with 173 additions and 3 deletions
@@ -0,0 +1,77 @@
<template>
<label class="flex flex-col gap-1.5 text-xs">
<span class="font-medium text-muted-foreground">{{ label }}</span>
<div class="flex gap-2">
<input
type="text"
readonly
class="min-w-0 flex-1 rounded-md border border-input bg-muted/40 px-3 py-2 font-mono text-xs text-foreground"
:value="value"
/>
<button
type="button"
class="shrink-0 rounded-md border border-border px-3 py-2 text-xs font-medium transition-colors hover:bg-muted/60"
@click="onCopyClick"
>
{{ copied ? 'Copied' : 'Copy' }}
</button>
</div>
</label>
</template>
<script setup lang="ts">
import { onUnmounted, ref, watch } from 'vue';
const COPIED_RESET_MS = 1000;
const props = defineProps({
label: {
type: String,
required: true
},
value: {
type: String,
required: true
}
});
const copied = ref(false);
let copiedResetTimeout: ReturnType<typeof setTimeout> | undefined;
// component stay mounted when user switching between images so we need to reset the copied state when the value changes
watch(
() => props.value,
() => resetCopied()
);
onUnmounted(() => clearCopiedResetTimeout());
const clearCopiedResetTimeout = (): void => {
if (copiedResetTimeout !== undefined) {
clearTimeout(copiedResetTimeout);
copiedResetTimeout = undefined;
}
};
const resetCopied = (): void => {
clearCopiedResetTimeout();
copied.value = false;
};
const onCopyClick = async (): Promise<void> => {
try {
await navigator.clipboard.writeText(props.value);
copied.value = true;
clearCopiedResetTimeout();
copiedResetTimeout = setTimeout(() => {
copied.value = false;
}, COPIED_RESET_MS);
} catch (error) {
console.error('[ShareLinkField] copy failed', error);
}
};
</script>