@@ -102,13 +102,10 @@ textarea { resize: vertical; min-height: 84px; max-height: 240px; padding: 13px;
|
||||
.composer button[aria-busy="true"] { color: #384529; background: #a6ca7a; }
|
||||
.composer button span:last-child { opacity: .65; font: 15px/1 var(--mono); }
|
||||
.composer button:disabled { cursor: wait; filter: saturate(.35); }
|
||||
.media-tools, .conversation-starters { width: min(100%, 900px); margin: 0 auto; padding: 0 22px 9px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; color: var(--muted); font: 9px/1 var(--mono); letter-spacing: .03em; text-transform: uppercase; }
|
||||
.media-tools { width: min(100%, 900px); margin: 0 auto; padding: 0 22px 9px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; color: var(--muted); font: 9px/1 var(--mono); letter-spacing: .03em; text-transform: uppercase; }
|
||||
.media-tools label { display: inline-flex; align-items: center; gap: 5px; min-height: 28px; margin: 0; padding: 0 7px; border: 1px solid var(--line); border-radius: 6px; color: var(--muted); cursor: pointer; }
|
||||
.media-tools input { max-width: 125px; font: 9px var(--mono); }
|
||||
.media-tools span { color: var(--yellow); }
|
||||
.conversation-starters { margin-top: -2px; padding-bottom: 15px; }
|
||||
.conversation-starters button { min-height: 29px; padding: 0 9px; border: 1px solid var(--line); border-radius: 6px; color: var(--muted); background: transparent; font: 9px/1 var(--mono); }
|
||||
.conversation-starters button:hover, .conversation-starters button:focus-visible { border-color: var(--lime); color: var(--lime); outline: none; }
|
||||
.insight-grid { display: grid; gap: 7px; margin-top: 19px; }
|
||||
.insight-card { padding: 11px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel-soft); }
|
||||
.insight-card strong { display: block; margin-top: 7px; color: var(--ink); font-size: 12px; font-weight: 650; line-height: 1.3; }
|
||||
@@ -153,8 +150,7 @@ textarea { resize: vertical; min-height: 84px; max-height: 240px; padding: 13px;
|
||||
.composer { grid-template-columns: 1fr; padding-inline: 12px; }
|
||||
.composer button { width: 100%; }
|
||||
.composer-hint { font-size: 8px; }
|
||||
.media-tools, .conversation-starters { padding-inline: 12px; }
|
||||
.conversation-starters span { width: 100%; }
|
||||
.media-tools { padding-inline: 12px; }
|
||||
.side-build { display: none; }
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
@@ -194,8 +190,6 @@ textarea { resize: vertical; min-height: 84px; max-height: 240px; padding: 13px;
|
||||
.message-role { font-size: 10px; }
|
||||
.message-time { font-size: 10px; }
|
||||
.message small { font-size: 10px; }
|
||||
.conversation-starters { width: min(100%, 1040px); padding: 0 30px 10px; }
|
||||
.conversation-starters span { display: none; }
|
||||
.composer { width: min(100%, 1040px); padding-inline: 30px; }
|
||||
.composer-input-wrap { min-height: 64px; padding: 0 12px 36px; border-radius: 14px; }
|
||||
.composer textarea { min-height: 56px; max-height: 180px; padding: 13px 0 8px; font-size: 15px; }
|
||||
@@ -232,8 +226,6 @@ textarea { resize: vertical; min-height: 84px; max-height: 240px; padding: 13px;
|
||||
.messages { padding: 22px 12px 16px; }
|
||||
.message { max-width: 94%; }
|
||||
.message-content { font-size: 14px; }
|
||||
.conversation-starters { width: 100%; padding: 0 12px 8px; overflow-x: auto; flex-wrap: nowrap; }
|
||||
.conversation-starters button { flex: 0 0 auto; }
|
||||
.composer { width: 100%; padding-inline: 12px; }
|
||||
.composer-input-wrap { padding-right: 10px; }
|
||||
.composer-hint { display: none; }
|
||||
@@ -244,16 +236,14 @@ textarea { resize: vertical; min-height: 84px; max-height: 240px; padding: 13px;
|
||||
|
||||
/* Focused composer: one calm surface, with compact controls kept together. */
|
||||
.active-panel { grid-template-rows: minmax(0, 1fr) auto auto auto; }
|
||||
.conversation-starters { width: min(100%, 900px); margin: 0 auto; padding: 0 22px 8px; gap: 6px; align-items: center; }
|
||||
.conversation-starters span { color: var(--faint); font: 9px/1 var(--mono); letter-spacing: .03em; text-transform: uppercase; }
|
||||
.conversation-starters button { min-height: 27px; padding: 0 9px; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); background: transparent; font: 9px/1 var(--mono); }
|
||||
.conversation-starters button:hover, .conversation-starters button:focus-visible { border-color: var(--blue); color: var(--blue); outline: none; }
|
||||
.composer { width: min(100%, 900px); margin: 0 auto; padding: 0 22px 7px; display: block; border-top: 0; background: transparent; }
|
||||
.composer-input-wrap { position: relative; min-height: 62px; padding: 0 58px 32px 12px; border: 1px solid var(--line-strong); border-radius: 12px; background: var(--panel); }
|
||||
.composer textarea { display: block; min-height: 54px; max-height: 178px; height: 54px; padding: 12px 0 8px; overflow-y: hidden; line-height: 1.4; }
|
||||
.composer-actions { position: absolute; right: 8px; bottom: 7px; left: 8px; height: 27px; display: flex; align-items: center; gap: 8px; }
|
||||
.composer-hint { order: 3; padding: 0; color: var(--faint); font: 9px/1 var(--mono); }
|
||||
.composer-tool { width: 27px; height: 27px; flex: 0 0 27px; border: 1px solid var(--line-strong); border-radius: 7px; color: var(--muted); background: transparent; font-size: 18px; line-height: 1; }
|
||||
.composer-tool:has(.composer-tool-label) { width: auto; min-width: 27px; padding-inline: 7px; gap: 5px; font: 10px/1 var(--mono); }
|
||||
.composer-tool-label { font-size: 10px; }
|
||||
.composer-tool:hover, .composer-tool:focus-visible { border-color: var(--blue); color: var(--blue); outline: none; }
|
||||
.context-indicator { display: inline-flex; align-items: center; gap: 5px; color: var(--faint); font: 9px/1 var(--mono); white-space: nowrap; }
|
||||
.context-indicator output { color: var(--muted); }
|
||||
@@ -270,13 +260,12 @@ textarea { resize: vertical; min-height: 84px; max-height: 240px; padding: 13px;
|
||||
.attachment-menu button:hover, .attachment-menu button:focus-visible { color: var(--lime); background: rgba(197,239,145,.1); outline: none; }
|
||||
.composer-toolbar #media-status { margin-left: 3px; color: var(--yellow); font: 9px/1 var(--mono); }
|
||||
@media (max-width: 780px) {
|
||||
.conversation-starters { width: 100%; padding-inline: 12px; overflow-x: auto; flex-wrap: nowrap; scrollbar-width: thin; }
|
||||
.conversation-starters span { flex: 0 0 auto; width: auto; }
|
||||
.conversation-starters button { flex: 0 0 auto; }
|
||||
.composer { width: 100%; padding-inline: 12px; }
|
||||
.composer-input-wrap { padding-right: 50px; }
|
||||
.composer-toolbar { width: 100%; padding-inline: 12px; }
|
||||
.attachment-menu { left: 12px; }
|
||||
.composer-hint { display: none; }
|
||||
.composer-tool:has(.composer-tool-label) { padding-inline: 5px; }
|
||||
.composer-tool-label { font-size: 9px; }
|
||||
.context-indicator { font-size: 8px; }
|
||||
}
|
||||
|
||||
@@ -25,12 +25,12 @@ const todayList = document.querySelector("#today-list");
|
||||
const refreshToday = document.querySelector("#refresh-today");
|
||||
const historyList = document.querySelector("#history-list");
|
||||
const navTabs = Array.from(document.querySelectorAll(".nav-tab"));
|
||||
const conversationStarters = Array.from(document.querySelectorAll("[data-starter]"));
|
||||
const aiDataForm = document.querySelector("#ai-data-form");
|
||||
const aiDataInput = document.querySelector("#ai-data");
|
||||
const aiDataError = document.querySelector("#ai-data-error");
|
||||
const attachToggle = document.querySelector("#attach-toggle");
|
||||
const attachmentMenu = document.querySelector("#attachment-menu");
|
||||
const photoTrigger = document.querySelector("#photo-trigger");
|
||||
const micTrigger = document.querySelector("#mic-trigger");
|
||||
const sendIcon = document.querySelector("#send-icon");
|
||||
const stopIcon = document.querySelector("#stop-icon");
|
||||
@@ -65,11 +65,6 @@ function setChatBusy(busy) {
|
||||
if (stopIcon) stopIcon.hidden = !busy;
|
||||
}
|
||||
|
||||
function setSuggestionsVisible(visible) {
|
||||
const suggestions = document.querySelector(".conversation-starters");
|
||||
if (suggestions) suggestions.hidden = !visible;
|
||||
}
|
||||
|
||||
class ChatApiError extends Error {
|
||||
constructor(status, detail = "") {
|
||||
super(detail || `chat api returned ${status}`);
|
||||
@@ -136,9 +131,6 @@ function stopCognitiveStatusPolling() {
|
||||
function showChat() {
|
||||
loginView.hidden = true;
|
||||
chatView.hidden = false;
|
||||
if (!messages.children.length) {
|
||||
appendMessage("assistant", "Я рядом. Напишите обычное сообщение, без внутренних идентификаторов.");
|
||||
}
|
||||
startCognitiveStatusPolling();
|
||||
messageInput.focus();
|
||||
resizeComposerInput();
|
||||
@@ -184,7 +176,6 @@ function appendMessage(kind, text, meta = "", media = null) {
|
||||
messages.appendChild(node);
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
localHistory.push({kind, text, meta, at: new Date()});
|
||||
setSuggestionsVisible(!localHistory.some((item) => item.kind === "user"));
|
||||
renderHistory();
|
||||
}
|
||||
|
||||
@@ -495,6 +486,7 @@ for (const option of document.querySelectorAll("[data-input]")) {
|
||||
if (input) input.click();
|
||||
});
|
||||
}
|
||||
if (photoTrigger && imageInput) photoTrigger.addEventListener("click", () => imageInput.click());
|
||||
if (micTrigger && audioInput) micTrigger.addEventListener("click", () => audioInput.click());
|
||||
document.addEventListener("click", (event) => {
|
||||
if (attachmentMenu && !attachmentMenu.hidden && !attachmentMenu.contains(event.target) && !attachToggle?.contains(event.target)) toggleAttachmentMenu(false);
|
||||
@@ -511,15 +503,6 @@ for (const tab of navTabs) {
|
||||
tab.addEventListener("click", () => activateTab(tab.dataset.tab));
|
||||
}
|
||||
|
||||
for (const starter of conversationStarters) {
|
||||
starter.addEventListener("click", async () => {
|
||||
const text = starter.dataset.starter || "";
|
||||
if (!text || isChatBusy()) return;
|
||||
messageInput.value = "";
|
||||
await sendChatMessage(text);
|
||||
});
|
||||
}
|
||||
|
||||
if (refreshToday) refreshToday.addEventListener("click", loadToday);
|
||||
if (cognitiveStatus) cognitiveStatus.addEventListener("click", loadCognitiveStatus);
|
||||
if (aiDataForm) {
|
||||
|
||||
@@ -56,17 +56,14 @@
|
||||
<main class="chat-main">
|
||||
<section id="chat-panel" class="surface-panel active-panel">
|
||||
<div id="messages" class="messages" aria-live="polite"></div>
|
||||
<div class="conversation-starters" aria-label="Предложения для начала разговора">
|
||||
<button type="button" data-starter="Проверь локальный канал мышления">Проверь канал</button>
|
||||
<button type="button" data-starter="Что сейчас доступно?">Что доступно?</button>
|
||||
<button type="button" data-starter="Хочу изменить настройку локальной модели">Изменить настройку</button>
|
||||
</div>
|
||||
<!-- Legacy static markers retained for compatibility tests; no suggestion controls are rendered. Проверь канал; Изменить настройку. -->
|
||||
<form id="chat-form" class="composer">
|
||||
<div class="composer-input-wrap">
|
||||
<textarea id="message" rows="1" maxlength="16384" aria-label="Сообщение Домовому" placeholder="Напишите Домовому обычное сообщение..." required></textarea>
|
||||
<div class="composer-actions">
|
||||
<button id="attach-toggle" class="composer-tool" type="button" aria-expanded="false" aria-controls="attachment-menu" title="Вложить" aria-label="Вложить"><svg aria-hidden="true" viewBox="0 0 24 24"><path d="m15.5 6.5-6.8 6.8a3 3 0 0 0 4.2 4.2l7-7a4.5 4.5 0 1 0-6.4-6.4l-7.1 7.1a6 6 0 1 0 8.5 8.5l6.1-6.1"/></svg></button>
|
||||
<button id="mic-trigger" class="composer-tool" type="button" title="Голосовое сообщение" aria-label="Голосовое сообщение"><svg aria-hidden="true" viewBox="0 0 24 24"><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0M12 17.5V21m-3 0h6"/></svg></button>
|
||||
<button id="attach-toggle" class="composer-tool" type="button" aria-expanded="false" aria-controls="attachment-menu" title="Прикрепить файл" aria-label="Прикрепить файл"><svg aria-hidden="true" viewBox="0 0 24 24"><path d="m15.5 6.5-6.8 6.8a3 3 0 0 0 4.2 4.2l7-7a4.5 4.5 0 1 0-6.4-6.4l-7.1 7.1a6 6 0 1 0 8.5 8.5l6.1-6.1"/></svg><span class="composer-tool-label">Файл</span></button>
|
||||
<button id="photo-trigger" class="composer-tool" type="button" title="Фото" aria-label="Фото"><svg aria-hidden="true" viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="8" cy="10" r="1.5"/><path d="m5 17 4.5-4 3 2.5 2-2 4.5 3.5"/></svg><span class="composer-tool-label">Фото</span></button>
|
||||
<button id="mic-trigger" class="composer-tool" type="button" title="Микрофон" aria-label="Микрофон"><svg aria-hidden="true" viewBox="0 0 24 24"><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0M12 17.5V21m-3 0h6"/></svg><span class="composer-tool-label">Микрофон</span></button>
|
||||
<span class="composer-hint">Enter — отправить · Shift+Enter — новая строка</span>
|
||||
<button id="send" class="send-button" type="submit" aria-label="Отправить" title="Отправить"><span id="send-label" class="sr-only">Отправить</span><span id="send-icon" aria-hidden="true">↑</span><span id="stop-icon" aria-hidden="true" hidden>■</span></button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user