{#snippet unavailable()} Unavailable {/snippet} {#snippet clockTime(value: string)} {/snippet} {#snippet chatContext(context: ChatContext)}
Match
{#if context.matchElapsedMs === null}{@render unavailable()}{:else}{formatDuration(context.matchElapsedMs)}{/if}
Round
{#if context.round === null}{@render unavailable()}{:else}{context.round}{/if}
{/snippet} {#snippet matchBoundary(entry: ChatBoundaryEntry)}
{entry.event === 'start' ? 'Match started' : entry.event === 'end' ? 'Match ended' : 'New match'} {#if entry.context.realTime}{@render clockTime(entry.context.realTime)}{/if} {#if entry.context.matchElapsedMs !== null}Match {formatDuration(entry.context.matchElapsedMs)}{/if} {#if entry.context.round !== null}Round {entry.context.round}{/if}
{/snippet}

Chat

Updates every 5s
{#if !follow}{/if}
{#if error}{/if} {#if !loaded && !error}

Loading chat…

{:else if loaded && !hasMessages}

{missing ? 'Waiting for the game log. Player messages will appear here.' : 'No player messages in the recent game log.'}

{:else if hasMessages}
    {#each timeline as item} {#if item.type === 'boundaries'}
  1. {#if item.entries.length > 1} {#key JSON.stringify(item.entries)}
    { if (event.currentTarget.open) follow = false; }}> {item.entries.length - 1} earlier match {item.entries.length === 2 ? 'event' : 'events'}
      {#each item.entries.slice(0, -1) as entry}
    1. {@render matchBoundary(entry)}
    2. {/each}
    {/key} {/if} {@render matchBoundary(item.entries[item.entries.length - 1])}
  2. {:else}
  3. {#if item.entry.context.realTime}{@render clockTime(item.entry.context.realTime)}{:else}Time: {@render unavailable()}{/if}
    {item.entry.message.player}{@render chatContext(item.entry.context)}

    {item.entry.message.message}

  4. {/if} {/each}
{/if}