Paint each board row in its own notification type's colour
The carousel gold and the grid blue were hardcoded in the dashboard's CSS, which was fine while carousel meant Recognition and grid meant Recertification. Now that any type can take either style, a type arrived wearing somebody else's colour: a green Kudos row came out gold, and every grid row came out Recertification blue regardless of what was picked in the type settings. Row headings now take the type's colour, and cards and tiles take theirs through a --accent property, so a shared category row shows a red incident tile beside a purple change tile. Heading text colour is computed from the background's luma rather than listed per colour, since a site picks its own hexes - gold needs dark text, navy needs white. The card backgrounds were gold- and blue-tinted gradients; they are neutral dark now so the accent is what carries the colour. The old values remain as CSS fallbacks for a card that somehow arrives with no type.
This commit is contained in:
@@ -45,13 +45,17 @@
|
||||
|
||||
<!-- Carousel - one card at a time, rotating -->
|
||||
<section v-else-if="group.displaystyle === 'carousel'" class="recognition-section">
|
||||
<div class="section-title recognition">{{ group.typename }}</div>
|
||||
<div
|
||||
class="section-title recognition"
|
||||
:style="{ backgroundColor: getTypeColor(group.typecolor), color: textOn(group.typecolor) }"
|
||||
>{{ group.typename }}</div>
|
||||
<div class="recognition-carousel">
|
||||
<div
|
||||
v-for="(rec, idx) in group.items"
|
||||
:key="`${rec.notificationid}-${rec.employeesso}`"
|
||||
class="recognition-card"
|
||||
:class="{ active: idx === carouselIndex(group) }"
|
||||
:style="{ '--accent': getTypeColor(rec.typecolor) }"
|
||||
>
|
||||
<!-- A type that names no employee is a message, not a person:
|
||||
no photo frame, no empty name line. -->
|
||||
@@ -82,7 +86,10 @@
|
||||
|
||||
<!-- Grid - a row of tiles, cycling a page at a time -->
|
||||
<section v-else class="recert-section">
|
||||
<div class="section-title recert-title">
|
||||
<div
|
||||
class="section-title recert-title"
|
||||
:style="{ backgroundColor: getTypeColor(group.typecolor), color: textOn(group.typecolor) }"
|
||||
>
|
||||
<span>{{ group.typename }} ({{ group.items.length }})</span>
|
||||
<span v-if="gridRangeLabel(group)" class="recert-range">{{ gridRangeLabel(group) }}</span>
|
||||
</div>
|
||||
@@ -99,6 +106,7 @@
|
||||
:key="`grid-${rec.notificationid}-${rec.employeesso}`"
|
||||
class="recert-tile"
|
||||
:class="{ 'message-tile': !hasEmployee(rec) }"
|
||||
:style="{ '--accent': getTypeColor(rec.typecolor) }"
|
||||
>
|
||||
<template v-if="hasEmployee(rec)">
|
||||
<img
|
||||
@@ -265,6 +273,10 @@ const styledGroups = computed(() => {
|
||||
key,
|
||||
typename: heading,
|
||||
displaystyle: n.displaystyle,
|
||||
// Heading colour comes from the first type in the row. A shared
|
||||
// category is one heading, so it can only carry one colour; the
|
||||
// individual cards below still wear their own type's colour.
|
||||
typecolor: n.typecolor,
|
||||
items: []
|
||||
})
|
||||
}
|
||||
@@ -453,6 +465,19 @@ function getTypeColor(typecolor) {
|
||||
return aliases[typecolor] || typecolor || '#14abef'
|
||||
}
|
||||
|
||||
// Text colour for a heading painted an arbitrary type colour. Gold needs dark
|
||||
// text, navy needs white, and a site picks its own hexes - so this is computed
|
||||
// rather than a per-colour rule.
|
||||
function textOn(backgroundcolor) {
|
||||
const hex = getTypeColor(backgroundcolor).replace('#', '')
|
||||
if (hex.length < 6) return '#fff'
|
||||
const r = parseInt(hex.slice(0, 2), 16)
|
||||
const g = parseInt(hex.slice(2, 4), 16)
|
||||
const b = parseInt(hex.slice(4, 6), 16)
|
||||
// Rec. 709 luma, the usual quick contrast test.
|
||||
return (0.2126 * r + 0.7152 * g + 0.0722 * b) > 150 ? '#231b00' : '#fff'
|
||||
}
|
||||
|
||||
function getSectionClass(notifications) {
|
||||
// Use danger color if any active incidents
|
||||
const hasIncident = notifications.some(n => n.typecolor === 'danger' && !n.resolved)
|
||||
@@ -602,6 +627,7 @@ function handlePhotoError(e) {
|
||||
}
|
||||
|
||||
.section-title.recognition {
|
||||
/* Fallback only - the real colour is the type's, set inline. */
|
||||
background: #ffc107;
|
||||
color: #3a2e00;
|
||||
}
|
||||
@@ -612,6 +638,7 @@ function handlePhotoError(e) {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.section-title.recert-title {
|
||||
/* Fallback only - the real colour is the type's, set inline. */
|
||||
background: #0d6efd;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
@@ -638,8 +665,8 @@ function handlePhotoError(e) {
|
||||
gap: 14px;
|
||||
}
|
||||
.recert-tile {
|
||||
background: linear-gradient(135deg, #1e3a5f 0%, #0d2137 100%);
|
||||
border: 2px solid #0d6efd;
|
||||
background: linear-gradient(135deg, #16233b 0%, #0d2137 100%);
|
||||
border: 2px solid var(--accent, #0d6efd);
|
||||
border-radius: 10px;
|
||||
padding: 14px 10px;
|
||||
display: flex;
|
||||
@@ -653,7 +680,7 @@ function handlePhotoError(e) {
|
||||
height: 90px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid #0d6efd;
|
||||
border: 3px solid var(--accent, #0d6efd);
|
||||
background: #1a1a2e;
|
||||
}
|
||||
.recert-photo.ge-logo-fallback {
|
||||
@@ -713,8 +740,8 @@ function handlePhotoError(e) {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(135deg, #4a3a0a 0%, #2a2200 100%);
|
||||
border: 3px solid #ffc107;
|
||||
background: linear-gradient(135deg, #2b2718 0%, #1d1a10 100%);
|
||||
border: 3px solid var(--accent, #ffc107);
|
||||
border-radius: 12px;
|
||||
padding: 20px 25px;
|
||||
display: flex;
|
||||
@@ -736,7 +763,7 @@ function handlePhotoError(e) {
|
||||
height: 140px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 4px solid #ffc107;
|
||||
border: 4px solid var(--accent, #ffc107);
|
||||
background: #1a1a2e;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user