feat(chat): add conversation UI and icon
This commit is contained in:
@@ -2,6 +2,7 @@ import { API_BASE_URL } from "@config/config_frontend";
|
||||
|
||||
type Source = { path: string; excerpt: string };
|
||||
type ChatAnswer = { answer: string; sources: Source[]; detail?: string };
|
||||
const chatIcon = `<svg viewBox="0 0 32 32" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 5h16a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H13l-7 4v-5a5 5 0 0 1-3-4V10a5 5 0 0 1 5-5Z"/><path d="M11 19c0-5 4-8 10-8 0 6-3 10-8 10"/><path d="M11 22c2-3 5-5 9-7"/></svg>`;
|
||||
|
||||
export function buildKnowledgeChat(): HTMLElement {
|
||||
const wrap = document.createElement("div");
|
||||
@@ -9,25 +10,44 @@ export function buildKnowledgeChat(): HTMLElement {
|
||||
const toggle = document.createElement("button");
|
||||
toggle.type = "button";
|
||||
toggle.className = "b01-knowledge-chat__toggle";
|
||||
toggle.textContent = "원문 안내";
|
||||
toggle.innerHTML = chatIcon;
|
||||
toggle.setAttribute("aria-label", "챗봇 열기");
|
||||
toggle.title = "챗봇";
|
||||
toggle.setAttribute("aria-expanded", "false");
|
||||
const panel = document.createElement("section");
|
||||
panel.className = "b01-knowledge-chat__panel";
|
||||
panel.hidden = true;
|
||||
panel.setAttribute("aria-label", "지식DB 원문 안내 채팅");
|
||||
panel.id = "b01-knowledge-chat-panel";
|
||||
panel.setAttribute("aria-label", "챗봇");
|
||||
toggle.setAttribute("aria-controls", panel.id);
|
||||
const header = document.createElement("header");
|
||||
header.textContent = "지식DB 원문 안내";
|
||||
const avatar = document.createElement("span");
|
||||
avatar.className = "b01-knowledge-chat__avatar";
|
||||
avatar.innerHTML = chatIcon;
|
||||
const title = document.createElement("strong");
|
||||
title.textContent = "챗봇";
|
||||
const close = document.createElement("button");
|
||||
close.type = "button";
|
||||
close.className = "b01-knowledge-chat__close";
|
||||
close.textContent = "×";
|
||||
close.setAttribute("aria-label", "챗봇 닫기");
|
||||
header.append(avatar, title, close);
|
||||
const messages = document.createElement("div");
|
||||
messages.className = "b01-knowledge-chat__messages";
|
||||
messages.setAttribute("role", "log");
|
||||
messages.setAttribute("aria-live", "polite");
|
||||
const welcome = document.createElement("p");
|
||||
welcome.className = "b01-knowledge-chat__reply";
|
||||
welcome.textContent =
|
||||
"안녕하세요! 법령이나 지침에 대해 질문해 주세요. 근거 문서도 함께 보여드릴게요.";
|
||||
messages.append(welcome);
|
||||
const form = document.createElement("form");
|
||||
form.className = "b01-knowledge-chat__form";
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.required = true;
|
||||
input.maxLength = 500;
|
||||
input.placeholder = "법령·지침을 질문하세요";
|
||||
input.placeholder = "메시지를 입력하세요";
|
||||
input.setAttribute("aria-label", "질문");
|
||||
const submit = document.createElement("button");
|
||||
submit.type = "submit";
|
||||
@@ -36,11 +56,15 @@ export function buildKnowledgeChat(): HTMLElement {
|
||||
panel.append(header, messages, form);
|
||||
wrap.append(toggle, panel);
|
||||
|
||||
toggle.addEventListener("click", () => {
|
||||
panel.hidden = !panel.hidden;
|
||||
const setOpen = (open: boolean): void => {
|
||||
panel.hidden = !open;
|
||||
toggle.setAttribute("aria-expanded", String(!panel.hidden));
|
||||
if (!panel.hidden) input.focus();
|
||||
});
|
||||
toggle.setAttribute("aria-label", open ? "챗봇 닫기" : "챗봇 열기");
|
||||
if (open) input.focus();
|
||||
else toggle.focus();
|
||||
};
|
||||
toggle.addEventListener("click", () => setOpen(Boolean(panel.hidden)));
|
||||
close.addEventListener("click", () => setOpen(false));
|
||||
|
||||
form.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -535,16 +535,30 @@
|
||||
|
||||
.b01-knowledge-chat__toggle,
|
||||
.b01-knowledge-chat__form button {
|
||||
padding: 10px 16px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
background: var(--color-royal-amethyst, #6843a7);
|
||||
color: #fff;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__toggle {
|
||||
display: grid;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
place-items: center;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 4px 16px #0004;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__toggle svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: min(380px, calc(100vw - 32px));
|
||||
height: min(540px, calc(100vh - 104px));
|
||||
border: 1px solid var(--color-border);
|
||||
@@ -560,34 +574,76 @@
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__panel header {
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__avatar {
|
||||
display: grid;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
place-items: center;
|
||||
border-radius: 50%;
|
||||
background: var(--color-royal-amethyst, #6843a7);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__avatar svg {
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__close {
|
||||
margin-left: auto;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
font-size: 26px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__messages {
|
||||
height: calc(100% - 106px);
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
padding: 16px 12px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__user,
|
||||
.b01-knowledge-chat__reply {
|
||||
margin: 0 0 12px;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
max-width: 88%;
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 14px;
|
||||
overflow-wrap: anywhere;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__user {
|
||||
align-self: flex-end;
|
||||
border-bottom-right-radius: 4px;
|
||||
background: var(--color-royal-amethyst, #6843a7);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__reply {
|
||||
align-self: flex-start;
|
||||
border-bottom-left-radius: 4px;
|
||||
background: var(--color-background, #f4f4f4);
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__reply details {
|
||||
margin-top: 8px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__reply summary {
|
||||
cursor: pointer;
|
||||
overflow-wrap: anywhere;
|
||||
@@ -602,6 +658,7 @@
|
||||
|
||||
.b01-knowledge-chat__form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
border-top: 1px solid var(--color-border);
|
||||
@@ -615,3 +672,14 @@
|
||||
border-radius: 6px;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat__form button {
|
||||
padding: 9px 14px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.b01-knowledge-chat button:focus-visible,
|
||||
.b01-knowledge-chat input:focus-visible {
|
||||
outline: 2px solid var(--color-royal-amethyst, #6843a7);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user