Skip to content

Commit

Permalink
Merge pull request #118 from MyLife-Services/117-alpha-ux-enhancements
Browse files Browse the repository at this point in the history
117 alpha ux enhancements
  • Loading branch information
Mookse authored Jan 4, 2024
2 parents dbce4b3 + 299764e commit 9ca3620
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 81 deletions.
9 changes: 6 additions & 3 deletions inc/js/factory-class-extenders/class-extenders.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function extendClass_avatar(_originClass,_references) {
if(!ctx?.state?.chatMessage)
throw new Error('No message provided in context')
if(!this.thread)
this.thread = ctx.state.MemberSession.thread
this.thread = ctx.state.thread
// add metadata, optional
// assign uploaded files (optional) and push `retrieval` to tools
// create message
Expand Down Expand Up @@ -722,9 +722,12 @@ function mPrepareMessage(_msg){
const _messageCategory = mFormatCategory(_match?.[1]??'')
// Remove from _msg
_msg = _msg.replace(_categoryRegex, '')
let _filteredLines = _msg.split('\n')
const _content = _msg.split('\n')
.filter(_line => _line.trim() !== '') // Remove empty lines
const _content = _filteredLines.join('\n')
.map(_msg=>{
return new Marked().parse(_msg)
})
.join('\n')
return {
category: _messageCategory,
content: _content,
Expand Down
1 change: 1 addition & 0 deletions inc/js/functions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ async function challenge(ctx){
}
async function chat(ctx){
ctx.state.chatMessage = ctx.request.body
ctx.state.thread = ctx.state.MemberSession.thread
const _message = ctx.request?.body?.message??false /* body has all the nodes sent by fe */
if(!_message) ctx.throw(400, `invalid message: missing \`message\``) // currently only accepts single contributions via post with :cid
if(!_message?.length) ctx.throw(400, `empty message content`)
Expand Down
32 changes: 17 additions & 15 deletions views/assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ h1 {
}
/* MyLife chatbot */
/* chat bubbles */
.agent-bubble {
background-color: #007BFF;
color: white;
margin-left: 0;
}
.chat-bubble {
border-radius: 1rem;
padding: 0.75rem;
Expand All @@ -166,34 +171,31 @@ h1 {
width: fit-content;
word-wrap: break-word;
}
.agent-bubble {
background-color: #007BFF;
color: white;
margin-left: 0;
}
.member-bubble {
background-color: #78a6c1;
color: black;
margin-left: auto;
}
.user-bubble {
background-color: #E0E0E0;
color: black;
margin-left: auto;
}
#chat-form {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
margin-top: 12px;
}
.chat-input {
flex: 1 1 90%; /* Flex-grow, flex-shrink, flex-basis */
margin-right: 10px; /* Adjust spacing between input and button */
}
.member-bubble, .user-bubble {
background-color: #78a6c1;
color: black;
margin-left: auto;
}
#message {
flex-grow: 1;
margin-right: 0.5rem;
}
#response {
margin-top: 1rem;
}
#submitButton {
white-space: nowrap; /* Prevents text wrapping in the button */
}
/* MyLife header */
#header {
background-color: #007BFF;
Expand Down
5 changes: 3 additions & 2 deletions views/assets/html/_widget-signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ <h5>Thank <em>you</em> for joining our Pilot!</h5>
let avatarNameEdited = false;
/* page functions */
function handleSignupSuccess() { // Update the button text and display the thank you message on successful signup
signUpForm.style.display = 'none';
const signUpSuccess = document.getElementById('sign-up-success');
signUpSuccess.style.display = 'block';
signUpForm.style.display = 'none';
joinButton.innerText = "Congratulations!";
joinButton.style.display = 'none';
signUpSuccess.classList.add('visible');
signUpSuccess.classList.remove('fade');
}
async function checkSignupStatus() {
try {
Expand Down
114 changes: 67 additions & 47 deletions views/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="container mt-5">
<div class="row">
<div id="chat" class="col-md-12">
<!-- Agent and User messages will be added via innerHTML here -->
<!-- Agent and User messages will be added via innerHTML here -->
</div>
</div>
<div class="row mt-4">
Expand All @@ -10,11 +10,12 @@
<span class="visually-hidden"></span>
</div>
</div>
<div class="col-md-6">
<form id="chat-form" class="d-flex align-items-center">
<div class="col-md-12">
<form id="chat-form" class="d-flex align-items-center justify-content-between">
<label for="message" class="me-2">Chat:</label>
<input id="message" name="message" required class="form-control me-2" />
<input id="message" name="message" required class="form-control me-2 chat-input" />
<button id="submitButton" type="submit" class="btn btn-primary">Submit</button>
<!-- ... other buttons ... -->
<button id="awaitButton" name="awaitButton" class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Connecting with <%= avatar.name %>...
Expand Down Expand Up @@ -47,18 +48,8 @@
1500
);
/* add listeners */
chatForm.addEventListener('submit', (event) => {
event.preventDefault();
const userMessage = messageInput.value.trim();
if (!userMessage.length)
return;
submit(event, userMessage);
addMessageToColumn({ message: userMessage }, {
bubbleClass: 'user-bubble',
_delay: 7,
});
messageInput.value = '';
});
chatForm.addEventListener('submit', addUserMessage);
messageInput.addEventListener('input', toggleInputTextarea); // Event listener to check length of input and convert to textarea
/* page functions */
function addMessageToColumn(_message, _options={
bubbleClass: 'agent-bubble',
Expand All @@ -72,6 +63,7 @@
chatBubble.setAttribute('id', `chat-bubble-${_chatBubbleCount}`);
chatBubble.className = `chat-bubble ${bubbleClass}`;
chatColumn.appendChild(chatBubble);
_message = escapeHtml(message);
if (_typewrite) {
let i = 0;
let tempMessage = '';
Expand All @@ -92,7 +84,52 @@
chatBubble.insertAdjacentHTML('beforeend', message);
}
}

function addUserMessage(_event){
event.preventDefault();
// Dynamically get the current message element (input or textarea)
const messageElement = document.getElementById('message');
let userMessage = messageElement.value.trim();
if (!userMessage.length) return;
userMessage = escapeHtml(userMessage); // Escape the user message
submit(event, userMessage);
addMessageToColumn({ message: userMessage }, {
bubbleClass: 'user-bubble',
_delay: 7,
});
messageElement.value = ''; // Clear the message field
}
// Function to escape HTML special characters
function escapeHtml(text) {
const map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
// Function to focus on the textarea and move cursor to the end
function focusAndSetCursor(textarea) {
textarea.focus();
// Move the cursor to the end of the text
textarea.selectionStart = textarea.selectionEnd = textarea.value.length;
}
// Function to replace an element (input/textarea) with a specified type
function replaceElement(element, newType) {
const newElement = document.createElement(newType);
newElement.id = element.id;
newElement.name = element.name;
newElement.required = element.required;
newElement.classList = element.classList;
newElement.value = element.value;
if (newType === 'textarea') {
newElement.setAttribute('rows', '3');
}
element.parentNode.replaceChild(newElement, element);
newElement.addEventListener('input', toggleInputTextarea); // Reattach the event listener
return newElement;
}
async function submit(_event, _message) {
_event.preventDefault();
submitButton.style.display = 'none';
Expand Down Expand Up @@ -130,34 +167,17 @@
return alert(`Error: ${err.message}`);
}
}
</script>
<style>
.chat-bubble {
border-radius: 1rem;
padding: 0.75rem;
margin-bottom: 0.5rem;
max-width: 66%;
min-width: 20%;
width: fit-content;
width: -moz-fit-content;
word-wrap: break-word;
}
.agent-bubble {
background-color: #007BFF;
color: white;
margin-left: 0;
}
.user-bubble {
background-color: #E0E0E0;
color: black;
margin-left: auto;
}
#header {
background-color: #007BFF;
padding: 0.5rem;
color: white;
}
.header-text {
font-weight: bold;
// Function to toggle between textarea and input based on character count
function toggleInputTextarea() {
let inputElement = document.getElementById('message');
if (inputElement.value.length > 42 && inputElement.tagName !== 'TEXTAREA') {
// Expand to textarea
inputElement = replaceElement(inputElement, 'textarea');
focusAndSetCursor(inputElement);
} else if (inputElement.value.length < 36 && inputElement.tagName === 'TEXTAREA') {
// Revert to input
inputElement = replaceElement(inputElement, 'input');
focusAndSetCursor(inputElement);
}
}
</style>
</script>
72 changes: 58 additions & 14 deletions views/members.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,10 @@
}
}, 1000);
/* page listeners */
chatForm.addEventListener('submit', (event) => {
event.preventDefault();
if (!messageInput.value.trim()?.length) return;
const _message = {
message: messageInput.value.trim()
};
messageInput.value = ''; // immediately scrub
addMessageToColumn(
_message,
{ bubbleClass: 'member-bubble', _typewrite: false }
);
submit(event, _message);

});
// Event listener to submit the form on enter
chatForm.addEventListener('submit', addUserMessage);
// Event listener to check length of input and convert to textarea
messageInput.addEventListener('input', toggleInputTextarea);
/* page functions */
/* todo: fix params, follow more of a content, config, {extras/instructions} structure */
function addMessageToColumn(_message, _options={
Expand All @@ -102,6 +92,7 @@
chatBubble.setAttribute('id', `chat-bubble-${_chatBubbleCount}`);
chatBubble.className = `chat-bubble ${bubbleClass}`;
chatColumn.appendChild(chatBubble);
_message = escapeHtml(message);
if (_typewrite) {
let i = 0;
let tempMessage = '';
Expand All @@ -121,9 +112,49 @@
chatBubble.insertAdjacentHTML('beforeend', message);
}
}
function addUserMessage(_event){
_event.preventDefault();
// Dynamically get the current message element (input or textarea)
const messageElement = document.getElementById('message');
let userMessage = messageElement.value.trim();
if (!userMessage.length) return;
userMessage = escapeHtml(userMessage); // Escape the user message
submit(_event, userMessage);
addMessageToColumn({ message: userMessage }, {
bubbleClass: 'user-bubble',
_delay: 7,
});
messageElement.value = ''; // Clear the message field
}
function getActiveCategory() {
return _activeCategory;
}
// Function to escape HTML special characters
function escapeHtml(text) {
const map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
// Function to replace an element (input/textarea) with a specified type
function replaceElement(element, newType) {
const newElement = document.createElement(newType);
newElement.id = element.id;
newElement.name = element.name;
newElement.required = element.required;
newElement.classList = element.classList;
newElement.value = element.value;
if (newType === 'textarea') {
newElement.setAttribute('rows', '3');
}
element.parentNode.replaceChild(newElement, element);
newElement.addEventListener('input', toggleInputTextarea); // Reattach the event listener
return newElement;
}
async function setActiveCategory(category, contributionId, question) {
const url = '/members/category'; // Replace with your server's URL
const data = {
Expand Down Expand Up @@ -203,4 +234,17 @@
console.error('Error submitting chat:', _error)
})
}
// Function to toggle between textarea and input based on character count
function toggleInputTextarea() {
let inputElement = document.getElementById('message');
if (inputElement.value.length > 42 && inputElement.tagName !== 'TEXTAREA') {
// Expand to textarea
inputElement = replaceElement(inputElement, 'textarea');
focusAndSetCursor(inputElement);
} else if (inputElement.value.length < 36 && inputElement.tagName === 'TEXTAREA') {
// Revert to input
inputElement = replaceElement(inputElement, 'input');
focusAndSetCursor(inputElement);
}
}
</script>

0 comments on commit 9ca3620

Please sign in to comment.