Laravel-based OAuth/IAM service with Passport, Vue 3 frontend, and Docker Compose setup for local and production deployment. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
46 lines
1.3 KiB
Vue
46 lines
1.3 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
|
|
interface BarItem {
|
|
label: string;
|
|
value: number;
|
|
}
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
title: string;
|
|
items: BarItem[];
|
|
emptyText?: string;
|
|
}>(),
|
|
{
|
|
emptyText: 'Sin datos en este período.',
|
|
},
|
|
);
|
|
|
|
const max = computed(() => Math.max(1, ...props.items.map((i) => i.value)));
|
|
|
|
function widthPct(value: number): number {
|
|
return Math.max(2, Math.round((value / max.value) * 100));
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="bar-list">
|
|
<h3 class="bar-list__title">{{ title }}</h3>
|
|
|
|
<p v-if="!items.length" class="bar-list__empty">{{ emptyText }}</p>
|
|
|
|
<ul v-else class="bar-list__items">
|
|
<li v-for="item in items" :key="item.label" class="bar-list__row" :title="`${item.label}: ${item.value}`">
|
|
<div class="bar-list__row-head">
|
|
<span class="bar-list__label">{{ item.label }}</span>
|
|
<span class="bar-list__value">{{ item.value }}</span>
|
|
</div>
|
|
<div class="bar-list__track">
|
|
<div class="bar-list__fill" :style="{ width: widthPct(item.value) + '%' }" />
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|