kopia lustrzana https://github.com/elk-zone/elk
feat: extract `StatusQuote` component with handling nested quote and hide preview card
rodzic
438ee860a9
commit
3ef90023ff
|
|
@ -5,10 +5,12 @@ const {
|
|||
status,
|
||||
newer,
|
||||
withAction = true,
|
||||
isNested = false,
|
||||
} = defineProps<{
|
||||
status: mastodon.v1.Status | mastodon.v1.StatusEdit
|
||||
newer?: mastodon.v1.Status
|
||||
withAction?: boolean
|
||||
isNested?: boolean
|
||||
}>()
|
||||
|
||||
const { translation } = await useTranslation(status, getLanguageCode())
|
||||
|
|
@ -26,42 +28,6 @@ const vnode = computed(() => {
|
|||
inReplyToStatus: newer,
|
||||
})
|
||||
})
|
||||
|
||||
function isQuoteType(quote: mastodon.v1.Status['quote']): quote is mastodon.v1.Quote | mastodon.v1.ShallowQuote {
|
||||
return !!quote
|
||||
}
|
||||
|
||||
function isShallowQuoteType(quote: mastodon.v1.Quote | mastodon.v1.ShallowQuote): quote is mastodon.v1.ShallowQuote {
|
||||
return 'quotedStatusId' in quote
|
||||
}
|
||||
|
||||
const quoteState = computed(() => {
|
||||
if (!isQuoteType(status.quote)) {
|
||||
return null
|
||||
}
|
||||
return status.quote.state
|
||||
})
|
||||
const shallowQuotedStatus = ref<mastodon.v1.Status | null>(null)
|
||||
watchEffect(async () => {
|
||||
if (!isQuoteType(status.quote) || !isShallowQuoteType(status.quote) || !status.quote.quotedStatusId) {
|
||||
shallowQuotedStatus.value = null
|
||||
return
|
||||
}
|
||||
shallowQuotedStatus.value = await fetchStatus(status.quote.quotedStatusId)
|
||||
})
|
||||
|
||||
const quotedStatus = computed(() => {
|
||||
if (!isQuoteType(status.quote)) {
|
||||
return null
|
||||
}
|
||||
if (isShallowQuoteType(status.quote)) {
|
||||
if (!status.quote.quotedStatusId) {
|
||||
return null
|
||||
}
|
||||
return shallowQuotedStatus.value
|
||||
}
|
||||
return status.quote.quotedStatus
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -74,37 +40,7 @@ const quotedStatus = computed(() => {
|
|||
<component :is="vnode" v-if="vnode" />
|
||||
</span>
|
||||
<div v-else />
|
||||
<template
|
||||
v-if="quotedStatus"
|
||||
>
|
||||
<StatusCard
|
||||
v-show="quoteState === 'accepted'"
|
||||
:status="quotedStatus"
|
||||
:actions="false"
|
||||
:newer="newer"
|
||||
border-1 my-3
|
||||
/>
|
||||
<p>(state.state: {{ JSON.stringify(status.quote?.state) }})</p>
|
||||
<!--
|
||||
TODO: handle non-accepted quoted post
|
||||
pending: never;
|
||||
accepted: never;
|
||||
rejected: never;
|
||||
revoked: never;
|
||||
deleted: never;
|
||||
unauthorized: never;
|
||||
|
||||
pending: The quote has been created but requires the original author's manual approval before it can be displayed to others.
|
||||
accepted: The quote has been approved by the original author and is ready to be displayed.
|
||||
rejected: The original author has explicitly rejected the quote, and it will not be displayed.
|
||||
revoked: The quote was previously accepted but the original author has since revoked it.
|
||||
deleted: The quote was accepted, but the original post has since been deleted.
|
||||
unauthorized: The user is not authorized to see the quote (e.g., it was a private post).
|
||||
blocked_account: The user has blocked the account that was quoted.
|
||||
blocked_domain: The user has blocked the domain of the account that was quoted.
|
||||
muted_account: The user has muted the account that was quoted.
|
||||
-->
|
||||
</template>
|
||||
<StatusQuote :status="status" :is-nested="isNested" />
|
||||
<template v-if="translation.visible">
|
||||
<div my2 h-px border="b base" bg-base />
|
||||
<ContentRich v-if="translation.success" class="line-compact" :content="translation.text" :emojis="status.emojis" />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { mastodon } from 'masto'
|
||||
|
||||
const { actions = true, older, newer, hasOlder, hasNewer, main, account, ...props } = defineProps<{
|
||||
const { actions = true, isNested = false, older, newer, hasOlder, hasNewer, main, account, ...props } = defineProps<{
|
||||
status: mastodon.v1.Status
|
||||
followedTag?: string | null
|
||||
actions?: boolean
|
||||
|
|
@ -9,6 +9,7 @@ const { actions = true, older, newer, hasOlder, hasNewer, main, account, ...prop
|
|||
hover?: boolean
|
||||
inNotification?: boolean
|
||||
isPreview?: boolean
|
||||
isNested?: boolean
|
||||
|
||||
// If we know the prev and next status in the timeline, we can simplify the card
|
||||
older?: mastodon.v1.Status
|
||||
|
|
@ -211,6 +212,7 @@ const forceShow = ref(false)
|
|||
:context="context"
|
||||
:is-preview="isPreview"
|
||||
:in-notification="inNotification"
|
||||
:is-nested="isNested"
|
||||
mb2 :class="{ 'mt-2 mb1': isDM }"
|
||||
/>
|
||||
<StatusActions v-if="actions !== false" v-show="!getPreferences(userSettings, 'zenMode')" :status="status" />
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ const { status, context } = defineProps<{
|
|||
context?: mastodon.v2.FilterContext | 'details'
|
||||
isPreview?: boolean
|
||||
inNotification?: boolean
|
||||
isNested: boolean
|
||||
}>()
|
||||
|
||||
const isDM = computed(() => status.visibility === 'direct')
|
||||
|
|
@ -41,7 +42,7 @@ const allowEmbeddedMedia = computed(() => status.card?.html && embeddedMediaPref
|
|||
'ms--3.5 mt--1 ms--1': isDM && context !== 'details',
|
||||
}"
|
||||
>
|
||||
<StatusBody v-if="(!isFiltered && isSensitiveNonSpoiler) || hideAllMedia" :status="status" :newer="newer" :with-action="!isDetails" :class="isDetails ? 'text-xl' : ''" />
|
||||
<StatusBody v-if="(!isFiltered && isSensitiveNonSpoiler) || hideAllMedia" :status="status" :newer="newer" :with-action="!isDetails" :is-nested="isNested" :class="isDetails ? 'text-xl' : ''" />
|
||||
<StatusSpoiler :enabled="hasSpoilerOrSensitiveMedia || isFiltered" :filter="isFiltered" :sensitive-non-spoiler="isSensitiveNonSpoiler || hideAllMedia" :is-d-m="isDM">
|
||||
<template v-if="spoilerTextPresent" #spoiler>
|
||||
<p>
|
||||
|
|
@ -51,7 +52,7 @@ const allowEmbeddedMedia = computed(() => status.card?.html && embeddedMediaPref
|
|||
<template v-else-if="filterPhrase" #spoiler>
|
||||
<p>{{ `${$t('status.filter_hidden_phrase')}: ${filterPhrase}` }}</p>
|
||||
</template>
|
||||
<StatusBody v-if="!(isSensitiveNonSpoiler || hideAllMedia)" :status="status" :newer="newer" :with-action="!isDetails" :class="isDetails ? 'text-xl' : ''" />
|
||||
<StatusBody v-if="!(isSensitiveNonSpoiler || hideAllMedia)" :status="status" :newer="newer" :with-action="!isDetails" :is-nested="isNested" :class="isDetails ? 'text-xl' : ''" />
|
||||
<StatusTranslation :status="status" />
|
||||
<StatusPoll v-if="status.poll" :status="status" />
|
||||
<StatusMedia
|
||||
|
|
@ -60,7 +61,7 @@ const allowEmbeddedMedia = computed(() => status.card?.html && embeddedMediaPref
|
|||
:is-preview="isPreview"
|
||||
/>
|
||||
<StatusPreviewCard
|
||||
v-if="status.card && !allowEmbeddedMedia"
|
||||
v-if="status.card && !allowEmbeddedMedia && !isNested"
|
||||
:card="status.card"
|
||||
:small-picture-only="status.mediaAttachments?.length > 0"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import type { mastodon } from 'masto'
|
||||
|
||||
const { actions = true, ...props } = defineProps<{
|
||||
const { actions = true, isNested = false, ...props } = defineProps<{
|
||||
status: mastodon.v1.Status
|
||||
newer?: mastodon.v1.Status
|
||||
command?: boolean
|
||||
actions?: boolean
|
||||
isNested?: boolean
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
|
|
@ -35,7 +36,7 @@ useHydratedHead({
|
|||
<AccountInfo :account="status.account" />
|
||||
</AccountHoverWrapper>
|
||||
</NuxtLink>
|
||||
<StatusContent :status="status" :newer="newer" context="details" />
|
||||
<StatusContent :status="status" :newer="newer" context="details" :is-nested="isNested" />
|
||||
<div flex="~ gap-1" items-center text-secondary text-sm>
|
||||
<div flex>
|
||||
<div>{{ createdAt }}</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
<script setup lang="ts">
|
||||
import type { mastodon } from 'masto'
|
||||
|
||||
const {
|
||||
status,
|
||||
isNested = false,
|
||||
} = defineProps<{
|
||||
status: mastodon.v1.Status | mastodon.v1.StatusEdit
|
||||
isNested?: boolean
|
||||
}>()
|
||||
|
||||
function isQuoteType(quote: mastodon.v1.Status['quote']): quote is mastodon.v1.Quote | mastodon.v1.ShallowQuote {
|
||||
return !!quote
|
||||
}
|
||||
|
||||
function isShallowQuoteType(quote: mastodon.v1.Quote | mastodon.v1.ShallowQuote): quote is mastodon.v1.ShallowQuote {
|
||||
return 'quotedStatusId' in quote
|
||||
}
|
||||
|
||||
const quoteState = computed(() => {
|
||||
if (!isQuoteType(status.quote)) {
|
||||
return null
|
||||
}
|
||||
return status.quote.state
|
||||
})
|
||||
const shallowQuotedStatus = ref<mastodon.v1.Status | null>(null)
|
||||
watchEffect(async () => {
|
||||
if (!isQuoteType(status.quote) || !isShallowQuoteType(status.quote) || !status.quote.quotedStatusId) {
|
||||
shallowQuotedStatus.value = null
|
||||
return
|
||||
}
|
||||
shallowQuotedStatus.value = await fetchStatus(status.quote.quotedStatusId)
|
||||
})
|
||||
|
||||
const quotedStatus = computed(() => {
|
||||
if (!isQuoteType(status.quote)) {
|
||||
return null
|
||||
}
|
||||
if (isShallowQuoteType(status.quote)) {
|
||||
if (!status.quote.quotedStatusId) {
|
||||
return null
|
||||
}
|
||||
return shallowQuotedStatus.value
|
||||
}
|
||||
return status.quote.quotedStatus
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="isNested && quotedStatus"
|
||||
flex b="~ 1" rounded-lg bg-card mt-3 p-3
|
||||
>
|
||||
Quoted post by
|
||||
<AccountInlineInfo :account="quotedStatus.account" :link="false" mx-1 />
|
||||
</div>
|
||||
<template
|
||||
v-else-if="quotedStatus"
|
||||
>
|
||||
<StatusCard
|
||||
v-show="quoteState === 'accepted'"
|
||||
:status="quotedStatus"
|
||||
:actions="false"
|
||||
:is-nested="true"
|
||||
b="base 1" rounded-lg hover:bg-active my-3
|
||||
/>
|
||||
<p>(state.state: {{ JSON.stringify(status.quote?.state) }})</p>
|
||||
<!--
|
||||
TODO: handle non-accepted quoted post
|
||||
pending: never;
|
||||
accepted: never;
|
||||
rejected: never;
|
||||
revoked: never;
|
||||
deleted: never;
|
||||
unauthorized: never;
|
||||
|
||||
pending: The quote has been created but requires the original author's manual approval before it can be displayed to others.
|
||||
accepted: The quote has been approved by the original author and is ready to be displayed.
|
||||
rejected: The original author has explicitly rejected the quote, and it will not be displayed.
|
||||
revoked: The quote was previously accepted but the original author has since revoked it.
|
||||
deleted: The quote was accepted, but the original post has since been deleted.
|
||||
unauthorized: The user is not authorized to see the quote (e.g., it was a private post).
|
||||
blocked_account: The user has blocked the account that was quoted.
|
||||
blocked_domain: The user has blocked the domain of the account that was quoted.
|
||||
muted_account: The user has muted the account that was quoted.
|
||||
-->
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
* {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
Ładowanie…
Reference in New Issue