feat: Replace traffic light with shield ring icon
This commit is contained in:
@@ -1,7 +1,56 @@
|
||||
<template>
|
||||
<UPageCard title="Ampelstatus" variant="naked" orientation="horizontal" class="mb-4">
|
||||
{{ statusEmoji }}
|
||||
</UPageCard>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="relative flex items-center justify-center">
|
||||
<svg
|
||||
class="shield-ring"
|
||||
:class="ringClass"
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
>
|
||||
<circle
|
||||
class="ring-background"
|
||||
cx="24"
|
||||
cy="24"
|
||||
r="20"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
opacity="0.1"
|
||||
/>
|
||||
<circle
|
||||
class="ring-progress"
|
||||
cx="24"
|
||||
cy="24"
|
||||
r="20"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
:stroke-dasharray="circumference"
|
||||
:stroke-dashoffset="progressOffset"
|
||||
transform="rotate(-90 24 24)"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<Transition name="shield-pulse" mode="out-in">
|
||||
<UIcon
|
||||
:key="status"
|
||||
:name="shieldIcon"
|
||||
class="absolute shield-icon"
|
||||
:class="iconClass"
|
||||
/>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<UBadge
|
||||
:label="statusLabel"
|
||||
:color="badgeColor"
|
||||
size="md"
|
||||
variant="subtle"
|
||||
class="status-badge"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -11,17 +60,154 @@ const props = defineProps<{
|
||||
status: ComplianceStatus
|
||||
}>()
|
||||
|
||||
const statusEmoji = computed(() => {
|
||||
const circumference = 2 * Math.PI * 20
|
||||
|
||||
const shieldIcon = computed(() => {
|
||||
switch (props.status) {
|
||||
case ComplianceStatus.Critical:
|
||||
return '🔴'
|
||||
return 'i-lucide-shield-alert'
|
||||
case ComplianceStatus.Warning:
|
||||
return '🟡'
|
||||
return 'i-lucide-shield-x'
|
||||
case ComplianceStatus.NonCritical:
|
||||
return '🟢'
|
||||
return 'i-lucide-shield-check'
|
||||
default:
|
||||
return '🟢'
|
||||
return 'i-lucide-shield-check'
|
||||
}
|
||||
})
|
||||
|
||||
const statusLabel = computed(() => {
|
||||
switch (props.status) {
|
||||
case ComplianceStatus.Critical:
|
||||
return 'Kritisch'
|
||||
case ComplianceStatus.Warning:
|
||||
return 'Warnung'
|
||||
case ComplianceStatus.NonCritical:
|
||||
return 'Unkritisch'
|
||||
default:
|
||||
return 'Unkritisch'
|
||||
}
|
||||
})
|
||||
|
||||
const badgeColor = computed(() => {
|
||||
switch (props.status) {
|
||||
case ComplianceStatus.Critical:
|
||||
return 'red'
|
||||
case ComplianceStatus.Warning:
|
||||
return 'yellow'
|
||||
case ComplianceStatus.NonCritical:
|
||||
return 'green'
|
||||
default:
|
||||
return 'green'
|
||||
}
|
||||
})
|
||||
|
||||
const ringClass = computed(() => {
|
||||
switch (props.status) {
|
||||
case ComplianceStatus.Critical:
|
||||
return 'text-red-500'
|
||||
case ComplianceStatus.Warning:
|
||||
return 'text-yellow-500'
|
||||
case ComplianceStatus.NonCritical:
|
||||
return 'text-green-500'
|
||||
default:
|
||||
return 'text-green-500'
|
||||
}
|
||||
})
|
||||
|
||||
const iconClass = computed(() => {
|
||||
switch (props.status) {
|
||||
case ComplianceStatus.Critical:
|
||||
return 'text-red-500 w-6 h-6'
|
||||
case ComplianceStatus.Warning:
|
||||
return 'text-yellow-500 w-6 h-6'
|
||||
case ComplianceStatus.NonCritical:
|
||||
return 'text-green-500 w-6 h-6'
|
||||
default:
|
||||
return 'text-green-500 w-6 h-6'
|
||||
}
|
||||
})
|
||||
|
||||
const progressValue = computed(() => {
|
||||
switch (props.status) {
|
||||
case ComplianceStatus.Critical:
|
||||
return 100
|
||||
case ComplianceStatus.Warning:
|
||||
return 60
|
||||
case ComplianceStatus.NonCritical:
|
||||
return 30
|
||||
default:
|
||||
return 30
|
||||
}
|
||||
})
|
||||
|
||||
const progressOffset = computed(() => {
|
||||
return circumference - (progressValue.value / 100) * circumference
|
||||
})
|
||||
|
||||
watch(() => props.status, () => {
|
||||
const element = document.querySelector('.shield-ring')
|
||||
if (element) {
|
||||
element.classList.add('status-change-pulse')
|
||||
setTimeout(() => {
|
||||
element.classList.remove('status-change-pulse')
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.shield-ring {
|
||||
transition: color 300ms ease-in-out;
|
||||
}
|
||||
|
||||
.ring-progress {
|
||||
transition: stroke-dashoffset 500ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.shield-icon {
|
||||
transition: color 300ms ease-in-out;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
transition: all 300ms ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes pulse-ring {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.status-change-pulse {
|
||||
animation: pulse-ring 600ms ease-in-out;
|
||||
}
|
||||
|
||||
.shield-pulse-enter-active,
|
||||
.shield-pulse-leave-active {
|
||||
transition: all 300ms ease-in-out;
|
||||
}
|
||||
|
||||
.shield-pulse-enter-from {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
.shield-pulse-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.shield-icon {
|
||||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
<UDashboardToolbar>
|
||||
<UNavigationMenu :items="links" highlight class="-mx-1 flex-1" />
|
||||
<FormValidationIndicator :status="validationStatus" />
|
||||
</UDashboardToolbar>
|
||||
</template>
|
||||
|
||||
@@ -28,9 +29,7 @@
|
||||
@save="onSave"
|
||||
@submit="onSubmit"
|
||||
@navigate="handleNavigate"
|
||||
>
|
||||
<FormValidationIndicator :status="validationStatus" />
|
||||
</FormStepperWithNavigation>
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UDashboardPanel>
|
||||
|
||||
@@ -5,12 +5,10 @@
|
||||
<template #leading>
|
||||
<UDashboardSidebarCollapse />
|
||||
</template>
|
||||
|
||||
<template #right />
|
||||
</UDashboardNavbar>
|
||||
|
||||
<UDashboardToolbar>
|
||||
<template #left />
|
||||
<FormValidationIndicator :status="validationStatus" />
|
||||
</UDashboardToolbar>
|
||||
</template>
|
||||
|
||||
@@ -28,7 +26,6 @@
|
||||
@save="onSave"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<FormValidationIndicator :status="validationStatus" />
|
||||
<UFormField label="Name" class="mb-4">
|
||||
<UInput v-model="applicationFormTemplate.name" />
|
||||
</UFormField>
|
||||
|
||||
Reference in New Issue
Block a user