Merge pull request #358 from Coffey-Labs/fix/contacts-resizable-list
Let the contact list be resized, and give the contact the rest of the page
This commit is contained in:
@@ -25,7 +25,7 @@ describe("which settings follow the account", () => {
|
|||||||
const synced = syncedPart(DEFAULT_SETTINGS);
|
const synced = syncedPart(DEFAULT_SETTINGS);
|
||||||
// A pane width picked on a monitor is wrong on a laptop, and the
|
// A pane width picked on a monitor is wrong on a laptop, and the
|
||||||
// notification toggles track a per-browser permission grant.
|
// notification toggles track a per-browser permission grant.
|
||||||
for (const key of ["listPaneWidth", "listPaneHeight", "sidebarWidth", "density", "fontSize", "sidebarCollapsed", "desktopNotifications", "notificationSound"]) {
|
for (const key of ["listPaneWidth", "listPaneHeight", "contactsListWidth", "sidebarWidth", "density", "fontSize", "sidebarCollapsed", "desktopNotifications", "notificationSound"]) {
|
||||||
expect(synced, key).not.toHaveProperty(key);
|
expect(synced, key).not.toHaveProperty(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1215,6 +1215,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "Vollbild",
|
"Full screen": "Vollbild",
|
||||||
"Resize panes": "Bereichsgröße ändern",
|
"Resize panes": "Bereichsgröße ändern",
|
||||||
"Resize message list": "Größe der Nachrichtenliste ändern",
|
"Resize message list": "Größe der Nachrichtenliste ändern",
|
||||||
|
"Resize contact list": "Größe der Kontaktliste ändern",
|
||||||
"Resize sidebar": "Größe der Seitenleiste ändern",
|
"Resize sidebar": "Größe der Seitenleiste ändern",
|
||||||
"Hide from list": "Aus der Liste ausblenden",
|
"Hide from list": "Aus der Liste ausblenden",
|
||||||
"Show in list": "In der Liste einblenden",
|
"Show in list": "In der Liste einblenden",
|
||||||
|
|||||||
@@ -1188,6 +1188,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "Pantalla completa",
|
"Full screen": "Pantalla completa",
|
||||||
"Resize panes": "Cambiar el tamaño de los paneles",
|
"Resize panes": "Cambiar el tamaño de los paneles",
|
||||||
"Resize message list": "Cambiar el tamaño de la lista de mensajes",
|
"Resize message list": "Cambiar el tamaño de la lista de mensajes",
|
||||||
|
"Resize contact list": "Cambiar el tamaño de la lista de contactos",
|
||||||
"Resize sidebar": "Cambiar el tamaño de la barra lateral",
|
"Resize sidebar": "Cambiar el tamaño de la barra lateral",
|
||||||
"Hide from list": "Ocultar de la lista",
|
"Hide from list": "Ocultar de la lista",
|
||||||
"Show in list": "Mostrar en la lista",
|
"Show in list": "Mostrar en la lista",
|
||||||
|
|||||||
@@ -1193,6 +1193,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "Plein écran",
|
"Full screen": "Plein écran",
|
||||||
"Resize panes": "Redimensionner les volets",
|
"Resize panes": "Redimensionner les volets",
|
||||||
"Resize message list": "Redimensionner la liste des messages",
|
"Resize message list": "Redimensionner la liste des messages",
|
||||||
|
"Resize contact list": "Redimensionner la liste des contacts",
|
||||||
"Resize sidebar": "Redimensionner la barre latérale",
|
"Resize sidebar": "Redimensionner la barre latérale",
|
||||||
"Hide from list": "Masquer de la liste",
|
"Hide from list": "Masquer de la liste",
|
||||||
"Show in list": "Afficher dans la liste",
|
"Show in list": "Afficher dans la liste",
|
||||||
|
|||||||
@@ -1196,6 +1196,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "全画面",
|
"Full screen": "全画面",
|
||||||
"Resize panes": "ペインの大きさを変更",
|
"Resize panes": "ペインの大きさを変更",
|
||||||
"Resize message list": "メール一覧の大きさを変更",
|
"Resize message list": "メール一覧の大きさを変更",
|
||||||
|
"Resize contact list": "連絡先一覧の大きさを変更",
|
||||||
"Resize sidebar": "サイドバーの大きさを変更",
|
"Resize sidebar": "サイドバーの大きさを変更",
|
||||||
"Hide from list": "一覧で非表示にする",
|
"Hide from list": "一覧で非表示にする",
|
||||||
"Show in list": "一覧に表示する",
|
"Show in list": "一覧に表示する",
|
||||||
|
|||||||
@@ -1184,6 +1184,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "Volledig scherm",
|
"Full screen": "Volledig scherm",
|
||||||
"Resize panes": "Vensterdelen verslepen",
|
"Resize panes": "Vensterdelen verslepen",
|
||||||
"Resize message list": "Grootte van de berichtenlijst wijzigen",
|
"Resize message list": "Grootte van de berichtenlijst wijzigen",
|
||||||
|
"Resize contact list": "Grootte van de contactenlijst wijzigen",
|
||||||
"Resize sidebar": "Grootte van de zijbalk wijzigen",
|
"Resize sidebar": "Grootte van de zijbalk wijzigen",
|
||||||
"Hide from list": "Verbergen in de lijst",
|
"Hide from list": "Verbergen in de lijst",
|
||||||
"Show in list": "Tonen in de lijst",
|
"Show in list": "Tonen in de lijst",
|
||||||
|
|||||||
@@ -1191,6 +1191,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "Tela cheia",
|
"Full screen": "Tela cheia",
|
||||||
"Resize panes": "Redimensionar os painéis",
|
"Resize panes": "Redimensionar os painéis",
|
||||||
"Resize message list": "Redimensionar a lista de mensagens",
|
"Resize message list": "Redimensionar a lista de mensagens",
|
||||||
|
"Resize contact list": "Redimensionar a lista de contatos",
|
||||||
"Resize sidebar": "Redimensionar a barra lateral",
|
"Resize sidebar": "Redimensionar a barra lateral",
|
||||||
"Hide from list": "Ocultar da lista",
|
"Hide from list": "Ocultar da lista",
|
||||||
"Show in list": "Mostrar na lista",
|
"Show in list": "Mostrar na lista",
|
||||||
|
|||||||
@@ -1190,6 +1190,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "Во весь экран",
|
"Full screen": "Во весь экран",
|
||||||
"Resize panes": "Изменить размер панелей",
|
"Resize panes": "Изменить размер панелей",
|
||||||
"Resize message list": "Изменить размер списка писем",
|
"Resize message list": "Изменить размер списка писем",
|
||||||
|
"Resize contact list": "Изменить размер списка контактов",
|
||||||
"Resize sidebar": "Изменить размер боковой панели",
|
"Resize sidebar": "Изменить размер боковой панели",
|
||||||
"Hide from list": "Скрыть из списка",
|
"Hide from list": "Скрыть из списка",
|
||||||
"Show in list": "Показать в списке",
|
"Show in list": "Показать в списке",
|
||||||
|
|||||||
@@ -1184,6 +1184,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "На весь екран",
|
"Full screen": "На весь екран",
|
||||||
"Resize panes": "Змінити розмір панелей",
|
"Resize panes": "Змінити розмір панелей",
|
||||||
"Resize message list": "Змінити розмір списку листів",
|
"Resize message list": "Змінити розмір списку листів",
|
||||||
|
"Resize contact list": "Змінити розмір списку контактів",
|
||||||
"Resize sidebar": "Змінити розмір бічної панелі",
|
"Resize sidebar": "Змінити розмір бічної панелі",
|
||||||
"Hide from list": "Сховати зі списку",
|
"Hide from list": "Сховати зі списку",
|
||||||
"Show in list": "Показати в списку",
|
"Show in list": "Показати в списку",
|
||||||
|
|||||||
@@ -1195,6 +1195,7 @@ export const catalog: Catalog = {
|
|||||||
"Full screen": "全屏",
|
"Full screen": "全屏",
|
||||||
"Resize panes": "调整窗格大小",
|
"Resize panes": "调整窗格大小",
|
||||||
"Resize message list": "调整邮件列表大小",
|
"Resize message list": "调整邮件列表大小",
|
||||||
|
"Resize contact list": "调整联系人列表大小",
|
||||||
"Resize sidebar": "调整侧边栏大小",
|
"Resize sidebar": "调整侧边栏大小",
|
||||||
"Hide from list": "从列表中隐藏",
|
"Hide from list": "从列表中隐藏",
|
||||||
"Show in list": "在列表中显示",
|
"Show in list": "在列表中显示",
|
||||||
|
|||||||
@@ -256,6 +256,8 @@ export interface Settings {
|
|||||||
listPaneWidth: number;
|
listPaneWidth: number;
|
||||||
/** Height (px) of the message list when the reading pane is below. */
|
/** Height (px) of the message list when the reading pane is below. */
|
||||||
listPaneHeight: number;
|
listPaneHeight: number;
|
||||||
|
/** Width (px) of the contact list, beside the contact on show. */
|
||||||
|
contactsListWidth: number;
|
||||||
/**
|
/**
|
||||||
* Width (px) of the sidebar, dragged by its edge (#345). Null until someone
|
* Width (px) of the sidebar, dragged by its edge (#345). Null until someone
|
||||||
* drags it, and null again after a double-click resets it -- which leaves the
|
* drags it, and null again after a double-click resets it -- which leaves the
|
||||||
@@ -377,6 +379,7 @@ export const DEFAULT_SETTINGS: Settings = {
|
|||||||
sendAndArchive: false,
|
sendAndArchive: false,
|
||||||
listPaneWidth: 520,
|
listPaneWidth: 520,
|
||||||
listPaneHeight: 340,
|
listPaneHeight: 340,
|
||||||
|
contactsListWidth: 320,
|
||||||
sidebarWidth: null,
|
sidebarWidth: null,
|
||||||
eventCategories: [
|
eventCategories: [
|
||||||
{ name: "Important", color: "#dc2626" },
|
{ name: "Important", color: "#dc2626" },
|
||||||
@@ -408,6 +411,7 @@ export const DEVICE_KEYS: ReadonlySet<keyof Settings> = new Set<keyof Settings>(
|
|||||||
"notificationSound",
|
"notificationSound",
|
||||||
"listPaneWidth",
|
"listPaneWidth",
|
||||||
"listPaneHeight",
|
"listPaneHeight",
|
||||||
|
"contactsListWidth",
|
||||||
"sidebarWidth",
|
"sidebarWidth",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1753,8 +1753,7 @@ select optgroup { background-color: var(--bg-elev); color: var(--fg); }
|
|||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Contacts
|
Contacts
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
.contacts-layout { display: grid; grid-template-columns: 220px minmax(280px, 360px) 1fr; height: 100%; min-height: 0; flex: 1; }
|
.contacts-layout { display: grid; grid-template-columns: var(--list-size, 320px) auto minmax(0, 1fr); height: 100%; min-height: 0; flex: 1; }
|
||||||
.contacts-books { border-right: 1px solid var(--border); padding: 12px 8px; overflow-y: auto; overflow-x: hidden; }
|
|
||||||
.contacts-list { border-right: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
|
.contacts-list { border-right: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
|
||||||
.contacts-list .list-search { padding: 10px 12px; border-bottom: 1px solid var(--border); }
|
.contacts-list .list-search { padding: 10px 12px; border-bottom: 1px solid var(--border); }
|
||||||
.contacts-scroll { flex: 1; overflow-y: auto; }
|
.contacts-scroll { flex: 1; overflow-y: auto; }
|
||||||
@@ -2015,7 +2014,6 @@ select optgroup { background-color: var(--bg-elev); color: var(--fg); }
|
|||||||
@media (max-width: 1100px) {
|
@media (max-width: 1100px) {
|
||||||
:root { --list-w: 44%; }
|
:root { --list-w: 44%; }
|
||||||
.msg-row .msg-from { width: 140px; }
|
.msg-row .msg-from { width: 140px; }
|
||||||
.contacts-layout { grid-template-columns: 200px 300px 1fr; }
|
|
||||||
}
|
}
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.mail-layout:not(.pane-off):not(.pane-bottom) { grid-template-columns: 1fr !important; }
|
.mail-layout:not(.pane-off):not(.pane-bottom) { grid-template-columns: 1fr !important; }
|
||||||
@@ -2036,7 +2034,7 @@ select optgroup { background-color: var(--bg-elev); color: var(--fg); }
|
|||||||
.admin-table .hide-mobile { display: none; }
|
.admin-table .hide-mobile { display: none; }
|
||||||
.admin-sheet { width: 100%; border-left: 0; box-shadow: none; }
|
.admin-sheet { width: 100%; border-left: 0; box-shadow: none; }
|
||||||
.contacts-layout { grid-template-columns: 1fr; }
|
.contacts-layout { grid-template-columns: 1fr; }
|
||||||
.contacts-books { display: none; }
|
.contacts-layout .splitter { display: none; }
|
||||||
.contacts-layout.detail .contacts-list { display: none; }
|
.contacts-layout.detail .contacts-list { display: none; }
|
||||||
.contacts-layout:not(.detail) .contact-detail { display: none; }
|
.contacts-layout:not(.detail) .contact-detail { display: none; }
|
||||||
.cal-layout { grid-template-columns: 1fr; }
|
.cal-layout { grid-template-columns: 1fr; }
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { formatDate, formatDateLong } from "@/lib/datetime";
|
|||||||
import { Avatar, Empty, Spinner, useIsNarrow } from "@/ui/misc";
|
import { Avatar, Empty, Spinner, useIsNarrow } from "@/ui/misc";
|
||||||
import { confirmDialog } from "@/ui/dialog";
|
import { confirmDialog } from "@/ui/dialog";
|
||||||
import { toast } from "@/ui/toast";
|
import { toast } from "@/ui/toast";
|
||||||
|
import { Splitter } from "@/ui/Splitter";
|
||||||
|
import { useSettings } from "@/store/settings";
|
||||||
import { ContactEditor } from "./ContactEditor";
|
import { ContactEditor } from "./ContactEditor";
|
||||||
import { avatarColor } from "@/lib/address";
|
import { avatarColor } from "@/lib/address";
|
||||||
import { plural, t as translate } from "@/lib/i18n";
|
import { plural, t as translate } from "@/lib/i18n";
|
||||||
@@ -18,6 +20,14 @@ export function ContactsView({ id }: { id?: string }) {
|
|||||||
const [, navigate] = useLocation();
|
const [, navigate] = useLocation();
|
||||||
const contacts = useContacts();
|
const contacts = useContacts();
|
||||||
const narrow = useIsNarrow();
|
const narrow = useIsNarrow();
|
||||||
|
const listWidth = useSettings((s) => s.settings.contactsListWidth);
|
||||||
|
const updateSettings = useSettings((s) => s.update);
|
||||||
|
const layoutRef = useRef<HTMLDivElement>(null);
|
||||||
|
/* The width mid-drag, and a ref mirroring it for the end of a key press,
|
||||||
|
which follows the resize in the same tick -- the same pair as the mail
|
||||||
|
list's splitter, for the same reason. */
|
||||||
|
const [liveWidth, setLiveWidth] = useState<number | null>(null);
|
||||||
|
const liveWidthRef = useRef<number | null>(null);
|
||||||
const [q, setQ] = useState("");
|
const [q, setQ] = useState("");
|
||||||
/* The book being shown lives in the store, because the list that chooses it
|
/* The book being shown lives in the store, because the list that chooses it
|
||||||
is the app's own sidebar rather than anything this view owns. */
|
is the app's own sidebar rather than anything this view owns. */
|
||||||
@@ -240,8 +250,23 @@ export function ContactsView({ id }: { id?: string }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const shownListWidth = liveWidth ?? listWidth;
|
||||||
|
const onSplit = (delta: number) => {
|
||||||
|
const total = layoutRef.current?.clientWidth ?? 1200;
|
||||||
|
const max = Math.max(240, total - 360);
|
||||||
|
const next = Math.min(max, Math.max(240, (liveWidthRef.current ?? shownListWidth) + delta));
|
||||||
|
liveWidthRef.current = next;
|
||||||
|
setLiveWidth(next);
|
||||||
|
};
|
||||||
|
const onSplitEnd = () => {
|
||||||
|
const width = liveWidthRef.current;
|
||||||
|
liveWidthRef.current = null;
|
||||||
|
setLiveWidth(null);
|
||||||
|
if (width != null) updateSettings({ contactsListWidth: width });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`contacts-layout ${selected || editing ? "detail" : ""}`}>
|
<div ref={layoutRef} className={`contacts-layout ${selected || editing ? "detail" : ""}`} style={{ "--list-size": `${shownListWidth}px` } as React.CSSProperties}>
|
||||||
|
|
||||||
<section className="contacts-list">
|
<section className="contacts-list">
|
||||||
{pickedIds.length ? (
|
{pickedIds.length ? (
|
||||||
@@ -303,6 +328,7 @@ export function ContactsView({ id }: { id?: string }) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
{!narrow && <Splitter direction="vertical" onResize={onSplit} onEnd={onSplitEnd} onReset={() => updateSettings({ contactsListWidth: 320 })} ariaLabel={translate("Resize contact list")} />}
|
||||||
|
|
||||||
<section className="contact-detail">
|
<section className="contact-detail">
|
||||||
{selected ? (
|
{selected ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user