Give a folder a colour from its right-click menu

Right-click a folder and pick one of the twelve colours the calendar
already uses, or clear it again. The colour tints the folder's icon; the
label keeps the sidebar's own contrast, which a dozen arbitrary colours
would not reliably give it.

Kept by mailbox id rather than by name, so a folder renamed or dragged
somewhere else keeps its colour. Stored in settings, which live in this
browser -- JMAP has nowhere on a Mailbox to put a colour, and every other
colour in the app, labels and event categories included, already works
this way. Worth knowing it does not follow you to another device.

The cascade needed care: .nav-item svg sets the colour on the icon
itself, so a colour inherited from a wrapper does nothing. Checking
getComputedStyle on the wrapper said the icon was purple while the pixels
stayed grey; the rule now targets the svg, and the check now reads the
pixels.
This commit is contained in:
2026-08-25 12:54:33 -07:00
parent 145abef3fe
commit 25046e85e3
5 changed files with 63 additions and 5 deletions
+15 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { canDropFolder, descendantIds, movable } from "../folderMove";
import { canDropFolder, descendantIds, folderColor, movable } from "../folderMove";
import type { Id, Mailbox } from "@/jmap/types";
const mb = (id: string, name: string, parentId: string | null, role: Mailbox["role"] = null): Mailbox =>
@@ -67,3 +67,17 @@ describe("canDropFolder", () => {
expect(canDropFolder(tree, "gone", "work")).toBe(false);
});
});
describe("folderColor", () => {
it("returns the colour chosen for that folder, and null for the rest", () => {
const colors = { work: "#7c3aed" };
expect(folderColor(colors, "work")).toBe("#7c3aed");
expect(folderColor(colors, "news")).toBeNull();
expect(folderColor({}, "work")).toBeNull();
});
it("is keyed by id, so a renamed folder keeps its colour", () => {
// The id is stable across a rename; the name and path are not.
expect(folderColor({ mb1: "#0f766e" }, "mb1")).toBe("#0f766e");
});
});
+5
View File
@@ -45,3 +45,8 @@ export function canDropFolder(mailboxes: Record<Id, Mailbox>, draggedId: Id, tar
if (!mailboxes[targetId]) return false;
return !descendantIds(mailboxes, draggedId).has(targetId);
}
/** The colour chosen for a folder, if any. Ids are used, so a rename keeps it. */
export function folderColor(colors: Record<string, string>, id: Id): string | null {
return colors[id] ?? null;
}