snapport 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,43 @@
1
+ export declare function getPortProjects(username: string, tag?: string, options?: {
2
+ forceRefresh?: boolean;
3
+ }): Promise<SanitizedRepo[]>;
4
+
5
+ export declare function initPortfolio(username: string, config?: PortfolioConfig): Promise<PortfolioResponse>;
6
+
7
+ export declare interface PortfolioConfig {
8
+ tag?: string;
9
+ searchContainer: string;
10
+ filtersContainer: string;
11
+ projectsContainer: string;
12
+ customCardTemplate?: (repo: SanitizedRepo) => string;
13
+ }
14
+
15
+ export declare interface PortfolioResponse {
16
+ projects?: any[];
17
+ status: 'success' | 'error';
18
+ message?: string;
19
+ }
20
+
21
+ export declare function renderFilters(projects: SanitizedRepo[], containerElement: HTMLElement | string): void;
22
+
23
+ export declare function renderProjects(projects: SanitizedRepo[], containerElement: HTMLElement | string, username?: string, customTemplate?: (repo: SanitizedRepo) => string): void;
24
+
25
+ export declare function renderSearchBar(containerElement: HTMLElement | string): void;
26
+
27
+ export declare interface SanitizedRepo {
28
+ id: number;
29
+ name: string;
30
+ description: string | null;
31
+ htmlUrl: string;
32
+ topics: string[];
33
+ stacks: string[];
34
+ deployUrl: string | null;
35
+ }
36
+
37
+ export declare interface TechInfo {
38
+ icon: string;
39
+ name: string;
40
+ color: string;
41
+ }
42
+
43
+ export { }
@@ -0,0 +1 @@
1
+ :root{--ghp-accent: #333;--ghp-bg: #ffffff;--ghp-border: rgba(226, 226, 228, .8);--ghp-shadow: rgba(0, 0, 0, .1);--ghp-text: #333;--ghp-text-light: #666}.ghp-search-input,.ghp-filter-btn,.ghp-card-links a{transition:all .2s ease}.ghp-search-container{position:relative;margin:0 15px 20px;max-width:400px}.ghp-search-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);color:#888;pointer-events:none}.ghp-search-input{width:100%;padding:10px 12px 10px 38px;border:1px solid var(--ghp-border);border-radius:8px;font-size:14px;outline:none}.ghp-search-input:focus{border-color:var(--ghp-accent);box-shadow:0 0 0 3px #0000000d}.ghp-filters-content{display:flex;gap:12px;padding:10px 15px;margin-bottom:25px;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none}.ghp-filters-content::-webkit-scrollbar{display:none}.ghp-filter-btn{scroll-snap-align:start;flex:0 0 auto;display:flex;align-items:center;gap:8px;background-color:var(--ghp-bg);padding:8px 16px;border:solid 2px #e1e4e8;border-radius:30px;cursor:pointer;font-family:inherit;font-weight:500}.ghp-filter-btn img,.ghp-filter-btn svg{width:18px;height:18px;object-fit:contain}.ghp-filter-btn p{margin:0;font-size:14px}@media(max-width:600px){.ghp-filters-content{gap:8px;padding:8px}}.ghp-filter-btn:hover{transform:translateY(-3px);border-color:var(--tech-color, var(--ghp-accent));color:var(--tech-color, var(--ghp-accent));box-shadow:0 4px 8px var(--ghp-shadow)}.ghp-filter-btn.active{background-color:var(--tech-color, var(--ghp-accent));color:#fff;border-color:var(--tech-color, var(--ghp-accent))}.ghp-filter-btn.active img{filter:brightness(0) invert(1)}.ghp-projects-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:25px;padding:15px;align-items:start}@media(max-width:1024px){.ghp-projects-grid{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}}.ghp-project-card{background-color:var(--ghp-bg);border-radius:12px;border:solid 1px var(--ghp-border);box-shadow:0 2px 5px var(--ghp-shadow);display:flex;flex-direction:column;transition:transform .2s ease;height:100%;min-height:220px}.ghp-img-container,.ghp-card-img{border-radius:8px 8px 0 0}.ghp-img-container{width:100%;aspect-ratio:16 / 9;background-color:#161b22;border-bottom:1px solid var(--ghp-border);overflow:hidden}.ghp-card-img{width:100%;height:100%;object-fit:cover;object-position:center;display:block}.ghp-card-content{display:flex;flex-direction:column;justify-content:space-between;flex:1;padding:20px}.ghp-skeleton-card{height:220px;width:100%;border:1px solid transparent;box-sizing:border-box}.ghp-project-card:hover{transform:translateY(-5px)}.ghp-project-card h3{margin:0 0 10px;font-size:18px}.ghp-project-card p{font-size:14px;color:var(--ghp-text-light);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;line-height:1.5}.ghp-card-links{display:flex;gap:10px}.ghp-card-links a{text-decoration:none;padding:6px 14px;color:var(--ghp-text);font-size:13px;font-weight:500;border:solid 1px var(--ghp-border);border-radius:20px;background-color:#f6f8fa}.ghp-card-links a:hover{background-color:var(--ghp-accent);color:#fff;border-color:var(--ghp-accent)}.ghp-skeleton{background:linear-gradient(90deg,#f0f0f0 25%,#e6e6e6,#f0f0f0 75%);background-size:200% 100%;animation:ghp-loading 1.5s infinite ease-in-out;border-radius:4px}@keyframes ghp-loading{0%{background-position:200% 0}to{background-position:-200% 0}}.ghp-skeleton-card{height:200px;width:100%;border-radius:12px}
@@ -0,0 +1,195 @@
1
+ const f = {
2
+ react: { name: "React", icon: "react", color: "61DAFB" },
3
+ vue: { name: "Vue.js", icon: "vuedotjs", color: "4FC08D" },
4
+ angular: { name: "Angular", icon: "angular", color: "DD0031" },
5
+ nextjs: { name: "Next.js", icon: "nextdotjs", color: "000000" },
6
+ typescript: { name: "TypeScript", icon: "typescript", color: "3178C6" },
7
+ javascript: { name: "JavaScript", icon: "javascript", color: "F7DF1E" },
8
+ html5: { name: "HTML5", icon: "html5", color: "E34F26" },
9
+ css3: { name: "CSS3", icon: "css3", color: "1572B6" },
10
+ sass: { name: "Sass", icon: "sass", color: "CC6699" },
11
+ "tailwind-css": { name: "Tailwind", icon: "tailwindcss", color: "06B6D4" },
12
+ bootstrap: { name: "Bootstrap", icon: "bootstrap", color: "7952B3" },
13
+ "styled-components": { name: "Styled Components", icon: "styledcomponents", color: "DB7093" },
14
+ figma: { name: "Figma", icon: "figma", color: "F24E1E" },
15
+ nodejs: { name: "Node.js", icon: "nodedotjs", color: "339933" },
16
+ express: { name: "Express", icon: "express", color: "000000" },
17
+ nestjs: { name: "NestJS", icon: "nestjs", color: "E0234E" },
18
+ python: { name: "Python", icon: "python", color: "3776AB" },
19
+ java: { name: "Java", icon: "openjdk", color: "007396" },
20
+ php: { name: "PHP", icon: "php", color: "777BB4" },
21
+ postgresql: { name: "PostgreSQL", icon: "postgresql", color: "4169E1" },
22
+ mongodb: { name: "MongoDB", icon: "mongodb", color: "47A248" },
23
+ mysql: { name: "MySQL", icon: "mysql", color: "4479A1" },
24
+ firebase: { name: "Firebase", icon: "firebase", color: "FFCA28" },
25
+ prisma: { name: "Prisma", icon: "prisma", color: "2D3748" },
26
+ docker: { name: "Docker", icon: "docker", color: "2496ED" },
27
+ git: { name: "Git", icon: "git", color: "F05032" },
28
+ jest: { name: "Jest", icon: "jest", color: "C21325" },
29
+ "github-actions": { name: "GitHub Actions", icon: "githubactions", color: "2088FF" }
30
+ }, u = typeof process < "u" && process.env.NODE_ENV !== "production" || typeof import.meta < "u" && import.meta.env.MODE !== "production", v = 7200 * 1e3, C = (t) => t ? t.filter((o) => !!f[o.toLocaleLowerCase().trim()]) : [], j = (t) => ({
31
+ id: t.id,
32
+ name: t.name ?? "Projeto sem nome",
33
+ description: t.description ?? "Sem descrição disponível",
34
+ htmlUrl: t.html_url,
35
+ topics: Array.isArray(t.topics) ? t.topics : [],
36
+ stacks: Array.isArray(t.topics) ? C(t.topics) : [],
37
+ deployUrl: t.homepage ?? null
38
+ });
39
+ function w(t) {
40
+ try {
41
+ Object.keys(localStorage).forEach((e) => {
42
+ e.startsWith("gh_projects_") && !e.includes(t) && localStorage.removeItem(e);
43
+ });
44
+ } catch (e) {
45
+ console.warn("Erro ao limpar caches antigos:", e);
46
+ }
47
+ }
48
+ async function $(t, e = "port", o = {}) {
49
+ if (!t)
50
+ return console.error("GitHubPortfolio: Username é obrigatório."), [];
51
+ const r = `gh_projects_${t}`, c = u || o.forceRefresh;
52
+ try {
53
+ if (w(t), c)
54
+ u && console.info(`[GitHubPortfolio]: Dev mode detectado. Cache ignorado para ${t}.`);
55
+ else {
56
+ const p = localStorage.getItem(r);
57
+ if (p) {
58
+ const { data: d, timestamp: y } = JSON.parse(p);
59
+ if (Date.now() - y < v)
60
+ return d;
61
+ }
62
+ }
63
+ const n = encodeURIComponent(`user:${t} topic:${e}`), s = await fetch(`https://api.github.com/search/repositories?q=${n}&sort=updated&order=desc`);
64
+ if (!s.ok)
65
+ throw new Error(`GitHub API error: ${s.status}`);
66
+ const a = ((await s.json()).items || []).map(j), l = {
67
+ data: a,
68
+ timestamp: Date.now()
69
+ };
70
+ return localStorage.setItem(r, JSON.stringify(l)), a;
71
+ } catch (n) {
72
+ console.error(`GitHubPortfolio: Erro ao buscar dados de ${t}:`, n);
73
+ const s = localStorage.getItem(r);
74
+ return s ? (console.warn("GitHubPortfolio: Usando cache expirado devido a erro de rede."), JSON.parse(s).data) : [];
75
+ }
76
+ }
77
+ const h = (t) => typeof t == "string" ? document.getElementById(t) : t, g = (t, e = null) => {
78
+ if (!e)
79
+ return `
80
+ <button class="ghp-filter-btn active" data-topic="all">
81
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
82
+ <rect width="7" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="14" y="3" rx="1"/>
83
+ <rect width="7" height="7" x="14" y="14" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/>
84
+ </svg>
85
+ <p>Todos</p>
86
+ </button>
87
+ `;
88
+ const o = `https://cdn.simpleicons.org/${e.icon}/${e.color}`;
89
+ return `
90
+ <button class="ghp-filter-btn" data-topic="${t}" style="--tech-color: #${e.color}">
91
+ <img src="${o}" alt="${e.name}" loading="lazy">
92
+ <p>${e.name}</p>
93
+ </button>
94
+ `;
95
+ }, b = (t, e) => {
96
+ const o = `https://raw.githubusercontent.com/${e}/${t.name}/main/preview.png`, r = `https://opengraph.githubassets.com/${e}/${t.name}`, c = `https://placehold.co/640x360?text=${encodeURIComponent(t.name)}`, n = t.deployUrl ? `<a href="${t.deployUrl}" target="_blank" rel="noopener noreferrer">Acessar</a>` : "", s = t.htmlUrl ? `<a href="${t.htmlUrl}" target="_blank" rel="noopener noreferrer">Github</a>` : "";
97
+ return `
98
+ <div class="ghp-project-card">
99
+ <div class="ghp-img-container">
100
+ <img
101
+ src="${o}"
102
+ alt="Preview do projeto ${t.name}"
103
+ class="ghp-card-img"
104
+ loading="lazy"
105
+ onerror="if (this.src.includes('preview.png')) { this.src='${r}'; } else { this.onerror=null; this.src='${c}'; }"
106
+ >
107
+ </div>
108
+ <div class="ghp-card-content">
109
+ <div>
110
+ <h3>${t.name}</h3>
111
+ <p title="${t.description}">${t.description}</p>
112
+ </div>
113
+ <div class="ghp-card-links">
114
+ ${s}
115
+ ${n}
116
+ </div>
117
+ </div>
118
+ </div>
119
+ `;
120
+ };
121
+ function E(t, e = 6) {
122
+ const o = h(t);
123
+ o && (o.className = "ghp-projects-grid", o.innerHTML = Array(e).fill('<div class="ghp-project-card ghp-skeleton ghp-skeleton-card"></div>').join(""));
124
+ }
125
+ function S(t, e) {
126
+ const o = h(e);
127
+ if (!o) return;
128
+ const r = t.flatMap((s) => s.topics || []), n = [...new Set(r)].reduce((s, i) => {
129
+ const a = f[i];
130
+ return a ? s + g(i, a) : s;
131
+ }, g("all"));
132
+ o.innerHTML = `<div class="ghp-filters-content">${n}</div>`;
133
+ }
134
+ function m(t, e, o = "", r) {
135
+ const c = h(e);
136
+ if (c) {
137
+ if (c.className = "ghp-projects-grid", c.style.minHeight = "auto", t.length === 0) {
138
+ c.innerHTML = '<p class="ghp-empty-msg">Nenhum projeto encontrado.</p>';
139
+ return;
140
+ }
141
+ c.innerHTML = t.map((n) => r ? r(n) : b(n, o)).join("");
142
+ }
143
+ }
144
+ function x(t) {
145
+ const e = h(t);
146
+ e && (e.innerHTML = `
147
+ <div class="ghp-search-container">
148
+ <svg class="ghp-search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
149
+ <circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>
150
+ </svg>
151
+ <input type="text" id="gh-port-search" class="ghp-search-input" placeholder="Buscar projeto..." autocomplete="off">
152
+ </div>
153
+ `);
154
+ }
155
+ function k(t, e, o, r, c) {
156
+ const n = document.getElementById(t);
157
+ n && n.addEventListener("click", (s) => {
158
+ const a = s.target.closest(".ghp-filter-btn");
159
+ if (!a) return;
160
+ const l = a.dataset.topic, p = l === "all" ? e : e.filter((d) => d.topics.includes(l));
161
+ m(p, o, r, c), n.querySelectorAll(".ghp-filter-btn").forEach((d) => d.classList.remove("active")), a.classList.add("active");
162
+ });
163
+ }
164
+ function B(t, e, o, r) {
165
+ const c = document.getElementById("gh-port-search");
166
+ c && c.addEventListener("input", (n) => {
167
+ const i = n.target.value.toLowerCase(), a = t.filter(
168
+ (l) => l.name.toLowerCase().includes(i) || (l.description || "").toLowerCase().includes(i) || l.topics.some((p) => p.toLowerCase().includes(i))
169
+ );
170
+ m(a, e, o, r);
171
+ });
172
+ }
173
+ async function L(t, e = {
174
+ searchContainer: "search-cont",
175
+ filtersContainer: "filters-cont",
176
+ projectsContainer: "projects-cont"
177
+ }) {
178
+ try {
179
+ const o = e.tag || "port";
180
+ x(e.searchContainer), E(e.projectsContainer, 6);
181
+ const r = await $(t, o);
182
+ return S(r, e.filtersContainer), m(r, e.projectsContainer, t, e.customCardTemplate), k(e.filtersContainer, r, e.projectsContainer, t, e.customCardTemplate), B(r, e.projectsContainer, t, e.customCardTemplate), { projects: r, status: "success" };
183
+ } catch (o) {
184
+ console.error("Erro ao inicializar portfólio:", o);
185
+ const r = document.getElementById(e.projectsContainer);
186
+ return r && (r.innerHTML = '<p class="ghp-empty-msg">Erro ao carregar projetos.</p>'), { status: "error", message: o.message };
187
+ }
188
+ }
189
+ export {
190
+ $ as getPortProjects,
191
+ L as initPortfolio,
192
+ S as renderFilters,
193
+ m as renderProjects,
194
+ x as renderSearchBar
195
+ };
@@ -0,0 +1,43 @@
1
+ (function(a,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(a=typeof globalThis<"u"?globalThis:a||self,p(a.SnapPort={}))})(this,(function(a){"use strict";var p=typeof document<"u"?document.currentScript:null;const f={react:{name:"React",icon:"react",color:"61DAFB"},vue:{name:"Vue.js",icon:"vuedotjs",color:"4FC08D"},angular:{name:"Angular",icon:"angular",color:"DD0031"},nextjs:{name:"Next.js",icon:"nextdotjs",color:"000000"},typescript:{name:"TypeScript",icon:"typescript",color:"3178C6"},javascript:{name:"JavaScript",icon:"javascript",color:"F7DF1E"},html5:{name:"HTML5",icon:"html5",color:"E34F26"},css3:{name:"CSS3",icon:"css3",color:"1572B6"},sass:{name:"Sass",icon:"sass",color:"CC6699"},"tailwind-css":{name:"Tailwind",icon:"tailwindcss",color:"06B6D4"},bootstrap:{name:"Bootstrap",icon:"bootstrap",color:"7952B3"},"styled-components":{name:"Styled Components",icon:"styledcomponents",color:"DB7093"},figma:{name:"Figma",icon:"figma",color:"F24E1E"},nodejs:{name:"Node.js",icon:"nodedotjs",color:"339933"},express:{name:"Express",icon:"express",color:"000000"},nestjs:{name:"NestJS",icon:"nestjs",color:"E0234E"},python:{name:"Python",icon:"python",color:"3776AB"},java:{name:"Java",icon:"openjdk",color:"007396"},php:{name:"PHP",icon:"php",color:"777BB4"},postgresql:{name:"PostgreSQL",icon:"postgresql",color:"4169E1"},mongodb:{name:"MongoDB",icon:"mongodb",color:"47A248"},mysql:{name:"MySQL",icon:"mysql",color:"4479A1"},firebase:{name:"Firebase",icon:"firebase",color:"FFCA28"},prisma:{name:"Prisma",icon:"prisma",color:"2D3748"},docker:{name:"Docker",icon:"docker",color:"2496ED"},git:{name:"Git",icon:"git",color:"F05032"},jest:{name:"Jest",icon:"jest",color:"C21325"},"github-actions":{name:"GitHub Actions",icon:"githubactions",color:"2088FF"}},y=typeof process<"u"&&process.env.NODE_ENV!=="production"||typeof{url:typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:p&&p.tagName.toUpperCase()==="SCRIPT"&&p.src||new URL("snap-port.umd.cjs",document.baseURI).href}<"u"&&(void 0).MODE!=="production",w=7200*1e3,S=e=>e?e.filter(o=>!!f[o.toLocaleLowerCase().trim()]):[],$=e=>({id:e.id,name:e.name??"Projeto sem nome",description:e.description??"Sem descrição disponível",htmlUrl:e.html_url,topics:Array.isArray(e.topics)?e.topics:[],stacks:Array.isArray(e.topics)?S(e.topics):[],deployUrl:e.homepage??null});function E(e){try{Object.keys(localStorage).forEach(t=>{t.startsWith("gh_projects_")&&!t.includes(e)&&localStorage.removeItem(t)})}catch(t){console.warn("Erro ao limpar caches antigos:",t)}}async function v(e,t="port",o={}){if(!e)return console.error("GitHubPortfolio: Username é obrigatório."),[];const r=`gh_projects_${e}`,s=y||o.forceRefresh;try{if(E(e),s)y&&console.info(`[GitHubPortfolio]: Dev mode detectado. Cache ignorado para ${e}.`);else{const u=localStorage.getItem(r);if(u){const{data:h,timestamp:x}=JSON.parse(u);if(Date.now()-x<w)return h}}const n=encodeURIComponent(`user:${e} topic:${t}`),c=await fetch(`https://api.github.com/search/repositories?q=${n}&sort=updated&order=desc`);if(!c.ok)throw new Error(`GitHub API error: ${c.status}`);const i=((await c.json()).items||[]).map($),d={data:i,timestamp:Date.now()};return localStorage.setItem(r,JSON.stringify(d)),i}catch(n){console.error(`GitHubPortfolio: Erro ao buscar dados de ${e}:`,n);const c=localStorage.getItem(r);return c?(console.warn("GitHubPortfolio: Usando cache expirado devido a erro de rede."),JSON.parse(c).data):[]}}const m=e=>typeof e=="string"?document.getElementById(e):e,C=(e,t=null)=>{if(!t)return`
2
+ <button class="ghp-filter-btn active" data-topic="all">
3
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
4
+ <rect width="7" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="14" y="3" rx="1"/>
5
+ <rect width="7" height="7" x="14" y="14" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/>
6
+ </svg>
7
+ <p>Todos</p>
8
+ </button>
9
+ `;const o=`https://cdn.simpleicons.org/${t.icon}/${t.color}`;return`
10
+ <button class="ghp-filter-btn" data-topic="${e}" style="--tech-color: #${t.color}">
11
+ <img src="${o}" alt="${t.name}" loading="lazy">
12
+ <p>${t.name}</p>
13
+ </button>
14
+ `},P=(e,t)=>{const o=`https://raw.githubusercontent.com/${t}/${e.name}/main/preview.png`,r=`https://opengraph.githubassets.com/${t}/${e.name}`,s=`https://placehold.co/640x360?text=${encodeURIComponent(e.name)}`,n=e.deployUrl?`<a href="${e.deployUrl}" target="_blank" rel="noopener noreferrer">Acessar</a>`:"",c=e.htmlUrl?`<a href="${e.htmlUrl}" target="_blank" rel="noopener noreferrer">Github</a>`:"";return`
15
+ <div class="ghp-project-card">
16
+ <div class="ghp-img-container">
17
+ <img
18
+ src="${o}"
19
+ alt="Preview do projeto ${e.name}"
20
+ class="ghp-card-img"
21
+ loading="lazy"
22
+ onerror="if (this.src.includes('preview.png')) { this.src='${r}'; } else { this.onerror=null; this.src='${s}'; }"
23
+ >
24
+ </div>
25
+ <div class="ghp-card-content">
26
+ <div>
27
+ <h3>${e.name}</h3>
28
+ <p title="${e.description}">${e.description}</p>
29
+ </div>
30
+ <div class="ghp-card-links">
31
+ ${c}
32
+ ${n}
33
+ </div>
34
+ </div>
35
+ </div>
36
+ `};function T(e,t=6){const o=m(e);o&&(o.className="ghp-projects-grid",o.innerHTML=Array(t).fill('<div class="ghp-project-card ghp-skeleton ghp-skeleton-card"></div>').join(""))}function j(e,t){const o=m(t);if(!o)return;const r=e.flatMap(c=>c.topics||[]),n=[...new Set(r)].reduce((c,l)=>{const i=f[l];return i?c+C(l,i):c},C("all"));o.innerHTML=`<div class="ghp-filters-content">${n}</div>`}function g(e,t,o="",r){const s=m(t);if(s){if(s.className="ghp-projects-grid",s.style.minHeight="auto",e.length===0){s.innerHTML='<p class="ghp-empty-msg">Nenhum projeto encontrado.</p>';return}s.innerHTML=e.map(n=>r?r(n):P(n,o)).join("")}}function b(e){const t=m(e);t&&(t.innerHTML=`
37
+ <div class="ghp-search-container">
38
+ <svg class="ghp-search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
39
+ <circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>
40
+ </svg>
41
+ <input type="text" id="gh-port-search" class="ghp-search-input" placeholder="Buscar projeto..." autocomplete="off">
42
+ </div>
43
+ `)}function k(e,t,o,r,s){const n=document.getElementById(e);n&&n.addEventListener("click",c=>{const i=c.target.closest(".ghp-filter-btn");if(!i)return;const d=i.dataset.topic,u=d==="all"?t:t.filter(h=>h.topics.includes(d));g(u,o,r,s),n.querySelectorAll(".ghp-filter-btn").forEach(h=>h.classList.remove("active")),i.classList.add("active")})}function B(e,t,o,r){const s=document.getElementById("gh-port-search");s&&s.addEventListener("input",n=>{const l=n.target.value.toLowerCase(),i=e.filter(d=>d.name.toLowerCase().includes(l)||(d.description||"").toLowerCase().includes(l)||d.topics.some(u=>u.toLowerCase().includes(l)));g(i,t,o,r)})}async function L(e,t={searchContainer:"search-cont",filtersContainer:"filters-cont",projectsContainer:"projects-cont"}){try{const o=t.tag||"port";b(t.searchContainer),T(t.projectsContainer,6);const r=await v(e,o);return j(r,t.filtersContainer),g(r,t.projectsContainer,e,t.customCardTemplate),k(t.filtersContainer,r,t.projectsContainer,e,t.customCardTemplate),B(r,t.projectsContainer,e,t.customCardTemplate),{projects:r,status:"success"}}catch(o){console.error("Erro ao inicializar portfólio:",o);const r=document.getElementById(t.projectsContainer);return r&&(r.innerHTML='<p class="ghp-empty-msg">Erro ao carregar projetos.</p>'),{status:"error",message:o.message}}}a.getPortProjects=v,a.initPortfolio=L,a.renderFilters=j,a.renderProjects=g,a.renderSearchBar=b,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "snapport",
3
3
  "private": false,
4
- "version": "1.1.0",
4
+ "version": "1.1.1",
5
5
  "keywords": [
6
6
  "portfolio",
7
7
  "github-api",