chat room is scrollable
This commit is contained in:
parent
66c0fe57df
commit
87a8fdc1d4
12
src/app.scss
12
src/app.scss
|
@ -94,4 +94,16 @@ div.copy-prompt {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 720px;
|
||||||
|
}
|
||||||
|
.message-list{
|
||||||
|
// max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
|
@ -102,7 +102,7 @@
|
||||||
// Scroll to the bottom of the page after any updates to the messages array
|
// Scroll to the bottom of the page after any updates to the messages array
|
||||||
window.scrollTo(0, document.body.scrollHeight);
|
window.scrollTo(0, document.body.scrollHeight);
|
||||||
input.focus();
|
input.focus();
|
||||||
copyFunction()
|
copyFunction();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Marked options
|
// Marked options
|
||||||
|
@ -286,7 +286,13 @@
|
||||||
const copyPrompt = document.createElement("div");
|
const copyPrompt = document.createElement("div");
|
||||||
copyPrompt.className = "copy-prompt";
|
copyPrompt.className = "copy-prompt";
|
||||||
const copyPromptText = document.createElement("button");
|
const copyPromptText = document.createElement("button");
|
||||||
copyPromptText.classList.add("button", "is-light", "is-outlined", "is-small", "is-responsive");
|
copyPromptText.classList.add(
|
||||||
|
"button",
|
||||||
|
"is-light",
|
||||||
|
"is-outlined",
|
||||||
|
"is-small",
|
||||||
|
"is-responsive"
|
||||||
|
);
|
||||||
copyPromptText.innerHTML = showCopyMessage;
|
copyPromptText.innerHTML = showCopyMessage;
|
||||||
copyPrompt.appendChild(copyPromptText);
|
copyPrompt.appendChild(copyPromptText);
|
||||||
block.appendChild(copyPrompt);
|
block.appendChild(copyPrompt);
|
||||||
|
@ -301,7 +307,7 @@
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav class="level chat-header">
|
<nav class="level chat-header">
|
||||||
|
@ -357,118 +363,125 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
<div class="is-fullhd message-container">
|
||||||
{#each chat.messages as message}
|
<div class="message-list">
|
||||||
{#if message.role === "user"}
|
{#each chat.messages as message}
|
||||||
<article
|
{#if message.role === "user"}
|
||||||
class="message is-info user-message"
|
<article
|
||||||
class:has-text-right={message.content
|
class="message is-info user-message"
|
||||||
.split("\n")
|
class:has-text-right={message.content
|
||||||
.filter((line) => line.trim()).length === 1}
|
.split("\n")
|
||||||
>
|
.filter((line) => line.trim()).length === 1}
|
||||||
<div class="message-body content">
|
|
||||||
<a
|
|
||||||
href={"#"}
|
|
||||||
class="greyscale is-pulled-right ml-2 is-hidden editbutton"
|
|
||||||
on:click={() => {
|
|
||||||
input.value = message.content;
|
|
||||||
input.focus();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
✏️
|
<div class="message-body content">
|
||||||
</a>
|
<a
|
||||||
<SvelteMarkdown
|
href={"#"}
|
||||||
source={message.content}
|
class="greyscale is-pulled-right ml-2 is-hidden editbutton"
|
||||||
options={markedownOptions}
|
on:click={() => {
|
||||||
renderers={{
|
input.value = message.content;
|
||||||
code: Code,
|
input.focus();
|
||||||
}}
|
}}
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
{:else if message.role === "system" || message.role === "error"}
|
|
||||||
<article class="message is-danger">
|
|
||||||
<div class="message-body content">
|
|
||||||
<SvelteMarkdown
|
|
||||||
source={message.content}
|
|
||||||
options={markedownOptions}
|
|
||||||
renderers={{
|
|
||||||
code: Code,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
{:else}
|
|
||||||
<article class="message is-success">
|
|
||||||
<div class="message-body content">
|
|
||||||
<SvelteMarkdown
|
|
||||||
source={message.content}
|
|
||||||
options={markedownOptions}
|
|
||||||
renderers={{
|
|
||||||
code: Code,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{#if message.usage}
|
|
||||||
<p class="is-size-7">
|
|
||||||
This message was generated using <span class="has-text-weight-bold"
|
|
||||||
>{message.usage.total_tokens}</span
|
|
||||||
>
|
>
|
||||||
tokens ~=
|
✏️
|
||||||
<span class="has-text-weight-bold"
|
</a>
|
||||||
>${(message.usage.total_tokens * token_price).toFixed(6)}</span
|
<SvelteMarkdown
|
||||||
>
|
source={message.content}
|
||||||
</p>
|
options={markedownOptions}
|
||||||
{/if}
|
renderers={{
|
||||||
</div>
|
code: Code,
|
||||||
</article>
|
}}
|
||||||
{/if}
|
/>
|
||||||
{/each}
|
</div>
|
||||||
|
</article>
|
||||||
|
{:else if message.role === "system" || message.role === "error"}
|
||||||
|
<article class="message is-danger">
|
||||||
|
<div class="message-body content">
|
||||||
|
<SvelteMarkdown
|
||||||
|
source={message.content}
|
||||||
|
options={markedownOptions}
|
||||||
|
renderers={{
|
||||||
|
code: Code,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{:else}
|
||||||
|
<article class="message is-success">
|
||||||
|
<div class="message-body content">
|
||||||
|
<SvelteMarkdown
|
||||||
|
source={message.content}
|
||||||
|
options={markedownOptions}
|
||||||
|
renderers={{
|
||||||
|
code: Code,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{#if message.usage}
|
||||||
|
<p class="is-size-7">
|
||||||
|
This message was generated using <span
|
||||||
|
class="has-text-weight-bold"
|
||||||
|
>{message.usage.total_tokens}</span
|
||||||
|
>
|
||||||
|
tokens ~=
|
||||||
|
<span class="has-text-weight-bold"
|
||||||
|
>${(message.usage.total_tokens * token_price).toFixed(
|
||||||
|
6
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="message-send">
|
||||||
|
{#if updating}
|
||||||
|
<progress class="progress is-small is-dark" max="100" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if updating}
|
<form
|
||||||
<progress class="progress is-small is-dark" max="100" />
|
class="field has-addons has-addons-right"
|
||||||
{/if}
|
on:submit|preventDefault={() => submitForm()}
|
||||||
|
|
||||||
<form
|
|
||||||
class="field has-addons has-addons-right"
|
|
||||||
on:submit|preventDefault={() => submitForm()}
|
|
||||||
>
|
|
||||||
<p class="control is-expanded">
|
|
||||||
<textarea
|
|
||||||
class="input is-info is-focused chat-input"
|
|
||||||
placeholder="Type your message here..."
|
|
||||||
rows="1"
|
|
||||||
on:keydown={(e) => {
|
|
||||||
// Only send if Enter is pressed, not Shift+Enter
|
|
||||||
if (e.key === "Enter" && !e.shiftKey) {
|
|
||||||
submitForm();
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
on:input={(e) => {
|
|
||||||
// Resize the textarea to fit the content - auto is important to reset the height after deleting content
|
|
||||||
input.style.height = "auto";
|
|
||||||
input.style.height = input.scrollHeight + "px";
|
|
||||||
}}
|
|
||||||
bind:this={input}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p class="control" class:is-hidden={!recognition}>
|
|
||||||
<button
|
|
||||||
class="button"
|
|
||||||
class:is-pulse={recording}
|
|
||||||
on:click|preventDefault={recordToggle}
|
|
||||||
><span class="greyscale">🎤</span></button
|
|
||||||
>
|
>
|
||||||
</p>
|
<p class="control is-expanded">
|
||||||
<p class="control">
|
<textarea
|
||||||
<button class="button" on:click|preventDefault={showSettings}
|
class="input is-info is-focused chat-input"
|
||||||
><span class="greyscale">⚙️</span></button
|
placeholder="Type your message here..."
|
||||||
>
|
rows="1"
|
||||||
</p>
|
on:keydown={(e) => {
|
||||||
<p class="control">
|
// Only send if Enter is pressed, not Shift+Enter
|
||||||
<button class="button is-info" type="submit">Send</button>
|
if (e.key === "Enter" && !e.shiftKey) {
|
||||||
</p>
|
submitForm();
|
||||||
</form>
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
on:input={(e) => {
|
||||||
|
// Resize the textarea to fit the content - auto is important to reset the height after deleting content
|
||||||
|
input.style.height = "auto";
|
||||||
|
input.style.height = input.scrollHeight + "px";
|
||||||
|
}}
|
||||||
|
bind:this={input}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p class="control" class:is-hidden={!recognition}>
|
||||||
|
<button
|
||||||
|
class="button"
|
||||||
|
class:is-pulse={recording}
|
||||||
|
on:click|preventDefault={recordToggle}
|
||||||
|
><span class="greyscale">🎤</span></button
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p class="control">
|
||||||
|
<button class="button" on:click|preventDefault={showSettings}
|
||||||
|
><span class="greyscale">⚙️</span></button
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p class="control">
|
||||||
|
<button class="button is-info" type="submit">Send</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
on:keydown={(event) => {
|
on:keydown={(event) => {
|
||||||
|
|
Loading…
Reference in New Issue