Menu
Public repository / ecdd82c68dc11022c41dbf1ff22cac68e002a3e1
AkurAI-Mail / src/routes/fixture-preview/+page.svelte
Latest change 22202d1bde69be4ace8a299dffd91f8ff24378df - Recover deployed webmail frontend (frontend parity with EC2 a6afffc) by Ólafur Búi Ólafsson
<script lang="ts">
// Visual fixture for the message list: 5,000 synthetic messages to exercise
// virtual scrolling, threading and scroll preservation across refreshes.
import MessageList from "$lib/webmail/MessageList.svelte";
const now = Date.now();
const minutesAgo = (minutes: number) => new Date(now - minutes * 60000).toISOString();
const total = 5000;
const fixture: any[] = [];
for (let i = 0; i < total; i++) {
const roadmap = i === 2 || i === 3 || i === 4;
fixture.push({
id: `m${i}`,
messageId: `<m${i}@fixture>`,
subject: i === 2 ? "Q3 roadmap review" : i === 3 || i === 4 ? "Re: Q3 roadmap review" : `Fixture subject ${i}`,
inReplyTo: i === 3 ? "<m2@fixture>" : i === 4 ? "<m3@fixture>" : undefined,
references: i === 4 ? ["<m2@fixture>", "<m3@fixture>"] : undefined,
from: roadmap ? "alice@example.com" : `sender${i}@example.com`,
to: "olibuijr@olibuijr.com",
date: minutesAgo(i * 7),
timestamp: now / 1000 - i * 420,
unread: i % 3 === 0,
flagged: i === 5,
preview: `This is fixture preview text for message ${i} to demonstrate row typography and truncation behaviour in the list.`,
attachments: i === 6 ? ["file.pdf"] : [],
spamScore: 0
});
}
// Same subject, unrelated participants: must not be threaded together.
fixture.push({ id: "u1", subject: "Update", from: "carol@corp.com", to: "olibuijr@olibuijr.com", date: minutesAgo(500), timestamp: now / 1000 - 500 * 60, unread: true, preview: "Unrelated update from Carol." });
fixture.push({ id: "u2", subject: "Update", from: "dave@other.com", to: "olibuijr@olibuijr.com", date: minutesAgo(600), timestamp: now / 1000 - 600 * 60, unread: false, preview: "Unrelated update from Dave, different sender/recipient pair." });
const folders = [
{ name: "Inbox", unread: 812, total },
{ name: "Sent", total: 240 },
{ name: "Archive", total: 1900 },
{ name: "Trash", total: 12 }
];
let messages = $state(fixture);
/** Replaces the array like a mailbox refresh does; scroll position must survive. */
function simulateRefresh() {
messages = fixture.slice();
}
function shortDate(value: string) {
const date = new Date(value);
return Number.isNaN(date.valueOf()) ? value || "" : date.toLocaleDateString([], { month: "short", day: "numeric" });
}
</script>
<svelte:head><title>Fixture · Message list</title></svelte:head>
<div class="mail-canvas" style="height:100vh">
<button id="refresh-btn" style="position:fixed;top:8px;right:8px;z-index:999" onclick={simulateRefresh}>Simulate refresh</button>
<MessageList
folderList={folders}
folder="Inbox"
unreadCount={812}
folderIcon={() => () => null}
onFolder={() => {}}
{messages}
totalMessages={total}
query=""
senderLabel={(message: any) => message.from}
{shortDate}
selected={null}
onRead={() => {}}
page={0}
pageCount={125}
nextCursor="cursor-2"
busy={false}
onPrevious={() => {}}
onNext={() => {}}
signalForMessage={() => null}
onThreadAction={() => {}}
/>
</div>
<style>
:global(html),
:global(body) {
height: 100%;
margin: 0;
}
:global(:root) {
--surface: #fff;
--surface-soft: #f6f9f7;
--surface-selected: #e5f2ec;
--ink: #17231f;
--muted: #60716b;
--line: #d7e2dd;
--line-soft: #e9efec;
--accent: #126b5a;
--accent-soft: #dcefe7;
--danger: #a33b2e;
}
.mail-canvas {
grid-template-columns: 205px minmax(310px, 400px) 1fr;
display: grid;
}
</style>