All checks were successful
Build and deploy updated apps / Build & deploy (push) Successful in 2m22s
56 lines
1.6 KiB
Vue
56 lines
1.6 KiB
Vue
<script setup lang="ts">
|
||
import {computed} from 'vue'
|
||
|
||
const props = defineProps({
|
||
/* Path or URL for the portrait image */
|
||
src: {type: String, required: true},
|
||
/* Alt text for the image */
|
||
alt: {type: String, default: ''},
|
||
/**
|
||
* Tailwind size token (e.g. 14 → w-14 h-14 or "full" → w-full h-full).
|
||
* Defaults to 14 (= 3.5 rem = 56 px).
|
||
*/
|
||
size: {type: [Number, String], default: 14},
|
||
/* Heading / description */
|
||
title: {type: String, required: true},
|
||
description: {type: String, required: true},
|
||
/* Image left or right */
|
||
imageSide: {type: String as () => 'left' | 'right', default: 'left'},
|
||
/* Extra wrapper classes */
|
||
wrapperClass: {type: String, default: ''}
|
||
})
|
||
|
||
/* Tailwind width/height classes */
|
||
const sizeClasses = computed(() => `w-${props.size} h-${props.size}`)
|
||
|
||
/* If the token is numeric, convert to px for NuxtImg width/height props */
|
||
const numericSize = computed(() => {
|
||
const n = Number(props.size)
|
||
return Number.isFinite(n) ? n * 4 /* Tailwind token ×4 px */ : undefined
|
||
})
|
||
|
||
const wrapperFlex = computed(() =>
|
||
props.imageSide === 'right' ? 'flex-row-reverse text-right' : 'flex-row text-left'
|
||
)
|
||
</script>
|
||
|
||
<template>
|
||
<div :class="['flex items-center gap-4', wrapperFlex, wrapperClass]">
|
||
<NuxtImg
|
||
:src="src"
|
||
:alt="alt"
|
||
:width="numericSize"
|
||
:height="numericSize"
|
||
class="rounded-full object-cover shrink-0"
|
||
:class="sizeClasses"
|
||
/>
|
||
|
||
<div>
|
||
<p class="font-semibold text-neutral-700">{{ title }}</p>
|
||
<p class="text-sm text-neutral-600">{{ description }}</p>
|
||
|
||
<slot/>
|
||
</div>
|
||
</div>
|
||
</template>
|