fix: restore complete working chat modal implementation from commit 3e01e9c
This commit is contained in:
parent
5d584bf8f0
commit
bd0b0a5f97
1 changed files with 256 additions and 214 deletions
|
|
@ -125,258 +125,292 @@ function addCodeBlockCopyButtons(element) {
|
|||
|
||||
// Advanced modal implementation (was openUncloseaiEmbeddedModalNew)
|
||||
export async function openUncloseaiEmbeddedModalNew() {
|
||||
// The complete 2000+ line implementation would go here
|
||||
// For now, calling the simpler version
|
||||
console.log("Advanced modal implementation - calling simpler version for now");
|
||||
return await openUncloseaiEmbeddedModal();
|
||||
}
|
||||
// Ensure ChunkFive font is loaded
|
||||
initializeChunkFiveFont();
|
||||
|
||||
// Get theme colors
|
||||
const theme = detectCurrentTheme();
|
||||
const colors = getThemeColors(theme);
|
||||
|
||||
// Main modal implementation (extracted from ui.js)
|
||||
export async function openUncloseaiEmbeddedModal() {
|
||||
const modal = document.createElement("dialog");
|
||||
modal.id = "uncloseai-embedded-modal";
|
||||
modal.setAttribute("data-theme", theme);
|
||||
|
||||
// Mobile-first: full screen on mobile, centered on desktop
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
if (isMobile) {
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background: white;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 2000;
|
||||
overflow: hidden;
|
||||
`;
|
||||
} else {
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
width: 90vw;
|
||||
max-width: 800px;
|
||||
height: 90vh;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border: none;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
|
||||
background: white;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 2000;
|
||||
overflow: hidden;
|
||||
`;
|
||||
}
|
||||
|
||||
const article = document.createElement("article");
|
||||
if (USE_CUSTOM_STYLING) {
|
||||
article.style.cssText = `
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: auto auto 1fr auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`;
|
||||
} else {
|
||||
// Responsive scaling based on screen width
|
||||
const screenWidth = window.innerWidth;
|
||||
const scale = screenWidth < 480 ? 0.9 : screenWidth < 768 ? 0.8 : 0.75;
|
||||
|
||||
article.style.cssText = `
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: auto auto 1fr auto;
|
||||
transform: scale(${scale});
|
||||
transform-origin: top center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
box-sizing: border-box;
|
||||
`;
|
||||
}
|
||||
modal.appendChild(article);
|
||||
|
||||
// Handle viewport changes (onscreen keyboard)
|
||||
if (!USE_CUSTOM_STYLING) {
|
||||
const handleViewportChange = () => {
|
||||
// Use dvh (dynamic viewport height) for better mobile keyboard handling
|
||||
modal.style.height = "100dvh";
|
||||
// Fallback for browsers that don't support dvh
|
||||
if (window.visualViewport) {
|
||||
modal.style.height = `${window.visualViewport.height}px`;
|
||||
}
|
||||
};
|
||||
|
||||
// Listen for visual viewport changes (keyboard open/close)
|
||||
if (window.visualViewport) {
|
||||
window.visualViewport.addEventListener("resize", handleViewportChange);
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: ${colors.modalBackground};
|
||||
color: ${colors.primaryText};
|
||||
z-index: 2000;
|
||||
${
|
||||
isMobile
|
||||
? `
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100vw;
|
||||
max-height: 100vh;
|
||||
border-radius: 0;
|
||||
`
|
||||
: `
|
||||
width: 90vw;
|
||||
max-width: 800px;
|
||||
height: 90vh;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 20px 40px ${colors.shadowColor};
|
||||
`
|
||||
}
|
||||
`;
|
||||
|
||||
// Also listen for window resize as fallback
|
||||
window.addEventListener("resize", handleViewportChange);
|
||||
// Simple container with flex layout
|
||||
const container = document.createElement("div");
|
||||
container.style.cssText = `
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
// Initial call
|
||||
handleViewportChange();
|
||||
}
|
||||
// Header
|
||||
const header = document.createElement("header");
|
||||
header.style.cssText = `
|
||||
flex-shrink: 0;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 4px ${colors.lightShadow};
|
||||
`;
|
||||
|
||||
// Create modal header
|
||||
const header = document.createElement("div");
|
||||
if (USE_CUSTOM_STYLING) {
|
||||
header.style.cssText = `
|
||||
background: linear-gradient(45deg, #4CAF50 0%, #45a049 100%);
|
||||
color: white;
|
||||
padding: 16px 20px;
|
||||
margin: -1em -1em 1em -1em;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
`;
|
||||
} else {
|
||||
header.style.cssText = `
|
||||
background: rgba(76, 175, 80, 0.9);
|
||||
color: white;
|
||||
padding: 16px 20px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
backdrop-filter: blur(10px);
|
||||
`;
|
||||
}
|
||||
article.appendChild(header);
|
||||
const titleContainer = document.createElement("div");
|
||||
titleContainer.style.cssText =
|
||||
"flex: 1; display: flex; flex-direction: column; gap: 4px;";
|
||||
|
||||
const h1 = document.createElement("h1");
|
||||
h1.innerHTML = `<span style="font-family: 'ChunkFiveRegular', monospace;">uncloseai.</span> ${getUIText("chatWithAI")}`;
|
||||
if (USE_CUSTOM_STYLING) {
|
||||
h1.style.cssText = `
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
`;
|
||||
} else {
|
||||
h1.style.cssText = `
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
`;
|
||||
}
|
||||
header.appendChild(h1);
|
||||
const title = document.createElement("h2");
|
||||
title.innerHTML =
|
||||
"🤖 <span style=\"font-family: 'ChunkFiveRegular', monospace;\">uncloseai.</span>";
|
||||
title.style.cssText = `
|
||||
margin: 0;
|
||||
font-size: ${isMobile ? "18px" : "20px"};
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const closeButton = document.createElement("button");
|
||||
closeButton.textContent = "X";
|
||||
if (USE_CUSTOM_STYLING) {
|
||||
closeButton.style.cssText = `
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
touch-action: manipulation;
|
||||
`;
|
||||
} else {
|
||||
closeButton.style.cssText = `
|
||||
background: rgba(255,255,255,0.2);
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: opacity 0.2s;
|
||||
touch-action: manipulation;
|
||||
`;
|
||||
closeButton.onmouseenter = () => (closeButton.style.opacity = "0.7");
|
||||
closeButton.onmouseleave = () => (closeButton.style.opacity = "1");
|
||||
}
|
||||
closeButton.onclick = () => {
|
||||
const subtitle = document.createElement("div");
|
||||
const pageTitle = document.title || window.location.hostname;
|
||||
subtitle.innerHTML = `
|
||||
<div style="font-size: 12px; opacity: 0.9; font-weight: normal; line-height: 1.3;">
|
||||
<span style="font-family: 'ChunkFiveRegular', monospace;">uncloseai.</span> ${getUIText("hermesIntro")}<br>
|
||||
<span style="opacity: 0.8;">${getUIText("discussingPage")}: ${pageTitle}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
titleContainer.appendChild(title);
|
||||
titleContainer.appendChild(subtitle);
|
||||
|
||||
const closeBtn = document.createElement("button");
|
||||
closeBtn.textContent = "✕";
|
||||
closeBtn.style.cssText = `
|
||||
background: rgba(255,255,255,0.2);
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.2s;
|
||||
`;
|
||||
closeBtn.onmouseover = () =>
|
||||
(closeBtn.style.background = "rgba(255,255,255,0.3)");
|
||||
closeBtn.onmouseout = () =>
|
||||
(closeBtn.style.background = "rgba(255,255,255,0.2)");
|
||||
closeBtn.onclick = () => {
|
||||
modal.close();
|
||||
document.body.removeChild(modal);
|
||||
window.uncloseaiEmbeddedModalOpen = false;
|
||||
};
|
||||
header.appendChild(closeButton);
|
||||
|
||||
// Add main content area with basic implementation
|
||||
const mainContent = document.createElement("div");
|
||||
mainContent.style.cssText = `
|
||||
const headerRight = document.createElement("div");
|
||||
headerRight.style.cssText = "display: flex; gap: 8px; align-items: center;";
|
||||
headerRight.appendChild(closeBtn);
|
||||
|
||||
header.appendChild(titleContainer);
|
||||
header.appendChild(headerRight);
|
||||
|
||||
// Chat area
|
||||
const chatArea = document.createElement("div");
|
||||
chatArea.style.cssText = `
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
background: ${colors.contentBackground};
|
||||
-webkit-overflow-scrolling: touch;
|
||||
`;
|
||||
|
||||
// Add a simple chat interface
|
||||
const chatBox = document.createElement("div");
|
||||
chatBox.id = "modal-chat-box";
|
||||
chatBox.style.cssText = `
|
||||
flex: 1;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
overflow-y: auto;
|
||||
background: #f9f9f9;
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
`;
|
||||
chatBox.innerHTML = `<p><em>Chat interface placeholder - full implementation needed</em></p>`;
|
||||
chatArea.appendChild(chatBox);
|
||||
|
||||
// Add input area
|
||||
// Assemble modal structure
|
||||
container.appendChild(header);
|
||||
container.appendChild(chatArea);
|
||||
|
||||
// Input area
|
||||
const inputArea = document.createElement("div");
|
||||
inputArea.style.cssText = `
|
||||
flex-shrink: 0;
|
||||
padding: 16px;
|
||||
background: ${colors.panelBackground};
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
align-items: flex-end;
|
||||
box-shadow: 0 -2px 10px ${colors.lightShadow};
|
||||
`;
|
||||
|
||||
const messageInput = document.createElement("input");
|
||||
messageInput.type = "text";
|
||||
messageInput.placeholder = getUIText("typePlaceholder") || "Type your message...";
|
||||
messageInput.style.cssText = `
|
||||
const input = document.createElement("textarea");
|
||||
input.id = "modal-user-input";
|
||||
input.placeholder = getUIText("typePlaceholder");
|
||||
input.style.cssText = `
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
min-height: 44px;
|
||||
max-height: 120px;
|
||||
padding: 12px;
|
||||
border: 1px solid ${colors.borderColor};
|
||||
border-radius: 24px;
|
||||
resize: none;
|
||||
font-size: 16px;
|
||||
font-family: inherit;
|
||||
line-height: 1.4;
|
||||
outline: none;
|
||||
background: ${colors.inputBackground};
|
||||
color: ${colors.primaryText};
|
||||
transition: border-color 0.2s;
|
||||
`;
|
||||
input.onfocus = () => (input.style.borderColor = colors.focusBorder);
|
||||
input.onblur = () => (input.style.borderColor = colors.borderColor);
|
||||
|
||||
const sendButton = document.createElement("button");
|
||||
sendButton.textContent = "Send";
|
||||
sendButton.style.cssText = `
|
||||
padding: 10px 20px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
sendButton.onclick = () => {
|
||||
console.log("Send clicked:", messageInput.value);
|
||||
// Basic chat functionality would go here
|
||||
// Auto-resize textarea
|
||||
input.oninput = () => {
|
||||
input.style.height = "auto";
|
||||
input.style.height = `${Math.min(input.scrollHeight, 120)}px`;
|
||||
};
|
||||
|
||||
inputArea.appendChild(messageInput);
|
||||
inputArea.appendChild(sendButton);
|
||||
mainContent.appendChild(chatBox);
|
||||
mainContent.appendChild(inputArea);
|
||||
article.appendChild(mainContent);
|
||||
const sendBtn = document.createElement("button");
|
||||
sendBtn.textContent = "→";
|
||||
sendBtn.style.cssText = `
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
padding: 0;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: transform 0.2s;
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
sendBtn.onmouseover = () => (sendBtn.style.transform = "scale(1.05)");
|
||||
sendBtn.onmouseout = () => (sendBtn.style.transform = "scale(1)");
|
||||
|
||||
// Handle message sending
|
||||
const sendMessageHandler = async () => {
|
||||
const message = input.value.trim();
|
||||
if (!message) return;
|
||||
|
||||
input.value = "";
|
||||
input.style.height = "44px";
|
||||
|
||||
// Add user message
|
||||
const userMsg = document.createElement("div");
|
||||
userMsg.style.cssText = `
|
||||
align-self: flex-end;
|
||||
background: ${colors.userMessageBg};
|
||||
color: ${colors.userMessageText};
|
||||
padding: 12px 16px;
|
||||
border-radius: 18px 18px 4px 18px;
|
||||
max-width: 80%;
|
||||
word-wrap: break-word;
|
||||
`;
|
||||
|
||||
userMsg.textContent = message;
|
||||
chatBox.appendChild(userMsg);
|
||||
|
||||
// Auto-scroll to bottom
|
||||
chatArea.scrollTop = chatArea.scrollHeight;
|
||||
|
||||
// Add AI response
|
||||
const aiMsg = document.createElement("div");
|
||||
aiMsg.style.cssText = `
|
||||
align-self: flex-start;
|
||||
background: ${colors.aiMessageBg};
|
||||
color: ${colors.aiMessageText};
|
||||
padding: 12px 16px;
|
||||
border-radius: 18px 18px 18px 4px;
|
||||
max-width: 80%;
|
||||
word-wrap: break-word;
|
||||
`;
|
||||
|
||||
const responseContent = document.createElement("div");
|
||||
aiMsg.appendChild(responseContent);
|
||||
chatBox.appendChild(aiMsg);
|
||||
|
||||
// Get AI response
|
||||
let accumulatedContent = "";
|
||||
try {
|
||||
for await (const chunk of sendMessage(message)) {
|
||||
accumulatedContent += chunk;
|
||||
responseContent.innerHTML = marked.parse(accumulatedContent);
|
||||
|
||||
// Add copy buttons to code blocks
|
||||
addCodeBlockCopyButtons(responseContent);
|
||||
|
||||
// Auto-scroll to bottom as response streams in
|
||||
chatArea.scrollTop = chatArea.scrollHeight;
|
||||
}
|
||||
} catch (error) {
|
||||
responseContent.textContent = `Error: ${error.message}`;
|
||||
}
|
||||
};
|
||||
|
||||
sendBtn.onclick = sendMessageHandler;
|
||||
input.onkeydown = (e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
sendMessageHandler();
|
||||
}
|
||||
};
|
||||
|
||||
inputArea.appendChild(input);
|
||||
inputArea.appendChild(sendBtn);
|
||||
container.appendChild(inputArea);
|
||||
|
||||
modal.appendChild(container);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// Use showModal() for proper mobile support and backdrop
|
||||
|
|
@ -393,6 +427,14 @@ export async function openUncloseaiEmbeddedModal() {
|
|||
|
||||
// Set global flag
|
||||
window.uncloseaiEmbeddedModalOpen = true;
|
||||
|
||||
// Focus input
|
||||
setTimeout(() => input.focus(), 100);
|
||||
}
|
||||
|
||||
// Main modal implementation - now calls the complete version
|
||||
export async function openUncloseaiEmbeddedModal() {
|
||||
return await openUncloseaiEmbeddedModalNew();
|
||||
}
|
||||
|
||||
// Export functions for global access
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue