Hello world

First open source release of Campfire 🎉
This commit is contained in:
Kevin McConnell
2025-08-15 11:02:42 +01:00
commit df76a227dc
664 changed files with 36235 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
export function scrollToBottom(container) {
container.scrollTop = container.scrollHeight
}
export function escapeHTML(html) {
const div = document.createElement("div")
div.textContent = html
return div.innerHTML
}
export function parseHTMLFragment(html) {
const template = document.createElement("template")
template.innerHTML = html
return template.content
}
export function insertHTMLFragment(fragment, container, top) {
if (top) {
container.prepend(fragment)
} else {
container.append(fragment)
}
}
export function ignoringBriefDisconnects(element, fn) {
requestAnimationFrame(() => {
if (!element.isConnected) fn()
})
}
export function trimChildren(count, container, top) {
const children = Array.from(container.children)
const elements = top ? children.slice(0, count) : children.slice(-count)
keepScroll(container, top, function() {
for (const element of elements) {
element.remove()
}
})
}
export async function keepScroll(container, top, fn) {
pauseInertiaScroll(container)
const scrollTop = container.scrollTop
const scrollHeight = container.scrollHeight
await fn()
if (top) {
container.scrollTop = scrollTop + (container.scrollHeight - scrollHeight)
} else {
container.scrollTop = scrollTop
}
}
function pauseInertiaScroll(container) {
container.style.overflow = "hidden"
requestAnimationFrame(() => {
container.style.overflow = ""
})
}
@@ -0,0 +1,3 @@
export function isTouchDevice() {
return "ontouchstart" in window && navigator.maxTouchPoints > 0
}
+7
View File
@@ -0,0 +1,7 @@
export function truncateString(string, length, omission = "…") {
if (string.length <= length) {
return string
} else {
return string.slice(0, length - omission.length) + omission
}
}
+39
View File
@@ -0,0 +1,39 @@
export function throttle(fn, delay = 1000) {
let timeoutId = null
return (...args) => {
if (!timeoutId) {
fn(...args)
timeoutId = setTimeout(() => timeoutId = null, delay)
}
}
}
export function debounce(fn, delay = 1000) {
let timeoutId = null
return (...args) => {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => fn.apply(this, args), delay)
}
}
export function nextEventLoopTick() {
return delay(0)
}
export function onNextEventLoopTick(callback) {
setTimeout(callback, 0)
}
export function nextFrame() {
return new Promise(requestAnimationFrame)
}
export function nextEventNamed(eventName, element = window) {
return new Promise(resolve => element.addEventListener(eventName, resolve, { once: true }))
}
export function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+3
View File
@@ -0,0 +1,3 @@
export function pageIsTurboPreview() {
return document.documentElement.hasAttribute("data-turbo-preview")
}