fix styling

This commit is contained in:
Lucas Gaitzsch
2026-05-22 18:14:57 +02:00
parent 401870c9bb
commit 9a302e5183
2 changed files with 79 additions and 40 deletions
+1 -10
View File
@@ -3,7 +3,7 @@
import { Email, ThreadGroup } from "@/lib/jmap/types"; import { Email, ThreadGroup } from "@/lib/jmap/types";
import { ThreadListItem } from "./thread-list-item"; import { ThreadListItem } from "./thread-list-item";
import { EmailContextMenu } from "./email-context-menu"; import { EmailContextMenu } from "./email-context-menu";
import { cn, formatDateTime } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Trash2, Mail, MailX, MailOpen, Loader2, SearchX, AlertTriangle, CalendarClock } from "lucide-react"; import { Trash2, Mail, MailX, MailOpen, Loader2, SearchX, AlertTriangle, CalendarClock } from "lucide-react";
import { useState, useEffect, useRef, useCallback, useMemo } from "react"; import { useState, useEffect, useRef, useCallback, useMemo } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -121,7 +121,6 @@ export function EmailList({
const density = useSettingsStore((state) => state.density); const density = useSettingsStore((state) => state.density);
const showPreview = useSettingsStore((state) => state.showPreview); const showPreview = useSettingsStore((state) => state.showPreview);
const mailLayout = useSettingsStore((state) => state.mailLayout); const mailLayout = useSettingsStore((state) => state.mailLayout);
const timeFormat = useSettingsStore((state) => state.timeFormat);
const isFocusedMailLayout = mailLayout === 'focus'; const isFocusedMailLayout = mailLayout === 'focus';
const footerHasMore = hasMore ?? hasMoreEmails; const footerHasMore = hasMore ?? hasMoreEmails;
const footerIsLoadingMore = isLoadingMoreItems ?? isLoadingMore; const footerIsLoadingMore = isLoadingMoreItems ?? isLoadingMore;
@@ -482,14 +481,6 @@ export function EmailList({
onSetColorTag={onSetColorTag} onSetColorTag={onSetColorTag}
onMarkAsSpam={onMarkAsSpam ? (email) => onMarkAsSpam(email) : undefined} onMarkAsSpam={onMarkAsSpam ? (email) => onMarkAsSpam(email) : undefined}
/> />
{isScheduledView && thread.latestEmail.isScheduled && (
<div className="flex flex-wrap items-center gap-2 border-b border-border bg-muted/10 px-4 py-2 text-xs">
<span className="flex items-center gap-1 text-muted-foreground">
<CalendarClock className="w-3.5 h-3.5" />
{thread.latestEmail.scheduledSendAt ? formatDateTime(thread.latestEmail.scheduledSendAt, timeFormat) : ''}
</span>
</div>
)}
</div> </div>
); );
})} })}
+78 -30
View File
@@ -1,11 +1,11 @@
"use client"; "use client";
import React, { useCallback } from "react"; import React, { useCallback } from "react";
import { formatDate, stripInvisibleLeading } from "@/lib/utils"; import { formatDate, formatDateTime, stripInvisibleLeading } from "@/lib/utils";
import { Email, ThreadGroup } from "@/lib/jmap/types"; import { Email, ThreadGroup } from "@/lib/jmap/types";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Avatar } from "@/components/ui/avatar"; import { Avatar } from "@/components/ui/avatar";
import { Paperclip, Star, Circle, ChevronRight, ChevronDown, Loader2, MessageSquare, CheckSquare, Square, Reply, Forward } from "lucide-react"; import { Paperclip, Star, Circle, ChevronRight, ChevronDown, Loader2, MessageSquare, CheckSquare, Square, Reply, Forward, CalendarClock } from "lucide-react";
import { useSettingsStore, KEYWORD_PALETTE } from "@/stores/settings-store"; import { useSettingsStore, KEYWORD_PALETTE } from "@/stores/settings-store";
import { useUIStore } from "@/stores/ui-store"; import { useUIStore } from "@/stores/ui-store";
import { useEmailStore } from "@/stores/email-store"; import { useEmailStore } from "@/stores/email-store";
@@ -67,6 +67,7 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
const emailKeywords = useSettingsStore((state) => state.emailKeywords); const emailKeywords = useSettingsStore((state) => state.emailKeywords);
const density = useSettingsStore((state) => state.density); const density = useSettingsStore((state) => state.density);
const mailLayout = useSettingsStore((state) => state.mailLayout); const mailLayout = useSettingsStore((state) => state.mailLayout);
const timeFormat = useSettingsStore((state) => state.timeFormat);
const showAvatarsInJunk = useSettingsStore((state) => state.showAvatarsInJunk); const showAvatarsInJunk = useSettingsStore((state) => state.showAvatarsInJunk);
const hideJunkAvatarImages = currentMailboxRole === 'junk' && !showAvatarsInJunk; const hideJunkAvatarImages = currentMailboxRole === 'junk' && !showAvatarsInJunk;
const isUnifiedView = useEmailStore((state) => state.isUnifiedView); const isUnifiedView = useEmailStore((state) => state.isUnifiedView);
@@ -76,6 +77,9 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
const isFocusedMailLayout = mailLayout === 'focus'; const isFocusedMailLayout = mailLayout === 'focus';
const trimmedPreview = stripInvisibleLeading(email.preview ?? ''); const trimmedPreview = stripInvisibleLeading(email.preview ?? '');
const inlinePreview = showPreview && trimmedPreview ? ` ${trimmedPreview}` : ''; const inlinePreview = showPreview && trimmedPreview ? ` ${trimmedPreview}` : '';
const scheduledSendLabel = email.isScheduled && email.scheduledSendAt
? formatDateTime(email.scheduledSendAt, timeFormat)
: null;
// Resolve color tags using keyword definitions; unknown tags fall back to gray // Resolve color tags using keyword definitions; unknown tags fall back to gray
const tagIds = getEmailColorTags(email.keywords); const tagIds = getEmailColorTags(email.keywords);
@@ -241,12 +245,22 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
{resolvedKeywordDefs.map((kd) => ( {resolvedKeywordDefs.map((kd) => (
<span key={kd.id} className={cn('h-2.5 w-2.5 rounded-full', KEYWORD_PALETTE[kd.color]?.dot || 'bg-gray-400')} /> <span key={kd.id} className={cn('h-2.5 w-2.5 rounded-full', KEYWORD_PALETTE[kd.color]?.dot || 'bg-gray-400')} />
))} ))}
<span className={cn( {scheduledSendLabel ? (
'text-xs tabular-nums', <span
isUnread ? 'text-foreground font-semibold' : 'text-muted-foreground' className="inline-flex max-w-[11rem] shrink-0 items-center gap-1 truncate rounded-full border border-sky-500/20 bg-sky-500/10 px-2 py-0.5 text-xs font-medium tabular-nums text-sky-700 dark:text-sky-300"
)}> title={scheduledSendLabel}
{formatDate(email.receivedAt)} >
</span> <CalendarClock className="h-3 w-3 shrink-0" />
<span className="truncate">{scheduledSendLabel}</span>
</span>
) : (
<span className={cn(
'text-xs tabular-nums',
isUnread ? 'text-foreground font-semibold' : 'text-muted-foreground'
)}>
{formatDate(email.receivedAt)}
</span>
)}
</div> </div>
</div> </div>
) : ( ) : (
@@ -299,14 +313,24 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
{kd.label} {kd.label}
</span> </span>
))} ))}
<span className={cn( {scheduledSendLabel ? (
"text-xs tabular-nums", <span
isUnread className="inline-flex max-w-[11rem] shrink-0 items-center gap-1 truncate rounded-full border border-sky-500/20 bg-sky-500/10 px-2 py-0.5 text-[11px] font-medium tabular-nums text-sky-700 dark:text-sky-300"
? "text-foreground font-semibold" title={scheduledSendLabel}
: "text-muted-foreground" >
)}> <CalendarClock className="h-3 w-3 shrink-0" />
{formatDate(email.receivedAt)} <span className="truncate">{scheduledSendLabel}</span>
</span> </span>
) : (
<span className={cn(
"text-xs tabular-nums",
isUnread
? "text-foreground font-semibold"
: "text-muted-foreground"
)}>
{formatDate(email.receivedAt)}
</span>
)}
</div> </div>
</div> </div>
@@ -376,12 +400,16 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
const showPreview = useSettingsStore((state) => state.showPreview); const showPreview = useSettingsStore((state) => state.showPreview);
const density = useSettingsStore((state) => state.density); const density = useSettingsStore((state) => state.density);
const mailLayout = useSettingsStore((state) => state.mailLayout); const mailLayout = useSettingsStore((state) => state.mailLayout);
const timeFormat = useSettingsStore((state) => state.timeFormat);
const showAvatarsInJunk = useSettingsStore((state) => state.showAvatarsInJunk); const showAvatarsInJunk = useSettingsStore((state) => state.showAvatarsInJunk);
const isMobile = useUIStore((state) => state.isMobile); const isMobile = useUIStore((state) => state.isMobile);
const { latestEmail, participantNames, hasUnread, hasStarred, hasAttachment, hasAnswered, hasForwarded, emailCount } = thread; const { latestEmail, participantNames, hasUnread, hasStarred, hasAttachment, hasAnswered, hasForwarded, emailCount } = thread;
const isFocusedMailLayout = mailLayout === 'focus'; const isFocusedMailLayout = mailLayout === 'focus';
const trimmedPreview = stripInvisibleLeading(latestEmail.preview ?? ''); const trimmedPreview = stripInvisibleLeading(latestEmail.preview ?? '');
const inlinePreview = showPreview && trimmedPreview ? ` ${trimmedPreview}` : ''; const inlinePreview = showPreview && trimmedPreview ? ` ${trimmedPreview}` : '';
const scheduledSendLabel = latestEmail.isScheduled && latestEmail.scheduledSendAt
? formatDateTime(latestEmail.scheduledSendAt, timeFormat)
: null;
const { selectedMailbox, mailboxes, selectedEmailIds, toggleEmailSelection, selectRangeEmails, clearSelection, isUnifiedView } = useEmailStore(); const { selectedMailbox, mailboxes, selectedEmailIds, toggleEmailSelection, selectRangeEmails, clearSelection, isUnifiedView } = useEmailStore();
const getAccountById = useAccountStore((state) => state.getAccountById); const getAccountById = useAccountStore((state) => state.getAccountById);
@@ -647,12 +675,22 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
{keywordDef && ( {keywordDef && (
<span className={cn('h-2.5 w-2.5 rounded-full', KEYWORD_PALETTE[keywordDef.color]?.dot || 'bg-gray-400')} /> <span className={cn('h-2.5 w-2.5 rounded-full', KEYWORD_PALETTE[keywordDef.color]?.dot || 'bg-gray-400')} />
)} )}
<span className={cn( {scheduledSendLabel ? (
'text-xs tabular-nums', <span
hasUnread ? 'text-foreground font-semibold' : 'text-muted-foreground' className="inline-flex max-w-[11rem] shrink-0 items-center gap-1 truncate rounded-full border border-sky-500/20 bg-sky-500/10 px-2 py-0.5 text-xs font-medium tabular-nums text-sky-700 dark:text-sky-300"
)}> title={scheduledSendLabel}
{formatDate(latestEmail.receivedAt)} >
</span> <CalendarClock className="h-3 w-3 shrink-0" />
<span className="truncate">{scheduledSendLabel}</span>
</span>
) : (
<span className={cn(
'text-xs tabular-nums',
hasUnread ? 'text-foreground font-semibold' : 'text-muted-foreground'
)}>
{formatDate(latestEmail.receivedAt)}
</span>
)}
</div> </div>
</div> </div>
) : ( ) : (
@@ -717,14 +755,24 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
{keywordDef.label} {keywordDef.label}
</span> </span>
)} )}
<span className={cn( {scheduledSendLabel ? (
"text-xs tabular-nums", <span
hasUnread className="inline-flex max-w-[11rem] shrink-0 items-center gap-1 truncate rounded-full border border-sky-500/20 bg-sky-500/10 px-2 py-0.5 text-[11px] font-medium tabular-nums text-sky-700 dark:text-sky-300"
? "text-foreground font-semibold" title={scheduledSendLabel}
: "text-muted-foreground" >
)}> <CalendarClock className="h-3 w-3 shrink-0" />
{formatDate(latestEmail.receivedAt)} <span className="truncate">{scheduledSendLabel}</span>
</span> </span>
) : (
<span className={cn(
"text-xs tabular-nums",
hasUnread
? "text-foreground font-semibold"
: "text-muted-foreground"
)}>
{formatDate(latestEmail.receivedAt)}
</span>
)}
</div> </div>
</div> </div>