diff --git a/components/email/email-list-item.tsx b/components/email/email-list-item.tsx
index 0db55e12..f12b5a6d 100644
--- a/components/email/email-list-item.tsx
+++ b/components/email/email-list-item.tsx
@@ -51,9 +51,9 @@ export function EmailListItem({ email, selected, onClick, onContextMenu, onToggl
const isFocusedMailLayout = mailLayout === 'focus';
const inlinePreview = showPreview && email.preview ? ` ${email.preview}` : '';
- // Resolve color tags using keyword definitions from settings
+ // Resolve color tags using keyword definitions from settings; unknown tags fall back to gray
const colorTagIds = getEmailColorTags(email.keywords);
- const keywordDefs = colorTagIds.map(id => emailKeywords.find(k => k.id === id)).filter(Boolean) as typeof emailKeywords;
+ const keywordDefs = colorTagIds.map(id => emailKeywords.find(k => k.id === id) ?? { id, label: id, color: 'gray' });
// Use first tag for background coloring
const keywordDef = keywordDefs[0] ?? null;
const colorTag = keywordDef ? KEYWORD_PALETTE[keywordDef.color]?.bg ?? null : null;
diff --git a/components/email/email-viewer.tsx b/components/email/email-viewer.tsx
index e5000d14..eb8c1fb9 100644
--- a/components/email/email-viewer.tsx
+++ b/components/email/email-viewer.tsx
@@ -3070,13 +3070,13 @@ export function EmailViewer({
<>
{currentColors.slice(0, 3).map((tagId) => {
- const kw = emailKeywords.find(k => k.id === tagId);
- return kw ? : null;
+ const kw = emailKeywords.find(k => k.id === tagId) ?? { id: tagId, label: tagId, color: 'gray' };
+ return ;
})}
{showToolbarLabels && currentColors.length === 1 && (
- {emailKeywords.find(k => k.id === currentColors[0])?.label}
+ {emailKeywords.find(k => k.id === currentColors[0])?.label ?? currentColors[0]}
)}
>
@@ -3674,11 +3674,11 @@ export function EmailViewer({
{currentColors.length > 0 && (
{currentColors.map((tagId) => {
- const kw = emailKeywords.find(k => k.id === tagId);
- const dotClass = kw ? KEYWORD_PALETTE[kw.color]?.dot : null;
- return dotClass ? (
-
- ) : null;
+ const kw = emailKeywords.find(k => k.id === tagId) ?? { id: tagId, label: tagId, color: 'gray' };
+ const dotClass = KEYWORD_PALETTE[kw.color]?.dot || 'bg-gray-500';
+ return (
+
+ );
})}
)}
diff --git a/components/email/thread-list-item.tsx b/components/email/thread-list-item.tsx
index 9ee8e705..819d180d 100644
--- a/components/email/thread-list-item.tsx
+++ b/components/email/thread-list-item.tsx
@@ -67,9 +67,9 @@ const SingleEmailItem = React.forwardRef(
const isFocusedMailLayout = mailLayout === 'focus';
const inlinePreview = showPreview && email.preview ? ` ${email.preview}` : '';
- // Resolve color tags using keyword definitions
+ // Resolve color tags using keyword definitions; unknown tags fall back to gray
const tagIds = getEmailColorTags(email.keywords);
- const resolvedKeywordDefs = tagIds.map(id => emailKeywords.find(k => k.id === id)).filter(Boolean) as typeof emailKeywords;
+ const resolvedKeywordDefs = tagIds.map(id => emailKeywords.find(k => k.id === id) ?? { id, label: id, color: 'gray' });
const resolvedKeywordDef = resolvedKeywordDefs[0] ?? null;
const resolvedColorTag = (() => {
if (colorTag) return colorTag;
@@ -375,7 +375,7 @@ export const ThreadListItem = React.forwardRef state.emailKeywords);
- const keywordDef = threadColor ? emailKeywordDefs.find(k => k.id === threadColor) : null;
+ const keywordDef = threadColor ? (emailKeywordDefs.find(k => k.id === threadColor) ?? { id: threadColor, label: threadColor, color: 'gray' }) : null;
const colorTag = keywordDef ? KEYWORD_PALETTE[keywordDef.color]?.bg ?? null : null;
const isSelected = selectedEmailId === latestEmail.id ||
diff --git a/components/filters/filter-rule-modal.tsx b/components/filters/filter-rule-modal.tsx
index 3dd5f4da..96c7b293 100644
--- a/components/filters/filter-rule-modal.tsx
+++ b/components/filters/filter-rule-modal.tsx
@@ -17,6 +17,7 @@ import type {
} from "@/lib/jmap/sieve-types";
import type { Mailbox } from "@/lib/jmap/types";
import { buildMailboxTree, flattenMailboxTree, type MailboxNode, generateUUID } from "@/lib/utils";
+import { useSettingsStore } from "@/stores/settings-store";
interface FilterRuleModalProps {
rule?: FilterRule;
@@ -58,6 +59,7 @@ export function FilterRuleModal({
}: FilterRuleModalProps) {
const t = useTranslations("settings.filters");
const isEdit = !!rule;
+ const emailKeywords = useSettingsStore((state) => state.emailKeywords);
const [name, setName] = useState(rule?.name || "");
const [matchType, setMatchType] = useState<"all" | "any">(rule?.matchType || "all");
@@ -375,12 +377,17 @@ export function FilterRuleModal({
)}
{action.type === "add_label" && (
- updateAction(index, { value: e.target.value })}
- placeholder={t("label_placeholder")}
- className="flex-1 min-w-[140px]"
- />
+ className={`${selectClass} flex-1 min-w-[140px]`}
+ aria-label={t("label_placeholder")}
+ >
+
+ {emailKeywords.map((kw) => (
+
+ ))}
+
)}