forked from Mirrors/elk
Compare commits
40 commits
main
...
feature/re
Author | SHA1 | Date | |
---|---|---|---|
|
8fc435c60e | ||
|
354914fc8d | ||
|
b8f492a255 | ||
|
ba4f6e9e1a | ||
|
f99d88a9e3 | ||
|
c36b900cdd | ||
|
ed06ad8074 | ||
|
299d33c7cb | ||
|
445891299f | ||
|
ed23c47ff2 | ||
|
075a9d115b | ||
|
0b3d32e821 | ||
|
eac0590af9 | ||
|
aa6b603eca | ||
|
979c97306b | ||
|
d3a567ddb8 | ||
|
084b5806bf | ||
|
b64a4784ab | ||
|
28c011ac2e | ||
|
501d422931 | ||
|
255c950dff | ||
|
b2e43bb11c | ||
|
9bf4a6e21e | ||
|
1044c8fcbc | ||
|
73a6678cb3 | ||
|
ff211ea77e | ||
|
50e0832310 | ||
|
a5c779aa2e | ||
|
853c65c056 | ||
|
c4de97636d | ||
|
6c114c6f14 | ||
|
6e5ef04bb6 | ||
|
e7f9e08192 | ||
|
9f85275791 | ||
|
9bdfd71b0a | ||
|
a2a76651a5 | ||
|
1cd6448bc5 | ||
|
5de275b505 | ||
|
3f2227ef4c | ||
|
1cac81ad57 |
5 changed files with 53 additions and 6 deletions
|
@ -5,15 +5,18 @@ const {
|
||||||
status,
|
status,
|
||||||
newer,
|
newer,
|
||||||
withAction = true,
|
withAction = true,
|
||||||
|
cleanSharedLink,
|
||||||
} = defineProps<{
|
} = defineProps<{
|
||||||
status: mastodon.v1.Status | mastodon.v1.StatusEdit
|
status: mastodon.v1.Status | mastodon.v1.StatusEdit
|
||||||
newer?: mastodon.v1.Status
|
newer?: mastodon.v1.Status
|
||||||
withAction?: boolean
|
withAction?: boolean
|
||||||
|
cleanSharedLink?: string | false
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { translation } = useTranslation(status, getLanguageCode())
|
const { translation } = useTranslation(status, getLanguageCode())
|
||||||
|
|
||||||
const emojisObject = useEmojisFallback(() => status.emojis)
|
const emojisObject = useEmojisFallback(() => status.emojis)
|
||||||
|
|
||||||
const vnode = $computed(() => {
|
const vnode = $computed(() => {
|
||||||
if (!status.content)
|
if (!status.content)
|
||||||
return null
|
return null
|
||||||
|
@ -24,7 +27,9 @@ const vnode = $computed(() => {
|
||||||
collapseMentionLink: !!('inReplyToId' in status && status.inReplyToId),
|
collapseMentionLink: !!('inReplyToId' in status && status.inReplyToId),
|
||||||
status: 'id' in status ? status : undefined,
|
status: 'id' in status ? status : undefined,
|
||||||
inReplyToStatus: newer,
|
inReplyToStatus: newer,
|
||||||
|
cleanSharedLink,
|
||||||
})
|
})
|
||||||
|
|
||||||
return vnode
|
return vnode
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -21,6 +21,10 @@ const isFiltered = $computed(() => status.account.id !== currentUser.value?.acco
|
||||||
// check spoiler text or media attachment
|
// check spoiler text or media attachment
|
||||||
// needed to handle accounts that mark all their posts as sensitive
|
// needed to handle accounts that mark all their posts as sensitive
|
||||||
const hasSpoilerOrSensitiveMedia = $computed(() => !!status.spoilerText || (status.sensitive && !!status.mediaAttachments.length))
|
const hasSpoilerOrSensitiveMedia = $computed(() => !!status.spoilerText || (status.sensitive && !!status.mediaAttachments.length))
|
||||||
|
|
||||||
|
const cleanSharedLink = !status.poll
|
||||||
|
&& !status.mediaAttachments.length
|
||||||
|
&& status.card?.url
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -39,7 +43,7 @@ const hasSpoilerOrSensitiveMedia = $computed(() => !!status.spoilerText || (stat
|
||||||
<template v-else-if="filterPhrase" #spoiler>
|
<template v-else-if="filterPhrase" #spoiler>
|
||||||
<p>{{ `${$t('status.filter_hidden_phrase')}: ${filterPhrase}` }}</p>
|
<p>{{ `${$t('status.filter_hidden_phrase')}: ${filterPhrase}` }}</p>
|
||||||
</template>
|
</template>
|
||||||
<StatusBody v-if="!status.sensitive || status.spoilerText" :status="status" :newer="newer" :with-action="!isDetails" :class="isDetails ? 'text-xl' : ''" />
|
<StatusBody v-if="!status.sensitive || status.spoilerText" :clean-shared-link="cleanSharedLink" :status="status" :newer="newer" :with-action="!isDetails" :class="isDetails ? 'text-xl' : ''" />
|
||||||
<StatusTranslation :status="status" />
|
<StatusTranslation :status="status" />
|
||||||
<StatusPoll v-if="status.poll" :status="status" />
|
<StatusPoll v-if="status.poll" :status="status" />
|
||||||
<StatusMedia
|
<StatusMedia
|
||||||
|
@ -51,6 +55,7 @@ const hasSpoilerOrSensitiveMedia = $computed(() => !!status.spoilerText || (stat
|
||||||
v-if="status.card"
|
v-if="status.card"
|
||||||
:card="status.card"
|
:card="status.card"
|
||||||
:small-picture-only="status.mediaAttachments?.length > 0"
|
:small-picture-only="status.mediaAttachments?.length > 0"
|
||||||
|
:clean-shared-link="cleanSharedLink"
|
||||||
/>
|
/>
|
||||||
<StatusCard
|
<StatusCard
|
||||||
v-if="status.reblog"
|
v-if="status.reblog"
|
||||||
|
|
|
@ -7,15 +7,16 @@ const props = defineProps<{
|
||||||
smallPictureOnly?: boolean
|
smallPictureOnly?: boolean
|
||||||
/** When it is root card in the list, not appear as a child card */
|
/** When it is root card in the list, not appear as a child card */
|
||||||
root?: boolean
|
root?: boolean
|
||||||
|
/** Defined when the preview card URL matches the last shared link href attribute */
|
||||||
|
cleanSharedLink?: string | false
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const providerName = props.card.providerName
|
const providerName = $computed(() => props.card.providerName ? props.card.providerName : new URL(props.card.url).hostname)
|
||||||
|
|
||||||
const gitHubCards = $(usePreferences('experimentalGitHubCards'))
|
const gitHubCards = $(usePreferences('experimentalGitHubCards'))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<LazyStatusPreviewGitHub v-if="gitHubCards && providerName === 'GitHub'" :card="card" />
|
<LazyStatusPreviewGitHub v-if="gitHubCards && providerName === 'GitHub'" :card="card" />
|
||||||
<LazyStatusPreviewStackBlitz v-else-if="gitHubCards && providerName === 'StackBlitz'" :card="card" :small-picture-only="smallPictureOnly" :root="root" />
|
<LazyStatusPreviewStackBlitz v-else-if="gitHubCards && providerName === 'StackBlitz'" :card="card" :small-picture-only="smallPictureOnly" :root="root" />
|
||||||
<StatusPreviewCardNormal v-else :card="card" :small-picture-only="smallPictureOnly" :root="root" />
|
<StatusPreviewCardNormal v-else :card="card" :clean-shared-link="cleanSharedLink" :small-picture-only="smallPictureOnly" :root="root" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -7,6 +7,8 @@ const props = defineProps<{
|
||||||
smallPictureOnly?: boolean
|
smallPictureOnly?: boolean
|
||||||
/** When it is root card in the list, not appear as a child card */
|
/** When it is root card in the list, not appear as a child card */
|
||||||
root?: boolean
|
root?: boolean
|
||||||
|
/** Defined when the preview card URL matches the last shared link href attribute */
|
||||||
|
cleanSharedLink?: string | false
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// mastodon's default max og image width
|
// mastodon's default max og image width
|
||||||
|
@ -19,7 +21,17 @@ const isSquare = $computed(() => (
|
||||||
|| Number(props.card.width || 0) < ogImageWidth
|
|| Number(props.card.width || 0) < ogImageWidth
|
||||||
|| Number(props.card.height || 0) < ogImageWidth / 2
|
|| Number(props.card.height || 0) < ogImageWidth / 2
|
||||||
))
|
))
|
||||||
const providerName = $computed(() => props.card.providerName ? props.card.providerName : new URL(props.card.url).hostname)
|
const providerName = $computed(() => {
|
||||||
|
let finalProviderName = new URL(props.card.url).hostname
|
||||||
|
|
||||||
|
if (props.card.providerName) {
|
||||||
|
finalProviderName = props.card.providerName
|
||||||
|
if (props.cleanSharedLink && finalProviderName !== props.cleanSharedLink)
|
||||||
|
finalProviderName = `${props.card.providerName} · ${props.cleanSharedLink.replace(/^https?:\/\//, '')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalProviderName
|
||||||
|
})
|
||||||
|
|
||||||
// TODO: handle card.type: 'photo' | 'video' | 'rich';
|
// TODO: handle card.type: 'photo' | 'video' | 'rich';
|
||||||
const cardTypeIconMap: Record<mastodon.v1.PreviewCardType, string> = {
|
const cardTypeIconMap: Record<mastodon.v1.PreviewCardType, string> = {
|
||||||
|
|
|
@ -17,6 +17,7 @@ export interface ContentParseOptions {
|
||||||
collapseMentionLink?: boolean
|
collapseMentionLink?: boolean
|
||||||
status?: mastodon.v1.Status
|
status?: mastodon.v1.Status
|
||||||
inReplyToStatus?: mastodon.v1.Status
|
inReplyToStatus?: mastodon.v1.Status
|
||||||
|
cleanSharedLink?: string | false // this is defined when conditions for cleaning the link are met
|
||||||
}
|
}
|
||||||
|
|
||||||
const sanitizerBasicClasses = filterClasses(/^(h-\S*|p-\S*|u-\S*|dt-\S*|e-\S*|mention|hashtag|ellipsis|invisible)$/u)
|
const sanitizerBasicClasses = filterClasses(/^(h-\S*|p-\S*|u-\S*|dt-\S*|e-\S*|mention|hashtag|ellipsis|invisible)$/u)
|
||||||
|
@ -86,6 +87,7 @@ export function parseMastodonHTML(
|
||||||
mentions,
|
mentions,
|
||||||
status,
|
status,
|
||||||
inReplyToStatus,
|
inReplyToStatus,
|
||||||
|
cleanSharedLink,
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
if (markdown) {
|
if (markdown) {
|
||||||
|
@ -135,7 +137,29 @@ export function parseMastodonHTML(
|
||||||
if (collapseMentionLink)
|
if (collapseMentionLink)
|
||||||
transforms.push(transformCollapseMentions(status, inReplyToStatus))
|
transforms.push(transformCollapseMentions(status, inReplyToStatus))
|
||||||
|
|
||||||
return transformSync(parse(html), transforms)
|
const node = parse(html) as Node
|
||||||
|
|
||||||
|
if (cleanSharedLink) {
|
||||||
|
// filter out invisible spans
|
||||||
|
const filteredNode = node.children.filter((child: Node) => !!child.children)
|
||||||
|
const matchedIndex = lastChildLinkMatchesPreviewUrl(filteredNode, cleanSharedLink)
|
||||||
|
|
||||||
|
if (matchedIndex)
|
||||||
|
filteredNode[filteredNode.length - 1].children.splice(matchedIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformSync(node, transforms)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the last link node if it matches the previewUrl
|
||||||
|
*/
|
||||||
|
export function lastChildLinkMatchesPreviewUrl(filteredNode: Node, previewUrl: string) {
|
||||||
|
const filteredLength = filteredNode.length
|
||||||
|
const length = filteredNode[filteredLength - 1].children.length
|
||||||
|
const lastChild = filteredNode[filteredLength - 1].children[length - 1]
|
||||||
|
const sharedHref = lastChild.attributes?.href
|
||||||
|
return sharedHref === previewUrl ? length - 1 : null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue