83 lines
2.9 KiB
Vue
83 lines
2.9 KiB
Vue
<template>
|
|
<div class="flex flex-col gap-1 w-full">
|
|
<div v-if="label" class="flex justify-between items-end px-0.5">
|
|
<div class="flex items-center gap-2">
|
|
<!-- Pixel Icon -->
|
|
<div class="w-4 h-4 flex items-center justify-center">
|
|
<slot name="icon"></slot>
|
|
</div>
|
|
<span class="text-[10px] font-mono font-bold leading-none text-[#8f80a0]">{{ label }}</span>
|
|
</div>
|
|
<span class="text-[10px] font-mono text-[#e0d8f0] leading-none">{{ Math.floor(current) }}/{{ max }}</span>
|
|
</div>
|
|
|
|
<!-- Segmented Bar Container -->
|
|
<div class="h-4 bg-[#1b1026] border-2 border-[#1b1026] relative p-[2px] shadow-[0_0_0_1px_#4a3b5e]">
|
|
<!-- Background (Empty segments) -->
|
|
<div class="absolute inset-[2px] flex gap-[2px]">
|
|
<div v-for="i in segments" :key="`bg-${i}`" class="flex-1 bg-[#2b193f]"></div>
|
|
</div>
|
|
|
|
<!-- Foreground (Filled segments) -->
|
|
<div class="absolute inset-[2px] flex gap-[2px] overflow-hidden">
|
|
<div
|
|
v-for="i in segments"
|
|
:key="`fill-${i}`"
|
|
class="flex-1 transition-all duration-300 relative"
|
|
:class="[
|
|
i <= filledSegments ? 'opacity-100' : 'opacity-0',
|
|
i === filledSegments + 1 && partialFill > 0 ? 'opacity-100' : ''
|
|
]"
|
|
>
|
|
<!-- The colored block -->
|
|
<div
|
|
class="w-full h-full relative"
|
|
:style="{
|
|
backgroundColor: barColor,
|
|
width: i === filledSegments + 1 ? `${partialFill}%` : '100%'
|
|
}"
|
|
>
|
|
<!-- Shine/Highlight for 3D effect -->
|
|
<div class="absolute top-0 left-0 right-0 h-[40%] bg-white opacity-20"></div>
|
|
<div class="absolute bottom-0 left-0 right-0 h-[20%] bg-black opacity-10"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
|
|
interface Props {
|
|
current: number;
|
|
max: number;
|
|
type: 'hp' | 'energy' | 'mana';
|
|
label?: string;
|
|
segments?: number; // Number of blocks, default 10
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
segments: 10
|
|
});
|
|
|
|
const percentage = computed(() => Math.min(100, Math.max(0, (props.current / props.max) * 100)));
|
|
|
|
// Calculate how many segments are fully filled
|
|
const filledSegments = computed(() => Math.floor((percentage.value / 100) * props.segments));
|
|
|
|
// Calculate the percentage of the partially filled segment
|
|
const partialFill = computed(() => {
|
|
const segmentSize = 100 / props.segments;
|
|
const remainder = percentage.value % segmentSize;
|
|
return (remainder / segmentSize) * 100;
|
|
});
|
|
|
|
const barColor = computed(() => {
|
|
if (props.type === 'energy') return '#f6b26b'; // Orange (Star)
|
|
if (props.type === 'mana') return '#99e550'; // Green (Potion) - Changed from Cyan
|
|
return '#d95763'; // Red (Heart)
|
|
});
|
|
</script>
|