From 913de061b1a3c9551e13bde61194dea497a26d84 Mon Sep 17 00:00:00 2001 From: manu chatterjee Date: Wed, 17 Apr 2024 11:07:44 -0700 Subject: [PATCH] added styling start --- dev/div-test4.html | 55 ++-- dev/features.md | 4 + dist/yackbox.cjs.js | 121 ++++++- dist/yackbox.cjs.js.map | 2 +- dist/yackbox.cjs.min.js | 2 +- dist/yackbox.cjs.min.js.map | 2 +- dist/yackbox.css | 347 ++++++++++++++------ dist/yackbox.esm.js | 121 ++++++- dist/yackbox.esm.js.map | 2 +- dist/yackbox.esm.js_sri.txt | 2 +- dist/yackbox.esm.min.js | 2 +- dist/yackbox.esm.min.js.map | 2 +- dist/yackbox.esm.min.js_sri.txt | 2 +- dist/yackbox.umd.js | 121 ++++++- dist/yackbox.umd.js.map | 2 +- dist/yackbox.umd.js_sri.txt | 2 +- dist/yackbox.umd.min.js | 2 +- dist/yackbox.umd.min.js.map | 2 +- dist/yackbox.umd.min.js_sri.txt | 2 +- examples/basic-esm/index.html | 108 +++--- examples/basic-umd/index.html | 25 +- examples/ollama-basic-js/simple_ollama.html | 4 - index.html | 67 +--- src/yackbox.js | 162 ++++++++- 24 files changed, 867 insertions(+), 294 deletions(-) diff --git a/dev/div-test4.html b/dev/div-test4.html index 292838c..23b54cd 100644 --- a/dev/div-test4.html +++ b/dev/div-test4.html @@ -9,9 +9,7 @@ - + - - - - Yackbox Example + + + + + + + + + Yackbox Example + -

YackBox Demo

-

- yackbox.js is a simple (pure vanilla) javascript chat control for testing simple chat and AI bot applications. -

- - -
- -
- - +

YackBox Demo

+

+ yackbox.js is a simple (pure vanilla) javascript chat control for testing simple chat and AI bot applications. +

+ + +
+ +
+ + - + + \ No newline at end of file diff --git a/examples/basic-umd/index.html b/examples/basic-umd/index.html index 94f62b3..abbf5cc 100644 --- a/examples/basic-umd/index.html +++ b/examples/basic-umd/index.html @@ -6,10 +6,12 @@ + + +

yackbox demo


- + +
- - - - - - + + - - - + +

yackbox.js

@@ -177,7 +120,7 @@

Installation

<div id="chat-container"></div>
 

Initialize yackbox in your JavaScript code by providing the container element and a callback function for message events:

-
const chat = new yackbox('#chat-container', messageCallback);
+
const chat = new yackbox('#chat-container', messageCallback);
 //Use the provided methods to interact with the chat control:
 
 // Add a message
diff --git a/src/yackbox.js b/src/yackbox.js
index 24ff106..d0acecd 100644
--- a/src/yackbox.js
+++ b/src/yackbox.js
@@ -8,13 +8,22 @@ export default class yackbox {
     constructor(div, completionCallback, streamCallback) {
         this.container = (typeof (div) == "string") ? document.querySelector(div) : (div instanceof HTMLElement) ? div : null;
         if (!this.container) {
-            console.error("Invalid container element for yackbox, creating a new one.");
+            console.error("Invalid container element for yackbox, creating a new element.");
             this.container = document.createElement('div');
         }
+        // title
+        this.title = "Chat";
+        this.titleAlignment = "center";
+
+        // user add
         this.userName = "You";
         this.userAlignment = "left";
+
+        // callback functions
         this.completionCallback = (completionCallback) ? completionCallback : () => { };
         this.streamCallback = (streamCallback) ? streamCallback : () => { };
+
+        // history
         this.messages = [];
         this.echo = true; // echo user input
         this.users = {}
@@ -60,20 +69,62 @@ export default class yackbox {
         this.echo = (echo) ? true : false;
         return this.echo;
     }
+
+    /**
+     * Adjusts the height of the messages area to fit the chat widget.
+     * This method should be called whenever the chat widget is resized.
+     */
+    adjustMessagesAreaHeight() {
+        const chatWidget = this.container;
+        const hiddenElements = [...chatWidget.children].filter(child => child.classList.contains('hidden'));
+        const totalHiddenHeight = hiddenElements.reduce((sum, child) => sum + child.offsetHeight, 0);
+        const containerHeight = chatWidget.offsetHeight;
+        this.messagesContainer.style.height = `calc(100% - ${containerHeight - totalHiddenHeight}px)`;
+    }
+  
+    handleContainerResize() {
+        adjustMessagesAreaHeight();
+        adjustSendButtonWidth();
+    }
+
+    adjustSendButtonWidth() {
+        const submitButtonText = this.submitButton.textContent.trim();
+        const fontSize = parseFloat(getComputedStyle(this.submitButton).fontSize);
+        const minWidth = fontSize * submitButtonText.length + 16; // Adjust the multiplier as needed
+        this.submitButton.style.minWidth = `${minWidth}px`;
+    }
+
+
+
+
     /**
     Shows or hides the input area of the chat.
     @param {boolean} show - True to show the input area, false to hide it.
     */
     showInputArea(show) {
         if (show) {
-            this.inputAreaBox.style.display = "";
-            this.messagesContainer.style.height = "88%;"
+            this.inputAreaBox.style.display = "flex";
+            this.inputAreaBox.classList.remove('hidden');
         }
         else {
             this.inputAreaBox.style.display = "none";
-            this.messagesContainer.style.height = "98%"
+            this.inputAreaBox.classList.add('hidden');
         }
+        this.adjustMessagesAreaHeight();
     }
+
+    showTitleArea(show) {
+        if (show) {
+            this.titleArea.style.display = "flex";
+            this.titleArea.classList.remove('hidden');
+        }
+        else {
+            this.titleArea.style.display = "none";
+            this.titleArea.classList.add('hidden');
+        }
+        this.adjustMessagesAreaHeight();
+    }
+
     /**
     Adds a new message to the chat.
     @param {string} content - The content of the message.
@@ -115,7 +166,7 @@ export default class yackbox {
         if (messageDiv) {
             const userContent = `
${message.user}
`; const messageContent = `
${message.content}
`; - messageDiv.innerHTML = `${ messageContent }${ userContent }`; + messageDiv.innerHTML = `${messageContent}${userContent}`; } return id; } @@ -168,12 +219,100 @@ export default class yackbox { Initializes the UI elements of the chat. */ initUI() { - this.container.innerHTML = `
`; - this.messagesContainer = this.container.querySelector('.yackbox-messages'); + this.container.innerHTML = + `
+
+
+
+ + +
+
`; + + // in-line styles : Note these settings are just for making the basic plumbing work and + // are not part of styling the chatbox. The chatbox is styled using the yackbox.css file + /* + this.baseStyles = { + "yackbox-base": { + "display": "flex", + "flex-direction": "column", + "height": "100%", + "width": "100%", + "min-width": "200px", + "min-height": "200px", + }, + "yackbox-title-area": { + "width": "100%", + "padding-left": "8px", + "padding-right": "8px", + }, + + "yackbox-messages-area": { + "flex-grow": "1", + "padding": "8px", + "overflow-y": "auto", + "width": "100%", + }, + + "yackbox-message": { + "padding": "2px" + }, + + "yackbox-input-area": { + "display": "flex", + "align-items": "center", + "padding": "8px", + "min-height": "56px", + "height": "4em", + "width": "100%" + }, + "yackbox-input-textbox": { + "flex-grow": "1", + "min-height": "40px", + "resize": "none", + "padding": "8px" + }, + "yackbox-input-send-btn": { + "margin-left": "8px", + "padding": "8px 12px", + "height": "100%", + "cursor": "pointer", + "white-space": "nowrap" + } + } + */ + let setStyles = (el, styles) => { + for (let s in styles) { + el.style[s] = styles[s]; + } + } + this.yackboxContainer = this.container.querySelector('.yackbox-base'); + this.titleArea = this.container.querySelector('.yackbox-title-area'); + this.titleArea.innerHTML = "

" +this.title+"

"; + + //setStyles (this.titleArea, this.baseStyles["yackbox-title-area"]); + + this.messagesContainer = this.container.querySelector('.yackbox-messages-area'); + //setStyles(this.messagesContainer, this.baseStyles["yackbox-messages-area"]); + this.messagesContainer.scrollIntoView(false); this.inputAreaBox = this.container.querySelector('.yackbox-input-area'); + //setStyles(this.inputAreaBox, this.baseStyles["yackbox-input-area"]); + this.inputTextArea = this.container.querySelector('.yackbox-input-textbox'); - this.submitButton = this.container.querySelector('.yackbox-submit'); + //setStyles(this.inputTextArea, this.baseStyles["yackbox-input-textbox"]); + + this.submitButton = this.container.querySelector('.yackbox-input-send-btn'); + //setStyles(this.submitButton, this.baseStyles["yackbox-input-send-btn"]); + + // now we add the base styles for the chat container and sub elements + // set base styles for the chat container. NOTE this is done in js so that we can have + // multiple instances of the chatbox on the same page with different styles + // see yaclbox.css for the default styles + + + + //=================================================================================== // Add event listener to the chat input textarea const inputTextarea = this.inputTextArea; // memoize callback fn @@ -203,6 +342,11 @@ export default class yackbox { } }); this.submitButton.addEventListener('click', () => { handleUserSubmit() }); + + this.container.addEventListener('resize', ()=> {handleContainerResize()}); + this.adjustMessagesAreaHeight(); + this.adjustSendButtonWidth(); + this.showTitleArea(false); } /** Returns a portion of the message history. @@ -238,7 +382,7 @@ export default class yackbox { getMessageStats() { let stats = { "numMessages": this.messages.length, - // "numUsers": this.users.keys().length, + // "numUsers": this.users.keys().length, "firstMsgTimestamp": this.messages.length > 0 ? this.messages[0].timestamp : "", "lastMsgTimestamp": this.messages.length > 0 ? this.messages[this.messages.length - 1].timestamp : "", }