💄 Optimize the post item

This commit is contained in:
2025-12-27 13:07:27 +08:00
parent cdf177d321
commit f8af7bfd36
4 changed files with 30 additions and 49 deletions

View File

@@ -50,45 +50,18 @@ import type { SnAttachment } from "~/types/api"
const props = defineProps<{ const props = defineProps<{
item: SnAttachment item: SnAttachment
original?: boolean original?: boolean
maxHeight?: string maxHeight?: number
}>() }>()
const itemType = computed(() => props.item.mimeType.split("/")[0] ?? "unknown") const itemType = computed(() => props.item.mimeType.split("/")[0] ?? "unknown")
const blurhash = computed(() => props.item.fileMeta?.blur) const blurhash = computed(() => props.item.fileMeta?.blur)
const imageWidth = computed(() => props.item.fileMeta?.width)
const imageHeight = computed(() => props.item.fileMeta?.height) const imageHeight = computed(() => props.item.fileMeta?.height)
const aspectRatio = computed( const aspectRatio = computed(
() => () =>
props.item.fileMeta?.ratio ?? props.item.fileMeta?.ratio ?? null
(imageWidth.value && imageHeight.value
? imageHeight.value / imageWidth.value
: null)
) )
const imageLoaded = ref(false) const imageLoaded = ref(false)
const router = useRouter()
function openExternally() {
// Capture image position for transition
const img = event?.target as HTMLImageElement
if (img && itemType.value === "image") {
const rect = img.getBoundingClientRect()
const transitionData = {
src: remoteSource.value,
x: rect.left,
y: rect.top,
width: rect.width,
height: rect.height,
aspectRatio: aspectRatio.value == null ? 0 : aspectRatio.value
}
// Store transition data
sessionStorage.setItem("imageTransition", JSON.stringify(transitionData))
}
router.push("/files/" + props.item.id)
}
const blurCanvas = ref<HTMLCanvasElement | null>(null) const blurCanvas = ref<HTMLCanvasElement | null>(null)
const apiBase = useSolarNetworkUrl() const apiBase = useSolarNetworkUrl()
@@ -108,8 +81,8 @@ const blurhashContainerStyle = computed(() => {
const containerStyle = computed(() => { const containerStyle = computed(() => {
return { return {
maxHeight: props.maxHeight ?? "720px", maxHeight: Math.min(props.maxHeight ?? 720, imageHeight.value).toString() + "px",
aspectRatio: aspectRatio.value?.toString() aspectRatio: aspectRatio.value != null ? aspectRatio.value.toString() : void 0
} }
}) })

View File

@@ -62,24 +62,28 @@ const carouselHeight = computed(() => {
if (!isAllImages.value) return Math.min(400, props.maxHeight || 400) if (!isAllImages.value) return Math.min(400, props.maxHeight || 400)
const aspectRatio = calculateAspectRatio() const aspectRatio = calculateAspectRatio()
if (aspectRatio == null) return null
// Use a base width of 600px for calculation, adjust height accordingly // Use a base width of 600px for calculation, adjust height accordingly
const baseWidth = 600 const baseWidth = 600
const calculatedHeight = Math.round(baseWidth / aspectRatio) const calculatedHeight = Math.round(baseWidth / aspectRatio)
// Respect maxHeight constraint if provided // Respect maxHeight constraint if provided
const constrainedHeight = props.maxHeight return props.maxHeight
? Math.min(calculatedHeight, props.maxHeight) ? Math.min(calculatedHeight, props.maxHeight)
: calculatedHeight : calculatedHeight
return constrainedHeight
}) })
const carouselStyle = computed(() => { const carouselStyle = computed(() => {
if (!isAllImages.value) return {} if (!isAllImages.value) return {}
const aspectRatio = calculateAspectRatio() const aspectRatio = calculateAspectRatio()
if (aspectRatio == null) {
return {}
}
const height = carouselHeight.value const height = carouselHeight.value
const width = Math.round(height * aspectRatio) const width = Math.round(height! * aspectRatio)
return { return {
width: `${width}px`, width: `${width}px`,
@@ -88,7 +92,7 @@ const carouselStyle = computed(() => {
} }
}) })
function calculateAspectRatio(): number { function calculateAspectRatio(): number | null {
const ratios: number[] = [] const ratios: number[] = []
// Collect all valid ratios // Collect all valid ratios
@@ -110,8 +114,7 @@ function calculateAspectRatio(): number {
} }
if (ratios.length === 0) { if (ratios.length === 0) {
// Default to 4:3 aspect ratio when no valid ratios found return null
return 4 / 3
} }
if (ratios.length === 1 && ratios[0]) { if (ratios.length === 1 && ratios[0]) {

View File

@@ -86,14 +86,19 @@
</div> </div>
<!-- Post Reactions --> <!-- Post Reactions -->
<div v-if="!compact" @click.stop> <div class="flex gap-2">
<post-reaction-list <n-tag type="success">
:parent-id="props.item.id" <template #icon>
:reactions="props.item.reactionsCount" <n-icon :component="ArrowUpIcon" />
:reactions-made="props.item.reactionsMade" </template>
:can-react="true" {{ props.item.upvotes }}
@react="handleReaction" </n-tag>
/> <n-tag type="error">
<template #icon>
<n-icon :component="ArrowDownIcon" />
</template>
{{ props.item.downvotes }}
</n-tag>
</div> </div>
</div> </div>
</n-card> </n-card>
@@ -104,7 +109,7 @@ import { ref, watch } from "vue"
import { useMarkdownProcessor } from "~/composables/useMarkdownProcessor" import { useMarkdownProcessor } from "~/composables/useMarkdownProcessor"
import type { SnPost } from "~/types/api" import type { SnPost } from "~/types/api"
import { useIntersectionObserver } from "@vueuse/core" import { useIntersectionObserver } from "@vueuse/core"
import { ForwardIcon, ReplyIcon } from "lucide-vue-next" import { ForwardIcon, ReplyIcon, ArrowUpIcon, ArrowDownIcon } from "lucide-vue-next"
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@@ -133,7 +138,6 @@ function handleReaction(symbol: string, attitude: number, delta: number) {
} }
function handleReplyReaction( function handleReplyReaction(
postId: string,
symbol: string, symbol: string,
attitude: number, attitude: number,
delta: number delta: number

View File

@@ -24,6 +24,7 @@
"cfturnstile-vue3": "^2.0.0", "cfturnstile-vue3": "^2.0.0",
"eslint": "^9.39.1", "eslint": "^9.39.1",
"highlightjs": "^9.16.2", "highlightjs": "^9.16.2",
"html2canvas": "^1.4.1",
"katex": "^0.16.25", "katex": "^0.16.25",
"lucide-vue-next": "^0.555.0", "lucide-vue-next": "^0.555.0",
"luxon": "^3.7.2", "luxon": "^3.7.2",
@@ -52,4 +53,4 @@
"unplugin-auto-import": "^20.3.0", "unplugin-auto-import": "^20.3.0",
"unplugin-vue-components": "^30.0.0" "unplugin-vue-components": "^30.0.0"
} }
} }