mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: show section labels in sentence case instead of all caps
This commit is contained in:
@@ -1629,7 +1629,7 @@ function LoginPageContent() {
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<span className="w-full border-t border-border/60" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-xs uppercase">
|
||||
<div className="relative flex justify-center text-xs">
|
||||
<span className="bg-background/80 px-3 text-muted-foreground">{t("or")}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,7 +61,7 @@ const PAGE = adminPageDef('policy');
|
||||
|
||||
const fieldLabelClass = 'mb-1 block text-[11px] font-medium text-muted-foreground';
|
||||
const cardClass = 'rounded-md border border-border bg-muted/30 p-3';
|
||||
const subLabelClass = 'mt-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground';
|
||||
const subLabelClass = 'mt-2 text-xs font-semibold text-muted-foreground';
|
||||
|
||||
/** Mirrors the sanitizer's URL rule so the admin sees the drop before saving. */
|
||||
function isValidDefaultAppUrl(raw: string): boolean {
|
||||
|
||||
@@ -388,7 +388,7 @@ export function ThemesPage() {
|
||||
))}
|
||||
{themes.length > 0 && (
|
||||
<>
|
||||
<p className="mt-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Installed</p>
|
||||
<p className="mt-2 text-xs font-semibold text-muted-foreground">Installed</p>
|
||||
{themes.map(theme => (
|
||||
<SettingItem key={theme.id} label={theme.name}>
|
||||
<ToggleSwitch checked={!disabledInstalled.includes(theme.id)} onChange={() => toggleAdminTheme(theme.id)} />
|
||||
|
||||
@@ -1610,7 +1610,7 @@ function SummaryGroup({ icon, title, children }: { icon: ReactNode; title: strin
|
||||
<div className="bg-card/50">
|
||||
<div className="flex items-center gap-2 px-3 py-2 bg-muted/40">
|
||||
<span className="text-muted-foreground">{icon}</span>
|
||||
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">{title}</span>
|
||||
<span className="text-xs font-semibold text-muted-foreground">{title}</span>
|
||||
</div>
|
||||
<div className="px-3 py-2 space-y-1.5">{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -226,8 +226,6 @@
|
||||
color: var(--pr-muted);
|
||||
font-size: 7.5pt;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.pr-month-week {
|
||||
@@ -332,8 +330,6 @@
|
||||
color: var(--pr-muted);
|
||||
font-size: 7.5pt;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.pr-tg-date {
|
||||
@@ -558,8 +554,6 @@
|
||||
color: var(--pr-muted);
|
||||
font-size: 7.5pt;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
break-after: avoid;
|
||||
}
|
||||
|
||||
@@ -655,8 +649,6 @@
|
||||
color: var(--pr-muted);
|
||||
font-size: 8.5pt;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
break-after: avoid;
|
||||
}
|
||||
|
||||
|
||||
@@ -328,7 +328,7 @@ export function AdminShell({ authenticated, isStalwartAutoLogin, configReadOnly,
|
||||
{groupIndex > 0 && <div className="mx-5 my-2 border-t border-border" />}
|
||||
{group.label && (
|
||||
<div className="px-5 pb-1.5 pt-3">
|
||||
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">{group.label}</span>
|
||||
<span className="text-xs font-semibold text-muted-foreground">{group.label}</span>
|
||||
</div>
|
||||
)}
|
||||
{group.items.map(({ page, sections }) => {
|
||||
@@ -414,7 +414,7 @@ export function AdminShell({ authenticated, isStalwartAutoLogin, configReadOnly,
|
||||
{groupIndex > 0 && <div className="mx-1 my-2 border-t border-border" />}
|
||||
{group.label && (
|
||||
<div className="px-3 pb-1 pt-2.5">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">{group.label}</span>
|
||||
<span className="text-[11px] font-semibold text-muted-foreground">{group.label}</span>
|
||||
</div>
|
||||
)}
|
||||
{group.items.map(({ page, sections }) => {
|
||||
|
||||
@@ -218,7 +218,7 @@ export function CalendarAgendaView({
|
||||
</span>
|
||||
<span className="min-w-0 leading-tight">
|
||||
<span className={cn(
|
||||
"block text-[11px] font-medium uppercase tracking-wide truncate",
|
||||
"block text-[11px] font-medium truncate first-letter:uppercase",
|
||||
today ? "text-primary" : "text-muted-foreground",
|
||||
)}>
|
||||
{intlFormatter.dateTime(group.date, { month: "short", weekday: "short" })}
|
||||
|
||||
@@ -371,7 +371,7 @@ export function CalendarDayView({
|
||||
aria-label={intlFormatter.dateTime(day, { weekday: "long", month: "long", day: "numeric", year: "numeric" })}
|
||||
>
|
||||
<div className={cn(
|
||||
"w-10 text-center text-[11px] font-medium uppercase tracking-wide",
|
||||
"w-10 text-center text-[11px] font-medium first-letter:uppercase",
|
||||
today ? "text-primary" : "text-muted-foreground",
|
||||
)}>
|
||||
{intlFormatter.dateTime(day, { weekday: "short" })}
|
||||
|
||||
@@ -169,7 +169,7 @@ export function CalendarSearchResults({
|
||||
|
||||
const section = (id: string, label: string, events: CalendarEvent[]) => events.length > 0 && (
|
||||
<section aria-labelledby={id} className="py-1">
|
||||
<h2 id={id} className="px-2 sm:px-4 pt-3 pb-1 text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
<h2 id={id} className="px-2 sm:px-4 pt-3 pb-1 text-xs font-medium text-muted-foreground">
|
||||
{label}
|
||||
</h2>
|
||||
<div className="px-1 sm:px-2">{events.map(renderRow)}</div>
|
||||
|
||||
@@ -483,7 +483,7 @@ export function CalendarSidebarPanel({
|
||||
) : (
|
||||
<ChevronRight className="w-3 h-3 text-muted-foreground flex-shrink-0" />
|
||||
)}
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider truncate" title={label}>{label}</span>
|
||||
<span className="text-xs font-medium text-muted-foreground truncate" title={label}>{label}</span>
|
||||
</button>
|
||||
{onAdd && (
|
||||
<IconButton
|
||||
@@ -571,7 +571,7 @@ export function CalendarSidebarPanel({
|
||||
<div className="mt-1">
|
||||
{owned.length > 0 && (
|
||||
<div>
|
||||
<div className="ps-5 pe-3 py-0.5 text-[10px] font-medium text-muted-foreground/80 uppercase tracking-wider">
|
||||
<div className="ps-5 pe-3 py-0.5 text-[11px] font-medium text-muted-foreground/80">
|
||||
{t('my_calendars')}
|
||||
</div>
|
||||
<div>
|
||||
@@ -581,7 +581,7 @@ export function CalendarSidebarPanel({
|
||||
)}
|
||||
{sharedGroups.map((sg) => (
|
||||
<div key={`${group.key}-shared-${sg.label}`} className="mt-2">
|
||||
<div className="ps-5 pe-3 py-0.5 text-[10px] font-medium text-muted-foreground/80 uppercase tracking-wider flex items-center gap-1">
|
||||
<div className="ps-5 pe-3 py-0.5 text-[11px] font-medium text-muted-foreground/80 flex items-center gap-1">
|
||||
<Share2 className="w-3 h-3" />
|
||||
{sg.label}
|
||||
</div>
|
||||
@@ -610,7 +610,7 @@ export function CalendarSidebarPanel({
|
||||
{renderSectionHeader('__others__', t('other_calendars'))}
|
||||
{!collapsedAccountGroups.has('__others__') && sharedAccountGroups.map((group) => (
|
||||
<div key={group.accountName} className="mt-2">
|
||||
<div className="ps-5 pe-3 py-0.5 text-[10px] font-medium text-muted-foreground/80 uppercase tracking-wider flex items-center gap-1">
|
||||
<div className="ps-5 pe-3 py-0.5 text-[11px] font-medium text-muted-foreground/80 flex items-center gap-1">
|
||||
<Share2 className="w-3 h-3" />
|
||||
{group.accountName}
|
||||
</div>
|
||||
|
||||
@@ -310,7 +310,7 @@ export function CalendarToolbar({
|
||||
</IconButton>
|
||||
{showCalendarDropdown && (
|
||||
<div className="absolute top-full end-0 mt-1 z-50 bg-popover border border-border rounded-lg shadow-lg p-2 min-w-[180px]">
|
||||
<h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2 px-1">
|
||||
<h3 className="text-xs font-medium text-muted-foreground mb-2 px-1">
|
||||
{t("my_calendars")}
|
||||
</h3>
|
||||
<div className="space-y-0.5">
|
||||
@@ -350,7 +350,7 @@ export function CalendarToolbar({
|
||||
}
|
||||
return Array.from(groups.values()).map((group) => (
|
||||
<div key={group.accountName} className="mt-2">
|
||||
<h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-1 px-1">
|
||||
<h3 className="text-xs font-medium text-muted-foreground mb-1 px-1">
|
||||
{group.accountName}
|
||||
</h3>
|
||||
<div className="space-y-0.5">
|
||||
|
||||
@@ -467,7 +467,7 @@ export function CalendarWeekView({
|
||||
className="flex flex-col items-center gap-0.5 pt-2 pb-1.5 border-e border-border last:border-e-0"
|
||||
>
|
||||
<div className={cn(
|
||||
"text-[11px] font-medium uppercase tracking-wide",
|
||||
"text-[11px] font-medium first-letter:uppercase",
|
||||
todayCol ? "text-primary" : "text-muted-foreground",
|
||||
)}>
|
||||
{intlFormatter.dateTime(day, { weekday: "short" })}
|
||||
|
||||
@@ -367,7 +367,7 @@ function CommandPalette({ onClose, onShowShortcuts }: { onClose: () => void; onS
|
||||
return (
|
||||
<li key={command.id} role="presentation">
|
||||
{showGroup && (
|
||||
<div aria-hidden="true" className="px-3 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div aria-hidden="true" className="px-3 pt-2 pb-1 text-[11px] font-semibold text-muted-foreground">
|
||||
{command.group}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -498,7 +498,7 @@ function formatContexts(contexts: Record<string, boolean> | undefined, label: (k
|
||||
export function Section({ title, children, className }: { title: string; children: React.ReactNode; className?: string }) {
|
||||
return (
|
||||
<section className={cn("py-6", className)}>
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-3">{title}</h3>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground mb-3">{title}</h3>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -145,7 +145,7 @@ function FormSection({ icon: Icon, title, children, collapsible, defaultOpen = t
|
||||
tabIndex={collapsible ? 0 : -1}
|
||||
>
|
||||
<Icon className="w-4 h-4 text-muted-foreground shrink-0" />
|
||||
<h3 className="flex-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">{title}</h3>
|
||||
<h3 className="flex-1 text-xs font-semibold text-muted-foreground">{title}</h3>
|
||||
{collapsible && (
|
||||
open ? <ChevronDown className="w-3.5 h-3.5 text-muted-foreground" /> : <ChevronRight className="w-3.5 h-3.5 text-muted-foreground" />
|
||||
)}
|
||||
|
||||
@@ -747,7 +747,7 @@ export function ContactList({
|
||||
<div>
|
||||
{groupedSections.map(({ letter, items }) => (
|
||||
<section key={letter} role="group" aria-label={letter}>
|
||||
<div aria-hidden className="sticky top-0 z-10 px-4 py-0.5 bg-background/90 backdrop-blur-sm text-[11px] font-medium text-muted-foreground/70 uppercase tracking-wide">
|
||||
<div aria-hidden className="sticky top-0 z-10 px-4 py-0.5 bg-background/90 backdrop-blur-sm text-[11px] font-medium text-muted-foreground/70">
|
||||
{letter}
|
||||
</div>
|
||||
{items.map(renderItem)}
|
||||
|
||||
@@ -364,7 +364,7 @@ export function ContactsSidebar({
|
||||
<ChevronRight className="w-3 h-3 text-muted-foreground" />
|
||||
)}
|
||||
<User className="w-3 h-3 text-muted-foreground" />
|
||||
<span className="text-xs font-semibold text-foreground/90 uppercase tracking-wider truncate">
|
||||
<span className="text-xs font-semibold text-foreground/90 truncate">
|
||||
{group.label}
|
||||
</span>
|
||||
</button>
|
||||
@@ -373,7 +373,7 @@ export function ContactsSidebar({
|
||||
<div className="ps-2">
|
||||
{owned.length > 0 && (
|
||||
<div className="mt-1">
|
||||
<div className="px-3 py-0.5 text-[10px] font-medium text-muted-foreground/80 uppercase tracking-wider">
|
||||
<div className="px-3 py-0.5 text-[11px] font-medium text-muted-foreground/80">
|
||||
{t("address_books.title")}
|
||||
</div>
|
||||
{owned.map((book) => (
|
||||
@@ -391,7 +391,7 @@ export function ContactsSidebar({
|
||||
)}
|
||||
{sharedGroups.map((sg) => (
|
||||
<div key={`${group.key}-shared-${sg.label}`} className="mt-1">
|
||||
<div className="px-3 py-0.5 text-[10px] font-medium text-muted-foreground/80 uppercase tracking-wider flex items-center gap-1">
|
||||
<div className="px-3 py-0.5 text-[11px] font-medium text-muted-foreground/80 flex items-center gap-1">
|
||||
<Share2 className="w-3 h-3" />
|
||||
{sg.label}
|
||||
</div>
|
||||
@@ -426,7 +426,7 @@ export function ContactsSidebar({
|
||||
) : (
|
||||
<ChevronDown className="w-3 h-3 text-muted-foreground" />
|
||||
)}
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
<span className="text-xs font-medium text-muted-foreground">
|
||||
{t("address_books.title")}
|
||||
</span>
|
||||
</button>
|
||||
@@ -468,7 +468,7 @@ export function ContactsSidebar({
|
||||
) : (
|
||||
<ChevronDown className="w-3 h-3 text-muted-foreground" />
|
||||
)}
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
<span className="text-xs font-medium text-muted-foreground">
|
||||
{t("tabs.groups")}
|
||||
</span>
|
||||
</button>
|
||||
@@ -506,7 +506,7 @@ export function ContactsSidebar({
|
||||
) : (
|
||||
<ChevronDown className="w-3 h-3 text-muted-foreground" />
|
||||
)}
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
<span className="text-xs font-medium text-muted-foreground">
|
||||
{t("detail.categories")}
|
||||
</span>
|
||||
</button>
|
||||
@@ -565,7 +565,7 @@ export function ContactsSidebar({
|
||||
<ChevronDown className="w-3 h-3 text-muted-foreground" />
|
||||
)}
|
||||
<Share2 className="w-3 h-3 text-muted-foreground" />
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider truncate">
|
||||
<span className="text-xs font-medium text-muted-foreground truncate">
|
||||
{t("address_books.shared_prefix", { name: group.accountName })}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@@ -893,7 +893,7 @@ export function CalendarInvitationBanner({ email }: CalendarInvitationBannerProp
|
||||
{/* Eyebrow + title + collapse */}
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="text-[11px] font-semibold text-muted-foreground">
|
||||
{bannerTitle}
|
||||
</div>
|
||||
{summary?.title && (
|
||||
|
||||
@@ -1064,7 +1064,7 @@ function SidebarSection({ icon: Icon, title, children }: { icon: React.Component
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1.5">
|
||||
<Icon className="w-3.5 h-3.5 text-muted-foreground" />
|
||||
<h4 className="text-xs font-medium text-muted-foreground uppercase tracking-wider">{title}</h4>
|
||||
<h4 className="text-xs font-medium text-muted-foreground">{title}</h4>
|
||||
</div>
|
||||
<div className="space-y-1 ps-5.5">{children}</div>
|
||||
</div>
|
||||
@@ -5270,7 +5270,7 @@ export function EmailViewer({
|
||||
const totalAttachmentSize = effectiveAttachments.reduce((s, a) => s + (a.size || 0), 0);
|
||||
const topMimeType = email.bodyStructure?.type;
|
||||
const SectionHeader = ({ children }: { children: React.ReactNode }) => (
|
||||
<div className="text-[10px] font-semibold tracking-wider text-muted-foreground uppercase mb-1.5">
|
||||
<div className="text-[11px] font-semibold text-muted-foreground mb-1.5">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -5304,7 +5304,7 @@ export function EmailViewer({
|
||||
>
|
||||
<Icon className={cn("w-3.5 h-3.5 flex-shrink-0", status.color)} />
|
||||
<span className="font-medium text-foreground">{name}</span>
|
||||
<span className={cn("text-[10px] uppercase tracking-wider", status.color)}>
|
||||
<span className={cn("text-[11px]", status.color)}>
|
||||
{translateAuthResult(result)}
|
||||
</span>
|
||||
{extra && (
|
||||
@@ -5454,7 +5454,7 @@ export function EmailViewer({
|
||||
)} />
|
||||
<span className="font-medium text-foreground">{t('authentication.spam_score')}</span>
|
||||
<span className={cn(
|
||||
"text-[10px] uppercase tracking-wider",
|
||||
"text-[11px]",
|
||||
email.spamScore > 5 ? "text-red-700 dark:text-red-400" :
|
||||
email.spamScore > 2 ? "text-amber-700 dark:text-amber-400" :
|
||||
"text-green-700 dark:text-green-400",
|
||||
@@ -5665,7 +5665,7 @@ export function EmailViewer({
|
||||
<ShieldAlert className="w-5 h-5" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="text-[11px] font-semibold text-muted-foreground">
|
||||
{senderVerificationLabel}
|
||||
</div>
|
||||
<div className="text-sm font-medium text-foreground break-words">
|
||||
@@ -5686,7 +5686,7 @@ export function EmailViewer({
|
||||
</div>
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<div>
|
||||
<div className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="text-[11px] font-semibold text-muted-foreground">
|
||||
External Content
|
||||
</div>
|
||||
<div className="text-sm font-medium text-foreground break-words">
|
||||
|
||||
@@ -130,7 +130,7 @@ export function PluginSearchResults({ surface, onOpenEmail }: PluginSearchResult
|
||||
onClick={() => toggle(group.id)}
|
||||
aria-expanded={open}
|
||||
aria-controls={listId}
|
||||
className="flex w-full items-center gap-1.5 px-3 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground hover:text-foreground"
|
||||
className="flex w-full items-center gap-1.5 px-3 py-1.5 text-xs font-semibold text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{open ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronRight className="h-3.5 w-3.5" />}
|
||||
<span className="truncate">{group.heading}</span>
|
||||
|
||||
@@ -18,7 +18,7 @@ export function ReadReceiptBanner({ requestedBy, onSend, onIgnore }: ReadReceipt
|
||||
const [state, setState] = useState<'idle' | 'sending' | 'sent'>('idle');
|
||||
|
||||
// Matches the host's "External Content" banner row: a round tinted icon chip,
|
||||
// an uppercase eyebrow, a foreground message, and neutral bordered actions.
|
||||
// a small muted label, a foreground message, and neutral bordered actions.
|
||||
if (state === 'sent') {
|
||||
return (
|
||||
<div className="flex items-center gap-3 py-1">
|
||||
@@ -37,7 +37,7 @@ export function ReadReceiptBanner({ requestedBy, onSend, onIgnore }: ReadReceipt
|
||||
</div>
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<div>
|
||||
<div className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="text-[11px] font-semibold text-muted-foreground">
|
||||
Read receipt
|
||||
</div>
|
||||
<div className="text-sm font-medium text-foreground break-words">
|
||||
|
||||
@@ -248,7 +248,7 @@ export function FilesSidebar({
|
||||
? <ChevronRight className="w-3 h-3 text-muted-foreground" />
|
||||
: <ChevronDown className="w-3 h-3 text-muted-foreground" />}
|
||||
{icon}
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider truncate">{label}</span>
|
||||
<span className="text-xs font-medium text-muted-foreground truncate">{label}</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ export function GlobalSearchPalette({ proShell = true }: { proShell?: boolean })
|
||||
if (hits.length === 0 && status.errors.length === 0 && status.status !== 'loading') return null;
|
||||
return (
|
||||
<div key={kind} className="py-1">
|
||||
<div className="flex items-center gap-2 px-3 pt-2 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
|
||||
<div className="flex items-center gap-2 px-3 pt-2 pb-1 text-xs font-semibold text-muted-foreground">
|
||||
{t(`scope_${kind}`)}
|
||||
<span className="inline-flex min-w-[18px] h-[18px] items-center justify-center rounded-full bg-muted px-1.5 text-[10px] font-semibold tabular-nums normal-case">
|
||||
{hits.length}
|
||||
@@ -171,7 +171,7 @@ export function GlobalSearchPalette({ proShell = true }: { proShell?: boolean })
|
||||
<div className="flex-1 min-h-0 overflow-y-auto py-1">
|
||||
{showRecent && (
|
||||
<div className="py-1">
|
||||
<div className="px-3 py-1 text-xs font-medium text-muted-foreground uppercase tracking-wide">{t('recent_searches')}</div>
|
||||
<div className="px-3 py-1 text-xs font-medium text-muted-foreground">{t('recent_searches')}</div>
|
||||
{recentSearches.map((term) => (
|
||||
<button
|
||||
key={term}
|
||||
|
||||
@@ -68,7 +68,7 @@ export function SearchResultList({ outcome, kinds, flat, selectedKey, onSelect,
|
||||
if (hits.length === 0 && status.errors.length === 0 && status.status !== 'loading') return null;
|
||||
return (
|
||||
<section key={kind} className="pb-2">
|
||||
<h3 className="flex items-center gap-2 px-3 pt-3 pb-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider sticky top-0 z-10 bg-background">
|
||||
<h3 className="flex items-center gap-2 px-3 pt-3 pb-1.5 text-xs font-semibold text-muted-foreground sticky top-0 z-10 bg-background">
|
||||
{t(`scope_${kind}`)}
|
||||
<span className="inline-flex min-w-[18px] h-[18px] items-center justify-center rounded-full bg-muted px-1.5 text-[10px] font-semibold tabular-nums normal-case">
|
||||
{hits.length}{status.hasMore ? '+' : ''}
|
||||
|
||||
@@ -127,7 +127,7 @@ export function KeyboardShortcutsModal({ isOpen, onClose, app }: KeyboardShortcu
|
||||
if (rows.length === 0 && !extra?.length) return null;
|
||||
return (
|
||||
<section key={section.id} className={cn(section.wide && "md:col-span-2")}>
|
||||
<h3 className="text-sm font-semibold text-foreground mb-3 uppercase tracking-wider">
|
||||
<h3 className="text-sm font-semibold text-foreground mb-3">
|
||||
{t(section.title)}
|
||||
</h3>
|
||||
{/* A wide section's two columns line up with the columns of the
|
||||
|
||||
@@ -111,7 +111,7 @@ function PanelHeader({ title, subtitle, href, onClose, children }: {
|
||||
return (
|
||||
<div className="flex items-start gap-1 px-4 pt-4 pb-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className={cn(subtitle ? "text-[11px] font-medium uppercase tracking-wider text-muted-foreground" : "text-[22px] leading-7")}>{title}</div>
|
||||
<div className={cn(subtitle ? "text-[11px] font-medium text-muted-foreground" : "text-[22px] leading-7")}>{title}</div>
|
||||
{subtitle && <div className="text-sm font-medium text-primary">{subtitle}</div>}
|
||||
</div>
|
||||
{children}
|
||||
|
||||
@@ -81,7 +81,7 @@ export function ProtocolAccountPicker({
|
||||
<dl className="space-y-1.5 text-sm">
|
||||
{details.map((detail) => (
|
||||
<div key={detail.label} className="grid grid-cols-[5.5rem_minmax(0,1fr)] gap-3">
|
||||
<dt className="text-xs font-medium uppercase tracking-wide text-muted-foreground">{detail.label}</dt>
|
||||
<dt className="text-xs font-medium text-muted-foreground">{detail.label}</dt>
|
||||
<dd className="truncate text-foreground" title={detail.value}>{detail.value}</dd>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -84,14 +84,14 @@ export function SearchSuggestions({
|
||||
|
||||
const heading =
|
||||
(i === 0 && hasRecent && suggestion.kind === "recent" && (
|
||||
<div className="px-3 pt-1 pb-0.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
<div className="px-3 pt-1 pb-0.5 text-[11px] font-medium text-muted-foreground">
|
||||
{t("suggestions_recent")}
|
||||
</div>
|
||||
)) ||
|
||||
(i === firstContactIndex && (
|
||||
<div
|
||||
className={cn(
|
||||
"px-3 pt-1 pb-0.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground",
|
||||
"px-3 pt-1 pb-0.5 text-[11px] font-medium text-muted-foreground",
|
||||
hasRecent && "mt-1 border-t border-border pt-2",
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -331,7 +331,7 @@ export function AddressBookManagementSettings() {
|
||||
.filter(([accountId]) => !managedAccountId || accountId === managedAccountId)
|
||||
.map(([accountId, group]) => (
|
||||
<div key={accountId} className="mt-4 space-y-2">
|
||||
<h4 className="text-xs font-medium text-muted-foreground uppercase tracking-wider flex items-center gap-1.5">
|
||||
<h4 className="text-xs font-medium text-muted-foreground flex items-center gap-1.5">
|
||||
<Share2 className="w-3 h-3" />
|
||||
{t("shared_prefix", { name: group.accountName })}
|
||||
</h4>
|
||||
|
||||
@@ -389,7 +389,7 @@ function PrincipalText({ principal }: { principal: Principal }) {
|
||||
<div className="flex items-center gap-2 truncate text-sm font-medium">
|
||||
<span className="truncate">{name}</span>
|
||||
{principal.type === "group" && (
|
||||
<span className="rounded bg-muted px-1 py-0.5 text-[10px] font-normal uppercase text-muted-foreground">{t("group")}</span>
|
||||
<span className="rounded bg-muted px-1 py-0.5 text-[11px] font-normal text-muted-foreground">{t("group")}</span>
|
||||
)}
|
||||
</div>
|
||||
{detail && <div className="truncate text-xs text-muted-foreground">{detail}</div>}
|
||||
|
||||
@@ -189,7 +189,7 @@ export function DelegatesSettings() {
|
||||
<div className="flex items-center gap-2 truncate text-sm font-medium">
|
||||
<span className="truncate">{display.name}</span>
|
||||
{principal?.type === "group" && (
|
||||
<span className="rounded bg-muted px-1 py-0.5 text-[10px] font-normal uppercase text-muted-foreground">{t("group")}</span>
|
||||
<span className="rounded bg-muted px-1 py-0.5 text-[11px] font-normal text-muted-foreground">{t("group")}</span>
|
||||
)}
|
||||
</div>
|
||||
{display.detail && <div className="truncate text-xs text-muted-foreground">{display.detail}</div>}
|
||||
|
||||
@@ -126,7 +126,7 @@ export function VisualRuleSummary({ rule }: { rule: FilterRule }) {
|
||||
return (
|
||||
<div className="mt-1.5 space-y-1 text-xs">
|
||||
<div className="flex items-baseline gap-1.5 flex-wrap">
|
||||
<span className="text-[10px] font-semibold uppercase tracking-wider text-blue-500 dark:text-blue-400">
|
||||
<span className="text-[11px] font-semibold text-blue-500 dark:text-blue-400">
|
||||
{t("if")}
|
||||
</span>
|
||||
{rule.conditions.map((c, i) => {
|
||||
@@ -167,7 +167,7 @@ export function VisualRuleSummary({ rule }: { rule: FilterRule }) {
|
||||
</div>
|
||||
|
||||
<div className="flex items-baseline gap-1.5 flex-wrap">
|
||||
<span className="text-[10px] font-semibold uppercase tracking-wider text-emerald-500 dark:text-emerald-400">
|
||||
<span className="text-[11px] font-semibold text-emerald-500 dark:text-emerald-400">
|
||||
{t("then")}
|
||||
</span>
|
||||
{rule.actions.map((a, i) => {
|
||||
@@ -188,7 +188,7 @@ export function VisualRuleSummary({ rule }: { rule: FilterRule }) {
|
||||
|
||||
{period && (
|
||||
<div className="flex items-baseline gap-1.5 flex-wrap">
|
||||
<span className="text-[10px] font-semibold uppercase tracking-wider text-violet-500 dark:text-violet-400">
|
||||
<span className="text-[11px] font-semibold text-violet-500 dark:text-violet-400">
|
||||
{t("period_title")}
|
||||
</span>
|
||||
<span className="min-w-0 max-w-full px-1.5 py-px rounded-sm bg-muted/60 text-foreground wrap-anywhere">
|
||||
|
||||
@@ -978,7 +978,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
{groupIndex > 0 && <div className="mx-5 my-2 border-t border-border" />}
|
||||
{group.label && (
|
||||
<div className="px-5 pt-3 pb-1.5">
|
||||
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-xs font-semibold text-muted-foreground">
|
||||
{group.label}
|
||||
</span>
|
||||
</div>
|
||||
@@ -1128,7 +1128,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
{groupIndex > 0 && <div className="mx-1 my-2 border-t border-border" />}
|
||||
{group.label && (
|
||||
<div className="px-3 pt-2.5 pb-1">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-[11px] font-semibold text-muted-foreground">
|
||||
{group.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -289,7 +289,7 @@ export function ShareCollectionDialog({
|
||||
<div className="text-sm font-medium truncate flex items-center gap-2">
|
||||
{p.name}
|
||||
{p.type === "group" && (
|
||||
<span className="text-[10px] uppercase font-normal text-muted-foreground bg-muted rounded px-1 py-0.5">
|
||||
<span className="text-[11px] font-normal text-muted-foreground bg-muted rounded px-1 py-0.5">
|
||||
{t("group")}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -128,7 +128,7 @@ export function TemplatePicker({ isOpen, onClose, onSelect, accountId }: Templat
|
||||
if (items.length === 0) return null;
|
||||
return (
|
||||
<div className="mb-4" key={`${source.key}:${title}`}>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-1 px-3">
|
||||
<h3 className="text-xs font-semibold text-muted-foreground mb-1 px-3">
|
||||
{title}
|
||||
</h3>
|
||||
<div className="space-y-0.5">{items.map((item) => renderTemplateItem(item, source))}</div>
|
||||
|
||||
@@ -61,7 +61,7 @@ describe('plugin UI kit components', () => {
|
||||
['components/files/file-views.tsx', 'border-b border-border/60'],
|
||||
['components/files/files-header.tsx', 'px-1.5 py-1 rounded-md transition-colors truncate max-w-[16rem]'],
|
||||
['components/email/email-viewer.tsx', 'w-10 h-10 rounded-full'],
|
||||
['components/email/email-viewer.tsx', 'text-[10px] font-semibold uppercase tracking-wider text-muted-foreground'],
|
||||
['components/email/email-viewer.tsx', 'text-[11px] font-semibold text-muted-foreground'],
|
||||
['components/email/email-viewer.tsx', 'inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md border border-border hover:bg-muted transition-colors min-h-[36px]'],
|
||||
['components/identity/identity-form.tsx', 'flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground transition-all duration-200'],
|
||||
];
|
||||
|
||||
@@ -1173,7 +1173,7 @@ export function InfoBar({ tone = 'neutral', icon, eyebrow, title, children, comp
|
||||
return (
|
||||
<div className="bk flex flex-wrap items-center gap-x-3 gap-y-1.5 px-6 py-1.5 border-b border-border bg-muted/30 text-sm">
|
||||
{icon && <span className={cn('w-6 h-6 rounded-full flex items-center justify-center flex-shrink-0', INFO_TONE[tone])}><Icon name={icon} size="sm" /></span>}
|
||||
{eyebrow && <span className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">{eyebrow}</span>}
|
||||
{eyebrow && <span className="text-[11px] font-semibold text-muted-foreground">{eyebrow}</span>}
|
||||
{title && <span className="min-w-0 flex-1 text-foreground break-words">{title}</span>}
|
||||
{children}
|
||||
</div>
|
||||
@@ -1191,7 +1191,7 @@ export function InfoBar({ tone = 'neutral', icon, eyebrow, title, children, comp
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
{(eyebrow || title) && (
|
||||
<div>
|
||||
{eyebrow && <div className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">{eyebrow}</div>}
|
||||
{eyebrow && <div className="text-[11px] font-semibold text-muted-foreground">{eyebrow}</div>}
|
||||
{title && <div className="text-sm font-medium text-foreground break-words">{title}</div>}
|
||||
</div>
|
||||
)}
|
||||
@@ -1332,7 +1332,7 @@ export function Panel({ children }: Children) {
|
||||
|
||||
/** The small caps heading of the message details' sections. */
|
||||
export function DetailHeading({ children }: Children) {
|
||||
return <div className="bk text-[10px] font-semibold tracking-wider text-muted-foreground uppercase mb-1.5">{children}</div>;
|
||||
return <div className="bk text-[11px] font-semibold text-muted-foreground mb-1.5">{children}</div>;
|
||||
}
|
||||
|
||||
/** Label and value rows like the message details (From, Date, Size...). Children are DetailRows. */
|
||||
|
||||
Reference in New Issue
Block a user