Skip to content

Commit

Permalink
Refactor feed components to improve layout and dynamic sizing
Browse files Browse the repository at this point in the history
Adjust media height and layout styles for better responsiveness across devices. Refactor VirtualScroll to streamline logic and add dynamic item height handling. Update FeedPageContent to simplify item filtering and integrate dynamic item height calculations.
  • Loading branch information
kazuyoshi80 committed Feb 5, 2025
1 parent 3920967 commit 9393a5b
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 30 deletions.
38 changes: 33 additions & 5 deletions src/components/Feed/Feed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import MediaCard from '@pages/passport/components/MediaCard.vue'
import { MediaEmbed } from '@devprotocol/clubs-plugin-passports/vue'
import type { PassportItemAssetType } from '@devprotocol/clubs-plugin-passports/types'
import type { FeedType } from '@fixtures/api/feed'
import { computed } from 'vue'
import { computed, onMounted, ref } from 'vue'
import { itemToHash } from '@fixtures/router/passportItem'
const props = defineProps<FeedType>()
Expand All @@ -12,10 +12,17 @@ const assetLink = computed(
() =>
`/passport/${props.address}/${props.parentPassportIndex === 0 ? '' : props.parentPassport.id}?i=${itemToHash(props.clipType, props.item.id)}`,
)
const mediaHeight = ref(0)
// PCの場合200px、スマホの場合110px
onMounted(() => {
mediaHeight.value = window.innerWidth > 768 ? 200 : 110
})
</script>

<template>
<div class="grid gap-2 p-2 border-b boder-black/20">
<div class="grid gap-2 p-2 h-full border-b boder-black/20">
<div class="flex flex-col gap-2">
<div class="grid grid-cols-[auto_1fr] items-center gap-3">
<a :href="`/passport/${address}`">
Expand Down Expand Up @@ -45,7 +52,7 @@ const assetLink = computed(
</div>
</div>

<div class="grid gap-2 grid-cols-2 rounded">
<div class="flex-grow grid gap-2 grid-cols-2 rounded">
<div class="flex flex-col gap-1">
<div
v-if="description"
Expand Down Expand Up @@ -83,6 +90,7 @@ const assetLink = computed(
<a
:href="assetLink"
target="_blank"
class="flex items-end"
:class="{ 'p-3 rounded': frameHexColor }"
:style="
frameHexColor
Expand All @@ -100,7 +108,7 @@ const assetLink = computed(
:found="!!assetSrc"
/>
</div>
<div v-if="tag === 'ugc'" class="rounded-xl bg-violet-50 p-2">
<div v-if="tag === 'ugc'" class="media-wrapper p-2 rounded-xl bg-violet-50" :style="{ height: `${mediaHeight}px` }">
<MediaEmbed
class="w-full rounded-xl aspect-[3/2] mx-auto max-w-40 lg:max-w-xs pointer-events-none overflow-hidden"
:found="!!assetSrc"
Expand All @@ -115,4 +123,24 @@ const assetLink = computed(
</div>
</template>

<style scoped lang="scss"></style>
<style lang="scss">
.instagram-media {
min-width: auto !important;
}
.twitter-tweet {
margin-top: 0 !important;
margin-bottom: 0 !important;
}
#twitter-widget-0 {
width: 100% !important;
}
</style>

<style scoped lang="scss">
.media-wrapper {
overflow-y: auto;
scrollbar-width: none;
}
</style>
16 changes: 8 additions & 8 deletions src/components/Feed/FeedPageContent.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script setup lang="ts">
import Feed from '@components/Feed/Feed.vue'
import type { FeedType } from '../../fixtures/api/feed'
import { computed, ref, watch } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import { set } from 'es-cookie'
import { CookieKey } from '@constants/cookie'
import { Mode } from '@constants/feeds'
Expand All @@ -21,11 +20,6 @@ const feedsByMode = ref<Record<Mode, FeedType[]>>({
const switchingTo = ref<Mode>()
const items = computed(() => feedsByMode.value[mode.value])
// itemsのtagsがugc以外をfilterして返す
const ugcItems = computed(() =>
feedsByMode.value[mode.value].filter((item) => item.tag === 'ugc'),
)
const changeMode = async (newmode: Mode) => {
switchingTo.value = newmode
if (feedsByMode.value[newmode].length > 0) {
Expand All @@ -47,6 +41,12 @@ const changeMode = async (newmode: Mode) => {
watch(mode, (mode_) => {
set(CookieKey.DefaultFeed, mode_)
})
const itemHeight = ref(278)
onMounted(() => {
itemHeight.value = window.innerWidth > 768 ? 278 : 180
})
</script>
<template>
<nav>
Expand Down Expand Up @@ -97,7 +97,7 @@ watch(mode, (mode_) => {
class="flex flex-col gap-2 flex-grow h-full transition"
:class="{ 'opacity-70': switchingTo && switchingTo !== mode }"
>
<VirtualScroll :items="ugcItems" :itemHeight="195" :buffer="1" />
<VirtualScroll :items="items" :itemHeight="itemHeight" :buffer="1" />
</div>
</div>
</template>
20 changes: 3 additions & 17 deletions src/components/Feed/VirtualScroll.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,37 @@ import { ref, computed, onMounted, watch } from 'vue'
import type { FeedType } from '@fixtures/api/feed'
import Feed from '@components/Feed/Feed.vue'
// プロパティの型定義
interface Props<T extends FeedType> {
items: T[]
itemHeight: number // アイテムの高さ
buffer: number // 表示範囲外のアイテム数
itemHeight: number
buffer: number
}
// プロパティの宣言
const props = defineProps<Props<FeedType>>()
// DOM要素の参照
const container = ref<HTMLElement | null>(null)
// スクロール位置の保存
const scrollTop = ref(0)
// 全体の高さを計算
const totalHeight = computed(() => props.items.length * props.itemHeight)
// 可視アイテムの数を計算
const visibleCount = computed(() => {
if (!container.value) return 0
return (
Math.ceil(container.value.clientHeight / props.itemHeight) + props.buffer
)
})
// 可視アイテムの開始インデックスを計算
const startIndex = computed(() => {
return Math.max(
0,
Math.floor(scrollTop.value / props.itemHeight) - props.buffer,
)
})
// 可視アイテムの終了インデックスを計算
const endIndex = computed(() => {
return Math.min(props.items.length, startIndex.value + visibleCount.value)
})
// 可視アイテムを計算
const visibleItems = computed(() => {
return props.items
.slice(startIndex.value, endIndex.value)
Expand All @@ -52,7 +43,6 @@ const visibleItems = computed(() => {
}))
})
// スクロールイベントハンドラ
const onScroll = () => {
if (container.value) {
scrollTop.value = container.value.scrollTop
Expand All @@ -68,14 +58,12 @@ const throttledOnScroll = () => {
scrollTimeout = window.setTimeout(onScroll, 16)
}
// マウント時にスクロール位置を初期化
onMounted(() => {
if (container.value) {
scrollTop.value = container.value.scrollTop
}
})
// スクロール位置やアイテムの変更を監視
watch([scrollTop, () => props.items], () => {
if (container.value) {
container.value.scrollTop = scrollTop.value
Expand All @@ -89,15 +77,13 @@ watch([scrollTop, () => props.items], () => {
ref="container"
@scroll="throttledOnScroll"
>
<!-- スクロールスペーサー。全体の高さを設定 -->
<div class="spacer" :style="{ height: totalHeight + 'px' }"></div>

<!-- 可視アイテムをレンダリング -->
<div
class="item"
v-for="feed in visibleItems"
:key="feed.id"
:style="{ top: `${feed.offset}px` }"
:style="{ top: `${feed.offset}px`, height: `${props.itemHeight}px` }"
>
<Feed :key="feed.id" v-bind="feed" />
</div>
Expand Down

0 comments on commit 9393a5b

Please sign in to comment.