implement styling refactor + fixes

This commit is contained in:
2026-04-15 14:22:08 +02:00
parent feaa2e42c4
commit 1d59aff09b
4 changed files with 97 additions and 72 deletions
-4
View File
@@ -48,7 +48,6 @@ const contextPopover = $("contextPopover");
const contextSummaryLabel = $("contextSummaryLabel"); const contextSummaryLabel = $("contextSummaryLabel");
const chatActionsMenuButton = $("chatActionsMenuButton"); const chatActionsMenuButton = $("chatActionsMenuButton");
const chatActionsPopover = $("chatActionsPopover"); const chatActionsPopover = $("chatActionsPopover");
const chatModePill = $("chatModePill");
const chatCharacterPill = $("chatCharacterPill"); const chatCharacterPill = $("chatCharacterPill");
const chatUserPersonaPill = $("chatUserPersonaPill"); const chatUserPersonaPill = $("chatUserPersonaPill");
const personaList = $("personaList"); const personaList = $("personaList");
@@ -96,7 +95,6 @@ const popupDescription = $("popupDescription");
const popupField = $("popupField"); const popupField = $("popupField");
const popupInputLabel = $("popupInputLabel"); const popupInputLabel = $("popupInputLabel");
const popupInput = $("popupInput"); const popupInput = $("popupInput");
const appNotice = $("appNotice");
const onboardingModal = $("onboardingModal"); const onboardingModal = $("onboardingModal");
const onboardingTitle = $("onboardingTitle"); const onboardingTitle = $("onboardingTitle");
const onboardingSubtitle = $("onboardingSubtitle"); const onboardingSubtitle = $("onboardingSubtitle");
@@ -116,7 +114,6 @@ export {
activeChatTitle, activeChatTitle,
activePersonaStatus, activePersonaStatus,
activeUserPersonaStatus, activeUserPersonaStatus,
appNotice,
authDiv, authDiv,
authMsg, authMsg,
authScreens, authScreens,
@@ -133,7 +130,6 @@ export {
chatListLoadingText, chatListLoadingText,
chatSidebar, chatSidebar,
chatDrawerCloseBtn, chatDrawerCloseBtn,
chatModePill,
chatSearchInput, chatSearchInput,
chatUserPersonaPill, chatUserPersonaPill,
clearChatBtn, clearChatBtn,
+2 -12
View File
@@ -14,17 +14,12 @@
<section id="auth" class="card auth-card auth-card-compact"> <section id="auth" class="card auth-card auth-card-compact">
<div class="auth-hero auth-hero-compact"> <div class="auth-hero auth-hero-compact">
<div class="brand"> <div class="brand">
<div class="logo" data-theme-logo>FG</div> <div class="logo logo-placeholder" aria-hidden="true"></div>
<div> <div>
<p class="eyebrow">Private workspace</p> <p class="eyebrow">Private workspace</p>
<h1 data-theme-name>FakeGPT</h1> <h1 data-theme-name>FakeGPT</h1>
</div> </div>
</div> </div>
<div class="hero-grid">
<article class="hero-panel">
<p>Private chat and roleplay.</p>
</article>
</div>
</div> </div>
<div class="auth-panel"> <div class="auth-panel">
@@ -110,9 +105,6 @@
<div class="chat-title-block"> <div class="chat-title-block">
<div class="chat-title"> <div class="chat-title">
<h2 id="activeChatTitle">New chat</h2> <h2 id="activeChatTitle">New chat</h2>
<div id="chatParticipants" class="chat-participants chat-participants-inline">
<span id="chatModePill" class="context-pill chat-mode-pill">Assistant mode</span>
</div>
</div> </div>
</div> </div>
<div class="chat-header-actions"> <div class="chat-header-actions">
@@ -216,8 +208,6 @@
</div> </div>
</header> </header>
<p id="appNotice" class="status inline-status hidden"></p>
<div id="chatActivityOverlay" class="chat-activity-overlay hidden" role="status" aria-live="polite" aria-atomic="true"> <div id="chatActivityOverlay" class="chat-activity-overlay hidden" role="status" aria-live="polite" aria-atomic="true">
<div class="chat-activity-card"> <div class="chat-activity-card">
<div class="chat-activity-mark" aria-hidden="true"> <div class="chat-activity-mark" aria-hidden="true">
@@ -238,7 +228,7 @@
<p class="composer-hint">Enter to send · Shift+Enter for new line</p> <p class="composer-hint">Enter to send · Shift+Enter for new line</p>
</div> </div>
<div class="input-container"> <div class="input-container">
<textarea id="msgInput" placeholder="Type your message..."></textarea> <textarea id="msgInput" rows="1" placeholder="Type your message..."></textarea>
<button id="send" type="button" aria-label="Send message"></button> <button id="send" type="button" aria-label="Send message"></button>
</div> </div>
</div> </div>
+22 -29
View File
@@ -4,7 +4,6 @@ import {
activeChatTitle, activeChatTitle,
activePersonaStatus, activePersonaStatus,
activeUserPersonaStatus, activeUserPersonaStatus,
appNotice,
authDiv, authDiv,
authMsg, authMsg,
authScreens, authScreens,
@@ -21,7 +20,6 @@ import {
chatListLoadingText, chatListLoadingText,
chatSidebar, chatSidebar,
chatDrawerCloseBtn, chatDrawerCloseBtn,
chatModePill,
chatSearchInput, chatSearchInput,
chatUserPersonaPill, chatUserPersonaPill,
clearChatBtn, clearChatBtn,
@@ -119,7 +117,6 @@ let activeUserPersonaId = null, currentSummary = null, publishedPersonaIds = new
let popupResolver = null, popupMode = null, popupLastFocus = null; let popupResolver = null, popupMode = null, popupLastFocus = null;
let roleplayPresetCharacterId = null; let roleplayPresetCharacterId = null;
let roleplayStarterStep = 1; let roleplayStarterStep = 1;
let noticeTimer = null;
let workspaceMode = localStorage.getItem("krishd-workspace-mode") || "basic"; let workspaceMode = localStorage.getItem("krishd-workspace-mode") || "basic";
let onboardingStep = 1, onboardingIntent = "ask"; let onboardingStep = 1, onboardingIntent = "ask";
let chatLoadingDepth = 0; let chatLoadingDepth = 0;
@@ -129,24 +126,6 @@ let messageRetryState = new Map();
function setAuthMessage(message, state = "") { authMsg.textContent = message; authMsg.className = state ? `status ${state}` : "status"; } function setAuthMessage(message, state = "") { authMsg.textContent = message; authMsg.className = state ? `status ${state}` : "status"; }
function setNotice(message = "", state = "") { function setNotice(message = "", state = "") {
if (!appNotice) return {message, state};
if (noticeTimer) {
clearTimeout(noticeTimer);
noticeTimer = null;
}
if (!message) {
appNotice.textContent = "";
appNotice.className = "status inline-status hidden";
return {message, state};
}
appNotice.textContent = message;
appNotice.className = state ? `status inline-status ${state}` : "status inline-status";
noticeTimer = window.setTimeout(() => {
if (appNotice.textContent === message) {
appNotice.textContent = "";
appNotice.className = "status inline-status hidden";
}
}, state === "error" ? 6000 : 3200);
return {message, state}; return {message, state};
} }
function setPersonaFormNotice(message = "", state = "") { function setPersonaFormNotice(message = "", state = "") {
@@ -351,6 +330,18 @@ function updateSendState() {
sendBtn.disabled = isProcessing || !hasText; sendBtn.disabled = isProcessing || !hasText;
} }
function resizeComposerInput() {
msgInput.style.height = "auto";
const nextHeight = Math.min(Math.max(msgInput.scrollHeight, 46), 96);
msgInput.style.height = `${nextHeight}px`;
}
function scrollMessagesToBottom() {
requestAnimationFrame(() => {
messagesDiv.scrollTop = messagesDiv.scrollHeight;
});
}
function getNewestMessage() { function getNewestMessage() {
return currentMessages.length ? currentMessages[currentMessages.length - 1] : null; return currentMessages.length ? currentMessages[currentMessages.length - 1] : null;
} }
@@ -652,7 +643,7 @@ function addMessage(contentOrMessage, isUser = false, isLoading = false, options
} }
} }
messagesDiv.appendChild(msgDiv); messagesDiv.appendChild(msgDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight; scrollMessagesToBottom();
return msgDiv; return msgDiv;
} }
@@ -670,6 +661,9 @@ function renderMessages() {
updateChatParticipants(); updateChatParticipants();
updateChatActionState(); updateChatActionState();
updateComposerPlaceholder(); updateComposerPlaceholder();
if (currentMessages.length) {
scrollMessagesToBottom();
}
} }
function createStarterAction(label, className, handler) { function createStarterAction(label, className, handler) {
@@ -778,16 +772,14 @@ function renderRoleplayStarterStep() {
function updateChatParticipants() { function updateChatParticipants() {
const chat = getChatById(activeChatId); const chat = getChatById(activeChatId);
if (!chatModePill || !chatCharacterPill || !chatUserPersonaPill) return; if (!chatCharacterPill || !chatUserPersonaPill) return;
if (!chat) { if (!chat) {
chatModePill.textContent = "No chat selected";
chatCharacterPill.classList.add("hidden"); chatCharacterPill.classList.add("hidden");
chatUserPersonaPill.classList.add("hidden"); chatUserPersonaPill.classList.add("hidden");
if (contextSummaryLabel) contextSummaryLabel.textContent = "None"; if (contextSummaryLabel) contextSummaryLabel.textContent = "None";
return; return;
} }
if (chat.assistant_persona_id) { if (chat.assistant_persona_id) {
chatModePill.textContent = "Roleplay mode";
chatCharacterPill.textContent = `Character: ${chat.assistant_persona_name || chat.title}`; chatCharacterPill.textContent = `Character: ${chat.assistant_persona_name || chat.title}`;
chatCharacterPill.classList.remove("hidden"); chatCharacterPill.classList.remove("hidden");
if (chat.user_persona_id) { if (chat.user_persona_id) {
@@ -800,7 +792,6 @@ function updateChatParticipants() {
if (contextSummaryLabel) contextSummaryLabel.textContent = chat.assistant_persona_name || "Roleplay"; if (contextSummaryLabel) contextSummaryLabel.textContent = chat.assistant_persona_name || "Roleplay";
return; return;
} }
chatModePill.textContent = "Assistant mode";
chatCharacterPill.classList.add("hidden"); chatCharacterPill.classList.add("hidden");
chatUserPersonaPill.classList.add("hidden"); chatUserPersonaPill.classList.add("hidden");
if (contextSummaryLabel) contextSummaryLabel.textContent = "Assistant"; if (contextSummaryLabel) contextSummaryLabel.textContent = "Assistant";
@@ -1598,7 +1589,9 @@ async function sendMessage() {
currentChat.title = autoTitle; updateWorkspaceCopy(); renderChatList(); await put(`/chats/${activeChatId}`, {title: autoTitle}); currentChat.title = autoTitle; updateWorkspaceCopy(); renderChatList(); await put(`/chats/${activeChatId}`, {title: autoTitle});
} }
currentMessages.push({role: "user", content: message}); addMessage(message, true); updateChatActionState(); currentMessages.push({role: "user", content: message}); addMessage(message, true); updateChatActionState();
msgInput.value = ""; msgInput.style.height = "auto"; setLoadingState(true, { msgInput.value = "";
resizeComposerInput();
setLoadingState(true, {
eyebrow: "Assistant replying", eyebrow: "Assistant replying",
title: "Generating response", title: "Generating response",
detail: "The assistant is reading your message and preparing a reply." detail: "The assistant is reading your message and preparing a reply."
@@ -1695,10 +1688,10 @@ logoutButton.addEventListener("click", async () => {
sendBtn.addEventListener("click", () => { void sendMessage(); }); sendBtn.addEventListener("click", () => { void sendMessage(); });
msgInput.addEventListener("keydown", (event) => { if (event.key === "Enter" && !event.shiftKey) { event.preventDefault(); void sendMessage(); } }); msgInput.addEventListener("keydown", (event) => { if (event.key === "Enter" && !event.shiftKey) { event.preventDefault(); void sendMessage(); } });
msgInput.addEventListener("input", function () { msgInput.addEventListener("input", function () {
this.style.height = "auto"; resizeComposerInput();
this.style.height = `${Math.min(this.scrollHeight, 180)}px`;
updateSendState(); updateSendState();
}); });
resizeComposerInput();
newChatBtn.addEventListener("click", () => { newChatBtn.addEventListener("click", () => {
closeChatActionsPopover(); closeChatActionsPopover();
closeMobileSidebar(); closeMobileSidebar();
+73 -27
View File
@@ -579,6 +579,35 @@ body::before {
box-shadow: none; box-shadow: none;
} }
.logo-placeholder {
position: relative;
color: transparent;
}
.logo-placeholder::before,
.logo-placeholder::after {
content: "";
position: absolute;
border-radius: 999px;
background: rgba(255, 248, 240, 0.94);
}
.logo-placeholder::before {
width: 10px;
height: 10px;
top: 14px;
left: 14px;
box-shadow: 16px 0 0 rgba(255, 248, 240, 0.94);
}
.logo-placeholder::after {
width: 24px;
height: 6px;
left: 15px;
bottom: 15px;
opacity: 0.9;
}
.eyebrow { .eyebrow {
margin: 0; margin: 0;
font-size: 0.73rem; font-size: 0.73rem;
@@ -614,6 +643,11 @@ h2 {
line-height: 1.6; line-height: 1.6;
} }
.composer-hint {
font-size: 0.84rem;
line-height: 1.3;
}
.hero-grid { .hero-grid {
display: grid; display: grid;
gap: 14px; gap: 14px;
@@ -1095,7 +1129,7 @@ select:focus {
} }
.chat-main-focus { .chat-main-focus {
grid-template-rows: auto minmax(0, 1fr) auto auto; grid-template-rows: auto minmax(0, 1fr) auto;
min-height: 0; min-height: 0;
} }
@@ -1708,35 +1742,40 @@ select:focus {
.input-shell { .input-shell {
display: grid; display: grid;
gap: 12px; gap: 8px;
align-self: end;
} }
.input-meta { .input-meta {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
gap: 12px; gap: 8px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.input-container { .input-container {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) 56px; grid-template-columns: minmax(0, 1fr) 48px;
gap: 12px; gap: 10px;
align-items: stretch; align-items: end;
} }
#msgInput { #msgInput {
min-height: 56px; height: 46px;
max-height: 180px; min-height: 46px;
max-height: 96px;
padding: 11px 12px;
line-height: 1.35;
} }
#send { #send {
width: 56px; width: 48px;
height: auto; height: 46px;
min-height: 56px; min-height: 46px;
padding: 0; padding: 0;
border-radius: 18px; border-radius: 16px;
align-self: end;
} }
#send::after { #send::after {
@@ -2979,7 +3018,7 @@ body[data-theme="beta-ai"] .persona-form .field {
} }
.chat-main-focus { .chat-main-focus {
grid-template-rows: auto minmax(300px, 1fr) auto auto; grid-template-rows: auto minmax(300px, 1fr) auto;
} }
.input-container { .input-container {
@@ -3439,7 +3478,7 @@ body[data-theme="beta-ai"] .persona-form .field {
.input-shell, .input-shell,
.input-shell-focus { .input-shell-focus {
padding: 16px 18px 18px; padding: 10px 14px 12px;
position: sticky; position: sticky;
bottom: 0; bottom: 0;
background: var(--composer-bg); background: var(--composer-bg);
@@ -3450,7 +3489,7 @@ body[data-theme="beta-ai"] .persona-form .field {
} }
#msgInput { #msgInput {
min-height: 72px; min-height: 42px;
} }
.chat-list { .chat-list {
@@ -3888,7 +3927,7 @@ body[data-theme="beta-ai"] .persona-form .field {
.chat-main, .chat-main,
.chat-main-focus { .chat-main-focus {
display: grid; display: grid;
grid-template-rows: auto auto minmax(0, 1fr) auto; grid-template-rows: auto minmax(0, 1fr) auto;
min-height: 0; min-height: 0;
gap: 12px; gap: 12px;
} }
@@ -3929,7 +3968,7 @@ body[data-theme="beta-ai"] .persona-form .field {
.messages-panel, .messages-panel,
.messages-panel-focus { .messages-panel-focus {
min-height: 0; min-height: 0;
padding: 10px 4px 0; padding: 10px 4px 18px;
background: transparent; background: transparent;
border: 0; border: 0;
border-radius: 0; border-radius: 0;
@@ -3955,12 +3994,12 @@ body[data-theme="beta-ai"] .persona-form .field {
.input-shell-focus { .input-shell-focus {
position: sticky; position: sticky;
bottom: 0; bottom: 0;
padding: 14px 16px 16px; align-self: end;
margin-top: -4px; padding: 10px 14px 12px;
margin-top: -2px;
background: linear-gradient(180deg, rgba(255, 255, 255, 0), var(--composer-bg) 18%); background: linear-gradient(180deg, rgba(255, 255, 255, 0), var(--composer-bg) 18%);
border: 0; border: 1px solid var(--line);
border-top: 1px solid var(--line); border-radius: 10;
border-radius: 0;
box-shadow: none; box-shadow: none;
backdrop-filter: blur(12px); backdrop-filter: blur(12px);
} }
@@ -3974,13 +4013,18 @@ body[data-theme="beta-ai"] .persona-form .field {
.input-meta { .input-meta {
width: 100%; width: 100%;
max-width: 980px; max-width: 980px;
margin: 0 auto 8px; margin: 0 auto 4px;
}
.messages-panel-focus + .input-shell-focus {
min-height: fit-content;
} }
#msgInput { #msgInput {
width: 100%; width: 100%;
min-width: 0; min-width: 0;
min-height: 144px; height: 46px;
min-height: 46px;
} }
.chat-drawer { .chat-drawer {
@@ -4192,7 +4236,8 @@ body.sidebar-open {
} }
#msgInput { #msgInput {
min-height: 132px; min-height: 46px;
height: 46px;
} }
.msg { .msg {
@@ -4262,11 +4307,12 @@ body.sidebar-open {
.input-shell, .input-shell,
.input-shell-focus { .input-shell-focus {
padding: 10px 12px calc(12px + env(safe-area-inset-bottom, 0px)); padding: 8px 10px calc(10px + env(safe-area-inset-bottom, 0px));
} }
#msgInput { #msgInput {
min-height: 120px; min-height: 44px;
height: 44px;
} }
.chat-drawer, .chat-drawer,