我正在使用 Bootstrap 5 和 NGX-Bootstrap 构建 Angular 12 应用程序。我想创建一个默认情况下处于活动状态但可折叠的侧面导航栏。使用 Bootstrap 5 Offcanvas 可以实现这一点吗?我喜欢使用 Offcanvas 组件轻松实现,并且更喜欢使用它,而不是使用 CSS 创建自己的组件。默认元素会覆盖内容而不是推送内容。有人做过吗?
“是否可以使用 Bootstrap 5 Offcanvas 来实现这一点?我喜欢使用 Offcanvas 组件实现的简便性,并且会 更喜欢使用它,而不是使用 CSS 创建自己的。”
不,不可能使用 Offcanvas 组件,因为默认的 Offcanvas 是覆盖实现。因此,它将需要自定义 CSS。
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Chatbot in JavaScript | CodingNepal</title>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Google Fonts Link For Icons -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,1,0" />
<script src="script.js" defer></script>
</head>
<body>
<button class="chatbot-toggler">
<span class="material-symbols-rounded">mode_comment</span>
<span class="material-symbols-outlined">close</span>
</button>
<div class="chatbot">
<header>
<h2>Chatbot</h2>
<span class="close-btn material-symbols-outlined">close</span>
</header>
<ul class="chatbox">
<li class="chat incoming">
<span class="material-symbols-outlined">smart_toy</span>
<p>Hi there <br>How can I help you today?</p>
</li>
</ul>
<div class="chat-input">
<textarea placeholder="Enter a message..." spellcheck="false" required></textarea>
<span id="send-btn" class="material-symbols-rounded">send</span>
</div>
</div>
</body>
</html>
<style>
/* Import Google font - Poppins */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
background: #E3F2FD;
}
.chatbot-toggler {
position: fixed;
bottom: 30px;
right: 35px;
outline: none;
border: none;
height: 50px;
width: 50px;
display: flex;
cursor: pointer;
align-items: center;
justify-content: center;
border-radius: 50%;
background: #724ae8;
transition: all 0.2s ease;
}
body.show-chatbot .chatbot-toggler {
transform: rotate(90deg);
}
.chatbot-toggler span {
color: #fff;
position: absolute;
}
.chatbot-toggler span:last-child,
body.show-chatbot .chatbot-toggler span:first-child {
opacity: 0;
}
body.show-chatbot .chatbot-toggler span:last-child {
opacity: 1;
}
.chatbot {
position: fixed;
right: 35px;
bottom: 90px;
width: 420px;
background: #fff;
border-radius: 15px;
overflow: hidden;
opacity: 0;
pointer-events: none;
transform: scale(0.5);
transform-origin: bottom right;
box-shadow: 0 0 128px 0 rgba(0,0,0,0.1),
0 32px 64px -48px rgba(0,0,0,0.5);
transition: all 0.1s ease;
}
body.show-chatbot .chatbot {
opacity: 1;
pointer-events: auto;
transform: scale(1);
}
.chatbot header {
padding: 16px 0;
position: relative;
text-align: center;
color: #fff;
background: #724ae8;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.chatbot header span {
position: absolute;
right: 15px;
top: 50%;
display: none;
cursor: pointer;
transform: translateY(-50%);
}
header h2 {
font-size: 1.4rem;
}
.chatbot .chatbox {
overflow-y: auto;
height: 510px;
padding: 30px 20px 100px;
}
.chatbot :where(.chatbox, textarea)::-webkit-scrollbar {
width: 6px;
}
.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-track {
background: #fff;
border-radius: 25px;
}
.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 25px;
}
.chatbox .chat {
display: flex;
list-style: none;
}
.chatbox .outgoing {
margin: 20px 0;
justify-content: flex-end;
}
.chatbox .incoming span {
width: 32px;
height: 32px;
color: #fff;
cursor: default;
text-align: center;
line-height: 32px;
align-self: flex-end;
background: #724ae8;
border-radius: 4px;
margin: 0 10px 7px 0;
}
.chatbox .chat p {
white-space: pre-wrap;
padding: 12px 16px;
border-radius: 10px 10px 0 10px;
max-width: 75%;
color: #fff;
font-size: 0.95rem;
background: #724ae8;
}
.chatbox .incoming p {
border-radius: 10px 10px 10px 0;
}
.chatbox .chat p.error {
color: #721c24;
background: #f8d7da;
}
.chatbox .incoming p {
color: #000;
background: #f2f2f2;
}
.chatbot .chat-input {
display: flex;
gap: 5px;
position: absolute;
bottom: 0;
width: 100%;
background: #fff;
padding: 3px 20px;
border-top: 1px solid #ddd;
}
.chat-input textarea {
height: 55px;
width: 100%;
border: none;
outline: none;
resize: none;
max-height: 180px;
padding: 15px 15px 15px 0;
font-size: 0.95rem;
}
.chat-input span {
align-self: flex-end;
color: #724ae8;
cursor: pointer;
height: 55px;
display: flex;
align-items: center;
visibility: hidden;
font-size: 1.35rem;
}
.chat-input textarea:valid ~ span {
visibility: visible;
}
@media (max-width: 490px) {
.chatbot-toggler {
right: 20px;
bottom: 20px;
}
.chatbot {
right: 0;
bottom: 0;
height: 100%;
border-radius: 0;
width: 100%;
}
.chatbot .chatbox {
height: 90%;
padding: 25px 15px 100px;
}
.chatbot .chat-input {
padding: 5px 15px;
}
.chatbot header span {
display: block;
}
}
</style>
<script>
const chatbotToggler = document.querySelector(".chatbot-toggler");
const closeBtn = document.querySelector(".close-btn");
const chatbox = document.querySelector(".chatbox");
const chatInput = document.querySelector(".chat-input textarea");
const sendChatBtn = document.querySelector(".chat-input span");
let userMessage = null; // Variable to store user's message
const inputInitHeight = chatInput.scrollHeight;
// API configuration
const API_KEY = "PASTE-YOUR-API-KEY"; // Your API key here
const API_URL = `https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent?key=${API_KEY}`;
const createChatLi = (message, className) => {
// Create a chat <li> element with passed message and className
const chatLi = document.createElement("li");
chatLi.classList.add("chat", `${className}`);
let chatContent = className === "outgoing" ? `<p></p>` : `<span class="material-symbols-outlined">smart_toy</span><p></p>`;
chatLi.innerHTML = chatContent;
chatLi.querySelector("p").textContent = message;
return chatLi; // return chat <li> element
}
const generateResponse = async (chatElement) => {
const messageElement = chatElement.querySelector("p");
// Define the properties and message for the API request
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
contents: [{
role: "user",
parts: [{ text: userMessage }]
}]
}),
}
// Send POST request to API, get response and set the reponse as paragraph text
try {
const response = await fetch(API_URL, requestOptions);
const data = await response.json();
if (!response.ok) throw new Error(data.error.message);
// Get the API response text and update the message element
messageElement.textContent = data.candidates[0].content.parts[0].text.replace(/\*\*(.*?)\*\*/g, '$1');
} catch (error) {
// Handle error
messageElement.classList.add("error");
messageElement.textContent = error.message;
} finally {
chatbox.scrollTo(0, chatbox.scrollHeight);
}
}
const handleChat = () => {
userMessage = chatInput.value.trim(); // Get user entered message and remove extra whitespace
if (!userMessage) return;
// Clear the input textarea and set its height to default
chatInput.value = "";
chatInput.style.height = `${inputInitHeight}px`;
// Append the user's message to the chatbox
chatbox.appendChild(createChatLi(userMessage, "outgoing"));
chatbox.scrollTo(0, chatbox.scrollHeight);
setTimeout(() => {
// Display "Thinking..." message while waiting for the response
const incomingChatLi = createChatLi("Thinking...", "incoming");
chatbox.appendChild(incomingChatLi);
chatbox.scrollTo(0, chatbox.scrollHeight);
generateResponse(incomingChatLi);
}, 600);
}
chatInput.addEventListener("input", () => {
// Adjust the height of the input textarea based on its content
chatInput.style.height = `${inputInitHeight}px`;
chatInput.style.height = `${chatInput.scrollHeight}px`;
});
chatInput.addEventListener("keydown", (e) => {
// If Enter key is pressed without Shift key and the window
// width is greater than 800px, handle the chat
if (e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) {
e.preventDefault();
handleChat();
}
});
sendChatBtn.addEventListener("click", handleChat);
closeBtn.addEventListener("click", () => document.body.classList.remove("show-chatbot"));
chatbotToggler.addEventListener("click", () => document.body.classList.toggle("show-chatbot"));
</script>