Teren-app/resources/js/Components/DataTable/StatusBadge.vue
Simon Pocrnjič 63e0958b66 Dev branch
2025-11-02 12:31:01 +01:00

171 lines
3.3 KiB
Vue

<script setup>
import { computed } from 'vue';
const props = defineProps({
status: {
type: String,
required: true,
},
variant: {
type: String,
default: 'default', // default, dot, pill
validator: (v) => ['default', 'dot', 'pill'].includes(v),
},
size: {
type: String,
default: 'md', // sm, md, lg
validator: (v) => ['sm', 'md', 'lg'].includes(v),
},
color: {
type: String,
default: null, // If null, uses status-based colors
validator: (v) =>
!v ||
[
'gray',
'red',
'yellow',
'green',
'blue',
'indigo',
'purple',
'pink',
'amber',
'emerald',
].includes(v),
},
});
// Status-based color mapping
const statusColors = {
active: 'green',
inactive: 'gray',
archived: 'gray',
pending: 'yellow',
completed: 'green',
failed: 'red',
success: 'green',
error: 'red',
warning: 'yellow',
info: 'blue',
draft: 'gray',
published: 'green',
};
const badgeColor = computed(() => {
if (props.color) return props.color;
const lowerStatus = props.status.toLowerCase();
return statusColors[lowerStatus] || 'gray';
});
const sizeClasses = {
sm: {
text: 'text-xs',
padding: 'px-2 py-0.5',
dot: 'w-1.5 h-1.5',
},
md: {
text: 'text-sm',
padding: 'px-2.5 py-1',
dot: 'w-2 h-2',
},
lg: {
text: 'text-base',
padding: 'px-3 py-1.5',
dot: 'w-2.5 h-2.5',
},
};
const colorClasses = {
gray: {
bg: 'bg-gray-100',
text: 'text-gray-800',
dot: 'bg-gray-500',
border: 'border-gray-300',
},
red: {
bg: 'bg-red-100',
text: 'text-red-800',
dot: 'bg-red-500',
border: 'border-red-300',
},
yellow: {
bg: 'bg-yellow-100',
text: 'text-yellow-800',
dot: 'bg-yellow-500',
border: 'border-yellow-300',
},
green: {
bg: 'bg-green-100',
text: 'text-green-800',
dot: 'bg-green-500',
border: 'border-green-300',
},
blue: {
bg: 'bg-blue-100',
text: 'text-blue-800',
dot: 'bg-blue-500',
border: 'border-blue-300',
},
indigo: {
bg: 'bg-indigo-100',
text: 'text-indigo-800',
dot: 'bg-indigo-500',
border: 'border-indigo-300',
},
purple: {
bg: 'bg-purple-100',
text: 'text-purple-800',
dot: 'bg-purple-500',
border: 'border-purple-300',
},
pink: {
bg: 'bg-pink-100',
text: 'text-pink-800',
dot: 'bg-pink-500',
border: 'border-pink-300',
},
amber: {
bg: 'bg-amber-100',
text: 'text-amber-800',
dot: 'bg-amber-500',
border: 'border-amber-300',
},
emerald: {
bg: 'bg-emerald-100',
text: 'text-emerald-800',
dot: 'bg-emerald-500',
border: 'border-emerald-300',
},
};
const colors = computed(() => colorClasses[badgeColor.value] || colorClasses.gray);
const sizes = computed(() => sizeClasses[props.size] || sizeClasses.md);
</script>
<template>
<span
:class="[
'inline-flex items-center font-medium',
sizes.text,
sizes.padding,
colors.bg,
colors.text,
variant === 'pill' ? 'rounded-full' : 'rounded-md',
variant === 'default' ? `border ${colors.border}` : '',
]"
>
<span
v-if="variant === 'dot'"
:class="[
'rounded-full mr-1.5',
sizes.dot,
colors.dot,
]"
></span>
<slot>{{ status }}</slot>
</span>
</template>