Files
speckle-server/packages/frontend-2/components/automate/function/Card.vue
T
Kristaps Fabians Geikins ef4bb520cf fix(fe2): ugly function card hydration issue (#2381)
* fix(fe2): ugly function card hydration issue

* comment adjustment

* minor optimization
2024-06-18 08:40:25 +03:00

146 lines
4.2 KiB
Vue

<template>
<Component
:is="noButtons ? NuxtLink : 'div'"
:class="classes"
:to="noButtons ? automationFunctionRoute(fn.id) : undefined"
:external="externalMoreInfo"
:target="externalMoreInfo ? '_blank' : undefined"
>
<div
class="px-4 py-4 flex flex-col gap-3 rounded-lg border border-outline-3 bg-foundation relative"
>
<div class="flex gap-3 items-center" :class="{ 'w-4/5': hasLabel }">
<AutomateFunctionLogo :logo="fn.logo" />
<div class="flex flex-col truncate">
<div
:class="[
'normal font-semibold text-foreground truncate',
noButtons ? '' : 'hover:underline'
]"
>
<Component
:is="noButtons ? 'div' : NuxtLink"
:to="automationFunctionRoute(fn.id)"
:target="externalMoreInfo ? '_blank' : undefined"
>
{{ fn.name }}
</Component>
</div>
<div class="label-light flex items-center space-x-1">
<span>by</span>
<Component
:is="noButtons ? 'div' : CommonTextLink"
external
:to="fn.repo.url"
size="sm"
>
{{ fn.repo.owner }}
</Component>
</div>
</div>
</div>
<div class="label-light text-foreground-2 line-clamp-3 h-16 whitespace-normal">
{{ plaintextDescription }}
</div>
<div v-if="!noButtons" class="flex flex-col sm:flex-row sm:self-end gap-2">
<template v-if="showEdit">
<FormButton
:icon-left="PencilIcon"
full-width
outlined
@click="$emit('edit')"
>
Edit Details
</FormButton>
</template>
<template v-else>
<FormButton
text
:to="automationFunctionRoute(fn.id)"
:external="externalMoreInfo"
:target="externalMoreInfo ? '_blank' : undefined"
>
Learn More
</FormButton>
<FormButton
:icon-left="selected ? CheckIcon : undefined"
@click="$emit('use')"
>
{{ selected ? 'Selected' : 'Select' }}
</FormButton>
</template>
</div>
<div class="absolute top-0 right-0">
<div
v-if="hasLabel"
class="rounded-bl-lg rounded-tr-[7px] text-xs px-2 py-1"
:class="{
'bg-foundation-focus text-foreground': fn.isFeatured,
'bg-warning text-foreground-on-primary': isOutdated
}"
>
<template v-if="isOutdated">Outdated</template>
<template v-else-if="fn.isFeatured">Featured</template>
</div>
</div>
</div>
</Component>
</template>
<script setup lang="ts">
import { graphql } from '~/lib/common/generated/gql'
import type { AutomationsFunctionsCard_AutomateFunctionFragment } from '~/lib/common/generated/gql/graphql'
import { CheckIcon, PencilIcon } from '@heroicons/vue/24/outline'
import { automationFunctionRoute } from '~/lib/common/helpers/route'
import { useMarkdown } from '~/lib/common/composables/markdown'
import { CommonTextLink } from '@speckle/ui-components'
graphql(`
fragment AutomationsFunctionsCard_AutomateFunction on AutomateFunction {
id
name
isFeatured
description
logo
repo {
id
url
owner
name
}
}
`)
defineEmits<{
edit: []
use: []
}>()
const props = defineProps<{
fn: AutomationsFunctionsCard_AutomateFunctionFragment
showEdit?: boolean
noButtons?: boolean
externalMoreInfo?: boolean
selected?: boolean
isOutdated?: boolean
}>()
const NuxtLink = resolveComponent('NuxtLink')
const hasLabel = computed(() => props.fn.isFeatured || props.isOutdated)
const { html: plaintextDescription } = useMarkdown(
computed(() => props.fn.description || ''),
{ plaintext: true }
)
const classes = computed(() => {
const classParts = ['rounded-lg']
if (props.selected) {
classParts.push('ring-2 ring-primary')
} else if (props.noButtons) {
classParts.push('ring-outline-2 hover:ring-2 cursor-pointer')
}
return classParts.join(' ')
})
</script>