Added dynamic component rendering attached to message with the

@app: command
This commit is contained in:
Samuel Andert 2023-07-22 16:08:00 +02:00
parent 379a163fce
commit 0053515286
4 changed files with 66 additions and 22 deletions

View File

@ -11,7 +11,7 @@
} }
</script> </script>
<div class="grid h-full w-full" style="display: grid; {componentsData.layout || ''}"> <div class="grid w-full h-full" style="display: grid; {componentsData.layout || ''}">
{#each componentsData.children as component (component.id)} {#each componentsData.children as component (component.id)}
{#await getComponent(component.componentName) then Component} {#await getComponent(component.componentName) then Component}
{#if Component} {#if Component}

View File

@ -1,47 +1,76 @@
<script> <script>
import { createMessage, clearMessages } from '$lib/services/messages'; import { createMessage, clearMessages } from '$lib/services/messages';
createMessage({
text: 'Component loaded',
sender: '$lib/components/MessageInput.svelte',
type: 'SYSTEM'
});
let newMessageText = ''; let newMessageText = '';
// Default message composite structure
const messageComposite = {
layout: '',
children: [
{
componentName: 'HelloEarth',
props: {}
}
]
};
function handleSend() { function handleSend() {
if (newMessageText.trim() !== '') { if (newMessageText.trim() !== '') {
// Create a new message with the default sender and type using an object // Default message without composite
createMessage({ text: newMessageText, sender: 'user', type: 'chat' }); const message = {
text: newMessageText,
sender: 'user',
type: 'chat'
};
// Check if text contains @app:command and add the composite accordingly
const appCommandPattern = /@app:(\w+)/;
const match = newMessageText.match(appCommandPattern);
if (match && match[1]) {
message.composite = {
layout: '',
children: [
{
componentName: match[1], // Matched component name
props: {}
}
]
};
}
createMessage(message);
// Store the last message that was sent
lastMessageSent = newMessageText;
newMessageText = ''; newMessageText = '';
} }
} }
function handleClear() { function handleClear() {
clearMessages(); // Call the clearMessages function to clear all messages. clearMessages();
} }
function handleKeyDown(event) { function handleKeyDown(event) {
if (event.key === 'Enter') { if (event.key === 'Enter') {
handleSend(); handleSend();
event.preventDefault(); // Prevents a newline being added to the input field event.preventDefault();
} }
} }
</script> </script>
<footer class="bg-white p-4 flex justify-end"> <footer class="flex justify-end p-4 bg-white">
<input <input
type="text" type="text"
class="flex-grow border rounded px-3 py-2 mr-2" class="flex-grow px-3 py-2 mr-2 border rounded"
placeholder="Type your message..." placeholder="Type your message..."
bind:value={newMessageText} bind:value={newMessageText}
on:keydown={handleKeyDown} on:keydown={handleKeyDown}
/> />
<button class="bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded" on:click={handleSend}> <button class="px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600" on:click={handleSend}>
Send Message Send Message
</button> </button>
<button <button
class="bg-red-500 hover:bg-red-600 text-white py-2 px-4 rounded ml-2" class="px-4 py-2 ml-2 text-white bg-red-500 rounded hover:bg-red-600"
on:click={handleClear} on:click={handleClear}
> >
Clear Clear

View File

@ -1,6 +1,7 @@
<script> <script>
import { messages, createMessage } from '$lib/services/messages'; import { messages, createMessage } from '$lib/services/messages';
import { onMount, afterUpdate } from 'svelte'; import { onMount } from 'svelte';
import Composite from './Composite.svelte';
let latestMessages = []; let latestMessages = [];
@ -16,20 +17,32 @@
} }
}; };
// Watch for changes in latestMessages
$: {
// Use setTimeout to give the DOM some time to update
setTimeout(scrollToBottom, 50);
}
onMount(scrollToBottom); onMount(scrollToBottom);
afterUpdate(scrollToBottom);
</script> </script>
<main bind:this={messagesContainer} class="p-4 overflow-y-auto h-full w-full"> <main bind:this={messagesContainer} class="w-full h-full p-4 overflow-y-auto">
{#each latestMessages as message} {#each latestMessages as message}
<div class="bg-white p-3 rounded-lg shadow-lg mb-2 border-b border-gray-300"> <div class="p-3 mb-2 bg-white border-b border-gray-300 rounded-lg shadow-lg">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<p class="text-sm text-gray-600"> <p class="text-sm text-gray-600">
{message.type} | {message.sender} {message.type} | {message.sender}
</p> </p>
<p class="text-xs text-gray-600">{message.timestamp}</p> <p class="text-xs text-gray-600">{message.timestamp}</p>
</div> </div>
<p class="text-base text-gray-800 mt-2">{message.text}</p> <p class="mt-2 text-base text-gray-800">{message.text}</p>
<!-- Render Composite Component -->
{#if message.composite}
<div class="mt-2 overflow-y-auto max-h-500">
<Composite componentsData={message.composite} />
</div>
{/if}
</div> </div>
{/each} {/each}
</main> </main>

View File

@ -28,8 +28,10 @@ export interface Message {
timestamp: string; timestamp: string;
sender: string; sender: string;
type: string; type: string;
composite?: object | null; // New field
} }
// Load messages from localStorage or set an empty array if not available // Load messages from localStorage or set an empty array if not available
const initialMessages = getFromLocalStorage('chat-messages', []); const initialMessages = getFromLocalStorage('chat-messages', []);
@ -48,11 +50,11 @@ export function createMessage(messageData) {
text: messageData.text, text: messageData.text,
timestamp: currentDate, timestamp: currentDate,
sender: messageData.sender, sender: messageData.sender,
type: messageData.type type: messageData.type,
composite: messageData.composite || null // New field
}; };
messages.update(oldMessages => [...oldMessages, newMessageObj]); messages.update(oldMessages => [...oldMessages, newMessageObj]);
} }
export function clearMessages() { export function clearMessages() {
messages.set([]); messages.set([]);
} }