Update plugin-list/plugin.js

This commit is contained in:
Marsn3 2025-03-31 04:34:36 +02:00
parent 571a439652
commit 0f77d127aa

View file

@ -1 +1,206 @@
penpot.ui.open("Plugins list",`?theme=${penpot.theme}`,{width:400,height:800});penpot.on("themechange",e=>{penpot.ui.sendMessage({type:"theme",content:e})});penpot.on("selectionchange",()=>{});
(function() {
const t=document.createElement("link").relList;
if(t&&t.supports&&t.supports("modulepreload"))return;
for(const n of document.querySelectorAll('link[rel="modulepreload"]'))o(n);
new MutationObserver(n=> {
for(const s of n)if(s.type==="childList")for(const a of s.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&o(a)
}
).observe(document, {
childList:!0,subtree:!0
}
);
function r(n) {
const s={};
return n.integrity&&(s.integrity=n.integrity),n.referrerPolicy&&(s.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?s.credentials="include":n.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s
}
function o(n) {
if(n.ep)return;
n.ep=!0;
const s=r(n);
fetch(n.href,s)
}
}
)();
const h=[ {
label:"Name (A-Z)",value:"name",direction:"asc"
}
, {
label:"Name (Z-A)",value:"name",direction:"desc"
}
, {
label:"Author (A-Z)",value:"author",direction:"asc"
}
, {
label:"Author (Z-A)",value:"author",direction:"desc"
}
],g=new URLSearchParams(window.location.search);
document.body.dataset.theme=g.get("theme")??"light";
async function m() {
const e=await fetch("https://plugins-list.girafic.net/penpot-plugins.json");
if(!e.ok)throw new Error("Failed to fetch plugins data");
return e.json()
}
function f() {
const e=document.createElement("div");
return e.className="loading-state",e.innerHTML=`
<svg class="loading-spinner" viewBox="0 0 50 50">
<circle cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
</svg>
<span>Loading plugins...</span>
`,e
}
function v(e) {
const t=document.createElement("div");
t.className="search-container",t.innerHTML=`
<div class="search-row">
<div class="search-input-wrapper">
<input
type="text"
class="input search-input"
placeholder="Search plugins..."
id="searchInput"
>
<button class="search-clear" id="searchClear" type="button">
<svg width="16" height="16" viewBox="0 0 16 16">
<path d="M8 6.586L4.293 2.879 2.879 4.293 6.586 8l-3.707 3.707 1.414 1.414L8 9.414l3.707 3.707 1.414-1.414L9.414 8l3.707-3.707-1.414-1.414L8 6.586z"/>
</svg>
</button>
</div>
<div class="select-wrapper">
<select class="select sort-select" id="sortSelect">
<option value="">Sort by</option>
${h.map(s=>`<option value="${s.value},${s.direction}">$ {
s.label
}
</option>`).join("")}
</select>
</div>
</div>
`,e.appendChild(t);
const r=t.querySelector("#searchInput"),o=t.querySelector("#sortSelect"),n=t.querySelector("#searchClear");
if(r&&o&&n) {
const s=()=> {
let a=L(r.value);
const[i,c]=o.value.split(",");
i&&c&&(a=y(a,i,c)),w(a),n.style.display=r.value?"flex":"none"
};
r.addEventListener("input",s),o.addEventListener("change",s),n.addEventListener("click",()=> {
r.value="",r.focus(),s()
}
),n.style.display="none"
}
}
function y(e,t,r) {
return[...e].sort((o,n)=> {
const s=o[t].toString().toLowerCase(),a=n[t].toString().toLowerCase();
return r==="asc"?s.localeCompare(a):a.localeCompare(s)
}
)
}
function L(e) {
const t=document.querySelector("body");
if(!(t!=null&&t.dataset.plugins))return[];
const r=JSON.parse(t.dataset.plugins),o=e.toLowerCase().trim();
return o===""?r:r.filter(n=>n.name.toLowerCase().includes(o)||n.author.toLowerCase().includes(o)||n.description.toLowerCase().includes(o))
}
function l(e) {
return`
<img src="${e.icon}" alt="${e.name}" class="plugin-icon">
<div class="plugin-info">
<h3 class="plugin-name">${e.name}</h3>
<p class="plugin-author">by <button class="author-button">${e.author}</button></p>
<p class="plugin-description">${e.description}</p>
<div class="plugin-actions">
<a href="${e.install.replace("https://design.penpot.app/","https://design.m3.fyi/")}" class="plugin-install" data-appearance="primary" target="_blank">Install</a>
<a href="${e.link}" class="plugin-link" data-appearance="secondary" target="_blank">Details</a>
</div>
</div>
`
}
function S(e) {
const t=document.querySelector("#searchInput"),r=document.querySelector("#sortSelect");
t&&r&&(t.value=e,r.value="",t.dispatchEvent(new Event("input")))
}
function u(e,t) {
const r=e.querySelector(".author-button");
r&&r.addEventListener("click",()=> {
S(t.author)
}
)
}
function d(e,t,r) {
return`
<div class="plugins-counter">
<div>${e===t?`Showing all $ {
t
}
plugins`:`Showing $ {
e
}
of $ {
t
}
plugins`}</div>
<div class="generated-at">Last updated: ${new Date(r).toLocaleString()}</div>
</div>
`
}
function w(e) {
const t=document.querySelector(".plugins-list"),r=document.querySelector("body");
if(!t||!(r!=null&&r.dataset.plugins))return;
const o=JSON.parse(r.dataset.plugins),n=new Date().toISOString();
if(t.innerHTML="",e.length===0) {
const a=document.createElement("div");
a.className="no-results",a.textContent="No plugins found",t.appendChild(a)
}
else e.forEach(a=> {
const i=document.createElement("div");
i.className="plugin-item",i.innerHTML=l(a),u(i,a),t.appendChild(i)
}
);
const s=document.createElement("div");
s.innerHTML=d(e.length,o.length,n),t.appendChild(s)
}
async function p() {
const e=document.querySelector("body");
if(!e)return;
e.innerHTML="",v(e);
const t=document.createElement("div");
t.className="plugins-list";
const r=f();
t.appendChild(r),e.appendChild(t);
try {
const o=await m(), {
plugins:n,generated_at:s
}
=o;
r.remove(),n.forEach(i=> {
const c=document.createElement("div");
c.className="plugin-item",c.innerHTML=l(i),u(c,i),t.appendChild(c)
}
);
const a=document.createElement("div");
a.innerHTML=d(n.length,o.plugins.length,s),t.appendChild(a),e.dataset.plugins=JSON.stringify(n)
}
catch {
r.innerHTML=`
<div class="loading-error">
<span>Failed to load plugins</span>
<button class="retry-button" data-appearance="primary">Retry</button>
</div>
`;
const n=r.querySelector(".retry-button");
n&&n.addEventListener("click",()=> {
p()
}
)
}
}
p();
window.addEventListener("message",async e=> {
e.data.type==="theme"&&(document.body.dataset.theme=e.data.content)
}
);