55 lines
1.2 KiB
Vue
55 lines
1.2 KiB
Vue
<script setup lang="ts">
|
|
import { t } from '@/i18n'
|
|
import { computed } from 'vue'
|
|
|
|
interface PasswordRule {
|
|
label: string
|
|
met: boolean
|
|
}
|
|
|
|
const props = defineProps<{
|
|
rules: PasswordRule[]
|
|
showErrors: boolean
|
|
}>()
|
|
|
|
function iconClass(rule: PasswordRule) {
|
|
if (rule.met) {
|
|
return 'text-success'
|
|
}
|
|
return props.showErrors ? 'text-error' : 'text-muted'
|
|
}
|
|
|
|
function textClass(rule: PasswordRule) {
|
|
if (rule.met) {
|
|
return 'text-default'
|
|
}
|
|
return props.showErrors ? 'text-error' : 'text-muted'
|
|
}
|
|
|
|
function itemIcon(rule: PasswordRule) {
|
|
if (rule.met) {
|
|
return 'i-lucide-check'
|
|
}
|
|
return props.showErrors ? 'i-lucide-circle-alert' : 'i-lucide-circle'
|
|
}
|
|
|
|
const items = computed(() =>
|
|
props.rules.map((rule) => ({
|
|
...rule,
|
|
iconClass: iconClass(rule),
|
|
textClass: textClass(rule),
|
|
icon: itemIcon(rule),
|
|
})),
|
|
)
|
|
</script>
|
|
|
|
<template>
|
|
<ul class="flex flex-col gap-1.5">
|
|
<li v-for="item in items" :key="item.label" class="flex items-center gap-2 text-xs/[18px]">
|
|
<UIcon :name="item.icon" :class="['size-3.5 shrink-0', item.iconClass]" />
|
|
<span :class="item.textClass">{{ item.label }}</span>
|
|
<span class="sr-only">{{ t(item.met ? 'met' : 'not met') }}</span>
|
|
</li>
|
|
</ul>
|
|
</template>
|