diff --git a/web/src/styles/app.css b/web/src/styles/app.css index 84b69a7..9f9630f 100644 --- a/web/src/styles/app.css +++ b/web/src/styles/app.css @@ -642,7 +642,10 @@ a.menu-item:hover { color: var(--fg); } .vcard-card { margin: 0 16px 12px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-sunken); display: flex; align-items: center; gap: 12px; } .unsubscribe-row { margin: 0 16px 8px; font-size: .88em; color: var(--fg-muted); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .reply-box { margin: 8px 16px 24px; } -.reply-box .reply-prompt { display: flex; gap: 8px; align-items: center; padding: 12px; border: 1px solid var(--border); border-radius: var(--radius); color: var(--fg-muted); } +/* Wraps, because it does not fit. Three labelled buttons and an overflow need + about 390px of it, which a 430px phone has and a 360px one does not -- and it + was already over the line on the smaller ones before the overflow was added. */ +.reply-box .reply-prompt { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 12px; border: 1px solid var(--border); border-radius: var(--radius); color: var(--fg-muted); } .reply-box .reply-prompt button { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border-strong); color: var(--fg); font-weight: 500; } .reply-box .reply-prompt button:hover { background: var(--bg-hover); } .no-thread { height: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 8px; color: var(--fg-muted); } @@ -1214,6 +1217,9 @@ button.dp-open:disabled { cursor: default; opacity: .5; } .dp-time:hover { background: var(--bg-hover); } .dp-time.selected { background: var(--accent); color: var(--accent-fg); } @media (max-width: 480px) { + /* The spacer would take the whole of the first line and push the overflow + onto a line of its own; packed together they wrap as a group instead. */ + .reply-box .reply-prompt .spacer { display: none; } .dp-datetime { flex-wrap: wrap; } .dp-datetime .dp-time-field { flex: 1 1 100%; } .dp-split { flex-direction: column; } diff --git a/web/src/views/mail/ThreadView.tsx b/web/src/views/mail/ThreadView.tsx index 365ad5a..df8bb5f 100644 --- a/web/src/views/mail/ThreadView.tsx +++ b/web/src/views/mail/ThreadView.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { AlertOctagon, Archive, ArrowLeft, ChevronDown, ChevronUp, FolderInput, Forward, Mail, MailOpen, MoreVertical, Printer, Reply, ReplyAll, ShieldCheck, Star, Tag, Trash2, Download } from "lucide-react"; +import { AlertOctagon, Archive, ArrowLeft, ChevronDown, ChevronUp, FolderInput, Forward, Mail, MailOpen, MailPlus, MoreVertical, Printer, Reply, ReplyAll, ShieldCheck, Star, Tag, Trash2, Download } from "lucide-react"; import { useMail } from "@/store/mail"; import { useSettings } from "@/store/settings"; import { useCompose } from "@/store/compose"; @@ -42,6 +42,8 @@ export function ThreadView({ threadId, mailboxId, onBack, actions, onNavigate, h const [allExpanded, setAllExpanded] = useState(false); const [labelAnchor, setLabelAnchor] = useState<{ x: number; y: number } | null>(null); const moreMenu = useMenu(); + /** The overflow on the reply strip, which is the only per-message menu a phone offers easily. */ + const replyMore = useMenu(); const scrollRef = useRef(null); const markTimer = useRef(null); const isTouch = useIsTouch(); @@ -289,6 +291,19 @@ export function ThreadView({ threadId, mailboxId, onBack, actions, onNavigate, h + {/* + On a phone this strip is where a thumb goes, and the per-message + menu at the top of a card is not somewhere anybody looks for + "send this again" -- which is how compose-as-new came to be + reported missing on mobile when it was there all along (#181). + A fourth full button does not fit at 500px; this does, and it + spells the action out once opened. + */} + + + + } label={t("Compose as new")} onClick={() => void useCompose.getState().composeAsNew(last)} /> + )}