forked from Mirrors/elk
Compare commits
7 commits
main
...
feat/387-e
Author | SHA1 | Date | |
---|---|---|---|
|
60b0bdb264 | ||
|
1180311984 | ||
|
05bbd6ba4d | ||
|
4890ea40d0 | ||
|
e2ca6f9da0 | ||
|
88f557b445 | ||
|
29f989984b |
4 changed files with 114 additions and 2 deletions
|
@ -23,6 +23,11 @@ const providerName = $computed(() => props.card.providerName ? props.card.provid
|
|||
|
||||
const gitHubCards = $(useFeatureFlag('experimentalGitHubCards'))
|
||||
|
||||
// checks if title contains a username
|
||||
const usernames = props.card.title.match(/@+[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/gi)
|
||||
const isMastodonLink = usernames?.length === 1 && props.card.type === 'link'
|
||||
const username = isMastodonLink ? usernames[0] : ''
|
||||
|
||||
// TODO: handle card.type: 'photo' | 'video' | 'rich';
|
||||
const cardTypeIconMap: Record<CardType, string> = {
|
||||
link: 'i-ri:profile-line',
|
||||
|
@ -34,6 +39,7 @@ const cardTypeIconMap: Record<CardType, string> = {
|
|||
|
||||
<template>
|
||||
<StatusPreviewGitHub v-if="gitHubCards && providerName === 'GitHub'" :card="card" />
|
||||
<StatusPreviewMastodon v-else-if="isMastodonLink" :card="card" />
|
||||
<NuxtLink
|
||||
v-else
|
||||
block
|
||||
|
@ -76,6 +82,6 @@ const cardTypeIconMap: Record<CardType, string> = {
|
|||
>
|
||||
<div :class="cardTypeIconMap[card.type]" w="30%" h="30%" text-secondary />
|
||||
</div>
|
||||
<StatusPreviewCardInfo :root="root" :card="card" :provider="providerName" />
|
||||
<StatusPreviewCardInfo :root="root" :card="card" :provider="providerName" :is-square="isSquare" />
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
|
|
@ -7,6 +7,7 @@ const props = defineProps<{
|
|||
root?: boolean
|
||||
/** For the preview image, only the small image mode is displayed */
|
||||
provider?: string
|
||||
isSquare?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
|
@ -28,7 +29,7 @@ const props = defineProps<{
|
|||
>{{ card.title }}</strong>
|
||||
<p
|
||||
v-if="card.description"
|
||||
line-clamp-1 break-all sm:break-words text-secondary ws-pre-wrap :class="[root ? 'sm:line-clamp-2' : '']"
|
||||
line-clamp-1 break-all sm:break-normal text-secondary ws-pre-wrap sm:line-clamp-2
|
||||
>
|
||||
{{ card.description }}
|
||||
</p>
|
||||
|
|
95
components/status/StatusPreviewMastodon.vue
Normal file
95
components/status/StatusPreviewMastodon.vue
Normal file
|
@ -0,0 +1,95 @@
|
|||
<script setup lang="ts">
|
||||
import type { Card } from 'masto'
|
||||
import type { StatusQuote } from '~~/composables/status-quote'
|
||||
|
||||
const props = defineProps<{
|
||||
card: Card
|
||||
}>()
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* - extract username
|
||||
* - generate user profile link
|
||||
* - quotation icon ?
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
{
|
||||
"url": "https://hachyderm.io/@hi_mayank/109638087773020859",
|
||||
"title": "Mayank :verified: (@hi_mayank@hachyderm.io)",
|
||||
"description": "this article from @ben@a11y.info is of course excellent https://benmyers.dev/blog/semantic-selectors/\n\nhowever, in practice, i have found myself unable to fully utilize this approach....\n\ntwo examples:\n\n1. an input with a disabled/required attribute can be styled by targeting `:disabled` or `:required` but styling its label probably needs a data attribute or class\n\n2. vertical tabs can be styled by targeting `aria-orientation` but its content or wrapper probably needs a data attribute or class.\n\n(cont...)",
|
||||
"type": "link",
|
||||
"author_name": "",
|
||||
"author_url": "",
|
||||
"provider_name": "Hachyderm.io",
|
||||
"provider_url": "",
|
||||
"html": "",
|
||||
"width": 400,
|
||||
"height": 400,
|
||||
"image": "https://media.mas.to/masto-public/cache/preview_cards/images/017/761/272/original/e8ce83dfa2e4c64d.jpeg",
|
||||
"embed_url": "",
|
||||
"blurhash": "UREyiOM{-=D%_4IURiRjRiWBM{%M%NRjWCWA"
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// build the Status from Card
|
||||
const card = $computed(() => props.card)
|
||||
const usernames = card.title.match(/@+[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/gi)
|
||||
const fullUserName = usernames?.length && usernames[0]
|
||||
let username, domain
|
||||
if (fullUserName) {
|
||||
username = fullUserName.split('@')[1]
|
||||
domain = fullUserName.split('@')[2]
|
||||
}
|
||||
const isSquare = card.width === card.height
|
||||
const avatar = isSquare ? card.image : '' // todo: default avatar
|
||||
const status: StatusQuote = {
|
||||
id: '',
|
||||
uri: '',
|
||||
createdAt: '',
|
||||
editedAt: null,
|
||||
account: {
|
||||
username: username || '',
|
||||
displayName: 'FAKE NAME', // todo update
|
||||
avatar: avatar || '',
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="card.image"
|
||||
flex flex-col
|
||||
display-block of-hidden
|
||||
bg-code
|
||||
relative
|
||||
border="base"
|
||||
w-full min-h-50 md:min-h-60 border-b
|
||||
justify-center
|
||||
rounded-lg
|
||||
>
|
||||
<div p4 sm:px-8 flex flex-col justify-between min-h-50 md:min-h-60 h-full>
|
||||
<div flex justify-between items-center gap-2 sm:gap-6 h-full mb-2 min-h-35 md:min-h-45>
|
||||
<div flex flex-col gap-2>
|
||||
<a flex gap-1 text-sm flex-wrap leading-none :href="card.url" target="_blank">
|
||||
<span>{{ card.title }}</span>
|
||||
</a>
|
||||
<a sm:text-lg :href="card.url" target="_blank">
|
||||
<span text-secondary leading-tight>{{ card.description }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a :href="card.url" target="_blank">
|
||||
<img w-30 aspect-square width="20" height="20" rounded-2 :src="card.image">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div flex justify-between>
|
||||
<div />
|
||||
<div text-2xl i-ri:mastodon-fill text-secondary />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
10
composables/status-quote.ts
Normal file
10
composables/status-quote.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import type { Status } from 'masto'
|
||||
|
||||
type RecursivePartial<T> = {
|
||||
[P in keyof T]?:
|
||||
T[P] extends (infer U)[] ? RecursivePartial<U>[] :
|
||||
T[P] extends object ? RecursivePartial<T[P]> :
|
||||
T[P];
|
||||
}
|
||||
|
||||
export type StatusQuote = RecursivePartial<Status>
|
Loading…
Reference in a new issue