✨ Rewind renders most of the data
This commit is contained in:
97
app/components/Post/PostItemContained.vue
Normal file
97
app/components/Post/PostItemContained.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div v-if="loading" class="flex justify-center items-center py-4">
|
||||
<n-spin size="large" />
|
||||
</div>
|
||||
<div v-else-if="error" class="text-red-500 text-center py-4">
|
||||
{{ error }}
|
||||
</div>
|
||||
<post-item
|
||||
v-else-if="post"
|
||||
:item="post"
|
||||
:compact="compact"
|
||||
:flat="flat"
|
||||
:slim="slim"
|
||||
:show-referenced="showReferenced"
|
||||
@react="handleReaction"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from "vue"
|
||||
import { useSolarNetwork } from "~/composables/useSolarNetwork"
|
||||
import type { SnPost } from "~/types/api"
|
||||
import PostItem from "./PostItem.vue"
|
||||
import { keysToCamel } from "~/utils/transformKeys"
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
postId: string
|
||||
showReferenced?: boolean
|
||||
compact?: boolean
|
||||
flat?: boolean
|
||||
slim?: boolean
|
||||
}>(),
|
||||
{ showReferenced: true, compact: false, flat: false, slim: false }
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
react: [symbol: string, attitude: number, delta: number]
|
||||
loaded: [post: SnPost]
|
||||
}>()
|
||||
|
||||
const api = useSolarNetwork()
|
||||
const post = ref<SnPost | null>(null)
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
const fetchPost = async () => {
|
||||
if (!props.postId) {
|
||||
error.value = "No post ID provided"
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
const response = await api<SnPost>(`/sphere/posts/${props.postId}`, {
|
||||
method: "GET",
|
||||
onResponse({ response }) {
|
||||
if (response._data) {
|
||||
response._data = keysToCamel(response._data)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
post.value = response
|
||||
emit("loaded", response)
|
||||
} catch (err) {
|
||||
console.error("Error fetching post:", err)
|
||||
error.value = err instanceof Error ? err.message : "Failed to fetch post"
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleReaction = (symbol: string, attitude: number, delta: number) => {
|
||||
emit("react", symbol, attitude, delta)
|
||||
}
|
||||
|
||||
// Watch for postId changes and refetch
|
||||
watch(
|
||||
() => props.postId,
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
fetchPost()
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// Initial fetch on mount
|
||||
onMounted(() => {
|
||||
if (props.postId) {
|
||||
fetchPost()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
41
app/components/account/account-nameplate.vue
Normal file
41
app/components/account/account-nameplate.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<n-card>
|
||||
<div class="flex flex-col justify-center gap-4">
|
||||
<img
|
||||
v-if="userBackground"
|
||||
:src="userBackground"
|
||||
style="aspect-ratio: 16/7"
|
||||
class="rounded-xl"
|
||||
/>
|
||||
<div class="flex items-center gap-4">
|
||||
<n-avatar :src="userPicture" />
|
||||
<div class="grow">
|
||||
<div class="font-bold text-lg">{{ data.nick }}</div>
|
||||
<div class="text-sm opacity-80">@{{ data.name }}</div>
|
||||
</div>
|
||||
<div><slot name="suffix" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { SnAccount } from "~/types/api"
|
||||
|
||||
const props = defineProps<{ data: SnAccount }>()
|
||||
const _ = defineSlots<{ suffix(): unknown }>()
|
||||
|
||||
const apiBase = useSolarNetworkUrl()
|
||||
|
||||
const userPicture = computed(() => {
|
||||
return props.data.profile.picture
|
||||
? `${apiBase}/drive/files/${props.data.profile.picture.id}`
|
||||
: undefined
|
||||
})
|
||||
|
||||
const userBackground = computed(() => {
|
||||
return props.data.profile.background
|
||||
? `${apiBase}/drive/files/${props.data.profile.background.id}`
|
||||
: undefined
|
||||
})
|
||||
</script>
|
||||
41
app/components/publisher/publisher-nameplate.vue
Normal file
41
app/components/publisher/publisher-nameplate.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<n-card>
|
||||
<div class="flex flex-col justify-center gap-4">
|
||||
<img
|
||||
v-if="userBackground"
|
||||
:src="userBackground"
|
||||
style="aspect-ratio: 16/7"
|
||||
class="rounded-xl"
|
||||
/>
|
||||
<div class="flex items-center gap-4">
|
||||
<n-avatar :src="userPicture" />
|
||||
<div class="grow">
|
||||
<div class="font-bold text-lg">{{ data.nick }}</div>
|
||||
<div class="text-sm opacity-80">@{{ data.name }}</div>
|
||||
</div>
|
||||
<div><slot name="suffix" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { SnPublisher } from "~/types/api"
|
||||
|
||||
const props = defineProps<{ data: SnPublisher }>()
|
||||
const _ = defineSlots<{ suffix(): unknown }>()
|
||||
|
||||
const apiBase = useSolarNetworkUrl()
|
||||
|
||||
const userPicture = computed(() => {
|
||||
return props.data.picture
|
||||
? `${apiBase}/drive/files/${props.data.picture.id}`
|
||||
: undefined
|
||||
})
|
||||
|
||||
const userBackground = computed(() => {
|
||||
return props.data.background
|
||||
? `${apiBase}/drive/files/${props.data.background.id}`
|
||||
: undefined
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user