feat: improve visualization of tags

Previously tags where very much focused on color coding email and less about
adding additional information. They were also visualized in different ways in
different locations.

This commit gets rid of all "Color-coding" references, aligns visualization of
the tags across the whole project and tries to improve user experience of using
tags in general.

A search box is shown in the tagging control so the user can quickly search for
a tag if they have a huge (more than 10) amount of tags.
This commit is contained in:
Mathy Vanvoorden
2026-07-29 17:18:42 +02:00
parent 013ef7d557
commit 108406a885
46 changed files with 1102 additions and 832 deletions
+26 -9
View File
@@ -168,10 +168,10 @@ export const KEYWORD_PREFIX = "$label:";
export const KEYWORD_PREFIX_LEGACY = "$color:";
/**
* Gets all active label/color tag IDs from email keywords.
* Gets every tag id set on a message.
* Reads both the current $label: prefix and the legacy $color: prefix.
*/
export function getEmailColorTags(keywords: Record<string, boolean> | undefined): string[] {
export function getEmailTagIds(keywords: Record<string, boolean> | undefined): string[] {
if (!keywords) return [];
const tags: string[] = [];
for (const key of Object.keys(keywords)) {
@@ -187,22 +187,39 @@ export function getEmailColorTags(keywords: Record<string, boolean> | undefined)
}
/**
* Gets label/color tag from email keywords (if any).
* Gets the first tag id set on a message, if any.
* Reads both the current $label: prefix and the legacy $color: prefix.
* @deprecated Use getEmailColorTags for multi-tag support.
* @deprecated Use getEmailTagIds for multi-tag support.
*/
export function getEmailColorTag(keywords: Record<string, boolean> | undefined): string | null {
const tags = getEmailColorTags(keywords);
export function getEmailTagId(keywords: Record<string, boolean> | undefined): string | null {
const tags = getEmailTagIds(keywords);
return tags.length > 0 ? tags[0] : null;
}
/**
* Checks if a thread has any color tag (returns first found).
* The first tag id found anywhere in a thread, if any.
*/
export function getThreadColorTag(emails: Email[]): string | null {
export function getThreadTagId(emails: Email[]): string | null {
for (const email of emails) {
const color = getEmailColorTag(email.keywords);
const color = getEmailTagId(email.keywords);
if (color) return color;
}
return null;
}
/**
* Every tag anywhere in a thread, deduplicated.
*
* A collapsed thread row stands in for all its messages, so it has to account
* for all their tags - showing only the first message's would hide the rest
* with nothing to indicate they exist.
*/
export function getThreadTagIds(emails: Email[]): string[] {
const tags = new Set<string>();
for (const email of emails) {
for (const tag of getEmailTagIds(email.keywords)) {
tags.add(tag);
}
}
return [...tags];
}