feat: image variants per image
This commit is contained in:
1 parent
f567866161
commit
951fef18ba
92 files changed
+8695
-413
No files matched your search
@@ -0,0 +1,109 @@
|
||||
<script setup lang="ts">
|
||||
import { t } from '@/i18n'
|
||||
|
||||
import { computed } from 'vue'
|
||||
import VariantPaneImage from '@/components/variants/VariantPaneImage.vue'
|
||||
import type { MediaItem } from '@/composables/useMedia'
|
||||
import type { MediaVariantItem } from '@/composables/useMediaVariants'
|
||||
import type { VariantFormat } from '@/composables/useImageVariants'
|
||||
import { formatSize, formatType } from '@/lib/mediaFormat'
|
||||
import { formatLabel, formatVariantSize } from '@/lib/variants/variantFormat'
|
||||
import { savesPercent } from '@/lib/variants/variantSaving'
|
||||
|
||||
const VARIANT_TONE_HASH = '1'
|
||||
const PANE =
|
||||
'flex overflow-auto border border-default bg-muted h-45 items-start justify-start sm:h-75 sm:items-center sm:justify-center'
|
||||
|
||||
const props = defineProps<{ variant: MediaVariantItem; original: MediaItem }>()
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false })
|
||||
|
||||
const variantSize = computed(() => props.variant.size ?? 0)
|
||||
const variantTitle = computed(
|
||||
() =>
|
||||
`${props.variant.name} · ${props.variant.output_width}×${props.variant.output_height} · ${formatLabel(props.variant.output_format as VariantFormat)}`,
|
||||
)
|
||||
const variantSub = computed(() =>
|
||||
t('{0} · saves {1}%', [
|
||||
formatVariantSize(variantSize.value),
|
||||
savesPercent(props.original.size, variantSize.value),
|
||||
]),
|
||||
)
|
||||
const originalTitle = computed(
|
||||
() =>
|
||||
`${t('Original')} · ${props.original.width ?? 0}×${props.original.height ?? 0} · ${formatType(props.original.content_type)}`,
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal
|
||||
v-model:open="open"
|
||||
:title="t('Preview: {0}', [variant.name])"
|
||||
:description="t('Both images are shown at actual size. Scroll to pan.')"
|
||||
:ui="{
|
||||
content:
|
||||
'sm:top-20 sm:translate-y-0 sm:max-w-220 max-sm:!inset-x-4 max-sm:!top-auto max-sm:!bottom-4 max-sm:!w-auto max-sm:!max-w-none max-sm:!translate-x-0 max-sm:!translate-y-0 divide-y-0 shadow-(--shadow-modal) ring-0',
|
||||
header: 'min-h-0 px-6 pt-5 pb-0 sm:px-6',
|
||||
close: 'top-5 end-6',
|
||||
title: 'text-lg/6 font-semibold',
|
||||
description: 'sr-only',
|
||||
body: 'px-6 pt-5 pb-0 sm:px-6 sm:pt-5 sm:pb-0',
|
||||
footer: 'px-6 py-5 sm:px-6',
|
||||
}"
|
||||
>
|
||||
<template #body>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<div class="flex min-w-0 flex-col gap-2">
|
||||
<div :class="PANE" data-testid="preview-variant-pane">
|
||||
<VariantPaneImage
|
||||
:src="variant.url"
|
||||
:width="variant.output_width"
|
||||
:height="variant.output_height"
|
||||
:content-type="original.content_type"
|
||||
:sha256="VARIANT_TONE_HASH"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-semibold text-highlighted">{{ variantTitle }}</span>
|
||||
<span class="text-xs/5 text-toned">{{ variantSub }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex min-w-0 flex-col gap-2">
|
||||
<div :class="PANE" data-testid="preview-original-pane">
|
||||
<VariantPaneImage
|
||||
:src="original.url"
|
||||
:width="original.width ?? 0"
|
||||
:height="original.height ?? 0"
|
||||
:content-type="original.content_type"
|
||||
:sha256="original.sha256"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-semibold text-highlighted">{{ originalTitle }}</span>
|
||||
<span class="text-xs/5 text-toned">{{
|
||||
formatSize(original.size)
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs/5 text-muted">
|
||||
{{ t('Both images are shown at actual size. Scroll to pan.') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex w-full flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
block
|
||||
class="h-11 justify-center border border-accented bg-default text-sm text-highlighted ring-0 sm:h-8 sm:w-auto sm:px-3"
|
||||
@click="open = false"
|
||||
>
|
||||
{{ t('Close') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
Reference in new issue
Block a user