Files
remanso/src/hooks/useComputeBacklinks.hook.ts
Julien Calixte e03ff49764 fix(mobile): restore overflow-y and unstick readme on vertical scroll
- Restore explicit overflow-y:auto on #main-app for mobile (removed in
  63f5d64) — implicit coercion from overflow-x:auto is not reliable in
  all Safari/WebKit versions.
- Override position:sticky on .readme to position:relative on mobile.
  The desktop sticky (left:0) is correct for horizontal scroll, but on
  mobile vertical scroll it pinned the 100dvh-tall readme across the
  entire viewport, hiding all stacked notes behind it.
2026-04-24 23:42:22 +02:00

122 lines
3.4 KiB
TypeScript

import { watch } from "vue"
import { backlinkEventBus } from "@/bus/backlinkEventBus"
import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum"
import { useFile } from "@/hooks/useFile.hook"
import { Backlink } from "@/modules/note/models/Backlink"
import { BacklinkNote } from "@/modules/note/models/BacklinkNote"
import { resolvePath } from "@/modules/repo/services/resolvePath"
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
import { isExternalLink } from "@/utils/link"
import { filenameToNoteTitle } from "@/utils/noteTitle"
import { confirmMessage } from "@/utils/notif"
const isMarkdown = (filename?: string) => filename?.endsWith(".md") ?? false
const yieldToMain = () =>
"scheduler" in globalThis
? (
globalThis as unknown as { scheduler: { yield: () => Promise<void> } }
).scheduler.yield()
: new Promise<void>((r) => setTimeout(r, 0))
export const useComputeBacklinks = () => {
const store = useUserRepoStore()
watch(
() => store.files,
async () => {
await new Promise<void>((r) => setTimeout(r, 300))
if (!store.userSettings?.backlink) {
return
}
let notifiedForComputation = false
const backlinks: Map<string, Backlink[]> = new Map()
for (const file of store.files) {
await yieldToMain()
if (!isMarkdown(file.path) || !file.sha) {
continue
}
const fileBacklinkId = generateId(DataType.BacklinkNote, file.sha)
const fileBacklink = await data.get<
DataType.BacklinkNote,
BacklinkNote
>(fileBacklinkId)
if (fileBacklink) {
continue
}
if (!backlinks.has(file.sha)) {
backlinks.set(file.sha, [])
}
const { getContent } = useFile(file.sha, false)
const note = await getContent()
if (!note) {
return
}
const parser = new DOMParser()
const htmlDoc = parser.parseFromString(note, "text/html")
const links = htmlDoc.querySelectorAll("a")
for (const link of links) {
const href = link.getAttribute("href") ?? ""
if (isExternalLink(href) || !isMarkdown(href)) {
continue
}
const path = resolvePath(file.path ?? "", href)
const backlinkFile = store.files.find((file) => file.path === path)
if (!backlinkFile?.sha || !backlinkFile?.path) {
continue
}
const previousBacklinks = backlinks.get(backlinkFile.sha) ?? []
if (previousBacklinks.find((bl) => bl.sha === file.sha)) {
continue
}
if (!notifiedForComputation) {
notifiedForComputation = true
confirmMessage("Updating backlinks...")
}
backlinks.set(backlinkFile.sha, [
...previousBacklinks,
{
sha: file.sha,
title: filenameToNoteTitle(file.path ?? "")
}
])
}
}
for (const [sha, fileBacklinks] of backlinks) {
const fileBacklinkId = generateId(DataType.BacklinkNote, sha)
const backlinkNote: BacklinkNote = {
_id: fileBacklinkId,
$type: DataType.BacklinkNote,
sha: sha,
links: fileBacklinks
}
await data.update(backlinkNote)
backlinkEventBus.emit({ fileSha: sha })
}
}
)
}