mailspy/ui/src/routes/+page.svelte

192 lines
3.4 KiB
Svelte

<script>
import axios from "axios";
import { useQuery } from "@sveltestack/svelte-query";
import Select from "svelte-select";
const listMessages = async () => {
const { data } = await axios.get(`/messages`);
return data;
};
const messageQuery = useQuery(["messages"], () => listMessages());
let selectedIndex;
let selectedPart;
const itemSelect = (idx) => () => {
selectedIndex = idx;
selectedPart = {
value: 0,
label: $messageQuery.data[selectedIndex].body[0].content_type,
};
};
const partSelect = ({ detail }) => {
selectedPart = detail;
};
$: isHtml = selectedPart?.label.toUpperCase().includes("HTML");
let partItems = [];
$: {
if (selectedIndex !== undefined) {
partItems = $messageQuery.data[selectedIndex].body.map((p, i) => ({
value: i,
label: p.content_type,
}));
}
}
</script>
<div class="header">mailspy</div>
<div class="message-list">
{#if !$messageQuery.isLoading}
{#each $messageQuery.data as msg, idx}
<div
class="mail-list-item"
on:click={itemSelect(idx)}
class:selected={selectedIndex === idx}
>
<div class="to">
{msg.to}
</div>
<div class="subject">
{msg.subject}
</div>
<div class="date">
{msg.date}
</div>
</div>
{/each}
{:else}
<div class="loader-container">
<div class="loader">
<div />
<div />
<div />
</div>
</div>
{/if}
</div>
{#if selectedIndex !== undefined}
<div class="part-select">
<Select
placeholder="Mail part"
isCreatable={false}
isClearable={false}
isSearchable={false}
items={partItems}
value={selectedPart}
on:select={partSelect}
/>
</div>
{/if}
<div class="body">
{#if selectedIndex !== undefined}
{#if isHtml}
{@html $messageQuery.data[selectedIndex].body[selectedPart.value]
.data}
{:else}
<pre>{$messageQuery.data[selectedIndex].body[selectedPart.value]
.data}</pre>
{/if}
{/if}
</div>
<style>
.message-list {
border-bottom: 1px solid #888;
background: #f5f5f5;
max-height: 200px;
overflow-y: scroll;
}
.part-select {
border-bottom: 1px solid #888;
}
.loader-container {
padding: 15px 25px;
}
.loader {
position: relative;
margin: auto auto;
width: 80px;
height: 80px;
}
.loader div {
display: inline-block;
position: absolute;
left: 8px;
width: 16px;
background: #888;
animation: loader 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite;
}
.loader div:nth-child(1) {
left: 8px;
animation-delay: -0.24s;
}
.loader div:nth-child(2) {
left: 32px;
animation-delay: -0.12s;
}
.loader div:nth-child(3) {
left: 56px;
animation-delay: 0;
}
@keyframes loader {
0% {
top: 8px;
height: 64px;
}
50%,
100% {
top: 24px;
height: 32px;
}
}
.mail-list-item {
transition: all 0.2s;
font-family: "Raleway", sans-serif;
font-size: 14px;
background: #fcfcfc;
border-bottom: 1px solid #ccc;
display: flex;
cursor: pointer;
font-weight: 500;
}
.mail-list-item:hover {
transition: all 0.2s;
background: #ddd;
}
.mail-list-item.selected {
transition: all 0.5s;
background: #ccddff;
}
.mail-list-item > * {
transition: all 0.2s;
padding: 8px 16px;
flex: 1;
}
.subject {
flex: 2;
}
.date {
text-align: right;
}
.body {
padding: 25px;
font-family: sans-serif;
}
.header {
font-family: "Raleway", sans-serif;
background: #222;
color: white;
font-weight: 900;
font-size: 24px;
padding: 14px 25px;
font-family: raleway;
}
pre {
padding: 0;
margin: 0;
}
</style>