feat: add "All Mail" view
This commit is contained in:
@@ -33,6 +33,7 @@ import {
|
||||
NotebookPen,
|
||||
CalendarClock,
|
||||
BellOff,
|
||||
Mails,
|
||||
} from "lucide-react";
|
||||
import { cn, buildMailboxTree, MailboxNode } from "@/lib/utils";
|
||||
import { Mailbox } from "@/lib/jmap/types";
|
||||
@@ -76,6 +77,8 @@ interface SidebarProps {
|
||||
onRefreshMailboxes?: () => void;
|
||||
scheduledTotal?: number;
|
||||
showScheduledMailbox?: boolean;
|
||||
/** Gated "All Mail" virtual folder that merges all of the account's folders. */
|
||||
showAllMailMailbox?: boolean;
|
||||
className?: string;
|
||||
/**
|
||||
* Multi-account (Pro) mode props. When `multiAccountMode` is true, the
|
||||
@@ -678,6 +681,7 @@ export function Sidebar({
|
||||
onRefreshMailboxes,
|
||||
scheduledTotal = 0,
|
||||
showScheduledMailbox = false,
|
||||
showAllMailMailbox = false,
|
||||
className,
|
||||
multiAccountMode = false,
|
||||
accountMailboxes,
|
||||
@@ -978,6 +982,16 @@ export function Sidebar({
|
||||
|
||||
{/* Mailbox List */}
|
||||
<div className="flex-1 overflow-y-auto" data-tour="sidebar">
|
||||
{showAllMailMailbox && (
|
||||
<SidebarRow
|
||||
icon={<Mails className={cn("w-4 h-4 flex-shrink-0", selectedMailbox === '__all_mail__' ? "text-foreground" : "text-muted-foreground")} />}
|
||||
label={t('mailboxes.all_mail')}
|
||||
depth={0}
|
||||
isSelected={!selectedKeyword && selectedMailbox === '__all_mail__'}
|
||||
onClick={() => onMailboxSelect?.('__all_mail__')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
{showUnified && (
|
||||
<div>
|
||||
<SidebarSectionHeader
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Check, Folder } from 'lucide-react';
|
||||
import { useSettingsStore, type ToolbarPosition, type MailLayout } from '@/stores/settings-store';
|
||||
import { SettingsSection, SettingItem, RadioGroup, ToggleSwitch } from './settings-section';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -117,11 +118,27 @@ function MailLayoutPreview({
|
||||
export function LayoutSettings() {
|
||||
const t = useTranslations('settings.appearance');
|
||||
const tEmail = useTranslations('settings.email_behavior');
|
||||
const { toolbarPosition, showToolbarLabels, hideAccountSwitcher, showRailAccountList, enableUnifiedMailbox, includeGroupInUnified, colorfulSidebarIcons, mailLayout, proInterface, updateSetting } = useSettingsStore();
|
||||
const { isSettingLocked, isSettingHidden } = usePolicyStore();
|
||||
const { toolbarPosition, showToolbarLabels, hideAccountSwitcher, showRailAccountList, enableUnifiedMailbox, includeGroupInUnified, enableAllMailView, allMailFolderIds, colorfulSidebarIcons, mailLayout, proInterface, updateSetting } = useSettingsStore();
|
||||
const { isSettingLocked, isSettingHidden, isFeatureEnabled } = usePolicyStore();
|
||||
const accounts = useAccountStore(s => s.accounts);
|
||||
const mailboxes = useEmailStore(s => s.mailboxes);
|
||||
const hasGroupInboxes = useMemo(() => mailboxes.some(m => m.isShared), [mailboxes]);
|
||||
const allMailViewAllowed = isFeatureEnabled('allMailViewEnabled');
|
||||
|
||||
// Own (non-shared) folders and the current All Mail selection. `null` =
|
||||
// never configured, which defaults to all non-special (no-role) folders.
|
||||
const ownMailboxes = useMemo(() => mailboxes.filter(m => !m.isShared), [mailboxes]);
|
||||
const allMailSelected = new Set(
|
||||
allMailFolderIds === null
|
||||
? ownMailboxes.filter(m => !m.role).map(m => m.id)
|
||||
: allMailFolderIds
|
||||
);
|
||||
const toggleAllMailFolder = (id: string) => {
|
||||
const next = new Set(allMailSelected);
|
||||
if (next.has(id)) next.delete(id);
|
||||
else next.add(id);
|
||||
updateSetting('allMailFolderIds', ownMailboxes.filter(m => next.has(m.id)).map(m => m.id));
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsSection title={t('title')} description={t('description')}>
|
||||
@@ -209,6 +226,56 @@ export function LayoutSettings() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{allMailViewAllowed && !isSettingHidden('enableAllMailView') && (
|
||||
<SettingItem
|
||||
label={t('all_mail.label')}
|
||||
description={t('all_mail.description')}
|
||||
locked={isSettingLocked('enableAllMailView')}
|
||||
>
|
||||
<ToggleSwitch
|
||||
checked={enableAllMailView}
|
||||
onChange={(v) => updateSetting('enableAllMailView', v)}
|
||||
/>
|
||||
</SettingItem>
|
||||
)}
|
||||
|
||||
{allMailViewAllowed && enableAllMailView && (
|
||||
<div className="ml-4 border-l-2 border-border pl-4 -mt-2 space-y-2">
|
||||
<div>
|
||||
<div className="text-sm font-medium text-foreground">{t('all_mail.folders_label')}</div>
|
||||
<div className="text-xs text-muted-foreground">{t('all_mail.folders_description')}</div>
|
||||
</div>
|
||||
{ownMailboxes.length === 0 ? (
|
||||
<p className="text-xs text-muted-foreground">{t('all_mail.no_folders')}</p>
|
||||
) : (
|
||||
<div className="space-y-0.5">
|
||||
{ownMailboxes.map((mb) => {
|
||||
const checked = allMailSelected.has(mb.id);
|
||||
return (
|
||||
<button
|
||||
key={mb.id}
|
||||
type="button"
|
||||
onClick={() => toggleAllMailFolder(mb.id)}
|
||||
className="w-full flex items-center gap-2.5 py-1.5 px-2 rounded-md hover:bg-muted/50 text-left"
|
||||
role="checkbox"
|
||||
aria-checked={checked}
|
||||
>
|
||||
<span className={cn(
|
||||
"flex items-center justify-center w-4 h-4 rounded border flex-shrink-0 transition-colors",
|
||||
checked ? "bg-primary border-primary text-primary-foreground" : "border-border"
|
||||
)}>
|
||||
{checked && <Check className="w-3 h-3" />}
|
||||
</span>
|
||||
<Folder className={cn("w-4 h-4 flex-shrink-0", mb.role ? "text-primary" : "text-muted-foreground")} />
|
||||
<span className="text-sm text-foreground truncate">{mb.name}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<SettingItem label={t('pro_interface.label')} description={t('pro_interface.description')}>
|
||||
<ToggleSwitch
|
||||
checked={proInterface}
|
||||
|
||||
Reference in New Issue
Block a user