AkurAI Build
Menu

Public repository / 275d4fa11a39ecc30e2caf604d5a0d499910e8db

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>