FN-7601: distinguish task-detail priority chip colors by level
Give the TaskDetailModal priority chip distinct tinted borders/backgrounds per level so low/high/urgent/normal are visually distinguishable at a glance.
- Add per-level border-color and stronger background overrides for .detail-priority-chip.card-priority-badge--{low,high,urgent}, using the matching semantic color token (info/warning/error) with higher specificity than the shared base rule.
- Leave the FN-7585 shared base chip rule and FN-7597 neutral 'normal' treatment untouched; scope changes strictly to .detail-priority-chip so read-only TaskCard badge tints are unaffected.
- Add a regression test asserting each level has distinct, non-var(--border) border-colors and backgrounds, mutually distinct across levels, while the read-only TaskCard badge selectors remain unchanged.
Files changed:
.../dashboard/app/components/TaskDetailModal.css | 33 ++++++++++
...etailModal.responsive-and-dependencies.test.tsx | 71 ++++++++++++++++++++++
2 files changed, 104 insertions(+)
Fusion-Task-Id: FN-7601
Fusion-Task-Lineage: 1e2fc574-835c-43b0-8689-02884ad5c2d6
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -431,6 +431,39 @@ read-only TaskCard priority badge (out of scope) is untouched.
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:TaskDetail 2026-07-05-13:30:
|
||||
FN-7601 — the FN-7585 base `.detail-priority-chip` rule pins `border-color:
|
||||
var(--border)` for every level, so once the chip shrank to a compact 30px box
|
||||
the only remaining differentiator (the ~15-18% tint backgrounds inherited
|
||||
from `.card-priority-badge--{low,high,urgent}`) reads as the same washed-out
|
||||
box for low vs high. Give each non-neutral level its own tinted border AND a
|
||||
stronger background on top of the shared base/normal rules above (higher
|
||||
specificity via the `.detail-priority-chip.card-priority-badge--X` compound
|
||||
selector) so low/high/urgent are unmistakably distinct colors at a glance,
|
||||
while normal keeps the FN-7597 neutral treatment and the FN-7585 shared
|
||||
border-width/radius/min-height stay untouched. Scoped to `.detail-priority-chip`
|
||||
so the read-only `.card-priority-badge--{low,high,urgent}` tints in
|
||||
TaskCard.css (out of scope) are unaffected.
|
||||
*/
|
||||
.detail-priority-chip.card-priority-badge--low {
|
||||
background: color-mix(in srgb, var(--color-info) 22%, transparent);
|
||||
border-color: color-mix(in srgb, var(--color-info) 65%, var(--border));
|
||||
color: var(--color-info);
|
||||
}
|
||||
|
||||
.detail-priority-chip.card-priority-badge--high {
|
||||
background: color-mix(in srgb, var(--color-warning) 28%, transparent);
|
||||
border-color: color-mix(in srgb, var(--color-warning) 65%, var(--border));
|
||||
color: var(--color-warning);
|
||||
}
|
||||
|
||||
.detail-priority-chip.card-priority-badge--urgent {
|
||||
background: color-mix(in srgb, var(--color-error) 30%, transparent);
|
||||
border-color: color-mix(in srgb, var(--color-error) 65%, var(--border));
|
||||
color: var(--color-error-dark);
|
||||
}
|
||||
|
||||
.detail-priority-select {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
|
||||
@@ -304,6 +304,77 @@ describe("TaskDetailModal", () => {
|
||||
expect(prioritySavingBlock).not.toMatch(/border|min-height|padding/);
|
||||
});
|
||||
|
||||
it("makes low/high/urgent visibly distinct colors on the detail Priority chip, scoped away from TaskCard (FN-7601)", () => {
|
||||
const css = readDashboardStylesSource();
|
||||
|
||||
// FN-7585's shared base rule and FN-7597's neutral `normal` rule must
|
||||
// survive untouched — this task only ADDS per-level overrides on top.
|
||||
const baseChipBlock = getExactCssRuleBlock(css, ".detail-priority-chip");
|
||||
expect(baseChipBlock).toContain("border-width: var(--btn-border-width);");
|
||||
expect(baseChipBlock).toContain("border-color: var(--border);");
|
||||
expect(baseChipBlock).toContain("border-radius: var(--detail-control-border-radius);");
|
||||
const normalBlock = getExactCssRuleBlock(css, ".detail-priority-chip.card-priority-badge--normal");
|
||||
expect(normalBlock).toMatch(/background:\s*color-mix\(in srgb, var\(--text-muted\)/);
|
||||
expect(normalBlock).toContain("color: var(--text-muted);");
|
||||
|
||||
const lowBlock = getExactCssRuleBlock(css, ".detail-priority-chip.card-priority-badge--low");
|
||||
const highBlock = getExactCssRuleBlock(css, ".detail-priority-chip.card-priority-badge--high");
|
||||
const urgentBlock = getExactCssRuleBlock(css, ".detail-priority-chip.card-priority-badge--urgent");
|
||||
|
||||
// Each non-neutral level must declare its own tinted border-color AND
|
||||
// background, using the matching semantic token family.
|
||||
for (const [block, token] of [
|
||||
[lowBlock, "--color-info"],
|
||||
[highBlock, "--color-warning"],
|
||||
[urgentBlock, "--color-error"],
|
||||
] as const) {
|
||||
expect(block).not.toBe("");
|
||||
expect(block).toMatch(/border-color\s*:/);
|
||||
expect(block).toMatch(/background\s*:/);
|
||||
expect(block).toContain(token);
|
||||
}
|
||||
|
||||
// None of the per-level border-colors may resolve to the plain shared
|
||||
// `var(--border)` value used by the base rule — that was the original
|
||||
// bug (every level looked the same washed-out box).
|
||||
const borderColorOf = (block: string): string => {
|
||||
const match = block.match(/border-color\s*:\s*([^;]+);/);
|
||||
return match?.[1]?.trim() ?? "";
|
||||
};
|
||||
const backgroundOf = (block: string): string => {
|
||||
const match = block.match(/background\s*:\s*([^;]+);/);
|
||||
return match?.[1]?.trim() ?? "";
|
||||
};
|
||||
|
||||
const lowBorder = borderColorOf(lowBlock);
|
||||
const highBorder = borderColorOf(highBlock);
|
||||
const urgentBorder = borderColorOf(urgentBlock);
|
||||
|
||||
expect(lowBorder).not.toBe("var(--border)");
|
||||
expect(highBorder).not.toBe("var(--border)");
|
||||
expect(urgentBorder).not.toBe("var(--border)");
|
||||
|
||||
// Mutually distinct — low, high, and urgent must not collapse onto the
|
||||
// same border-color or background declaration as one another.
|
||||
expect(new Set([lowBorder, highBorder, urgentBorder]).size).toBe(3);
|
||||
const lowBg = backgroundOf(lowBlock);
|
||||
const highBg = backgroundOf(highBlock);
|
||||
const urgentBg = backgroundOf(urgentBlock);
|
||||
expect(new Set([lowBg, highBg, urgentBg]).size).toBe(3);
|
||||
|
||||
// `normal`'s background/border must remain distinct from all three tinted
|
||||
// levels (it keeps the FN-7597 neutral treatment, not a semantic tint).
|
||||
expect(new Set([backgroundOf(normalBlock), lowBg, highBg, urgentBg]).size).toBe(4);
|
||||
|
||||
// The read-only TaskCard badge tints referenced by TaskCard.css must be
|
||||
// untouched by this task — confirm no `.detail-priority-chip` compound
|
||||
// selector leaks a border-color override into the bare `.card-priority-badge--*`
|
||||
// selectors (those remain single-class, background/color-only rules).
|
||||
expect(css).toMatch(/\.card-priority-badge--low\s*\{\s*background:\s*color-mix\(in srgb, var\(--color-info\) 15%, transparent\);\s*color:\s*var\(--color-info\);\s*\}/);
|
||||
expect(css).toMatch(/\.card-priority-badge--high\s*\{\s*background:\s*color-mix\(in srgb, var\(--color-warning\) 18%, transparent\);\s*color:\s*var\(--color-warning\);\s*\}/);
|
||||
expect(css).toMatch(/\.card-priority-badge--urgent\s*\{\s*background:\s*color-mix\(in srgb, var\(--color-error\) 20%, transparent\);\s*color:\s*var\(--color-error-dark\);\s*\}/);
|
||||
});
|
||||
|
||||
it("keeps grouped timestamp metadata inline on desktop and mobile", () => {
|
||||
const css = readDashboardStylesSource();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user