Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
KotGPT
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Michael Pastushkov
KotGPT
Commits
a62db13c
Commit
a62db13c
authored
Aug 18, 2025
by
michaelpastushkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix
parent
829e340b
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
9 additions
and
84 deletions
+9
-84
static/www/1.html
+9
-84
No files found.
static/www/1.html
View file @
a62db13c
...
...
@@ -155,41 +155,6 @@
filter
:
drop-shadow
(
0
6px
16px
rgba
(
0
,
0
,
0
,
.15
));
opacity
:
.98
;
}
/* Fixed scroll-to-bottom button (ensures visibility above composer/footer) */
#scrollDownBtn
{
position
:
fixed
;
right
:
1rem
;
bottom
:
calc
(
var
(
--footer-h
)
+
var
(
--composer-h
)
+
1rem
);
z-index
:
1031
;
display
:
none
;
border
:
none
;
border-radius
:
999px
;
width
:
40px
;
height
:
40px
;
background
:
rgba
(
13
,
110
,
253
,
.95
);
color
:
#fff
;
box-shadow
:
0
4px
14px
rgba
(
0
,
0
,
0
,
.18
);
cursor
:
pointer
;
transition
:
opacity
.18s
ease-in-out
;
opacity
:
.92
;
}
#scrollDownBtn
:hover
{
opacity
:
1
;
}
#scrollDownBtn
svg
{
width
:
22px
;
height
:
22px
;
pointer-events
:
none
;
}
#scrollDownBtn
.show
{
display
:
inline-flex
;
align-items
:
center
;
justify-content
:
center
;
}
</style>
</head>
...
...
@@ -212,14 +177,6 @@
<div
id=
"thread"
></div>
</main>
<!-- Fixed scroll-to-bottom button -->
<button
id=
"scrollDownBtn"
type=
"button"
aria-label=
"Scroll down"
>
<svg
viewBox=
"0 0 24 24"
fill=
"currentColor"
aria-hidden=
"true"
>
<path
d=
"M12 16a1 1 0 0 1-.7-.29l-6-6a1 1 0 1 1 1.4-1.42L12 13.59l5.3-5.3a1 1 0 0 1 1.4 1.42l-6 6A1 1 0 0 1 12 16z"
/>
</svg>
</button>
<!-- Composer (sticks above fixed footer) -->
<div
class=
"composer py-3"
>
<div
class=
"container"
>
...
...
@@ -305,11 +262,6 @@
if
(
stopBtn
)
stopBtn
.
textContent
=
t
(
'buttons.stop'
,
'Stop'
);
const
disclaimer
=
document
.
getElementById
(
'disclaimer'
);
if
(
disclaimer
)
disclaimer
.
textContent
=
t
(
'footer.disclaimer'
,
'Beware: Cat can make mistakes.'
);
const
scrollDownBtn
=
document
.
getElementById
(
'scrollDownBtn'
);
if
(
scrollDownBtn
)
{
scrollDownBtn
.
setAttribute
(
'aria-label'
,
t
(
'buttons.scrollDown'
,
'Scroll down'
));
scrollDownBtn
.
title
=
t
(
'buttons.scrollDown'
,
'Scroll down'
);
}
setWelcomeImage
();
}
...
...
@@ -324,12 +276,10 @@
const
stopBtn
=
document
.
getElementById
(
'stopBtn'
);
const
welcomeLogo
=
document
.
getElementById
(
'welcomeLogo'
);
const
mainScroll
=
document
.
getElementById
(
'mainScroll'
);
const
scrollDownBtn
=
document
.
getElementById
(
'scrollDownBtn'
);
let
firstRequestDone
=
false
;
let
controller
=
null
;
// --- helpers ---
function
renderMarkdown
(
targetEl
,
markdownText
)
{
const
html
=
marked
.
parse
(
markdownText
,
{
breaks
:
true
,
gfm
:
true
,
headerIds
:
false
});
targetEl
.
innerHTML
=
DOMPurify
.
sanitize
(
html
,
{
USE_PROFILES
:
{
html
:
true
}
});
...
...
@@ -346,28 +296,11 @@
const
img
=
targetEl
.
querySelector
(
'img.thinking-cat'
);
if
(
img
)
targetEl
.
innerHTML
=
''
;
}
// --- Scroll indicator ---
function
needsScroll
()
{
return
mainScroll
.
scrollHeight
-
mainScroll
.
clientHeight
>
8
;
}
function
atBottom
()
{
return
mainScroll
.
scrollTop
+
mainScroll
.
clientHeight
>=
mainScroll
.
scrollHeight
-
50
;
}
function
updateScrollIndicator
()
{
if
(
needsScroll
()
&&
!
atBottom
())
scrollDownBtn
.
classList
.
add
(
'show'
);
else
scrollDownBtn
.
classList
.
remove
(
'show'
);
function
scrollToBottom
()
{
// force scroll to very bottom of the scrollable area
mainScroll
.
scrollTop
=
mainScroll
.
scrollHeight
;
}
scrollDownBtn
.
addEventListener
(
'click'
,
()
=>
{
mainScroll
.
scrollBy
({
top
:
mainScroll
.
clientHeight
,
behavior
:
'smooth'
});
setTimeout
(
updateScrollIndicator
,
320
);
});
mainScroll
.
addEventListener
(
'scroll'
,
updateScrollIndicator
);
window
.
addEventListener
(
'resize'
,
updateScrollIndicator
);
// Observe dynamic changes to keep indicator in sync
const
ro
=
new
ResizeObserver
(
updateScrollIndicator
);
ro
.
observe
(
mainScroll
);
ro
.
observe
(
thread
);
mainScroll
.
addEventListener
(
'load'
,
updateScrollIndicator
,
true
);
// --- Composer lock ---
function
setComposerLocked
(
locked
)
{
isRunning
=
locked
;
inputText
.
placeholder
=
locked
?
t
(
'status.thinking'
,
'Thinking…'
)
:
t
(
'composer.placeholder'
,
'What can I help you with?'
);
...
...
@@ -377,28 +310,23 @@
if
(
locked
)
inputText
.
blur
();
else
inputText
.
focus
();
}
// --- Flow ---
async
function
start
()
{
const
prompt
=
inputText
.
value
.
trim
();
if
(
!
prompt
)
return
;
if
(
!
firstRequestDone
)
{
welcomeLogo
?.
remove
();
firstRequestDone
=
true
;
updateScrollIndicator
();
}
const
shouldAutoScroll
=
atBottom
();
if
(
!
firstRequestDone
)
{
welcomeLogo
?.
remove
();
firstRequestDone
=
true
;
}
const
userMsg
=
document
.
createElement
(
'div'
);
userMsg
.
className
=
'message user-message'
;
userMsg
.
textContent
=
prompt
;
thread
.
appendChild
(
userMsg
);
updateScrollIndicator
();
scrollToBottom
();
const
assistantMsg
=
document
.
createElement
(
'div'
);
assistantMsg
.
className
=
'message assistant-message'
;
showThinkingCat
(
assistantMsg
);
thread
.
appendChild
(
assistantMsg
);
updateScrollIndicator
();
if
(
shouldAutoScroll
)
assistantMsg
.
scrollIntoView
({
behavior
:
'smooth'
,
block
:
'start'
});
scrollToBottom
();
inputText
.
value
=
''
;
controller
=
new
AbortController
();
...
...
@@ -426,10 +354,7 @@
rafPending
=
false
;
if
(
!
receivedAny
)
{
clearThinkingCatIfPresent
(
assistantMsg
);
receivedAny
=
true
;
}
renderMarkdown
(
assistantMsg
,
rawMarkdown
);
if
(
shouldAutoScroll
&&
atBottom
())
{
mainScroll
.
scrollTop
=
mainScroll
.
scrollHeight
;
}
updateScrollIndicator
();
scrollToBottom
();
});
};
...
...
@@ -454,7 +379,7 @@
}
finally
{
setComposerLocked
(
false
);
controller
=
null
;
updateScrollIndicator
();
scrollToBottom
();
}
}
...
...
@@ -481,7 +406,7 @@
try
{
await
fetch
(
'/api/clear'
,
{
method
:
'GET'
});
}
catch
(
_
)
{
}
await
loadLocale
(
CURRENT_LOCALE
);
document
.
getElementById
(
'inputText'
).
focus
();
updateScrollIndicator
();
scrollToBottom
();
});
</script>
</body>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment