On a touch screen a nerd-stats tooltip showed only through the browser faking hover, unreliably, and couldn't be scrolled. Where the pointer can't hover (AppStatusService.CanHover), a tap on a NerdTip now opens its rows in a sheet from the bottom; the trigger is focusable, says it opens a dialog, and is at least 44px on touch. A closed tooltip takes no room any more (daisyUI only made it transparent, and one past a card's edge made a phone's feed scroll sideways), and on touch it never shows. The rows are a component of their own (NerdRows), at 12px on phones. A card's More menu has a Details entry on phones that gathers the post's, its author's, its place's or CDN's and its counts' rows in one sheet. A picture's tip doesn't open on a tap, the picture does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
199 lines
5.0 KiB
JavaScript
199 lines
5.0 KiB
JavaScript
window.cascadingStateInstanceReference = (dotNetReference) => {
|
|
try {
|
|
window.cascadingStateInstance = dotNetReference
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
window.logFromJs = (message, where) => {
|
|
try {
|
|
if (!window.cascadingStateInstance ||
|
|
typeof window.cascadingStateInstance.invokeMethodAsync != "function")
|
|
return
|
|
window.cascadingStateInstance.invokeMethodAsync('LogFromJs', message, where)
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
window.isServiceWorkerAvailable = () => {
|
|
try {
|
|
return navigator.serviceWorker.valueOf().controller != null
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "isServiceWorkerAvailable")
|
|
}
|
|
}
|
|
window.getLanguage = () => {
|
|
try {
|
|
return navigator.language.substr(0, 2)
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "getLanguage")
|
|
}
|
|
}
|
|
window.setLanguage = (lang) => {
|
|
try {
|
|
navigator.language = lang
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "setLanguage")
|
|
}
|
|
}
|
|
window.isOnline = async () => {
|
|
try {
|
|
const isOnline = navigator.onLine
|
|
//const url = "https://contents.nuvola.xyz/api/assets/6d9f5e55-2034-456f-92e7-d9ec51066443"
|
|
//let isOnlineStatusCode = true
|
|
|
|
//try {
|
|
// const online = await fetch(url)
|
|
// isOnlineStatusCode = online.status >= 200 && online.status < 399
|
|
//} catch (_) {
|
|
// isOnlineStatusCode = false
|
|
//}
|
|
|
|
if (navigator.connection !== undefined &&
|
|
navigator.connection.effectiveType !== undefined &&
|
|
navigator.connection.type !== undefined) {
|
|
if (!isOnline)
|
|
return isOnline
|
|
|
|
return navigator.connection.type === "cellular" ?
|
|
navigator.connection.effectiveType.indexOf("2g") === -1 /*&& isOnlineStatusCode*/ :
|
|
true
|
|
} else
|
|
return isOnline //&& isOnlineStatusCode
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "isOnline")
|
|
}
|
|
}
|
|
window.clearCache = async () => {
|
|
try {
|
|
const cachesNames = await caches.keys()
|
|
for (let i = 0; i < cachesNames.length; i++)
|
|
await caches.delete(cachesNames[i])
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "clearCache")
|
|
}
|
|
}
|
|
window.clearLocalStorage = () => {
|
|
try {
|
|
localStorage.removeItem("PrivateCacheData")
|
|
localStorage.removeItem("AuthData")
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "clearLocalStorage")
|
|
}
|
|
}
|
|
window.reloadPage = () => {
|
|
try {
|
|
location.reload(true)
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "reloadPage")
|
|
}
|
|
}
|
|
window.getHeight = (classId) => {
|
|
try {
|
|
const elements = document.querySelectorAll(classId)
|
|
let px = 0
|
|
if (!elements) return 0
|
|
elements.forEach(v => px += v.offsetHeight)
|
|
return px
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "getHeight")
|
|
}
|
|
}
|
|
window.setAppBadge = (counter) => {
|
|
try {
|
|
navigator.setAppBadge(counter)
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "setAppBadge")
|
|
}
|
|
}
|
|
window.clearAppBadge = () => {
|
|
try {
|
|
navigator.clearAppBadge()
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "clearAppBadge")
|
|
}
|
|
}
|
|
window.canHover = () => {
|
|
try {
|
|
return window.matchMedia("(hover: hover)").matches
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "canHover")
|
|
return true
|
|
}
|
|
}
|
|
// the selected tab of a sideways-scrolling strip, brought into its middle
|
|
window.revealActive = strip => {
|
|
try {
|
|
strip?.querySelector("[aria-selected=true]")?.scrollIntoView({ inline: "center", block: "nearest" })
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "revealActive")
|
|
}
|
|
}
|
|
// a phone: narrower than Tailwind's md, or held sideways (as short as the short: variant)
|
|
window.isMobileMedia = () => {
|
|
try {
|
|
return window.matchMedia("(max-width: 767.98px), (max-height: 30rem)").matches
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "isMobileMedia")
|
|
}
|
|
}
|
|
window.canShareStuff = () => {
|
|
try {
|
|
return navigator.share !== undefined
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "canShareStuff")
|
|
}
|
|
}
|
|
window.shareTextUrl = (title, text, url) => {
|
|
try {
|
|
navigator.share({
|
|
title: title,
|
|
text: text,
|
|
url: url
|
|
})
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "shareTextUrl")
|
|
}
|
|
}
|
|
window.shareText = (title, text) => {
|
|
try {
|
|
navigator.share({
|
|
title: title,
|
|
text: text
|
|
})
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "shareText")
|
|
}
|
|
}// This device's position for located posts and the Nearby feed, asked only when the reader chooses one of them. It
|
|
// goes to PrivaPub only, which keeps located posts on the server and rounds what it stores.
|
|
window.feedPosition = () => new Promise(resolve => {
|
|
try {
|
|
if (!navigator.geolocation)
|
|
return resolve({ error: "unsupported" })
|
|
navigator.geolocation.getCurrentPosition(
|
|
position => resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy }),
|
|
error => resolve({ error: error.message || String(error.code) }),
|
|
{ enableHighAccuracy: false, timeout: 15000, maximumAge: 600000 })
|
|
} catch (e) {
|
|
console.error(e)
|
|
window.logFromJs(e.message, "feedPosition")
|
|
resolve({ error: e.message })
|
|
}
|
|
})
|