improve chat ui
All checks were successful
Build Container / Build Container (push) Successful in 1m29s
All checks were successful
Build Container / Build Container (push) Successful in 1m29s
This commit is contained in:
parent
2ef2b04e49
commit
81923c4f8c
7 changed files with 170 additions and 48 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import {createIcons, Send, Stars} from "lucide"
|
import {Bot, createIcons, UserRound, Send, Stars} from "lucide"
|
||||||
|
import {useTranslations} from "../i18n/utils.ts"
|
||||||
import removeDiacritics from "./removeDiacritics.ts"
|
import removeDiacritics from "./removeDiacritics.ts"
|
||||||
|
|
||||||
export type ResponseDictType = {
|
export type ResponseDictType = {
|
||||||
|
|
@ -16,6 +17,8 @@ const doors = window.doors
|
||||||
const auth = window.auth
|
const auth = window.auth
|
||||||
const doorAction = window.doorAction
|
const doorAction = window.doorAction
|
||||||
|
|
||||||
|
const t = useTranslations(lang)
|
||||||
|
|
||||||
const responses =
|
const responses =
|
||||||
lang === "de"
|
lang === "de"
|
||||||
? (await import("./chatDict_de")).default
|
? (await import("./chatDict_de")).default
|
||||||
|
|
@ -25,19 +28,51 @@ const responses =
|
||||||
const sortedResponses = responses.sort(
|
const sortedResponses = responses.sort(
|
||||||
(a, b) => b.priority - a.priority)
|
(a, b) => b.priority - a.priority)
|
||||||
|
|
||||||
|
const chatAvatar = `
|
||||||
|
<div class="chat-image avatar">
|
||||||
|
<div class="w-10 rounded-full ${lang === 'uwu' ? 'bg-transparent' : 'bg-primary'} flex items-center justify-center">
|
||||||
|
${lang === 'uwu' ? '<span class="text-4xl">🥺</span>' : '<i data-lucide="bot"></i>'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const chatHeader = `
|
||||||
|
<div class="chat-header">
|
||||||
|
${t("chat.dooris")}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const chatAvatarUser = `
|
||||||
|
<div class="chat-image avatar">
|
||||||
|
<div class="w-10 rounded-full ${lang === 'uwu' ? 'bg-transparent' : 'bg-secondary'} flex items-center justify-center">
|
||||||
|
${lang === 'uwu' ? '<span class="text-4xl">🥺</span>' : '<i data-lucide="user-round"></i>'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const chatHeaderUser = `
|
||||||
|
<div class="chat-header">
|
||||||
|
${t("chat.user")}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const chatWait = `
|
||||||
|
<div class="chat chat-start w-full prose" data-waiting>
|
||||||
|
${chatAvatar}
|
||||||
|
${chatHeader}
|
||||||
|
<div class="chat-bubble chat-bubble-primary whitespace-normal min-h-10">
|
||||||
|
<span class="loading loading-dots loading-md"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
const templateInjectChat = `
|
const templateInjectChat = `
|
||||||
<details class="dropdown dropdown-top dropdown-end absolute right-4 bottom-4" id="chat-root">
|
<details class="dropdown dropdown-top dropdown-end absolute right-2 bottom-2" id="chat-root">
|
||||||
<summary class="btn btn-lg btn-circle btn-primary">
|
<summary class="btn btn-lg btn-circle btn-primary me-2 mb-2">
|
||||||
<i data-lucide="stars"></i>
|
<i data-lucide="stars"></i>
|
||||||
</summary>
|
</summary>
|
||||||
<div class="dropdown-content card min-h-120 max-h-200 w-80 bg-base-300 p-4 mb-4">
|
<div class="dropdown-content card h-140 w-90 bg-base-300 p-4 mb-4" style="max-height: min(calc(100vh - 10rem), 50rem); max-width: calc(100vw - 1rem)">
|
||||||
<div class="w-full overflow-auto h-full prose leading-5" id="chat"></div>
|
<div class="w-full overflow-y-auto h-full prose leading-5 grow pb-4" id="chat"></div>
|
||||||
<div class="chat chat-start w-full hidden" id="chat-waiting">
|
|
||||||
<div class="chat-bubble chat-bubble-primary whitespace-normal">
|
|
||||||
<span class="loading loading-dots loading-md"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-4"></div>
|
|
||||||
<div class="join mt-auto w-full">
|
<div class="join mt-auto w-full">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<label class="input join-item">
|
<label class="input join-item">
|
||||||
|
|
@ -79,11 +114,14 @@ function refreshChat() {
|
||||||
const chatContainer = document.createElement("div")
|
const chatContainer = document.createElement("div")
|
||||||
const chatBubble = document.createElement("div")
|
const chatBubble = document.createElement("div")
|
||||||
|
|
||||||
chatBubble.classList.add("chat-bubble", "chat-bubble-primary", "whitespace-normal")
|
chatBubble.classList.add("chat-bubble", "chat-bubble-primary", "whitespace-normal", "min-h-10", "break-[break-word]")
|
||||||
|
chatBubble.style.wordBreak = "break-word"
|
||||||
chatBubble.classList.toggle("shimmer", special)
|
chatBubble.classList.toggle("shimmer", special)
|
||||||
chatBubble.id = id
|
|
||||||
chatBubble.dataset.content = message
|
chatBubble.dataset.content = message
|
||||||
chatContainer.classList.add("chat", "chat-start", "w-full")
|
chatContainer.classList.add("chat", "chat-start", "w-full", "overflow-visible", "hidden", "pe-10")
|
||||||
|
chatContainer.id = id
|
||||||
|
chatContainer.insertAdjacentHTML("afterbegin", chatAvatar)
|
||||||
|
chatContainer.insertAdjacentHTML("afterbegin", chatHeader)
|
||||||
chatContainer.append(chatBubble)
|
chatContainer.append(chatBubble)
|
||||||
|
|
||||||
return chatContainer
|
return chatContainer
|
||||||
|
|
@ -91,10 +129,16 @@ function refreshChat() {
|
||||||
|
|
||||||
|
|
||||||
const templateUser = (message: string) => `
|
const templateUser = (message: string) => `
|
||||||
<div class="chat chat-end w-full">
|
<div class="chat chat-end w-full ps-10">
|
||||||
<div class="chat-bubble chat-bubble-secondary whitespace-normal">${message}</div>
|
${chatAvatarUser}
|
||||||
|
${chatHeaderUser}
|
||||||
|
<div class="chat-bubble chat-bubble-secondary whitespace-normal" style="word-break: break-word;">${message}</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
|
const chatBubbleIds: Array<string> = []
|
||||||
|
|
||||||
|
console.log(chat)
|
||||||
|
|
||||||
chat.forEach(chatItem => {
|
chat.forEach(chatItem => {
|
||||||
switch (chatItem.type) {
|
switch (chatItem.type) {
|
||||||
case "bot":
|
case "bot":
|
||||||
|
|
@ -102,8 +146,7 @@ function refreshChat() {
|
||||||
chatItem.id = `chat-${chatId}`
|
chatItem.id = `chat-${chatId}`
|
||||||
chatId++
|
chatId++
|
||||||
chatElement?.appendChild(templateBot(chatItem.id, chatItem.message, chatItem.special ?? false))
|
chatElement?.appendChild(templateBot(chatItem.id, chatItem.message, chatItem.special ?? false))
|
||||||
typeBubble(chatItem.id, () => {
|
chatBubbleIds.push(chatItem.id)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "user":
|
case "user":
|
||||||
|
|
@ -115,16 +158,35 @@ function refreshChat() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
chatWaitElement.classList.toggle("hidden", !chatWaiting.value)
|
|
||||||
|
typeBubble(chatBubbleIds)
|
||||||
|
|
||||||
|
chatElement.querySelector("[data-waiting]")?.remove()
|
||||||
|
|
||||||
|
if (chatWaiting.value) {
|
||||||
|
chatElement.insertAdjacentHTML("beforeend", chatWait)
|
||||||
|
}
|
||||||
|
|
||||||
chatElement.scrollTo({
|
chatElement.scrollTo({
|
||||||
top: chatElement.scrollHeight,
|
top: chatElement.scrollHeight,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
refreshIcons()
|
||||||
}
|
}
|
||||||
|
|
||||||
function typeBubble(id: string, callback: Function) {
|
function typeBubble(ids: Array<string>) {
|
||||||
const element = document.getElementById(id)!
|
if (!ids.length) return
|
||||||
|
|
||||||
|
console.log(ids)
|
||||||
|
|
||||||
|
const firstId = ids.slice(0, 1)[0]
|
||||||
|
const restIds = ids.slice(1)!
|
||||||
|
|
||||||
|
const chatContainer = document.getElementById(firstId)!
|
||||||
|
chatContainer.classList.remove('hidden')
|
||||||
|
const chatBubble: HTMLDivElement = chatContainer.querySelector('.chat-bubble')!
|
||||||
const tmpDiv = document.createElement("div")
|
const tmpDiv = document.createElement("div")
|
||||||
tmpDiv.innerHTML = element.getAttribute("data-content") || ""
|
tmpDiv.innerHTML = chatBubble.getAttribute("data-content") || ""
|
||||||
|
|
||||||
const typingArray: Array<string> = []
|
const typingArray: Array<string> = []
|
||||||
|
|
||||||
|
|
@ -144,14 +206,14 @@ function typeBubble(id: string, callback: Function) {
|
||||||
function typeChar() {
|
function typeChar() {
|
||||||
if (charIndex < typingArray.length) {
|
if (charIndex < typingArray.length) {
|
||||||
text += typingArray.at(charIndex)
|
text += typingArray.at(charIndex)
|
||||||
element.innerHTML = text
|
chatBubble.innerHTML = text
|
||||||
charIndex++
|
charIndex++
|
||||||
setTimeout(typeChar, typingSpeed)
|
setTimeout(typeChar, typingSpeed)
|
||||||
chatElement.scrollTo({
|
chatElement.scrollTo({
|
||||||
top: chatElement.scrollHeight,
|
top: chatElement.scrollHeight,
|
||||||
})
|
})
|
||||||
} else if (callback) {
|
} else if (restIds.length > 0) {
|
||||||
callback()
|
typeBubble(restIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,7 +382,7 @@ function getResponse(message: string) {
|
||||||
return {
|
return {
|
||||||
type: "bot" as ChatMessage["type"],
|
type: "bot" as ChatMessage["type"],
|
||||||
message: response.message,
|
message: response.message,
|
||||||
special: response.special
|
special: response.special,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -335,7 +397,6 @@ function getResponse(message: string) {
|
||||||
|
|
||||||
document.querySelector("body")?.insertAdjacentHTML("beforeend", templateInjectChat)
|
document.querySelector("body")?.insertAdjacentHTML("beforeend", templateInjectChat)
|
||||||
const chatElement: HTMLDivElement = document.querySelector("#chat")!
|
const chatElement: HTMLDivElement = document.querySelector("#chat")!
|
||||||
const chatWaitElement: HTMLDivElement = document.querySelector("#chat-waiting")!
|
|
||||||
|
|
||||||
function initChat() {
|
function initChat() {
|
||||||
chat.push({
|
chat.push({
|
||||||
|
|
@ -347,14 +408,20 @@ function initChat() {
|
||||||
|
|
||||||
let firstOpen = true
|
let firstOpen = true
|
||||||
|
|
||||||
createIcons({
|
function refreshIcons() {
|
||||||
nameAttr: "data-lucide",
|
createIcons({
|
||||||
root: document.querySelector("#chat-root")!,
|
nameAttr: "data-lucide",
|
||||||
icons: {
|
root: document.querySelector("#chat-root")!,
|
||||||
Stars,
|
icons: {
|
||||||
Send,
|
Stars,
|
||||||
},
|
Send,
|
||||||
})
|
UserRound,
|
||||||
|
Bot,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshIcons()
|
||||||
|
|
||||||
document.querySelector("#send-chat")!.addEventListener("click", sendMessage)
|
document.querySelector("#send-chat")!.addEventListener("click", sendMessage)
|
||||||
document.querySelector("#chat-text")!.addEventListener("keydown", (e: Event) => {
|
document.querySelector("#chat-text")!.addEventListener("keydown", (e: Event) => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import type {ResponseDictType} from "./chat.ts"
|
import type {ResponseDictType} from "./chat.ts"
|
||||||
|
|
||||||
const responses: ResponseDictType[] = [
|
const responses: ResponseDictType[] = [
|
||||||
|
{
|
||||||
|
trigger: ["hi", "moin", "hallo", "servus", "gruess gott"],
|
||||||
|
response: "Moin! 👋",
|
||||||
|
priority: 0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
startsWith: ["bist du", "sind sie"],
|
startsWith: ["bist du", "sind sie"],
|
||||||
response: "Sein oder Nichtsein - das sind doch bürgerliche Kategorien...",
|
response: "Sein oder Nichtsein - das sind doch bürgerliche Kategorien...",
|
||||||
|
|
@ -22,8 +27,8 @@ const responses: ResponseDictType[] = [
|
||||||
priority: 0,
|
priority: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
trigger: ["hi", "moin", "hallo", "servus", "gruess gott"],
|
trigger: [":3"],
|
||||||
response: "Moin! 👋",
|
response: ":3",
|
||||||
priority: 0,
|
priority: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -68,7 +73,7 @@ const responses: ResponseDictType[] = [
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
response: "Moin!<br>Wie kann ich dir behilflich sein? 🤓",
|
response: "Moin, ich bin TüRIS!<br>Wie kann ich dir behilflich sein? 🤓",
|
||||||
priority: -1,
|
priority: -1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import type {ResponseDictType} from "./chat.ts"
|
import type {ResponseDictType} from "./chat.ts"
|
||||||
|
|
||||||
const responses: ResponseDictType[] = [
|
const responses: ResponseDictType[] = [
|
||||||
|
{
|
||||||
|
trigger: ["hi", "hello"],
|
||||||
|
response: "Hi! 👋",
|
||||||
|
priority: 0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
startsWith: ["are you"],
|
startsWith: ["are you"],
|
||||||
response: "To be or not to be - those are bourgeois categories, after all...",
|
response: "To be or not to be - those are bourgeois categories, after all...",
|
||||||
|
|
@ -22,8 +27,8 @@ const responses: ResponseDictType[] = [
|
||||||
priority: 0,
|
priority: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
trigger: ["hi", "hello"],
|
trigger: [":3"],
|
||||||
response: "Hi! 👋",
|
response: ":3",
|
||||||
priority: 0,
|
priority: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -68,7 +73,7 @@ const responses: ResponseDictType[] = [
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
response: "Hi!<br>How can I help you? 🤓",
|
response: "Hi, I'm DOORIS!<br>How can I help you? 🤓",
|
||||||
priority: -1,
|
priority: -1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import type {ResponseDictType} from "./chat.ts"
|
import type {ResponseDictType} from "./chat.ts"
|
||||||
|
|
||||||
const responses: ResponseDictType[] = [
|
const responses: ResponseDictType[] = [
|
||||||
|
{
|
||||||
|
trigger: ["uwu", "hi", "hello"],
|
||||||
|
response: "uwu!",
|
||||||
|
priority: 0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
startsWith: ["are you"],
|
startsWith: ["are you"],
|
||||||
response: "me is uwu!",
|
response: "me is uwu!",
|
||||||
|
|
@ -22,8 +27,8 @@ const responses: ResponseDictType[] = [
|
||||||
priority: 0,
|
priority: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
trigger: ["uwu", "hi", "hello"],
|
trigger: [":3"],
|
||||||
response: "uwu!",
|
response: ":3",
|
||||||
priority: 0,
|
priority: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import {Fetcher} from "openapi-typescript-fetch"
|
import {Fetcher} from "openapi-typescript-fetch"
|
||||||
import type {paths} from "../api/schema"
|
import type {paths} from "../api/schema"
|
||||||
|
import type {ui} from "../i18n/ui.ts"
|
||||||
|
|
||||||
const fetcher = Fetcher.for<paths>()
|
const fetcher = Fetcher.for<paths>()
|
||||||
|
|
||||||
|
|
@ -25,7 +26,7 @@ export type AuthType = {
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
lang: string;
|
lang: keyof typeof ui;
|
||||||
doors: Array<DoorType>;
|
doors: Array<DoorType>;
|
||||||
auth: AuthType;
|
auth: AuthType;
|
||||||
doorAction: (action: 'unlock' | 'lock', doorId: string) => void;
|
doorAction: (action: 'unlock' | 'lock', doorId: string) => void;
|
||||||
|
|
@ -160,6 +161,9 @@ async function fetchDoors() {
|
||||||
jammed: door.status.is_error_jammed,
|
jammed: door.status.is_error_jammed,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
loading.doors = false
|
||||||
|
refresh()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// check which operation threw the exception
|
// check which operation threw the exception
|
||||||
if (e instanceof getDoors.Error) {
|
if (e instanceof getDoors.Error) {
|
||||||
|
|
@ -167,6 +171,8 @@ async function fetchDoors() {
|
||||||
|
|
||||||
if (error.status === 401) {
|
if (error.status === 401) {
|
||||||
console.log("unauthorized")
|
console.log("unauthorized")
|
||||||
|
loading.doors = false
|
||||||
|
refresh()
|
||||||
} else if (error.status >= 500 && error.status < 600) {
|
} else if (error.status >= 500 && error.status < 600) {
|
||||||
apiError.current = "serverError"
|
apiError.current = "serverError"
|
||||||
clearInterval(doorsInterval)
|
clearInterval(doorsInterval)
|
||||||
|
|
@ -181,9 +187,6 @@ async function fetchDoors() {
|
||||||
apiError.current = "networkError"
|
apiError.current = "networkError"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
loading.doors = false
|
|
||||||
refresh()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ export const ui = {
|
||||||
"networkError.title": "Network error",
|
"networkError.title": "Network error",
|
||||||
"networkError.description": `Please check your network connection.`,
|
"networkError.description": `Please check your network connection.`,
|
||||||
"loadingDoors": 'Loading doors',
|
"loadingDoors": 'Loading doors',
|
||||||
|
"chat.dooris": "DOORIS",
|
||||||
|
"chat.user": "You",
|
||||||
},
|
},
|
||||||
de: {
|
de: {
|
||||||
"dooris": "TüRIS <span class='text-neutral-content/50 text-xs'>(DOORIS)</span>",
|
"dooris": "TüRIS <span class='text-neutral-content/50 text-xs'>(DOORIS)</span>",
|
||||||
|
|
@ -61,6 +63,8 @@ export const ui = {
|
||||||
"networkError.title": "Netzwerkfehler",
|
"networkError.title": "Netzwerkfehler",
|
||||||
"networkError.description": `Bitte überprüfe deine Internetverbindung.`,
|
"networkError.description": `Bitte überprüfe deine Internetverbindung.`,
|
||||||
"loadingDoors": 'Lade Türen',
|
"loadingDoors": 'Lade Türen',
|
||||||
|
"chat.dooris": "TüRIS",
|
||||||
|
"chat.user": "Du",
|
||||||
},
|
},
|
||||||
uwu: {
|
uwu: {
|
||||||
"dooris": "uwu <span class='opacity-50 text-xs'>(DOORIS)</span>",
|
"dooris": "uwu <span class='opacity-50 text-xs'>(DOORIS)</span>",
|
||||||
|
|
@ -89,5 +93,7 @@ export const ui = {
|
||||||
"networkError.title": "network is not worky",
|
"networkError.title": "network is not worky",
|
||||||
"networkError.description": `pwease connect to internet`,
|
"networkError.description": `pwease connect to internet`,
|
||||||
"loadingDoors": 'loading portals',
|
"loadingDoors": 'loading portals',
|
||||||
|
"chat.dooris": "uwu",
|
||||||
|
"chat.user": "my fren :3",
|
||||||
},
|
},
|
||||||
} as const
|
} as const
|
||||||
|
|
@ -6,10 +6,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.shimmer {
|
.shimmer {
|
||||||
background-image: linear-gradient(60deg, transparent 30%, rgba(100%,100%,100%,0.2) 50%, transparent 70%);
|
background-image: linear-gradient(60deg, transparent 30%, rgba(100%, 100%, 100%, 0.2) 50%, transparent 70%);
|
||||||
background-size: 300%;
|
background-size: 300%;
|
||||||
background-position-x: 100%;
|
background-position-x: 100%;
|
||||||
animation: shimmer 2s infinite linear;
|
animation: shimmer 2s infinite linear;
|
||||||
|
box-shadow: var(--color-primary) 0 0 1em 0.2em;
|
||||||
|
border-end-start-radius: var(--radius-field);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shimmer::before {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes shimmer {
|
@keyframes shimmer {
|
||||||
|
|
@ -17,3 +23,28 @@
|
||||||
background-position-x: 0;
|
background-position-x: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chat-start:has( + .chat-start:not(.hidden)) {
|
||||||
|
padding-bottom: 0.1rem;
|
||||||
|
|
||||||
|
> .chat-image {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .chat-bubble {
|
||||||
|
border-end-start-radius: var(--radius-field);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .chat-bubble::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + .chat-start {
|
||||||
|
padding-top: 0.1rem;
|
||||||
|
|
||||||
|
> .chat-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue