From aac4ef24a46fe59d0e9ce468f4521e954a206367 Mon Sep 17 00:00:00 2001
From: Massimo Melina
Date: Tue, 17 Mar 2026 15:44:00 +0100
Subject: [PATCH 1/2] added gitignore
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 .gitignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b7552f6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+dist/storage
\ No newline at end of file
From aa2136d3821f98cb56bcbca84811f4fab375cdf0 Mon Sep 17 00:00:00 2001
From: Massimo Melina
Date: Tue, 17 Mar 2026 15:40:50 +0100
Subject: [PATCH 2/2] fix: don't overlap with pagination-bar on phone
---
dist/plugin.js | 5 ++++-
dist/public/main.js | 49 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/dist/plugin.js b/dist/plugin.js
index b372973..dd63548 100644
--- a/dist/plugin.js
+++ b/dist/plugin.js
@@ -1,4 +1,4 @@
-exports.version = 1.3
+exports.version = 1.31
exports.description = "Simple chat integrated in HFS"
exports.apiRequired = 8.87
exports.repo = "damienzonly/hfs-chat"
@@ -56,6 +56,9 @@ exports.config = {
frontend: true
}
}
+exports.changelog = [
+ { "version": 1.21, "message": "fix: don't overlap with pagination-bar on phone" }
+]
exports.init = async api => {
const chatDb = await api.openDb('chat', { rewriteLater: true })
diff --git a/dist/public/main.js b/dist/public/main.js
index 9178db4..1ee85d4 100644
--- a/dist/public/main.js
+++ b/dist/public/main.js
@@ -29,6 +29,7 @@
msg && HFS.toast(msg, 'error')
}
+ const CONTAINER_CLASS = 'chat-container'
function ChatContainer() {
const {username} = HFS.useSnapState()
const [m, sm] = useState('');
@@ -70,8 +71,8 @@
if (goBottom)
el?.scrollTo(0, el.scrollHeight)
}, [goBottom, msgs, collapsed])
-
- return h('div', { className: 'chat-container' },
+ useStickyHelper()
+ return h('div', { className: CONTAINER_CLASS },
h('div', { className: 'chat-header' },
h('span', {},
`Chat`,
@@ -134,6 +135,50 @@
})
return isBanned || (!anonCanRead && !anonCanWrite)? null : h(ChatContainer);
}
+
+ // don't overlap with pagination-bar when we are in sticky mode
+ function useStickyHelper() {
+ useEffect(() => {
+ let frame = 0
+ let resizeObserver
+ const mutationObserver = new MutationObserver(update)
+ const stopResize = HFS.domOn('resize', update, { target: window })
+ mutationObserver.observe(document.body, { childList: true, subtree: true })
+ update()
+ return () => {
+ cancelAnimationFrame(frame)
+ stopResize?.()
+ mutationObserver.disconnect()
+ resizeObserver?.disconnect()
+ const paging = document.getElementById('paging')
+ if (paging) paging.style.bottom = ''
+ }
+
+ function update() {
+ frame ||= requestAnimationFrame(() => {
+ frame = 0
+ const chat = document.querySelector('.'+CONTAINER_CLASS)
+ const paging = document.getElementById('paging')
+ if (!paging) return
+ if (!chat) {
+ paging.style.bottom = ''
+ return
+ }
+ const { position } = getComputedStyle(chat)
+ // use the applied css position as source of truth, so js doesn't duplicate media-query rules
+ const shouldOffsetPaging = position === 'sticky'
+ paging.style.bottom = shouldOffsetPaging ? Math.ceil(chat.getBoundingClientRect().height) + 'px' : ''
+ resizeObserver?.disconnect()
+ if (window.ResizeObserver) {
+ resizeObserver = new ResizeObserver(update)
+ resizeObserver.observe(chat)
+ resizeObserver.observe(paging)
+ }
+ })
+ }
+
+ }, [])
+ }
}