192 lines
3.4 KiB
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>
|