feat: Replace traffic light with shield ring icon
This commit is contained in:
@@ -1,7 +1,56 @@
|
|||||||
<template>
|
<template>
|
||||||
<UPageCard title="Ampelstatus" variant="naked" orientation="horizontal" class="mb-4">
|
<div class="flex items-center gap-2">
|
||||||
{{ statusEmoji }}
|
<div class="relative flex items-center justify-center">
|
||||||
</UPageCard>
|
<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>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -11,17 +60,154 @@ const props = defineProps<{
|
|||||||
status: ComplianceStatus
|
status: ComplianceStatus
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const statusEmoji = computed(() => {
|
const circumference = 2 * Math.PI * 20
|
||||||
|
|
||||||
|
const shieldIcon = computed(() => {
|
||||||
switch (props.status) {
|
switch (props.status) {
|
||||||
case ComplianceStatus.Critical:
|
case ComplianceStatus.Critical:
|
||||||
return '🔴'
|
return 'i-lucide-shield-alert'
|
||||||
case ComplianceStatus.Warning:
|
case ComplianceStatus.Warning:
|
||||||
return '🟡'
|
return 'i-lucide-shield-x'
|
||||||
case ComplianceStatus.NonCritical:
|
case ComplianceStatus.NonCritical:
|
||||||
return '🟢'
|
return 'i-lucide-shield-check'
|
||||||
default:
|
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>
|
</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>
|
<UDashboardToolbar>
|
||||||
<UNavigationMenu :items="links" highlight class="-mx-1 flex-1" />
|
<UNavigationMenu :items="links" highlight class="-mx-1 flex-1" />
|
||||||
|
<FormValidationIndicator :status="validationStatus" />
|
||||||
</UDashboardToolbar>
|
</UDashboardToolbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -28,9 +29,7 @@
|
|||||||
@save="onSave"
|
@save="onSave"
|
||||||
@submit="onSubmit"
|
@submit="onSubmit"
|
||||||
@navigate="handleNavigate"
|
@navigate="handleNavigate"
|
||||||
>
|
/>
|
||||||
<FormValidationIndicator :status="validationStatus" />
|
|
||||||
</FormStepperWithNavigation>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UDashboardPanel>
|
</UDashboardPanel>
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
<template #leading>
|
<template #leading>
|
||||||
<UDashboardSidebarCollapse />
|
<UDashboardSidebarCollapse />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #right />
|
|
||||||
</UDashboardNavbar>
|
</UDashboardNavbar>
|
||||||
|
|
||||||
<UDashboardToolbar>
|
<UDashboardToolbar>
|
||||||
<template #left />
|
<FormValidationIndicator :status="validationStatus" />
|
||||||
</UDashboardToolbar>
|
</UDashboardToolbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -28,7 +26,6 @@
|
|||||||
@save="onSave"
|
@save="onSave"
|
||||||
@submit="onSubmit"
|
@submit="onSubmit"
|
||||||
>
|
>
|
||||||
<FormValidationIndicator :status="validationStatus" />
|
|
||||||
<UFormField label="Name" class="mb-4">
|
<UFormField label="Name" class="mb-4">
|
||||||
<UInput v-model="applicationFormTemplate.name" />
|
<UInput v-model="applicationFormTemplate.name" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
|
|||||||
Reference in New Issue
Block a user