-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathChat.svelte
160 lines (142 loc) · 3.19 KB
/
Chat.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<script lang="ts">
import { useQuery, useConvexClient } from '$lib/client.svelte.js';
import type { Doc } from '../convex/_generated/dataModel.js';
import { api } from '../convex/_generated/api.js';
const { initialMessages = [] as Doc<'messages'>[] } = $props();
let useStale = $state(true);
let muteWordsString = $state('');
let muteWords = $derived(
muteWordsString
.split(',')
.map((x) => x.trim())
.filter((x) => x)
);
let toSend = $state('');
let author = $state('me');
const messages = useQuery(
api.messages.list,
() => ({ muteWords: muteWords }),
() => ({ initialData: initialMessages, keepPreviousData: useStale })
);
const client = useConvexClient();
function onSubmit(e: SubmitEvent) {
const data = Object.fromEntries(new FormData(e.target as HTMLFormElement).entries());
toSend = '';
client.mutation(api.messages.send, {
author: data.author as string,
body: data.body as string
});
}
function formatDate(ts: number) {
return new Date(ts).toLocaleString();
}
</script>
<div class="chat">
<label for="muteWords"> Hide messages containing these phrases: </label>
<input
type="text"
id="muteWords"
name="muteWords"
placeholder="vim, emacs"
bind:value={muteWordsString}
/>
<div>
<label for="useStale"> Display old results while loading: </label>
<input type="checkbox" id="useStale" name="useStale" bind:checked={useStale} />
</div>
<form onsubmit={onSubmit}>
<input type="text" id="author" name="author" bind:value={author} />
<input type="text" id="body" name="body" bind:value={toSend} />
<button type="submit" disabled={!toSend}>Send</button>
</form>
{#if messages.isLoading}
Loading...
{:else if messages.error}
failed to load
{:else}
<ul class="messages" class:stale={messages.isStale}>
<ul>
{#each messages.data as message}
<li>
<span>{message.author}</span>
<span>{message.body}</span>
<span>{formatDate(message._creationTime)}</span>
</li>
{/each}
</ul>
</ul>
{/if}
</div>
<style>
.chat {
display: flex;
align-items: center;
flex-direction: column;
border-top: 1px solid rgba(0, 0, 0, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
margin: 1rem 0;
width: 100%;
}
.stale {
color: rgba(0, 0, 0, 0.8);
}
ul {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
padding: 0;
}
li {
display: flex;
width: 100%;
gap: 1rem;
justify-content: space-between;
flex-wrap: wrap;
}
li span:nth-child(1) {
flex: 0 0 100px;
overflow-wrap: break-word;
min-width: 0;
font-weight: bold;
}
li span:nth-child(2) {
flex: 1 0 160px;
overflow-wrap: break-word;
min-width: 0;
}
li span:nth-child(3) {
flex: 0 0;
white-space: nowrap;
}
button {
padding: 0.3rem;
margin: 0.2rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border: 0;
background-color: transparent;
touch-action: manipulation;
}
button:hover {
background-color: var(--color-bg-1);
}
button:active {
opacity: 0.6;
}
form {
display: flex;
align-items: center;
max-width: 500px;
}
input#muteWords {
width: 40%;
max-width: 400px;
min-width: 200px;
}
form input {
margin: 4px;
}
</style>