mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
feat: colour unified rows by account and give every tag a hue of its own
In the unified view each row can be shaded with its account colour instead of carrying an account dot, behind a layout setting. Tags keep their own generated hue on their chips.
This commit is contained in:
@@ -14,6 +14,18 @@ vi.mock('@/stores/auth-store', () => ({
|
||||
useAuthStore: () => ({ identities: [] }),
|
||||
}));
|
||||
|
||||
const ACCOUNT_TEAL = { id: 'acct-teal', avatarColor: '#0d9488', label: 'Teal account' };
|
||||
const accountState = {
|
||||
getAccountById: (id: string) => (id === ACCOUNT_TEAL.id ? ACCOUNT_TEAL : undefined),
|
||||
};
|
||||
vi.mock('@/stores/account-store', () => ({
|
||||
useAccountStore: Object.assign(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(selector: any) => (selector ? selector(accountState) : accountState),
|
||||
{ getState: () => accountState },
|
||||
),
|
||||
}));
|
||||
|
||||
const makeEmail = (overrides: Partial<Email> = {}): Email => ({
|
||||
id: 'email-1',
|
||||
threadId: 'thread-1',
|
||||
@@ -288,3 +300,83 @@ describe('ThreadListItem row tint', () => {
|
||||
expect(classes).toContain('bg-accent/40');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('ThreadListItem account row tint', () => {
|
||||
beforeEach(() => {
|
||||
useSettingsStore.setState({
|
||||
emailKeywords: [...DEFAULT_KEYWORDS],
|
||||
showPreview: false,
|
||||
mailLayout: 'split',
|
||||
tintListRowsByTag: true,
|
||||
tintListRowsByAccount: false,
|
||||
});
|
||||
useEmailStore.setState({
|
||||
selectedEmailIds: new Set<string>(),
|
||||
selectedMailbox: 'inbox',
|
||||
isUnifiedView: false,
|
||||
});
|
||||
});
|
||||
|
||||
const row = (c: HTMLElement) => c.querySelector('[data-subject="Test Subject"]');
|
||||
const accountEmail = () => makeEmail({ accountId: ACCOUNT_TEAL.id, accountLabel: ACCOUNT_TEAL.label });
|
||||
|
||||
it('tints the row with the account colour in the unified view', () => {
|
||||
useSettingsStore.setState({ tintListRowsByAccount: true });
|
||||
useEmailStore.setState({ isUnifiedView: true });
|
||||
|
||||
const { container } = renderRow(accountEmail());
|
||||
expect(row(container)!.className).toContain('bg-teal-100');
|
||||
});
|
||||
|
||||
it('leaves rows untinted outside the unified view', () => {
|
||||
useSettingsStore.setState({ tintListRowsByAccount: true });
|
||||
useEmailStore.setState({ isUnifiedView: false });
|
||||
|
||||
const { container } = renderRow(accountEmail());
|
||||
expect(row(container)!.className).not.toContain('bg-teal-100');
|
||||
});
|
||||
|
||||
it('does not tint by account while the setting is off', () => {
|
||||
useEmailStore.setState({ isUnifiedView: true });
|
||||
|
||||
const { container } = renderRow(accountEmail());
|
||||
expect(row(container)!.className).not.toContain('bg-teal-100');
|
||||
});
|
||||
|
||||
it('still tints when accountId matches no local account', () => {
|
||||
// Shared/group entries carry the JMAP owner id, which no AccountEntry
|
||||
// matches - the row must fall back to a colour from the label, not stay blank.
|
||||
useSettingsStore.setState({ tintListRowsByAccount: true });
|
||||
useEmailStore.setState({ isUnifiedView: true });
|
||||
const orphan = makeEmail({ accountId: 'jmap-owner-id-with-no-entry', accountLabel: 'luca@lucazanon.it' });
|
||||
|
||||
const { container } = renderRow(orphan);
|
||||
expect(row(container)!.className).toMatch(/bg-[a-z]+-\d+/);
|
||||
});
|
||||
|
||||
it('gives different accounts different tints', () => {
|
||||
useSettingsStore.setState({ tintListRowsByAccount: true });
|
||||
useEmailStore.setState({ isUnifiedView: true });
|
||||
|
||||
const a = renderRow(makeEmail({ accountId: 'x', accountLabel: 'luca@insulaab.it' }));
|
||||
const clsA = row(a.container)!.className.match(/bg-[a-z]+-\d+/)![0];
|
||||
a.unmount();
|
||||
const b = renderRow(makeEmail({ accountId: 'y', accountLabel: 'luca@lucazanon.it' }));
|
||||
const clsB = row(b.container)!.className.match(/bg-[a-z]+-\d+/)![0];
|
||||
|
||||
expect(clsA).not.toBe(clsB);
|
||||
});
|
||||
|
||||
it('outranks the tag tint', () => {
|
||||
useSettingsStore.setState({ tintListRowsByAccount: true });
|
||||
useEmailStore.setState({ isUnifiedView: true });
|
||||
const tagged = makeEmail({
|
||||
accountId: ACCOUNT_TEAL.id,
|
||||
keywords: { $seen: true, [`$label:${DEFAULT_KEYWORDS[0].id}`]: true },
|
||||
});
|
||||
|
||||
const { container } = renderRow(tagged);
|
||||
expect(row(container)!.className).toContain('bg-teal-100');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,8 @@ import type { Attachment } from "@/lib/jmap/types";
|
||||
import { SelectableAvatar } from "@/components/email/selectable-avatar";
|
||||
import { Paperclip, Star, Pin, Circle, ChevronRight, ChevronDown, Loader2, MessageSquare, CheckSquare, Square, Reply, Forward, CalendarClock, Folder, Archive, Trash2, MailOpen, ShieldAlert } from "lucide-react";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import { useSettingsStore } from "@/stores/settings-store";
|
||||
import { useSettingsStore, KEYWORD_PALETTE } from "@/stores/settings-store";
|
||||
import { accountTintKey, generateAvatarColor } from "@/lib/account-utils";
|
||||
import { useUIStore } from "@/stores/ui-store";
|
||||
import { useEmailStore } from "@/stores/email-store";
|
||||
import { useAccountStore, type AccountEntry } from "@/stores/account-store";
|
||||
@@ -176,6 +177,7 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
|
||||
const { sortTagIds, tagColor } = useKeywordFormat();
|
||||
const { variant: tagVariant, placement: tagPlacement } = useTagDisplay();
|
||||
const tintListRowsByTag = useSettingsStore((state) => state.tintListRowsByTag);
|
||||
const tintListRowsByAccount = useSettingsStore((state) => state.tintListRowsByAccount);
|
||||
const density = useSettingsStore((state) => state.density);
|
||||
const mailLayout = useSettingsStore((state) => state.mailLayout);
|
||||
const timeFormat = useSettingsStore((state) => state.timeFormat);
|
||||
@@ -202,7 +204,22 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
|
||||
: null;
|
||||
|
||||
const tagIds = sortTagIds(getEmailTagIds(email.keywords));
|
||||
const resolvedRowTint = !tintListRowsByTag ? null : (rowTint ?? (tagIds[0] ? tagColor(tagIds[0]).rowTint : null));
|
||||
// The account tint stands in for the per-account dot, so it outranks the
|
||||
// tag tint - the tag still shows its own colour on its chip.
|
||||
//
|
||||
// `accountId` only resolves to a local account for personal entries; shared
|
||||
// ones carry the JMAP owner id, which no AccountEntry matches. Falling back
|
||||
// to the reaching client and then to a colour derived from the label means
|
||||
// every row that knows which account it came from gets tinted, instead of
|
||||
// silently staying blank.
|
||||
const accountTintSource = accountColor
|
||||
?? (email.sourceClientAccountId ? getAccountById(email.sourceClientAccountId)?.avatarColor : undefined)
|
||||
?? (email.accountLabel ? generateAvatarColor(email.accountLabel) : undefined);
|
||||
const accountRowTint = (tintListRowsByAccount && isUnifiedView && accountTintSource)
|
||||
? (KEYWORD_PALETTE[accountTintKey(accountTintSource)]?.rowTint ?? null)
|
||||
: null;
|
||||
const resolvedRowTint = accountRowTint
|
||||
?? (!tintListRowsByTag ? null : (rowTint ?? (tagIds[0] ? tagColor(tagIds[0]).rowTint : null)));
|
||||
|
||||
const { dragHandlers, isDragging } = useEmailDrag({
|
||||
email,
|
||||
@@ -392,7 +409,7 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
|
||||
{isFocusedMailLayout ? (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||
{isUnifiedView && email.accountId && accountColor && (
|
||||
{isUnifiedView && email.accountId && accountColor && !tintListRowsByAccount && (
|
||||
<span
|
||||
className="w-2 h-2 rounded-full flex-shrink-0"
|
||||
style={{ backgroundColor: accountColor }}
|
||||
@@ -463,7 +480,7 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
|
||||
<>
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<div className="flex items-center gap-2 min-w-0 flex-1">
|
||||
{isUnifiedView && email.accountId && accountColor && (
|
||||
{isUnifiedView && email.accountId && accountColor && !tintListRowsByAccount && (
|
||||
<span
|
||||
className="w-2 h-2 rounded-full flex-shrink-0"
|
||||
style={{ backgroundColor: accountColor }}
|
||||
@@ -681,9 +698,17 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
|
||||
const { sortTagIds, tagColor } = useKeywordFormat();
|
||||
const { variant: tagVariant, placement: tagPlacement } = useTagDisplay();
|
||||
const tintListRowsByTag = useSettingsStore((state) => state.tintListRowsByTag);
|
||||
const tintListRowsByAccount = useSettingsStore((state) => state.tintListRowsByAccount);
|
||||
// A collapsed row speaks for every message under it, so it carries their tags too.
|
||||
const tagIds = sortTagIds(getThreadTagIds(thread.emails));
|
||||
const rowTint = (tintListRowsByTag && tagIds[0]) ? tagColor(tagIds[0]).rowTint : null;
|
||||
const threadTintSource = threadAccountColor
|
||||
?? (latestEmail.sourceClientAccountId ? getAccountById(latestEmail.sourceClientAccountId)?.avatarColor : undefined)
|
||||
?? (latestEmail.accountLabel ? generateAvatarColor(latestEmail.accountLabel) : undefined);
|
||||
const accountRowTint = (tintListRowsByAccount && isUnifiedView && threadTintSource)
|
||||
? (KEYWORD_PALETTE[accountTintKey(threadTintSource)]?.rowTint ?? null)
|
||||
: null;
|
||||
const rowTint = accountRowTint
|
||||
?? ((tintListRowsByTag && tagIds[0]) ? tagColor(tagIds[0]).rowTint : null);
|
||||
|
||||
const isSelected = selectedEmailId === latestEmail.id ||
|
||||
thread.emails.some(e => e.id === selectedEmailId);
|
||||
@@ -885,7 +910,7 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
|
||||
{isFocusedMailLayout ? (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||
{isUnifiedView && latestEmail.accountId && threadAccountColor && (
|
||||
{isUnifiedView && latestEmail.accountId && threadAccountColor && !tintListRowsByAccount && (
|
||||
<span
|
||||
className="w-2 h-2 rounded-full flex-shrink-0"
|
||||
style={{ backgroundColor: threadAccountColor }}
|
||||
@@ -962,7 +987,7 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
|
||||
<>
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<div className="flex items-center gap-2 min-w-0 flex-1">
|
||||
{isUnifiedView && latestEmail.accountId && threadAccountColor && (
|
||||
{isUnifiedView && latestEmail.accountId && threadAccountColor && !tintListRowsByAccount && (
|
||||
<span
|
||||
className="w-2 h-2 rounded-full flex-shrink-0"
|
||||
style={{ backgroundColor: threadAccountColor }}
|
||||
|
||||
@@ -118,7 +118,7 @@ function MailLayoutPreview({
|
||||
export function LayoutSettings() {
|
||||
const t = useTranslations('settings.appearance');
|
||||
const tEmail = useTranslations('settings.email_behavior');
|
||||
const { toolbarPosition, showToolbarLabels, hideAccountSwitcher, showRailAccountList, enableUnifiedMailbox, includeGroupInUnified, unifiedCrossAccount, allMailFolderIds, enableCrossUnreadView, enableCrossStarredView, enableCrossAllView, colorfulSidebarIcons, tintListRowsByTag, showFolderTotalCount, faviconUnreadBadge, mailLayout, proInterface, updateSetting } = useSettingsStore();
|
||||
const { toolbarPosition, showToolbarLabels, hideAccountSwitcher, showRailAccountList, enableUnifiedMailbox, includeGroupInUnified, unifiedCrossAccount, allMailFolderIds, enableCrossUnreadView, enableCrossStarredView, enableCrossAllView, colorfulSidebarIcons, tintListRowsByTag, tintListRowsByAccount, showFolderTotalCount, faviconUnreadBadge, mailLayout, proInterface, updateSetting } = useSettingsStore();
|
||||
const { isSettingLocked, isSettingHidden, isFeatureEnabled } = usePolicyStore();
|
||||
const accounts = useAccountStore(s => s.accounts);
|
||||
const activeAccountId = useAccountStore(s => s.activeAccountId);
|
||||
@@ -231,6 +231,13 @@ export function LayoutSettings() {
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('tint_list_rows_by_account.label')} description={t('tint_list_rows_by_account.description')}>
|
||||
<ToggleSwitch
|
||||
checked={tintListRowsByAccount}
|
||||
onChange={(checked) => updateSetting('tintListRowsByAccount', checked)}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('show_folder_total_count.label')} description={t('show_folder_total_count.description')}>
|
||||
<ToggleSwitch
|
||||
checked={showFolderTotalCount}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { useKeywordFormat } from '../use-keyword-format';
|
||||
import { useSettingsStore, KEYWORD_PALETTE, type KeywordDefinition } from '@/stores/settings-store';
|
||||
import { suggestKeywordColor } from '@/lib/keyword-discovery';
|
||||
|
||||
const TAGS: KeywordDefinition[] = [
|
||||
{ id: 'work', label: 'Work', color: 'blue' },
|
||||
@@ -22,18 +23,45 @@ describe('useKeywordFormat', () => {
|
||||
expect(result.current.tagColor('archive')).toBe(KEYWORD_PALETTE['red-dark']);
|
||||
});
|
||||
|
||||
it('falls back to grey for a keyword this client has no definition for', () => {
|
||||
// Set on the message by another client, or its tag was deleted here.
|
||||
it('gives a keyword it has no definition for a hue of its own', () => {
|
||||
// Set on the message by another client, applied by a server-side filter,
|
||||
// or its tag was deleted here. One shared grey made every such tag look
|
||||
// alike, which is when telling them apart matters most.
|
||||
const { result } = renderHook(() => useKeywordFormat());
|
||||
|
||||
expect(result.current.tagColor('never-heard-of-it')).toBe(KEYWORD_PALETTE.gray);
|
||||
expect(result.current.tagColor('never-heard-of-it'))
|
||||
.toBe(KEYWORD_PALETTE[suggestKeywordColor('never-heard-of-it')]);
|
||||
});
|
||||
|
||||
it('falls back to grey for a colour that is not in the palette', () => {
|
||||
it('matches the colour the settings screen would propose for that tag', () => {
|
||||
// Adopting a discovered tag must not make its colour jump.
|
||||
const { result } = renderHook(() => useKeywordFormat());
|
||||
|
||||
for (const id of ['netflix', 'humb', 'ebay']) {
|
||||
expect(result.current.tagColor(id)).toBe(KEYWORD_PALETTE[suggestKeywordColor(id)]);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps an undefined tag on the same hue across renders', () => {
|
||||
const a = renderHook(() => useKeywordFormat());
|
||||
const b = renderHook(() => useKeywordFormat());
|
||||
|
||||
expect(a.result.current.tagColor('humb')).toBe(b.result.current.tagColor('humb'));
|
||||
});
|
||||
|
||||
it('spreads undefined tags over several hues', () => {
|
||||
const { result } = renderHook(() => useKeywordFormat());
|
||||
const ids = ['humb', 'alie', 'ebay', 'zoop', 'fire', 'nexu', 'ubis', 'tlsreports'];
|
||||
|
||||
const dots = new Set(ids.map((id) => result.current.tagColor(id).dot));
|
||||
expect(dots.size).toBeGreaterThan(1);
|
||||
});
|
||||
|
||||
it('derives a hue for a definition whose colour is not in the palette', () => {
|
||||
useSettingsStore.setState({ emailKeywords: [{ id: 'odd', label: 'Odd', color: 'chartreuse' }] });
|
||||
const { result } = renderHook(() => useKeywordFormat());
|
||||
|
||||
expect(result.current.tagColor('odd')).toBe(KEYWORD_PALETTE.gray);
|
||||
expect(result.current.tagColor('odd')).toBe(KEYWORD_PALETTE[suggestKeywordColor('odd')]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
type KeywordColor,
|
||||
} from "@/stores/settings-store";
|
||||
import { formatKeyword, formatKeywordLabels, keywordRenderings } from "@/lib/keyword-format";
|
||||
import { suggestKeywordColor } from "@/lib/keyword-discovery";
|
||||
|
||||
/**
|
||||
* Names and colours tags for the screen, bound to the user's tag settings.
|
||||
@@ -31,13 +32,22 @@ export function useKeywordFormat() {
|
||||
tagNameCandidates: (id: string) => keywordRenderings(formatKeywordLabels(id, keywords, nested)),
|
||||
|
||||
/**
|
||||
* The tag's colour. Falls back to grey for a keyword this client has no
|
||||
* definition for - one created on another device, or whose tag was
|
||||
* deleted - so such a tag still shows rather than silently vanishing.
|
||||
* The tag's colour.
|
||||
*
|
||||
* A keyword this client has no definition for - one created on another
|
||||
* device, applied by a server-side filter, or whose tag was deleted -
|
||||
* still gets a hue of its own, derived from its id by the same function
|
||||
* that proposes colours for recovered tags. One shared grey made every
|
||||
* such tag look alike, which is exactly when telling them apart matters:
|
||||
* a mailbox filling up with server-assigned tags would show a single
|
||||
* undifferentiated colour. The hue is a pure function of the id, so it is
|
||||
* stable across reloads and devices, and it degrades to grey only when
|
||||
* the proposal names a colour the palette does not hold.
|
||||
*/
|
||||
tagColor: (id: string): KeywordColor => {
|
||||
const color = keywords.find((keyword) => keyword.id === id)?.color;
|
||||
return (color ? KEYWORD_PALETTE[color] : undefined) ?? KEYWORD_PALETTE[FALLBACK_KEYWORD_COLOR];
|
||||
if (color && KEYWORD_PALETTE[color]) return KEYWORD_PALETTE[color];
|
||||
return KEYWORD_PALETTE[suggestKeywordColor(id)] ?? KEYWORD_PALETTE[FALLBACK_KEYWORD_COLOR];
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,41 @@ export function generateAvatarColor(email: string): string {
|
||||
return colors[Math.abs(hash) % colors.length];
|
||||
}
|
||||
|
||||
/**
|
||||
* The `KEYWORD_PALETTE` key whose tint matches an account's avatar colour.
|
||||
*
|
||||
* Row tints are Tailwind class pairs (light + dark) rather than raw colours, so
|
||||
* an account's hex cannot be used directly as a background. Mapping onto the
|
||||
* shared tag palette keeps account tints in the same visual language as tag
|
||||
* tints and gets dark mode for free.
|
||||
*
|
||||
* These pick the palette's `-dark` variants. A tag tint can afford to be faint
|
||||
* because the tag also shows a coloured chip, but an account tint replaces the
|
||||
* account dot and has to carry that information on its own - the fainter
|
||||
* variants are close to invisible against the row background.
|
||||
*
|
||||
* The palette has no violet, so the two purple-ish avatar hues would collide.
|
||||
* Purple keeps `purple-dark` and violet falls back to the plain `purple`, whose
|
||||
* lighter wash still tells the two apart.
|
||||
*/
|
||||
export function accountTintKey(avatarColor: string | undefined): string {
|
||||
switch ((avatarColor ?? '').toLowerCase()) {
|
||||
case '#2563eb': return 'blue-dark';
|
||||
case '#7c3aed': return 'purple';
|
||||
case '#db2777': return 'pink-dark';
|
||||
case '#dc2626': return 'red-dark';
|
||||
case '#ea580c': return 'orange-dark';
|
||||
case '#d97706': return 'amber-dark';
|
||||
case '#65a30d': return 'lime-dark';
|
||||
case '#16a34a': return 'green-dark';
|
||||
case '#0d9488': return 'teal-dark';
|
||||
case '#0891b2': return 'cyan-dark';
|
||||
case '#6366f1': return 'indigo-dark';
|
||||
case '#9333ea': return 'purple-dark';
|
||||
default: return 'gray-dark';
|
||||
}
|
||||
}
|
||||
|
||||
/** Get initials for an avatar from a display name or email */
|
||||
export function getInitials(name: string, email?: string): string {
|
||||
if (name) {
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "تلوين صفوف القائمة بلون الوسم",
|
||||
"description": "تظليل كل صف رسالة بلون أول وسم فيها. عطّل هذا لإبقاء الصفوف عادية؛ ستظل نقاط الوسوم وشاراتها تظهر اللون."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "إظهار إجمالي عدد الرسائل",
|
||||
"description": "إظهار إجمالي عدد الرسائل بجانب المجلدات والوسوم، إلى جانب عدد غير المقروء. عطّل هذا لإظهار عدد غير المقروء فقط."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Acoloreix les files de la llista segons l'etiqueta",
|
||||
"description": "Ombreja cada fila de missatge amb el color de la primera etiqueta. Desactiveu-ho per mantenir les files planes; els punts i les etiquetes encara mostraran el color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Mostra el nombre total de missatges",
|
||||
"description": "Mostra el nombre total de missatges al costat de les carpetes i etiquetes, juntament amb el nombre de no llegits. Desactiveu-ho per mostrar només els no llegits."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Zobrazit celkový počet zpráv",
|
||||
"description": "Zobrazí celkový počet zpráv vedle složek a štítků spolu s počtem nepřečtených. Vypněte pro zobrazení pouze nepřečtených."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Vis samlet antal beskeder",
|
||||
"description": "Viser det samlede antal beskeder ud for mapper og tags sammen med antallet af ulæste. Slå fra for kun at vise ulæste."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Nachrichtenzeilen mit Tag-Farbe einfärben",
|
||||
"description": "Die einzelnen Nachrichtenzeilen mit der Farbe ihres ersten Tags einfärben. Deaktivieren Sie diese Option, um die Zeilen neutral zu halten; Tag-Punkte und -Markierungen zeigen die Farbe weiterhin an."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Gesamtzahl der Nachrichten anzeigen",
|
||||
"description": "Zeigt neben Ordnern und Tags die Gesamtzahl der Nachrichten zusätzlich zur Anzahl ungelesener Nachrichten an. Deaktivieren, um nur ungelesene Nachrichten anzuzeigen."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Show Total Message Count",
|
||||
"description": "Show the total message count next to folders and tags, alongside the unread count. Disable to show only unread counts."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Mostrar el número total de mensajes",
|
||||
"description": "Muestra el número total de mensajes junto a las carpetas y etiquetas, además del número de mensajes no leídos. Desactívalo para mostrar solo los no leídos."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "نمایش تعداد کل پیامها",
|
||||
"description": "تعداد کل پیامها را در کنار پوشهها و برچسبها، همراه با تعداد خواندهنشدهها نمایش میدهد. برای نمایش فقط تعداد خواندهنشدهها غیرفعال کنید."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Afficher le nombre total de messages",
|
||||
"description": "Affiche le nombre total de messages à côté des dossiers et des étiquettes, en plus du nombre de messages non lus. Désactivez pour n'afficher que les messages non lus."
|
||||
|
||||
@@ -1028,6 +1028,10 @@
|
||||
"label": "צביעת שורות הרשימה לפי צבע התגית",
|
||||
"description": "צובע כל שורת הודעה בצבע התגית הראשונה שלה. כבו כדי להשאיר את השורות ללא צבע; נקודות ותוויות התגיות עדיין יציגו את הצבע."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "הצגת מספר ההודעות הכולל",
|
||||
"description": "מציג את מספר ההודעות הכולל לצד תיקיות ותגיות, לצד מספר ההודעות שלא נקראו. כבו כדי להציג רק את מספר ההודעות שלא נקראו."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Összes üzenet számának megjelenítése",
|
||||
"description": "Megjeleníti az üzenetek teljes számát a mappák és címkék mellett, az olvasatlanok számán túl. Kapcsolja ki, ha csak az olvasatlanok számát szeretné látni."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Colora le righe in base all'account",
|
||||
"description": "Nella vista unificata, colora ogni riga con il colore del suo account invece di mostrare il pallino. Ha la precedenza sulla tinta del tag; i tag mantengono il loro colore sulle etichette."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Mostra il numero totale di messaggi",
|
||||
"description": "Mostra il numero totale di messaggi accanto a cartelle ed etichette, insieme al conteggio dei non letti. Disattiva per mostrare solo i non letti."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "メッセージの総数を表示",
|
||||
"description": "フォルダーやタグの横に、未読数に加えてメッセージの総数を表示します。未読数のみを表示するには無効にします。"
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "전체 메시지 수 표시",
|
||||
"description": "읽지 않은 수와 함께 폴더 및 태그 옆에 전체 메시지 수를 표시합니다. 읽지 않은 수만 표시하려면 비활성화하세요."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Rādīt kopējo ziņojumu skaitu",
|
||||
"description": "Rāda kopējo ziņojumu skaitu blakus mapēm un tagiem, kā arī nelasīto ziņojumu skaitu. Atspējojiet, lai rādītu tikai nelasītos."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Тагийн өнгөөр эгнээнүүдийг будах",
|
||||
"description": "Мессежийн мөр бүрийг эхний шошгоны өнгөөр сүүдэрлээрэй. Мөрүүдийг энгийн байлгахын тулд идэвхгүй болгох; шошгоны цэгүүд болон чипүүд нь өнгийг харуулсан хэвээр байна."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Нийт мессежийн тоог харуулах",
|
||||
"description": "Нийт мессежийн тоог хавтас, шошгоны хажууд уншаагүй тооны хажууд харуул. Зөвхөн уншаагүй тоонуудыг харуулахын тулд идэвхгүй болго."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Fargelegg meldingsrader etter etikett",
|
||||
"description": "Gi hver meldingsrad en svak bakgrunnsfarge basert på den første etiketten. Deaktiver dette for nøytrale rader; etikettmarkørene viser fortsatt fargen."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Vis totalt antall meldinger",
|
||||
"description": "Vis totalt antall meldinger ved siden av mapper og etiketter, sammen med antall uleste. Deaktiver for å vise bare antall uleste."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Totaal aantal berichten tonen",
|
||||
"description": "Toont het totale aantal berichten naast mappen en labels, naast het aantal ongelezen berichten. Schakel uit om alleen ongelezen aantallen te tonen."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Pokaż łączną liczbę wiadomości",
|
||||
"description": "Pokazuje łączną liczbę wiadomości obok folderów i etykiet, obok liczby nieprzeczytanych. Wyłącz, aby pokazywać tylko nieprzeczytane."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Mostrar contagem total de mensagens",
|
||||
"description": "Mostra a contagem total de mensagens ao lado de pastas e etiquetas, além da contagem de não lidas. Desative para mostrar apenas as não lidas."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Afișează numărul total de mesaje",
|
||||
"description": "Afișează numărul total de mesaje lângă foldere și etichete, pe lângă numărul celor necitite. Dezactivează pentru a afișa doar mesajele necitite."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Показывать общее количество сообщений",
|
||||
"description": "Показывает общее количество сообщений рядом с папками и метками, наряду с количеством непрочитанных. Отключите, чтобы показывать только непрочитанные."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Zobraziť celkový počet správ",
|
||||
"description": "Zobraziť celkový počet správ vedľa priečinkov a štítkov spolu s počtom neprečítaných."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Toplam mesaj sayısını göster",
|
||||
"description": "Klasörlerin ve etiketlerin yanında, okunmamış sayısının yanı sıra toplam mesaj sayısını gösterir. Yalnızca okunmamışları göstermek için devre dışı bırakın."
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "Показувати загальну кількість повідомлень",
|
||||
"description": "Показує загальну кількість повідомлень поруч із теками та мітками, разом із кількістю непрочитаних. Вимкніть, щоб показувати лише непрочитані."
|
||||
|
||||
@@ -1066,6 +1066,10 @@
|
||||
"label": "依標籤顏色為清單列上色",
|
||||
"description": "以第一個標籤的顏色為每封郵件列加上底色。停用後郵件列保持無底色,但標籤圓點與標籤仍會顯示該顏色。"
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "顯示郵件總數",
|
||||
"description": "在信件匣與標籤旁顯示郵件總數及未讀數量。停用後只顯示未讀數量。"
|
||||
|
||||
@@ -1063,6 +1063,10 @@
|
||||
"label": "Tint List Rows by Tag Color",
|
||||
"description": "Shade each message row with its first tag color. Disable to keep rows plain; tag dots and chips still show the color."
|
||||
},
|
||||
"tint_list_rows_by_account": {
|
||||
"label": "Tint List Rows by Account Color",
|
||||
"description": "In the unified view, shade each row with its account color instead of showing the account dot. Takes precedence over the tag tint; tags keep their color on their chips."
|
||||
},
|
||||
"show_folder_total_count": {
|
||||
"label": "显示邮件总数",
|
||||
"description": "在文件夹和标签旁边显示邮件总数,以及未读数量。停用后仅显示未读数量。"
|
||||
|
||||
@@ -454,6 +454,7 @@ interface SettingsState {
|
||||
// Sidebar
|
||||
colorfulSidebarIcons: boolean; // Tint folder icons by role (inbox blue, junk red, etc.)
|
||||
tintListRowsByTag: boolean; // Tint mail-list rows by the first tag color
|
||||
tintListRowsByAccount: boolean; // In the unified view, tint rows by account colour instead of showing the account dot
|
||||
showFolderTotalCount: boolean; // Show total message count next to folders/tags (alongside unread)
|
||||
|
||||
// Folders
|
||||
@@ -668,6 +669,7 @@ const DEFAULT_SETTINGS = {
|
||||
// Sidebar
|
||||
colorfulSidebarIcons: true,
|
||||
tintListRowsByTag: true,
|
||||
tintListRowsByAccount: false,
|
||||
showFolderTotalCount: true,
|
||||
|
||||
// Folders
|
||||
@@ -863,6 +865,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
faviconUnreadBadge: state.faviconUnreadBadge,
|
||||
colorfulSidebarIcons: state.colorfulSidebarIcons,
|
||||
tintListRowsByTag: state.tintListRowsByTag,
|
||||
tintListRowsByAccount: state.tintListRowsByAccount,
|
||||
showFolderTotalCount: state.showFolderTotalCount,
|
||||
folderIcons: state.folderIcons,
|
||||
emailKeywords: state.emailKeywords,
|
||||
|
||||
Reference in New Issue
Block a user