feat: show the mail skeleton while a mailto link opens

This commit is contained in:
Linus Rath
2026-11-01 19:40:21 +01:00
parent cdf661d320
commit 1e8f64f36e
3 changed files with 43 additions and 7 deletions
+9 -1
View File
@@ -3,6 +3,14 @@ import { MailtoProtocolClient } from "@/components/protocol/mailto-protocol-clie
export default async function MailtoProtocolPage() {
const t = await getTranslations("protocol_handlers");
const tSidebar = await getTranslations("sidebar");
const labels = {
mail: tSidebar("mail"),
calendar: tSidebar("calendar"),
contacts: tSidebar("contacts"),
files: tSidebar("files"),
settings: tSidebar("settings"),
};
return <MailtoProtocolClient openingText={t("opening_mailto")} />;
return <MailtoProtocolClient openingText={t("opening_mailto")} labels={labels} />;
}
@@ -0,0 +1,26 @@
import { render } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';
vi.mock('@/lib/protocol-handlers/session', () => ({
// Still asking an open tab whether it takes the message.
requestOpenMailtoInExistingClient: vi.fn(() => new Promise(() => {})),
savePendingMailto: vi.fn(),
}));
const { MailtoProtocolClient } = await import('../mailto-protocol-client');
afterEach(() => {
window.history.replaceState(null, '', '/');
});
describe('mailto handler page', () => {
// It hands over to the mail page, where the composer opens: it draws that
// page's skeleton instead of a line of text on a blank page.
it('draws the mail skeleton with the opening text as its status', () => {
window.history.replaceState(null, '', '/protocol/mailto?url=mailto%3Aa%40example.com');
const { container } = render(<MailtoProtocolClient openingText="Opening email…" />);
const region = container.querySelector('[data-boot-skeleton="mail"]');
expect(region).not.toBeNull();
expect(region!.querySelector('[role="status"]')?.textContent).toBe('Opening email…');
});
});
@@ -1,6 +1,8 @@
"use client";
import { useEffect } from "react";
import { MailSkeleton } from "@/components/boot-skeleton/mail-skeleton";
import type { RailLabels } from "@/components/boot-skeleton/shell";
import { parseMailto } from "@/lib/protocol-handlers/mailto";
import { requestOpenMailtoInExistingClient, savePendingMailto } from "@/lib/protocol-handlers/session";
import { useSettingsStore } from "@/stores/settings-store";
@@ -51,9 +53,11 @@ async function focusExistingClient() {
interface MailtoProtocolClientProps {
openingText: string;
/** The phone bottom bar's labels for the skeleton. */
labels?: RailLabels;
}
export function MailtoProtocolClient({ openingText }: MailtoProtocolClientProps) {
export function MailtoProtocolClient({ openingText, labels }: MailtoProtocolClientProps) {
useEffect(() => {
let cancelled = false;
@@ -99,9 +103,7 @@ export function MailtoProtocolClient({ openingText }: MailtoProtocolClientProps)
};
}, []);
return (
<main className="flex min-h-screen items-center justify-center">
<p>{openingText}</p>
</main>
);
// The mail page this hands over to, where the composer opens: its skeleton,
// with the opening text as the status message.
return <MailSkeleton label={openingText} labels={labels} />;
}