Archipelago — open-source initial import

This commit is contained in:
Archipelago
2026-08-12 10:55:50 +00:00
commit b67e1527a2
2068 changed files with 472303 additions and 0 deletions
@@ -0,0 +1,59 @@
import { ref, reactive, watch, isRef, type Ref } from 'vue'
interface UseContentImagesOptions<T> {
items: Ref<T[]> | (() => T[])
id: (item: T) => string
existingUrl: (item: T) => string | undefined | null
fetch: (item: T) => Promise<string | null>
fallback: (item: T) => string
}
export function useContentImages<T>(options: UseContentImagesOptions<T>) {
const failed = ref<Set<string>>(new Set())
const fetched = reactive<Map<string, string>>(new Map())
function markFailed(id: string) {
failed.value = new Set([...failed.value, id])
}
function coverSrc(item: T): string | null {
const itemId = options.id(item)
if (failed.value.has(itemId)) return null
return options.existingUrl(item) || fetched.get(itemId) || null
}
function fallbackSrc(item: T): string {
return options.fallback(item)
}
function onError(item: T) {
markFailed(options.id(item))
}
function isLoading(item: T): boolean {
const itemId = options.id(item)
return !coverSrc(item) && !failed.value.has(itemId)
}
function fetchCovers(list: T[]) {
for (const item of list) {
const itemId = options.id(item)
if (options.existingUrl(item) || fetched.has(itemId) || failed.value.has(itemId)) continue
options.fetch(item).then((url) => {
if (url) {
fetched.set(itemId, url)
} else {
markFailed(itemId)
}
}).catch(() => {
markFailed(itemId)
})
}
}
const src = options.items
const itemsGetter: () => T[] = isRef(src) ? () => src.value : src
watch(itemsGetter, (list) => fetchCovers(list), { immediate: true })
return { coverSrc, fallbackSrc, onError, isLoading }
}