Skip to content

Commit 266cd44

Browse files
authored
Script
1 parent 225f62f commit 266cd44

1 file changed

Lines changed: 152 additions & 0 deletions

File tree

docs/script.js

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
const rawBase =
2+
"https://raw.githubusercontent.com/ForjSkript/ForgeExtensions/refs/heads/main"
3+
4+
const listURL = `${rawBase}/extensions/list.json`
5+
6+
let listData = []
7+
let filteredData = []
8+
9+
10+
async function loadExtensions() {
11+
const list = await cachedFetch(listURL)
12+
listData = sortExtensions(list)
13+
filteredData = listData
14+
15+
setupSearch()
16+
renderExtensions()
17+
}
18+
19+
20+
/**
21+
* Cache fetch (5 min TTL)
22+
*/
23+
async function cachedFetch(url) {
24+
const key = "cache:" + url
25+
const cached = localStorage.getItem(key)
26+
27+
if (cached) {
28+
const { time, data } = JSON.parse(cached)
29+
if (Date.now() - time < 5 * 60 * 1000) return data
30+
}
31+
32+
const res = await fetch(url)
33+
const data = await res.json()
34+
35+
localStorage.setItem(
36+
key,
37+
JSON.stringify({ time: Date.now(), data })
38+
)
39+
40+
return data
41+
}
42+
43+
44+
/**
45+
* Sort extensions
46+
*/
47+
function sortExtensions(list) {
48+
return [...list].sort((a, b) => {
49+
if (a.id === "@tryforge/forgescript") return -1
50+
if (b.id === "@tryforge/forgescript") return 1
51+
return a.name.localeCompare(b.name)
52+
})
53+
}
54+
55+
56+
/**
57+
* Setup search input
58+
*/
59+
function setupSearch() {
60+
const input = document.getElementById("search")
61+
62+
input.addEventListener("input", () => {
63+
const q = input.value.toLowerCase()
64+
65+
filteredData = listData.filter(ext =>
66+
ext.id.toLowerCase().includes(q) ||
67+
ext.name.toLowerCase().includes(q)
68+
)
69+
70+
renderExtensions()
71+
})
72+
}
73+
74+
75+
/**
76+
* Detect extension type from file path
77+
*/
78+
function getType(file) {
79+
if (file.includes("extensions/official/")) return "official"
80+
if (file.includes("extensions/community/")) return "community"
81+
return "unlisted"
82+
}
83+
84+
85+
/**
86+
* Get color styles based on type
87+
*/
88+
function getTypeStyles(type) {
89+
switch (type) {
90+
case "official":
91+
return "border-blue-500/30 bg-blue-500/5"
92+
case "community":
93+
return "border-green-500/30 bg-green-500/5"
94+
default:
95+
return "border-yellow-500/30 bg-yellow-500/5"
96+
}
97+
}
98+
99+
100+
/**
101+
* Render extensions
102+
*/
103+
function renderExtensions() {
104+
const container = document.getElementById("extensions")
105+
container.innerHTML = ""
106+
107+
filteredData.forEach((ext, i) => {
108+
const type = getType(ext.file)
109+
const styles = getTypeStyles(type)
110+
111+
const el = document.createElement("div")
112+
113+
el.className = `
114+
opacity-0 translate-y-4
115+
rounded-xl border p-4 transition-all duration-500
116+
${styles}
117+
`
118+
119+
el.innerHTML = `
120+
<div class="flex items-center justify-between mb-2">
121+
<h2 class="text-lg font-semibold">${ext.name}</h2>
122+
<span class="text-xs text-slate-500">${ext.id}</span>
123+
</div>
124+
125+
<p class="text-sm text-slate-400 mb-3">
126+
${ext.description || "No description provided."}
127+
</p>
128+
129+
<div class="flex items-center justify-between">
130+
<span class="text-xs capitalize text-slate-400">${type}</span>
131+
132+
<a
133+
href="${rawBase}/${ext.file}"
134+
target="_blank"
135+
class="text-sm text-blue-400 hover:underline"
136+
>
137+
View
138+
</a>
139+
</div>
140+
`
141+
142+
container.appendChild(el)
143+
144+
// ✨ fade-up animation (staggered)
145+
setTimeout(() => {
146+
el.classList.remove("opacity-0", "translate-y-4")
147+
}, i * 60)
148+
})
149+
}
150+
151+
152+
loadExtensions()

0 commit comments

Comments
 (0)