feat(notifications): introduce constants for notification icons and colors to streamline notification rendering across components

This commit is contained in:
Ajit Mehrotra
2025-12-15 17:41:24 -05:00
parent ad78a0251a
commit c2d2fbea40
6 changed files with 58 additions and 52 deletions
@@ -11,6 +11,7 @@ import type {
WarningAndAlertNotificationsQueryVariables,
} from '~/composables/gql/graphql';
import { NOTIFICATION_ICONS, NOTIFICATION_TOAST_COLORS } from '~/components/Notifications/constants';
import {
archiveNotification,
NOTIFICATION_FRAGMENT,
@@ -95,19 +96,19 @@ const importanceMeta: Record<
[NotificationImportance.ALERT]: {
label: 'Alert',
badge: 'bg-red-100 text-red-700 border border-red-300',
icon: 'i-lucide-octagon',
icon: NOTIFICATION_ICONS[NotificationImportance.ALERT],
accent: 'text-red-600',
},
[NotificationImportance.WARNING]: {
label: 'Warning',
badge: 'bg-amber-100 text-amber-700 border border-amber-300',
icon: 'i-lucide-alert-triangle',
icon: NOTIFICATION_ICONS[NotificationImportance.WARNING],
accent: 'text-amber-600',
},
[NotificationImportance.INFO]: {
label: 'Info',
badge: 'bg-blue-100 text-blue-700 border border-blue-300',
icon: 'i-lucide-alert-triangle',
icon: NOTIFICATION_ICONS[NotificationImportance.INFO],
accent: 'text-blue-600',
},
};
@@ -160,15 +161,7 @@ onNotificationAdded(({ data }) => {
if (notification.timestamp) {
// Trigger the global toast in tandem with the subscription update.
const funcMapping: Record<
NotificationImportance,
'error' | 'warning' | 'info' | 'primary' | 'secondary' | 'success' | 'neutral'
> = {
[NotificationImportance.ALERT]: 'error',
[NotificationImportance.WARNING]: 'warning',
[NotificationImportance.INFO]: 'success',
};
const color = funcMapping[notification.importance];
const color = NOTIFICATION_TOAST_COLORS[notification.importance];
const createOpener = () => ({
label: 'Open',
onClick: () => {
@@ -194,7 +187,11 @@ onNotificationAdded(({ data }) => {
<section class="flex flex-col gap-4 rounded-lg border border-amber-200 bg-white p-4 shadow-sm">
<header class="flex items-center justify-between gap-3">
<div class="flex items-center gap-2">
<UIcon name="i-lucide-alert-triangle" class="size-5 text-amber-600" aria-hidden="true" />
<UIcon
name="i-heroicons-exclamation-triangle-20-solid"
class="size-5 text-amber-600"
aria-hidden="true"
/>
<h2 class="text-base font-semibold text-gray-900">Warnings & Alerts</h2>
</div>
<span v-if="!loading" class="rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-700">
+12 -12
View File
@@ -5,6 +5,7 @@ import { cn } from '@unraid/ui';
import type { OverviewQuery } from '~/composables/gql/graphql';
import { NOTIFICATION_COLORS, NOTIFICATION_ICONS } from '~/components/Notifications/constants';
import { NotificationImportance as Importance } from '~/composables/gql/graphql';
const props = defineProps<{ overview?: OverviewQuery['notifications']['overview']; seen?: boolean }>();
@@ -26,19 +27,18 @@ const indicatorLevel = computed(() => {
});
const icon = computed<{ name: string; color: string } | null>(() => {
switch (indicatorLevel.value) {
case Importance.WARNING:
return {
name: 'i-heroicons-exclamation-triangle-20-solid',
color: 'text-yellow-500 translate-y-0.5',
};
case Importance.ALERT:
return {
name: 'i-heroicons-shield-exclamation-20-solid',
color: 'text-unraid-red',
};
const level = indicatorLevel.value;
if (level !== Importance.WARNING && level !== Importance.ALERT) {
return null;
}
return null;
return {
name: NOTIFICATION_ICONS[level],
color: cn(NOTIFICATION_COLORS[level], {
'translate-y-0.5': level === Importance.WARNING,
}),
};
});
</script>
+8 -17
View File
@@ -9,6 +9,7 @@ import { navigate } from '~/helpers/external-navigation';
import type { NotificationFragmentFragment } from '~/composables/gql/graphql';
import { NOTIFICATION_COLORS, NOTIFICATION_ICONS } from '~/components/Notifications/constants';
import {
archiveNotification as archiveMutation,
deleteNotification as deleteMutation,
@@ -29,24 +30,14 @@ const descriptionMarkup = computedAsync(async () => {
}, '');
const icon = computed<{ name: string; color: string } | null>(() => {
switch (props.importance) {
case 'INFO':
return {
name: 'i-heroicons-check-badge-20-solid',
color: 'text-unraid-green',
};
case 'WARNING':
return {
name: 'i-heroicons-exclamation-triangle-20-solid',
color: 'text-yellow-accent',
};
case 'ALERT':
return {
name: 'i-heroicons-shield-exclamation-20-solid',
color: 'text-unraid-red',
};
if (!props.importance || !NOTIFICATION_ICONS[props.importance]) {
return null;
}
return null;
return {
name: NOTIFICATION_ICONS[props.importance],
color: NOTIFICATION_COLORS[props.importance],
};
});
const archive = reactive(
+3 -1
View File
@@ -6,7 +6,9 @@ import { useQuery } from '@vue/apollo-composable';
import { vInfiniteScroll } from '@vueuse/components';
import { useDebounceFn } from '@vueuse/core';
import { dbgApolloError, extractGraphQLErrorMessage } from '~/helpers/functions';
import { extractGraphQLErrorMessage } from '~/helpers/functions';
// import { dbgApolloError } from '~/helpers/functions';
import type { ApolloError } from '@apollo/client/errors';
import type {
+2 -9
View File
@@ -6,6 +6,7 @@ import { useMutation, useQuery, useSubscription } from '@vue/apollo-composable';
import { navigate } from '~/helpers/external-navigation';
import ConfirmDialog from '~/components/ConfirmDialog.vue';
import { NOTIFICATION_TOAST_COLORS } from '~/components/Notifications/constants';
import {
archiveAllNotifications,
deleteArchivedNotifications,
@@ -95,15 +96,7 @@ onNotificationAdded(({ data }) => {
latestNotificationTimestamp.value = notif.timestamp;
}
const funcMapping: Record<
Importance,
'error' | 'warning' | 'info' | 'primary' | 'secondary' | 'success' | 'neutral'
> = {
[Importance.ALERT]: 'error',
[Importance.WARNING]: 'warning',
[Importance.INFO]: 'success',
};
const color = funcMapping[notif.importance];
const color = NOTIFICATION_TOAST_COLORS[notif.importance];
const createOpener = () => ({
label: t('notifications.sidebar.toastOpen'),
onClick: () => navigate(notif.link as string),
@@ -0,0 +1,23 @@
import { NotificationImportance } from '~/composables/gql/graphql';
export const NOTIFICATION_ICONS: Record<NotificationImportance, string> = {
[NotificationImportance.INFO]: 'i-heroicons-check-badge-20-solid',
[NotificationImportance.WARNING]: 'i-heroicons-exclamation-triangle-20-solid',
[NotificationImportance.ALERT]: 'i-heroicons-shield-exclamation-20-solid',
};
export const NOTIFICATION_COLORS: Record<NotificationImportance, string> = {
[NotificationImportance.INFO]: 'text-unraid-green',
[NotificationImportance.WARNING]: 'text-yellow-accent',
[NotificationImportance.ALERT]: 'text-unraid-red',
};
// Toast color mapping (used in Sidebar and CriticalNotifications)
export const NOTIFICATION_TOAST_COLORS: Record<
NotificationImportance,
'error' | 'warning' | 'info' | 'success'
> = {
[NotificationImportance.ALERT]: 'error',
[NotificationImportance.WARNING]: 'warning',
[NotificationImportance.INFO]: 'success',
};