feat(SPA): media page T0
This commit is contained in:
1 parent
0d99544579
commit
67d456baf6
32 files changed
+4874
-40
No files matched your search
@@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import AppLogo from '@/components/AppLogo.vue'
|
||||
|
||||
const TONE_COUNT = 4
|
||||
const HEX_RADIX = 16
|
||||
const ALPHA_TYPES = ['image/png', 'image/svg+xml']
|
||||
const SVG_TYPE = 'image/svg+xml'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
item: { url: string; content_type: string; sha256: string }
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl'
|
||||
}>(),
|
||||
{ size: 'lg' },
|
||||
)
|
||||
|
||||
const loaded = ref(false)
|
||||
const failed = ref(false)
|
||||
|
||||
const hasAlpha = computed(() => ALPHA_TYPES.includes(props.item.content_type))
|
||||
const isSvg = computed(() => props.item.content_type === SVG_TYPE)
|
||||
const tone = computed(() => {
|
||||
const digit = Number.parseInt(props.item.sha256.charAt(0), HEX_RADIX)
|
||||
return Number.isNaN(digit) ? 0 : digit % TONE_COUNT
|
||||
})
|
||||
const iconClass = computed(
|
||||
() => ({ sm: 'size-4', md: 'size-5', lg: 'size-6', xl: 'size-10' })[props.size],
|
||||
)
|
||||
const logoSize = computed(() => ({ sm: 16, md: 20, lg: 28, xl: 40 })[props.size])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
data-testid="media-thumb"
|
||||
class="relative flex shrink-0 items-center justify-center overflow-hidden text-muted"
|
||||
:class="hasAlpha ? 'media-thumb-checker' : ['media-thumb-tone', `media-thumb-tone-${tone}`]"
|
||||
>
|
||||
<span v-if="!loaded" aria-hidden="true" class="absolute flex">
|
||||
<AppLogo v-if="isSvg" :size="logoSize" aria-hidden="true" />
|
||||
<UIcon v-else name="i-lucide-image" class="opacity-55" :class="iconClass" />
|
||||
</span>
|
||||
<img
|
||||
v-if="!failed"
|
||||
:src="item.url"
|
||||
alt=""
|
||||
loading="lazy"
|
||||
class="absolute inset-0 size-full object-cover"
|
||||
@load="loaded = true"
|
||||
@error="failed = true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.media-thumb-checker {
|
||||
background: conic-gradient(
|
||||
var(--ui-bg-accented) 25%,
|
||||
var(--ui-bg) 0 50%,
|
||||
var(--ui-bg-accented) 0 75%,
|
||||
var(--ui-bg) 0
|
||||
)
|
||||
0 0 / 16px 16px;
|
||||
}
|
||||
.media-thumb-tone {
|
||||
background-image: repeating-linear-gradient(
|
||||
135deg,
|
||||
color-mix(in srgb, var(--ui-text-muted) 12%, transparent) 0 1px,
|
||||
transparent 1px 12px
|
||||
);
|
||||
}
|
||||
.media-thumb-tone-0 {
|
||||
background-color: var(--ui-color-secondary-200);
|
||||
}
|
||||
.dark .media-thumb-tone-0 {
|
||||
background-color: var(--ui-color-secondary-300);
|
||||
}
|
||||
.media-thumb-tone-1 {
|
||||
background-color: var(--ui-bg-accented);
|
||||
}
|
||||
.media-thumb-tone-2 {
|
||||
background-color: color-mix(in srgb, var(--ui-border-accented) 35%, var(--ui-bg));
|
||||
}
|
||||
.media-thumb-tone-3 {
|
||||
background-color: var(--ui-bg-elevated);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user