Files
RenewCMS/web/src/components/variants/VariantPreview.vue
T

133 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { t } from '@/i18n'
import { computed, ref } from 'vue'
import ImageCompare from '@/components/variants/ImageCompare.vue'
import { useCopyToClipboard } from '@/composables/useCopyToClipboard'
import { useVariantRender } from '@/composables/useVariantRender'
import {
SAMPLE_SOURCE,
estimateLabel,
estimateVariant,
type EstimateRequest,
} from '@/lib/variants/variantEstimate'
import { parseDimension, sliderValue, type VariantFormValues } from '@/lib/variants/variantForm'
import { formatVariantSize } from '@/lib/variants/variantFormat'
const URL_PREFIX = '/static/uploadedImages/'
const NAME_PLACEHOLDER = '<name>'
const props = defineProps<{
values: VariantFormValues
disabled: boolean
}>()
const position = ref(50)
const { copied, copy } = useCopyToClipboard()
const dimensionsAreValid = computed(
() =>
(props.values.width.trim() === '' || parseDimension(props.values.width) !== null) &&
(props.values.height.trim() === '' || parseDimension(props.values.height) !== null),
)
const request = computed<EstimateRequest | null>(() =>
dimensionsAreValid.value
? {
width: parseDimension(props.values.width),
height: parseDimension(props.values.height),
fit: props.values.fit,
format: props.values.format,
quality: sliderValue(props.values.quality),
}
: null,
)
const estimate = computed(() => (request.value ? estimateVariant(request.value) : null))
const { original, variant } = useVariantRender(request)
const shownName = computed(() => props.values.name || t('name'))
const outputLine = computed(() => {
if (!estimate.value) {
return t('No output yet')
}
const bytes = variant.value
? Math.min(SAMPLE_SOURCE.bytes, variant.value.bytes)
: estimate.value.bytes
return estimateLabel({ size: estimate.value.size, bytes })
})
const originalLine = computed(
() =>
`${SAMPLE_SOURCE.width} × ${SAMPLE_SOURCE.height} · ${formatVariantSize(SAMPLE_SOURCE.bytes)}`,
)
const hasName = computed(() => props.values.name !== '')
const url = computed(
() => `${URL_PREFIX}${SAMPLE_SOURCE.filename}?v=${props.values.name || NAME_PLACEHOLDER}`,
)
async function onCopy() {
try {
await copy(url.value)
} catch {
return
}
}
</script>
<template>
<div class="flex min-w-0 flex-col gap-3">
<div class="flex items-baseline gap-2">
<h3 class="flex-1 font-semibold text-highlighted">{{ t('Preview') }}</h3>
<span class="text-xs/5 text-muted">{{
t('Sample: {0}', [SAMPLE_SOURCE.filename])
}}</span>
</div>
<ImageCompare
v-model="position"
:name="values.name"
:comparable="estimate !== null"
:original-src="original"
:variant-src="variant?.url ?? null"
/>
<div class="grid grid-cols-2 gap-3">
<div class="flex flex-col">
<span class="font-medium text-highlighted">{{ t('Original') }}</span>
<span class="text-xs/5 text-muted">{{ originalLine }}</span>
</div>
<div class="flex flex-col">
<span class="font-mono font-medium text-highlighted">{{ shownName }}</span>
<span class="text-xs/5 text-muted">{{ outputLine }}</span>
</div>
</div>
<p class="text-xs/5 text-muted">
{{
t(
'Drag the divider, or focus it and use the arrow keys. The estimate comes from a sample; output is never larger than the source.',
)
}}
</p>
<div class="flex flex-col gap-1.5">
<span class="font-medium text-highlighted">{{ t('URL') }}</span>
<div class="flex gap-2">
<div
data-testid="variant-url"
class="flex min-h-11 min-w-0 flex-1 items-center truncate border border-default bg-elevated px-3 font-mono text-xs sm:min-h-8"
:class="hasName ? 'text-highlighted' : 'text-muted'"
>
{{ url }}
</div>
<UButton
color="neutral"
variant="outline"
:icon="copied ? 'i-lucide-check' : 'i-lucide-copy'"
:disabled="!hasName || disabled"
class="h-11 shrink-0 gap-1.5 border border-accented bg-default px-3 text-sm text-highlighted ring-0 sm:h-8"
@click="onCopy"
>
{{ copied ? t('Copied') : t('Copy') }}
</UButton>
</div>
</div>
</div>
</template>