|
8 | 8 | <meta name="theme-color" content="#ef1237" media="(prefers-color-scheme: light)"> |
9 | 9 | <meta name="theme-color" content="#100f27" media="(prefers-color-scheme: dark)"> |
10 | 10 | <meta name="color-scheme" content="light dark" /> |
| 11 | + <!-- Package images are self-hosted; restrict where any image can load from. --> |
| 12 | + <meta http-equiv="Content-Security-Policy" content="img-src 'self' https://raw.githubusercontent.com data:;"> |
11 | 13 |
|
12 | 14 | <!-- Fonts --> |
13 | 15 | <link rel="preconnect" href="https://fonts.bunny.net" /> |
|
69 | 71 | <a href="https://github.com/BasisVR/BasisPackageManager/releases" target="_blank" |
70 | 72 | class="ml-6 inline-flex items-center gap-2 rounded-2xl border border-gray-200 bg-white/70 px-4 py-2 text-sm font-semibold text-gray-900 shadow-sm hover:border-brand hover:text-brand dark:border-white/10 dark:bg-white/10 dark:text-white"> |
71 | 73 | <svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v12m0 0 4-4m-4 4-4-4"/><path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg> |
72 | | - Get the app |
| 74 | + Get the Package Manager |
73 | 75 | </a> |
74 | 76 | <button id="submitBtn" class="ml-3 inline-flex items-center gap-2 rounded-2xl bg-gradient-to-r from-brand to-purple-600 px-4 py-2 text-sm font-semibold text-white shadow hover:shadow-lg">Submit a package</button> |
75 | 77 | </div> |
@@ -160,6 +162,10 @@ <h4 class="mb-3 text-xs font-semibold uppercase tracking-wide text-gray-400">Cat |
160 | 162 | : s==='community' ? 'bg-purple-500/15 text-purple-600 dark:text-purple-400 ring-1 ring-purple-500/30' |
161 | 163 | : 'bg-gray-500/15 text-gray-500 ring-1 ring-gray-500/20'; |
162 | 164 | const dotCls = k => k==='curated'?'bg-brand':k==='community'?'bg-purple-500':'bg-gray-400'; |
| 165 | +// Package image is a self-hosted path (icons/<id>.png) or null → fall back to the emoji icon. |
| 166 | +const imgOrIcon = p => p.image |
| 167 | + ? `<img src="${esc(p.image)}" alt="" loading="lazy" referrerpolicy="no-referrer" class="h-full w-full object-cover" onerror="this.replaceWith(document.createTextNode('📦'))">` |
| 168 | + : esc(p.icon||'📦'); |
163 | 169 |
|
164 | 170 | function toast(msg, kind){ |
165 | 171 | const t=document.getElementById('toast'); |
@@ -233,7 +239,7 @@ <h4 class="mb-3 text-xs font-semibold uppercase tracking-wide text-gray-400">Cat |
233 | 239 | grid.innerHTML = ALL.map(p=>` |
234 | 240 | <div data-id="${esc(p.id)}" class="group flex cursor-pointer flex-col rounded-2xl border border-gray-200 bg-white/70 p-5 shadow-sm backdrop-blur transition hover:-translate-y-0.5 hover:shadow-lg hover:shadow-brand/20 dark:border-white/10 dark:bg-white/5"> |
235 | 241 | <div class="flex items-start gap-3"> |
236 | | - <div class="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-gray-100 text-xl ring-1 ring-gray-200 dark:bg-white/5 dark:ring-white/10">${esc(p.icon||'📦')}</div> |
| 242 | + <div class="inline-flex h-11 w-11 shrink-0 items-center justify-center overflow-hidden rounded-xl bg-gray-100 text-xl ring-1 ring-gray-200 dark:bg-white/5 dark:ring-white/10">${imgOrIcon(p)}</div> |
237 | 243 | <div class="min-w-0"> |
238 | 244 | <h3 class="flex flex-wrap items-center gap-2 font-semibold">${esc(p.name)} |
239 | 245 | <span class="rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide ${badgeCls(p.source)}">${esc(p.source)}</span></h3> |
@@ -278,7 +284,7 @@ <h5 class="mb-2 flex items-center gap-2 font-semibold"><span class="${num}">2</s |
278 | 284 | const stat = 'text-gray-600 dark:text-gray-300'; |
279 | 285 | m.innerHTML = `<div class="w-full max-w-2xl max-h-[85vh] overflow-auto rounded-2xl border border-gray-200 bg-white shadow-2xl dark:border-white/10 dark:bg-basisbg" onclick="event.stopPropagation()"> |
280 | 286 | <div class="flex items-start gap-4 border-b border-gray-200 p-6 dark:border-white/10"> |
281 | | - <div class="inline-flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gray-100 text-3xl ring-1 ring-gray-200 dark:bg-white/5 dark:ring-white/10">${esc(p.icon||'📦')}</div> |
| 287 | + <div class="inline-flex h-14 w-14 shrink-0 items-center justify-center overflow-hidden rounded-2xl bg-gray-100 text-3xl ring-1 ring-gray-200 dark:bg-white/5 dark:ring-white/10">${imgOrIcon(p)}</div> |
282 | 288 | <div class="min-w-0 flex-1"> |
283 | 289 | <h2 class="flex flex-wrap items-center gap-2 text-xl font-bold">${esc(p.name)} <span class="rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide ${badgeCls(p.source)}">${esc(p.source)}</span></h2> |
284 | 290 | <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">by ${p.authorUrl?`<a href="${esc(p.authorUrl)}" target="_blank" class="underline hover:text-brand">${esc(p.author)}</a>`:esc(p.author)} · ${esc(p.category)}${hostOf(p)?' · '+hostOf(p):''}</p> |
|
0 commit comments